*** empty log message ***
[wmaker-crm.git] / wrlib / draw.c
blobfc2df6627ac91ce53a4bb9a7b481eeb635da6a55
1 /* draw.c - pixel plotting, line drawing
2 *
3 * Raster graphics library
4 *
5 * Copyright (c) 1998 Dan Pascu
6 * Copyright (c) 2000 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.
23 #include <config.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <assert.h>
29 #include "wraster.h"
32 #define MIN(a,b) ((a) < (b) ? (a) : (b))
33 #define MAX(a,b) ((a) > (b) ? (a) : (b))
38 * Returns the color of the pixel at coordinates (x, y) in "color".
40 Bool
41 RGetPixel(RImage *image, int x, int y, RColor *color)
43 int ofs;
45 assert(image!=NULL);
46 if (x < 0 || x >= image->width
47 || y < 0 || y >= image->height)
48 return False;
50 if (image->format == RRGBAFormat) {
51 ofs = (y*image->width + x) * 4;
52 color->red = image->data[ofs];
53 color->green = image->data[ofs++];
54 color->blue = image->data[ofs++];
55 color->alpha = image->data[ofs];
56 } else {
57 ofs = (y*image->width + x) * 3;
58 color->red = image->data[ofs++];
59 color->green = image->data[ofs++];
60 color->blue = image->data[ofs++];
61 /* If the image does not have alpha channel, we consider alpha 255 */
62 color->alpha = 255;
65 return True;
69 void
70 RPutPixel(RImage *image, int x, int y, RColor *color)
72 unsigned char *ptr;
74 assert(image!=NULL);
75 assert(color!=NULL);
76 if (x < 0 || x >= image->width || y < 0 || y >= image->height)
77 return;
79 if (image->format == RRGBAFormat) {
80 ptr = image->data + (y*image->width + x) * 4;
81 } else {
82 ptr = image->data + (y*image->width + x) * 3;
85 if (color->alpha==255) {
86 *ptr++ = color->red;
87 *ptr++ = color->green;
88 *ptr++ = color->blue;
89 if (image->format == RRGBAFormat) {
90 *ptr = 255;
92 } else {
93 register int alpha, nalpha, r, g, b;
95 r = color->red;
96 g = color->green;
97 b = color->blue;
98 alpha = color->alpha;
99 nalpha = 255 - alpha;
101 *ptr++ = (((int)*ptr * nalpha) + (r * alpha))/256;
102 *ptr++ = (((int)*ptr * nalpha) + (g * alpha))/256;
103 *ptr++ = (((int)*ptr * nalpha) + (b * alpha))/256;
104 if (image->format == RRGBAFormat) {
105 *ptr = alpha + ((int)*ptr * nalpha)/256;
111 static void
112 operatePixel(RImage *image, int ofs, int operation, RColor *color)
114 unsigned char *sr, *sg, *sb, *sa;
115 register int alpha, nalpha, tmp;
116 int hasAlpha = image->format == RRGBAFormat;
118 alpha = color->alpha;
119 nalpha = 255 - alpha;
121 sr = image->data + ofs*(hasAlpha ? 4 : 3);
122 sg = image->data + ofs*(hasAlpha ? 4 : 3) + 1;
123 sb = image->data + ofs*(hasAlpha ? 4 : 3) + 2;
124 sa = image->data + ofs*(hasAlpha ? 4 : 3) + 3;
126 switch (operation) {
127 case RClearOperation:
128 *sr = 0;
129 *sg = 0;
130 *sb = 0;
131 if (hasAlpha)
132 *sa = 0;
133 break;
134 case RCopyOperation:
135 *sr = color->red;
136 *sg = color->green;
137 *sb = color->blue;
138 if (hasAlpha)
139 *sa = color->alpha;
140 break;
141 case RNormalOperation:
142 if (color->alpha==255) {
143 *sr = color->red;
144 *sg = color->green;
145 *sb = color->blue;
146 if (hasAlpha)
147 *sa = 255;
148 } else {
149 *sr = (((int)*sr * nalpha) + ((int)color->red * alpha))/256;
150 *sg = (((int)*sg * nalpha) + ((int)color->green * alpha))/256;
151 *sb = (((int)*sb * nalpha) + ((int)color->blue * alpha))/256;
153 break;
154 case RAddOperation:
155 tmp = color->red + *sr;
156 *sr = MIN(255, tmp);
157 tmp = color->green + *sg;
158 *sg = MIN(255, tmp);
159 tmp = color->blue + *sb;
160 *sb = MIN(255, tmp);
161 if (hasAlpha)
162 *sa = MIN(*sa, color->alpha);
163 break;
164 case RSubtractOperation:
165 tmp = *sr - color->red;
166 *sr = MAX(0, tmp);
167 tmp = *sg - color->green;
168 *sg = MAX(0, tmp);
169 tmp = *sb - color->blue;
170 *sb = MAX(0, tmp);
171 if (hasAlpha)
172 *sa = MIN(*sa, color->alpha);
173 break;
179 void
180 ROperatePixel(RImage *image, int operation, int x, int y, RColor *color)
182 int ofs;
184 assert(image!=NULL);
185 assert(color!=NULL);
186 assert(x >= 0 && x < image->width);
187 assert(y >= 0 && y < image->height);
189 ofs = y*image->width + x;
191 operatePixel(image, ofs, operation, color);
195 void
196 RPutPixels(RImage *image, RPoint *points, int npoints, int mode, RColor *color)
198 register int x, y, i;
200 assert(image!=NULL);
201 assert(points!=NULL);
203 x = y = 0;
205 for (i=0; i<npoints; i++) {
206 if (mode == RAbsoluteCoordinates) {
207 x = points[i].x;
208 y = points[i].y;
209 } else {
210 x += points[i].x;
211 y += points[i].y;
213 RPutPixel(image, x, y, color);
218 void
219 ROperatePixels(RImage *image, int operation, RPoint *points, int npoints,
220 int mode, RColor *color)
222 register int x, y, i;
224 assert(image!=NULL);
225 assert(points!=NULL);
227 x = y = 0;
229 for (i=0; i<npoints; i++) {
230 if (mode == RAbsoluteCoordinates) {
231 x = points[i].x;
232 y = points[i].y;
233 } else {
234 x += points[i].x;
235 y += points[i].y;
237 ROperatePixel(image, operation, x, y, color);
242 static Bool
243 clipLineInRectangle(int xmin, int ymin, int xmax, int ymax,
244 int *x1, int *y1, int *x2, int *y2)
246 #define TOP (1<<0)
247 #define BOT (1<<1)
248 #define LEF (1<<2)
249 #define RIG (1<<3)
250 #define CHECK_OUT(X,Y) (((Y) > ymax ? TOP : ((Y) < ymin ? BOT : 0))\
251 | ((X) > xmax ? RIG : ((X) < xmin ? LEF : 0)))
253 int ocode1, ocode2, ocode;
254 int accept = 0;
255 int x, y;
257 ocode1 = CHECK_OUT(*x1, *y1);
258 ocode2 = CHECK_OUT(*x2, *y2);
260 for(;;) {
261 if (!ocode1 && !ocode2) { /* completely inside */
262 accept = 1;
263 break;
264 } else if (ocode1 & ocode2) {
265 break;
268 if (ocode1)
269 ocode = ocode1;
270 else
271 ocode = ocode2;
273 if (ocode & TOP) {
274 x = *x1 + (*x2 - *x1) * (ymax - *y1) / (*y2 - *y1);
275 y = ymax;
276 } else if (ocode & BOT) {
277 x = *x1 + (*x2 - *x1) * (ymin - *y1) / (*y2 - *y1);
278 y = ymin;
279 } else if (ocode & RIG) {
280 y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1);
281 x = xmax;
282 } else if (ocode & LEF) {
283 y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1);
284 x = xmin;
287 if (ocode == ocode1) {
288 *x1 = x;
289 *y1 = y;
290 ocode1 = CHECK_OUT(x, y);
291 } else {
292 *x2 = x;
293 *y2 = y;
294 ocode2 = CHECK_OUT(x, y);
298 return accept;
303 * This routine is a generic drawing routine, based on Bresenham's line
304 * drawing algorithm.
306 static int
307 genericLine(RImage *image, int x0, int y0, int x1, int y1, RColor *color,
308 int operation, int polyline)
310 int i, err, du, dv, du2, dv2, uofs, vofs, last;
312 assert(image!=NULL);
314 if (!clipLineInRectangle(0, 0, image->width-1, image->height-1,
315 &x0, &y0, &x1, &y1))
316 return True;
318 if (x0 < x1) {
319 du = x1 - x0;
320 uofs = 1;
321 } else {
322 du = x0 - x1;
323 uofs = -1;
325 if (y0 < y1) {
326 dv = y1 -y0;
327 vofs = image->width;
328 } else {
329 dv = y0 - y1;
330 vofs = -image->width;
333 if (du < dv) {
334 /* Swap coordinates between them, so that always du>dv */
335 i = du; du = dv; dv = i;
336 i = uofs; uofs = vofs; vofs = i;
339 err = 0;
340 du2 = du<<1;
341 dv2 = dv<<1;
342 last = (polyline) ? du-1 : du;
344 if (color->alpha==255 || operation==RCopyOperation) {
345 unsigned char *ptr;
347 if (image->format == RRGBAFormat)
348 i = (y0*image->width + x0) * 4;
349 else
350 i = (y0*image->width + x0) * 3;
351 ptr = image->data + i;
353 for (i=0; i<=last; i++) {
354 /* Draw the pixel */
355 *ptr = color->red;
356 *(ptr+1) = color->green;
357 *(ptr+2) = color->blue;
358 if (image->format == RRGBAFormat)
359 *(ptr+3) = 255;
361 /* Compute error for NeXT Step */
362 err += dv2;
363 if (err >= du) {
364 if (image->format == RRGBAFormat)
365 ptr += vofs*4;
366 else
367 ptr += vofs*3;
368 err -= du2;
370 if (image->format == RRGBAFormat)
371 ptr += uofs*4;
372 else
373 ptr += uofs*3;
375 } else {
376 register int ofs = y0*image->width + x0;
378 for (i=0; i<=last; i++) {
379 /* Draw the pixel */
380 operatePixel(image, ofs, operation, color);
382 /* Compute error for NeXT Step */
383 err += dv2;
384 if (err >= du) {
385 ofs += vofs;
386 err -= du2;
388 ofs += uofs;
392 #if 0
393 if (mode == RALTER_PIXELS) {
394 RColorOffset *cdelta = (RColorOffset*)cdata;
395 register short r, g, b, a;
397 for (i=0; i<=last; i++) {
398 /* Change the pixel with offset */
399 r = (short)*sr + cdelta->red;
400 g = (short)*sg + cdelta->green;
401 b = (short)*sb + cdelta->blue;
402 if (r>255) r = 255; else if (r<0) r = 0;
403 if (g>255) g = 255; else if (g<0) g = 0;
404 if (b>255) b = 255; else if (b<0) b = 0;
405 *sr = (unsigned char) r;
406 *sg = (unsigned char) g;
407 *sb = (unsigned char) b;
408 if (image->data[3]) {
409 a = (short)*sa + cdelta->alpha;
410 if (a>255) a = 255; else if (a<0) a = 0;
411 *sa = (unsigned char) a;
414 /* Compute error for NeXT Step */
415 err += dv2;
416 if (err >= du) {
417 sr += vofs; sg += vofs;
418 sb += vofs; sa += vofs;
419 err -= du2;
421 sr += uofs; sg += uofs;
422 sb += uofs; sa += uofs;
424 } else {
425 RColor *color = (RColor*)cdata;
427 if (color->alpha==255) {
428 for (i=0; i<=last; i++) {
429 /* Draw the pixel */
430 *sr = color->red;
431 *sg = color->green;
432 *sb = color->blue;
433 if (image->data[3])
434 *sa = 255;
436 /* Compute error for NeXT Step */
437 err += dv2;
438 if (err >= du) {
439 sr += vofs; sg += vofs;
440 sb += vofs; sa += vofs;
441 err -= du2;
443 sr += uofs; sg += uofs;
444 sb += uofs; sa += uofs;
446 } else {
447 register short alpha, nalpha, r, g ,b;
449 alpha = color->alpha;
450 nalpha = 255 - alpha;
451 r = color->red;
452 g = color->green;
453 b = color->blue;
455 for (i=0; i<=last; i++) {
456 /* Draw the pixel */
457 *sr = (((int)*sr * nalpha) + (r * alpha))/256;
458 *sg = (((int)*sg * nalpha) + (g * alpha))/256;
459 *sb = (((int)*sb * nalpha) + (b * alpha))/256;
460 if (image->data[3])
461 *sa = alpha + ((int)*sa * nalpha)/256;
463 /* Compute error for NeXT Step */
464 err += dv2;
465 if (err >= du) {
466 sr += vofs; sg += vofs;
467 sb += vofs; sa += vofs;
468 err -= du2;
470 sr += uofs; sg += uofs;
471 sb += uofs; sa += uofs;
475 #endif
476 return True;
481 RDrawLine(RImage *image, int x0, int y0, int x1, int y1, RColor *color)
483 return genericLine(image, x0, y0, x1, y1, color, RNormalOperation, False);
488 ROperateLine(RImage *image, int operation, int x0, int y0, int x1,
489 int y1, RColor *color)
491 return genericLine(image, x0, y0, x1, y1, color, operation, False);
495 void
496 RDrawLines(RImage *image, RPoint *points, int npoints, int mode, RColor *color)
498 register int x1, y1, x2, y2, i;
500 assert(points!=NULL);
502 if (npoints==0)
503 return;
505 x1 = points[0].x;
506 y1 = points[0].y;
507 x2 = y2 = 0;
509 for (i=1; i<npoints-1; i++) {
510 if (mode == RAbsoluteCoordinates) {
511 x2 = points[i].x;
512 y2 = points[i].y;
513 } else {
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);
519 x1 = x2;
520 y1 = y2;
522 i = npoints-1; /* last point */
523 if (mode == RAbsoluteCoordinates) {
524 x2 = points[i].x;
525 y2 = points[i].y;
526 } else {
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);
535 void
536 ROperateLines(RImage *image, int operation, RPoint *points,
537 int npoints, int mode, RColor *color)
539 register int x1, y1, x2, y2, i;
541 assert(points!=NULL);
543 if (npoints==0)
544 return;
546 x1 = points[0].x;
547 y1 = points[0].y;
548 x2 = y2 = 0;
550 for (i=1; i<npoints-1; i++) {
551 if (mode == RAbsoluteCoordinates) {
552 x2 = points[i].x;
553 y2 = points[i].y;
554 } else {
555 x2 += points[i-1].x;
556 y2 += points[i-1].y;
558 /* Don't draw pixels at junction points twice */
559 genericLine(image, x1, y1, x2, y2, color, operation, True);
560 x1 = x2;
561 y1 = y2;
563 i = npoints-1; /* last point */
564 if (mode == RAbsoluteCoordinates) {
565 x2 = points[i].x;
566 y2 = points[i].y;
567 } else {
568 x2 += points[i-1].x;
569 y2 += points[i-1].y;
571 i = (points[0].x==x2 && points[0].y==y2 && npoints>1);
572 genericLine(image, x1, y1, x2, y2, color, operation, i);
576 void
577 RDrawSegments(RImage *image, RSegment *segs, int nsegs, RColor *color)
579 register int i;
581 assert(segs!=NULL);
583 for (i=0; i<nsegs; i++) {
584 genericLine(image, segs->x1, segs->y1, segs->x2, segs->y2, color,
585 RNormalOperation, False);
586 segs++;
591 void
592 ROperateSegments(RImage *image, int operation, RSegment *segs,
593 int nsegs, RColor *color)
595 register int i;
597 assert(segs!=NULL);
599 for (i=0; i<nsegs; i++) {
600 genericLine(image, segs->x1, segs->y1, segs->x2, segs->y2, color,
601 operation, False);
602 segs++;