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