1 /* gradient.c - renders gradients
3 * Raster graphics library
5 * Copyright (c) 1997 Alfredo K. Kojima
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
33 static RImage
*renderHGradient(unsigned width
, unsigned height
,
34 int r0
, int g0
, int b0
,
35 int rf
, int gf
, int bf
);
36 static RImage
*renderVGradient(unsigned width
, unsigned height
,
37 int r0
, int g0
, int b0
,
38 int rf
, int gf
, int bf
);
39 static RImage
*renderDGradient(unsigned width
, unsigned height
,
40 int r0
, int g0
, int b0
,
41 int rf
, int gf
, int bf
);
43 static RImage
*renderMHGradient(unsigned width
, unsigned height
,
44 RColor
**colors
, int count
);
45 static RImage
*renderMVGradient(unsigned width
, unsigned height
,
46 RColor
**colors
, int count
);
47 static RImage
*renderMDGradient(unsigned width
, unsigned height
,
48 RColor
**colors
, int count
);
51 RRenderMultiGradient(unsigned width
, unsigned height
, RColor
**colors
, int style
)
56 while (colors
[count
]!=NULL
) count
++;
60 case RHorizontalGradient
:
61 return renderMHGradient(width
, height
, colors
, count
);
62 case RVerticalGradient
:
63 return renderMVGradient(width
, height
, colors
, count
);
64 case RDiagonalGradient
:
65 return renderMDGradient(width
, height
, colors
, count
);
67 } else if (count
> 1) {
68 return RRenderGradient(width
, height
, colors
[0], colors
[1], style
);
69 } else if (count
> 0) {
70 return RRenderGradient(width
, height
, colors
[0], colors
[0], style
);
79 RRenderGradient(unsigned width
, unsigned height
, RColor
*from
, RColor
*to
,
83 case RHorizontalGradient
:
84 return renderHGradient(width
, height
, from
->red
, from
->green
,
85 from
->blue
, to
->red
, to
->green
, to
->blue
);
86 case RVerticalGradient
:
87 return renderVGradient(width
, height
, from
->red
, from
->green
,
88 from
->blue
, to
->red
, to
->green
, to
->blue
);
90 case RDiagonalGradient
:
91 return renderDGradient(width
, height
, from
->red
, from
->green
,
92 from
->blue
, to
->red
, to
->green
, to
->blue
);
100 *----------------------------------------------------------------------
102 * Renders a horizontal linear gradient of the specified size in the
103 * RImage format with a border of the specified type.
106 * A 24bit RImage with the gradient (no alpha channel).
110 *----------------------------------------------------------------------
113 renderHGradient(unsigned width
, unsigned height
, int r0
, int g0
, int b0
,
114 int rf
, int gf
, int bf
)
117 unsigned long r
, g
, b
, dr
, dg
, db
;
119 unsigned char *rp
, *gp
, *bp
;
121 image
= RCreateImage(width
, height
, False
);
133 dr
= ((rf
-r0
)<<16)/(int)width
;
134 dg
= ((gf
-g0
)<<16)/(int)width
;
135 db
= ((bf
-b0
)<<16)/(int)width
;
136 /* render the first line */
137 for (i
=0; i
<width
; i
++) {
138 *(rp
++) = (unsigned char)(r
>>16);
139 *(gp
++) = (unsigned char)(g
>>16);
140 *(bp
++) = (unsigned char)(b
>>16);
147 /* copy the first line to the other lines */
148 for (i
=1; i
<height
; i
++) {
149 memcpy(&(image
->data
[0][i
*width
]), image
->data
[0], width
);
150 memcpy(&(image
->data
[1][i
*width
]), image
->data
[1], width
);
151 memcpy(&(image
->data
[2][i
*width
]), image
->data
[2], width
);
157 *----------------------------------------------------------------------
159 * Renders a vertical linear gradient of the specified size in the
160 * RImage format with a border of the specified type.
163 * A 24bit RImage with the gradient (no alpha channel).
167 *----------------------------------------------------------------------
170 renderVGradient(unsigned width
, unsigned height
, int r0
, int g0
, int b0
,
171 int rf
, int gf
, int bf
)
174 unsigned long r
, g
, b
, dr
, dg
, db
;
176 unsigned char *rp
, *gp
, *bp
;
178 image
= RCreateImage(width
, height
, False
);
190 dr
= ((rf
-r0
)<<16)/(int)height
;
191 dg
= ((gf
-g0
)<<16)/(int)height
;
192 db
= ((bf
-b0
)<<16)/(int)height
;
194 for (i
=0; i
<height
; i
++) {
195 memset(rp
, (unsigned char)(r
>>16), width
);
196 memset(gp
, (unsigned char)(g
>>16), width
);
197 memset(bp
, (unsigned char)(b
>>16), width
);
210 *----------------------------------------------------------------------
212 * Renders a diagonal linear gradient of the specified size in the
213 * RImage format with a border of the specified type.
216 * A 24bit RImage with the gradient (no alpha channel).
220 *----------------------------------------------------------------------
223 /* This version is slower then the one below. It uses more operations,
224 * most of them multiplication of floats. Dan.
227 renderDGradient(unsigned width
, unsigned height
, int r0
, int g0
, int b0
,
228 int rf
, int gf
, int bf
)
231 float from_red
,from_green
,from_blue
;
232 float to_red
,to_green
,to_blue
;
233 float dr
,dg
,db
,dx
,dy
,w
,h
,xred
,yred
,xgreen
,ygreen
,xblue
,yblue
;
235 unsigned char *rp
, *gp
, *bp
;
237 image
= RCreateImage(width
, height
, False
);
245 from_red
= (float)r0
;
246 from_green
= (float)g0
;
247 from_blue
= (float)b0
;
250 to_green
= (float)gf
;
256 dr
= (to_red
- from_red
);
257 dg
= (to_green
- from_green
);
258 db
= (to_blue
- from_blue
);
260 for (y
=0; y
<height
; y
++) {
264 yred
= dr
* dy
+ from_red
;
265 ygreen
= dg
* dy
+ from_green
;
266 yblue
= db
* dy
+ from_blue
;
268 for (x
=0; x
<width
; x
++) {
271 xred
= dr
* dx
+ from_red
;
272 xgreen
= dg
* dx
+ from_green
;
273 xblue
= db
* dx
+ from_blue
;
275 *(rp
++) = (unsigned char)((xred
+ yred
)/2);
276 *(gp
++) = (unsigned char)((xgreen
+ ygreen
)/2);
277 *(bp
++) = (unsigned char)((xblue
+ yblue
)/2);
286 renderDGradient(unsigned width
, unsigned height
, int r0
, int g0
, int b0
,
287 int rf
, int gf
, int bf
)
294 return renderVGradient(width
, height
, r0
, g0
, b0
, rf
, gf
, bf
);
295 else if (height
== 1)
296 return renderHGradient(width
, height
, r0
, g0
, b0
, rf
, gf
, bf
);
298 image
= RCreateImage(width
, height
, False
);
303 tmp
= renderHGradient(2*width
-1, 1, r0
, g0
, b0
, rf
, gf
, bf
);
305 RDestroyImage(image
);
309 a
= ((float)(width
- 1))/((float)(height
- 1));
311 /* copy the first line to the other lines with corresponding offset */
312 for (i
=0; i
<height
; i
++) {
313 offset
= (int)(a
*i
+0.5);
314 memcpy(&(image
->data
[0][i
*width
]), &(tmp
->data
[0][offset
]), width
);
315 memcpy(&(image
->data
[1][i
*width
]), &(tmp
->data
[1][offset
]), width
);
316 memcpy(&(image
->data
[2][i
*width
]), &(tmp
->data
[2][offset
]), width
);
324 renderMHGradient(unsigned width
, unsigned height
, RColor
**colors
, int count
)
327 unsigned long r
, g
, b
, dr
, dg
, db
;
329 unsigned char *rp
, *gp
, *bp
;
335 image
= RCreateImage(width
, height
, False
);
347 width2
= width
/(count
-1);
353 r
= colors
[0]->red
<< 16;
354 g
= colors
[0]->green
<< 16;
355 b
= colors
[0]->blue
<< 16;
357 /* render the first line */
358 for (i
=1; i
<count
; i
++) {
359 dr
= ((int)(colors
[i
]->red
- colors
[i
-1]->red
) <<16)/(int)width2
;
360 dg
= ((int)(colors
[i
]->green
- colors
[i
-1]->green
)<<16)/(int)width2
;
361 db
= ((int)(colors
[i
]->blue
- colors
[i
-1]->blue
) <<16)/(int)width2
;
362 for (j
=0; j
<width2
; j
++) {
363 *(rp
++) = (unsigned char)(r
>>16);
364 *(gp
++) = (unsigned char)(g
>>16);
365 *(bp
++) = (unsigned char)(b
>>16);
371 r
= colors
[i
]->red
<< 16;
372 g
= colors
[i
]->green
<< 16;
373 b
= colors
[i
]->blue
<< 16;
375 for (j
=k
; j
<width
; j
++) {
376 *(rp
++) = (unsigned char)(r
>>16);
377 *(gp
++) = (unsigned char)(g
>>16);
378 *(bp
++) = (unsigned char)(b
>>16);
381 /* copy the first line to the other lines */
382 for (i
=1; i
<height
; i
++) {
383 memcpy(&(image
->data
[0][i
*width
]), image
->data
[0], width
);
384 memcpy(&(image
->data
[1][i
*width
]), image
->data
[1], width
);
385 memcpy(&(image
->data
[2][i
*width
]), image
->data
[2], width
);
394 renderMVGradient(unsigned width
, unsigned height
, RColor
**colors
, int count
)
397 unsigned long r
, g
, b
, dr
, dg
, db
;
399 unsigned char *rp
, *gp
, *bp
;
405 image
= RCreateImage(width
, height
, False
);
417 height2
= height
/(count
-1);
423 r
= colors
[0]->red
<< 16;
424 g
= colors
[0]->green
<< 16;
425 b
= colors
[0]->blue
<< 16;
427 for (i
=1; i
<count
; i
++) {
428 dr
= ((int)(colors
[i
]->red
- colors
[i
-1]->red
) <<16)/(int)height2
;
429 dg
= ((int)(colors
[i
]->green
- colors
[i
-1]->green
)<<16)/(int)height2
;
430 db
= ((int)(colors
[i
]->blue
- colors
[i
-1]->blue
) <<16)/(int)height2
;
431 for (j
=0; j
<height2
; j
++) {
432 memset(rp
, (unsigned char)(r
>>16), width
);
433 memset(gp
, (unsigned char)(g
>>16), width
);
434 memset(bp
, (unsigned char)(b
>>16), width
);
443 r
= colors
[i
]->red
<< 16;
444 g
= colors
[i
]->green
<< 16;
445 b
= colors
[i
]->blue
<< 16;
447 for (j
=k
; j
<height
; j
++) {
448 memset(rp
, (unsigned char)(r
>>16), width
);
449 memset(gp
, (unsigned char)(g
>>16), width
);
450 memset(bp
, (unsigned char)(b
>>16), width
);
461 renderMDGradient(unsigned width
, unsigned height
, RColor
**colors
, int count
)
470 return renderMVGradient(width
, height
, colors
, count
);
471 else if (height
== 1)
472 return renderMHGradient(width
, height
, colors
, count
);
474 image
= RCreateImage(width
, height
, False
);
485 tmp
= renderMHGradient(2*width
-1, 1, colors
, count
);
487 tmp
= renderHGradient(2*width
-1, 1, colors
[0]->red
<<8,
488 colors
[0]->green
<<8, colors
[0]->blue
<<8,
489 colors
[1]->red
<<8, colors
[1]->green
<<8,
493 RDestroyImage(image
);
497 a
= ((float)(width
- 1))/((float)(height
- 1));
499 /* copy the first line to the other lines with corresponding offset */
500 for (i
=0; i
<height
; i
++) {
501 offset
= (int)(a
*i
+0.5);
502 memcpy(&(image
->data
[0][i
*width
]), &(tmp
->data
[0][offset
]), width
);
503 memcpy(&(image
->data
[1][i
*width
]), &(tmp
->data
[1][offset
]), width
);
504 memcpy(&(image
->data
[2][i
*width
]), &(tmp
->data
[2][offset
]), width
);