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