Initial revision
[wmaker-crm.git] / wrlib / gradient.c
blob8bbb5f58b28da13013740f44eb43ceaad13dc5e5
1 /* gradient.c - renders gradients
3 * Raster graphics library
5 * Copyright (c) 1997 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>
28 #include <assert.h>
30 #include "wraster.h"
33 static RImage *renderHGradient(unsigned width, unsigned height,
34 int r0, int g0, int b0,
35 int rf, int gf, int bf);
36 static RImage *renderVGradient(unsigned width, unsigned height,
37 int r0, int g0, int b0,
38 int rf, int gf, int bf);
39 static RImage *renderDGradient(unsigned width, unsigned height,
40 int r0, int g0, int b0,
41 int rf, int gf, int bf);
43 static RImage *renderMHGradient(unsigned width, unsigned height,
44 RColor **colors, int count);
45 static RImage *renderMVGradient(unsigned width, unsigned height,
46 RColor **colors, int count);
47 static RImage *renderMDGradient(unsigned width, unsigned height,
48 RColor **colors, int count);
50 RImage*
51 RRenderMultiGradient(unsigned width, unsigned height, RColor **colors, int style)
53 int count;
55 count = 0;
56 while (colors[count]!=NULL) count++;
58 if (count > 2) {
59 switch (style) {
60 case RHorizontalGradient:
61 return renderMHGradient(width, height, colors, count);
62 case RVerticalGradient:
63 return renderMVGradient(width, height, colors, count);
64 case RDiagonalGradient:
65 return renderMDGradient(width, height, colors, count);
67 } else if (count > 1) {
68 return RRenderGradient(width, height, colors[0], colors[1], style);
69 } else if (count > 0) {
70 return RRenderGradient(width, height, colors[0], colors[0], style);
72 assert(0);
73 return NULL;
78 RImage*
79 RRenderGradient(unsigned width, unsigned height, RColor *from, RColor *to,
80 int style)
82 switch (style) {
83 case RHorizontalGradient:
84 return renderHGradient(width, height, from->red, from->green,
85 from->blue, to->red, to->green, to->blue);
86 case RVerticalGradient:
87 return renderVGradient(width, height, from->red, from->green,
88 from->blue, to->red, to->green, to->blue);
90 case RDiagonalGradient:
91 return renderDGradient(width, height, from->red, from->green,
92 from->blue, to->red, to->green, to->blue);
94 assert(0);
95 return NULL;
100 *----------------------------------------------------------------------
101 * renderHGradient--
102 * Renders a horizontal linear gradient of the specified size in the
103 * RImage format with a border of the specified type.
105 * Returns:
106 * A 24bit RImage with the gradient (no alpha channel).
108 * Side effects:
109 * None
110 *----------------------------------------------------------------------
112 static RImage*
113 renderHGradient(unsigned width, unsigned height, int r0, int g0, int b0,
114 int rf, int gf, int bf)
116 int i;
117 unsigned long r, g, b, dr, dg, db;
118 RImage *image;
119 unsigned char *rp, *gp, *bp;
121 image = RCreateImage(width, height, False);
122 if (!image) {
123 return NULL;
125 rp = image->data[0];
126 gp = image->data[1];
127 bp = image->data[2];
129 r = r0 << 16;
130 g = g0 << 16;
131 b = b0 << 16;
133 dr = ((rf-r0)<<16)/(int)width;
134 dg = ((gf-g0)<<16)/(int)width;
135 db = ((bf-b0)<<16)/(int)width;
136 /* render the first line */
137 for (i=0; i<width; i++) {
138 *(rp++) = (unsigned char)(r>>16);
139 *(gp++) = (unsigned char)(g>>16);
140 *(bp++) = (unsigned char)(b>>16);
141 r += dr;
142 g += dg;
143 b += db;
147 /* copy the first line to the other lines */
148 for (i=1; i<height; i++) {
149 memcpy(&(image->data[0][i*width]), image->data[0], width);
150 memcpy(&(image->data[1][i*width]), image->data[1], width);
151 memcpy(&(image->data[2][i*width]), image->data[2], width);
153 return image;
157 *----------------------------------------------------------------------
158 * renderVGradient--
159 * Renders a vertical linear gradient of the specified size in the
160 * RImage format with a border of the specified type.
162 * Returns:
163 * A 24bit RImage with the gradient (no alpha channel).
165 * Side effects:
166 * None
167 *----------------------------------------------------------------------
169 static RImage*
170 renderVGradient(unsigned width, unsigned height, int r0, int g0, int b0,
171 int rf, int gf, int bf)
173 int i;
174 unsigned long r, g, b, dr, dg, db;
175 RImage *image;
176 unsigned char *rp, *gp, *bp;
178 image = RCreateImage(width, height, False);
179 if (!image) {
180 return NULL;
182 rp = image->data[0];
183 gp = image->data[1];
184 bp = image->data[2];
186 r = r0<<16;
187 g = g0<<16;
188 b = b0<<16;
190 dr = ((rf-r0)<<16)/(int)height;
191 dg = ((gf-g0)<<16)/(int)height;
192 db = ((bf-b0)<<16)/(int)height;
194 for (i=0; i<height; i++) {
195 memset(rp, (unsigned char)(r>>16), width);
196 memset(gp, (unsigned char)(g>>16), width);
197 memset(bp, (unsigned char)(b>>16), width);
198 rp+=width;
199 gp+=width;
200 bp+=width;
201 r+=dr;
202 g+=dg;
203 b+=db;
205 return image;
210 *----------------------------------------------------------------------
211 * renderDGradient--
212 * Renders a diagonal linear gradient of the specified size in the
213 * RImage format with a border of the specified type.
215 * Returns:
216 * A 24bit RImage with the gradient (no alpha channel).
218 * Side effects:
219 * None
220 *----------------------------------------------------------------------
222 #if 0
223 /* This version is slower then the second below. It uses more operations,
224 * most of them multiplication of floats. -Dan
226 static RImage*
227 renderDGradient(unsigned width, unsigned height, int r0, int g0, int b0,
228 int rf, int gf, int bf)
230 int x, y;
231 float from_red,from_green,from_blue;
232 float to_red,to_green,to_blue;
233 float dr,dg,db,dx,dy,w,h,xred,yred,xgreen,ygreen,xblue,yblue;
234 RImage *image;
235 unsigned char *rp, *gp, *bp;
237 image = RCreateImage(width, height, False);
238 if (!image) {
239 return NULL;
241 rp = image->data[0];
242 gp = image->data[1];
243 bp = image->data[2];
245 from_red = (float)r0;
246 from_green = (float)g0;
247 from_blue = (float)b0;
249 to_red = (float)rf;
250 to_green = (float)gf;
251 to_blue = (float)bf;
253 w = (float) width;
254 h = (float) height;
256 dr = (to_red - from_red);
257 dg = (to_green - from_green);
258 db = (to_blue - from_blue);
260 for (y=0; y<height; y++) {
262 dy = y / h;
264 yred = dr * dy + from_red;
265 ygreen = dg * dy + from_green;
266 yblue = db * dy + from_blue;
268 for (x=0; x<width; x++) {
269 dx = x / w;
271 xred = dr * dx + from_red;
272 xgreen = dg * dx + from_green;
273 xblue = db * dx + from_blue;
275 *(rp++) = (unsigned char)((xred + yred)/2);
276 *(gp++) = (unsigned char)((xgreen + ygreen)/2);
277 *(bp++) = (unsigned char)((xblue + yblue)/2);
280 return image;
282 #endif
285 static RImage*
286 renderDGradient(unsigned width, unsigned height, int r0, int g0, int b0,
287 int rf, int gf, int bf)
289 RImage *image, *tmp;
290 float a;
291 int i, offset;
293 if (width == 1)
294 return renderVGradient(width, height, r0, g0, b0, rf, gf, bf);
295 else if (height == 1)
296 return renderHGradient(width, height, r0, g0, b0, rf, gf, bf);
298 image = RCreateImage(width, height, False);
299 if (!image) {
300 return NULL;
303 tmp = renderHGradient(2*width-1, 1, r0, g0, b0, rf, gf, bf);
304 if (!tmp) {
305 RDestroyImage(image);
306 return NULL;
309 a = ((float)(width - 1))/((float)(height - 1));
311 /* copy the first line to the other lines with corresponding offset */
312 for (i=0; i<height; i++) {
313 offset = (int)(a*i+0.5);
314 memcpy(&(image->data[0][i*width]), &(tmp->data[0][offset]), width);
315 memcpy(&(image->data[1][i*width]), &(tmp->data[1][offset]), width);
316 memcpy(&(image->data[2][i*width]), &(tmp->data[2][offset]), width);
318 RDestroyImage(tmp);
319 return image;
323 static RImage*
324 renderMHGradient(unsigned width, unsigned height, RColor **colors, int count)
326 int i, j, k;
327 unsigned long r, g, b, dr, dg, db;
328 RImage *image;
329 unsigned char *rp, *gp, *bp;
330 unsigned width2;
333 assert(count > 2);
335 image = RCreateImage(width, height, False);
336 if (!image) {
337 return NULL;
339 rp = image->data[0];
340 gp = image->data[1];
341 bp = image->data[2];
343 if (count > width)
344 count = width;
346 if (count > 1)
347 width2 = width/(count-1);
348 else
349 width2 = width;
351 k = 0;
353 r = colors[0]->red << 16;
354 g = colors[0]->green << 16;
355 b = colors[0]->blue << 16;
357 /* render the first line */
358 for (i=1; i<count; i++) {
359 dr = ((int)(colors[i]->red - colors[i-1]->red) <<16)/(int)width2;
360 dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)width2;
361 db = ((int)(colors[i]->blue - colors[i-1]->blue) <<16)/(int)width2;
362 for (j=0; j<width2; j++) {
363 *(rp++) = (unsigned char)(r>>16);
364 *(gp++) = (unsigned char)(g>>16);
365 *(bp++) = (unsigned char)(b>>16);
366 r += dr;
367 g += dg;
368 b += db;
369 k++;
371 r = colors[i]->red << 16;
372 g = colors[i]->green << 16;
373 b = colors[i]->blue << 16;
375 for (j=k; j<width; j++) {
376 *(rp++) = (unsigned char)(r>>16);
377 *(gp++) = (unsigned char)(g>>16);
378 *(bp++) = (unsigned char)(b>>16);
381 /* copy the first line to the other lines */
382 for (i=1; i<height; i++) {
383 memcpy(&(image->data[0][i*width]), image->data[0], width);
384 memcpy(&(image->data[1][i*width]), image->data[1], width);
385 memcpy(&(image->data[2][i*width]), image->data[2], width);
387 return image;
393 static RImage*
394 renderMVGradient(unsigned width, unsigned height, RColor **colors, int count)
396 int i, j, k;
397 unsigned long r, g, b, dr, dg, db;
398 RImage *image;
399 unsigned char *rp, *gp, *bp;
400 unsigned height2;
403 assert(count > 2);
405 image = RCreateImage(width, height, False);
406 if (!image) {
407 return NULL;
409 rp = image->data[0];
410 gp = image->data[1];
411 bp = image->data[2];
413 if (count > height)
414 count = height;
416 if (count > 1)
417 height2 = height/(count-1);
418 else
419 height2 = height;
421 k = 0;
423 r = colors[0]->red << 16;
424 g = colors[0]->green << 16;
425 b = colors[0]->blue << 16;
427 for (i=1; i<count; i++) {
428 dr = ((int)(colors[i]->red - colors[i-1]->red) <<16)/(int)height2;
429 dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)height2;
430 db = ((int)(colors[i]->blue - colors[i-1]->blue) <<16)/(int)height2;
431 for (j=0; j<height2; j++) {
432 memset(rp, (unsigned char)(r>>16), width);
433 memset(gp, (unsigned char)(g>>16), width);
434 memset(bp, (unsigned char)(b>>16), width);
435 rp+=width;
436 gp+=width;
437 bp+=width;
438 r += dr;
439 g += dg;
440 b += db;
441 k++;
443 r = colors[i]->red << 16;
444 g = colors[i]->green << 16;
445 b = colors[i]->blue << 16;
447 for (j=k; j<height; j++) {
448 memset(rp, (unsigned char)(r>>16), width);
449 memset(gp, (unsigned char)(g>>16), width);
450 memset(bp, (unsigned char)(b>>16), width);
451 rp+=width;
452 gp+=width;
453 bp+=width;
456 return image;
460 static RImage*
461 renderMDGradient(unsigned width, unsigned height, RColor **colors, int count)
463 RImage *image, *tmp;
464 float a;
465 int i, offset;
467 assert(count > 2);
469 if (width == 1)
470 return renderMVGradient(width, height, colors, count);
471 else if (height == 1)
472 return renderMHGradient(width, height, colors, count);
474 image = RCreateImage(width, height, False);
475 if (!image) {
476 return NULL;
479 if (count > width)
480 count = width;
481 if (count > height)
482 count = height;
484 if (count > 2)
485 tmp = renderMHGradient(2*width-1, 1, colors, count);
486 else
487 tmp = renderHGradient(2*width-1, 1, colors[0]->red<<8,
488 colors[0]->green<<8, colors[0]->blue<<8,
489 colors[1]->red<<8, colors[1]->green<<8,
490 colors[1]->blue<<8);
492 if (!tmp) {
493 RDestroyImage(image);
494 return NULL;
497 a = ((float)(width - 1))/((float)(height - 1));
499 /* copy the first line to the other lines with corresponding offset */
500 for (i=0; i<height; i++) {
501 offset = (int)(a*i+0.5);
502 memcpy(&(image->data[0][i*width]), &(tmp->data[0][offset]), width);
503 memcpy(&(image->data[1][i*width]), &(tmp->data[1][offset]), width);
504 memcpy(&(image->data[2][i*width]), &(tmp->data[2][offset]), width);
506 RDestroyImage(tmp);
507 return image;