asm optimization for 8bpp (no mmx)
[wmaker-crm.git] / wrlib / gradient.c
blob2117bd913ef982ed9cac86eb67009db2359f67ea
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;
153 *----------------------------------------------------------------------
154 * renderVGradient--
155 * Renders a vertical linear gradient of the specified size in the
156 * RImage format with a border of the specified type.
158 * Returns:
159 * A 24bit RImage with the gradient (no alpha channel).
161 * Side effects:
162 * None
163 *----------------------------------------------------------------------
165 static RImage*
166 renderVGradient(unsigned width, unsigned height, int r0, int g0, int b0,
167 int rf, int gf, int bf)
169 int i, j;
170 unsigned long r, g, b, dr, dg, db;
171 RImage *image;
172 unsigned char *ptr;
173 unsigned int *iptr;
174 unsigned char rr, gg, bb;
176 image = RCreateImage(width, height, False);
177 if (!image) {
178 return NULL;
180 iptr = (unsigned int*)ptr = image->data;
182 r = r0<<16;
183 g = g0<<16;
184 b = b0<<16;
186 dr = ((rf-r0)<<16)/(int)height;
187 dg = ((gf-g0)<<16)/(int)height;
188 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/4; 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;
201 switch (width%4) {
202 case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
203 case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
204 case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
206 r+=dr;
207 g+=dg;
208 b+=db;
210 return image;
215 *----------------------------------------------------------------------
216 * renderDGradient--
217 * Renders a diagonal linear gradient of the specified size in the
218 * RImage format with a border of the specified type.
220 * Returns:
221 * A 24bit RImage with the gradient (no alpha channel).
223 * Side effects:
224 * None
225 *----------------------------------------------------------------------
229 static RImage*
230 renderDGradient(unsigned width, unsigned height, int r0, int g0, int b0,
231 int rf, int gf, int bf)
233 RImage *image, *tmp;
234 int i, j, offset;
235 float a;
236 char *ptr;
238 if (width == 1)
239 return renderVGradient(width, height, r0, g0, b0, rf, gf, bf);
240 else if (height == 1)
241 return renderHGradient(width, height, r0, g0, b0, rf, gf, bf);
243 image = RCreateImage(width, height, False);
244 if (!image) {
245 return NULL;
248 tmp = renderHGradient(2*width-1, 1, r0, g0, b0, rf, gf, bf);
249 if (!tmp) {
250 RDestroyImage(image);
251 return NULL;
254 ptr = tmp->data;
256 width *= 3;
257 a = ((float)(width - 1))/((float)(height - 1));
259 /* copy the first line to the other lines with corresponding offset */
260 for (i=0, j=0, offset=0; i<height; i++, j += width) {
261 offset = (int)(a*i+0.5)*3;
262 memcpy(&(image->data[j]), &ptr[offset], width);
265 RDestroyImage(tmp);
266 return image;
270 static RImage*
271 renderMHGradient(unsigned width, unsigned height, RColor **colors, int count)
273 int i, j, k;
274 unsigned long r, g, b, dr, dg, db;
275 RImage *image;
276 unsigned char *ptr;
277 unsigned width2;
280 assert(count > 2);
282 image = RCreateImage(width, height, False);
283 if (!image) {
284 return NULL;
286 ptr = image->data;
288 if (count > width)
289 count = width;
291 if (count > 1)
292 width2 = width/(count-1);
293 else
294 width2 = width;
296 k = 0;
298 r = colors[0]->red << 16;
299 g = colors[0]->green << 16;
300 b = colors[0]->blue << 16;
302 /* render the first line */
303 for (i=1; i<count; i++) {
304 dr = ((int)(colors[i]->red - colors[i-1]->red) <<16)/(int)width2;
305 dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)width2;
306 db = ((int)(colors[i]->blue - colors[i-1]->blue) <<16)/(int)width2;
307 for (j=0; j<width2; j++) {
308 *ptr++ = (unsigned char)(r>>16);
309 *ptr++ = (unsigned char)(g>>16);
310 *ptr++ = (unsigned char)(b>>16);
311 r += dr;
312 g += dg;
313 b += db;
314 k++;
316 r = colors[i]->red << 16;
317 g = colors[i]->green << 16;
318 b = colors[i]->blue << 16;
320 for (j=k; j<width; j++) {
321 *ptr++ = (unsigned char)(r>>16);
322 *ptr++ = (unsigned char)(g>>16);
323 *ptr++ = (unsigned char)(b>>16);
326 /* copy the first line to the other lines */
327 for (i=1; i<height; i++) {
328 memcpy(&(image->data[i*width*3]), image->data, width*3);
330 return image;
336 static RImage*
337 renderMVGradient(unsigned width, unsigned height, RColor **colors, int count)
339 int i, j, k;
340 unsigned long r, g, b, dr, dg, db;
341 RImage *image;
342 unsigned char *ptr, *tmp;
343 unsigned height2;
344 int x;
345 unsigned char rr, gg, bb;
348 assert(count > 2);
350 image = RCreateImage(width, height, False);
351 if (!image) {
352 return NULL;
354 ptr = image->data;
356 if (count > height)
357 count = height;
359 if (count > 1)
360 height2 = height/(count-1);
361 else
362 height2 = height;
364 k = 0;
366 r = colors[0]->red << 16;
367 g = colors[0]->green << 16;
368 b = colors[0]->blue << 16;
370 for (i=1; i<count; i++) {
371 dr = ((int)(colors[i]->red - colors[i-1]->red) <<16)/(int)height2;
372 dg = ((int)(colors[i]->green - colors[i-1]->green)<<16)/(int)height2;
373 db = ((int)(colors[i]->blue - colors[i-1]->blue) <<16)/(int)height2;
375 for (j=0; j<height2; j++) {
376 rr = r>>16;
377 gg = g>>16;
378 bb = b>>16;
380 for (x=0; x<width/4; x++) {
381 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
382 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
383 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
384 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
386 switch (width%4) {
387 case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
388 case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
389 case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
391 r += dr;
392 g += dg;
393 b += db;
394 k++;
396 r = colors[i]->red << 16;
397 g = colors[i]->green << 16;
398 b = colors[i]->blue << 16;
401 rr = r>>16;
402 gg = g>>16;
403 bb = b>>16;
405 if (k<height) {
406 tmp = ptr;
407 for (x=0; x<width/4; x++) {
408 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
409 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
410 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
411 *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
413 switch (width%4) {
414 case 3: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
415 case 2: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
416 case 1: *ptr++ = rr; *ptr++ = gg; *ptr++ = bb;
417 default: break;
420 for (j=k+1; j<height; j++) {
421 memcpy(ptr, tmp, width*3);
422 ptr += width*3;
426 return image;
430 static RImage*
431 renderMDGradient(unsigned width, unsigned height, RColor **colors, int count)
433 RImage *image, *tmp;
434 float a;
435 int i, offset, j;
436 unsigned char *ptr;
438 assert(count > 2);
440 if (width == 1)
441 return renderMVGradient(width, height, colors, count);
442 else if (height == 1)
443 return renderMHGradient(width, height, colors, count);
445 image = RCreateImage(width, height, False);
446 if (!image) {
447 return NULL;
450 if (count > width)
451 count = width;
452 if (count > height)
453 count = height;
455 if (count > 2)
456 tmp = renderMHGradient(2*width-1, 1, colors, count);
457 else
458 tmp = renderHGradient(2*width-1, 1, colors[0]->red<<8,
459 colors[0]->green<<8, colors[0]->blue<<8,
460 colors[1]->red<<8, colors[1]->green<<8,
461 colors[1]->blue<<8);
463 if (!tmp) {
464 RDestroyImage(image);
465 return NULL;
467 ptr = tmp->data;
470 a = ((float)(width - 1))/((float)(height - 1));
472 /* copy the first line to the other lines with corresponding offset */
473 for (i=0, j=0, offset=0; i<height; i++, j += width) {
474 offset = (int)(a*i+0.5)*3;
475 memcpy(&(image->data[j]), &ptr[offset], width);
477 RDestroyImage(tmp);
478 return image;