rectangle and diagonal grads yay
[dana/openbox.git] / render / gradient.c
1 #include <GL/gl.h>
2 #include <glib.h>
3 #include "render.h"
4 #include "gradient.h"
5 #include "../kernel/openbox.h"
6 #include "color.h"
7
8 void gradient_render(Surface *sf, int w, int h)
9 {
10     pixel32 *data = sf->data.planar.pixel_data;
11     pixel32 current;
12     unsigned int r,g,b;
13     int off, x;
14
15     switch (sf->data.planar.grad) {
16     case Background_Solid: /* already handled */
17         return;
18     case Background_Vertical:
19         gradient_vertical(sf, w, h);
20         break;
21     case Background_Horizontal:
22         gradient_horizontal(sf, w, h);
23         break;
24     case Background_Diagonal:
25         gradient_diagonal(sf, w, h);
26         break;
27     case Background_CrossDiagonal:
28         gradient_crossdiagonal(sf, w, h);
29         break;
30     case Background_Pyramid:
31         gradient_pyramid(sf, w, h);
32         break;
33     case Background_PipeCross:
34         gradient_pipecross(sf, w, h);
35         break;
36     case Background_Rectangle:
37         gradient_rectangle(sf, w, h);
38         break;
39     default:
40         g_message("unhandled gradient");
41         return;
42     }
43   
44     if (sf->data.planar.relief == Flat && sf->data.planar.border) {
45         r = sf->data.planar.border_color->r;
46         g = sf->data.planar.border_color->g;
47         b = sf->data.planar.border_color->b;
48         current = (r << default_red_offset)
49             + (g << default_green_offset)
50             + (b << default_blue_offset);
51         for (off = 0, x = 0; x < w; ++x, off++) {
52             *(data + off) = current;
53             *(data + off + ((h-1) * w)) = current;
54         }
55         for (off = 0, x = 0; x < h; ++x, off++) {
56             *(data + (off * w)) = current;
57             *(data + (off * w) + w - 1) = current;
58         }
59     }
60
61     if (sf->data.planar.relief != Flat) {
62         if (sf->data.planar.bevel == Bevel1) {
63             for (off = 1, x = 1; x < w - 1; ++x, off++)
64                 highlight(data + off,
65                           data + off + (h-1) * w,
66                           sf->data.planar.relief==Raised);
67             for (off = 0, x = 0; x < h; ++x, off++)
68                 highlight(data + off * w,
69                           data + off * w + w - 1,
70                           sf->data.planar.relief==Raised);
71         }
72
73         if (sf->data.planar.bevel == Bevel2) {
74             for (off = 2, x = 2; x < w - 2; ++x, off++)
75                 highlight(data + off + w,
76                           data + off + (h-2) * w,
77                           sf->data.planar.relief==Raised);
78             for (off = 1, x = 1; x < h-1; ++x, off++)
79                 highlight(data + off * w + 1,
80                           data + off * w + w - 2,
81                           sf->data.planar.relief==Raised);
82         }
83     }
84 }
85
86
87
88 void gradient_vertical(Surface *sf, int w, int h)
89 {
90     pixel32 *data = sf->data.planar.pixel_data;
91     pixel32 current;
92     float dr, dg, db;
93     unsigned int r,g,b;
94     int x, y;
95
96     dr = (float)(sf->data.planar.secondary->r - sf->data.planar.primary->r);
97     dr/= (float)h;
98
99     dg = (float)(sf->data.planar.secondary->g - sf->data.planar.primary->g);
100     dg/= (float)h;
101
102     db = (float)(sf->data.planar.secondary->b - sf->data.planar.primary->b);
103     db/= (float)h;
104
105     for (y = 0; y < h; ++y) {
106         r = sf->data.planar.primary->r + (int)(dr * y);
107         g = sf->data.planar.primary->g + (int)(dg * y);
108         b = sf->data.planar.primary->b + (int)(db * y);
109         current = (r << default_red_offset)
110             + (g << default_green_offset)
111             + (b << default_blue_offset);
112         for (x = 0; x < w; ++x, ++data)
113             *data = current;
114     }
115 }
116
117 void gradient_horizontal(Surface *sf, int w, int h)
118 {
119     pixel32 *data = sf->data.planar.pixel_data;
120     pixel32 current;
121     float dr, dg, db;
122     unsigned int r,g,b;
123     int x, y;
124
125     dr = (float)(sf->data.planar.secondary->r - sf->data.planar.primary->r);
126     dr/= (float)w;
127
128     dg = (float)(sf->data.planar.secondary->g - sf->data.planar.primary->g);
129     dg/= (float)w;
130
131     db = (float)(sf->data.planar.secondary->b - sf->data.planar.primary->b);
132     db/= (float)w;
133
134     for (x = 0; x < w; ++x, ++data) {
135         r = sf->data.planar.primary->r + (int)(dr * x);
136         g = sf->data.planar.primary->g + (int)(dg * x);
137         b = sf->data.planar.primary->b + (int)(db * x);
138         current = (r << default_red_offset)
139             + (g << default_green_offset)
140             + (b << default_blue_offset);
141         for (y = 0; y < h; ++y)
142             *(data + y*w) = current;
143     }
144 }
145
146 void gradient_diagonal(Surface *sf, int w, int h)
147 {
148     pixel32 *data = sf->data.planar.pixel_data;
149     pixel32 current;
150     float drx, dgx, dbx, dry, dgy, dby;
151     unsigned int r,g,b;
152     int x, y;
153
154     for (y = 0; y < h; ++y) {
155         drx = (float)(sf->data.planar.secondary->r -
156                       sf->data.planar.primary->r);
157         dry = drx/(float)h;
158         drx/= (float)w;
159
160         dgx = (float)(sf->data.planar.secondary->g -
161                       sf->data.planar.primary->g);
162         dgy = dgx/(float)h;
163         dgx/= (float)w;
164
165         dbx = (float)(sf->data.planar.secondary->b -
166                       sf->data.planar.primary->b);
167         dby = dbx/(float)h;
168         dbx/= (float)w;
169         for (x = 0; x < w; ++x, ++data) {
170             r = sf->data.planar.primary->r +
171                 ((int)(drx * x) + (int)(dry * y))/2;
172             g = sf->data.planar.primary->g +
173                 ((int)(dgx * x) + (int)(dgy * y))/2;
174             b = sf->data.planar.primary->b +
175                 ((int)(dbx * x) + (int)(dby * y))/2;
176             current = (r << default_red_offset)
177                 + (g << default_green_offset)
178                 + (b << default_blue_offset);
179             *data = current;
180         }
181     }
182 }
183
184 void gradient_crossdiagonal(Surface *sf, int w, int h)
185 {
186     pixel32 *data = sf->data.planar.pixel_data;
187     pixel32 current;
188     float drx, dgx, dbx, dry, dgy, dby;
189     unsigned int r,g,b;
190     int x, y;
191
192     for (y = 0; y < h; ++y) {
193         drx = (float)(sf->data.planar.secondary->r -
194                       sf->data.planar.primary->r);
195         dry = drx/(float)h;
196         drx/= (float)w;
197
198         dgx = (float)(sf->data.planar.secondary->g -
199                       sf->data.planar.primary->g);
200         dgy = dgx/(float)h;
201         dgx/= (float)w;
202
203         dbx = (float)(sf->data.planar.secondary->b -
204                       sf->data.planar.primary->b);
205         dby = dbx/(float)h;
206         dbx/= (float)w;
207         for (x = w; x > 0; --x, ++data) {
208             r = sf->data.planar.primary->r +
209                 ((int)(drx * (x-1)) + (int)(dry * y))/2;
210             g = sf->data.planar.primary->g +
211                 ((int)(dgx * (x-1)) + (int)(dgy * y))/2;
212             b = sf->data.planar.primary->b +
213                 ((int)(dbx * (x-1)) + (int)(dby * y))/2;
214             current = (r << default_red_offset)
215                 + (g << default_green_offset)
216                 + (b << default_blue_offset);
217             *data = current;
218         }
219     }
220 }
221
222 void highlight(pixel32 *x, pixel32 *y, gboolean raised)
223 {
224     int r, g, b;
225
226     pixel32 *up, *down;
227     if (raised) {
228         up = x;
229         down = y;
230     } else {
231         up = y;
232         down = x;
233     }
234     r = (*up >> default_red_offset) & 0xFF;
235     r += r >> 1;
236     g = (*up >> default_green_offset) & 0xFF;
237     g += g >> 1;
238     b = (*up >> default_blue_offset) & 0xFF;
239     b += b >> 1;
240     if (r > 0xFF) r = 0xFF;
241     if (g > 0xFF) g = 0xFF;
242     if (b > 0xFF) b = 0xFF;
243     *up = (r << default_red_offset) + (g << default_green_offset)
244         + (b << default_blue_offset);
245   
246     r = (*down >> default_red_offset) & 0xFF;
247     r = (r >> 1) + (r >> 2);
248     g = (*down >> default_green_offset) & 0xFF;
249     g = (g >> 1) + (g >> 2);
250     b = (*down >> default_blue_offset) & 0xFF;
251     b = (b >> 1) + (b >> 2);
252     *down = (r << default_red_offset) + (g << default_green_offset)
253         + (b << default_blue_offset);
254 }
255
256 static void create_bevel_colors(Appearance *l)
257 {
258     int r, g, b;
259
260     /* light color */
261     r = l->surface.data.planar.primary->r;
262     r += r >> 1;
263     g = l->surface.data.planar.primary->g;
264     g += g >> 1;
265     b = l->surface.data.planar.primary->b;
266     b += b >> 1;
267     if (r > 0xFF) r = 0xFF;
268     if (g > 0xFF) g = 0xFF;
269     if (b > 0xFF) b = 0xFF;
270     g_assert(!l->surface.data.planar.bevel_light);
271     l->surface.data.planar.bevel_light = color_new(r, g, b);
272     color_allocate_gc(l->surface.data.planar.bevel_light);
273
274     /* dark color */
275     r = l->surface.data.planar.primary->r;
276     r = (r >> 1) + (r >> 2);
277     g = l->surface.data.planar.primary->g;
278     g = (g >> 1) + (g >> 2);
279     b = l->surface.data.planar.primary->b;
280     b = (b >> 1) + (b >> 2);
281     g_assert(!l->surface.data.planar.bevel_dark);
282     l->surface.data.planar.bevel_dark = color_new(r, g, b);
283     color_allocate_gc(l->surface.data.planar.bevel_dark);
284 }
285
286 void gradient_solid(Appearance *l, int x, int y, int w, int h) 
287 {
288     pixel32 pix;
289     int i, a, b;
290     PlanarSurface *sp = &l->surface.data.planar;
291     int left = x, top = y, right = x + w - 1, bottom = y + h - 1;
292
293     if (sp->primary->gc == None)
294         color_allocate_gc(sp->primary);
295     pix = (sp->primary->r << default_red_offset)
296         + (sp->primary->g << default_green_offset)
297         + (sp->primary->b << default_blue_offset);
298
299     for (a = 0; a < l->area.width; a++)
300         for (b = 0; b < l->area.height; b++)
301             sp->pixel_data[a + b*l->area.width] = pix;
302
303     XFillRectangle(ob_display, l->pixmap, sp->primary->gc,
304                    x, y, w, h);
305
306     if (sp->interlaced) {
307         if (sp->secondary->gc == None)
308             color_allocate_gc(sp->secondary);
309         for (i = y; i < h; i += 2)
310             XDrawLine(ob_display, l->pixmap, sp->secondary->gc,
311                       x, i, w, i);
312     }
313
314     switch (sp->relief) {
315     case Raised:
316         if (!sp->bevel_dark)
317             create_bevel_colors(l);
318
319         switch (sp->bevel) {
320         case Bevel1:
321             XDrawLine(ob_display, l->pixmap, sp->bevel_dark->gc,
322                       left, bottom, right, bottom);
323             XDrawLine(ob_display, l->pixmap, sp->bevel_dark->gc,
324                       right, bottom, right, top);
325                 
326             XDrawLine(ob_display, l->pixmap, sp->bevel_light->gc,
327                       left, top, right, top);
328             XDrawLine(ob_display, l->pixmap, sp->bevel_light->gc,
329                       left, bottom, left, top);
330             break;
331         case Bevel2:
332             XDrawLine(ob_display, l->pixmap,
333                       sp->bevel_dark->gc,
334                       left + 1, bottom - 2, right - 2, bottom - 2);
335             XDrawLine(ob_display, l->pixmap,
336                       sp->bevel_dark->gc,
337                       right - 2, bottom - 2, right - 2, top + 1);
338
339             XDrawLine(ob_display, l->pixmap,
340                       sp->bevel_light->gc,
341                       left + 1, top + 1, right - 2, top + 1);
342             XDrawLine(ob_display, l->pixmap,
343                       sp->bevel_light->gc,
344                       left + 1, bottom - 2, left + 1, top + 1);
345             break;
346         default:
347             g_assert_not_reached(); /* unhandled BevelType */
348         }
349         break;
350     case Sunken:
351         if (!sp->bevel_dark)
352             create_bevel_colors(l);
353
354         switch (sp->bevel) {
355         case Bevel1:
356             XDrawLine(ob_display, l->pixmap, sp->bevel_light->gc,
357                       left, bottom, right, bottom);
358             XDrawLine(ob_display, l->pixmap, sp->bevel_light->gc,
359                       right, bottom, right, top);
360       
361             XDrawLine(ob_display, l->pixmap, sp->bevel_dark->gc,
362                       left, top, right, top);
363             XDrawLine(ob_display, l->pixmap, sp->bevel_dark->gc,
364                       left, bottom, left, top);
365             break;
366         case Bevel2:
367             XDrawLine(ob_display, l->pixmap, sp->bevel_light->gc,
368                       left + 1, bottom - 2, right - 2, bottom - 2);
369             XDrawLine(ob_display, l->pixmap, sp->bevel_light->gc,
370                       right - 2, bottom - 2, right - 2, top + 1);
371       
372             XDrawLine(ob_display, l->pixmap, sp->bevel_dark->gc,
373                       left + 1, top + 1, right - 2, top + 1);
374             XDrawLine(ob_display, l->pixmap, sp->bevel_dark->gc,
375                       left + 1, bottom - 2, left + 1, top + 1);
376
377             break;
378         default:
379             g_assert_not_reached(); /* unhandled BevelType */
380         }
381         break;
382     case Flat:
383         if (sp->border) {
384             if (sp->border_color->gc == None)
385                 color_allocate_gc(sp->border_color);
386             XDrawRectangle(ob_display, l->pixmap, sp->border_color->gc,
387                            left, top, right, bottom);
388         }
389         break;
390     default:  
391         g_assert_not_reached(); /* unhandled ReliefType */
392     }
393 }
394
395 void gradient_pyramid(Surface *sf, int inw, int inh)
396 {
397     pixel32 *data = sf->data.planar.pixel_data;
398     pixel32 *end = data + inw*inh - 1;
399     pixel32 current;
400     float drx, dgx, dbx, dry, dgy, dby;
401     unsigned int r,g,b;
402     int x, y, h=(inh/2) + 1, w=(inw/2) + 1;
403     for (y = 0; y < h; ++y) {
404         drx = (float)(sf->data.planar.secondary->r -
405                       sf->data.planar.primary->r);
406         dry = drx/(float)h;
407         drx/= (float)w;
408
409         dgx = (float)(sf->data.planar.secondary->g -
410                       sf->data.planar.primary->g);
411         dgy = dgx/(float)h;
412         dgx/= (float)w;
413
414         dbx = (float)(sf->data.planar.secondary->b -
415                       sf->data.planar.primary->b);
416         dby = dbx/(float)h;
417         dbx/= (float)w;
418         for (x = 0; x < w; ++x, data) {
419             r = sf->data.planar.primary->r +
420                 ((int)(drx * x) + (int)(dry * y))/2;
421             g = sf->data.planar.primary->g +
422                 ((int)(dgx * x) + (int)(dgy * y))/2;
423             b = sf->data.planar.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(Surface *sf, int inw, int inh)
439 {
440     pixel32 *data = sf->data.planar.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     int val;
447
448     for (y = 0; y < h; ++y) {
449         drx = (float)(sf->data.planar.primary->r -
450                       sf->data.planar.secondary->r);
451         dry = drx/(float)h;
452         drx/= (float)w;
453
454         dgx = (float)(sf->data.planar.primary->g -
455                       sf->data.planar.secondary->g);
456         dgy = dgx/(float)h;
457         dgx/= (float)w;
458
459         dbx = (float)(sf->data.planar.primary->b -
460                       sf->data.planar.secondary->b);
461         dby = dbx/(float)h;
462         dbx/= (float)w;
463         for (x = 0; x < w; ++x, data) {
464             if ((float)x/(float)w < (float)y/(float)h) val = (int)(drx * x);
465             else val = (int)(dry * y);
466
467             r = sf->data.planar.secondary->r + val;
468             g = sf->data.planar.secondary->g + val;
469             b = sf->data.planar.secondary->b + val;
470             current = (r << default_red_offset)
471                 + (g << default_green_offset)
472                 + (b << default_blue_offset);
473             *(data+x) = current;
474             *(data+inw-x) = current;
475             *(end-x) = current;
476             *(end-(inw-x)) = current;
477         }
478         data+=inw;
479         end-=inw;
480     }
481 }
482
483 void gradient_pipecross(Surface *sf, int inw, int inh)
484 {
485     pixel32 *data = sf->data.planar.pixel_data;
486     pixel32 *end = data + inw*inh - 1;
487     pixel32 current;
488     float drx, dgx, dbx, dry, dgy, dby;
489     unsigned int r,g,b;
490     int x, y, h=(inh/2) + 1, w=(inw/2) + 1;
491     int val;
492
493     for (y = 0; y < h; ++y) {
494         drx = (float)(sf->data.planar.secondary->r -
495                       sf->data.planar.primary->r);
496         dry = drx/(float)h;
497         drx/= (float)w;
498
499         dgx = (float)(sf->data.planar.secondary->g -
500                       sf->data.planar.primary->g);
501         dgy = dgx/(float)h;
502         dgx/= (float)w;
503
504         dbx = (float)(sf->data.planar.secondary->b -
505                       sf->data.planar.primary->b);
506         dby = dbx/(float)h;
507         dbx/= (float)w;
508         for (x = 0; x < w; ++x, data) {
509             if ((float)x/(float)w > (float)y/(float)h) val = (int)(drx * x);
510             else val = (int)(dry * y);
511
512             r = sf->data.planar.primary->r + val;
513             g = sf->data.planar.primary->g + val;
514             b = sf->data.planar.primary->b + val;
515             current = (r << default_red_offset)
516                 + (g << default_green_offset)
517                 + (b << default_blue_offset);
518             *(data+x) = current;
519             *(data+inw-x) = current;
520             *(end-x) = current;
521             *(end-(inw-x)) = current;
522         }
523         data+=inw;
524         end-=inw;
525     }
526 }
527 #ifdef USE_GL
528 void render_gl_gradient(Surface *sf, int x, int y, int w, int h)
529 {
530     float pr,pg,pb;
531     float sr, sg, sb;
532     float ar, ag, ab;
533
534     pr = (float)sf->data.planar.primary->r/255.0;
535     pg = (float)sf->data.planar.primary->g/255.0;
536     pb = (float)sf->data.planar.primary->b/255.0;
537     if (sf->data.planar.secondary) {
538         sr = (float)sf->data.planar.secondary->r/255.0;
539         sg = (float)sf->data.planar.secondary->g/255.0;
540         sb = (float)sf->data.planar.secondary->b/255.0;
541     }
542     switch (sf->data.planar.grad) {
543     case Background_Solid: /* already handled */
544         glBegin(GL_TRIANGLES);
545         glColor3f(pr, pg, pb);
546         glVertex3i(x, y, 0);
547         glVertex3i(x+w, y, 0);
548         glVertex3i(x+w, y+h, 0);
549
550         glVertex3i(x+w, y+h, 0);
551         glVertex3i(x, y+h, 0);
552         glVertex3i(x, y, 0);
553         glEnd();
554         return;
555     case Background_Horizontal:
556         glBegin(GL_TRIANGLES);
557         glColor3f(pr, pg, pb);
558         glVertex3i(x, y, 0);
559         glColor3f(sr, sg, sb);
560         glVertex3i(x+w, y, 0);
561         glVertex3i(x+w, y+h, 0);
562
563         glVertex3i(x+w, y+h, 0);
564         glColor3f(pr, pg, pb);
565         glVertex3i(x, y+h, 0);
566         glVertex3i(x, y, 0);
567         glEnd();
568         break;
569     case Background_Vertical:
570         glBegin(GL_TRIANGLES);
571         glColor3f(pr, pg, pb);
572         glVertex3i(x, y, 0);
573         glVertex3i(x+w, y, 0);
574         glColor3f(sr, sg, sb);
575         glVertex3i(x+w, y+h, 0);
576
577         glVertex3i(x+w, y+h, 0);
578         glVertex3i(x, y+h, 0);
579         glColor3f(pr, pg, pb);
580         glVertex3i(x, y, 0);
581         glEnd();
582         break;
583     case Background_Diagonal:
584         ar = (pr + sr) / 2.0;
585         ag = (pg + sg) / 2.0;
586         ab = (pb + sb) / 2.0;
587         glBegin(GL_TRIANGLES);
588         glColor3f(ar, ag, ab);
589         glVertex3i(x, y, 0);
590         glColor3f(pr, pg, pb);
591         glVertex3i(x+w, y, 0);
592         glColor3f(ar, ag, ab);
593         glVertex3i(x+w, y+h, 0);
594
595         glColor3f(ar, ag, ab);
596         glVertex3i(x+w, y+h, 0);
597         glColor3f(sr, sg, sb);
598         glVertex3i(x, y+h, 0);
599         glColor3f(ar, ag, ab);
600         glVertex3i(x, y, 0);
601         glEnd();
602         break;
603     case Background_CrossDiagonal:
604         ar = (pr + sr) / 2.0;
605         ag = (pg + sg) / 2.0;
606         ab = (pb + sb) / 2.0;
607         glBegin(GL_TRIANGLES);
608         glColor3f(pr, pg, pb);
609         glVertex3i(x, y, 0);
610         glColor3f(ar, ag, ab);
611         glVertex3i(x+w, y, 0);
612         glColor3f(sr, sg, sb);
613         glVertex3i(x+w, y+h, 0);
614
615         glColor3f(sr, sg, sb);
616         glVertex3i(x+w, y+h, 0);
617         glColor3f(ar, ag, ab);
618         glVertex3i(x, y+h, 0);
619         glColor3f(pr, pg, pb);
620         glVertex3i(x, y, 0);
621         glEnd();
622         break;
623     case Background_Pyramid:
624 printf("pyramid\n");
625         break;
626     case Background_PipeCross:
627         break;
628     case Background_Rectangle:
629         glBegin(GL_TRIANGLES);
630         glColor3f(pr, pg, pb);
631         glVertex3i(x, y, 0);
632         glColor3f(sr, sg, sb);
633         glVertex3i(x+w/2, y+h/2, 0);
634         glColor3f(pr, pg, pb);
635         glVertex3i(x, y+h, 0);
636
637         glVertex3i(x, y+h, 0);
638         glColor3f(sr, sg, sb);
639         glVertex3i(x+w/2, y+h/2, 0);
640         glColor3f(pr, pg, pb);
641         glVertex3i(x+w, y+h, 0);
642
643         glVertex3i(x+w, y+h, 0);
644         glColor3f(sr, sg, sb);
645         glVertex3i(x+w/2, y+h/2, 0);
646         glColor3f(pr, pg, pb);
647         glVertex3i(x+w, y, 0);
648
649         glVertex3i(x+w, y, 0);
650         glColor3f(sr, sg, sb);
651         glVertex3i(x+w/2, y+h/2, 0);
652         glColor3f(pr, pg, pb);
653         glVertex3i(x, y, 0);
654
655         glEnd();
656         break;
657     default:
658         g_message("unhandled gradient");
659         return;
660     }
661 }
662 #endif /* USE_GL */