rename the Client struct to ObClient
[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, *datav;
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         datav = data;
346         for (y = h - 1; y >= 0; --y) {  /* 0 -> h */
347             *datav = current;
348             datav += w;
349         }
350         ++data;
351
352         NEXT(x);
353     }
354     current = COLOR(x);
355     for (y = h - 1; y >= 0; --y)  /* 0 -> h */
356         *(data + y * w) = current;
357 }
358
359 static void gradient_vertical(RrSurface *sf, int w, int h)
360 {
361     int x, y;
362     RrPixel32 *data = sf->RrPixel_data;
363     RrPixel32 current;
364
365     VARS(y);
366     SETUP(y, sf->primary, sf->secondary, h);
367
368     for (y = h - 1; y > 0; --y) {  /* 0 -> h-1 */
369         current = COLOR(y);
370         for (x = w - 1; x >= 0; --x)  /* 0 -> w */
371             *(data++) = current;
372
373         NEXT(y);
374     }
375     current = COLOR(y);
376     for (x = w - 1; x >= 0; --x)  /* 0 -> w */
377         *(data++) = current;
378 }
379
380
381 static void gradient_diagonal(RrSurface *sf, int w, int h)
382 {
383     int x, y;
384     RrPixel32 *data = sf->RrPixel_data;
385     RrColor left, right;
386     RrColor extracorner;
387
388     VARS(lefty);
389     VARS(righty);
390     VARS(x);
391
392     extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
393     extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
394     extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
395
396     SETUP(lefty, sf->primary, (&extracorner), h);
397     SETUP(righty, (&extracorner), sf->secondary, h);
398
399     for (y = h - 1; y > 0; --y) {  /* 0 -> h-1 */
400         COLOR_RR(lefty, (&left));
401         COLOR_RR(righty, (&right));
402
403         SETUP(x, (&left), (&right), w);
404
405         for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
406             *(data++) = COLOR(x);
407
408             NEXT(x);
409         }
410         *(data++) = COLOR(x);
411
412         NEXT(lefty);
413         NEXT(righty);
414     }
415     COLOR_RR(lefty, (&left));
416     COLOR_RR(righty, (&right));
417
418     SETUP(x, (&left), (&right), w);
419
420     for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
421         *(data++) = COLOR(x);
422         
423         NEXT(x);
424     }
425     *data = COLOR(x);
426 }
427
428 static void gradient_crossdiagonal(RrSurface *sf, int w, int h)
429 {
430     int x, y;
431     RrPixel32 *data = sf->RrPixel_data;
432     RrColor left, right;
433     RrColor extracorner;
434
435     VARS(lefty);
436     VARS(righty);
437     VARS(x);
438
439     extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
440     extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
441     extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
442
443     SETUP(lefty, (&extracorner), sf->secondary, h);
444     SETUP(righty, sf->primary, (&extracorner), h);
445
446     for (y = h - 1; y > 0; --y) {  /* 0 -> h-1 */
447         COLOR_RR(lefty, (&left));
448         COLOR_RR(righty, (&right));
449
450         SETUP(x, (&left), (&right), w);
451
452         for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
453             *(data++) = COLOR(x);
454
455             NEXT(x);
456         }
457         *(data++) = COLOR(x);
458
459         NEXT(lefty);
460         NEXT(righty);
461     }
462     COLOR_RR(lefty, (&left));
463     COLOR_RR(righty, (&right));
464
465     SETUP(x, (&left), (&right), w);
466
467     for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
468         *(data++) = COLOR(x);
469         
470         NEXT(x);
471     }
472     *data = COLOR(x);
473 }
474
475 static void gradient_pyramid(RrSurface *sf, int inw, int inh)
476 {
477     int x, y, w = (inw >> 1) + 1, h = (inh >> 1) + 1;
478     RrPixel32 *data = sf->RrPixel_data;
479     RrPixel32 *end = data + inw*inh - 1;
480     RrPixel32 current;
481     RrColor left, right;
482     RrColor extracorner;
483
484     VARS(lefty);
485     VARS(righty);
486     VARS(x);
487
488     extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
489     extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
490     extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
491
492     SETUP(lefty, (&extracorner), sf->secondary, h);
493     SETUP(righty, sf->primary, (&extracorner), h);
494
495     for (y = h - 1; y > 0; --y) {  /* 0 -> h-1 */
496         COLOR_RR(lefty, (&left));
497         COLOR_RR(righty, (&right));
498
499         SETUP(x, (&left), (&right), w);
500
501         for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
502             current = COLOR(x);
503             *(data+x) = current;
504             *(data+inw-x) = current;
505             *(end-x) = current;
506             *(end-(inw-x)) = current;
507
508             NEXT(x);
509         }
510         current = COLOR(x);
511         *(data+x) = current;
512         *(data+inw-x) = current;
513         *(end-x) = current;
514         *(end-(inw-x)) = current;
515
516         data+=inw;
517         end-=inw;
518
519         NEXT(lefty);
520         NEXT(righty);
521     }
522     COLOR_RR(lefty, (&left));
523     COLOR_RR(righty, (&right));
524
525     SETUP(x, (&left), (&right), w);
526
527     for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
528         current = COLOR(x);
529         *(data+x) = current;
530         *(data+inw-x) = current;
531         *(end-x) = current;
532         *(end-(inw-x)) = current;
533         
534         NEXT(x);
535     }
536     current = COLOR(x);
537     *(data+x) = current;
538     *(data+inw-x) = current;
539     *(end-x) = current;
540     *(end-(inw-x)) = current;
541 }
542