updated translations and image files for WINGs, bug fixes in WINGs
[wmaker-crm.git] / wrlib / draw.c
blobbbcc9c129c11873b613547687f78730e4cd9f316
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);
235 static Bool
236 clipLineInRectangle(int xmin, int ymin, int xmax, int ymax,
237 int *x1, int *y1, int *x2, int *y2)
239 #define TOP (1<<0)
240 #define BOT (1<<1)
241 #define LEF (1<<2)
242 #define RIG (1<<3)
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;
247 int accept = 0;
248 int x, y;
250 ocode1 = CHECK_OUT(*x1, *y1);
251 ocode2 = CHECK_OUT(*x2, *y2);
253 for(;;) {
254 if (!ocode1 && !ocode2) { /* completely inside */
255 accept = 1;
256 break;
257 } else if (ocode1 & ocode2) {
258 break;
261 if (ocode1)
262 ocode = ocode1;
263 else
264 ocode = ocode2;
266 if (ocode & TOP) {
267 x = *x1 + (*x2 - *x1) * (ymax - *y1) / (*y2 - *y1);
268 y = ymax;
269 } else if (ocode & BOT) {
270 x = *x1 + (*x2 - *x1) * (ymin - *y1) / (*y2 - *y1);
271 y = ymin;
272 } else if (ocode & RIG) {
273 y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1);
274 x = xmax;
275 } else if (ocode & LEF) {
276 y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1);
277 x = xmin;
280 if (ocode == ocode1) {
281 *x1 = x;
282 *y1 = y;
283 ocode1 = CHECK_OUT(x, y);
284 } else {
285 *x2 = x;
286 *y2 = y;
287 ocode2 = CHECK_OUT(x, y);
291 return accept;
296 * This routine is a generic drawing routine, based on Bresenham's line
297 * drawing algorithm.
299 static int
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;
305 assert(image!=NULL);
307 if (!clipLineInRectangle(0, 0, image->width-1, image->height-1,
308 &x0, &y0, &x1, &y1))
309 return True;
311 if (x0 < x1) {
312 du = x1 - x0;
313 uofs = 1;
314 } else {
315 du = x0 - x1;
316 uofs = -1;
318 if (y0 < y1) {
319 dv = y1 -y0;
320 vofs = image->width;
321 } else {
322 dv = y0 - y1;
323 vofs = -image->width;
326 if (du < dv) {
327 /* Swap coordinates between them, so that always du>dv */
328 i = du; du = dv; dv = i;
329 i = uofs; uofs = vofs; vofs = i;
332 err = 0;
333 du2 = du<<1;
334 dv2 = dv<<1;
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++) {
347 /* Draw the pixel */
348 *sr = color->red;
349 *sg = color->green;
350 *sb = color->blue;
351 if (image->data[3])
352 *sa = 255;
354 /* Compute error for NeXT Step */
355 err += dv2;
356 if (err >= du) {
357 sr += vofs; sg += vofs;
358 sb += vofs; sa += vofs;
359 err -= du2;
361 sr += uofs; sg += uofs;
362 sb += uofs; sa += uofs;
364 } else {
365 register int ofs = y0*image->width + x0;
367 for (i=0; i<=last; i++) {
368 /* Draw the pixel */
369 operatePixel(image, ofs, operation, color);
371 /* Compute error for NeXT Step */
372 err += dv2;
373 if (err >= du) {
374 ofs += vofs;
375 err -= du2;
377 ofs += uofs;
381 #if 0
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 */
404 err += dv2;
405 if (err >= du) {
406 sr += vofs; sg += vofs;
407 sb += vofs; sa += vofs;
408 err -= du2;
410 sr += uofs; sg += uofs;
411 sb += uofs; sa += uofs;
413 } else {
414 RColor *color = (RColor*)cdata;
416 if (color->alpha==255) {
417 for (i=0; i<=last; i++) {
418 /* Draw the pixel */
419 *sr = color->red;
420 *sg = color->green;
421 *sb = color->blue;
422 if (image->data[3])
423 *sa = 255;
425 /* Compute error for NeXT Step */
426 err += dv2;
427 if (err >= du) {
428 sr += vofs; sg += vofs;
429 sb += vofs; sa += vofs;
430 err -= du2;
432 sr += uofs; sg += uofs;
433 sb += uofs; sa += uofs;
435 } else {
436 register short alpha, nalpha, r, g ,b;
438 alpha = color->alpha;
439 nalpha = 255 - alpha;
440 r = color->red;
441 g = color->green;
442 b = color->blue;
444 for (i=0; i<=last; i++) {
445 /* Draw the pixel */
446 *sr = (((int)*sr * nalpha) + (r * alpha))/256;
447 *sg = (((int)*sg * nalpha) + (g * alpha))/256;
448 *sb = (((int)*sb * nalpha) + (b * alpha))/256;
449 if (image->data[3])
450 *sa = alpha + ((int)*sa * nalpha)/256;
452 /* Compute error for NeXT Step */
453 err += dv2;
454 if (err >= du) {
455 sr += vofs; sg += vofs;
456 sb += vofs; sa += vofs;
457 err -= du2;
459 sr += uofs; sg += uofs;
460 sb += uofs; sa += uofs;
464 #endif
465 return True;
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);
484 void
485 RDrawLines(RImage *image, RPoint *points, int npoints, int mode, RColor *color)
487 register int x1, y1, x2, y2, i;
489 assert(points!=NULL);
491 if (npoints==0)
492 return;
494 x1 = points[0].x;
495 y1 = points[0].y;
496 x2 = y2 = 0;
498 for (i=1; i<npoints-1; i++) {
499 if (mode == RAbsoluteCoordinates) {
500 x2 = points[i].x;
501 y2 = points[i].y;
502 } else {
503 x2 += points[i-1].x;
504 y2 += points[i-1].y;
506 /* Don't draw pixels at junction points twice */
507 genericLine(image, x1, y1, x2, y2, color, RNormalOperation, True);
508 x1 = x2;
509 y1 = y2;
511 i = npoints-1; /* last point */
512 if (mode == RAbsoluteCoordinates) {
513 x2 = points[i].x;
514 y2 = points[i].y;
515 } else {
516 x2 += points[i-1].x;
517 y2 += points[i-1].y;
519 i = (points[0].x==x2 && points[0].y==y2 && npoints>1);
520 genericLine(image, x1, y1, x2, y2, color, RNormalOperation, i);
524 void
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);
532 if (npoints==0)
533 return;
535 x1 = points[0].x;
536 y1 = points[0].y;
537 x2 = y2 = 0;
539 for (i=1; i<npoints-1; i++) {
540 if (mode == RAbsoluteCoordinates) {
541 x2 = points[i].x;
542 y2 = points[i].y;
543 } else {
544 x2 += points[i-1].x;
545 y2 += points[i-1].y;
547 /* Don't draw pixels at junction points twice */
548 genericLine(image, x1, y1, x2, y2, color, operation, True);
549 x1 = x2;
550 y1 = y2;
552 i = npoints-1; /* last point */
553 if (mode == RAbsoluteCoordinates) {
554 x2 = points[i].x;
555 y2 = points[i].y;
556 } else {
557 x2 += points[i-1].x;
558 y2 += points[i-1].y;
560 i = (points[0].x==x2 && points[0].y==y2 && npoints>1);
561 genericLine(image, x1, y1, x2, y2, color, operation, i);
565 void
566 RDrawSegments(RImage *image, RSegment *segs, int nsegs, RColor *color)
568 register int i;
570 assert(segs!=NULL);
572 for (i=0; i<nsegs; i++) {
573 genericLine(image, segs->x1, segs->y1, segs->x2, segs->y2, color,
574 RNormalOperation, False);
575 segs++;
580 void
581 ROperateSegments(RImage *image, int operation, RSegment *segs,
582 int nsegs, RColor *color)
584 register int i;
586 assert(segs!=NULL);
588 for (i=0; i<nsegs; i++) {
589 genericLine(image, segs->x1, segs->y1, segs->x2, segs->y2, color,
590 operation, False);
591 segs++;