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,
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
)
47 while (colors
[count
] != NULL
)
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
);
68 RImage
*RRenderGradient(unsigned width
, unsigned height
, const RColor
*from
, const RColor
*to
, RGradientStyle 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
);
87 *----------------------------------------------------------------------
89 * Renders a horizontal linear gradient of the specified size in the
90 * RImage format with a border of the specified type.
93 * A 24bit RImage with the gradient (no alpha channel).
97 *----------------------------------------------------------------------
99 static RImage
*renderHGradient(unsigned width
, unsigned height
, int r0
, int g0
, int b0
, int rf
, int gf
, int bf
)
102 long r
, g
, b
, dr
, dg
, db
;
103 unsigned lineSize
= width
* 3;
107 image
= RCreateImage(width
, height
, False
);
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);
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
);
137 static inline unsigned char *renderGradientWidth(unsigned char *ptr
, unsigned width
, unsigned char r
, unsigned char g
, unsigned char b
)
141 for (i
= width
/ 4; i
--;) {
176 *----------------------------------------------------------------------
178 * Renders a vertical linear gradient of the specified size in the
179 * RImage format with a border of the specified type.
182 * A 24bit RImage with the gradient (no alpha channel).
186 *----------------------------------------------------------------------
188 static RImage
*renderVGradient(unsigned width
, unsigned height
, int r0
, int g0
, int b0
, int rf
, int gf
, int bf
)
191 long r
, g
, b
, dr
, dg
, db
;
195 image
= RCreateImage(width
, height
, False
);
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);
219 *----------------------------------------------------------------------
221 * Renders a diagonal linear gradient of the specified size in the
222 * RImage format with a border of the specified type.
225 * A 24bit RImage with the gradient (no alpha channel).
229 *----------------------------------------------------------------------
232 static RImage
*renderDGradient(unsigned width
, unsigned height
, int r0
, int g0
, int b0
, int rf
, int gf
, int bf
)
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
);
249 tmp
= renderHGradient(2 * width
- 1, 1, r0
, g0
, b0
, rf
, gf
, bf
);
251 RReleaseImage(image
);
257 a
= ((float)(width
- 1)) / ((float)(height
- 1));
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
);
270 static RImage
*renderMHGradient(unsigned width
, unsigned height
, RColor
** colors
, int count
)
273 long r
, g
, b
, dr
, dg
, db
;
274 unsigned lineSize
= width
* 3;
281 image
= RCreateImage(width
, height
, False
);
291 width2
= width
/ (count
- 1);
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);
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
);
332 static RImage
*renderMVGradient(unsigned width
, unsigned height
, RColor
** colors
, int count
)
335 long r
, g
, b
, dr
, dg
, db
;
336 unsigned lineSize
= width
* 3;
338 unsigned char *ptr
, *tmp
;
343 image
= RCreateImage(width
, height
, False
);
353 height2
= height
/ (count
- 1);
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);
375 r
= colors
[i
]->red
<< 16;
376 g
= colors
[i
]->green
<< 16;
377 b
= colors
[i
]->blue
<< 16;
382 ptr
= renderGradientWidth(ptr
, width
, r
>> 16, g
>> 16, b
>> 16);
383 for (j
= k
+ 1; j
< height
; j
++) {
384 memcpy(ptr
, tmp
, lineSize
);
392 static RImage
*renderMDGradient(unsigned width
, unsigned height
, RColor
** colors
, int count
)
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
);
417 tmp
= renderMHGradient(2 * width
- 1, 1, colors
, count
);
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);
424 RReleaseImage(image
);
429 a
= ((float)(width
- 1)) / ((float)(height
- 1));
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
);
441 RImage
*RRenderInterwovenGradient(unsigned width
, unsigned height
,
442 RColor colors1
[2], int thickness1
, RColor colors2
[2], int thickness2
)
445 long r1
, g1
, b1
, dr1
, dg1
, db1
;
446 long r2
, g2
, b2
, dr2
, dg2
, db2
;
450 image
= RCreateImage(width
, height
, False
);
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
++) {
474 ptr
= renderGradientWidth(ptr
, width
, r1
>> 16, g1
>> 16, b1
>> 16);
476 ptr
= renderGradientWidth(ptr
, width
, r2
>> 16, g2
>> 16, b2
>> 16);