WINGs: inverted the direction for mouse wheel on WMSliders
[wmaker-crm.git] / wrlib / gradient.c
bloba537959e8c1d5cec2a40f6602168db34ec7291d6
1 /* gradient.c - renders gradients
3 * Raster graphics library
5 * Copyright (c) 1997-2003 Alfredo K. Kojima
6 * Copyright (c) 1998-2003 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., 51 Franklin St, Fifth Floor, Boston,
21 * MA 02110-1301, USA.
24 #include <config.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <string.h>
30 #include <assert.h>
32 #include "wraster.h"
34 static RImage *renderHGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf);
35 static RImage *renderVGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf);
36 static RImage *renderDGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf);
38 static RImage *renderMHGradient(unsigned width, unsigned height, RColor ** colors, int count);
39 static RImage *renderMVGradient(unsigned width, unsigned height, RColor ** colors, int count);
40 static RImage *renderMDGradient(unsigned width, unsigned height, RColor ** colors, int count);
42 RImage *RRenderMultiGradient(unsigned width, unsigned height, RColor **colors, RGradientStyle style)
44 int count;
46 count = 0;
47 while (colors[count] != NULL)
48 count++;
50 if (count > 2) {
51 switch (style) {
52 case RHorizontalGradient:
53 return renderMHGradient(width, height, colors, count);
54 case RVerticalGradient:
55 return renderMVGradient(width, height, colors, count);
56 case RDiagonalGradient:
57 return renderMDGradient(width, height, colors, count);
59 } else if (count > 1) {
60 return RRenderGradient(width, height, colors[0], colors[1], style);
61 } else if (count > 0) {
62 return RRenderGradient(width, height, colors[0], colors[0], style);
64 assert(0);
65 return NULL;
68 RImage *RRenderGradient(unsigned width, unsigned height, const RColor *from, const RColor *to, RGradientStyle style)
70 switch (style) {
71 case RHorizontalGradient:
72 return renderHGradient(width, height, from->red, from->green,
73 from->blue, to->red, to->green, to->blue);
74 case RVerticalGradient:
75 return renderVGradient(width, height, from->red, from->green,
76 from->blue, to->red, to->green, to->blue);
78 case RDiagonalGradient:
79 return renderDGradient(width, height, from->red, from->green,
80 from->blue, to->red, to->green, to->blue);
82 assert(0);
83 return NULL;
87 *----------------------------------------------------------------------
88 * renderHGradient--
89 * Renders a horizontal linear gradient of the specified size in the
90 * RImage format with a border of the specified type.
92 * Returns:
93 * A 24bit RImage with the gradient (no alpha channel).
95 * Side effects:
96 * None
97 *----------------------------------------------------------------------
99 static RImage *renderHGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf)
101 int i;
102 long r, g, b, dr, dg, db;
103 unsigned lineSize = width * 3;
104 RImage *image;
105 unsigned char *ptr;
107 image = RCreateImage(width, height, False);
108 if (!image) {
109 return NULL;
111 ptr = image->data;
113 r = r0 << 16;
114 g = g0 << 16;
115 b = b0 << 16;
117 dr = ((rf - r0) << 16) / (int)width;
118 dg = ((gf - g0) << 16) / (int)width;
119 db = ((bf - b0) << 16) / (int)width;
120 /* render the first line */
121 for (i = 0; i < width; i++) {
122 *(ptr++) = (unsigned char)(r >> 16);
123 *(ptr++) = (unsigned char)(g >> 16);
124 *(ptr++) = (unsigned char)(b >> 16);
125 r += dr;
126 g += dg;
127 b += db;
130 /* copy the first line to the other lines */
131 for (i = 1; i < height; i++) {
132 memcpy(&(image->data[i * lineSize]), image->data, lineSize);
134 return image;
137 static inline unsigned char *renderGradientWidth(unsigned char *ptr, unsigned width, unsigned char r, unsigned char g, unsigned char b)
139 int i;
141 for (i = width / 4; i--;) {
142 *ptr++ = r;
143 *ptr++ = g;
144 *ptr++ = b;
146 *ptr++ = r;
147 *ptr++ = g;
148 *ptr++ = b;
150 *ptr++ = r;
151 *ptr++ = g;
152 *ptr++ = b;
154 *ptr++ = r;
155 *ptr++ = g;
156 *ptr++ = b;
158 switch (width % 4) {
159 case 3:
160 *ptr++ = r;
161 *ptr++ = g;
162 *ptr++ = b;
163 case 2:
164 *ptr++ = r;
165 *ptr++ = g;
166 *ptr++ = b;
167 case 1:
168 *ptr++ = r;
169 *ptr++ = g;
170 *ptr++ = b;
172 return ptr;
176 *----------------------------------------------------------------------
177 * renderVGradient--
178 * Renders a vertical linear gradient of the specified size in the
179 * RImage format with a border of the specified type.
181 * Returns:
182 * A 24bit RImage with the gradient (no alpha channel).
184 * Side effects:
185 * None
186 *----------------------------------------------------------------------
188 static RImage *renderVGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf)
190 int i;
191 long r, g, b, dr, dg, db;
192 RImage *image;
193 unsigned char *ptr;
195 image = RCreateImage(width, height, False);
196 if (!image) {
197 return NULL;
199 ptr = image->data;
201 r = r0 << 16;
202 g = g0 << 16;
203 b = b0 << 16;
205 dr = ((rf - r0) << 16) / (int)height;
206 dg = ((gf - g0) << 16) / (int)height;
207 db = ((bf - b0) << 16) / (int)height;
209 for (i = 0; i < height; i++) {
210 ptr = renderGradientWidth(ptr, width, r >> 16, g >> 16, b >> 16);
211 r += dr;
212 g += dg;
213 b += db;
215 return image;
219 *----------------------------------------------------------------------
220 * renderDGradient--
221 * Renders a diagonal linear gradient of the specified size in the
222 * RImage format with a border of the specified type.
224 * Returns:
225 * A 24bit RImage with the gradient (no alpha channel).
227 * Side effects:
228 * None
229 *----------------------------------------------------------------------
232 static RImage *renderDGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf)
234 RImage *image, *tmp;
235 int j;
236 float a, offset;
237 unsigned char *ptr;
239 if (width == 1)
240 return renderVGradient(width, height, r0, g0, b0, rf, gf, bf);
241 else if (height == 1)
242 return renderHGradient(width, height, r0, g0, b0, rf, gf, bf);
244 image = RCreateImage(width, height, False);
245 if (!image) {
246 return NULL;
249 tmp = renderHGradient(2 * width - 1, 1, r0, g0, b0, rf, gf, bf);
250 if (!tmp) {
251 RReleaseImage(image);
252 return NULL;
255 ptr = tmp->data;
257 a = ((float)(width - 1)) / ((float)(height - 1));
258 width = width * 3;
260 /* copy the first line to the other lines with corresponding offset */
261 for (j = 0, offset = 0.0; j < width * height; j += width) {
262 memcpy(&(image->data[j]), &ptr[3 * (int)offset], width);
263 offset += a;
266 RReleaseImage(tmp);
267 return image;
270 static RImage *renderMHGradient(unsigned width, unsigned height, RColor ** colors, int count)
272 int i, j, k;
273 long r, g, b, dr, dg, db;
274 unsigned lineSize = width * 3;
275 RImage *image;
276 unsigned char *ptr;
277 unsigned width2;
279 assert(count > 2);
281 image = RCreateImage(width, height, False);
282 if (!image) {
283 return NULL;
285 ptr = image->data;
287 if (count > width)
288 count = width;
290 if (count > 1)
291 width2 = width / (count - 1);
292 else
293 width2 = width;
295 k = 0;
297 r = colors[0]->red << 16;
298 g = colors[0]->green << 16;
299 b = colors[0]->blue << 16;
301 /* render the first line */
302 for (i = 1; i < count; i++) {
303 dr = ((int)(colors[i]->red - colors[i - 1]->red) << 16) / (int)width2;
304 dg = ((int)(colors[i]->green - colors[i - 1]->green) << 16) / (int)width2;
305 db = ((int)(colors[i]->blue - colors[i - 1]->blue) << 16) / (int)width2;
306 for (j = 0; j < width2; j++) {
307 *ptr++ = (unsigned char)(r >> 16);
308 *ptr++ = (unsigned char)(g >> 16);
309 *ptr++ = (unsigned char)(b >> 16);
310 r += dr;
311 g += dg;
312 b += db;
313 k++;
315 r = colors[i]->red << 16;
316 g = colors[i]->green << 16;
317 b = colors[i]->blue << 16;
319 for (j = k; j < width; j++) {
320 *ptr++ = (unsigned char)(r >> 16);
321 *ptr++ = (unsigned char)(g >> 16);
322 *ptr++ = (unsigned char)(b >> 16);
325 /* copy the first line to the other lines */
326 for (i = 1; i < height; i++) {
327 memcpy(&(image->data[i * lineSize]), image->data, lineSize);
329 return image;
332 static RImage *renderMVGradient(unsigned width, unsigned height, RColor ** colors, int count)
334 int i, j, k;
335 long r, g, b, dr, dg, db;
336 unsigned lineSize = width * 3;
337 RImage *image;
338 unsigned char *ptr, *tmp;
339 unsigned height2;
341 assert(count > 2);
343 image = RCreateImage(width, height, False);
344 if (!image) {
345 return NULL;
347 ptr = image->data;
349 if (count > height)
350 count = height;
352 if (count > 1)
353 height2 = height / (count - 1);
354 else
355 height2 = height;
357 k = 0;
359 r = colors[0]->red << 16;
360 g = colors[0]->green << 16;
361 b = colors[0]->blue << 16;
363 for (i = 1; i < count; i++) {
364 dr = ((int)(colors[i]->red - colors[i - 1]->red) << 16) / (int)height2;
365 dg = ((int)(colors[i]->green - colors[i - 1]->green) << 16) / (int)height2;
366 db = ((int)(colors[i]->blue - colors[i - 1]->blue) << 16) / (int)height2;
368 for (j = 0; j < height2; j++) {
369 ptr = renderGradientWidth(ptr, width, r >> 16, g >> 16, b >> 16);
370 r += dr;
371 g += dg;
372 b += db;
373 k++;
375 r = colors[i]->red << 16;
376 g = colors[i]->green << 16;
377 b = colors[i]->blue << 16;
380 if (k < height) {
381 tmp = ptr;
382 ptr = renderGradientWidth(ptr, width, r >> 16, g >> 16, b >> 16);
383 for (j = k + 1; j < height; j++) {
384 memcpy(ptr, tmp, lineSize);
385 ptr += lineSize;
389 return image;
392 static RImage *renderMDGradient(unsigned width, unsigned height, RColor ** colors, int count)
394 RImage *image, *tmp;
395 float a, offset;
396 int j;
397 unsigned char *ptr;
399 assert(count > 2);
401 if (width == 1)
402 return renderMVGradient(width, height, colors, count);
403 else if (height == 1)
404 return renderMHGradient(width, height, colors, count);
406 image = RCreateImage(width, height, False);
407 if (!image) {
408 return NULL;
411 if (count > width)
412 count = width;
413 if (count > height)
414 count = height;
416 if (count > 2)
417 tmp = renderMHGradient(2 * width - 1, 1, colors, count);
418 else
419 tmp = renderHGradient(2 * width - 1, 1, colors[0]->red << 8,
420 colors[0]->green << 8, colors[0]->blue << 8,
421 colors[1]->red << 8, colors[1]->green << 8, colors[1]->blue << 8);
423 if (!tmp) {
424 RReleaseImage(image);
425 return NULL;
427 ptr = tmp->data;
429 a = ((float)(width - 1)) / ((float)(height - 1));
430 width = width * 3;
432 /* copy the first line to the other lines with corresponding offset */
433 for (j = 0, offset = 0; j < width * height; j += width) {
434 memcpy(&(image->data[j]), &ptr[3 * (int)offset], width);
435 offset += a;
437 RReleaseImage(tmp);
438 return image;
441 RImage *RRenderInterwovenGradient(unsigned width, unsigned height,
442 RColor colors1[2], int thickness1, RColor colors2[2], int thickness2)
444 int i, k, l, ll;
445 long r1, g1, b1, dr1, dg1, db1;
446 long r2, g2, b2, dr2, dg2, db2;
447 RImage *image;
448 unsigned char *ptr;
450 image = RCreateImage(width, height, False);
451 if (!image) {
452 return NULL;
454 ptr = image->data;
456 r1 = colors1[0].red << 16;
457 g1 = colors1[0].green << 16;
458 b1 = colors1[0].blue << 16;
460 r2 = colors2[0].red << 16;
461 g2 = colors2[0].green << 16;
462 b2 = colors2[0].blue << 16;
464 dr1 = ((colors1[1].red - colors1[0].red) << 16) / (int)height;
465 dg1 = ((colors1[1].green - colors1[0].green) << 16) / (int)height;
466 db1 = ((colors1[1].blue - colors1[0].blue) << 16) / (int)height;
468 dr2 = ((colors2[1].red - colors2[0].red) << 16) / (int)height;
469 dg2 = ((colors2[1].green - colors2[0].green) << 16) / (int)height;
470 db2 = ((colors2[1].blue - colors2[0].blue) << 16) / (int)height;
472 for (i = 0, k = 0, l = 0, ll = thickness1; i < height; i++) {
473 if (k == 0)
474 ptr = renderGradientWidth(ptr, width, r1 >> 16, g1 >> 16, b1 >> 16);
475 else
476 ptr = renderGradientWidth(ptr, width, r2 >> 16, g2 >> 16, b2 >> 16);
478 if (++l == ll) {
479 if (k == 0) {
480 k = 1;
481 ll = thickness2;
482 } else {
483 k = 0;
484 ll = thickness1;
486 l = 0;
488 r1 += dr1;
489 g1 += dg1;
490 b1 += db1;
492 r2 += dr2;
493 g2 += dg2;
494 b2 += db2;
496 return image;