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 * This routine is a generic drawing routine, based on Bresenham's line
240 genericLine(RImage
*image
, int x0
, int y0
, int x1
, int y1
, RColor
*color
,
241 int operation
, int polyline
)
243 int i
, err
, du
, dv
, du2
, dv2
, uofs
, vofs
, last
;
246 assert(x0
>= 0 && x0
<= image
->width
);
247 assert(x1
>= 0 && x1
<= image
->width
);
248 assert(y0
>= 0 && y0
<= image
->height
);
249 assert(y1
>= 0 && y1
<= image
->height
);
263 vofs
= -image
->width
;
267 /* Swap coordinates between them, so that always du>dv */
268 i
= du
; du
= dv
; dv
= i
;
269 i
= uofs
; uofs
= vofs
; vofs
= i
;
275 last
= (polyline
) ? du
-1 : du
;
277 if (color
->alpha
==255 || operation
==RCopyOperation
) {
278 unsigned char *sr
, *sg
, *sb
, *sa
;
280 i
= y0
*image
->width
+ x0
;
281 sr
= image
->data
[0] + i
;
282 sg
= image
->data
[1] + i
;
283 sb
= image
->data
[2] + i
;
284 sa
= image
->data
[3] + i
;
286 for (i
=0; i
<=last
; i
++) {
294 /* Compute error for NeXT Step */
297 sr
+= vofs
; sg
+= vofs
;
298 sb
+= vofs
; sa
+= vofs
;
301 sr
+= uofs
; sg
+= uofs
;
302 sb
+= uofs
; sa
+= uofs
;
305 register int ofs
= y0
*image
->width
+ x0
;
307 for (i
=0; i
<=last
; i
++) {
309 operatePixel(image
, ofs
, operation
, color
);
311 /* Compute error for NeXT Step */
322 if (mode
== RALTER_PIXELS
) {
323 RColorOffset
*cdelta
= (RColorOffset
*)cdata
;
324 register short r
, g
, b
, a
;
326 for (i
=0; i
<=last
; i
++) {
327 /* Change the pixel with offset */
328 r
= (short)*sr
+ cdelta
->red
;
329 g
= (short)*sg
+ cdelta
->green
;
330 b
= (short)*sb
+ cdelta
->blue
;
331 if (r
>255) r
= 255; else if (r
<0) r
= 0;
332 if (g
>255) g
= 255; else if (g
<0) g
= 0;
333 if (b
>255) b
= 255; else if (b
<0) b
= 0;
334 *sr
= (unsigned char) r
;
335 *sg
= (unsigned char) g
;
336 *sb
= (unsigned char) b
;
337 if (image
->data
[3]) {
338 a
= (short)*sa
+ cdelta
->alpha
;
339 if (a
>255) a
= 255; else if (a
<0) a
= 0;
340 *sa
= (unsigned char) a
;
343 /* Compute error for NeXT Step */
346 sr
+= vofs
; sg
+= vofs
;
347 sb
+= vofs
; sa
+= vofs
;
350 sr
+= uofs
; sg
+= uofs
;
351 sb
+= uofs
; sa
+= uofs
;
354 RColor
*color
= (RColor
*)cdata
;
356 if (color
->alpha
==255) {
357 for (i
=0; i
<=last
; i
++) {
365 /* Compute error for NeXT Step */
368 sr
+= vofs
; sg
+= vofs
;
369 sb
+= vofs
; sa
+= vofs
;
372 sr
+= uofs
; sg
+= uofs
;
373 sb
+= uofs
; sa
+= uofs
;
376 register short alpha
, nalpha
, r
, g
,b
;
378 alpha
= color
->alpha
;
379 nalpha
= 255 - alpha
;
384 for (i
=0; i
<=last
; i
++) {
386 *sr
= (((int)*sr
* nalpha
) + (r
* alpha
))/256;
387 *sg
= (((int)*sg
* nalpha
) + (g
* alpha
))/256;
388 *sb
= (((int)*sb
* nalpha
) + (b
* alpha
))/256;
390 *sa
= alpha
+ ((int)*sa
* nalpha
)/256;
392 /* Compute error for NeXT Step */
395 sr
+= vofs
; sg
+= vofs
;
396 sb
+= vofs
; sa
+= vofs
;
399 sr
+= uofs
; sg
+= uofs
;
400 sb
+= uofs
; sa
+= uofs
;
410 RDrawLine(RImage
*image
, int x0
, int y0
, int x1
, int y1
, RColor
*color
)
412 return genericLine(image
, x0
, y0
, x1
, y1
, color
, RNormalOperation
, False
);
417 ROperateLine(RImage
*image
, int operation
, int x0
, int y0
, int x1
,
418 int y1
, RColor
*color
)
420 return genericLine(image
, x0
, y0
, x1
, y1
, color
, operation
, False
);
425 RDrawLines(RImage
*image
, RPoint
*points
, int npoints
, int mode
, RColor
*color
)
427 register int x1
, y1
, x2
, y2
, i
;
429 assert(points
!=NULL
);
438 for (i
=1; i
<npoints
-1; i
++) {
439 if (mode
== RAbsoluteCoordinates
) {
446 /* Don't draw pixels at junction points twice */
447 genericLine(image
, x1
, y1
, x2
, y2
, color
, RNormalOperation
, True
);
451 i
= npoints
-1; /* last point */
452 if (mode
== RAbsoluteCoordinates
) {
459 i
= (points
[0].x
==x2
&& points
[0].y
==y2
&& npoints
>1);
460 genericLine(image
, x1
, y1
, x2
, y2
, color
, RNormalOperation
, i
);
465 ROperateLines(RImage
*image
, int operation
, RPoint
*points
,
466 int npoints
, int mode
, RColor
*color
)
468 register int x1
, y1
, x2
, y2
, i
;
470 assert(points
!=NULL
);
479 for (i
=1; i
<npoints
-1; i
++) {
480 if (mode
== RAbsoluteCoordinates
) {
487 /* Don't draw pixels at junction points twice */
488 genericLine(image
, x1
, y1
, x2
, y2
, color
, operation
, True
);
492 i
= npoints
-1; /* last point */
493 if (mode
== RAbsoluteCoordinates
) {
500 i
= (points
[0].x
==x2
&& points
[0].y
==y2
&& npoints
>1);
501 genericLine(image
, x1
, y1
, x2
, y2
, color
, operation
, i
);
506 RDrawSegments(RImage
*image
, RSegment
*segs
, int nsegs
, RColor
*color
)
512 for (i
=0; i
<nsegs
; i
++) {
513 genericLine(image
, segs
->x1
, segs
->y1
, segs
->x2
, segs
->y2
, color
,
514 RNormalOperation
, False
);
521 ROperateSegments(RImage
*image
, int operation
, RSegment
*segs
,
522 int nsegs
, RColor
*color
)
528 for (i
=0; i
<nsegs
; i
++) {
529 genericLine(image
, segs
->x1
, segs
->y1
, segs
->x2
, segs
->y2
, color
,