Fixed the mdgradient code.
[wmaker-crm.git] / wrlib / gradient.c
blob4540384e80d0a65deb1d7371d0e3afb6e73b145c
1 /* gradient.c - renders gradients
3 * Raster graphics library
5 * Copyright (c) 1997-2000 Alfredo K. Kojima
6 * Copyright (c) 1998-2000 Dan Pascu
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 <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
29 #include <assert.h>
31 #include "wraster.h"
34 static RImage *renderHGradient(unsigned width, unsigned height,
35 int r0, int g0, int b0,
36 int rf, int gf, int bf);
37 static RImage *renderVGradient(unsigned width, unsigned height,
38 int r0, int g0, int b0,
39 int rf, int gf, int bf);
40 static RImage *renderDGradient(unsigned width, unsigned height,
41 int r0, int g0, int b0,
42 int rf, int gf, int bf);
44 static RImage *renderMHGradient(unsigned width, unsigned height,
45 RColor **colors, int count);
46 static RImage *renderMVGradient(unsigned width, unsigned height,
47 RColor **colors, int count);
48 static RImage *renderMDGradient(unsigned width, unsigned height,
49 RColor **colors, int count);
51 RImage*
52 RRenderMultiGradient(unsigned width, unsigned height, RColor **colors, int style)
54 int count;
56 count = 0;
57 while (colors[count]!=NULL) count++;
59 if (count > 2) {
60 switch (style) {
61 case RHorizontalGradient:
62 return renderMHGradient(width, height, colors, count);
63 case RVerticalGradient:
64 return renderMVGradient(width, height, colors, count);
65 case RDiagonalGradient:
66 return renderMDGradient(width, height, colors, count);
68 } else if (count > 1) {
69 return RRenderGradient(width, height, colors[0], colors[1], style);
70 } else if (count > 0) {
71 return RRenderGradient(width, height, colors[0], colors[0], style);
73 assert(0);
74 return NULL;
79 RImage*
80 RRenderGradient(unsigned width, unsigned height, RColor *from, RColor *to,
81 int style)
83 switch (style) {
84 case RHorizontalGradient:
85 return renderHGradient(width, height, from->red, from->green,
86 from->blue, to->red, to->green, to->blue);
87 case RVerticalGradient:
88 return renderVGradient(width, height, from->red, from->green,
89 from->blue, to->red, to->green, to->blue);
91 case RDiagonalGradient:
92 return renderDGradient(width, height, from->red, from->green,
93 from->blue, to->red, to->green, to->blue);
95 assert(0);
96 return NULL;
101 *----------------------------------------------------------------------
102 * renderHGradient--
103 * Renders a horizontal linear gradient of the specified size in the
104 * RImage format with a border of the specified type.
106 * Returns:
107 * A 24bit RImage with the gradient (no alpha channel).
109 * Side effects:
110 * None
111 *----------------------------------------------------------------------
113 static RImage*
114 renderHGradient(unsigned width, unsigned height, int r0, int g0, int b0,
115 int rf, int gf, int bf)
117 int i;
118 unsigned long r, g, b, dr, dg, db;
119 RImage *image;
120 unsigned char *ptr;
122 image = RCreateImage(width, height, False);
123 if (!image) {
124 return NULL;
126 ptr = image->data;
128 r = r0 << 16;
129 g = g0 << 16;
130 b = b0 << 16;
132 dr = ((rf-r0)<<16)/(int)width;
133 dg = ((gf-g0)<<16)/(int)width;
134 db = ((bf-b0)<<16)/(int)width;
135 /* render the first line */
136 for (i=0; i<width; i++) {
137 *(ptr++) = (unsigned char)(r>>16);
138 *(ptr++) = (unsigned char)(g>>16);
139 *(ptr++) = (unsigned char)(b>>16);
140 r += dr;
141 g += dg;
142 b += db;
145 /* copy the first line to the other lines */
146 for (i=1; i<height; i++) {
147 memcpy(&(image->data[i*width*3]), image->data, width*3);
149 return image;
155 *----------------------------------------------------------------------
156 * renderVGradient--
157 * Renders a vertical linear gradient of the specified size in the
158 * RImage format with a border of the specified type.
160 * Returns:
161 * A 24bit RImage with the gradient (no alpha channel).
163 * Side effects:
164 * None
165 *----------------------------------------------------------------------
167 static RImage*
168 renderVGradient(unsigned width, unsigned height, int r0, int g0, int b0,
169 int rf, int gf, int bf)
171 int i, j;
172 unsigned long r, g, b, dr, dg, db;
173 RImage *image;
174 unsigned char *ptr;
175 unsigned char rr, gg, bb;
177 image = RCreateImage(width, height, False);
178 if (!image) {
179 return NULL;
181 ptr = image->data;
183 r = r0<<16;
184 g = g0<<16;
185 b = b0<<16;
187 dr = ((rf-r0)<<16)/(int)height;
188 dg = ((gf-g0)<<16)/(int)height;
189 db = ((bf-b0)<<16)/(int)height;
191 for (i=0; i<height; i++) {
192 rr = r>>16;
193 gg = g>>16;
194 bb = b>>16;
195 for (j=0; j<width/8; j++) {
196 *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
197 *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
198 *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
199 *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
200 *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
201 *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
202 *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
203 *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
205 switch (width%8) {
206 case 7: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
207 case 6: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
208 case 5: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
209 case 4: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
210 case 3: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
211 case 2: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
212 case 1: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
214 r+=dr;
215 g+=dg;
216 b+=db;
218 return image;
223 *----------------------------------------------------------------------
224 * renderDGradient--
225 * Renders a diagonal linear gradient of the specified size in the
226 * RImage format with a border of the specified type.
228 * Returns:
229 * A 24bit RImage with the gradient (no alpha channel).
231 * Side effects:
232 * None
233 *----------------------------------------------------------------------
237 static RImage*
238 renderDGradient(unsigned width, unsigned height, int r0, int g0, int b0,
239 int rf, int gf, int bf)
241 RImage *image, *tmp;
242 int j;
243 float a, offset;
244 char *ptr;
246 if (width == 1)
247 return renderVGradient(width, height, r0, g0, b0, rf, gf, bf);
248 else if (height == 1)
249 return renderHGradient(width, height, r0, g0, b0, rf, gf, bf);
251 image = RCreateImage(width, height, False);
252 if (!image) {
253 return NULL;
256 tmp = renderHGradient(2*width-1, 1, r0, g0, b0, rf, gf, bf);
257 if (!tmp) {
258 RDestroyImage(image);
259 return NULL;
262 ptr = tmp->data;
264 a = ((float)(width - 1))/((float)(height - 1));
265 width = width * 3;
267 /* copy the first line to the other lines with corresponding offset */
268 for (j=0, offset=0.0; j<width*height; j += width) {
269 memcpy(&(image->data[j]), &ptr[3*(int)offset], width);
270 offset += a;
273 RDestroyImage(tmp);
274 return image;
278 static RImage*
279 renderMHGradient(unsigned width, unsigned height, RColor **colors, int count)
281 int i, j, k;
282 unsigned long r, g, b, dr, dg, db;
283 RImage *image;
284 unsigned char *ptr;
285 unsigned width2;
288 assert(count > 2);
290 image = RCreateImage(width, height, False);
291 if (!image) {
292 return NULL;
294 ptr = image->data;
296 if (count > width)
297 count = width;
299 if (count > 1)
300 width2 = width/(count-1);
301 else
302 width2 = width;
304 k = 0;
306 r = colors[0]->red << 16;
307 g = colors[0]->green << 16;
308 b = colors[0]->blue << 16;
310 /* render the first line */
311 for (i=1; i<count; i++) {
312 dr = ((int)(colors[i]->red - colors[i-1]->red) <<16)/(int)width2;
313 dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)width2;
314 db = ((int)(colors[i]->blue - colors[i-1]->blue) <<16)/(int)width2;
315 for (j=0; j<width2; j++) {
316 *ptr++ = (unsigned char)(r>>16);
317 *ptr++ = (unsigned char)(g>>16);
318 *ptr++ = (unsigned char)(b>>16);
319 r += dr;
320 g += dg;
321 b += db;
322 k++;
324 r = colors[i]->red << 16;
325 g = colors[i]->green << 16;
326 b = colors[i]->blue << 16;
328 for (j=k; j<width; j++) {
329 *ptr++ = (unsigned char)(r>>16);
330 *ptr++ = (unsigned char)(g>>16);
331 *ptr++ = (unsigned char)(b>>16);
334 /* copy the first line to the other lines */
335 for (i=1; i<height; i++) {
336 memcpy(&(image->data[i*width*3]), image->data, width*3);
338 return image;
344 static RImage*
345 renderMVGradient(unsigned width, unsigned height, RColor **colors, int count)
347 int i, j, k;
348 unsigned long r, g, b, dr, dg, db;
349 RImage *image;
350 unsigned char *ptr, *tmp;
351 unsigned height2;
352 int x;
353 unsigned char rr, gg, bb;
356 assert(count > 2);
358 image = RCreateImage(width, height, False);
359 if (!image) {
360 return NULL;
362 ptr = image->data;
364 if (count > height)
365 count = height;
367 if (count > 1)
368 height2 = height/(count-1);
369 else
370 height2 = height;
372 k = 0;
374 r = colors[0]->red << 16;
375 g = colors[0]->green << 16;
376 b = colors[0]->blue << 16;
378 for (i=1; i<count; i++) {
379 dr = ((int)(colors[i]->red - colors[i-1]->red) <<16)/(int)height2;
380 dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)height2;
381 db = ((int)(colors[i]->blue - colors[i-1]->blue) <<16)/(int)height2;
383 for (j=0; j<height2; j++) {
384 rr = r>>16;
385 gg = g>>16;
386 bb = b>>16;
388 for (x=0; x<width/4; x++) {
389 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
390 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
391 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
392 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
394 switch (width%4) {
395 case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
396 case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
397 case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
399 r += dr;
400 g += dg;
401 b += db;
402 k++;
404 r = colors[i]->red << 16;
405 g = colors[i]->green << 16;
406 b = colors[i]->blue << 16;
409 rr = r>>16;
410 gg = g>>16;
411 bb = b>>16;
413 if (k<height) {
414 tmp = ptr;
415 for (x=0; x<width/4; x++) {
416 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
417 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
418 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
419 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
421 switch (width%4) {
422 case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
423 case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
424 case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
425 default: break;
428 for (j=k+1; j<height; j++) {
429 memcpy(ptr, tmp, width*3);
430 ptr += width*3;
434 return image;
438 static RImage*
439 renderMDGradient(unsigned width, unsigned height, RColor **colors, int count)
441 RImage *image, *tmp;
442 float a, offset;
443 int j;
444 unsigned char *ptr;
446 assert(count > 2);
448 if (width == 1)
449 return renderMVGradient(width, height, colors, count);
450 else if (height == 1)
451 return renderMHGradient(width, height, colors, count);
453 image = RCreateImage(width, height, False);
454 if (!image) {
455 return NULL;
458 if (count > width)
459 count = width;
460 if (count > height)
461 count = height;
463 if (count > 2)
464 tmp = renderMHGradient(2*width-1, 1, colors, count);
465 else
466 tmp = renderHGradient(2*width-1, 1, colors[0]->red<<8,
467 colors[0]->green<<8, colors[0]->blue<<8,
468 colors[1]->red<<8, colors[1]->green<<8,
469 colors[1]->blue<<8);
471 if (!tmp) {
472 RDestroyImage(image);
473 return NULL;
475 ptr = tmp->data;
477 a = ((float)(width - 1))/((float)(height - 1));
478 width = width * 3;
480 /* copy the first line to the other lines with corresponding offset */
481 for (j=0, offset=0; j<width*height; j += width) {
482 memcpy(&(image->data[j]), &ptr[3*(int)offset], width);
483 offset += a;
485 RDestroyImage(tmp);
486 return image;
492 RImage *RRenderInterwovenGradient(unsigned width, unsigned height,
493 RColor colors1[2], int thickness1,
494 RColor colors2[2], int thickness2)
496 int i, j, k, l, ll;
497 unsigned long r1, g1, b1, dr1, dg1, db1;
498 unsigned long r2, g2, b2, dr2, dg2, db2;
499 RImage *image;
500 unsigned char *ptr;
501 unsigned char rr, gg, bb;
503 image = RCreateImage(width, height, False);
504 if (!image) {
505 return NULL;
507 ptr = image->data;
509 r1 = colors1[0].red<<16;
510 g1 = colors1[0].green<<16;
511 b1 = colors1[0].blue<<16;
513 r2 = colors2[0].red<<16;
514 g2 = colors2[0].green<<16;
515 b2 = colors2[0].blue<<16;
517 dr1 = ((colors1[1].red-colors1[0].red)<<16)/(int)height;
518 dg1 = ((colors1[1].green-colors1[0].green)<<16)/(int)height;
519 db1 = ((colors1[1].blue-colors1[0].blue)<<16)/(int)height;
521 dr2 = ((colors2[1].red-colors2[0].red)<<16)/(int)height;
522 dg2 = ((colors2[1].green-colors2[0].green)<<16)/(int)height;
523 db2 = ((colors2[1].blue-colors2[0].blue)<<16)/(int)height;
525 for (i=0,k=0,l=0,ll=thickness1; i<height; i++) {
526 if (k == 0) {
527 rr = r1>>16;
528 gg = g1>>16;
529 bb = b1>>16;
530 } else {
531 rr = r2>>16;
532 gg = g2>>16;
533 bb = b2>>16;
535 for (j=0; j<width/8; j++) {
536 *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
537 *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
538 *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
539 *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
540 *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
541 *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
542 *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
543 *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
545 switch (width%8) {
546 case 7: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
547 case 6: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
548 case 5: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
549 case 4: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
550 case 3: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
551 case 2: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
552 case 1: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
554 if (++l == ll) {
555 if (k == 0) {
556 k = 1;
557 ll = thickness2;
558 } else {
559 k = 0;
560 ll = thickness1;
562 l = 0;
564 r1+=dr1;
565 g1+=dg1;
566 b1+=db1;
568 r2+=dr2;
569 g2+=dg2;
570 b2+=db2;
572 return image;