1
/* draw.c - pixel plotting, line drawing
3
* Raster graphics library
5
* Copyright (c) 1998-2003 Dan Pascu
6
* Copyright (c) 2000-2003 Alfredo K. Kojima
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.
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.
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.
32
#define MIN(a,b) ((a) < (b) ? (a) : (b))
33
#define MAX(a,b) ((a) > (b) ? (a) : (b))
38
* Returns the color of the pixel at coordinates (x, y) in "color".
41
RGetPixel(RImage *image, int x, int y, RColor *color)
46
if (x < 0 || x >= image->width
47
|| y < 0 || y >= image->height)
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];
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 */
70
RPutPixel(RImage *image, int x, int y, RColor *color)
76
if (x < 0 || x >= image->width || y < 0 || y >= image->height)
79
if (image->format == RRGBAFormat) {
80
ptr = image->data + (y*image->width + x) * 4;
82
ptr = image->data + (y*image->width + x) * 3;
85
if (color->alpha==255) {
87
*ptr++ = color->green;
89
if (image->format == RRGBAFormat) {
93
register int alpha, nalpha, r, g, b;
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;
112
operatePixel(RImage *image, int ofs, int operation, RColor *color)
114
unsigned char *sr, *sg, *sb, *sa;
115
register int alpha, nalpha, tmp;
116
int hasAlpha = image->format == RRGBAFormat;
118
alpha = color->alpha;
119
nalpha = 255 - alpha;
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;
127
case RClearOperation:
141
case RNormalOperation:
142
if (color->alpha==255) {
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;
155
tmp = color->red + *sr;
157
tmp = color->green + *sg;
159
tmp = color->blue + *sb;
162
*sa = MIN(*sa, color->alpha);
164
case RSubtractOperation:
165
tmp = *sr - color->red;
167
tmp = *sg - color->green;
169
tmp = *sb - color->blue;
172
*sa = MIN(*sa, color->alpha);
180
ROperatePixel(RImage *image, int operation, int x, int y, RColor *color)
186
assert(x >= 0 && x < image->width);
187
assert(y >= 0 && y < image->height);
189
ofs = y*image->width + x;
191
operatePixel(image, ofs, operation, color);
196
RPutPixels(RImage *image, RPoint *points, int npoints, int mode, RColor *color)
198
register int x, y, i;
201
assert(points!=NULL);
205
for (i=0; i<npoints; i++) {
206
if (mode == RAbsoluteCoordinates) {
213
RPutPixel(image, x, y, color);
219
ROperatePixels(RImage *image, int operation, RPoint *points, int npoints,
220
int mode, RColor *color)
222
register int x, y, i;
225
assert(points!=NULL);
229
for (i=0; i<npoints; i++) {
230
if (mode == RAbsoluteCoordinates) {
237
ROperatePixel(image, operation, x, y, color);
243
clipLineInRectangle(int xmin, int ymin, int xmax, int ymax,
244
int *x1, int *y1, int *x2, int *y2)
250
#define CHECK_OUT(X,Y) (((Y) > ymax ? TOP : ((Y) < ymin ? BOT : 0))\
251
| ((X) > xmax ? RIG : ((X) < xmin ? LEF : 0)))
253
int ocode1, ocode2, ocode;
257
ocode1 = CHECK_OUT(*x1, *y1);
258
ocode2 = CHECK_OUT(*x2, *y2);
261
if (!ocode1 && !ocode2) { /* completely inside */
264
} else if (ocode1 & ocode2) {
274
x = *x1 + (*x2 - *x1) * (ymax - *y1) / (*y2 - *y1);
276
} else if (ocode & BOT) {
277
x = *x1 + (*x2 - *x1) * (ymin - *y1) / (*y2 - *y1);
279
} else if (ocode & RIG) {
280
y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1);
282
} else { /* //if (ocode & LEF) { */
283
y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1);
287
if (ocode == ocode1) {
290
ocode1 = CHECK_OUT(x, y);
294
ocode2 = CHECK_OUT(x, y);
303
* This routine is a generic drawing routine, based on Bresenham's line
307
genericLine(RImage *image, int x0, int y0, int x1, int y1, RColor *color,
308
int operation, int polyline)
310
int i, err, du, dv, du2, dv2, uofs, vofs, last;
314
if (!clipLineInRectangle(0, 0, image->width-1, image->height-1,
330
vofs = -image->width;
334
/* Swap coordinates between them, so that always du>dv */
335
i = du; du = dv; dv = i;
336
i = uofs; uofs = vofs; vofs = i;
342
last = (polyline) ? du-1 : du;
344
if (color->alpha==255 || operation==RCopyOperation) {
347
if (image->format == RRGBAFormat)
348
i = (y0*image->width + x0) * 4;
350
i = (y0*image->width + x0) * 3;
351
ptr = image->data + i;
353
for (i=0; i<=last; i++) {
356
*(ptr+1) = color->green;
357
*(ptr+2) = color->blue;
358
if (image->format == RRGBAFormat)
361
/* Compute error for NeXT Step */
364
if (image->format == RRGBAFormat)
370
if (image->format == RRGBAFormat)
376
register int ofs = y0*image->width + x0;
378
for (i=0; i<=last; i++) {
380
operatePixel(image, ofs, operation, color);
382
/* Compute error for NeXT Step */
393
if (mode == RALTER_PIXELS) {
394
RColorOffset *cdelta = (RColorOffset*)cdata;
395
register short r, g, b, a;
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;
414
/* Compute error for NeXT Step */
417
sr += vofs; sg += vofs;
418
sb += vofs; sa += vofs;
421
sr += uofs; sg += uofs;
422
sb += uofs; sa += uofs;
425
RColor *color = (RColor*)cdata;
427
if (color->alpha==255) {
428
for (i=0; i<=last; i++) {
436
/* Compute error for NeXT Step */
439
sr += vofs; sg += vofs;
440
sb += vofs; sa += vofs;
443
sr += uofs; sg += uofs;
444
sb += uofs; sa += uofs;
447
register short alpha, nalpha, r, g ,b;
449
alpha = color->alpha;
450
nalpha = 255 - alpha;
455
for (i=0; i<=last; i++) {
457
*sr = (((int)*sr * nalpha) + (r * alpha))/256;
458
*sg = (((int)*sg * nalpha) + (g * alpha))/256;
459
*sb = (((int)*sb * nalpha) + (b * alpha))/256;
461
*sa = alpha + ((int)*sa * nalpha)/256;
463
/* Compute error for NeXT Step */
466
sr += vofs; sg += vofs;
467
sb += vofs; sa += vofs;
470
sr += uofs; sg += uofs;
471
sb += uofs; sa += uofs;
481
RDrawLine(RImage *image, int x0, int y0, int x1, int y1, RColor *color)
483
return genericLine(image, x0, y0, x1, y1, color, RNormalOperation, False);
488
ROperateLine(RImage *image, int operation, int x0, int y0, int x1,
489
int y1, RColor *color)
491
return genericLine(image, x0, y0, x1, y1, color, operation, False);
496
RDrawLines(RImage *image, RPoint *points, int npoints, int mode, RColor *color)
498
register int x1, y1, x2, y2, i;
500
assert(points!=NULL);
509
for (i=1; i<npoints-1; i++) {
510
if (mode == RAbsoluteCoordinates) {
517
/* Don't draw pixels at junction points twice */
518
genericLine(image, x1, y1, x2, y2, color, RNormalOperation, True);
522
i = npoints-1; /* last point */
523
if (mode == RAbsoluteCoordinates) {
530
i = (points[0].x==x2 && points[0].y==y2 && npoints>1);
531
genericLine(image, x1, y1, x2, y2, color, RNormalOperation, i);
536
ROperateLines(RImage *image, int operation, RPoint *points,
537
int npoints, int mode, RColor *color)
539
register int x1, y1, x2, y2, i;
541
assert(points!=NULL);
550
for (i=1; i<npoints-1; i++) {
551
if (mode == RAbsoluteCoordinates) {
558
/* Don't draw pixels at junction points twice */
559
genericLine(image, x1, y1, x2, y2, color, operation, True);
563
i = npoints-1; /* last point */
564
if (mode == RAbsoluteCoordinates) {
571
i = (points[0].x==x2 && points[0].y==y2 && npoints>1);
572
genericLine(image, x1, y1, x2, y2, color, operation, i);
577
RDrawSegments(RImage *image, RSegment *segs, int nsegs, RColor *color)
583
for (i=0; i<nsegs; i++) {
584
genericLine(image, segs->x1, segs->y1, segs->x2, segs->y2, color,
585
RNormalOperation, False);
592
ROperateSegments(RImage *image, int operation, RSegment *segs,
593
int nsegs, RColor *color)
599
for (i=0; i<nsegs; i++) {
600
genericLine(image, segs->x1, segs->y1, segs->x2, segs->y2, color,