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
);
138 *----------------------------------------------------------------------
140 * Renders a vertical linear gradient of the specified size in the
141 * RImage format with a border of the specified type.
144 * A 24bit RImage with the gradient (no alpha channel).
148 *----------------------------------------------------------------------
150 static RImage
*renderVGradient(unsigned width
, unsigned height
, int r0
, int g0
, int b0
, int rf
, int gf
, int bf
)
153 long r
, g
, b
, dr
, dg
, db
;
156 unsigned char rr
, gg
, bb
;
158 image
= RCreateImage(width
, height
, False
);
168 dr
= ((rf
- r0
) << 16) / (int)height
;
169 dg
= ((gf
- g0
) << 16) / (int)height
;
170 db
= ((bf
- b0
) << 16) / (int)height
;
172 for (i
= 0; i
< height
; i
++) {
176 for (j
= 0; j
< width
/ 8; j
++) {
240 *----------------------------------------------------------------------
242 * Renders a diagonal linear gradient of the specified size in the
243 * RImage format with a border of the specified type.
246 * A 24bit RImage with the gradient (no alpha channel).
250 *----------------------------------------------------------------------
253 static RImage
*renderDGradient(unsigned width
, unsigned height
, int r0
, int g0
, int b0
, int rf
, int gf
, int bf
)
261 return renderVGradient(width
, height
, r0
, g0
, b0
, rf
, gf
, bf
);
262 else if (height
== 1)
263 return renderHGradient(width
, height
, r0
, g0
, b0
, rf
, gf
, bf
);
265 image
= RCreateImage(width
, height
, False
);
270 tmp
= renderHGradient(2 * width
- 1, 1, r0
, g0
, b0
, rf
, gf
, bf
);
272 RReleaseImage(image
);
278 a
= ((float)(width
- 1)) / ((float)(height
- 1));
281 /* copy the first line to the other lines with corresponding offset */
282 for (j
= 0, offset
= 0.0; j
< width
* height
; j
+= width
) {
283 memcpy(&(image
->data
[j
]), &ptr
[3 * (int)offset
], width
);
291 static RImage
*renderMHGradient(unsigned width
, unsigned height
, RColor
** colors
, int count
)
294 long r
, g
, b
, dr
, dg
, db
;
295 unsigned lineSize
= width
* 3;
302 image
= RCreateImage(width
, height
, False
);
312 width2
= width
/ (count
- 1);
318 r
= colors
[0]->red
<< 16;
319 g
= colors
[0]->green
<< 16;
320 b
= colors
[0]->blue
<< 16;
322 /* render the first line */
323 for (i
= 1; i
< count
; i
++) {
324 dr
= ((int)(colors
[i
]->red
- colors
[i
- 1]->red
) << 16) / (int)width2
;
325 dg
= ((int)(colors
[i
]->green
- colors
[i
- 1]->green
) << 16) / (int)width2
;
326 db
= ((int)(colors
[i
]->blue
- colors
[i
- 1]->blue
) << 16) / (int)width2
;
327 for (j
= 0; j
< width2
; j
++) {
328 *ptr
++ = (unsigned char)(r
>> 16);
329 *ptr
++ = (unsigned char)(g
>> 16);
330 *ptr
++ = (unsigned char)(b
>> 16);
336 r
= colors
[i
]->red
<< 16;
337 g
= colors
[i
]->green
<< 16;
338 b
= colors
[i
]->blue
<< 16;
340 for (j
= k
; j
< width
; j
++) {
341 *ptr
++ = (unsigned char)(r
>> 16);
342 *ptr
++ = (unsigned char)(g
>> 16);
343 *ptr
++ = (unsigned char)(b
>> 16);
346 /* copy the first line to the other lines */
347 for (i
= 1; i
< height
; i
++) {
348 memcpy(&(image
->data
[i
* lineSize
]), image
->data
, lineSize
);
353 static RImage
*renderMVGradient(unsigned width
, unsigned height
, RColor
** colors
, int count
)
356 long r
, g
, b
, dr
, dg
, db
;
357 unsigned lineSize
= width
* 3;
359 unsigned char *ptr
, *tmp
;
362 unsigned char rr
, gg
, bb
;
366 image
= RCreateImage(width
, height
, False
);
376 height2
= height
/ (count
- 1);
382 r
= colors
[0]->red
<< 16;
383 g
= colors
[0]->green
<< 16;
384 b
= colors
[0]->blue
<< 16;
386 for (i
= 1; i
< count
; i
++) {
387 dr
= ((int)(colors
[i
]->red
- colors
[i
- 1]->red
) << 16) / (int)height2
;
388 dg
= ((int)(colors
[i
]->green
- colors
[i
- 1]->green
) << 16) / (int)height2
;
389 db
= ((int)(colors
[i
]->blue
- colors
[i
- 1]->blue
) << 16) / (int)height2
;
391 for (j
= 0; j
< height2
; j
++) {
396 for (x
= 0; x
< width
/ 4; x
++) {
429 r
= colors
[i
]->red
<< 16;
430 g
= colors
[i
]->green
<< 16;
431 b
= colors
[i
]->blue
<< 16;
440 for (x
= 0; x
< width
/ 4; x
++) {
471 for (j
= k
+ 1; j
< height
; j
++) {
472 memcpy(ptr
, tmp
, lineSize
);
480 static RImage
*renderMDGradient(unsigned width
, unsigned height
, RColor
** colors
, int count
)
490 return renderMVGradient(width
, height
, colors
, count
);
491 else if (height
== 1)
492 return renderMHGradient(width
, height
, colors
, count
);
494 image
= RCreateImage(width
, height
, False
);
505 tmp
= renderMHGradient(2 * width
- 1, 1, colors
, count
);
507 tmp
= renderHGradient(2 * width
- 1, 1, colors
[0]->red
<< 8,
508 colors
[0]->green
<< 8, colors
[0]->blue
<< 8,
509 colors
[1]->red
<< 8, colors
[1]->green
<< 8, colors
[1]->blue
<< 8);
512 RReleaseImage(image
);
517 a
= ((float)(width
- 1)) / ((float)(height
- 1));
520 /* copy the first line to the other lines with corresponding offset */
521 for (j
= 0, offset
= 0; j
< width
* height
; j
+= width
) {
522 memcpy(&(image
->data
[j
]), &ptr
[3 * (int)offset
], width
);
529 RImage
*RRenderInterwovenGradient(unsigned width
, unsigned height
,
530 RColor colors1
[2], int thickness1
, RColor colors2
[2], int thickness2
)
533 long r1
, g1
, b1
, dr1
, dg1
, db1
;
534 long r2
, g2
, b2
, dr2
, dg2
, db2
;
537 unsigned char rr
, gg
, bb
;
539 image
= RCreateImage(width
, height
, False
);
545 r1
= colors1
[0].red
<< 16;
546 g1
= colors1
[0].green
<< 16;
547 b1
= colors1
[0].blue
<< 16;
549 r2
= colors2
[0].red
<< 16;
550 g2
= colors2
[0].green
<< 16;
551 b2
= colors2
[0].blue
<< 16;
553 dr1
= ((colors1
[1].red
- colors1
[0].red
) << 16) / (int)height
;
554 dg1
= ((colors1
[1].green
- colors1
[0].green
) << 16) / (int)height
;
555 db1
= ((colors1
[1].blue
- colors1
[0].blue
) << 16) / (int)height
;
557 dr2
= ((colors2
[1].red
- colors2
[0].red
) << 16) / (int)height
;
558 dg2
= ((colors2
[1].green
- colors2
[0].green
) << 16) / (int)height
;
559 db2
= ((colors2
[1].blue
- colors2
[0].blue
) << 16) / (int)height
;
561 for (i
= 0, k
= 0, l
= 0, ll
= thickness1
; i
< height
; i
++) {
571 for (j
= 0; j
< width
/ 8; j
++) {