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,
36 static RImage
*renderHGradient(unsigned width
, unsigned height
, int r0
, int g0
, int b0
, int rf
, int gf
, int bf
);
37 static RImage
*renderVGradient(unsigned width
, unsigned height
, int r0
, int g0
, int b0
, int rf
, int gf
, int bf
);
38 static RImage
*renderDGradient(unsigned width
, unsigned height
, int r0
, int g0
, int b0
, int rf
, int gf
, int bf
);
40 static RImage
*renderMHGradient(unsigned width
, unsigned height
, RColor
** colors
, int count
);
41 static RImage
*renderMVGradient(unsigned width
, unsigned height
, RColor
** colors
, int count
);
42 static RImage
*renderMDGradient(unsigned width
, unsigned height
, RColor
** colors
, int count
);
44 RImage
*RRenderMultiGradient(unsigned width
, unsigned height
, RColor
**colors
, RGradientStyle style
)
49 while (colors
[count
] != NULL
)
54 case RHorizontalGradient
:
55 return renderMHGradient(width
, height
, colors
, count
);
56 case RVerticalGradient
:
57 return renderMVGradient(width
, height
, colors
, count
);
58 case RDiagonalGradient
:
59 return renderMDGradient(width
, height
, colors
, count
);
61 } else if (count
> 1) {
62 return RRenderGradient(width
, height
, colors
[0], colors
[1], style
);
63 } else if (count
> 0) {
64 return RRenderGradient(width
, height
, colors
[0], colors
[0], style
);
70 RImage
*RRenderGradient(unsigned width
, unsigned height
, const RColor
*from
, const RColor
*to
, RGradientStyle style
)
73 case RHorizontalGradient
:
74 return renderHGradient(width
, height
, from
->red
, from
->green
,
75 from
->blue
, to
->red
, to
->green
, to
->blue
);
76 case RVerticalGradient
:
77 return renderVGradient(width
, height
, from
->red
, from
->green
,
78 from
->blue
, to
->red
, to
->green
, to
->blue
);
80 case RDiagonalGradient
:
81 return renderDGradient(width
, height
, from
->red
, from
->green
,
82 from
->blue
, to
->red
, to
->green
, to
->blue
);
89 *----------------------------------------------------------------------
91 * Renders a horizontal linear gradient of the specified size in the
92 * RImage format with a border of the specified type.
95 * A 24bit RImage with the gradient (no alpha channel).
99 *----------------------------------------------------------------------
101 static RImage
*renderHGradient(unsigned width
, unsigned height
, int r0
, int g0
, int b0
, int rf
, int gf
, int bf
)
104 long r
, g
, b
, dr
, dg
, db
;
105 unsigned lineSize
= width
* 3;
109 image
= RCreateImage(width
, height
, False
);
119 dr
= ((rf
- r0
) << 16) / (int)width
;
120 dg
= ((gf
- g0
) << 16) / (int)width
;
121 db
= ((bf
- b0
) << 16) / (int)width
;
122 /* render the first line */
123 for (i
= 0; i
< width
; i
++) {
124 *(ptr
++) = (unsigned char)(r
>> 16);
125 *(ptr
++) = (unsigned char)(g
>> 16);
126 *(ptr
++) = (unsigned char)(b
>> 16);
132 /* copy the first line to the other lines */
133 for (i
= 1; i
< height
; i
++) {
134 memcpy(&(image
->data
[i
* lineSize
]), image
->data
, lineSize
);
139 static inline unsigned char *renderGradientWidth(unsigned char *ptr
, unsigned width
, unsigned char r
, unsigned char g
, unsigned char b
)
143 for (i
= width
/ 4; i
--;) {
180 *----------------------------------------------------------------------
182 * Renders a vertical linear gradient of the specified size in the
183 * RImage format with a border of the specified type.
186 * A 24bit RImage with the gradient (no alpha channel).
190 *----------------------------------------------------------------------
192 static RImage
*renderVGradient(unsigned width
, unsigned height
, int r0
, int g0
, int b0
, int rf
, int gf
, int bf
)
195 long r
, g
, b
, dr
, dg
, db
;
199 image
= RCreateImage(width
, height
, False
);
209 dr
= ((rf
- r0
) << 16) / (int)height
;
210 dg
= ((gf
- g0
) << 16) / (int)height
;
211 db
= ((bf
- b0
) << 16) / (int)height
;
213 for (i
= 0; i
< height
; i
++) {
214 ptr
= renderGradientWidth(ptr
, width
, r
>> 16, g
>> 16, b
>> 16);
223 *----------------------------------------------------------------------
225 * Renders a diagonal linear gradient of the specified size in the
226 * RImage format with a border of the specified type.
229 * A 24bit RImage with the gradient (no alpha channel).
233 *----------------------------------------------------------------------
236 static RImage
*renderDGradient(unsigned width
, unsigned height
, int r0
, int g0
, int b0
, int rf
, int gf
, int bf
)
244 return renderVGradient(width
, height
, r0
, g0
, b0
, rf
, gf
, bf
);
245 else if (height
== 1)
246 return renderHGradient(width
, height
, r0
, g0
, b0
, rf
, gf
, bf
);
248 image
= RCreateImage(width
, height
, False
);
253 tmp
= renderHGradient(2 * width
- 1, 1, r0
, g0
, b0
, rf
, gf
, bf
);
255 RReleaseImage(image
);
261 a
= ((float)(width
- 1)) / ((float)(height
- 1));
264 /* copy the first line to the other lines with corresponding offset */
265 for (j
= 0, offset
= 0.0; j
< width
* height
; j
+= width
) {
266 memcpy(&(image
->data
[j
]), &ptr
[3 * (int)offset
], width
);
274 static RImage
*renderMHGradient(unsigned width
, unsigned height
, RColor
** colors
, int count
)
277 long r
, g
, b
, dr
, dg
, db
;
278 unsigned lineSize
= width
* 3;
285 image
= RCreateImage(width
, height
, False
);
295 width2
= width
/ (count
- 1);
301 r
= colors
[0]->red
<< 16;
302 g
= colors
[0]->green
<< 16;
303 b
= colors
[0]->blue
<< 16;
305 /* render the first line */
306 for (i
= 1; i
< count
; i
++) {
307 dr
= ((int)(colors
[i
]->red
- colors
[i
- 1]->red
) << 16) / (int)width2
;
308 dg
= ((int)(colors
[i
]->green
- colors
[i
- 1]->green
) << 16) / (int)width2
;
309 db
= ((int)(colors
[i
]->blue
- colors
[i
- 1]->blue
) << 16) / (int)width2
;
310 for (j
= 0; j
< width2
; j
++) {
311 *ptr
++ = (unsigned char)(r
>> 16);
312 *ptr
++ = (unsigned char)(g
>> 16);
313 *ptr
++ = (unsigned char)(b
>> 16);
319 r
= colors
[i
]->red
<< 16;
320 g
= colors
[i
]->green
<< 16;
321 b
= colors
[i
]->blue
<< 16;
323 for (j
= k
; j
< width
; j
++) {
324 *ptr
++ = (unsigned char)(r
>> 16);
325 *ptr
++ = (unsigned char)(g
>> 16);
326 *ptr
++ = (unsigned char)(b
>> 16);
329 /* copy the first line to the other lines */
330 for (i
= 1; i
< height
; i
++) {
331 memcpy(&(image
->data
[i
* lineSize
]), image
->data
, lineSize
);
336 static RImage
*renderMVGradient(unsigned width
, unsigned height
, RColor
** colors
, int count
)
339 long r
, g
, b
, dr
, dg
, db
;
340 unsigned lineSize
= width
* 3;
342 unsigned char *ptr
, *tmp
;
347 image
= RCreateImage(width
, height
, False
);
357 height2
= height
/ (count
- 1);
363 r
= colors
[0]->red
<< 16;
364 g
= colors
[0]->green
<< 16;
365 b
= colors
[0]->blue
<< 16;
367 for (i
= 1; i
< count
; i
++) {
368 dr
= ((int)(colors
[i
]->red
- colors
[i
- 1]->red
) << 16) / (int)height2
;
369 dg
= ((int)(colors
[i
]->green
- colors
[i
- 1]->green
) << 16) / (int)height2
;
370 db
= ((int)(colors
[i
]->blue
- colors
[i
- 1]->blue
) << 16) / (int)height2
;
372 for (j
= 0; j
< height2
; j
++) {
373 ptr
= renderGradientWidth(ptr
, width
, r
>> 16, g
>> 16, b
>> 16);
379 r
= colors
[i
]->red
<< 16;
380 g
= colors
[i
]->green
<< 16;
381 b
= colors
[i
]->blue
<< 16;
386 ptr
= renderGradientWidth(ptr
, width
, r
>> 16, g
>> 16, b
>> 16);
387 for (j
= k
+ 1; j
< height
; j
++) {
388 memcpy(ptr
, tmp
, lineSize
);
396 static RImage
*renderMDGradient(unsigned width
, unsigned height
, RColor
** colors
, int count
)
406 return renderMVGradient(width
, height
, colors
, count
);
407 else if (height
== 1)
408 return renderMHGradient(width
, height
, colors
, count
);
410 image
= RCreateImage(width
, height
, False
);
421 tmp
= renderMHGradient(2 * width
- 1, 1, colors
, count
);
423 tmp
= renderHGradient(2 * width
- 1, 1, colors
[0]->red
<< 8,
424 colors
[0]->green
<< 8, colors
[0]->blue
<< 8,
425 colors
[1]->red
<< 8, colors
[1]->green
<< 8, colors
[1]->blue
<< 8);
428 RReleaseImage(image
);
433 a
= ((float)(width
- 1)) / ((float)(height
- 1));
436 /* copy the first line to the other lines with corresponding offset */
437 for (j
= 0, offset
= 0; j
< width
* height
; j
+= width
) {
438 memcpy(&(image
->data
[j
]), &ptr
[3 * (int)offset
], width
);
445 RImage
*RRenderInterwovenGradient(unsigned width
, unsigned height
,
446 RColor colors1
[2], int thickness1
, RColor colors2
[2], int thickness2
)
449 long r1
, g1
, b1
, dr1
, dg1
, db1
;
450 long r2
, g2
, b2
, dr2
, dg2
, db2
;
454 image
= RCreateImage(width
, height
, False
);
460 r1
= colors1
[0].red
<< 16;
461 g1
= colors1
[0].green
<< 16;
462 b1
= colors1
[0].blue
<< 16;
464 r2
= colors2
[0].red
<< 16;
465 g2
= colors2
[0].green
<< 16;
466 b2
= colors2
[0].blue
<< 16;
468 dr1
= ((colors1
[1].red
- colors1
[0].red
) << 16) / (int)height
;
469 dg1
= ((colors1
[1].green
- colors1
[0].green
) << 16) / (int)height
;
470 db1
= ((colors1
[1].blue
- colors1
[0].blue
) << 16) / (int)height
;
472 dr2
= ((colors2
[1].red
- colors2
[0].red
) << 16) / (int)height
;
473 dg2
= ((colors2
[1].green
- colors2
[0].green
) << 16) / (int)height
;
474 db2
= ((colors2
[1].blue
- colors2
[0].blue
) << 16) / (int)height
;
476 for (i
= 0, k
= 0, l
= 0, ll
= thickness1
; i
< height
; i
++) {
478 ptr
= renderGradientWidth(ptr
, width
, r1
>> 16, g1
>> 16, b1
>> 16);
480 ptr
= renderGradientWidth(ptr
, width
, r2
>> 16, g2
>> 16, b2
>> 16);