1 /* draw.c - pixel plotting, line drawing
3 * Raster graphics library
5 * Copyright (c) 1998 Dan Pascu
6 * Copyright (c) 2000 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
,