*** empty log message ***
[wmaker-crm.git] / wrlib / gradient.c
blobb4612eb45882d152d53afd2463f4a5433a483377
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 int *iptr;
176 unsigned char rr, gg, bb;
178 image = RCreateImage(width, height, False);
179 if (!image) {
180 return NULL;
182 iptr = (unsigned int*)ptr = image->data;
184 r = r0<<16;
185 g = g0<<16;
186 b = b0<<16;
188 dr = ((rf-r0)<<16)/(int)height;
189 dg = ((gf-g0)<<16)/(int)height;
190 db = ((bf-b0)<<16)/(int)height;
192 for (i=0; i<height; i++) {
193 rr = r>>16;
194 gg = g>>16;
195 bb = b>>16;
196 for (j=0; j<width/8; j++) {
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;
204 *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
206 switch (width%8) {
207 case 7: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
208 case 6: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
209 case 5: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
210 case 4: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
211 case 3: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
212 case 2: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
213 case 1: *(ptr++) = rr; *(ptr++) = gg; *(ptr++) = bb;
215 r+=dr;
216 g+=dg;
217 b+=db;
219 return image;
224 *----------------------------------------------------------------------
225 * renderDGradient--
226 * Renders a diagonal linear gradient of the specified size in the
227 * RImage format with a border of the specified type.
229 * Returns:
230 * A 24bit RImage with the gradient (no alpha channel).
232 * Side effects:
233 * None
234 *----------------------------------------------------------------------
238 static RImage*
239 renderDGradient(unsigned width, unsigned height, int r0, int g0, int b0,
240 int rf, int gf, int bf)
242 RImage *image, *tmp;
243 int j;
244 float a, offset;
245 char *ptr;
247 if (width == 1)
248 return renderVGradient(width, height, r0, g0, b0, rf, gf, bf);
249 else if (height == 1)
250 return renderHGradient(width, height, r0, g0, b0, rf, gf, bf);
252 image = RCreateImage(width, height, False);
253 if (!image) {
254 return NULL;
257 tmp = renderHGradient(2*width-1, 1, r0, g0, b0, rf, gf, bf);
258 if (!tmp) {
259 RDestroyImage(image);
260 return NULL;
263 ptr = tmp->data;
265 a = ((float)(width - 1))/((float)(height - 1));
266 width = width * 3;
268 /* copy the first line to the other lines with corresponding offset */
269 for (j=0, offset=0.0; j<width*height; j += width) {
270 memcpy(&(image->data[j]), &ptr[3*(int)offset], width);
271 offset += a;
274 RDestroyImage(tmp);
275 return image;
279 static RImage*
280 renderMHGradient(unsigned width, unsigned height, RColor **colors, int count)
282 int i, j, k;
283 unsigned long r, g, b, dr, dg, db;
284 RImage *image;
285 unsigned char *ptr;
286 unsigned width2;
289 assert(count > 2);
291 image = RCreateImage(width, height, False);
292 if (!image) {
293 return NULL;
295 ptr = image->data;
297 if (count > width)
298 count = width;
300 if (count > 1)
301 width2 = width/(count-1);
302 else
303 width2 = width;
305 k = 0;
307 r = colors[0]->red << 16;
308 g = colors[0]->green << 16;
309 b = colors[0]->blue << 16;
311 /* render the first line */
312 for (i=1; i<count; i++) {
313 dr = ((int)(colors[i]->red - colors[i-1]->red) <<16)/(int)width2;
314 dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)width2;
315 db = ((int)(colors[i]->blue - colors[i-1]->blue) <<16)/(int)width2;
316 for (j=0; j<width2; j++) {
317 *ptr++ = (unsigned char)(r>>16);
318 *ptr++ = (unsigned char)(g>>16);
319 *ptr++ = (unsigned char)(b>>16);
320 r += dr;
321 g += dg;
322 b += db;
323 k++;
325 r = colors[i]->red << 16;
326 g = colors[i]->green << 16;
327 b = colors[i]->blue << 16;
329 for (j=k; j<width; j++) {
330 *ptr++ = (unsigned char)(r>>16);
331 *ptr++ = (unsigned char)(g>>16);
332 *ptr++ = (unsigned char)(b>>16);
335 /* copy the first line to the other lines */
336 for (i=1; i<height; i++) {
337 memcpy(&(image->data[i*width*3]), image->data, width*3);
339 return image;
345 static RImage*
346 renderMVGradient(unsigned width, unsigned height, RColor **colors, int count)
348 int i, j, k;
349 unsigned long r, g, b, dr, dg, db;
350 RImage *image;
351 unsigned char *ptr, *tmp;
352 unsigned height2;
353 int x;
354 unsigned char rr, gg, bb;
357 assert(count > 2);
359 image = RCreateImage(width, height, False);
360 if (!image) {
361 return NULL;
363 ptr = image->data;
365 if (count > height)
366 count = height;
368 if (count > 1)
369 height2 = height/(count-1);
370 else
371 height2 = height;
373 k = 0;
375 r = colors[0]->red << 16;
376 g = colors[0]->green << 16;
377 b = colors[0]->blue << 16;
379 for (i=1; i<count; i++) {
380 dr = ((int)(colors[i]->red - colors[i-1]->red) <<16)/(int)height2;
381 dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)height2;
382 db = ((int)(colors[i]->blue - colors[i-1]->blue) <<16)/(int)height2;
384 for (j=0; j<height2; j++) {
385 rr = r>>16;
386 gg = g>>16;
387 bb = b>>16;
389 for (x=0; x<width/4; x++) {
390 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
391 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
392 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
393 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
395 switch (width%4) {
396 case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
397 case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
398 case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
400 r += dr;
401 g += dg;
402 b += db;
403 k++;
405 r = colors[i]->red << 16;
406 g = colors[i]->green << 16;
407 b = colors[i]->blue << 16;
410 rr = r>>16;
411 gg = g>>16;
412 bb = b>>16;
414 if (k<height) {
415 tmp = ptr;
416 for (x=0; x<width/4; x++) {
417 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
418 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
419 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
420 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
422 switch (width%4) {
423 case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
424 case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
425 case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
426 default: break;
429 for (j=k+1; j<height; j++) {
430 memcpy(ptr, tmp, width*3);
431 ptr += width*3;
435 return image;
439 static RImage*
440 renderMDGradient(unsigned width, unsigned height, RColor **colors, int count)
442 RImage *image, *tmp;
443 float a, offset;
444 int j;
445 unsigned char *ptr;
447 assert(count > 2);
449 if (width == 1)
450 return renderMVGradient(width, height, colors, count);
451 else if (height == 1)
452 return renderMHGradient(width, height, colors, count);
454 image = RCreateImage(width, height, False);
455 if (!image) {
456 return NULL;
459 if (count > width)
460 count = width;
461 if (count > height)
462 count = height;
464 if (count > 2)
465 tmp = renderMHGradient(2*width-1, 1, colors, count);
466 else
467 tmp = renderHGradient(2*width-1, 1, colors[0]->red<<8,
468 colors[0]->green<<8, colors[0]->blue<<8,
469 colors[1]->red<<8, colors[1]->green<<8,
470 colors[1]->blue<<8);
472 if (!tmp) {
473 RDestroyImage(image);
474 return NULL;
476 ptr = tmp->data;
478 a = ((float)(width - 1))/((float)(height - 1));
479 width = width * 3;
481 /* copy the first line to the other lines with corresponding offset */
482 for (j=0, offset=0; j<width*height; j += width) {
483 memcpy(&(image->data[j]), &ptr[3*(int)offset], width);
484 offset += a;
486 RDestroyImage(tmp);
487 return image;