~profzoom/ubuntu/quantal/wmaker/bug-1079925

« back to all changes in this revision

Viewing changes to wrlib/draw.c

  • Committer: Bazaar Package Importer
  • Author(s): Marcelo E. Magallon
  • Date: 2004-11-10 14:05:30 UTC
  • Revision ID: james.westby@ubuntu.com-20041110140530-qpd66b5lm38x7apk
Tags: upstream-0.91.0
ImportĀ upstreamĀ versionĀ 0.91.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* draw.c - pixel plotting, line drawing
 
2
 *
 
3
 * Raster graphics library
 
4
 *
 
5
 * Copyright (c) 1998-2003 Dan Pascu
 
6
 * Copyright (c) 2000-2003 Alfredo K. Kojima
 
7
 *
 
8
 *  This library is free software; you can redistribute it and/or
 
9
 *  modify it under the terms of the GNU Library General Public
 
10
 *  License as published by the Free Software Foundation; either
 
11
 *  version 2 of the License, or (at your option) any later version.
 
12
 *
 
13
 *  This library is distributed in the hope that it will be useful,
 
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
 *  Library General Public License for more details.
 
17
 *
 
18
 *  You should have received a copy of the GNU Library General Public
 
19
 *  License along with this library; if not, write to the Free
 
20
 *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
21
 */
 
22
 
 
23
#include <config.h>
 
24
 
 
25
#include <stdio.h>
 
26
#include <stdlib.h>
 
27
#include <assert.h>
 
28
 
 
29
#include "wraster.h"
 
30
 
 
31
 
 
32
#define MIN(a,b)        ((a) < (b) ? (a) : (b))
 
33
#define MAX(a,b)        ((a) > (b) ? (a) : (b))
 
34
 
 
35
 
 
36
 
 
37
/*
 
38
 * Returns the color of the pixel at coordinates (x, y) in "color".
 
39
 */
 
40
Bool
 
41
RGetPixel(RImage *image, int x, int y, RColor *color)
 
42
{
 
43
    int ofs;
 
44
 
 
45
    assert(image!=NULL);
 
46
    if (x < 0 || x >= image->width
 
47
        || y < 0 || y >= image->height)
 
48
        return False;
 
49
 
 
50
    if (image->format == RRGBAFormat) {
 
51
        ofs = (y*image->width + x) * 4;
 
52
        color->red = image->data[ofs++];
 
53
        color->green = image->data[ofs++];
 
54
        color->blue = image->data[ofs++];
 
55
        color->alpha = image->data[ofs];
 
56
    } else {
 
57
        ofs = (y*image->width + x) * 3;
 
58
        color->red = image->data[ofs++];
 
59
        color->green = image->data[ofs++];
 
60
        color->blue = image->data[ofs];
 
61
        /* If the image does not have alpha channel, we consider alpha 255 */
 
62
        color->alpha = 255;
 
63
    }
 
64
 
 
65
    return True;
 
66
}
 
67
 
 
68
 
 
69
void
 
70
RPutPixel(RImage *image, int x, int y, RColor *color)
 
71
{
 
72
    unsigned char *ptr;
 
73
 
 
74
    assert(image!=NULL);
 
75
    assert(color!=NULL);
 
76
    if (x < 0 || x >= image->width || y < 0 || y >= image->height)
 
77
        return;
 
78
 
 
79
    if (image->format == RRGBAFormat) {
 
80
        ptr = image->data + (y*image->width + x) * 4;
 
81
    } else {
 
82
        ptr = image->data + (y*image->width + x) * 3;
 
83
    }
 
84
 
 
85
    if (color->alpha==255) {
 
86
        *ptr++ = color->red;
 
87
        *ptr++ = color->green;
 
88
        *ptr++ = color->blue;
 
89
        if (image->format == RRGBAFormat) {
 
90
            *ptr = 255;
 
91
        }
 
92
    } else {
 
93
        register int alpha, nalpha, r, g, b;
 
94
 
 
95
        r = color->red;
 
96
        g = color->green;
 
97
        b = color->blue;
 
98
        alpha = color->alpha;
 
99
        nalpha = 255 - alpha;
 
100
 
 
101
        *ptr = (((int)*ptr * nalpha) + (r * alpha))/256; ptr++;
 
102
        *ptr = (((int)*ptr * nalpha) + (g * alpha))/256; ptr++;
 
103
        *ptr = (((int)*ptr * nalpha) + (b * alpha))/256; ptr++;
 
104
        if (image->format == RRGBAFormat) {
 
105
            *ptr = alpha + ((int)*ptr * nalpha)/256;
 
106
        }
 
107
    }
 
108
}
 
