Change to the linux kernel coding style
[wmaker-crm.git] / wrlib / gradient.c
1 /* gradient.c - renders gradients
2  *
3  * Raster graphics library
4  *
5  * Copyright (c) 1997-2003 Alfredo K. Kojima
6  * Copyright (c) 1998-2003 Dan Pascu
7  *
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.
12  *
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.
17  *
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., 675 Mass Ave, Cambridge, MA 02139, USA.
21  */
22
23 #include <config.h>
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28
29 #include <assert.h>
30
31 #include "wraster.h"
32
33 static RImage *renderHGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf);
34 static RImage *renderVGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf);
35 static RImage *renderDGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf);
36
37 static RImage *renderMHGradient(unsigned width, unsigned height, RColor ** colors, int count);
38 static RImage *renderMVGradient(unsigned width, unsigned height, RColor ** colors, int count);
39 static RImage *renderMDGradient(unsigned width, unsigned height, RColor ** colors, int count);
40
41 RImage *RRenderMultiGradient(unsigned width, unsigned height, RColor ** colors, int style)
42 {
43         int count;
44
45         count = 0;
46         while (colors[count] != NULL)
47                 count++;
48
49         if (count > 2) {
50                 switch (style) {
51                 case RHorizontalGradient:
52                         return renderMHGradient(width, height, colors, count);
53                 case RVerticalGradient:
54                         return renderMVGradient(width, height, colors, count);
55                 case RDiagonalGradient:
56                         return renderMDGradient(width, height, colors, count);
57                 }
58         } else if (count > 1) {
59                 return RRenderGradient(width, height, colors[0], colors[1], style);
60         } else if (count > 0) {
61                 return RRenderGradient(width, height, colors[0], colors[0], style);
62         }
63         assert(0);
64         return NULL;
65 }
66
67 RImage *RRenderGradient(unsigned width, unsigned height, RColor * from, RColor * to, int style)
68 {
69         switch (style) {
70         case RHorizontalGradient:
71                 return renderHGradient(width, height, from->red, from->green,
72                                        from->blue, to->red, to->green, to->blue);
73         case RVerticalGradient:
74                 return renderVGradient(width, height, from->red, from->green,
75                                        from->blue, to->red, to->green, to->blue);
76
77         case RDiagonalGradient:
78                 return renderDGradient(width, height, from->red, from->green,
79                                        from->blue, to->red, to->green, to->blue);
80         }
81         assert(0);
82         return NULL;
83 }
84
85 /*
86  *----------------------------------------------------------------------
87  * renderHGradient--
88  *      Renders a horizontal linear gradient of the specified size in the
89  * RImage format with a border of the specified type.
90  *
91  * Returns:
92  *      A 24bit RImage with the gradient (no alpha channel).
93  *
94  * Side effects:
95  *      None
96  *----------------------------------------------------------------------
97  */
98 static RImage *renderHGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf)
99 {
100         int i;
101         long r, g, b, dr, dg, db;
102         unsigned lineSize = width * 3;
103         RImage *image;
104         unsigned char *ptr;
105
106         image = RCreateImage(width, height, False);
107         if (!image) {
108                 return NULL;
109         }
110         ptr = image->data;
111
112         r = r0 << 16;
113         g = g0 << 16;
114         b = b0 << 16;
115
116         dr = ((rf - r0) << 16) / (int)width;
117         dg = ((gf - g0) << 16) / (int)width;
118         db = ((bf - b0) << 16) / (int)width;
119         /* render the first line */
120         for (i = 0; i < width; i++) {
121                 *(ptr++) = (unsigned char)(r >> 16);
122                 *(ptr++) = (unsigned char)(g >> 16);
123                 *(ptr++) = (unsigned char)(b >> 16);
124                 r += dr;
125                 g += dg;
126                 b += db;
127         }
128
129         /* copy the first line to the other lines */
130         for (i = 1; i < height; i++) {
131                 memcpy(&(image->data[i * lineSize]), image->data, lineSize);
132         }
133         return image;
134 }
135
136 /*
137  *----------------------------------------------------------------------
138  * renderVGradient--
139  *      Renders a vertical linear gradient of the specified size in the
140  * RImage format with a border of the specified type.
141  *
142  * Returns:
143  *      A 24bit RImage with the gradient (no alpha channel).
144  *
145  * Side effects:
146  *      None
147  *----------------------------------------------------------------------
148  */
149 static RImage *renderVGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf)
150 {
151         int i, j;
152         long r, g, b, dr, dg, db;
153         RImage *image;
154         unsigned char *ptr;
155         unsigned char rr, gg, bb;
156
157         image = RCreateImage(width, height, False);
158         if (!image) {
159                 return NULL;
160         }
161         ptr = image->data;
162
163         r = r0 << 16;
164         g = g0 << 16;
165         b = b0 << 16;
166
167         dr = ((rf - r0) << 16) / (int)height;
168         dg = ((gf - g0) << 16) / (int)height;
169         db = ((bf - b0) << 16) / (int)height;
170
171         for (i = 0; i < height; i++) {
172                 rr = r >> 16;
173                 gg = g >> 16;
174                 bb = b >> 16;
175                 for (j = 0; j < width / 8; j++) {
176                         *(ptr++) = rr;
177                         *(ptr++) = gg;
178                         *(ptr++) = bb;
179                         *(ptr++) = rr;
180                         *(ptr++) = gg;
181                         *(ptr++) = bb;
182                         *(ptr++) = rr;
183                         *(ptr++) = gg;
184                         *(ptr++) = bb;
185                         *(ptr++) = rr;
186                         *(ptr++) = gg;
187                         *(ptr++) = bb;
188                         *(ptr++) = rr;
189                         *(ptr++) = gg;
190                         *(ptr++) = bb;
191                         *(ptr++) = rr;
192                         *(ptr++) = gg;
193                         *(ptr++) = bb;
194                         *(ptr++) = rr;
195                         *(ptr++) = gg;
196                         *(ptr++) = bb;
197                         *(ptr++) = rr;
198                         *(ptr++) = gg;
199                         *(ptr++) = bb;
200                 }
201                 switch (width % 8) {
202                 case 7:
203                         *(ptr++) = rr;
204                         *(ptr++) = gg;
205                         *(ptr++) = bb;
206                 case 6:
207                         *(ptr++) = rr;
208                         *(ptr++) = gg;
209                         *(ptr++) = bb;
210                 case 5:
211                         *(ptr++) = rr;
212                         *(ptr++) = gg;
213                         *(ptr++) = bb;
214                 case 4:
215                         *(ptr++) = rr;
216                         *(ptr++) = gg;
217                         *(ptr++) = bb;
218                 case 3:
219                         *(ptr++) = rr;
220                         *(ptr++) = gg;
221                         *(ptr++) = bb;
222                 case 2:
223                         *(ptr++) = rr;
224                         *(ptr++) = gg;
225                         *(ptr++) = bb;
226                 case 1:
227                         *(ptr++) = rr;
228                         *(ptr++) = gg;
229                         *(ptr++) = bb;
230                 }
231                 r += dr;
232                 g += dg;
233                 b += db;
234         }
235         return image;
236 }
237
238 /*
239  *----------------------------------------------------------------------
240  * renderDGradient--
241  *      Renders a diagonal linear gradient of the specified size in the
242  * RImage format with a border of the specified type.
243  *
244  * Returns:
245  *      A 24bit RImage with the gradient (no alpha channel).
246  *
247  * Side effects:
248  *      None
249  *----------------------------------------------------------------------
250  */
251
252 static RImage *renderDGradient(unsigned width, unsigned height, int r0, int g0, int b0, int rf, int gf, int bf)
253 {
254         RImage *image, *tmp;
255         int j;
256         float a, offset;
257         unsigned char *ptr;
258
259         if (width == 1)
260                 return renderVGradient(width, height, r0, g0, b0, rf, gf, bf);
261         else if (height == 1)
262                 return renderHGradient(width, height, r0, g0, b0, rf, gf, bf);
263
264         image = RCreateImage(width, height, False);
265         if (!image) {
266                 return NULL;
267         }
268
269         tmp = renderHGradient(2 * width - 1, 1, r0, g0, b0, rf, gf, bf);
270         if (!tmp) {
271                 RReleaseImage(image);
272                 return NULL;
273         }
274
275         ptr = tmp->data;
276
277         a = ((float)(width - 1)) / ((float)(height - 1));
278         width = width * 3;
279
280         /* copy the first line to the other lines with corresponding offset */
281         for (j = 0, offset = 0.0; j < width * height; j += width) {
282                 memcpy(&(image->data[j]), &ptr[3 * (int)offset], width);
283                 offset += a;
284         }
285
286         RReleaseImage(tmp);
287         return image;
288 }
289
290 static RImage *renderMHGradient(unsigned width, unsigned height, RColor ** colors, int count)
291 {
292         int i, j, k;
293         long r, g, b, dr, dg, db;
294         unsigned lineSize = width * 3;
295         RImage *image;
296         unsigned char *ptr;
297         unsigned width2;
298
299         assert(count > 2);
300
301         image = RCreateImage(width, height, False);
302         if (!image) {
303                 return NULL;
304         }
305         ptr = image->data;
306
307         if (count > width)
308                 count = width;
309
310         if (count > 1)
311                 width2 = width / (count - 1);
312         else
313                 width2 = width;
314
315         k = 0;
316
317         r = colors[0]->red << 16;
318         g = colors[0]->green << 16;
319         b = colors[0]->blue << 16;
320
321         /* render the first line */
322         for (i = 1; i < count; i++) {
323                 dr = ((int)(colors[i]->red - colors[i - 1]->red) << 16) / (int)width2;
324                 dg = ((int)(colors[i]->green - colors[i - 1]->green) << 16) / (int)width2;
325                 db = ((int)(colors[i]->blue - colors[i - 1]->blue) << 16) / (int)width2;
326                 for (j = 0; j < width2; j++) {
327                         *ptr++ = (unsigned char)(r >> 16);
328                         *ptr++ = (unsigned char)(g >> 16);
329                         *ptr++ = (unsigned char)(b >> 16);
330                         r += dr;
331                         g += dg;
332                         b += db;
333                         k++;
334                 }
335                 r = colors[i]->red << 16;
336                 g = colors[i]->green << 16;
337                 b = colors[i]->blue << 16;
338         }
339         for (j = k; j < width; j++) {
340                 *ptr++ = (unsigned char)(r >> 16);
341                 *ptr++ = (unsigned char)(g >> 16);
342                 *ptr++ = (unsigned char)(b >> 16);
343         }
344
345         /* copy the first line to the other lines */
346         for (i = 1; i < height; i++) {
347                 memcpy(&(image->data[i * lineSize]), image->data, lineSize);
348         }
349         return image;
350 }
351
352 static RImage *renderMVGradient(unsigned width, unsigned height, RColor ** colors, int count)
353 {
354         int i, j, k;
355         long r, g, b, dr, dg, db;
356         unsigned lineSize = width * 3;
357         RImage *image;
358         unsigned char *ptr, *tmp;
359         unsigned height2;
360         int x;
361         unsigned char rr, gg, bb;
362
363         assert(count > 2);
364
365         image = RCreateImage(width, height, False);
366         if (!image) {
367                 return NULL;
368         }
369         ptr = image->data;
370
371         if (count > height)
372                 count = height;
373
374         if (count > 1)
375                 height2 = height / (count - 1);
376         else
377                 height2 = height;
378
379         k = 0;
380
381         r = colors[0]->red << 16;
382         g = colors[0]->green << 16;
383         b = colors[0]->blue << 16;
384
385         for (i = 1; i < count; i++) {
386                 dr = ((int)(colors[i]->red - colors[i - 1]->red) << 16) / (int)height2;
387                 dg = ((int)(colors[i]->green - colors[i - 1]->green) << 16) / (int)height2;
388                 db = ((int)(colors[i]->blue - colors[i - 1]->blue) << 16) / (int)height2;
389
390                 for (j = 0; j < height2; j++) {
391                         rr = r >> 16;
392                         gg = g >> 16;
393                         bb = b >> 16;
394
395                         for (x = 0; x < width / 4; x++) {
396                                 *ptr++ = rr;
397                                 *ptr++ = gg;
398                                 *ptr++ = bb;
399                                 *ptr++ = rr;
400                                 *ptr++ = gg;
401                                 *ptr++ = bb;
402                                 *ptr++ = rr;
403                                 *ptr++ = gg;
404                                 *ptr++ = bb;
405                                 *ptr++ = rr;
406                                 *ptr++ = gg;
407                                 *ptr++ = bb;
408                         }
409                         switch (width % 4) {
410                         case 3:
411                                 *ptr++ = rr;
412                                 *ptr++ = gg;
413                                 *ptr++ = bb;
414                         case 2:
415                                 *ptr++ = rr;
416                                 *ptr++ = gg;
417                                 *ptr++ = bb;
418                         case 1:
419                                 *ptr++ = rr;
420                                 *ptr++ = gg;
421                                 *ptr++ = bb;
422                         }
423                         r += dr;
424                         g += dg;
425                         b += db;
426                         k++;
427                 }
428                 r = colors[i]->red << 16;
429                 g = colors[i]->green << 16;
430                 b = colors[i]->blue << 16;
431         }
432
433         rr = r >> 16;
434         gg = g >> 16;
435         bb = b >> 16;
436
437         if (k < height) {
438                 tmp = ptr;
439                 for (x = 0; x < width / 4; x++) {
440                         *ptr++ = rr;
441                         *ptr++ = gg;
442                         *ptr++ = bb;
443                         *ptr++ = rr;
444                         *ptr++ = gg;
445                         *ptr++ = bb;
446                         *ptr++ = rr;
447                         *ptr++ = gg;
448                         *ptr++ = bb;
449                         *ptr++ = rr;
450                         *ptr++ = gg;
451                         *ptr++ = bb;
452                 }
453                 switch (width % 4) {
454                 case 3:
455                         *ptr++ = rr;
456                         *ptr++ = gg;
457                         *ptr++ = bb;
458                 case 2:
459                         *ptr++ = rr;
460                         *ptr++ = gg;
461                         *ptr++ = bb;
462                 case 1:
463                         *ptr++ = rr;
464                         *ptr++ = gg;
465                         *ptr++ = bb;
466                 default:
467                         break;
468                 }
469
470                 for (j = k + 1; j < height; j++) {
471                         memcpy(ptr, tmp, lineSize);
472                         ptr += lineSize;
473                 }
474         }
475
476         return image;
477 }
478
479 static RImage *renderMDGradient(unsigned width, unsigned height, RColor ** colors, int count)
480 {
481         RImage *image, *tmp;
482         float a, offset;
483         int j;
484         unsigned char *ptr;
485
486         assert(count > 2);
487
488         if (width == 1)
489                 return renderMVGradient(width, height, colors, count);
490         else if (height == 1)
491                 return renderMHGradient(width, height, colors, count);
492
493         image = RCreateImage(width, height, False);
494         if (!image) {
495                 return NULL;
496         }
497
498         if (count > width)
499                 count = width;
500         if (count > height)
501                 count = height;
502
503         if (count > 2)
504                 tmp = renderMHGradient(2 * width - 1, 1, colors, count);
505         else
506                 tmp = renderHGradient(2 * width - 1, 1, colors[0]->red << 8,
507                                       colors[0]->green << 8, colors[0]->blue << 8,
508                                       colors[1]->red << 8, colors[1]->green << 8, colors[1]->blue << 8);
509
510         if (!tmp) {
511                 RReleaseImage(image);
512                 return NULL;
513         }
514         ptr = tmp->data;
515
516         a = ((float)(width - 1)) / ((float)(height - 1));
517         width = width * 3;
518
519         /* copy the first line to the other lines with corresponding offset */
520         for (j = 0, offset = 0; j < width * height; j += width) {
521                 memcpy(&(image->data[j]), &ptr[3 * (int)offset], width);
522                 offset += a;
523         }
524         RReleaseImage(tmp);
525         return image;
526 }
527
528 RImage *RRenderInterwovenGradient(unsigned width, unsigned height,
529                                   RColor colors1[2], int thickness1, RColor colors2[2], int thickness2)
530 {
531         int i, j, k, l, ll;
532         long r1, g1, b1, dr1, dg1, db1;
533         long r2, g2, b2, dr2, dg2, db2;
534         RImage *image;
535         unsigned char *ptr;
536         unsigned char rr, gg, bb;
537
538         image = RCreateImage(width, height, False);
539         if (!image) {
540                 return NULL;
541         }
542         ptr = image->data;
543
544         r1 = colors1[0].red << 16;
545         g1 = colors1[0].green << 16;
546         b1 = colors1[0].blue << 16;
547
548         r2 = colors2[0].red << 16;
549         g2 = colors2[0].green << 16;
550         b2 = colors2[0].blue << 16;
551
552         dr1 = ((colors1[1].red - colors1[0].red) << 16) / (int)height;
553         dg1 = ((colors1[1].green - colors1[0].green) << 16) / (int)height;
554         db1 = ((colors1[1].blue - colors1[0].blue) << 16) / (int)height;
555
556         dr2 = ((colors2[1].red - colors2[0].red) << 16) / (int)height;
557         dg2 = ((colors2[1].green - colors2[0].green) << 16) / (int)height;
558         db2 = ((colors2[1].blue - colors2[0].blue) << 16) / (int)height;
559
560         for (i = 0, k = 0, l = 0, ll = thickness1; i < height; i++) {
561                 if (k == 0) {
562                         rr = r1 >> 16;
563                         gg = g1 >> 16;
564                         bb = b1 >> 16;
565                 } else {
566                         rr = r2 >> 16;
567                         gg = g2 >> 16;
568                         bb = b2 >> 16;
569                 }
570                 for (j = 0; j < width / 8; j++) {
571                         *(ptr++) = rr;
572                         *(ptr++) = gg;
573                         *(ptr++) = bb;
574                         *(ptr++) = rr;
575                         *(ptr++) = gg;
576                         *(ptr++) = bb;
577                         *(ptr++) = rr;
578                         *(ptr++) = gg;
579                         *(ptr++) = bb;
580                         *(ptr++) = rr;
581                         *(ptr++) = gg;
582                         *(ptr++) = bb;
583                         *(ptr++) = rr;
584                         *(ptr++) = gg;
585                         *(ptr++) = bb;
586                         *(ptr++) = rr;
587                         *(ptr++) = gg;
588                         *(ptr++) = bb;
589                         *(ptr++) = rr;
590                         *(ptr++) = gg;
591                         *(ptr++) = bb;
592                         *(ptr++) = rr;
593                         *(ptr++) = gg;
594                         *(ptr++) = bb;
595                 }
596                 switch (width % 8) {
597                 case 7:
598                         *(ptr++) = rr;
599                         *(ptr++) = gg;
600                         *(ptr++) = bb;
601                 case 6:
602                         *(ptr++) = rr;
603                         *(ptr++) = gg;
604                         *(ptr++) = bb;
605                 case 5:
606                         *(ptr++) = rr;
607                         *(ptr++) = gg;
608                         *(ptr++) = bb;
609                 case 4:
610                         *(ptr++) = rr;
611                         *(ptr++) = gg;
612                         *(ptr++) = bb;
613                 case 3:
614                         *(ptr++) = rr;
615                         *(ptr++) = gg;
616                         *(ptr++) = bb;
617                 case 2:
618                         *(ptr++) = rr;
619                         *(ptr++) = gg;
620                         *(ptr++) = bb;
621                 case 1:
622                         *(ptr++) = rr;
623                         *(ptr++) = gg;
624                         *(ptr++) = bb;
625                 }
626                 if (++l == ll) {
627                         if (k == 0) {
628                                 k = 1;
629                                 ll = thickness2;
630                         } else {
631                                 k = 0;
632                                 ll = thickness1;
633                         }
634                         l = 0;
635                 }
636                 r1 += dr1;
637                 g1 += dg1;
638                 b1 += db1;
639
640                 r2 += dr2;
641                 g2 += dg2;
642                 b2 += db2;
643         }
644         return image;
645 }