Update Serbian translation from master branch
[wmaker-crm.git] / wrlib / draw.c
blob49992600b638c0a62999dbd5d5812ef7d27e9321
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., 51 Franklin St, Fifth Floor, Boston,
21 * MA 02110-1301, USA.
24 #include <config.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <assert.h>
30 #include "wraster.h"
31 #include "wr_i18n.h"
34 #define MIN(a,b) ((a) < (b) ? (a) : (b))
35 #define MAX(a,b) ((a) > (b) ? (a) : (b))
38 * Returns the color of the pixel at coordinates (x, y) in "color".
40 Bool RGetPixel(RImage * image, int x, int y, RColor * color)
42 int ofs;
44 assert(image != NULL);
45 if (x < 0 || x >= image->width || y < 0 || y >= image->height)
46 return False;
48 if (image->format == RRGBAFormat) {
49 ofs = (y * image->width + x) * 4;
50 color->red = image->data[ofs++];
51 color->green = image->data[ofs++];
52 color->blue = image->data[ofs++];
53 color->alpha = image->data[ofs];
54 } else {
55 ofs = (y * image->width + x) * 3;
56 color->red = image->data[ofs++];
57 color->green = image->data[ofs++];
58 color->blue = image->data[ofs];
59 /* If the image does not have alpha channel, we consider alpha 255 */
60 color->alpha = 255;
63 return True;
66 void RPutPixel(RImage *image, int x, int y, const RColor *color)
68 unsigned char *ptr;
70 assert(image != NULL);
71 assert(color != NULL);
72 if (x < 0 || x >= image->width || y < 0 || y >= image->height)
73 return;
75 if (image->format == RRGBAFormat) {
76 ptr = image->data + (y * image->width + x) * 4;
77 } else {
78 ptr = image->data + (y * image->width + x) * 3;
81 if (color->alpha == 255) {
82 *ptr++ = color->red;
83 *ptr++ = color->green;
84 *ptr++ = color->blue;
85 if (image->format == RRGBAFormat) {
86 *ptr = 255;
88 } else {
89 register int alpha, nalpha, r, g, b;
91 r = color->red;
92 g = color->green;
93 b = color->blue;
94 alpha = color->alpha;
95 nalpha = 255 - alpha;
97 *ptr = (((int)*ptr * nalpha) + (r * alpha)) / 256;
98 ptr++;
99 *ptr = (((int)*ptr * nalpha) + (g * alpha)) / 256;
100 ptr++;
101 *ptr = (((int)*ptr * nalpha) + (b * alpha)) / 256;
102 ptr++;
103 if (image->format == RRGBAFormat) {
104 *ptr = alpha + ((int)*ptr * nalpha) / 256;
109 static void operatePixel(RImage *image, int ofs, RPixelOperation operation, const RColor *color)
111 unsigned char *sr, *sg, *sb, *sa;
112 register int alpha, nalpha, tmp;
113 int hasAlpha = image->format == RRGBAFormat;
115 alpha = color->alpha;
116 nalpha = 255 - alpha;
118 sr = image->data + ofs * (hasAlpha ? 4 : 3);
119 sg = image->data + ofs * (hasAlpha ? 4 : 3) + 1;
120 sb = image->data + ofs * (hasAlpha ? 4 : 3) + 2;
121 sa = image->data + ofs * (hasAlpha ? 4 : 3) + 3;
123 switch (operation) {
124 case RClearOperation:
125 *sr = 0;
126 *sg = 0;
127 *sb = 0;
128 if (hasAlpha)
129 *sa = 0;
130 break;
131 case RCopyOperation:
132 *sr = color->red;
133 *sg = color->green;
134 *sb = color->blue;
135 if (hasAlpha)
136 *sa = color->alpha;
137 break;
138 case RNormalOperation:
139 if (color->alpha == 255) {
140 *sr = color->red;
141 *sg = color->green;
142 *sb = color->blue;
143 if (hasAlpha)
144 *sa = 255;
145 } else {
146 *sr = (((int)*sr * nalpha) + ((int)color->red * alpha)) / 256;
147 *sg = (((int)*sg * nalpha) + ((int)color->green * alpha)) / 256;
148 *sb = (((int)*sb * nalpha) + ((int)color->blue * alpha)) / 256;
149 *sa = alpha + ((int)*sa * nalpha) / 256;
151 break;
152 case RAddOperation:
153 tmp = color->red + *sr;
154 *sr = MIN(255, tmp);
155 tmp = color->green + *sg;
156 *sg = MIN(255, tmp);
157 tmp = color->blue + *sb;
158 *sb = MIN(255, tmp);
159 if (hasAlpha)
160 *sa = MIN(*sa, color->alpha);
161 break;
162 case RSubtractOperation:
163 tmp = *sr - color->red;
164 *sr = MAX(0, tmp);
165 tmp = *sg - color->green;
166 *sg = MAX(0, tmp);
167 tmp = *sb - color->blue;
168 *sb = MAX(0, tmp);
169 if (hasAlpha)
170 *sa = MIN(*sa, color->alpha);
171 break;
175 void ROperatePixel(RImage *image, RPixelOperation operation, int x, int y, const RColor *color)
177 int ofs;
179 assert(image != NULL);
180 assert(color != NULL);
181 assert(x >= 0 && x < image->width);
182 assert(y >= 0 && y < image->height);
184 ofs = y * image->width + x;
186 operatePixel(image, ofs, operation, color);
189 void RPutPixels(RImage *image, const RPoint *points, int npoints, RCoordinatesMode mode, const 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);
210 void ROperatePixels(RImage *image, RPixelOperation operation,
211 const RPoint *points, int npoints, RCoordinatesMode mode,
212 const RColor *color)
214 register int x, y, i;
216 assert(image != NULL);
217 assert(points != NULL);
219 x = y = 0;
221 for (i = 0; i < npoints; i++) {
222 if (mode == RAbsoluteCoordinates) {
223 x = points[i].x;
224 y = points[i].y;
225 } else {
226 x += points[i].x;
227 y += points[i].y;
229 ROperatePixel(image, operation, x, y, color);
233 static Bool clipLineInRectangle(int xmin, int ymin, int xmax, int ymax, int *x1, int *y1, int *x2, int *y2)
235 #define TOP (1<<0)
236 #define BOT (1<<1)
237 #define LEF (1<<2)
238 #define RIG (1<<3)
239 #define CHECK_OUT(X,Y) (((Y) > ymax ? TOP : ((Y) < ymin ? BOT : 0))\
240 | ((X) > xmax ? RIG : ((X) < xmin ? LEF : 0)))
242 int ocode1, ocode2, ocode;
243 int accept = 0;
244 int x, y;
246 ocode1 = CHECK_OUT(*x1, *y1);
247 ocode2 = CHECK_OUT(*x2, *y2);
249 for (;;) {
250 if (!ocode1 && !ocode2) { /* completely inside */
251 accept = 1;
252 break;
253 } else if (ocode1 & ocode2) {
254 break;
257 if (ocode1)
258 ocode = ocode1;
259 else
260 ocode = ocode2;
262 if (ocode & TOP) {
263 x = *x1 + (*x2 - *x1) * (ymax - *y1) / (*y2 - *y1);
264 y = ymax;
265 } else if (ocode & BOT) {
266 x = *x1 + (*x2 - *x1) * (ymin - *y1) / (*y2 - *y1);
267 y = ymin;
268 } else if (ocode & RIG) {
269 y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1);
270 x = xmax;
271 } else { /* //if (ocode & LEF) { */
272 y = *y1 + (*y2 - *y1) * (xmax - *x1) / (*x2 - *x1);
273 x = xmin;
276 if (ocode == ocode1) {
277 *x1 = x;
278 *y1 = y;
279 ocode1 = CHECK_OUT(x, y);
280 } else {
281 *x2 = x;
282 *y2 = y;
283 ocode2 = CHECK_OUT(x, y);
287 return accept;
291 * This routine is a generic drawing routine, based on Bresenham's line
292 * drawing algorithm.
294 static int genericLine(RImage *image, int x0, int y0, int x1, int y1, const RColor *color,
295 RPixelOperation operation, int polyline)
297 int i, err, du, dv, du2, dv2, uofs, vofs, last;
299 assert(image != NULL);
301 if (!clipLineInRectangle(0, 0, image->width - 1, image->height - 1, &x0, &y0, &x1, &y1))
302 return True;
304 if (x0 < x1) {
305 du = x1 - x0;
306 uofs = 1;
307 } else {
308 du = x0 - x1;
309 uofs = -1;
311 if (y0 < y1) {
312 dv = y1 - y0;
313 vofs = image->width;
314 } else {
315 dv = y0 - y1;
316 vofs = -image->width;
319 if (du < dv) {
320 /* Swap coordinates between them, so that always du>dv */
321 i = du;
322 du = dv;
323 dv = i;
324 i = uofs;
325 uofs = vofs;
326 vofs = i;
329 err = 0;
330 du2 = du << 1;
331 dv2 = dv << 1;
332 last = (polyline) ? du - 1 : du;
334 if (color->alpha == 255 || operation == RCopyOperation) {
335 unsigned char *ptr;
337 if (image->format == RRGBAFormat)
338 i = (y0 * image->width + x0) * 4;
339 else
340 i = (y0 * image->width + x0) * 3;
341 ptr = image->data + i;
343 for (i = 0; i <= last; i++) {
344 /* Draw the pixel */
345 *ptr = color->red;
346 *(ptr + 1) = color->green;
347 *(ptr + 2) = color->blue;
348 if (image->format == RRGBAFormat)
349 *(ptr + 3) = 255;
351 /* Compute error for NeXT Step */
352 err += dv2;
353 if (err >= du) {
354 if (image->format == RRGBAFormat)
355 ptr += vofs * 4;
356 else
357 ptr += vofs * 3;
358 err -= du2;
360 if (image->format == RRGBAFormat)
361 ptr += uofs * 4;
362 else
363 ptr += uofs * 3;
365 } else {
366 register int ofs = y0 * image->width + x0;
368 for (i = 0; i <= last; i++) {
369 /* Draw the pixel */
370 operatePixel(image, ofs, operation, color);
372 /* Compute error for NeXT Step */
373 err += dv2;
374 if (err >= du) {
375 ofs += vofs;
376 err -= du2;
378 ofs += uofs;
382 return True;
385 int RDrawLine(RImage * image, int x0, int y0, int x1, int y1, const RColor * color)
387 return genericLine(image, x0, y0, x1, y1, color, RNormalOperation, False);
390 int ROperateLine(RImage *image, RPixelOperation operation, int x0, int y0, int x1, int y1, const RColor *color)
392 return genericLine(image, x0, y0, x1, y1, color, operation, False);
395 void RDrawLines(RImage *image, const RPoint *points, int npoints, RCoordinatesMode mode, const RColor *color)
397 register int x1, y1, x2, y2, i;
399 assert(points != NULL);
401 if (npoints == 0)
402 return;
404 x1 = points[0].x;
405 y1 = points[0].y;
406 x2 = y2 = 0;
408 for (i = 1; i < npoints - 1; i++) {
409 if (mode == RAbsoluteCoordinates) {
410 x2 = points[i].x;
411 y2 = points[i].y;
412 } else {
413 x2 += points[i - 1].x;
414 y2 += points[i - 1].y;
416 /* Don't draw pixels at junction points twice */
417 genericLine(image, x1, y1, x2, y2, color, RNormalOperation, True);
418 x1 = x2;
419 y1 = y2;
421 i = npoints - 1; /* last point */
422 if (mode == RAbsoluteCoordinates) {
423 x2 = points[i].x;
424 y2 = points[i].y;
425 } else {
426 x2 += points[i - 1].x;
427 y2 += points[i - 1].y;
429 i = (points[0].x == x2 && points[0].y == y2 && npoints > 1);
430 genericLine(image, x1, y1, x2, y2, color, RNormalOperation, i);
433 void ROperateLines(RImage *image, RPixelOperation operation,
434 const RPoint *points, int npoints, RCoordinatesMode mode,
435 const RColor *color)
437 register int x1, y1, x2, y2, i;
439 assert(points != NULL);
441 if (npoints == 0)
442 return;
444 x1 = points[0].x;
445 y1 = points[0].y;
446 x2 = y2 = 0;
448 for (i = 1; i < npoints - 1; i++) {
449 if (mode == RAbsoluteCoordinates) {
450 x2 = points[i].x;
451 y2 = points[i].y;
452 } else {
453 x2 += points[i - 1].x;
454 y2 += points[i - 1].y;
456 /* Don't draw pixels at junction points twice */
457 genericLine(image, x1, y1, x2, y2, color, operation, True);
458 x1 = x2;
459 y1 = y2;
461 i = npoints - 1; /* last point */
462 if (mode == RAbsoluteCoordinates) {
463 x2 = points[i].x;
464 y2 = points[i].y;
465 } else {
466 x2 += points[i - 1].x;
467 y2 += points[i - 1].y;
469 i = (points[0].x == x2 && points[0].y == y2 && npoints > 1);
470 genericLine(image, x1, y1, x2, y2, color, operation, i);
473 void ROperateRectangle(RImage *image, RPixelOperation operation, int x0, int y0, int x1, int y1, const RColor *color)
475 int y;
477 for (y = y0; y <= y1; y++) {
478 genericLine(image, x0, y, x1, y, color, operation, False);
482 void RDrawSegments(RImage *image, const RSegment *segs, int nsegs, const RColor *color)
484 register int i;
486 assert(segs != NULL);
488 for (i = 0; i < nsegs; i++) {
489 genericLine(image, segs->x1, segs->y1, segs->x2, segs->y2, color, RNormalOperation, False);
490 segs++;
494 void ROperateSegments(RImage *image, RPixelOperation operation, const RSegment *segs, int nsegs, const RColor *color)
496 register int i;
498 assert(segs != NULL);
500 for (i = 0; i < nsegs; i++) {
501 genericLine(image, segs->x1, segs->y1, segs->x2, segs->y2, color, operation, False);
502 segs++;