109
 
 
110
 
 
111
static void
 
112
operatePixel(RImage *image, int ofs, int operation, RColor *color)
 
113
{
 
114
    unsigned char *sr, *sg, *sb, *sa;
 
115
    register int alpha, nalpha, tmp;
 
116
    int hasAlpha = image->format == RRGBAFormat;
 
117
 
 
118
    alpha = color->alpha;
 
119
    nalpha = 255 - alpha;
 
120
 
 
121
    sr = image->data + ofs*(hasAlpha ? 4 : 3);
 
122
    sg = image->data + ofs*(hasAlpha ? 4 : 3) + 1;
 
123
    sb = image->data + ofs*(hasAlpha ? 4 : 3) + 2;
 
124
    sa = image->data + ofs*(hasAlpha ? 4 : 3) + 3;
 
125
 
 
126
    switch (operation) {
 
127
    case RClearOperation:
 
128
        *sr = 0;
 
129
        *sg = 0;
 
130
        *sb = 0;
 
131
        if (hasAlpha)
 
132
            *sa = 0;
 
133
        break;
 
134
    case RCopyOperation:
 
135
        *sr = color->red;
 
136
        *sg = color->green;
 
137
        *sb = color->blue;
 
138
        if (hasAlpha)
 
139
            *sa = color->alpha;
 
140
        break;
 
141
    case RNormalOperation:
 
142
        if (color->alpha==255) {
 
143
            *sr = color->red;
 
144
            *sg = color->green;
 
145
            *sb = color->blue;
 
146
            if (hasAlpha)
 
147
                *sa = 255;
 
148
        } else {
 
149
            *sr = (((int)*sr * nalpha) + ((int)color->red * alpha))/256;
 
150
            *sg = (((int)*sg * nalpha) + ((int)color->green * alpha))/256;
 
151
            *sb = (((int)*sb * nalpha) + ((int)color->blue * alpha))/256;
 
152
        }
 
153
        break;
 
154
    case RAddOperation:
 
155
        tmp = color->red + *sr;
 
156
        *sr = MIN(255, tmp);
 
157
        tmp = color->green + *sg;
 
158
        *sg = MIN(255, tmp);
 
159
        tmp = color->blue + *sb;
 
160
        *sb = MIN(255, tmp);
 
161
        if (hasAlpha)
 
162
            *sa = MIN(*sa, color->alpha);
 
163
        break;
 
164
    case RSubtractOperation:
 
165
        tmp = *sr - color->red;
 
166
        *sr = MAX(0, tmp);
 
167
        tmp = *sg - color->green;
 
168
        *sg = MAX(0, tmp);
 
169
        tmp = *sb - color->blue;
 
170
        *sb = MAX(0, tmp);
 
171
        if (hasAlpha)
 
172
            *sa = MIN(*sa, color->alpha);
 
173
        break;
 
174
    }
 
175
}
 
176
 
 
177
 
 
178
 
 
179
void
 
180
ROperatePixel(RImage *image, int operation, int x, int y, RColor *color)
 
181
{
 
182
    int ofs;
 
183
 
 
184
    assert(image!=NULL);
 
185
    assert(color!=NULL);
 
186
    assert(x >= 0 && x < image->width);
 
187
    assert(y >= 0 && y < image->height);
 
188
 
 
189
    ofs = y*image->width + x;
 
190
 
 
191
    operatePixel(image, ofs, operation, color);
 
192
}
 
