]> icculus.org git repositories - mikachu/openbox.git/blob - render/gradient.c
made all the gradients work with integer math. removed the pipecross and rectangle...
[mikachu/openbox.git] / render / gradient.c
1 #include "render.h"
2 #include "gradient.h"
3 #include "color.h"
4 #include <glib.h>
5
6 static void highlight(RrPixel32 *x, RrPixel32 *y, gboolean raised);
7 static void gradient_solid(RrAppearance *l, int w, int h);
8 static void gradient_vertical(RrSurface *sf, int w, int h);
9 static void gradient_horizontal(RrSurface *sf, int w, int h);
10 static void gradient_diagonal(RrSurface *sf, int w, int h);
11 static void gradient_crossdiagonal(RrSurface *sf, int w, int h);
12 static void gradient_pyramid(RrSurface *sf, int inw, int inh);
13
14 void RrRender(RrAppearance *a, int w, int h)
15 {
16     RrPixel32 *data = a->surface.RrPixel_data;
17     RrPixel32 current;
18     unsigned int r,g,b;
19     int off, x;
20
21     switch (a->surface.grad) {
22     case RR_SURFACE_SOLID:
23         gradient_solid(a, w, h);
24         return;
25     case RR_SURFACE_VERTICAL:
26         gradient_vertical(&a->surface, w, h);
27         break;
28     case RR_SURFACE_HORIZONTAL:
29         gradient_horizontal(&a->surface, w, h);
30         break;
31     case RR_SURFACE_DIAGONAL:
32         gradient_diagonal(&a->surface, w, h);
33         break;
34     case RR_SURFACE_CROSS_DIAGONAL:
35         gradient_crossdiagonal(&a->surface, w, h);
36         break;
37     case RR_SURFACE_PYRAMID:
38         gradient_pyramid(&a->surface, w, h);
39         break;
40     default:
41         g_message("unhandled gradient");
42         return;
43     }
44   
45     if (a->surface.relief == RR_RELIEF_FLAT && a->surface.border) {
46         r = a->surface.border_color->r;
47         g = a->surface.border_color->g;
48         b = a->surface.border_color->b;
49         current = (r << RrDefaultRedOffset)
50             + (g << RrDefaultGreenOffset)
51             + (b << RrDefaultBlueOffset);
52         for (off = 0, x = 0; x < w; ++x, off++) {
53             *(data + off) = current;
54             *(data + off + ((h-1) * w)) = current;
55         }
56         for (off = 0, x = 0; x < h; ++x, off++) {
57             *(data + (off * w)) = current;
58             *(data + (off * w) + w - 1) = current;
59         }
60     }
61
62     if (a->surface.relief != RR_RELIEF_FLAT) {
63         if (a->surface.bevel == RR_BEVEL_1) {
64             for (off = 1, x = 1; x < w - 1; ++x, off++)
65                 highlight(data + off,
66                           data + off + (h-1) * w,
67                           a->surface.relief==RR_RELIEF_RAISED);
68             for (off = 0, x = 0; x < h; ++x, off++)
69                 highlight(data + off * w,
70                           data + off * w + w - 1,
71                           a->surface.relief==RR_RELIEF_RAISED);
72         }
73
74         if (a->surface.bevel == RR_BEVEL_2) {
75             for (off = 2, x = 2; x < w - 2; ++x, off++)
76                 highlight(data + off + w,
77                           data + off + (h-2) * w,
78                           a->surface.relief==RR_RELIEF_RAISED);
79             for (off = 1, x = 1; x < h-1; ++x, off++)
80                 highlight(data + off * w + 1,
81                           data + off * w + w - 2,
82                           a->surface.relief==RR_RELIEF_RAISED);
83         }
84     }
85 }
86
87 static void highlight(RrPixel32 *x, RrPixel32 *y, gboolean raised)
88 {
89     int r, g, b;
90
91     RrPixel32 *up, *down;
92     if (raised) {
93         up = x;
94         down = y;
95     } else {
96         up = y;
97         down = x;
98     }
99     r = (*up >> RrDefaultRedOffset) & 0xFF;
100     r += r >> 1;
101     g = (*up >> RrDefaultGreenOffset) & 0xFF;
102     g += g >> 1;
103     b = (*up >> RrDefaultBlueOffset) & 0xFF;
104     b += b >> 1;
105     if (r > 0xFF) r = 0xFF;
106     if (g > 0xFF) g = 0xFF;
107     if (b > 0xFF) b = 0xFF;
108     *up = (r << RrDefaultRedOffset) + (g << RrDefaultGreenOffset)
109         + (b << RrDefaultBlueOffset);
110   
111     r = (*down >> RrDefaultRedOffset) & 0xFF;
112     r = (r >> 1) + (r >> 2);
113     g = (*down >> RrDefaultGreenOffset) & 0xFF;
114     g = (g >> 1) + (g >> 2);
115     b = (*down >> RrDefaultBlueOffset) & 0xFF;
116     b = (b >> 1) + (b >> 2);
117     *down = (r << RrDefaultRedOffset) + (g << RrDefaultGreenOffset)
118         + (b << RrDefaultBlueOffset);
119 }
120
121 static void create_bevel_colors(RrAppearance *l)
122 {
123     int r, g, b;
124
125     /* light color */
126     r = l->surface.primary->r;
127     r += r >> 1;
128     g = l->surface.primary->g;
129     g += g >> 1;
130     b = l->surface.primary->b;
131     b += b >> 1;
132     if (r > 0xFF) r = 0xFF;
133     if (g > 0xFF) g = 0xFF;
134     if (b > 0xFF) b = 0xFF;
135     g_assert(!l->surface.bevel_light);
136     l->surface.bevel_light = RrColorNew(l->inst, r, g, b);
137     RrColorAllocateGC(l->surface.bevel_light);
138
139     /* dark color */
140     r = l->surface.primary->r;
141     r = (r >> 1) + (r >> 2);
142     g = l->surface.primary->g;
143     g = (g >> 1) + (g >> 2);
144     b = l->surface.primary->b;
145     b = (b >> 1) + (b >> 2);
146     g_assert(!l->surface.bevel_dark);
147     l->surface.bevel_dark = RrColorNew(l->inst, r, g, b);
148     RrColorAllocateGC(l->surface.bevel_dark);
149 }
150
151 static void gradient_solid(RrAppearance *l, int w, int h) 
152 {
153     RrPixel32 pix;
154     int i, a, b;
155     RrSurface *sp = &l->surface;
156     int left = 0, top = 0, right = w - 1, bottom = h - 1;
157
158     if (sp->primary->gc == None)
159         RrColorAllocateGC(sp->primary);
160     pix = (sp->primary->r << RrDefaultRedOffset)
161         + (sp->primary->g << RrDefaultGreenOffset)
162         + (sp->primary->b << RrDefaultBlueOffset);
163
164     for (a = 0; a < w; a++)
165         for (b = 0; b < h; b++)
166             sp->RrPixel_data[a + b * w] = pix;
167
168     XFillRectangle(RrDisplay(l->inst), l->pixmap, sp->primary->gc,
169                    0, 0, w, h);
170
171     if (sp->interlaced) {
172         if (sp->secondary->gc == None)
173             RrColorAllocateGC(sp->secondary);
174         for (i = 0; i < h; i += 2)
175             XDrawLine(RrDisplay(l->inst), l->pixmap, sp->secondary->gc,
176                       0, i, w, i);
177     }
178
179     switch (sp->relief) {
180     case RR_RELIEF_RAISED:
181         if (!sp->bevel_dark)
182             create_bevel_colors(l);
183
184         switch (sp->bevel) {
185         case RR_BEVEL_1:
186             XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_dark->gc,
187                       left, bottom, right, bottom);
188             XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_dark->gc,
189                       right, bottom, right, top);
190                 
191             XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_light->gc,
192                       left, top, right, top);
193             XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_light->gc,
194                       left, bottom, left, top);
195             break;
196         case RR_BEVEL_2:
197             XDrawLine(RrDisplay(l->inst), l->pixmap,
198                       sp->bevel_dark->gc,
199                       left + 1, bottom - 2, right - 2, bottom - 2);
200             XDrawLine(RrDisplay(l->inst), l->pixmap,
201                       sp->bevel_dark->gc,
202                       right - 2, bottom - 2, right - 2, top + 1);
203
204             XDrawLine(RrDisplay(l->inst), l->pixmap,
205                       sp->bevel_light->gc,
206                       left + 1, top + 1, right - 2, top + 1);
207             XDrawLine(RrDisplay(l->inst), l->pixmap,
208                       sp->bevel_light->gc,
209                       left + 1, bottom - 2, left + 1, top + 1);
210             break;
211         default:
212             g_assert_not_reached(); /* unhandled BevelType */
213         }
214         break;
215     case RR_RELIEF_SUNKEN:
216         if (!sp->bevel_dark)
217             create_bevel_colors(l);
218
219         switch (sp->bevel) {
220         case RR_BEVEL_1:
221             XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_light->gc,
222                       left, bottom, right, bottom);
223             XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_light->gc,
224                       right, bottom, right, top);
225       
226             XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_dark->gc,
227                       left, top, right, top);
228             XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_dark->gc,
229                       left, bottom, left, top);
230             break;
231         case RR_BEVEL_2:
232             XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_light->gc,
233                       left + 1, bottom - 2, right - 2, bottom - 2);
234             XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_light->gc,
235                       right - 2, bottom - 2, right - 2, top + 1);
236       
237             XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_dark->gc,
238                       left + 1, top + 1, right - 2, top + 1);
239             XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_dark->gc,
240                       left + 1, bottom - 2, left + 1, top + 1);
241
242             break;
243         default:
244             g_assert_not_reached(); /* unhandled BevelType */
245         }
246         break;
247     case RR_RELIEF_FLAT:
248         if (sp->border) {
249             if (sp->border_color->gc == None)
250                 RrColorAllocateGC(sp->border_color);
251             XDrawRectangle(RrDisplay(l->inst), l->pixmap, sp->border_color->gc,
252                            left, top, right, bottom);
253         }
254         break;
255     default:  
256         g_assert_not_reached(); /* unhandled ReliefType */
257     }
258 }
259
260 /* * * * * * * * * * * * * * GRADIENT MAGIC WOOT * * * * * * * * * * * * * * */
261
262 #define VARS(x)                                                     \
263     unsigned int color##x[3];                                       \
264     int len##x, cdelta##x[3], error##x[3] = { 0, 0, 0 }, inc##x[3]; \
265     gboolean bigslope##x[3] /* color slope > 1 */
266
267 #define SETUP(x, from, to, w)         \
268     len##x = w;                       \
269                                       \
270     color##x[0] = from->r;            \
271     color##x[1] = from->g;            \
272     color##x[2] = from->b;            \
273                                       \
274     cdelta##x[0] = to->r - from->r;   \
275     cdelta##x[1] = to->g - from->g;   \
276     cdelta##x[2] = to->b - from->b;   \
277                                       \
278     if (cdelta##x[0] < 0) {           \
279         cdelta##x[0] = -cdelta##x[0]; \
280         inc##x[0] = -1;               \
281     } else                            \
282         inc##x[0] = 1;                \
283     if (cdelta##x[1] < 0) {           \
284         cdelta##x[1] = -cdelta##x[1]; \
285         inc##x[1] = -1;               \
286     } else                            \
287         inc##x[1] = 1;                \
288     if (cdelta##x[2] < 0) {           \
289         cdelta##x[2] = -cdelta##x[2]; \
290         inc##x[2] = -1;               \
291     } else                            \
292         inc##x[2] = 1;                \
293     bigslope##x[0] = cdelta##x[0] > w;\
294     bigslope##x[1] = cdelta##x[1] > w;\
295     bigslope##x[2] = cdelta##x[2] > w
296
297 #define COLOR_RR(x, c)                       \
298     c->r = color##x[0];                      \
299     c->g = color##x[1];                      \
300     c->b = color##x[2]
301
302 #define COLOR(x)                             \
303     ((color##x[0] << RrDefaultRedOffset) +   \
304      (color##x[1] << RrDefaultGreenOffset) + \
305      (color##x[2] << RrDefaultBlueOffset))
306
307 #define NEXT(x)                                           \
308 {                                                         \
309     int i;                                                \
310     for (i = 2; i >= 0; --i) {                            \
311         if (!cdelta##x[i]) continue;                      \
312                                                           \
313         if (!bigslope##x[i]) {                            \
314             /* Y (color) is dependant on X */             \
315             error##x[i] += cdelta##x[i];                  \
316             if ((error##x[i] << 1) >= len##x) {           \
317                 color##x[i] += inc##x[i];                 \
318                 error##x[i] -= len##x;                    \
319             }                                             \
320         } else {                                          \
321             /* X is dependant on Y (color) */             \
322             while (1) {                                   \
323                 color##x[i] += inc##x[i];                 \
324                 error##x[i] += len##x;                    \
325                 if ((error##x[i] << 1) >= cdelta##x[i]) { \
326                     error##x[i] -= cdelta##x[i];          \
327                     break;                                \
328                 }                                         \
329             }                                             \
330         }                                                 \
331     }                                                     \
332 }
333
334 static void gradient_horizontal(RrSurface *sf, int w, int h)
335 {
336     int x, y;
337     RrPixel32 *data = sf->RrPixel_data;
338     RrPixel32 current;
339
340     VARS(x);
341     SETUP(x, sf->primary, sf->secondary, w);
342
343     for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
344         current = COLOR(x);
345         for (y = h - 1; y >= 0; --y)  /* 0 -> h */
346             *(data + y * w) = current;
347         ++data;
348
349         NEXT(x);
350     }
351     current = COLOR(x);
352     for (y = h - 1; y >= 0; --y)  /* 0 -> h */
353         *(data + y * w) = current;
354 }
355
356 static void gradient_vertical(RrSurface *sf, int w, int h)
357 {
358     int x, y;
359     RrPixel32 *data = sf->RrPixel_data;
360     RrPixel32 current;
361
362     VARS(y);
363     SETUP(y, sf->primary, sf->secondary, h);
364
365     for (y = h - 1; y > 0; --y) {  /* 0 -> h-1 */
366         current = COLOR(y);
367         for (x = w - 1; x >= 0; --x)  /* 0 -> w */
368             *(data++) = current;
369
370         NEXT(y);
371     }
372     current = COLOR(y);
373     for (x = w - 1; x >= 0; --x)  /* 0 -> w */
374         *(data++) = current;
375 }
376
377
378 static void gradient_diagonal(RrSurface *sf, int w, int h)
379 {
380     int x, y;
381     RrPixel32 *data = sf->RrPixel_data;
382     RrColor left, right;
383     RrColor extracorner;
384
385     VARS(lefty);
386     VARS(righty);
387     VARS(x);
388
389     extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
390     extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
391     extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
392
393     SETUP(lefty, sf->primary, (&extracorner), h);
394     SETUP(righty, (&extracorner), sf->secondary, h);
395
396     for (y = h - 1; y > 0; --y) {  /* 0 -> h-1 */
397         COLOR_RR(lefty, (&left));
398         COLOR_RR(righty, (&right));
399
400         SETUP(x, (&left), (&right), w);
401
402         for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
403             *(data++) = COLOR(x);
404
405             NEXT(x);
406         }
407         *(data++) = COLOR(x);
408
409         NEXT(lefty);
410         NEXT(righty);
411     }
412     COLOR_RR(lefty, (&left));
413     COLOR_RR(righty, (&right));
414
415     SETUP(x, (&left), (&right), w);
416
417     for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
418         *(data++) = COLOR(x);
419         
420         NEXT(x);
421     }
422     *data = COLOR(x);
423 }
424
425 static void gradient_crossdiagonal(RrSurface *sf, int w, int h)
426 {
427     int x, y;
428     RrPixel32 *data = sf->RrPixel_data;
429     RrColor left, right;
430     RrColor extracorner;
431
432     VARS(lefty);
433     VARS(righty);
434     VARS(x);
435
436     extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
437     extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
438     extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
439
440     SETUP(lefty, (&extracorner), sf->secondary, h);
441     SETUP(righty, sf->primary, (&extracorner), h);
442
443     for (y = h - 1; y > 0; --y) {  /* 0 -> h-1 */
444         COLOR_RR(lefty, (&left));
445         COLOR_RR(righty, (&right));
446
447         SETUP(x, (&left), (&right), w);
448
449         for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
450             *(data++) = COLOR(x);
451
452             NEXT(x);
453         }
454         *(data++) = COLOR(x);
455
456         NEXT(lefty);
457         NEXT(righty);
458     }
459     COLOR_RR(lefty, (&left));
460     COLOR_RR(righty, (&right));
461
462     SETUP(x, (&left), (&right), w);
463
464     for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
465         *(data++) = COLOR(x);
466         
467         NEXT(x);
468     }
469     *data = COLOR(x);
470 }
471
472 static void gradient_pyramid(RrSurface *sf, int inw, int inh)
473 {
474     int x, y, w = (inw >> 1) + 1, h = (inh >> 1) + 1;
475     RrPixel32 *data = sf->RrPixel_data;
476     RrPixel32 *end = data + inw*inh - 1;
477     RrPixel32 current;
478     RrColor left, right;
479     RrColor extracorner;
480
481     VARS(lefty);
482     VARS(righty);
483     VARS(x);
484
485     extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
486     extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
487     extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
488
489     SETUP(lefty, (&extracorner), sf->secondary, h);
490     SETUP(righty, sf->primary, (&extracorner), h);
491
492     for (y = h - 1; y > 0; --y) {  /* 0 -> h-1 */
493         COLOR_RR(lefty, (&left));
494         COLOR_RR(righty, (&right));
495
496         SETUP(x, (&left), (&right), w);
497
498         for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
499             current = COLOR(x);
500             *(data+x) = current;
501             *(data+inw-x) = current;
502             *(end-x) = current;
503             *(end-(inw-x)) = current;
504
505             NEXT(x);
506         }
507         current = COLOR(x);
508         *(data+x) = current;
509         *(data+inw-x) = current;
510         *(end-x) = current;
511         *(end-(inw-x)) = current;
512
513         data+=inw;
514         end-=inw;
515
516         NEXT(lefty);
517         NEXT(righty);
518     }
519     COLOR_RR(lefty, (&left));
520     COLOR_RR(righty, (&right));
521
522     SETUP(x, (&left), (&right), w);
523
524     for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
525         current = COLOR(x);
526         *(data+x) = current;
527         *(data+inw-x) = current;
528         *(end-x) = current;
529         *(end-(inw-x)) = current;
530         
531         NEXT(x);
532     }
533     *(data+x) = current;
534     *(data+inw-x) = current;
535     *(end-x) = current;
536     *(end-(inw-x)) = current;
537 }
538