there's the rect grad. now stop bugging me :(
[dana/openbox.git] / render / gradient.c
1 #include <glib.h>
2 #include "render.h"
3 #include "gradient.h"
4 #include "../kernel/openbox.h"
5 #include "color.h"
6
7 void gradient_render(Surface *sf, int w, int h)
8 {
9   pixel32 *data = sf->data.planar.pixel_data;
10   pixel32 current;
11   unsigned int r,g,b;
12   int off, x;
13
14   switch (sf->data.planar.grad) {
15   case Background_Solid: /* already handled */
16     return;
17   case Background_Vertical:
18     gradient_vertical(sf, w, h);
19     break;
20   case Background_Horizontal:
21     gradient_horizontal(sf, w, h);
22     break;
23   case Background_Diagonal:
24     gradient_diagonal(sf, w, h);
25     break;
26   case Background_CrossDiagonal:
27     gradient_crossdiagonal(sf, w, h);
28     break;
29   case Background_Pyramid:
30     gradient_pyramid(sf, w, h);
31     break;
32   case Background_PipeCross:
33     printf("PipeCross\n");
34     break;
35   case Background_Rectangle:
36     gradient_rectangle(sf, w, h);
37     break;
38   default:
39     g_message("unhandled gradient");
40     return;
41   }
42   
43   if (sf->data.planar.relief == Flat && sf->data.planar.border) {
44     r = sf->data.planar.border_color->r;
45     g = sf->data.planar.border_color->g;
46     b = sf->data.planar.border_color->b;
47     current = (r << default_red_offset)
48             + (g << default_green_offset)
49             + (b << default_blue_offset);
50     for (off = 0, x = 0; x < w; ++x, off++) {
51       *(data + off) = current;
52       *(data + off + ((h-1) * w)) = current;
53     }
54     for (off = 0, x = 0; x < h; ++x, off++) {
55       *(data + (off * w)) = current;
56       *(data + (off * w) + w - 1) = current;
57     }
58   }
59
60   if (sf->data.planar.relief != Flat) {
61     if (sf->data.planar.bevel == Bevel1) {
62       for (off = 1, x = 1; x < w - 1; ++x, off++)
63         highlight(data + off,
64                   data + off + (h-1) * w,
65                   sf->data.planar.relief==Raised);
66       for (off = 0, x = 0; x < h; ++x, off++)
67         highlight(data + off * w,
68                   data + off * w + w - 1,
69                   sf->data.planar.relief==Raised);
70     }
71
72     if (sf->data.planar.bevel == Bevel2) {
73       for (off = 2, x = 2; x < w - 2; ++x, off++)
74         highlight(data + off + w,
75                   data + off + (h-2) * w,
76                   sf->data.planar.relief==Raised);
77       for (off = 1, x = 1; x < h-1; ++x, off++)
78         highlight(data + off * w + 1,
79                   data + off * w + w - 2,
80                   sf->data.planar.relief==Raised);
81     }
82   }
83 }
84
85
86
87 void gradient_vertical(Surface *sf, int w, int h)
88 {
89   pixel32 *data = sf->data.planar.pixel_data;
90   pixel32 current;
91   float dr, dg, db;
92   unsigned int r,g,b;
93   int x, y;
94
95   dr = (float)(sf->data.planar.secondary->r - sf->data.planar.primary->r);
96   dr/= (float)h;
97
98   dg = (float)(sf->data.planar.secondary->g - sf->data.planar.primary->g);
99   dg/= (float)h;
100
101   db = (float)(sf->data.planar.secondary->b - sf->data.planar.primary->b);
102   db/= (float)h;
103
104   for (y = 0; y < h; ++y) {
105     r = sf->data.planar.primary->r + (int)(dr * y);
106     g = sf->data.planar.primary->g + (int)(dg * y);
107     b = sf->data.planar.primary->b + (int)(db * y);
108     current = (r << default_red_offset)
109             + (g << default_green_offset)
110             + (b << default_blue_offset);
111     for (x = 0; x < w; ++x, ++data)
112       *data = current;
113   }
114 }
115
116 void gradient_horizontal(Surface *sf, int w, int h)
117 {
118   pixel32 *data = sf->data.planar.pixel_data;
119   pixel32 current;
120   float dr, dg, db;
121   unsigned int r,g,b;
122   int x, y;
123
124   dr = (float)(sf->data.planar.secondary->r - sf->data.planar.primary->r);
125   dr/= (float)w;
126
127   dg = (float)(sf->data.planar.secondary->g - sf->data.planar.primary->g);
128   dg/= (float)w;
129
130   db = (float)(sf->data.planar.secondary->b - sf->data.planar.primary->b);
131   db/= (float)w;
132
133   for (x = 0; x < w; ++x, ++data) {
134     r = sf->data.planar.primary->r + (int)(dr * x);
135     g = sf->data.planar.primary->g + (int)(dg * x);
136     b = sf->data.planar.primary->b + (int)(db * x);
137     current = (r << default_red_offset)
138             + (g << default_green_offset)
139             + (b << default_blue_offset);
140     for (y = 0; y < h; ++y)
141       *(data + y*w) = current;
142   }
143 }
144
145 void gradient_diagonal(Surface *sf, int w, int h)
146 {
147   pixel32 *data = sf->data.planar.pixel_data;
148   pixel32 current;
149   float drx, dgx, dbx, dry, dgy, dby;
150   unsigned int r,g,b;
151   int x, y;
152
153   for (y = 0; y < h; ++y) {
154     drx = (float)(sf->data.planar.secondary->r - sf->data.planar.primary->r);
155     dry = drx/(float)h;
156     drx/= (float)w;
157
158     dgx = (float)(sf->data.planar.secondary->g - sf->data.planar.primary->g);
159     dgy = dgx/(float)h;
160     dgx/= (float)w;
161
162     dbx = (float)(sf->data.planar.secondary->b - sf->data.planar.primary->b);
163     dby = dbx/(float)h;
164     dbx/= (float)w;
165     for (x = 0; x < w; ++x, ++data) {
166       r = sf->data.planar.primary->r + ((int)(drx * x) + (int)(dry * y))/2;
167       g = sf->data.planar.primary->g + ((int)(dgx * x) + (int)(dgy * y))/2;
168       b = sf->data.planar.primary->b + ((int)(dbx * x) + (int)(dby * y))/2;
169       current = (r << default_red_offset)
170               + (g << default_green_offset)
171               + (b << default_blue_offset);
172       *data = current;
173     }
174   }
175 }
176
177 void gradient_crossdiagonal(Surface *sf, int w, int h)
178 {
179   pixel32 *data = sf->data.planar.pixel_data;
180   pixel32 current;
181   float drx, dgx, dbx, dry, dgy, dby;
182   unsigned int r,g,b;
183   int x, y;
184
185   for (y = 0; y < h; ++y) {
186     drx = (float)(sf->data.planar.secondary->r - sf->data.planar.primary->r);
187     dry = drx/(float)h;
188     drx/= (float)w;
189
190     dgx = (float)(sf->data.planar.secondary->g - sf->data.planar.primary->g);
191     dgy = dgx/(float)h;
192     dgx/= (float)w;
193
194     dbx = (float)(sf->data.planar.secondary->b - sf->data.planar.primary->b);
195     dby = dbx/(float)h;
196     dbx/= (float)w;
197     for (x = w; x > 0; --x, ++data) {
198       r = sf->data.planar.primary->r + ((int)(drx * (x-1)) + (int)(dry * y))/2;
199       g = sf->data.planar.primary->g + ((int)(dgx * (x-1)) + (int)(dgy * y))/2;
200       b = sf->data.planar.primary->b + ((int)(dbx * (x-1)) + (int)(dby * y))/2;
201       current = (r << default_red_offset)
202               + (g << default_green_offset)
203               + (b << default_blue_offset);
204       *data = current;
205     }
206   }
207 }
208
209 void highlight(pixel32 *x, pixel32 *y, gboolean raised)
210 {
211   int r, g, b;
212
213   pixel32 *up, *down;
214   if (raised) {
215     up = x;
216     down = y;
217   } else {
218     up = y;
219     down = x;
220   }
221   r = (*up >> default_red_offset) & 0xFF;
222   r += r >> 1;
223   g = (*up >> default_green_offset) & 0xFF;
224   g += g >> 1;
225   b = (*up >> default_blue_offset) & 0xFF;
226   b += b >> 1;
227   if (r > 255) r = 255;
228   if (g > 255) g = 255;
229   if (b > 255) b = 255;
230   *up = (r << default_red_offset) + (g << default_green_offset)
231       + (b << default_blue_offset);
232   
233   r = (*down >> default_red_offset) & 0xFF;
234   r = (r >> 1) + (r >> 2);
235   g = (*down >> default_green_offset) & 0xFF;
236   g = (g >> 1) + (g >> 2);
237   b = (*down >> default_blue_offset) & 0xFF;
238   b = (b >> 1) + (b >> 2);
239   *down = (r << default_red_offset) + (g << default_green_offset)
240         + (b << default_blue_offset);
241 }
242
243 void gradient_solid(Appearance *l, int x, int y, int w, int h) 
244 {
245   pixel32 pix;
246   int i, a, b;
247   PlanarSurface *sp = &l->surface.data.planar;
248   int left = x, top = y, right = w - 1, bottom = h - 1;
249
250   if (sp->primary->gc == None)
251     color_allocate_gc(sp->primary);
252   pix = (sp->primary->r << default_red_offset)
253       + (sp->primary->g << default_green_offset)
254       + (sp->primary->b << default_blue_offset);
255
256   for (a = 0; a < l->area.width; a++)
257     for (b = 0; b < l->area.height; b++)
258       sp->pixel_data[a + b*l->area.width] = pix;
259
260   XFillRectangle(ob_display, l->pixmap, sp->primary->gc
261                  , x, y, w, h);
262
263   if (l->surface.data.planar.interlaced) {
264     if (sp->secondary->gc == None)
265       color_allocate_gc(sp->secondary);
266     for (i = y; i < h; i += 2)
267       XDrawLine(ob_display, l->pixmap, sp->secondary->gc,
268                 x, i, w, i);
269   }
270 /*
271   switch (texture.relief()) {
272   case RenderTexture::Raised:
273     switch (texture.bevel()) {
274     case RenderTexture::Bevel1:
275       XDrawLine(ob_display, l->pixmap, texture.bevelDarkColor().gc(),
276                 left, bottom, right, bottom);
277       XDrawLine(ob_display, l->pixmap, texture.bevelDarkColor().gc(),
278                 right, bottom, right, top);
279                 
280       XDrawLine(ob_display, l->pixmap, texture.bevelLightColor().gc(),
281                 left, top, right, top);
282       XDrawLine(ob_display, l->pixmap, texture.bevelLightColor().gc(),
283                 left, bottom, left, top);
284       break;
285     case RenderTexture::Bevel2:
286       XDrawLine(ob_display, l->pixmap, texture.bevelDarkColor().gc(),
287                 left + 1, bottom - 2, right - 2, bottom - 2);
288       XDrawLine(ob_display, l->pixmap, texture.bevelDarkColor().gc(),
289                 right - 2, bottom - 2, right - 2, top + 1);
290
291       XDrawLine(ob_display, l->pixmap, texture.bevelLightColor().gc(),
292                 left + 1, top + 1, right - 2, top + 1);
293       XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
294                 left + 1, bottom - 2, left + 1, top + 1);
295       break;
296     default:
297       assert(false); // unhandled RenderTexture::BevelType   
298     }
299     break;
300   case RenderTexture::Sunken:
301     switch (texture.bevel()) {
302     case RenderTexture::Bevel1:
303       XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
304                 left, bottom, right, bottom);
305       XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
306                 right, bottom, right, top);
307       
308       XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
309                 left, top, right, top);
310       XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
311                 left, bottom, left, top);
312       break;
313     case RenderTexture::Bevel2:
314       XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
315                 left + 1, bottom - 2, right - 2, bottom - 2);
316       XDrawLine(**display, sf.pixmap(), texture.bevelLightColor().gc(),
317                 right - 2, bottom - 2, right - 2, top + 1);
318       
319       XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
320                 left + 1, top + 1, right - 2, top + 1);
321       XDrawLine(**display, sf.pixmap(), texture.bevelDarkColor().gc(),
322                 left + 1, bottom - 2, left + 1, top + 1);
323
324       break;
325     default:
326       assert(false); // unhandled RenderTexture::BevelType   
327     }
328     break;
329   case RenderTexture::Flat:
330     if (texture.border())
331       XDrawRectangle(**display, sf.pixmap(), texture.borderColor().gc(),
332                      left, top, right, bottom);
333     break;
334   default:  
335     assert(false); // unhandled RenderTexture::ReliefType
336   }
337 */
338 }
339
340 void gradient_pyramid(Surface *sf, int inw, int inh)
341 {
342   pixel32 *data = sf->data.planar.pixel_data;
343   pixel32 *end = data + inw*inh;
344   pixel32 current;
345   float drx, dgx, dbx, dry, dgy, dby;
346   unsigned int r,g,b;
347   int x, y, h=(inh/2) + 1, w=(inw/2) + 1;
348   for (y = 0; y < h; ++y) {
349     drx = (float)(sf->data.planar.secondary->r - sf->data.planar.primary->r);
350     dry = drx/(float)h;
351     drx/= (float)w;
352
353     dgx = (float)(sf->data.planar.secondary->g - sf->data.planar.primary->g);
354     dgy = dgx/(float)h;
355     dgx/= (float)w;
356
357     dbx = (float)(sf->data.planar.secondary->b - sf->data.planar.primary->b);
358     dby = dbx/(float)h;
359     dbx/= (float)w;
360     for (x = 0; x < w; ++x, data) {
361       r = sf->data.planar.primary->r + ((int)(drx * x) + (int)(dry * y))/2;
362       g = sf->data.planar.primary->g + ((int)(dgx * x) + (int)(dgy * y))/2;
363       b = sf->data.planar.primary->b + ((int)(dbx * x) + (int)(dby * y))/2;
364       current = (r << default_red_offset)
365               + (g << default_green_offset)
366               + (b << default_blue_offset);
367       *(data+x) = current;
368       *(data+inw-x) = current;
369       *(end-x) = current;
370       *(end-(inw-x)) = current;
371     }
372     data+=inw;
373     end-=inw;
374   }
375 }
376
377 void gradient_rectangle(Surface *sf, int inw, int inh)
378 {
379   pixel32 *data = sf->data.planar.pixel_data;
380   pixel32 *end = data + inw*inh;
381   pixel32 current;
382   float drx, dgx, dbx, dry, dgy, dby;
383   unsigned int r,g,b;
384   int x, y, h=(inh/2) + 1, w=(inw/2) + 1;
385   int val;
386
387   for (y = 0; y < h; ++y) {
388     drx = (float)(sf->data.planar.secondary->r - sf->data.planar.primary->r);
389     dry = drx/(float)h;
390     drx/= (float)w;
391
392     dgx = (float)(sf->data.planar.secondary->g - sf->data.planar.primary->g);
393     dgy = dgx/(float)h;
394     dgx/= (float)w;
395
396     dbx = (float)(sf->data.planar.secondary->b - sf->data.planar.primary->b);
397     dby = dbx/(float)h;
398     dbx/= (float)w;
399     for (x = 0; x < w; ++x, data) {
400       if ((float)x/(float)w < (float)y/(float)h) val = (int)(drx * x);
401       else val = (int)(dry * y);
402
403       r = sf->data.planar.primary->r + val;
404       g = sf->data.planar.primary->g + val;
405       b = sf->data.planar.primary->b + val;
406       current = (r << default_red_offset)
407               + (g << default_green_offset)
408               + (b << default_blue_offset);
409       *(data+x) = current;
410       *(data+inw-x) = current;
411       *(end-x) = current;
412       *(end-(inw-x)) = current;
413     }
414     data+=inw;
415     end-=inw;
416   }
417 }