about summary refs log tree commit diff
path: root/lib/ppmdraw.h
blob: b2c4b5d54ffa4ada5c91b074c19f7911bae64a82 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
/* ppmdraw.h - header file for simple drawing routines in libppm
**
** Simple, yes, and also fairly slow if the truth be told; but also very
** flexible and powerful.
**
** The two basic concepts are the drawproc and clientdata.  All the drawing
** routines take a drawproc that does the actual drawing.  A drawproc draws
** a single point, and it looks like this:
*/

#include <netpbm/pm_config.h>
#include <netpbm/ppm.h>

#ifdef __cplusplus
extern "C" {
#endif
#if 0
} /* to fake out automatic code indenters */
#endif


typedef struct {
    int x;
    int y;
} ppmd_point;

static __inline__ ppmd_point
ppmd_makePoint(int const x,
               int const y) {

    ppmd_point p;

    p.x = x;
    p.y = y;

    return p;
}

void
ppmd_validateCoord(int const c);

void
ppmd_validatePoint(ppmd_point const p);

typedef enum {
    PPMD_PATHLEG_LINE
} ppmd_pathlegtype;

struct ppmd_linelegparms {
    ppmd_point end;
};

typedef struct {
/*----------------------------------------------------------------------------
   A leg of a ppmd_path.
-----------------------------------------------------------------------------*/
    ppmd_pathlegtype type;
    union {
        struct ppmd_linelegparms linelegparms;
    } u;
} ppmd_pathleg;

ppmd_pathleg
ppmd_makeLineLeg(ppmd_point const point);

typedef struct {
/*----------------------------------------------------------------------------
   A closed path
-----------------------------------------------------------------------------*/
    unsigned int version;
        /* Must be zero.  For future expansion. */
    ppmd_point   begPoint;
    unsigned int legCount;
        /* Number of legs in the path; i.e. size of 'legs' array */
    size_t       legSize;
        /* Size of storage occupied by one ppmd_pathleg.  I.e.
           sizeof(ppmd_pathleg).  Used for
           binary backward compatibility between callers and libppmd
           as the definition of ppmd_pathleg changes.
        */
    ppmd_pathleg * legs;
        /* An array of the legs of the path, in order, starting at 'begPoint'.
        */
} ppmd_path;

typedef struct {

    ppmd_path path;
        /* The path we are building (or have built).
           Null for path.legs means we don't have a leg array yet.
        */

    bool begIsSet;
        /* User has set path.begPoint.  If this is false, path.begPoint is
           meaningless.
        */

    unsigned int legsAllocSize;
        /* How many legs of space is allocated in the leg array path.legs */

    bool legsAreAutoAllocated;
        /* The array 'legs' is allocated or reallocated automatically by
           ppmd_path_addlineline(), as opposed to being supplied by the
           user as part of initializing this structure, never to be altered.
        */

} ppmd_pathbuilder;

ppmd_pathbuilder *
ppmd_pathbuilder_create(void);

void
ppmd_pathbuilder_destroy(ppmd_pathbuilder * const pathBuilderP);

void
ppmd_pathbuilder_setLegArray(ppmd_pathbuilder * const pathBuilderP,
                             ppmd_pathleg *     const legs,
                             unsigned int       const legCount);

void
ppmd_pathbuilder_preallocLegArray(ppmd_pathbuilder * const pathBuilderP,
                                  unsigned int       const legCount);

void
ppmd_pathbuilder_setBegPoint(ppmd_pathbuilder * const pathBuilderP,
                             ppmd_point         const begPoint);

void
ppmd_pathbuilder_addLineLeg(ppmd_pathbuilder * const pathBuilderP,
                            ppmd_pathleg       const leg);

const ppmd_path *
ppmd_pathbuilder_pathP(ppmd_pathbuilder * const pathBuilderP);

typedef void ppmd_drawprocp(pixel **, unsigned int, unsigned int,
                            pixval, ppmd_point, const void *);
typedef void ppmd_drawproc(pixel **, int, int, pixval, int, int, const void *);

ppmd_drawprocp ppmd_point_drawprocp;
ppmd_drawproc ppmd_point_drawproc;

