1 /* draw.c - pixel plotting, line drawing
3 * Raster graphics library
5 * Copyright (c) 1998 Dan Pascu
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 #define MIN(a,b) ((a) < (b) ? (a) : (b))
32 #define MAX(a,b) ((a) > (b) ? (a) : (b))
37 * Returns the color of the pixel at coordinates (x, y) in "color".
40 RGetPixel(RImage
*image
, int x
, int y
, RColor
*color
)
45 if (x
< 0 || x
>= image
->width
46 || y
< 0 || y
>= image
->height
)
49 ofs
= y
*image
->width
+ x
;
50 color
->red
= image
->data
[0][ofs
];
51 color
->green
= image
->data
[1][ofs
];
52 color
->blue
= image
->data
[2][ofs
];
53 /* If the image does not have alpha channel, we consider alpha 255 */
55 color
->alpha
= image
->data
[3][ofs
];
64 RPutPixel(RImage
*image
, int x
, int y
, RColor
*color
)
67 unsigned char *sr
, *sg
, *sb
, *sa
;
71 if (x
< 0 || x
>= image
->width
|| y
< 0 || y
>= image
->height
)
74 ofs
= y
*image
->width
+ x
;
75 sr
= image
->data
[0] + ofs
;
76 sg
= image
->data
[1] + ofs
;
77 sb
= image
->data
[2] + ofs
;
78 sa
= image
->data
[3] + ofs
;
80 if (color
->alpha
==255) {
87 register int alpha
, nalpha
, r
, g
, b
;
95 *sr
= (((int)*sr
* nalpha
) + (r
* alpha
))/256;
96 *sg
= (((int)*sg
* nalpha
) + (g
* alpha
))/256;
97 *sb
= (((int)*sb
* nalpha
) + (b
* alpha
))/256;
99 *sa
= alpha
+ ((int)*sa
* nalpha
)/256;
105 operatePixel(RImage
*image
, int ofs
, int operation
, RColor
*color
)
107 unsigned char *sr
, *sg
, *sb
, *sa
;
108 register int alpha
, nalpha
, tmp
;
109 int hasAlpha
= image
->data
[3]!=NULL
;
111 alpha
= color
->alpha
;
112 nalpha
= 255 - alpha
;
114 sr
= image
->data
[0] + ofs
;
115 sg
= image
->data
[1] + ofs
;
116 sb
= image
->data
[2] + ofs
;
117 sa
= image
->data
[3] + ofs
;
120 case RClearOperation
:
134 case RNormalOperation
:
135 if (color
->alpha
==255) {
142 *sr
= (((int)*sr
* nalpha
) + ((int)color
->red
* alpha
))/256;
143 *sg
= (((int)*sg
* nalpha
) + ((int)color
->green
* alpha
))/256;
144 *sb
= (((int)*sb
* nalpha
) + ((int)color
->blue
* alpha
))/256;
148 tmp
= color
->red
+ *sr
;
150 tmp
= color
->green
+ *sg
;
152 tmp
= color
->blue
+ *sb
;
155 *sa
= MIN(*sa
, color
->alpha
);
157 case RSubtractOperation
:
158 tmp
= *sr
- color
->red
;
160 tmp
= *sg
- color
->green
;
162 tmp
= *sb
- color
->blue
;
165 *sa
= MIN(*sa
, color
->alpha
);
173 ROperatePixel(RImage
*image
, int operation
, int x
, int y
, RColor
*color
)
179 assert(x
>= 0 && x
< image
->width
);
180 assert(y
>= 0 && y
< image
->height
);
182 ofs
= y
*image
->width
+ x
;
184 operatePixel(image
, ofs
, operation
, color
);
189 RPutPixels(RImage
*image
, RPoint
*points
, int npoints
, int mode
, RColor
*color
)
191 register int x
, y
, i
;
194 assert(points
!=NULL
);
198 for (i
=0; i
<npoints
; i
++) {
199 if (mode
== RAbsoluteCoordinates
) {
206 RPutPixel(image
, x
, y
, color
);
212 ROperatePixels(RImage
*image
, int operation
, RPoint
*points
, int npoints
,
213 int mode
, RColor
*color
)
215 register int x
, y
, i
;
218 assert(points
!=NULL
);
222 for (i
=0; i
<npoints
; i
++) {
223 if (mode
== RAbsoluteCoordinates
) {
230 ROperatePixel(image
, operation
, x
, y
, color
);
236 clipLineInRectangle(int xmin
, int ymin
, int xmax
, int ymax
,
237 int *x1
, int *y1
, int *x2
, int *y2
)
243 #define CHECK_OUT(X,Y) (((Y) > ymax ? TOP : ((Y) < ymin ? BOT : 0))\
244 | ((X) > xmax ? RIG : ((X) < xmin ? LEF : 0)))
246 int ocode1
, ocode2
, ocode
;
250 ocode1
= CHECK_OUT(*x1
, *y1
);
251 ocode2
= CHECK_OUT(*x2
, *y2
);
254 if (!ocode1
&& !ocode2
) { /* completely inside */
257 } else if (ocode1
& ocode2
) {
267 x
= *x1
+ (*x2
- *x1
) * (ymax
- *y1
) / (*y2
- *y1
);
269 } else if (ocode
& BOT
) {
270 x
= *x1
+ (*x2
- *x1
) * (ymin
- *y1
) / (*y2
- *y1
);
272 } else if (ocode
& RIG
) {
273 y
= *y1
+ (*y2
- *y1
) * (xmax
- *x1
) / (*x2
- *x1
);
275 } else if (ocode
& LEF
) {
276 y
= *y1
+ (*y2
- *y1
) * (xmax
- *x1
) / (*x2
- *x1
);
280 if (ocode
== ocode1
) {
283 ocode1
= CHECK_OUT(x
, y
);
287 ocode2
= CHECK_OUT(x
, y
);
296 * This routine is a generic drawing routine, based on Bresenham's line
300 genericLine(RImage
*image
, int x0
, int y0
, int x1
, int y1
, RColor
*color
,
301 int operation
, int polyline
)
303 int i
, err
, du
, dv
, du2
, dv2
, uofs
, vofs
, last
;
307 if (!clipLineInRectangle(0, 0, image
->width
-1, image
->height
-1,
323 vofs
= -image
->width
;
327 /* Swap coordinates between them, so that always du>dv */
328 i
= du
; du
= dv
; dv
= i
;
329 i
= uofs
; uofs
= vofs
; vofs
= i
;
335 last
= (polyline
) ? du
-1 : du
;
337 if (color
->alpha
==255 || operation
==RCopyOperation
) {
338 unsigned char *sr
, *sg
, *sb
, *sa
;
340 i
= y0
*image
->width
+ x0
;
341 sr
= image
->data
[0] + i
;
342 sg
= image
->data
[1] + i
;
343 sb
= image
->data
[2] + i
;
344 sa
= image
->data
[3] + i
;
346 for (i
=0; i
<=last
; i
++) {
354 /* Compute error for NeXT Step */
357 sr
+= vofs
; sg
+= vofs
;
358 sb
+= vofs
; sa
+= vofs
;
361 sr
+= uofs
; sg
+= uofs
;
362 sb
+= uofs
; sa
+= uofs
;
365 register int ofs
= y0
*image
->width
+ x0
;
367 for (i
=0; i
<=last
; i
++) {
369 operatePixel(image
, ofs
, operation
, color
);
371 /* Compute error for NeXT Step */
382 if (mode
== RALTER_PIXELS
) {
383 RColorOffset
*cdelta
= (RColorOffset
*)cdata
;
384 register short r
, g
, b
, a
;
386 for (i
=0; i
<=last
; i
++) {
387 /* Change the pixel with offset */
388 r
= (short)*sr
+ cdelta
->red
;
389 g
= (short)*sg
+ cdelta
->green
;
390 b
= (short)*sb
+ cdelta
->blue
;
391 if (r
>255) r
= 255; else if (r
<0) r
= 0;
392 if (g
>255) g
= 255; else if (g
<0) g
= 0;
393 if (b
>255) b
= 255; else if (b
<0) b
= 0;
394 *sr
= (unsigned char) r
;
395 *sg
= (unsigned char) g
;
396 *sb
= (unsigned char) b
;
397 if (image
->data
[3]) {
398 a
= (short)*sa
+ cdelta
->alpha
;
399 if (a
>255) a
= 255; else if (a
<0) a
= 0;
400 *sa
= (unsigned char) a
;
403 /* Compute error for NeXT Step */
406 sr
+= vofs
; sg
+= vofs
;
407 sb
+= vofs
; sa
+= vofs
;
410 sr
+= uofs
; sg
+= uofs
;
411 sb
+= uofs
; sa
+= uofs
;
414 RColor
*color
= (RColor
*)cdata
;
416 if (color
->alpha
==255) {
417 for (i
=0; i
<=last
; i
++) {
425 /* Compute error for NeXT Step */
428 sr
+= vofs
; sg
+= vofs
;
429 sb
+= vofs
; sa
+= vofs
;
432 sr
+= uofs
; sg
+= uofs
;
433 sb
+= uofs
; sa
+= uofs
;
436 register short alpha
, nalpha
, r
, g
,b
;
438 alpha
= color
->alpha
;
439 nalpha
= 255 - alpha
;
444 for (i
=0; i
<=last
; i
++) {
446 *sr
= (((int)*sr
* nalpha
) + (r
* alpha
))/256;
447 *sg
= (((int)*sg
* nalpha
) + (g
* alpha
))/256;
448 *sb
= (((int)*sb
* nalpha
) + (b
* alpha
))/256;
450 *sa
= alpha
+ ((int)*sa
* nalpha
)/256;
452 /* Compute error for NeXT Step */
455 sr
+= vofs
; sg
+= vofs
;
456 sb
+= vofs
; sa
+= vofs
;
459 sr
+= uofs
; sg
+= uofs
;
460 sb
+= uofs
; sa
+= uofs
;
470 RDrawLine(RImage
*image
, int x0
, int y0
, int x1
, int y1
, RColor
*color
)
472 return genericLine(image
, x0
, y0
, x1
, y1
, color
, RNormalOperation
, False
);
477 ROperateLine(RImage
*image
, int operation
, int x0
, int y0
, int x1
,
478 int y1
, RColor
*color
)
480 return genericLine(image
, x0
, y0
, x1
, y1
, color
, operation
, False
);
485 RDrawLines(RImage
*image
, RPoint
*points
, int npoints
, int mode
, RColor
*color
)
487 register int x1
, y1
, x2
, y2
, i
;
489 assert(points
!=NULL
);
498 for (i
=1; i
<npoints
-1; i
++) {
499 if (mode
== RAbsoluteCoordinates
) {
506 /* Don't draw pixels at junction points twice */
507 genericLine(image
, x1
, y1
, x2
, y2
, color
, RNormalOperation
, True
);
511 i
= npoints
-1; /* last point */
512 if (mode
== RAbsoluteCoordinates
) {
519 i
= (points
[0].x
==x2
&& points
[0].y
==y2
&& npoints
>1);
520 genericLine(image
, x1
, y1
, x2
, y2
, color
, RNormalOperation
, i
);
525 ROperateLines(RImage
*image
, int operation
, RPoint
*points
,
526 int npoints
, int mode
, RColor
*color
)
528 register int x1
, y1
, x2
, y2
, i
;
530 assert(points
!=NULL
);
539 for (i
=1; i
<npoints
-1; i
++) {
540 if (mode
== RAbsoluteCoordinates
) {
547 /* Don't draw pixels at junction points twice */
548 genericLine(image
, x1
, y1
, x2
, y2
, color
, operation
, True
);
552 i
= npoints
-1; /* last point */
553 if (mode
== RAbsoluteCoordinates
) {
560 i
= (points
[0].x
==x2
&& points
[0].y
==y2
&& npoints
>1);
561 genericLine(image
, x1
, y1
, x2
, y2
, color
, operation
, i
);
566 RDrawSegments(RImage
*image
, RSegment
*segs
, int nsegs
, RColor
*color
)
572 for (i
=0; i
<nsegs
; i
++) {
573 genericLine(image
, segs
->x1
, segs
->y1
, segs
->x2
, segs
->y2
, color
,
574 RNormalOperation
, False
);
581 ROperateSegments(RImage
*image
, int operation
, RSegment
*segs
,
582 int nsegs
, RColor
*color
)
588 for (i
=0; i
<nsegs
; i
++) {
589 genericLine(image
, segs
->x1
, segs
->y1
, segs
->x2
, segs
->y2
, color
,