changed format of RImage, added x86 speicfic optimized code
[wmaker-crm.git] / wrlib / gradient.c
blob885b3fe6a9442426b05280b4b8a91d72d55b04b6
1 /* gradient.c - renders gradients
3 * Raster graphics library
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>
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 *ptr;
121 image = RCreateImage(width, height, False);
122 if (!image) {
123 return NULL;
125 ptr = image->data;
127 r = r0 << 16;
128 g = g0 << 16;
129 b = b0 << 16;
131 dr = ((rf-r0)<<16)/(int)width;
132 dg = ((gf-g0)<<16)/(int)width;
133 db = ((bf-b0)<<16)/(int)width;
134 /* render the first line */
135 for (i=0; i<width; i++) {
136 *(ptr++) = (unsigned char)(r>>16);
137 *(ptr++) = (unsigned char)(g>>16);
138 *(ptr++) = (unsigned char)(b>>16);
139 r += dr;
140 g += dg;
141 b += db;
144 /* copy the first line to the other lines */
145 for (i=1; i<height; i++) {
146 memcpy(&(image->data[i*width*3]), image->data, width*3);
148 return image;
152 *----------------------------------------------------------------------
153 * renderVGradient--
154 * Renders a vertical linear gradient of the specified size in the
155 * RImage format with a border of the specified type.
157 * Returns:
158 * A 24bit RImage with the gradient (no alpha channel).
160 * Side effects:
161 * None
162 *----------------------------------------------------------------------
164 static RImage*
165 renderVGradient(unsigned width, unsigned height, int r0, int g0, int b0,
166 int rf, int gf, int bf)
168 int i, j;
169 unsigned long r, g, b, dr, dg, db;
170 RImage *image;
171 unsigned char *ptr;
172 unsigned int *iptr;
173 unsigned char rr, gg, bb;
175 image = RCreateImage(width, height, False);
176 if (!image) {
177 return NULL;
179 iptr = (unsigned int*)ptr = image->data;
181 r = r0<<16;
182 g = g0<<16;
183 b = b0<<16;
185 dr = ((rf-r0)<<16)/(int)height;
186 dg = ((gf-g0)<<16)/(int)height;
187 db = ((bf-b0)<<16)/(int)height;
190 for (i=0; i<height; i++) {
191 rr = r>>16;
192 gg = g>>16;
193 bb = b>>16;
194 for (j=0; j<width/4; j++) {
195 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
196 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
197 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
198 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
200 switch (width%4) {
201 case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
202 case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
203 case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
205 r+=dr;
206 g+=dg;
207 b+=db;
209 return image;
214 *----------------------------------------------------------------------
215 * renderDGradient--
216 * Renders a diagonal linear gradient of the specified size in the
217 * RImage format with a border of the specified type.
219 * Returns:
220 * A 24bit RImage with the gradient (no alpha channel).
222 * Side effects:
223 * None
224 *----------------------------------------------------------------------
228 static RImage*
229 renderDGradient(unsigned width, unsigned height, int r0, int g0, int b0,
230 int rf, int gf, int bf)
232 RImage *image, *tmp;
233 unsigned long a;
234 int i, j, offset;
236 if (width == 1)
237 return renderVGradient(width, height, r0, g0, b0, rf, gf, bf);
238 else if (height == 1)
239 return renderHGradient(width, height, r0, g0, b0, rf, gf, bf);
241 image = RCreateImage(width, height, False);
242 if (!image) {
243 return NULL;
246 tmp = renderHGradient(2*width-1, 1, r0, g0, b0, rf, gf, bf);
247 if (!tmp) {
248 RDestroyImage(image);
249 return NULL;
252 a = (((width - 1)<<16) / ((height - 1)<<16)) * 3;
254 width *= 3;
255 /* copy the first line to the other lines with corresponding offset */
256 for (i=0, j=0, offset = 0; i<height; i++, j+= width) {
257 offset += a;
258 memcpy(&(image->data[j]), &(tmp->data[(offset>>16)]), width);
260 RDestroyImage(tmp);
261 return image;
265 static RImage*
266 renderMHGradient(unsigned width, unsigned height, RColor **colors, int count)
268 int i, j, k;
269 unsigned long r, g, b, dr, dg, db;
270 RImage *image;
271 unsigned char *ptr;
272 unsigned width2;
275 assert(count > 2);
277 image = RCreateImage(width, height, False);
278 if (!image) {
279 return NULL;
281 ptr = image->data;
283 if (count > width)
284 count = width;
286 if (count > 1)
287 width2 = width/(count-1);
288 else
289 width2 = width;
291 k = 0;
293 r = colors[0]->red << 16;
294 g = colors[0]->green << 16;
295 b = colors[0]->blue << 16;
297 /* render the first line */
298 for (i=1; i<count; i++) {
299 dr = ((int)(colors[i]->red - colors[i-1]->red) <<16)/(int)width2;
300 dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)width2;
301 db = ((int)(colors[i]->blue - colors[i-1]->blue) <<16)/(int)width2;
302 for (j=0; j<width2; j++) {
303 *ptr++ = (unsigned char)(r>>16);
304 *ptr++ = (unsigned char)(g>>16);
305 *ptr++ = (unsigned char)(b>>16);
306 r += dr;
307 g += dg;
308 b += db;
309 k++;
311 r = colors[i]->red << 16;
312 g = colors[i]->green << 16;
313 b = colors[i]->blue << 16;
315 for (j=k; j<width; j++) {
316 *ptr++ = (unsigned char)(r>>16);
317 *ptr++ = (unsigned char)(g>>16);
318 *ptr++ = (unsigned char)(b>>16);
321 /* copy the first line to the other lines */
322 for (i=1; i<height; i++) {
323 memcpy(&(image->data[i*width*3]), image->data, width*3);
325 return image;
331 static RImage*
332 renderMVGradient(unsigned width, unsigned height, RColor **colors, int count)
334 int i, j, k;
335 unsigned long r, g, b, dr, dg, db;
336 RImage *image;
337 unsigned char *ptr, *tmp;
338 unsigned height2;
339 int x;
340 unsigned char rr, gg, bb;
343 assert(count > 2);
345 image = RCreateImage(width, height, False);
346 if (!image) {
347 return NULL;
349 ptr = image->data;
351 if (count > height)
352 count = height;
354 if (count > 1)
355 height2 = height/(count-1);
356 else
357 height2 = height;
359 k = 0;
361 r = colors[0]->red << 16;
362 g = colors[0]->green << 16;
363 b = colors[0]->blue << 16;
365 for (i=1; i<count; i++) {
366 dr = ((int)(colors[i]->red - colors[i-1]->red) <<16)/(int)height2;
367 dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)height2;
368 db = ((int)(colors[i]->blue - colors[i-1]->blue) <<16)/(int)height2;
370 for (j=0; j<height2; j++) {
371 rr = r>>16;
372 gg = g>>16;
373 bb = b>>16;
375 for (x=0; x<width/4; x++) {
376 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
377 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
378 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
379 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
381 switch (width%4) {
382 case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
383 case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
384 case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
386 r += dr;
387 g += dg;
388 b += db;
389 k++;
391 r = colors[i]->red << 16;
392 g = colors[i]->green << 16;
393 b = colors[i]->blue << 16;
396 rr = r>>16;
397 gg = g>>16;
398 bb = b>>16;
400 tmp = ptr;
401 for (x=0; x<width/4; x++) {
402 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
403 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
404 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
405 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
407 switch (width%4) {
408 case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
409 case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
410 case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
413 for (j=k+1; j<width; j++) {
414 memcpy(ptr, tmp, width*3);
415 ptr += width*3;
418 return image;
422 static RImage*
423 renderMDGradient(unsigned width, unsigned height, RColor **colors, int count)
425 RImage *image, *tmp;
426 float a;
427 int i, offset;
429 assert(count > 2);
431 if (width == 1)
432 return renderMVGradient(width, height, colors, count);
433 else if (height == 1)
434 return renderMHGradient(width, height, colors, count);
436 image = RCreateImage(width, height, False);
437 if (!image) {
438 return NULL;
441 if (count > width)
442 count = width;
443 if (count > height)
444 count = height;
446 if (count > 2)
447 tmp = renderMHGradient(2*width-1, 1, colors, count);
448 else
449 tmp = renderHGradient(2*width-1, 1, colors[0]->red<<8,
450 colors[0]->green<<8, colors[0]->blue<<8,
451 colors[1]->red<<8, colors[1]->green<<8,
452 colors[1]->blue<<8);
454 if (!tmp) {
455 RDestroyImage(image);
456 return NULL;
459 a = ((float)(width - 1))/((float)(height - 1));
461 /* copy the first line to the other lines with corresponding offset */
462 for (i=0; i<height; i++) {
463 offset = (int)(a*i+0.5)*3;
464 memcpy(&(image->data[i*width*3]), &(tmp->data[offset]), width*3);
466 RDestroyImage(tmp);
467 return image;