/*
** So, you call a drawing routine, e.g. ppmd_line(), and pass it a drawproc;
** it calls the drawproc for each point it wants to draw.  Why so complicated?
** Because you can define your own drawprocs to do more interesting things than
** simply draw the point.  For example, you could make one that calls back into
** another drawing routine, say ppmd_circle() to draw a circle at each point
** of a line.
**
** Slow?  Well sure, we're talking results here, not realtime.  You can do
** tricks with this arrangement that you couldn't even think of before.
** Still, to speed things up for the 90% case you can use this:
*/
#define PPMD_NULLDRAWPROC NULL
/*
** Just like ppmd_point_drawproc() it simply draws the point, but it's done
** inline, and clipping is assumed to be handled at a higher level.
**
** Now, what about clientdata.  Well, it's an arbitrary pointer, and can
** mean something different to each different drawproc.  For the above two
** drawprocs, clientdata should be a pointer to a pixel holding the color
** to be drawn.  Other drawprocs can use it to point to something else,
** e.g. some structure to be modified, or they can ignore it.
*/


/* Outline drawing routines.  Lines, splines, circles, etc. */

int
ppmd_setlinetype(int const type);

#define PPMD_LINETYPE_NORMAL 0
#define PPMD_LINETYPE_NODIAGS 1
/* If you set NODIAGS, all pixels drawn by ppmd_line() will be 4-connected
** instead of 8-connected; in other words, no diagonals.  This is useful
** for some applications, for example when you draw many parallel lines
** and you want them to fit together without gaps.
*/

int
ppmd_setlineclip(int const clip);

#define ppmd_setlineclipping(x)     ppmd_setlineclip(x)
/* Normally, ppmd_line() clips to the edges of the pixmap.  You can use this
** routine to disable the clipping, for example if you are using a drawproc
** that wants to do its own clipping.
*/

void
ppmd_linep(pixel **       const pixels,
           int            const cols,
           int            const rows,
           pixval         const maxval,
           ppmd_point     const p0,
           ppmd_point     const p1,
           ppmd_drawprocp       drawProc,
           const void *   const clientdata);

    /* Draws a line from p0 to p1.  */

void
ppmd_line(pixel**       const pixels,
          int           const cols,
          int           const rows,
          pixval        const maxval,
          int           const x0,
          int           const y0,
          int           const x1,
          int           const y1,
          ppmd_drawproc       drawproc,
          const void *  const clientdata);
    /* Draws a line from (x0, y0) to (x1, y1). */

void
ppmd_spline3p(pixel **       const pixels,
              int            const cols,
              int            const rows,
              pixval         const maxval,
              ppmd_point     const p0,
              ppmd_point     const p1,
              ppmd_point     const p2,
              ppmd_drawprocp       drawProc,
              const void *   const clientdata);

    /* Draws a three-point spline from p0 to p2, with p1
       as the control point.  All drawing is done via ppmd_linep(),
       so the routines that control it control ppmd_spline3p() as well.
    */

void
ppmd_spline3(pixel **      const pixels,
             int           const cols,
             int           const rows,
             pixval        const maxval,
             int           const x0,
             int           const y0,
             int           const x1,
             int           const y1,
             int           const x2,
             int           const y2,
             ppmd_drawproc       drawproc,
             const void *  const clientdata);

void
ppmd_polysplinep(pixel **       const pixels,
                 unsigned int   const cols,
                 unsigned int   const rows,
                 pixval         const maxval,
                 ppmd_point     const p0,
                 unsigned int   const nc,
                 ppmd_point *   const c,
                 ppmd_point     const p1,
                 ppmd_drawprocp       drawProc,
                 const void *   const clientdata);

    /* Draws a bunch of splines end to end.  p0 and p1 are the initial and
       final points, and the c[] are the intermediate control points.  nc is
       the number of these control points.
    */

void
ppmd_polyspline(pixel **     const pixels,
                int          const cols,
                int          const rows,
                pixval       const maxval,
                int          const x0,
                int          const y0,
                int          const nc,
                int *        const xc,
                int *        const yc,
                int          const x1,
                int          const y1,
                ppmd_drawproc      drawProc,
                const void * const clientdata);

