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.
31 #define MIN(a,b) ((a) < (b) ? (a) : (b))
32 #define MAX(a,b) ((a) > (b) ? (a) : (b))
35 * Returns the color of the pixel at coordinates (x, y) in "color".
37 Bool
RGetPixel(RImage
* image
, int x
, int y
, RColor
* color
)
41 assert(image
!= NULL
);
42 if (x
< 0 || x
>= image
->width
|| y
< 0 || y
>= image
->height
)
45 if (image
->format
== RRGBAFormat
) {
46 ofs
= (y
* image
->width
+ x
) * 4;
47 color
->red
= image
->data
[ofs
++];
48 color
->green
= image
->data
[ofs
++];
49 color
->blue
= image
->data
[ofs
++];
50 color
->alpha
= image
->data
[ofs
];
52 ofs
= (y
* image
->width
+ x
) * 3;
53 color
->red
= image
->data
[ofs
++];
54 color
->green
= image
->data
[ofs
++];
55 color
->blue
= image
->data
[ofs
];
56 /* If the image does not have alpha channel, we consider alpha 255 */
63 void RPutPixel(RImage
* image
, int x
, int y
, RColor
* color
)
67 assert(image
!= NULL
);
68 assert(color
!= NULL
);
69 if (x
< 0 || x
>= image
->width
|| y
< 0 || y
>= image
->height
)
72 if (image
->format
== RRGBAFormat
) {
73 ptr
= image
->data
+ (y
* image
->width
+ x
) * 4;
75 ptr
= image
->data
+ (y
* image
->width
+ x
) * 3;
78 if (color
->alpha
== 255) {
80 *ptr
++ = color
->green
;
82 if (image
->format
== RRGBAFormat
) {
86 register int alpha
, nalpha
, r
, g
, b
;
94 *ptr
= (((int)*ptr
* nalpha
) + (r
* alpha
)) / 256;
96 *ptr
= (((int)*ptr
* nalpha
) + (g
* alpha
)) / 256;
98 *ptr
= (((int)*ptr
* nalpha
) + (b
* alpha
)) / 256;
100 if (image
->format
== RRGBAFormat
) {
101 *ptr
= alpha
+ ((int)*ptr
* nalpha
) / 256;
106 static void operatePixel(RImage
* image
, int ofs
, int operation
, RColor
* color
)
108 unsigned char *sr
, *sg
, *sb
, *sa
;
109 register int alpha
, nalpha
, tmp
;
110 int hasAlpha
= image
->format
== RRGBAFormat
;
112 alpha
= color
->alpha
;
113 nalpha
= 255 - alpha
;
115 sr
= image
->data
+ ofs
* (hasAlpha
? 4 : 3);
116 sg
= image
->data
+ ofs
* (hasAlpha
? 4 : 3) + 1;
117 sb
= image
->data
+ ofs
* (hasAlpha
? 4 : 3) + 2;
118 sa
= image
->data
+ ofs
* (hasAlpha
? 4 : 3) + 3;
121 case RClearOperation
:
135 case RNormalOperation
:
136 if (color
->alpha
== 255) {
143 *sr
= (((int)*sr
* nalpha
) + ((int)color
->red
* alpha
)) / 256;
144 *sg
= (((int)*sg
* nalpha
) + ((int)color
->green
* alpha
)) / 256;
145 *sb
= (((int)*sb
* nalpha
) + ((int)color
->blue
* alpha
)) / 256;
149 tmp
= color
->red
+ *sr
;
151 tmp
= color
->green
+ *sg
;
153 tmp
= color
->blue
+ *sb
;
156 *sa
= MIN(*sa
, color
->alpha
);
158 case RSubtractOperation
:
159 tmp
= *sr
- color
->red
;
161 tmp
= *sg
- color
->green
;
163 tmp
= *sb
- color
->blue
;
166 *sa
= MIN(*sa
, color
->alpha
);
171 void ROperatePixel(RImage
* image
, int operation
, int x
, int y
, RColor
* color
)
175 assert(image
!= NULL
);
176 assert(color
!= NULL
);
177 assert(x
>= 0 && x
< image
->width
);
178 assert(y
>= 0 && y
< image
->height
);
180 ofs
= y
* image
->width
+ x
;
182 operatePixel(image
, ofs
, operation
, color
);
185 void RPutPixels(RImage
* image
, RPoint
* points
, int npoints
, int mode
, RColor
* color
)
187 register int x
, y
, i
;
189 assert(image
!= NULL
);
190 assert(points
!= NULL
);
194 for (i
= 0; i
< npoints
; i
++) {
195 if (mode
== RAbsoluteCoordinates
) {
202 RPutPixel(image
, x
, y
, color
);
206 void ROperatePixels(RImage
* image
, int operation
, RPoint
* points
, int npoints
, int mode
, RColor
* color
)
208 register int x
, y
, i
;
210 assert(image
!= NULL
);
211 assert(points
!= NULL
);
215 for (i
= 0; i
< npoints
; i
++) {
216 if (mode
== RAbsoluteCoordinates
) {
223 ROperatePixel(image
, operation
, x
, y
, color
);
227 static Bool
clipLineInRectangle(int xmin
, int ymin
, int xmax
, int ymax
, int *x1
, int *y1
, int *x2
, int *y2
)
233 #define CHECK_OUT(X,Y) (((Y) > ymax ? TOP : ((Y) < ymin ? BOT : 0))\
234 | ((X) > xmax ? RIG : ((X) < xmin ? LEF : 0)))
236 int ocode1
, ocode2
, ocode
;
240 ocode1
= CHECK_OUT(*x1
, *y1
);
241 ocode2
= CHECK_OUT(*x2
, *y2
);
244 if (!ocode1
&& !ocode2
) { /* completely inside */
247 } else if (ocode1
& ocode2
) {
257 x
= *x1
+ (*x2
- *x1
) * (ymax
- *y1
) / (*y2
- *y1
);
259 } else if (ocode
& BOT
) {
260 x
= *x1
+ (*x2
- *x1
) * (ymin
- *y1
) / (*y2
- *y1
);
262 } else if (ocode
& RIG
) {
263 y
= *y1
+ (*y2
- *y1
) * (xmax
- *x1
) / (*x2
- *x1
);
265 } else { /* //if (ocode & LEF) { */
266 y
= *y1
+ (*y2
- *y1
) * (xmax
- *x1
) / (*x2
- *x1
);
270 if (ocode
== ocode1
) {
273 ocode1
= CHECK_OUT(x
, y
);
277 ocode2
= CHECK_OUT(x
, y
);
285 * This routine is a generic drawing routine, based on Bresenham's line
288 static int genericLine(RImage
* image
, int x0
, int y0
, int x1
, int y1
, RColor
* color
, int operation
, int polyline
)
290 int i
, err
, du
, dv
, du2
, dv2
, uofs
, vofs
, last
;
292 assert(image
!= NULL
);
294 if (!clipLineInRectangle(0, 0, image
->width
- 1, image
->height
- 1, &x0
, &y0
, &x1
, &y1
))
309 vofs
= -image
->width
;
313 /* Swap coordinates between them, so that always du>dv */
325 last
= (polyline
) ? du
- 1 : du
;
327 if (color
->alpha
== 255 || operation
== RCopyOperation
) {
330 if (image
->format
== RRGBAFormat
)
331 i
= (y0
* image
->width
+ x0
) * 4;
333 i
= (y0
* image
->width
+ x0
) * 3;
334 ptr
= image
->data
+ i
;
336 for (i
= 0; i
<= last
; i
++) {
339 *(ptr
+ 1) = color
->green
;
340 *(ptr
+ 2) = color
->blue
;
341 if (image
->format
== RRGBAFormat
)
344 /* Compute error for NeXT Step */
347 if (image
->format
== RRGBAFormat
)
353 if (image
->format
== RRGBAFormat
)
359 register int ofs
= y0
* image
->width
+ x0
;
361 for (i
= 0; i
<= last
; i
++) {
363 operatePixel(image
, ofs
, operation
, color
);
365 /* Compute error for NeXT Step */
376 if (mode
== RALTER_PIXELS
) {
377 RColorOffset
*cdelta
= (RColorOffset
*) cdata
;
378 register short r
, g
, b
, a
;
380 for (i
= 0; i
<= last
; i
++) {
381 /* Change the pixel with offset */
382 r
= (short)*sr
+ cdelta
->red
;
383 g
= (short)*sg
+ cdelta
->green
;
384 b
= (short)*sb
+ cdelta
->blue
;
397 *sr
= (unsigned char)r
;
398 *sg
= (unsigned char)g
;
399 *sb
= (unsigned char)b
;
400 if (image
->data
[3]) {
401 a
= (short)*sa
+ cdelta
->alpha
;
406 *sa
= (unsigned char)a
;
409 /* Compute error for NeXT Step */
424 RColor
*color
= (RColor
*) cdata
;
426 if (color
->alpha
== 255) {
427 for (i
= 0; i
<= last
; i
++) {
435 /* Compute error for NeXT Step */
450 register short alpha
, nalpha
, r
, g
, b
;
452 alpha
= color
->alpha
;
453 nalpha
= 255 - alpha
;
458 for (i
= 0; i
<= last
; i
++) {
460 *sr
= (((int)*sr
* nalpha
) + (r
* alpha
)) / 256;
461 *sg
= (((int)*sg
* nalpha
) + (g
* alpha
)) / 256;
462 *sb
= (((int)*sb
* nalpha
) + (b
* alpha
)) / 256;
464 *sa
= alpha
+ ((int)*sa
* nalpha
) / 256;
466 /* Compute error for NeXT Step */
486 int RDrawLine(RImage
* image
, int x0
, int y0
, int x1
, int y1
, RColor
* color
)
488 return genericLine(image
, x0
, y0
, x1
, y1
, color
, RNormalOperation
, False
);
491 int ROperateLine(RImage
* image
, int operation
, int x0
, int y0
, int x1
, int y1
, RColor
* color
)
493 return genericLine(image
, x0
, y0
, x1
, y1
, color
, operation
, False
);
496 void 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
) {
514 x2
+= points
[i
- 1].x
;
515 y2
+= points
[i
- 1].y
;
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
) {
527 x2
+= points
[i
- 1].x
;
528 y2
+= points
[i
- 1].y
;
530 i
= (points
[0].x
== x2
&& points
[0].y
== y2
&& npoints
> 1);
531 genericLine(image
, x1
, y1
, x2
, y2
, color
, RNormalOperation
, i
);
534 void ROperateLines(RImage
* image
, int operation
, RPoint
* points
, int npoints
, int mode
, RColor
* color
)
536 register int x1
, y1
, x2
, y2
, i
;
538 assert(points
!= NULL
);
547 for (i
= 1; i
< npoints
- 1; i
++) {
548 if (mode
== RAbsoluteCoordinates
) {
552 x2
+= points
[i
- 1].x
;
553 y2
+= points
[i
- 1].y
;
555 /* Don't draw pixels at junction points twice */
556 genericLine(image
, x1
, y1
, x2
, y2
, color
, operation
, True
);
560 i
= npoints
- 1; /* last point */
561 if (mode
== RAbsoluteCoordinates
) {
565 x2
+= points
[i
- 1].x
;
566 y2
+= points
[i
- 1].y
;
568 i
= (points
[0].x
== x2
&& points
[0].y
== y2
&& npoints
> 1);
569 genericLine(image
, x1
, y1
, x2
, y2
, color
, operation
, i
);
572 void RDrawSegments(RImage
* image
, RSegment
* segs
, int nsegs
, RColor
* color
)
576 assert(segs
!= NULL
);
578 for (i
= 0; i
< nsegs
; i
++) {
579 genericLine(image
, segs
->x1
, segs
->y1
, segs
->x2
, segs
->y2
, color
, RNormalOperation
, False
);
584 void ROperateSegments(RImage
* image
, int operation
, RSegment
* segs
, int nsegs
, RColor
* color
)
588 assert(segs
!= NULL
);
590 for (i
= 0; i
< nsegs
; i
++) {
591 genericLine(image
, segs
->x1
, segs
->y1
, segs
->x2
, segs
->y2
, color
, operation
, False
);