193
 
 
194
 
 
195
void
 
196
RPutPixels(RImage *image, RPoint *points, int npoints, int mode, RColor *color)
 
197
{
 
198
    register int x, y, i;
 
199
 
 
200
    assert(image!=NULL);
 
201
    assert(points!=NULL);
 
202
 
 
203
    x = y = 0;
 
204
 
 
205
    for (i=0; i<npoints; i++) {
 
206
        if (mode == RAbsoluteCoordinates) {
 
207
            x = points[i].x;
 
208
            y = points[i].y;
 
209
        } else {
 
210
            x += points[i].x;
 
211
            y += points[i].y;
 
212
        }
 
213
        RPutPixel(image, x, y, color);
 
214
    }
 
215
}
 
216
 
 
217
 
 
218
void
 
219
ROperatePixels(RImage *image, int operation, RPoint *points, int npoints,
 
220
               int mode, RColor *color)
 
221
{
 
222
    register int x, y, i;
 
223
 
 
224
    assert(image!=NULL);
 
225
    assert(points!=NULL);
 
226
 
 
227
    x = y = 0;
 
228
 
 
229
    for (i=0; i<npoints; i++) {
 
230
        if (mode == RAbsoluteCoordinates) {
 
231
            x = points[i].x;
 
232
            y = points[i].y;
 
233
        } else {
 
234
            x += points[i].x;
 
235
            y += points[i].y;
 
236
        }
 
237
        ROperatePixel(image, operation, x, y, color);
 
238
    }
 
239
}
 
240
 
 
241
 
 
242
static Bool
 
243
clipLineInRectangle(int xmin, int ymin, int xmax, int ymax,
 
244
                    int *x1, int *y1, int *x2, int *y2)
 
245
{
 
246
#define TOP     (1<<0)
 
247
#define BOT     (1<<1)
 
248
#define LEF     (1<<2)
 
249
#define RIG     (1<<3)
 
250
#define CHECK_OUT(X,Y)  (((Y) > ymax ? TOP : ((Y) < ymin ? BOT : 0))\
 
251
    | ((X) > xmax ? RIG : ((X) < xmin ? LEF : 0)))
 
252
 
 
253
    int ocode1, ocode2, ocode;
 
254
    int accept = 0;
 
255
    int x, y;
 
256
 
 
257
    ocode1 = CHECK_OUT(*x1, *y1);
 
258
    ocode2 = CHECK_OUT(*x2, *y2);
 
259
 
 
260
    for(;;) {
 
261
        if (!ocode1 && !ocode2) { /* completely inside */
 
262
            accept = 1;
 
263
            break;
 
264
        } else if (ocode1 & ocode2) {
 
265
            break;
 
266
        }
 
267
 
 
268
        if (ocode1)
 
269
            ocode = ocode1;
 
270
        else
 
271
            ocode = ocode2;
 
272
 
 
273
        if (ocode & TOP) {
 
274
            x = *x1 + (*x2 - *x1) * (ymax - *y1) / (*y2 - *y1);
 
275
            y = ymax;
 
276
        } else if (ocode & BOT) {
 
277
            x = *x1 + (*x2 - *x1) * (ymin - *y1) / (*y2 - *y1);
 
278
            y = ymin;
 
279
        } else if (ocode & RIG) {
 
280
            y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1);
 
281
            x = xmax;
 
282
        } else { /* //if (ocode & LEF) { */
 
283
            y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1);
 
284
            x = xmin;
 
285
        }
 
286
 
 
287
        if (ocode == ocode1) {
 
288
            *x1 = x;
 
289
            *y1 = y;
 
290
            ocode1 = CHECK_OUT(x, y);
 
291
        } else {
 
292
            *x2 = x;
 
293
            *y2 = y;
 
294
            ocode2 = CHECK_OUT(x, y);
 
295
        }
 
