]> Dogcows Code - chaz/openbox/blob - render/gradient.c
integer math for gradients. horz vert and diags and pipecross work so far.
[chaz/openbox] / 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 static void highlight(RrPixel32 *x, RrPixel32 *y, gboolean raised)
96 {
97 int r, g, b;
98
99 RrPixel32 *up, *down;
100 if (raised) {
101 up = x;
102 down = y;
103 } else {
104 up = y;
105 down = x;
106 }
107 r = (*up >> RrDefaultRedOffset) & 0xFF;
108 r += r >> 1;
109 g = (*up >> RrDefaultGreenOffset) & 0xFF;
110 g += g >> 1;
111 b = (*up >> RrDefaultBlueOffset) & 0xFF;
112 b += b >> 1;
113 if (r > 0xFF) r = 0xFF;
114 if (g > 0xFF) g = 0xFF;
115 if (b > 0xFF) b = 0xFF;
116 *up = (r << RrDefaultRedOffset) + (g << RrDefaultGreenOffset)
117 + (b << RrDefaultBlueOffset);
118
119 r = (*down >> RrDefaultRedOffset) & 0xFF;
120 r = (r >> 1) + (r >> 2);
121 g = (*down >> RrDefaultGreenOffset) & 0xFF;
122 g = (g >> 1) + (g >> 2);
123 b = (*down >> RrDefaultBlueOffset) & 0xFF;
124 b = (b >> 1) + (b >> 2);
125 *down = (r << RrDefaultRedOffset) + (g << RrDefaultGreenOffset)
126 + (b << RrDefaultBlueOffset);
127 }
128
129 static void create_bevel_colors(RrAppearance *l)
130 {
131 int r, g, b;
132
133 /* light color */
134 r = l->surface.primary->r;
135 r += r >> 1;
136 g = l->surface.primary->g;
137 g += g >> 1;
138 b = l->surface.primary->b;
139 b += b >> 1;
140 if (r > 0xFF) r = 0xFF;
141 if (g > 0xFF) g = 0xFF;
142 if (b > 0xFF) b = 0xFF;
143 g_assert(!l->surface.bevel_light);
144 l->surface.bevel_light = RrColorNew(l->inst, r, g, b);
145 RrColorAllocateGC(l->surface.bevel_light);
146
147 /* dark color */
148 r = l->surface.primary->r;
149 r = (r >> 1) + (r >> 2);
150 g = l->surface.primary->g;
151 g = (g >> 1) + (g >> 2);
152 b = l->surface.primary->b;
153 b = (b >> 1) + (b >> 2);
154 g_assert(!l->surface.bevel_dark);
155 l->surface.bevel_dark = RrColorNew(l->inst, r, g, b);
156 RrColorAllocateGC(l->surface.bevel_dark);
157 }
158
159 static void gradient_solid(RrAppearance *l, int w, int h)
160 {
161 RrPixel32 pix;
162 int i, a, b;
163 RrSurface *sp = &l->surface;
164 int left = 0, top = 0, right = w - 1, bottom = h - 1;
165
166 if (sp->primary->gc == None)
167 RrColorAllocateGC(sp->primary);
168 pix = (sp->primary->r << RrDefaultRedOffset)
169 + (sp->primary->g << RrDefaultGreenOffset)
170 + (sp->primary->b << RrDefaultBlueOffset);
171
172 for (a = 0; a < w; a++)
173 for (b = 0; b < h; b++)
174 sp->RrPixel_data[a + b * w] = pix;
175
176 XFillRectangle(RrDisplay(l->inst), l->pixmap, sp->primary->gc,
177 0, 0, w, h);
178
179 if (sp->interlaced) {
180 if (sp->secondary->gc == None)
181 RrColorAllocateGC(sp->secondary);
182 for (i = 0; i < h; i += 2)
183 XDrawLine(RrDisplay(l->inst), l->pixmap, sp->secondary->gc,
184 0, i, w, i);
185 }
186
187 switch (sp->relief) {
188 case RR_RELIEF_RAISED:
189 if (!sp->bevel_dark)
190 create_bevel_colors(l);
191
192 switch (sp->bevel) {
193 case RR_BEVEL_1:
194 XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_dark->gc,
195 left, bottom, right, bottom);
196 XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_dark->gc,
197 right, bottom, right, top);
198
199 XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_light->gc,
200 left, top, right, top);
201 XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_light->gc,
202 left, bottom, left, top);
203 break;
204 case RR_BEVEL_2:
205 XDrawLine(RrDisplay(l->inst), l->pixmap,
206 sp->bevel_dark->gc,
207 left + 1, bottom - 2, right - 2, bottom - 2);
208 XDrawLine(RrDisplay(l->inst), l->pixmap,
209 sp->bevel_dark->gc,
210 right - 2, bottom - 2, right - 2, top + 1);
211
212 XDrawLine(RrDisplay(l->inst), l->pixmap,
213 sp->bevel_light->gc,
214 left + 1, top + 1, right - 2, top + 1);
215 XDrawLine(RrDisplay(l->inst), l->pixmap,
216 sp->bevel_light->gc,
217 left + 1, bottom - 2, left + 1, top + 1);
218 break;
219 default:
220 g_assert_not_reached(); /* unhandled BevelType */
221 }
222 break;
223 case RR_RELIEF_SUNKEN:
224 if (!sp->bevel_dark)
225 create_bevel_colors(l);
226
227 switch (sp->bevel) {
228 case RR_BEVEL_1:
229 XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_light->gc,
230 left, bottom, right, bottom);
231 XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_light->gc,
232 right, bottom, right, top);
233
234 XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_dark->gc,
235 left, top, right, top);
236 XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_dark->gc,
237 left, bottom, left, top);
238 break;
239 case RR_BEVEL_2:
240 XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_light->gc,
241 left + 1, bottom - 2, right - 2, bottom - 2);
242 XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_light->gc,
243 right - 2, bottom - 2, right - 2, top + 1);
244
245 XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_dark->gc,
246 left + 1, top + 1, right - 2, top + 1);
247 XDrawLine(RrDisplay(l->inst), l->pixmap, sp->bevel_dark->gc,
248 left + 1, bottom - 2, left + 1, top + 1);
249
250 break;
251 default:
252 g_assert_not_reached(); /* unhandled BevelType */
253 }
254 break;
255 case RR_RELIEF_FLAT:
256 if (sp->border) {
257 if (sp->border_color->gc == None)
258 RrColorAllocateGC(sp->border_color);
259 XDrawRectangle(RrDisplay(l->inst), l->pixmap, sp->border_color->gc,
260 left, top, right, bottom);
261 }
262 break;
263 default:
264 g_assert_not_reached(); /* unhandled ReliefType */
265 }
266 }
267
268 /* * * * * * * * * * * * * * GRADIENT MAGIC WOOT * * * * * * * * * * * * * * */
269
270 #define VARS(x) \
271 unsigned int color##x[3]; \
272 int len##x, cdelta##x[3], error##x[3] = { 0, 0, 0 }, inc##x[3]; \
273 gboolean bigslope##x[3] /* color slope > 1 */
274
275 #define SETUP(x, from, to, w) \
276 len##x = w; \
277 \
278 color##x[0] = from->r; \
279 color##x[1] = from->g; \
280 color##x[2] = from->b; \
281 \
282 cdelta##x[0] = to->r - from->r; \
283 cdelta##x[1] = to->g - from->g; \
284 cdelta##x[2] = to->b - from->b; \
285 \
286 if (cdelta##x[0] < 0) { \
287 cdelta##x[0] = -cdelta##x[0]; \
288 inc##x[0] = -1; \
289 } else \
290 inc##x[0] = 1; \
291 if (cdelta##x[1] < 0) { \
292 cdelta##x[1] = -cdelta##x[1]; \
293 inc##x[1] = -1; \
294 } else \
295 inc##x[1] = 1; \
296 if (cdelta##x[2] < 0) { \
297 cdelta##x[2] = -cdelta##x[2]; \
298 inc##x[2] = -1; \
299 } else \
300 inc##x[2] = 1; \
301 bigslope##x[0] = cdelta##x[0] > w;\
302 bigslope##x[1] = cdelta##x[1] > w;\
303 bigslope##x[2] = cdelta##x[2] > w
304
305 #define COLOR_RR(x, c) \
306 c->r = color##x[0]; \
307 c->g = color##x[1]; \
308 c->b = color##x[2]
309
310 #define COLOR(x) \
311 ((color##x[0] << RrDefaultRedOffset) + \
312 (color##x[1] << RrDefaultGreenOffset) + \
313 (color##x[2] << RrDefaultBlueOffset))
314
315 #define NEXT(x) \
316 { \
317 int i; \
318 for (i = 2; i >= 0; --i) { \
319 if (!cdelta##x[i]) continue; \
320 \
321 if (!bigslope##x[i]) { \
322 /* Y (color) is dependant on X */ \
323 error##x[i] += cdelta##x[i]; \
324 if ((error##x[i] << 1) >= len##x) { \
325 color##x[i] += inc##x[i]; \
326 error##x[i] -= len##x; \
327 } \
328 } else { \
329 /* X is dependant on Y (color) */ \
330 while (1) { \
331 color##x[i] += inc##x[i]; \
332 error##x[i] += len##x; \
333 if ((error##x[i] << 1) >= cdelta##x[i]) { \
334 error##x[i] -= cdelta##x[i]; \
335 break; \
336 } \
337 } \
338 } \
339 } \
340 }
341
342 static void gradient_horizontal(RrSurface *sf, int w, int h)
343 {
344 int x, y;
345 RrPixel32 *data = sf->RrPixel_data;
346 RrPixel32 current;
347
348 VARS(x);
349 SETUP(x, sf->primary, sf->secondary, w);
350
351 for (x = w - 1; x > 0; --x) { /* 0 -> w-1 */
352 current = COLOR(x);
353 for (y = h - 1; y >= 0; --y) /* 0 -> h */
354 *(data + y * w) = current;
355 ++data;
356
357 NEXT(x);
358 }
359 current = COLOR(x);
360 for (y = h - 1; y >= 0; --y) /* 0 -> h */
361 *(data + y * w) = current;
362 }
363
364 static void gradient_vertical(RrSurface *sf, int w, int h)
365 {
366 int x, y;
367 RrPixel32 *data = sf->RrPixel_data;
368 RrPixel32 current;
369
370 VARS(y);
371 SETUP(y, sf->primary, sf->secondary, h);
372
373 for (y = h - 1; y > 0; --y) { /* 0 -> h-1 */
374 current = COLOR(y);
375 for (x = w - 1; x >= 0; --x) /* 0 -> w */
376 *(data++) = current;
377
378 NEXT(y);
379 }
380 current = COLOR(y);
381 for (x = w - 1; x >= 0; --x) /* 0 -> w */
382 *(data++) = current;
383 }
384
385
386 static void gradient_diagonal(RrSurface *sf, int w, int h)
387 {
388 int x, y;
389 RrPixel32 *data = sf->RrPixel_data;
390 RrColor left, right;
391 RrColor extracorner;
392
393 VARS(lefty);
394 VARS(righty);
395 VARS(x);
396
397 extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
398 extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
399 extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
400
401 SETUP(lefty, sf->primary, (&extracorner), h);
402 SETUP(righty, (&extracorner), sf->secondary, h);
403
404 for (y = h - 1; y > 0; --y) { /* 0 -> h-1 */
405 COLOR_RR(lefty, (&left));
406 COLOR_RR(righty, (&right));
407
408 SETUP(x, (&left), (&right), w);
409
410 for (x = w - 1; x > 0; --x) { /* 0 -> w-1 */
411 *(data++) = COLOR(x);
412
413 NEXT(x);
414 }
415 *(data++) = COLOR(x);
416
417 NEXT(lefty);
418 NEXT(righty);
419 }
420 COLOR_RR(lefty, (&left));
421 COLOR_RR(righty, (&right));
422
423 SETUP(x, (&left), (&right), w);
424
425 for (x = w - 1; x > 0; --x) { /* 0 -> w-1 */
426 *(data++) = COLOR(x);
427
428 NEXT(x);
429 }
430 *data = COLOR(x);
431 }
432
433 static void gradient_crossdiagonal(RrSurface *sf, int w, int h)
434 {
435 int x, y;
436 RrPixel32 *data = sf->RrPixel_data;
437 RrColor left, right;
438 RrColor extracorner;
439
440 VARS(lefty);
441 VARS(righty);
442 VARS(x);
443
444 extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
445 extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
446 extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
447
448 SETUP(lefty, (&extracorner), sf->secondary, h);
449 SETUP(righty, sf->primary, (&extracorner), h);
450
451 for (y = h - 1; y > 0; --y) { /* 0 -> h-1 */
452 COLOR_RR(lefty, (&left));
453 COLOR_RR(righty, (&right));
454
455 SETUP(x, (&left), (&right), w);
456
457 for (x = w - 1; x > 0; --x) { /* 0 -> w-1 */
458 *(data++) = COLOR(x);
459
460 NEXT(x);
461 }
462 *(data++) = COLOR(x);
463
464 NEXT(lefty);
465 NEXT(righty);
466 }
467 COLOR_RR(lefty, (&left));
468 COLOR_RR(righty, (&right));
469
470 SETUP(x, (&left), (&right), w);
471
472 for (x = w - 1; x > 0; --x) { /* 0 -> w-1 */
473 *(data++) = COLOR(x);
474
475 NEXT(x);
476 }
477 *data = COLOR(x);
478 }
479
480 static void gradient_pyramid(RrSurface *sf, int inw, int inh)
481 {
482 int x, y, w = (inw >> 1) + 1, h = (inh >> 1) + 1;
483 RrPixel32 *data = sf->RrPixel_data;
484 RrPixel32 *end = data + inw*inh - 1;
485 RrPixel32 current;
486 RrColor left, right;
487 RrColor extracorner;
488
489 VARS(lefty);
490 VARS(righty);
491 VARS(x);
492
493 extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
494 extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
495 extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
496
497 SETUP(lefty, (&extracorner), sf->secondary, h);
498 SETUP(righty, sf->primary, (&extracorner), h);
499
500 for (y = h - 1; y > 0; --y) { /* 0 -> h-1 */
501 COLOR_RR(lefty, (&left));
502 COLOR_RR(righty, (&right));
503
504 SETUP(x, (&left), (&right), w);
505
506 for (x = w - 1; x > 0; --x) { /* 0 -> w-1 */
507 current = COLOR(x);
508 *(data+x) = current;
509 *(data+inw-x) = current;
510 *(end-x) = current;
511 *(end-(inw-x)) = current;
512
513 NEXT(x);
514 }
515 current = COLOR(x);
516 *(data+x) = current;
517 *(data+inw-x) = current;
518 *(end-x) = current;
519 *(end-(inw-x)) = current;
520
521 data+=inw;
522 end-=inw;
523
524 NEXT(lefty);
525 NEXT(righty);
526 }
527 COLOR_RR(lefty, (&left));
528 COLOR_RR(righty, (&right));
529
530 SETUP(x, (&left), (&right), w);
531
532 for (x = w - 1; x > 0; --x) { /* 0 -> w-1 */
533 current = COLOR(x);
534 *(data+x) = current;
535 *(data+inw-x) = current;
536 *(end-x) = current;
537 *(end-(inw-x)) = current;
538
539 NEXT(x);
540 }
541 *(data+x) = current;
542 *(data+inw-x) = current;
543 *(end-x) = current;
544 *(end-(inw-x)) = current;
545 }
546
547 static void gradient_rectangle(RrSurface *sf, int inw, int inh)
548 {
549 int x, y, w = (inw >> 1) + 1, h = (inh >> 1) + 1;
550 RrPixel32 *data = sf->RrPixel_data;
551 RrPixel32 *end = data + inw*inh - 1;
552 RrPixel32 current;
553 RrColor left, right;
554 RrColor extracorner;
555
556 VARS(lefty);
557 VARS(righty);
558 VARS(x);
559
560 extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
561 extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
562 extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
563
564 SETUP(lefty, (&extracorner), sf->secondary, h);
565 SETUP(righty, sf->primary, (&extracorner), h);
566
567 for (y = h - 1; y > 0; --y) { /* 0 -> h-1 */
568 COLOR_RR(lefty, (&left));
569 COLOR_RR(righty, (&right));
570
571 SETUP(x, (&left), (&right), w);
572
573 for (x = w - 1; x > 0; --x) { /* 0 -> w-1 */
574 current = COLOR(x);
575 *(data+x) = current;
576 *(data+inw-x) = current;
577 *(end-x) = current;
578 *(end-(inw-x)) = current;
579
580 NEXT(x);
581 }
582 current = COLOR(x);
583 *(data+x) = current;
584 *(data+inw-x) = current;
585 *(end-x) = current;
586 *(end-(inw-x)) = current;
587
588 data+=inw;
589 end-=inw;
590
591 NEXT(lefty);
592 NEXT(righty);
593 }
594 COLOR_RR(lefty, (&left));
595 COLOR_RR(righty, (&right));
596
597 SETUP(x, (&left), (&right), w);
598
599 for (x = w - 1; x > 0; --x) { /* 0 -> w-1 */
600 current = COLOR(x);
601 *(data+x) = current;
602 *(data+inw-x) = current;
603 *(end-x) = current;
604 *(end-(inw-x)) = current;
605
606 NEXT(x);
607 }
608 *(data+x) = current;
609 *(data+inw-x) = current;
610 *(end-x) = current;
611 *(end-(inw-x)) = current;
612 }
613
614 static void gradient_pipecross(RrSurface *sf, int inw, int inh)
615 {
616 RrPixel32 *data = sf->RrPixel_data;
617 RrPixel32 *end = data + inw*inh - 1;
618 RrPixel32 current;
619 float drx, dgx, dbx, dry, dgy, dby;
620 unsigned int r,g,b;
621 int x, y, h=(inh/2) + 1, w=(inw/2) + 1;
622
623 drx = (float)(sf->secondary->r -
624 sf->primary->r);
625 dry = drx/(float)h;
626 drx/= (float)w;
627
628 dgx = (float)(sf->secondary->g -
629 sf->primary->g);
630 dgy = dgx/(float)h;
631 dgx/= (float)w;
632
633 dbx = (float)(sf->secondary->b -
634 sf->primary->b);
635 dby = dbx/(float)h;
636 dbx/= (float)w;
637
638 for (y = 0; y < h; ++y) {
639 for (x = 0; x < w; ++x, data) {
640 if ((float)x/(float)w > (float)y/(float)h) {
641 r = sf->primary->r + (drx * x);
642 g = sf->primary->g + (dgx * x);
643 b = sf->primary->b + (dbx * x);
644 } else {
645 r = sf->primary->r + (dry * x);
646 g = sf->primary->g + (dgy * x);
647 b = sf->primary->b + (dby * x);
648 }
649 current = (r << RrDefaultRedOffset)
650 + (g << RrDefaultGreenOffset)
651 + (b << RrDefaultBlueOffset);
652 *(data+x) = current;
653 *(data+inw-x) = current;
654 *(end-x) = current;
655 *(end-(inw-x)) = current;
656 }
657 data+=inw;
658 end-=inw;
659 }
660 }
This page took 0.064707 seconds and 5 git commands to generate.