Updating to version 0.20.2
[wmaker-crm.git] / wrlib / draw.c
blob89f5b955c1e099f636b00e6394a72f1e30b6d98e
1 /* draw.c - pixel plotting, line drawing
2 *
3 * Raster graphics library
4 *
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.
22 #include <config.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <assert.h>
28 #include "wraster.h"
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".
39 Bool
40 RGetPixel(RImage *image, int x, int y, RColor *color)
42 int ofs;
44 assert(image!=NULL);
45 if (x < 0 || x >= image->width
46 || y < 0 || y >= image->height)
47 return False;
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 */
54 if (image->data[3])
55 color->alpha = image->data[3][ofs];
56 else
57 color->alpha = 255;
59 return True;
63 void
64 RPutPixel(RImage *image, int x, int y, RColor *color)
66 int ofs;
67 unsigned char *sr, *sg, *sb, *sa;
69 assert(image!=NULL);
70 assert(color!=NULL);
71 if (x < 0 || x >= image->width || y < 0 || y >= image->height)
72 return;
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) {
81 *sr = color->red;
82 *sg = color->green;
83 *sb = color->blue;
84 if (image->data[3])
85 *sa = 255;
86 } else {
87 register int alpha, nalpha, r, g, b;
89 r = color->red;
90 g = color->green;
91 b = color->blue;
92 alpha = color->alpha;
93 nalpha = 255 - alpha;
95 *sr = (((int)*sr * nalpha) + (r * alpha))/256;
96 *sg = (((int)*sg * nalpha) + (g * alpha))/256;
97 *sb = (((int)*sb * nalpha) + (b * alpha))/256;
98 if (image->data[3])
99 *sa = alpha + ((int)*sa * nalpha)/256;
104 static void
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;
119 switch (operation) {
120 case RClearOperation:
121 *sr = 0;
122 *sg = 0;
123 *sb = 0;
124 if (hasAlpha)
125 *sa = 0;
126 break;
127 case RCopyOperation:
128 *sr = color->red;
129 *sg = color->green;
130 *sb = color->blue;
131 if (hasAlpha)
132 *sa = color->alpha;
133 break;
134 case RNormalOperation:
135 if (color->alpha==255) {
136 *sr = color->red;
137 *sg = color->green;
138 *sb = color->blue;
139 if (hasAlpha)
140 *sa = 255;
141 } else {
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;
146 break;
147 case RAddOperation:
148 tmp = color->red + *sr;
149 *sr = MIN(255, tmp);
150 tmp = color->green + *sg;
151 *sg = MIN(255, tmp);
152 tmp = color->blue + *sb;
153 *sb = MIN(255, tmp);
154 if (hasAlpha)
155 *sa = MIN(*sa, color->alpha);
156 break;
157 case RSubtractOperation:
158 tmp = *sr - color->red;
159 *sr = MAX(0, tmp);
160 tmp = *sg - color->green;
161 *sg = MAX(0, tmp);
162 tmp = *sb - color->blue;
163 *sb = MAX(0, tmp);
164 if (hasAlpha)
165 *sa = MIN(*sa, color->alpha);
166 break;
172 void
173 ROperatePixel(RImage *image, int operation, int x, int y, RColor *color)
175 int ofs;
177 assert(image!=NULL);
178 assert(color!=NULL);
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);
188 void
189 RPutPixels(RImage *image, RPoint *points, int npoints, int mode, RColor *color)
191 register int x, y, i;
193 assert(image!=NULL);
194 assert(points!=NULL);
196 x = y = 0;
198 for (i=0; i<npoints; i++) {
199 if (mode == RAbsoluteCoordinates) {
200 x = points[i].x;
201 y = points[i].y;
202 } else {
203 x += points[i].x;
204 y += points[i].y;
206 RPutPixel(image, x, y, color);
211 void
212 ROperatePixels(RImage *image, int operation, RPoint *points, int npoints,
213 int mode, RColor *color)
215 register int x, y, i;
217 assert(image!=NULL);
218 assert(points!=NULL);
220 x = y = 0;
222 for (i=0; i<npoints; i++) {
223 if (mode == RAbsoluteCoordinates) {
224 x = points[i].x;
225 y = points[i].y;
226 } else {
227 x += points[i].x;
228 y += points[i].y;
230 ROperatePixel(image, operation, x, y, color);
236 * This routine is a generic drawing routine, based on Bresenham's line
237 * drawing algorithm.
239 static int
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;
245 assert(image!=NULL);
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);
251 if (x0 < x1) {
252 du = x1 - x0;
253 uofs = 1;
254 } else {
255 du = x0 - x1;
256 uofs = -1;
258 if (y0 < y1) {
259 dv = y1 -y0;
260 vofs = image->width;
261 } else {
262 dv = y0 - y1;
263 vofs = -image->width;
266 if (du < dv) {
267 /* Swap coordinates between them, so that always du>dv */
268 i = du; du = dv; dv = i;
269 i = uofs; uofs = vofs; vofs = i;
272 err = 0;
273 du2 = du<<1;
274 dv2 = dv<<1;
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++) {
287 /* Draw the pixel */
288 *sr = color->red;
289 *sg = color->green;
290 *sb = color->blue;
291 if (image->data[3])
292 *sa = 255;
294 /* Compute error for NeXT Step */
295 err += dv2;
296 if (err >= du) {
297 sr += vofs; sg += vofs;
298 sb += vofs; sa += vofs;
299 err -= du2;
301 sr += uofs; sg += uofs;
302 sb += uofs; sa += uofs;
304 } else {
305 register int ofs = y0*image->width + x0;
307 for (i=0; i<=last; i++) {
308 /* Draw the pixel */
309 operatePixel(image, ofs, operation, color);
311 /* Compute error for NeXT Step */
312 err += dv2;
313 if (err >= du) {
314 ofs += vofs;
315 err -= du2;
317 ofs += uofs;
321 #if 0
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 */
344 err += dv2;
345 if (err >= du) {
346 sr += vofs; sg += vofs;
347 sb += vofs; sa += vofs;
348 err -= du2;
350 sr += uofs; sg += uofs;
351 sb += uofs; sa += uofs;
353 } else {
354 RColor *color = (RColor*)cdata;
356 if (color->alpha==255) {
357 for (i=0; i<=last; i++) {
358 /* Draw the pixel */
359 *sr = color->red;
360 *sg = color->green;
361 *sb = color->blue;
362 if (image->data[3])
363 *sa = 255;
365 /* Compute error for NeXT Step */
366 err += dv2;
367 if (err >= du) {
368 sr += vofs; sg += vofs;
369 sb += vofs; sa += vofs;
370 err -= du2;
372 sr += uofs; sg += uofs;
373 sb += uofs; sa += uofs;
375 } else {
376 register short alpha, nalpha, r, g ,b;
378 alpha = color->alpha;
379 nalpha = 255 - alpha;
380 r = color->red;
381 g = color->green;
382 b = color->blue;
384 for (i=0; i<=last; i++) {
385 /* Draw the pixel */
386 *sr = (((int)*sr * nalpha) + (r * alpha))/256;
387 *sg = (((int)*sg * nalpha) + (g * alpha))/256;
388 *sb = (((int)*sb * nalpha) + (b * alpha))/256;
389 if (image->data[3])
390 *sa = alpha + ((int)*sa * nalpha)/256;
392 /* Compute error for NeXT Step */
393 err += dv2;
394 if (err >= du) {
395 sr += vofs; sg += vofs;
396 sb += vofs; sa += vofs;
397 err -= du2;
399 sr += uofs; sg += uofs;
400 sb += uofs; sa += uofs;
404 #endif
405 return True;
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);
424 void
425 RDrawLines(RImage *image, RPoint *points, int npoints, int mode, RColor *color)
427 register int x1, y1, x2, y2, i;
429 assert(points!=NULL);
431 if (npoints==0)
432 return;
434 x1 = points[0].x;
435 y1 = points[0].y;
436 x2 = y2 = 0;
438 for (i=1; i<npoints-1; i++) {
439 if (mode == RAbsoluteCoordinates) {
440 x2 = points[i].x;
441 y2 = points[i].y;
442 } else {
443 x2 += points[i-1].x;
444 y2 += points[i-1].y;
446 /* Don't draw pixels at junction points twice */
447 genericLine(image, x1, y1, x2, y2, color, RNormalOperation, True);
448 x1 = x2;
449 y1 = y2;
451 i = npoints-1; /* last point */
452 if (mode == RAbsoluteCoordinates) {
453 x2 = points[i].x;
454 y2 = points[i].y;
455 } else {
456 x2 += points[i-1].x;
457 y2 += points[i-1].y;
459 i = (points[0].x==x2 && points[0].y==y2 && npoints>1);
460 genericLine(image, x1, y1, x2, y2, color, RNormalOperation, i);
464 void
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);
472 if (npoints==0)
473 return;
475 x1 = points[0].x;
476 y1 = points[0].y;
477 x2 = y2 = 0;
479 for (i=1; i<npoints-1; i++) {
480 if (mode == RAbsoluteCoordinates) {
481 x2 = points[i].x;
482 y2 = points[i].y;
483 } else {
484 x2 += points[i-1].x;
485 y2 += points[i-1].y;
487 /* Don't draw pixels at junction points twice */
488 genericLine(image, x1, y1, x2, y2, color, operation, True);
489 x1 = x2;
490 y1 = y2;
492 i = npoints-1; /* last point */
493 if (mode == RAbsoluteCoordinates) {
494 x2 = points[i].x;
495 y2 = points[i].y;
496 } else {
497 x2 += points[i-1].x;
498 y2 += points[i-1].y;
500 i = (points[0].x==x2 && points[0].y==y2 && npoints>1);
501 genericLine(image, x1, y1, x2, y2, color, operation, i);
505 void
506 RDrawSegments(RImage *image, RSegment *segs, int nsegs, RColor *color)
508 register int i;
510 assert(segs!=NULL);
512 for (i=0; i<nsegs; i++) {
513 genericLine(image, segs->x1, segs->y1, segs->x2, segs->y2, color,
514 RNormalOperation, False);
515 segs++;
520 void
521 ROperateSegments(RImage *image, int operation, RSegment *segs,
522 int nsegs, RColor *color)
524 register int i;
526 assert(segs!=NULL);
528 for (i=0; i<nsegs; i++) {
529 genericLine(image, segs->x1, segs->y1, segs->x2, segs->y2, color,
530 operation, False);
531 segs++;