296
    }
 
297
 
 
298
    return accept;
 
299
}
 
300
 
 
301
 
 
302
/*
 
303
 * This routine is a generic drawing routine, based on Bresenham's line
 
304
 * drawing algorithm.
 
305
 */
 
306
static int
 
307
genericLine(RImage *image, int x0, int y0, int x1, int y1, RColor *color,
 
308
            int operation, int polyline)
 
309
{
 
310
    int i, err, du, dv, du2, dv2, uofs, vofs, last;
 
311
 
 
312
    assert(image!=NULL);
 
313
 
 
314
    if (!clipLineInRectangle(0, 0, image->width-1, image->height-1,
 
315
                             &x0, &y0, &x1, &y1))
 
316
        return True;
 
317
 
 
318
    if (x0 < x1) {
 
319
        du = x1 - x0;
 
320
        uofs = 1;
 
321
    } else {
 
322
        du = x0 - x1;
 
323
        uofs = -1;
 
324
    }
 
325
    if (y0 < y1) {
 
326
        dv = y1 -y0;
 
327
        vofs = image->width;
 
328
    } else {
 
329
        dv = y0 - y1;
 
330
        vofs = -image->width;
 
331
    }
 
332
 
 
333
    if (du < dv) {
 
334
        /* Swap coordinates between them, so that always du>dv */
 
335
        i = du; du = dv; dv = i;
 
336
        i = uofs; uofs = vofs; vofs = i;
 
337
    }
 
338
 
 
339
    err = 0;
 
340
    du2 = du<<1;
 
341
    dv2 = dv<<1;
 
342
    last = (polyline) ? du-1 : du;
 
343
 
 
344
    if (color->alpha==255 || operation==RCopyOperation) {
 
345
        unsigned char *ptr;
 
346
 
 
347
        if (image->format == RRGBAFormat)
 
348
            i = (y0*image->width + x0) * 4;
 
349
        else
 
350
            i = (y0*image->width + x0) * 3;
 
351
        ptr = image->data + i;
 
352
 
 
353
        for (i=0; i<=last; i++) {
 
354
            /* Draw the pixel */
 
355
            *ptr = color->red;
 
356
            *(ptr+1) = color->green;
 
357
            *(ptr+2) = color->blue;
 
358
            if (image->format == RRGBAFormat)
 
359
                *(ptr+3) = 255;
 
360
 
 
361
            /* Compute error for NeXT Step */
 
362
            err += dv2;
 
363
            if (err >= du) {
 
364
                if (image->format == RRGBAFormat)
 
365
                    ptr += vofs*4;
 
366
                else
 
367
                    ptr += vofs*3;
 
368
                err -= du2;
 
369
            }
 
370
            if (image->format == RRGBAFormat)
 
371
                ptr += uofs*4;
 
372
            else
 
373
                ptr += uofs*3;
 
374
        }
 
375
    } else {
 
376
        register int ofs = y0*image->width + x0;
 
377
 
 
378
        for (i=0; i<=last; i++) {
 
379
            /* Draw the pixel */
 
380
            operatePixel(image, ofs, operation, color);
 
381
 
 
382
            /* Compute error for NeXT Step */
 
383
            err += dv2;
 
384
            if (err >= du) {
 
385
                ofs += vofs;
 
386
                err -= du2;
 
387
            }
 
388
            ofs += uofs;
 
389
        }
 
390
    }
 
391
 
 
392
#if 0
 
393
    if (mode == RALTER_PIXELS) {
 
394
        RColorOffset *cdelta = (RColorOffset*)cdata;
 
395
        register short r, g, b, a;
 
396
 
 
397
        for (i=0; i<=last; i++) {
 
398
            /* Change the pixel with offset */
 
399
            r = (short)*sr + cdelta->red;
 
400
            g = (short)*sg + cdelta->green;
 
401
            b = (short)*sb + cdelta->blue;
 
402
            if (r>255) r = 255; else if (r<0) r = 0;
 
403
            if (g>255) g = 255; else if (g<0) g = 0;
 
404
            if (b>255) b = 255; else if (b<0) b = 0;
 
405
            *sr = (unsigned char) r;
 
406
            *sg = (unsigned char) g;
 
407
            *sb = (unsigned char) b;
 
408
            if (image->data[3]) {
 
409
                a = (short)*sa + cdelta->alpha;
 
410
                if (a>255) a = 255; else if (a<0) a = 0;
 
411
                *sa = (unsigned char) a;
 
412
            }
 
413
 
 
414
            /* Compute error for NeXT Step */
 
415
            err += dv2;
 
416
            if (err >= du) {
 
417
                sr += vofs; sg += vofs;
 
418
                sb += vofs; sa += vofs;
 
419
                err -= du2;
 
420
            }
 
421
            sr += uofs; sg += uofs;
 
422
            sb += uofs; sa += uofs;
 
423
        }
 
424
    } else {
 
425
        RColor *color = (RColor*)cdata;
 
426
 
 
427
        if (color->alpha==255) {
 
428
            for (i=0; i<=last; i++) {
 
429
                /* Draw the pixel */
 
430
                *sr = color->red;
 
431
                *sg = color->green;
 
432
                *sb = color->blue;
 
433
                if (image->data[3])
 
434
                    *sa = 255;
 
435
 
 
436
                /* Compute error for NeXT Step */
 
437
                err += dv2;
 
438
                if (err >= du) {
 
439
                    sr += vofs; sg += vofs;
 
440
                    sb += vofs; sa += vofs;
 
441
                    err -= du2;
 
442
                }
 
443
                sr += uofs; sg += uofs;
 
444
                sb += uofs; sa += uofs;
 
445
            }
 
446
        } else {
 
447
            register short alpha, nalpha, r, g ,b;
 
448
 
 
449
            alpha = color->alpha;
 
450
            nalpha = 255 - alpha;
 
451
            r = color->red;
 
452
            g = color->green;
 
453
            b = color->blue;
 
454
 
 
455
            for (i=0; i<=last; i++) {
 
456
                /* Draw the pixel */
 
457
                *sr = (((int)*sr * nalpha) + (r * alpha))/256;
 
458
                *sg = (((int)*sg * nalpha) + (g * alpha))/256;
 
459
                *sb = (((int)*sb * nalpha) + (b * alpha))/256;
 
460
                if (image->data[3])
 
461
                    *sa = alpha + ((int)*sa * nalpha)/256;
 
462
 
 
463
                /* Compute error for NeXT Step */
 
464
                err += dv2;
 
465
                if (err >= du) {
 
466
                    sr += vofs; sg += vofs;
 
467
                    sb += vofs; sa += vofs;
 
468
                    err -= du2;
 
469
                }
 
470
                sr += uofs; sg += uofs;
 
471
                sb += uofs; sa += uofs;
 
472
            }
 
473
        }
 
474
    }
 
475
#endif
 
476
    return True;
 
477
}
 