void
ppmd_spline4p(pixel **       const pixels,
              unsigned int   const cols,
              unsigned int   const rows,
              pixval         const maxval,
              ppmd_point     const endPt0,
              ppmd_point     const endPt1,
              ppmd_point     const ctlPt0,
              ppmd_point     const ctlPt1,
              ppmd_drawprocp       drawproc,
              const void *   const clientdata);

void
ppmd_circlep(pixel **       const pixels,
             unsigned int   const cols,
             unsigned int   const rows,
             pixval         const maxval,
             ppmd_point     const center,
             unsigned int   const radius,
             ppmd_drawprocp       drawProc,
             const void *   const clientData);
    /* Draws a circle centered at 'center' with radius 'radius' */

void
ppmd_circle(pixel **     const pixels,
            int          const cols,
            int          const rows,
            pixval       const maxval,
            int          const cx,
            int          const cy,
            int          const radius,
            ppmd_drawproc      drawProc,
            const void * const clientdata);


/* Simple filling routines.  */

void
ppmd_filledrectangle(pixel **      const pixels,
                     int           const cols,
                     int           const rows,
                     pixval        const maxval,
                     int           const x,
                     int           const y,
                     int           const width,
                     int           const height,
                     ppmd_drawproc       drawproc,
                     const void *  const clientdata );
    /* Fills in the rectangle [x, y, width, height]. */


void
ppmd_fill_path(pixel **          const pixels,
               int               const cols,
               int               const rows,
               pixval            const maxval,
               const ppmd_path * const pathP,
               pixel             const color);
    /* Fills in a closed path.  Not much different from ppmd_fill(),
       but with a different interface.
    */


/* Arbitrary filling routines.  With these you can fill any outline that
** you can draw with the outline routines.
*/

struct fillobj;

struct fillobj *
ppmd_fill_create(void);
    /* Returns a blank fillhandle. */

void
ppmd_fill_destroy(struct fillobj * fillObjP);

/* For backward compatibility only: */
char *
ppmd_fill_init(void);

void
ppmd_fill_drawprocp(pixel **     const pixels,
                    unsigned int const cols,
                    unsigned int const rows,
                    pixval       const maxval,
                    ppmd_point   const p,
                    const void * const clientdata);
    /* Use this drawproc to trace the outline you want filled.  Use
       the fillhandle as the clientdata.
    */

void
ppmd_fill_drawproc(pixel **     const pixels,
                   int          const cols,
                   int          const rows,
                   pixval       const maxval,
                   int          const x,
                   int          const y,
                   const void * const clientdata);

void
ppmd_fill(pixel **         const pixels,
          int              const cols,
          int              const rows,
          pixval           const maxval,
          struct fillobj * const fh,
          ppmd_drawproc          drawProc,
          const void *     const clientdata);

/* Once you've traced the outline, give the fillhandle to this routine to
** do the actual drawing.  As usual, it takes a drawproc and clientdata;
** you could define drawprocs to do stipple fills and such.
*/

/* Text drawing routines. */

void
ppmd_textp(pixel**        const pixels,
           int            const cols,
           int            const rows,
           pixval         const maxval,
           ppmd_point     const pos,
           int            const height,
           int            const angle,
           const char *   const sArg,
           ppmd_drawprocp       drawProc,
           const void *   const clientdata);

void
ppmd_text(pixel**       const pixels,
          int           const cols,
          int           const rows,
          pixval        const maxval,
          int           const xpos,
          int           const ypos,
          int           const height,
          int           const angle,
          const char *  const sArg,
          ppmd_drawproc       drawProc,
          const void *  const clientdata);
/* Draws the null-terminated string 's' left justified at the point
   ('x', 'y').  The text will be 'height' pixels high and will be aligned on a
   baseline inclined 'angle' degrees with the X axis.  The supplied
   drawproc and clientdata are passed to ppmd_line() which performs the
   actual drawing.
*/

void
ppmd_text_box(int          const height,
              int          const angle,
              const char * const s,
              int *        const leftP,
              int *        const topP,
              int *        const rightP,
              int *        const bottomP);
/* Calculates the extents box for text drawn by ppm_text with the given
   string, size, and orientation.  Most extent box calculations should use
   an angle specification of zero to calculate the unrotated box enclosing
   the text.  If you need the extents of rotated text, however, you can
   call ppmd_text_box with a nonzero angle.
*/

#ifdef __cplusplus
}
#endif