RCombineArea* will detect the intersec geometry.
[wmaker-crm.git] / wrlib / raster.c
blob8a8c635525b2da4d8bcf14872ade4b24e0ce83bf
1 /* raster.c - main and other misc stuff
2 *
3 * Raster graphics library
4 *
5 * Copyright (c) 1997-2000 Alfredo K. Kojima
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 <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <X11/Xlib.h>
28 #include "wraster.h"
30 #include <assert.h>
33 char *WRasterLibVersion="0.9";
35 int RErrorCode=RERR_NONE;
38 #define HAS_ALPHA(I) ((I)->format == RRGBAFormat)
41 RImage*
42 RCreateImage(unsigned width, unsigned height, int alpha)
44 RImage *image=NULL;
46 assert(width>0 && height>0);
48 image = malloc(sizeof(RImage));
49 if (!image) {
50 RErrorCode = RERR_NOMEMORY;
51 return NULL;
54 memset(image, 0, sizeof(RImage));
55 image->width = width;
56 image->height = height;
57 if (alpha) {
58 image->format = RRGBAFormat;
59 } else {
60 image->format = RRGBFormat;
62 /* the +4 is to give extra bytes at the end of the buffer,
63 * so that we can optimize image conversion for MMX(tm).. see convert.c
65 image->data = malloc(width * height * (alpha ? 4 : 3) + 4);
66 if (!image->data) {
67 RErrorCode = RERR_NOMEMORY;
68 free(image);
69 image = NULL;
72 return image;
77 RImage*
78 RCloneImage(RImage *image)
80 RImage *new_image;
82 assert(image!=NULL);
84 new_image = RCreateImage(image->width, image->height, HAS_ALPHA(image));
85 if (!new_image)
86 return NULL;
88 new_image->background = image->background;
89 memcpy(new_image->data, image->data,
90 image->width*image->height*(HAS_ALPHA(image) ? 4 : 3));
92 return new_image;
96 RImage*
97 RGetSubImage(RImage *image, int x, int y, unsigned width, unsigned height)
99 int i, ofs;
100 RImage *new_image;
101 unsigned total_line_size, line_size;
103 assert(image!=NULL);
104 assert(x>=0 && y>=0);
105 assert(x<image->width && y<image->height);
106 assert(width>0 && height>0);
108 if (x+width > image->width)
109 width = image->width-x;
110 if (y+height > image->height)
111 height = image->height-y;
113 new_image = RCreateImage(width, height, HAS_ALPHA(image));
115 if (!new_image)
116 return NULL;
117 new_image->background = image->background;
119 total_line_size = image->width * (HAS_ALPHA(image) ? 4 : 3);
120 line_size = width * (HAS_ALPHA(image) ? 4 : 3);
122 ofs = x*(HAS_ALPHA(image) ? 4 : 3) + y*total_line_size;;
124 for (i=0; i<height; i++) {
125 memcpy(&new_image->data[i*line_size],
126 &image->data[i*total_line_size+ofs], line_size);
128 return new_image;
132 void
133 RDestroyImage(RImage *image)
135 assert(image!=NULL);
137 free(image->data);
138 free(image);
143 *----------------------------------------------------------------------
144 * RCombineImages-
145 * Combines two equal sized images with alpha image. The second
146 * image will be placed on top of the first one.
147 *----------------------------------------------------------------------
149 void
150 RCombineImages(RImage *image, RImage *src)
152 assert(image->width == src->width);
153 assert(image->height == src->height);
155 if (!HAS_ALPHA(src)) {
156 if (!HAS_ALPHA(image)) {
157 memcpy(image->data, src->data, image->height*image->width*3);
158 } else {
159 int x, y;
160 unsigned char *d, *s;
162 d = image->data;
163 s = src->data;
164 for (y = 0; y < image->height; y++) {
165 for (x = 0; x < image->width; x++) {
166 *d++ = *s++;
167 *d++ = *s++;
168 *d++ = *s++;
169 d++;
173 } else {
174 register int i;
175 unsigned char *d;
176 unsigned char *s;
177 int alpha, calpha;
179 d = image->data;
180 s = src->data;
182 if (!HAS_ALPHA(image)) {
183 for (i=0; i<image->height*image->width; i++) {
184 alpha = *(s+3);
185 calpha = 255 - alpha;
186 *d = (((int)*d * calpha) + ((int)*s * alpha))/256;
187 d++; s++;
188 *d = (((int)*d * calpha) + ((int)*s * alpha))/256;
189 d++; s++;
190 *d = (((int)*d * calpha) + ((int)*s * alpha))/256;
191 d++; s++;
192 s++;
194 } else {
195 for (i=0; i<image->height*image->width; i++) {
196 alpha = *(s+3);
197 calpha = 255 - alpha;
198 *d = (((int)*d * calpha) + ((int)*s * alpha))/256;
199 d++; s++;
200 *d = (((int)*d * calpha) + ((int)*s * alpha))/256;
201 d++; s++;
202 *d = (((int)*d * calpha) + ((int)*s * alpha))/256;
203 d++; s++;
204 *d++ |= *s++;
213 void
214 RCombineImagesWithOpaqueness(RImage *image, RImage *src, int opaqueness)
216 register int i;
217 unsigned char *d;
218 unsigned char *s;
219 int c_opaqueness;
221 assert(image->width == src->width);
222 assert(image->height == src->height);
224 d = image->data;
225 s = src->data;
227 c_opaqueness = 255 - opaqueness;
228 #define OP opaqueness
229 if (!HAS_ALPHA(src)) {
230 int dalpha = HAS_ALPHA(image);
231 #define COP c_opaqueness
232 for (i=0; i < image->width*image->height; i++) {
233 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256;
234 d++; s++;
235 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256;
236 d++; s++;
237 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256;
238 d++; s++;
239 if (dalpha) {
240 d++;
243 #undef COP
244 } else {
245 int tmp;
247 if (!HAS_ALPHA(image)) {
248 for (i=0; i<image->width*image->height; i++) {
249 tmp = (*(s+3) * opaqueness)/256;
250 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256;
251 d++; s++;
252 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256;
253 d++; s++;
254 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256;
255 d++; s++;
256 s++;
258 } else {
259 for (i=0; i<image->width*image->height; i++) {
260 tmp = (*(s+3) * opaqueness)/256;
261 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256;
262 d++; s++;
263 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256;
264 d++; s++;
265 *d = (((int)*d * (255-tmp)) + ((int)*s * tmp))/256;
266 d++; s++;
267 *d |= tmp;
268 d++; s++;
272 #undef OP
276 calculateCombineArea(RImage *des, RImage *src,
277 int *sx, int *sy,
278 int *swidth, int *sheight,
279 int *dx, int *dy) {
281 if (*dx < 0) {
282 *sx = -*dx;
283 *swidth = *swidth + *dx;
284 *dx = 0;
287 if (*dx + *swidth > des->width) {
288 *swidth = des->width - *dx;
291 if (*dy < 0) {
292 *sy = -*dy;
293 *sheight = *sheight + *dy;
294 *dy = 0;
297 if (*dy + *sheight > des->height) {
298 *sheight = des->height - *dy;
301 if (*sheight > 0 && *swidth > 0) {
302 return True;
303 } else return False;
306 void
307 RCombineArea(RImage *image, RImage *src, int sx, int sy, unsigned width,
308 unsigned height, int dx, int dy)
310 int x, y, dwi, swi;
311 unsigned char *d;
312 unsigned char *s;
313 int alpha, calpha;
315 if(!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
316 return;
318 if (!HAS_ALPHA(src)) {
319 if (!HAS_ALPHA(image)) {
320 swi = src->width * 3;
321 dwi = image->width * 3;
323 s = src->data + (sy*(int)src->width + sx) * 3;
324 d = image->data + (dy*(int)image->width + dx) * 3;
326 for (y=0; y < height; y++) {
327 memcpy(d, s, width*3);
328 d += dwi;
329 s += swi;
331 } else {
332 swi = (src->width - width) * 3;
333 dwi = (image->width - width) * 4;
335 s = src->data + (sy*(int)src->width + sx) * 3;
336 d = image->data + (dy*(int)image->width + dx) * 4;
338 for (y=0; y < height; y++) {
339 for (x=0; x < width; x++) {
340 *d++ = *s++;
341 *d++ = *s++;
342 *d++ = *s++;
343 d++;
345 d += dwi;
346 s += swi;
349 } else {
350 int dalpha = HAS_ALPHA(image);
352 swi = (src->width - width) * 4;
353 s = src->data + (sy*(int)src->width + sx) * 4;
354 if (dalpha) {
355 dwi = (image->width - width) * 4;
356 d = image->data + (dy*(int)image->width + dx) * 4;
357 } else {
358 dwi = (image->width - width) * 3;
359 d = image->data + (dy*(int)image->width + dx) * 3;
362 for (y=0; y < height; y++) {
363 for (x=0; x < width; x++) {
364 alpha = *(s+3);
365 calpha = 255 - alpha;
366 *d = (((int)*d * calpha) + ((int)*s * alpha))/256;
367 s++; d++;
368 *d = (((int)*d * calpha) + ((int)*s * alpha))/256;
369 s++; d++;
370 *d = (((int)*d * calpha) + ((int)*s * alpha))/256;
371 s++; d++;
372 s++;
373 if (dalpha)
374 d++;
376 d += dwi;
377 s += swi;
383 void
384 RCombineAreaWithOpaqueness(RImage *image, RImage *src, int sx, int sy,
385 unsigned width, unsigned height, int dx, int dy,
386 int opaqueness)
388 int x, y, dwi, swi;
389 int c_opaqueness;
390 unsigned char *d;
391 unsigned char *s;
392 int dalpha = HAS_ALPHA(image);
393 int dch = (dalpha ? 4 : 3);
395 if(!calculateCombineArea(image, src, &sx, &sy, &width, &height, &dx, &dy))
396 return;
398 d = image->data + (dy*image->width + dx) * dch;
399 dwi = (image->width - width)*dch;
401 c_opaqueness = 255 - opaqueness;
402 #define OP opaqueness
403 if (!HAS_ALPHA(src)) {
404 #define COP c_opaqueness
406 s = src->data + sy*src->width*3;
407 swi = (src->width - width) * 3;
409 for (y=0; y < height; y++) {
410 for (x=0; x < width; x++) {
411 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256;
412 s++; d++;
413 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256;
414 s++; d++;
415 *d = (((int)*d *(int)COP) + ((int)*s *(int)OP))/256;
416 s++; d++;
417 if (dalpha)
418 d++;
420 d += dwi; s += swi;
422 #undef COP
423 } else {
424 int tmp;
426 s = src->data + sy*src->width*4;
427 swi = (src->width - width) * 4;
429 for (y=0; y < height; y++) {
430 for (x=0; x < width; x++) {
431 tmp= (*(s+3) * opaqueness)/256;
432 *d = (((int)*d *(int)(255-tmp)) + ((int)*s *(int)tmp))/256;
433 d++; s++;
434 *d = (((int)*d *(int)(255-tmp)) + ((int)*s *(int)tmp))/256;
435 d++; s++;
436 *d = (((int)*d *(int)(255-tmp)) + ((int)*s *(int)tmp))/256;
437 d++; s++;
438 s++;
439 if (dalpha)
440 d++;
442 d += dwi; s += swi;
445 #undef OP
450 void
451 RCombineImageWithColor(RImage *image, RColor *color)
453 register int i;
454 unsigned char *d;
455 int alpha, nalpha, r, g, b;
457 d = image->data;
459 if (!HAS_ALPHA(image)) {
460 /* Image has no alpha channel, so we consider it to be all 255.
461 * Thus there are no transparent parts to be filled. */
462 return;
464 r = color->red;
465 g = color->green;
466 b = color->blue;
468 for (i=0; i < image->width*image->height; i++) {
469 alpha = *(d+3);
470 nalpha = 255 - alpha;
472 *d = (((int)*d * alpha) + (r * nalpha))/256;
473 d++;
474 *d = (((int)*d * alpha) + (g * nalpha))/256;
475 d++;
476 *d = (((int)*d * alpha) + (b * nalpha))/256;
477 d++;
478 d++;
485 RImage*
486 RMakeTiledImage(RImage *tile, unsigned width, unsigned height)
488 int x, y;
489 unsigned w;
490 unsigned long tile_size = tile->width * tile->height;
491 unsigned long tx = 0;
492 RImage *image;
493 unsigned char *s, *d;
495 if (width == tile->width && height == tile->height)
496 image = RCloneImage(tile);
497 else if (width <= tile->width && height <= tile->height)
498 image = RGetSubImage(tile, 0, 0, width, height);
499 else {
500 int has_alpha = HAS_ALPHA(tile);
502 image = RCreateImage(width, height, has_alpha);
504 d = image->data;
505 s = tile->data;
507 for (y = 0; y < height; y++) {
508 for (x = 0; x < width; x += tile->width) {
510 w = (width - x < tile->width) ? width - x : tile->width;
512 if (has_alpha) {
513 w *= 4;
514 memcpy(d, s+tx*4, w);
515 } else {
516 w *= 3;
517 memcpy(d, s+tx*3, w);
519 d += w;
522 tx = (tx + tile->width) % tile_size;
525 return image;
529 RImage*
530 RMakeCenteredImage(RImage *image, unsigned width, unsigned height, RColor *color)
532 int x, y, w, h, sx, sy;
533 RImage *tmp;
535 tmp = RCreateImage(width, height, False);
536 if (!tmp) {
537 return NULL;
540 RClearImage(tmp, color);
542 if (image->height < height) {
543 h = image->height;
544 y = (height - h)/2;
545 sy = 0;
546 } else {
547 sy = (image->height - height)/2;
548 y = 0;
549 h = height;
551 if (image->width < width) {
552 w = image->width;
553 x = (width - w)/2;
554 sx = 0;
555 } else {
556 sx = (image->width - width)/2;
557 x = 0;
558 w = width;
560 RCombineArea(tmp, image, sx, sy, w, h, x, y);
562 return tmp;