478
 
 
479
 
 
480
int
 
481
RDrawLine(RImage *image, int x0, int y0, int x1, int y1, RColor *color)
 
482
{
 
483
    return genericLine(image, x0, y0, x1, y1, color, RNormalOperation, False);
 
484
}
 
485
 
 
486
 
 
487
int
 
488
ROperateLine(RImage *image, int operation, int x0, int y0, int x1,
 
489
             int y1, RColor *color)
 
490
{
 
491
    return genericLine(image, x0, y0, x1, y1, color, operation, False);
 
492
}
 
493
 
 
494
 
 
495
void
 
496
RDrawLines(RImage *image, RPoint *points, int npoints, int mode, RColor *color)
 
497
{
 
498
    register int x1, y1, x2, y2, i;
 
499
 
 
500
    assert(points!=NULL);
 
501
 
 
502
    if (npoints==0)
 
503
        return;
 
504
 
 
505
    x1 = points[0].x;
 
506
    y1 = points[0].y;
 
507
    x2 = y2 = 0;
 
508
 
 
509
    for (i=1; i<npoints-1; i++) {
 
510
        if (mode == RAbsoluteCoordinates) {
 
511
            x2 = points[i].x;
 
512
            y2 = points[i].y;
 
513
        } else {
 
514
            x2 += points[i-1].x;
 
515
            y2 += points[i-1].y;
 
516
        }
 
517
        /* Don't draw pixels at junction points twice */
 
518
        genericLine(image, x1, y1, x2, y2, color, RNormalOperation, True);
 
519
        x1 = x2;
 
520
        y1 = y2;
 
521
    }
 
522
    i = npoints-1; /* last point */
 
523
    if (mode == RAbsoluteCoordinates) {
 
524
        x2 = points[i].x;
 
525
        y2 = points[i].y;
 
526
    } else {
 
527
        x2 += points[i-1].x;
 
528
        y2 += points[i-1].y;
 
529
    }
 
530
    i = (points[0].x==x2 && points[0].y==y2 && npoints>1);
 
531
    genericLine(image, x1, y1, x2, y2, color, RNormalOperation, i);
 
532
}
 
533
 
 
534
 
 
535
void
 
536
ROperateLines(RImage *image, int operation, RPoint *points,
 
537
              int npoints, int mode, RColor *color)
 
538
{
 
539
    register int x1, y1, x2, y2, i;
 
540
 
 
541
    assert(points!=NULL);
 
542
 
 
543
    if (npoints==0)
 
544
        return;
 
545
 
 
546
    x1 = points[0].x;
 
547
    y1 = points[0].y;
 
548
    x2 = y2 = 0;
 
549
 
 
550
    for (i=1; i<npoints-1; i++) {
 
551
        if (mode == RAbsoluteCoordinates) {
 
552
            x2 = points[i].x;
 
553
            y2 = points[i].y;
 
554
        } else {
 
555
            x2 += points[i-1].x;
 
556
            y2 += points[i-1].y;
 
557
        }
 
558
        /* Don't draw pixels at junction points twice */
 
559
        genericLine(image, x1, y1, x2, y2, color, operation, True);
 
560
        x1 = x2;
 
561
        y1 = y2;
 
562
    }
 
563
    i = npoints-1; /* last point */
 
564
    if (mode == RAbsoluteCoordinates) {
 
565
        x2 = points[i].x;
 
566
        y2 = points[i].y;
 
567
    } else {
 
568
        x2 += points[i-1].x;
 
569
        y2 += points[i-1].y;
 
570
    }
 
571
    i = (points[0].x==x2 && points[0].y==y2 && npoints>1);
 
572
    genericLine(image, x1, y1, x2, y2, color, operation, i);
 
573
}
 
574
 
 
575
 
 
576
void
 
577
RDrawSegments(RImage *image, RSegment *segs, int nsegs, RColor *color)
 
578
{
 
579
    register int i;
 
580
 
 
581
    assert(segs!=NULL);
 
582
 
 
583
    for (i=0; i<nsegs; i++) {
 
584
        genericLine(image, segs->x1, segs->y1, segs->x2, segs->y2, color,
 
585
                    RNormalOperation, False);
 
586
        segs++;
 
587
    }
 
588
}
 
589
 
 
590
 
 
591
void
 
592
ROperateSegments(RImage *image, int operation, RSegment *segs,
 
593
                 int nsegs, RColor *color)
 
594
{
 
595
    register int i;
 
596
 
 
597
    assert(segs!=NULL);
 
598
 
 
599
    for (i=0; i<nsegs; i++) {
 
600
        genericLine(image, segs->x1, segs->y1, segs->x2, segs->y2, color,
 
601
                    operation, False);
 
602
        segs++;
 
603
    }
 
604
}
 
605