]> Dogcows Code - chaz/openbox/blob - render/gradient.c
8b6850f0e5a41adbea92d01f8f34007946069eed
[chaz/openbox] / render / gradient.c
1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
2
3 gradient.c for the Openbox window manager
4 Copyright (c) 2006 Mikael Magnusson
5 Copyright (c) 2003-2008 Dana Jansens
6 Copyright (c) 2003 Derek Foreman
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 See the COPYING file for a copy of the GNU General Public License.
19 */
20
21 #include "render.h"
22 #include "gradient.h"
23 #include "color.h"
24 #include <glib.h>
25 #include <string.h>
26
27 static void highlight(RrSurface *s, RrPixel32 *x, RrPixel32 *y,
28 gboolean raised);
29 static void gradient_parentrelative(RrAppearance *a, gint w, gint h);
30 static void gradient_solid(RrAppearance *l, gint w, gint h);
31 static void gradient_splitvertical(RrAppearance *a, gint w, gint h);
32 static void gradient_vertical(RrSurface *sf, gint w, gint h);
33 static void gradient_horizontal(RrSurface *sf, gint w, gint h);
34 static void gradient_mirrorhorizontal(RrSurface *sf, gint w, gint h);
35 static void gradient_diagonal(RrSurface *sf, gint w, gint h);
36 static void gradient_crossdiagonal(RrSurface *sf, gint w, gint h);
37 static void gradient_pyramid(RrSurface *sf, gint inw, gint inh);
38
39 void RrRender(RrAppearance *a, gint w, gint h)
40 {
41 RrPixel32 *data = a->surface.pixel_data;
42 RrPixel32 current;
43 guint r,g,b;
44 register gint off, x;
45
46 switch (a->surface.grad) {
47 case RR_SURFACE_PARENTREL:
48 gradient_parentrelative(a, w, h);
49 break;
50 case RR_SURFACE_SOLID:
51 gradient_solid(a, w, h);
52 break;
53 case RR_SURFACE_SPLIT_VERTICAL:
54 gradient_splitvertical(a, w, h);
55 break;
56 case RR_SURFACE_VERTICAL:
57 gradient_vertical(&a->surface, w, h);
58 break;
59 case RR_SURFACE_HORIZONTAL:
60 gradient_horizontal(&a->surface, w, h);
61 break;
62 case RR_SURFACE_MIRROR_HORIZONTAL:
63 gradient_mirrorhorizontal(&a->surface, w, h);
64 break;
65 case RR_SURFACE_DIAGONAL:
66 gradient_diagonal(&a->surface, w, h);
67 break;
68 case RR_SURFACE_CROSS_DIAGONAL:
69 gradient_crossdiagonal(&a->surface, w, h);
70 break;
71 case RR_SURFACE_PYRAMID:
72 gradient_pyramid(&a->surface, w, h);
73 break;
74 default:
75 g_assert_not_reached(); /* unhandled gradient */
76 return;
77 }
78
79 if (a->surface.interlaced) {
80 gint i;
81 RrPixel32 *p;
82
83 r = a->surface.interlace_color->r;
84 g = a->surface.interlace_color->g;
85 b = a->surface.interlace_color->b;
86 current = (r << RrDefaultRedOffset)
87 + (g << RrDefaultGreenOffset)
88 + (b << RrDefaultBlueOffset);
89 p = data;
90 for (i = 0; i < h; i += 2, p += w)
91 for (x = 0; x < w; ++x, ++p)
92 *p = current;
93 }
94
95 if (a->surface.relief == RR_RELIEF_FLAT && a->surface.border) {
96 r = a->surface.border_color->r;
97 g = a->surface.border_color->g;
98 b = a->surface.border_color->b;
99 current = (r << RrDefaultRedOffset)
100 + (g << RrDefaultGreenOffset)
101 + (b << RrDefaultBlueOffset);
102 for (off = 0, x = 0; x < w; ++x, off++) {
103 *(data + off) = current;
104 *(data + off + ((h-1) * w)) = current;
105 }
106 for (off = 0, x = 0; x < h; ++x, off++) {
107 *(data + (off * w)) = current;
108 *(data + (off * w) + w - 1) = current;
109 }
110 }
111
112 if (a->surface.relief != RR_RELIEF_FLAT) {
113 if (a->surface.bevel == RR_BEVEL_1) {
114 for (off = 1, x = 1; x < w - 1; ++x, off++)
115 highlight(&a->surface, data + off,
116 data + off + (h-1) * w,
117 a->surface.relief==RR_RELIEF_RAISED);
118 for (off = 0, x = 0; x < h; ++x, off++)
119 highlight(&a->surface, data + off * w,
120 data + off * w + w - 1,
121 a->surface.relief==RR_RELIEF_RAISED);
122 }
123
124 if (a->surface.bevel == RR_BEVEL_2) {
125 for (off = 2, x = 2; x < w - 2; ++x, off++)
126 highlight(&a->surface, data + off + w,
127 data + off + (h-2) * w,
128 a->surface.relief==RR_RELIEF_RAISED);
129 for (off = 1, x = 1; x < h-1; ++x, off++)
130 highlight(&a->surface, data + off * w + 1,
131 data + off * w + w - 2,
132 a->surface.relief==RR_RELIEF_RAISED);
133 }
134 }
135 }
136
137 static void highlight(RrSurface *s, RrPixel32 *x, RrPixel32 *y, gboolean raised)
138 {
139 register gint r, g, b;
140
141 RrPixel32 *up, *down;
142 if (raised) {
143 up = x;
144 down = y;
145 } else {
146 up = y;
147 down = x;
148 }
149
150 r = (*up >> RrDefaultRedOffset) & 0xFF;
151 r += (r * s->bevel_light_adjust) >> 8;
152 g = (*up >> RrDefaultGreenOffset) & 0xFF;
153 g += (g * s->bevel_light_adjust) >> 8;
154 b = (*up >> RrDefaultBlueOffset) & 0xFF;
155 b += (b * s->bevel_light_adjust) >> 8;
156 if (r > 0xFF) r = 0xFF;
157 if (g > 0xFF) g = 0xFF;
158 if (b > 0xFF) b = 0xFF;
159 *up = (r << RrDefaultRedOffset) + (g << RrDefaultGreenOffset)
160 + (b << RrDefaultBlueOffset);
161
162 r = (*down >> RrDefaultRedOffset) & 0xFF;
163 r -= (r * s->bevel_dark_adjust) >> 8;
164 g = (*down >> RrDefaultGreenOffset) & 0xFF;
165 g -= (g * s->bevel_dark_adjust) >> 8;
166 b = (*down >> RrDefaultBlueOffset) & 0xFF;
167 b -= (b * s->bevel_dark_adjust) >> 8;
168 *down = (r << RrDefaultRedOffset) + (g << RrDefaultGreenOffset)
169 + (b << RrDefaultBlueOffset);
170 }
171
172 static void create_bevel_colors(RrAppearance *l)
173 {
174 register gint r, g, b;
175
176 /* light color */
177 r = l->surface.primary->r;
178 r += (r * l->surface.bevel_light_adjust) >> 8;
179 g = l->surface.primary->g;
180 g += (g * l->surface.bevel_light_adjust) >> 8;
181 b = l->surface.primary->b;
182 b += (b * l->surface.bevel_light_adjust) >> 8;
183 if (r > 0xFF) r = 0xFF;
184 if (g > 0xFF) g = 0xFF;
185 if (b > 0xFF) b = 0xFF;
186 g_assert(!l->surface.bevel_light);
187 l->surface.bevel_light = RrColorNew(l->inst, r, g, b);
188
189 /* dark color */
190 r = l->surface.primary->r;
191 r -= (r * l->surface.bevel_dark_adjust) >> 8;
192 g = l->surface.primary->g;
193 g -= (g * l->surface.bevel_dark_adjust) >> 8;
194 b = l->surface.primary->b;
195 b -= (b * l->surface.bevel_dark_adjust) >> 8;
196 g_assert(!l->surface.bevel_dark);
197 l->surface.bevel_dark = RrColorNew(l->inst, r, g, b);
198 }
199
200 /*! Repeat the first pixel over the entire block of memory
201 @param start The block of memory. start[0] will be copied
202 to the rest of the block.
203 @param w The width of the block of memory (including the already-set first
204 element
205 */
206 static inline void repeat_pixel(RrPixel32 *start, gint w)
207 {
208 register gint x;
209 RrPixel32 *dest;
210
211 dest = start + 1;
212
213 /* for really small things, just copy ourselves */
214 if (w < 8) {
215 for (x = w-1; x > 0; --x)
216 *(dest++) = *start;
217 }
218
219 /* for >= 8, then use O(log n) memcpy's... */
220 else {
221 gchar *cdest;
222 gint lenbytes;
223
224 /* copy the first 3 * 32 bits (3 words) ourselves - then we have
225 3 + the original 1 = 4 words to make copies of at a time
226
227 this is faster than doing memcpy for 1 or 2 words at a time
228 */
229 for (x = 3; x > 0; --x)
230 *(dest++) = *start;
231
232 /* cdest is a pointer to the pixel data that is typed char* so that
233 adding 1 to its position moves it only one byte
234
235 lenbytes is the amount of bytes that we will be copying each
236 iteration. this doubles each time through the loop.
237
238 x is the number of bytes left to copy into. lenbytes will alwaysa
239 be bounded by x
240
241 this loop will run O(log n) times (n is the number of bytes we
242 need to copy into), since the size of the copy is doubled each
243 iteration. it seems that gcc does some nice optimizations to make
244 this memcpy very fast on hardware with support for vector operations
245 such as mmx or see. here is an idea of the kind of speed up we are
246 getting by doing this (splitvertical3 switches from doing
247 "*(data++) = color" n times to doing this memcpy thing log n times:
248
249 % cumulative self self total
250 time seconds seconds calls ms/call ms/call name
251 49.44 0.88 0.88 1063 0.83 0.83 splitvertical1
252 47.19 1.72 0.84 1063 0.79 0.79 splitvertical2
253 2.81 1.77 0.05 1063 0.05 0.05 splitvertical3
254 */
255 cdest = (gchar*)dest;
256 lenbytes = 4 * sizeof(RrPixel32);
257 for (x = (w - 4) * sizeof(RrPixel32); x > 0;) {
258 memcpy(cdest, start, lenbytes);
259 x -= lenbytes;
260 cdest += lenbytes;
261 lenbytes <<= 1;
262 if (lenbytes > x)
263 lenbytes = x;
264 }
265 }
266 }
267
268 static void gradient_parentrelative(RrAppearance *a, gint w, gint h)
269 {
270 RrPixel32 *source, *dest;
271 gint sw, sh, partial_w, partial_h;
272 register gint i;
273
274 g_assert (a->surface.parent);
275 g_assert (a->surface.parent->w);
276
277 sw = a->surface.parent->w;
278 sh = a->surface.parent->h;
279
280 /* This is a little hack. When a texture is parentrelative, and the same
281 area as the parent, and has a bevel, it will draw its bevel on top
282 of the parent's, amplifying it. So instead, rerender the child with
283 the parent's settings, but the child's bevel and interlace */
284 if (a->surface.relief != RR_RELIEF_FLAT &&
285 (a->surface.parent->surface.relief != RR_RELIEF_FLAT ||
286 a->surface.parent->surface.border) &&
287 !a->surface.parentx && !a->surface.parenty &&
288 sw == w && sh == h)
289 {
290 RrSurface old = a->surface;
291 a->surface = a->surface.parent->surface;
292
293 /* turn these off for the parent */
294 a->surface.relief = RR_RELIEF_FLAT;
295 a->surface.border = FALSE;
296
297 a->surface.pixel_data = old.pixel_data;
298
299 RrRender(a, w, h);
300 a->surface = old;
301 } else {
302 source = (a->surface.parent->surface.pixel_data +
303 a->surface.parentx + sw * a->surface.parenty);
304 dest = a->surface.pixel_data;
305
306 if (a->surface.parentx + w > sw) {
307 partial_w = sw - a->surface.parentx;
308 } else partial_w = w;
309
310 if (a->surface.parenty + h > sh) {
311 partial_h = sh - a->surface.parenty;
312 } else partial_h = h;
313
314 for (i = 0; i < partial_h; i++, source += sw, dest += w) {
315 memcpy(dest, source, partial_w * sizeof(RrPixel32));
316 }
317 }
318 }
319
320 static void gradient_solid(RrAppearance *l, gint w, gint h)
321 {
322 register gint i;
323 RrPixel32 pix;
324 RrPixel32 *data = l->surface.pixel_data;
325 RrSurface *sp = &l->surface;
326 gint left = 0, top = 0, right = w - 1, bottom = h - 1;
327
328 pix = (sp->primary->r << RrDefaultRedOffset)
329 + (sp->primary->g << RrDefaultGreenOffset)
330 + (sp->primary->b << RrDefaultBlueOffset);
331
332 for (i = 0; i < w * h; i++)
333 *data++ = pix;
334
335 if (sp->interlaced)
336 return;
337
338 XFillRectangle(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->primary),
339 0, 0, w, h);
340
341 switch (sp->relief) {
342 case RR_RELIEF_RAISED:
343 if (!sp->bevel_dark)
344 create_bevel_colors(l);
345
346 switch (sp->bevel) {
347 case RR_BEVEL_1:
348 XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
349 left, bottom, right, bottom);
350 XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
351 right, bottom, right, top);
352
353 XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
354 left, top, right, top);
355 XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
356 left, bottom, left, top);
357 break;
358 case RR_BEVEL_2:
359 XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
360 left + 2, bottom - 1, right - 2, bottom - 1);
361 XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
362 right - 1, bottom - 1, right - 1, top + 1);
363
364 XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
365 left + 2, top + 1, right - 2, top + 1);
366 XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
367 left + 1, bottom - 1, left + 1, top + 1);
368 break;
369 default:
370 g_assert_not_reached(); /* unhandled BevelType */
371 }
372 break;
373 case RR_RELIEF_SUNKEN:
374 if (!sp->bevel_dark)
375 create_bevel_colors(l);
376
377 switch (sp->bevel) {
378 case RR_BEVEL_1:
379 XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
380 left, bottom, right, bottom);
381 XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
382 right, bottom, right, top);
383
384 XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
385 left, top, right, top);
386 XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
387 left, bottom, left, top);
388 break;
389 case RR_BEVEL_2:
390 XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
391 left + 2, bottom - 1, right - 2, bottom - 1);
392 XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
393 right - 1, bottom - 1, right - 1, top + 1);
394
395 XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
396 left + 2, top + 1, right - 2, top + 1);
397 XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
398 left + 1, bottom - 1, left + 1, top + 1);
399 break;
400 default:
401 g_assert_not_reached(); /* unhandled BevelType */
402 }
403 break;
404 case RR_RELIEF_FLAT:
405 if (sp->border) {
406 XDrawRectangle(RrDisplay(l->inst), l->pixmap,
407 RrColorGC(sp->border_color),
408 left, top, right, bottom);
409 }
410 break;
411 default:
412 g_assert_not_reached(); /* unhandled ReliefType */
413 }
414 }
415
416 /* * * * * * * * * * * * * * GRADIENT MAGIC WOOT * * * * * * * * * * * * * * */
417
418 #define VARS(x) \
419 register gint len##x; \
420 guint color##x[3]; \
421 gint cdelta##x[3], error##x[3] = { 0, 0, 0 }, inc##x[3]; \
422 gboolean bigslope##x[3] /* color slope > 1 */
423
424 #define SETUP(x, from, to, w) \
425 len##x = w; \
426 \
427 color##x[0] = from->r; \
428 color##x[1] = from->g; \
429 color##x[2] = from->b; \
430 \
431 cdelta##x[0] = to->r - from->r; \
432 cdelta##x[1] = to->g - from->g; \
433 cdelta##x[2] = to->b - from->b; \
434 \
435 if (cdelta##x[0] < 0) { \
436 cdelta##x[0] = -cdelta##x[0]; \
437 inc##x[0] = -1; \
438 } else \
439 inc##x[0] = 1; \
440 if (cdelta##x[1] < 0) { \
441 cdelta##x[1] = -cdelta##x[1]; \
442 inc##x[1] = -1; \
443 } else \
444 inc##x[1] = 1; \
445 if (cdelta##x[2] < 0) { \
446 cdelta##x[2] = -cdelta##x[2]; \
447 inc##x[2] = -1; \
448 } else \
449 inc##x[2] = 1; \
450 bigslope##x[0] = cdelta##x[0] > w;\
451 bigslope##x[1] = cdelta##x[1] > w;\
452 bigslope##x[2] = cdelta##x[2] > w
453
454 #define COLOR_RR(x, c) \
455 c->r = color##x[0]; \
456 c->g = color##x[1]; \
457 c->b = color##x[2]
458
459 #define COLOR(x) \
460 ((color##x[0] << RrDefaultRedOffset) + \
461 (color##x[1] << RrDefaultGreenOffset) + \
462 (color##x[2] << RrDefaultBlueOffset))
463
464 #define INCREMENT(x, i) \
465 (inc##x[i])
466
467 #define NEXT(x) \
468 { \
469 register gint i; \
470 for (i = 2; i >= 0; --i) { \
471 if (!cdelta##x[i]) continue; \
472 \
473 if (!bigslope##x[i]) { \
474 /* Y (color) is dependant on X */ \
475 error##x[i] += cdelta##x[i]; \
476 if ((error##x[i] << 1) >= len##x) { \
477 color##x[i] += INCREMENT(x, i); \
478 error##x[i] -= len##x; \
479 } \
480 } else { \
481 /* X is dependant on Y (color) */ \
482 while (1) { \
483 color##x[i] += INCREMENT(x, i); \
484 error##x[i] += len##x; \
485 if ((error##x[i] << 1) >= cdelta##x[i]) { \
486 error##x[i] -= cdelta##x[i]; \
487 break; \
488 } \
489 } \
490 } \
491 } \
492 }
493
494 static void gradient_splitvertical(RrAppearance *a, gint w, gint h)
495 {
496 register gint y1, y2, y3;
497 RrSurface *sf = &a->surface;
498 RrPixel32 *data;
499 register gint y1sz, y2sz, y3sz;
500
501 VARS(y1);
502 VARS(y2);
503 VARS(y3);
504
505 /* if h <= 5, then a 0 or 1px middle gradient.
506 if h > 5, then always a 1px middle gradient.
507 */
508 if (h <= 5) {
509 y1sz = MAX(h/2, 0);
510 y2sz = (h < 3 ? 0 : h % 2);
511 y3sz = MAX(h/2, 1);
512 }
513 else {
514 y1sz = h/2 - (1 - (h % 2));
515 y2sz = 1;
516 y3sz = h/2;
517 }
518
519 SETUP(y1, sf->split_primary, sf->primary, y1sz);
520 if (y2sz) {
521 /* setup to get the colors _in between_ these other 2 */
522 SETUP(y2, sf->primary, sf->secondary, y2sz + 2);
523 NEXT(y2); /* skip the first one, its the same as the last of y1 */
524 }
525 SETUP(y3, sf->secondary, sf->split_secondary, y3sz);
526
527 /* find the color for the first pixel of each row first */
528 data = sf->pixel_data;
529
530 for (y1 = y1sz-1; y1 > 0; --y1) {
531 *data = COLOR(y1);
532 data += w;
533 NEXT(y1);
534 }
535 *data = COLOR(y1);
536 data += w;
537 for (y2 = y2sz-1; y2 > 0; --y2) {
538 *data = COLOR(y2);
539 data += w;
540 NEXT(y2);
541 }
542 *data = COLOR(y2);
543 data += w;
544 for (y3 = y3sz-1; y3 > 0; --y3) {
545 *data = COLOR(y3);
546 data += w;
547 NEXT(y3);
548 }
549 *data = COLOR(y3);
550
551 /* copy the first pixels into the whole rows */
552 data = sf->pixel_data;
553 for (y1 = h; y1 > 0; --y1) {
554 repeat_pixel(data, w);
555 data += w;
556 }
557 }
558
559 static void gradient_horizontal(RrSurface *sf, gint w, gint h)
560 {
561 register gint x, y, cpbytes;
562 RrPixel32 *data = sf->pixel_data, *datav;
563 gchar *datac;
564
565 VARS(x);
566 SETUP(x, sf->primary, sf->secondary, w);
567
568 /* set the color values for the first row */
569 datav = data;
570 for (x = w - 1; x > 0; --x) { /* 0 -> w - 1 */
571 *datav = COLOR(x);
572 ++datav;
573 NEXT(x);
574 }
575 *datav = COLOR(x);
576 ++datav;
577
578 /* copy the first row to the rest in O(logn) copies */
579 datac = (gchar*)datav;
580 cpbytes = 1 * w * sizeof(RrPixel32);
581 for (y = (h - 1) * w * sizeof(RrPixel32); y > 0;) {
582 memcpy(datac, data, cpbytes);
583 y -= cpbytes;
584 datac += cpbytes;
585 cpbytes <<= 1;
586 if (cpbytes > y)
587 cpbytes = y;
588 }
589 }
590
591 static void gradient_mirrorhorizontal(RrSurface *sf, gint w, gint h)
592 {
593 register gint x, y, half1, half2, cpbytes;
594 RrPixel32 *data = sf->pixel_data, *datav;
595 gchar *datac;
596
597 VARS(x);
598
599 half1 = (w + 1) / 2;
600 half2 = w / 2;
601
602 /* set the color values for the first row */
603
604 SETUP(x, sf->primary, sf->secondary, half1);
605 datav = data;
606 for (x = half1 - 1; x > 0; --x) { /* 0 -> half1 - 1 */
607 *datav = COLOR(x);
608 ++datav;
609 NEXT(x);
610 }
611 *datav = COLOR(x);
612 ++datav;
613
614 if (half2 > 0) {
615 SETUP(x, sf->secondary, sf->primary, half2);
616 for (x = half2 - 1; x > 0; --x) { /* 0 -> half2 - 1 */
617 *datav = COLOR(x);
618 ++datav;
619 NEXT(x);
620 }
621 *datav = COLOR(x);
622 ++datav;
623 }
624
625 /* copy the first row to the rest in O(logn) copies */
626 datac = (gchar*)datav;
627 cpbytes = 1 * w * sizeof(RrPixel32);
628 for (y = (h - 1) * w * sizeof(RrPixel32); y > 0;) {
629 memcpy(datac, data, cpbytes);
630 y -= cpbytes;
631 datac += cpbytes;
632 cpbytes <<= 1;
633 if (cpbytes > y)
634 cpbytes = y;
635 }
636 }
637
638 static void gradient_vertical(RrSurface *sf, gint w, gint h)
639 {
640 register gint y;
641 RrPixel32 *data;
642
643 VARS(y);
644 SETUP(y, sf->primary, sf->secondary, h);
645
646 /* find the color for the first pixel of each row first */
647 data = sf->pixel_data;
648
649 for (y = h - 1; y > 0; --y) { /* 0 -> h-1 */
650 *data = COLOR(y);
651 data += w;
652 NEXT(y);
653 }
654 *data = COLOR(y);
655
656 /* copy the first pixels into the whole rows */
657 data = sf->pixel_data;
658 for (y = h; y > 0; --y) {
659 repeat_pixel(data, w);
660 data += w;
661 }
662 }
663
664 static void gradient_diagonal(RrSurface *sf, gint w, gint h)
665 {
666 register gint x, y;
667 RrPixel32 *data = sf->pixel_data;
668 RrColor left, right;
669 RrColor extracorner;
670
671 VARS(lefty);
672 VARS(righty);
673 VARS(x);
674
675 extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
676 extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
677 extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
678
679 SETUP(lefty, sf->primary, (&extracorner), h);
680 SETUP(righty, (&extracorner), sf->secondary, h);
681
682 for (y = h - 1; y > 0; --y) { /* 0 -> h-1 */
683 COLOR_RR(lefty, (&left));
684 COLOR_RR(righty, (&right));
685
686 SETUP(x, (&left), (&right), w);
687
688 for (x = w - 1; x > 0; --x) { /* 0 -> w-1 */
689 *(data++) = COLOR(x);
690
691 NEXT(x);
692 }
693 *(data++) = COLOR(x);
694
695 NEXT(lefty);
696 NEXT(righty);
697 }
698 COLOR_RR(lefty, (&left));
699 COLOR_RR(righty, (&right));
700
701 SETUP(x, (&left), (&right), w);
702
703 for (x = w - 1; x > 0; --x) { /* 0 -> w-1 */
704 *(data++) = COLOR(x);
705
706 NEXT(x);
707 }
708 *data = COLOR(x);
709 }
710
711 static void gradient_crossdiagonal(RrSurface *sf, gint w, gint h)
712 {
713 register gint x, y;
714 RrPixel32 *data = sf->pixel_data;
715 RrColor left, right;
716 RrColor extracorner;
717
718 VARS(lefty);
719 VARS(righty);
720 VARS(x);
721
722 extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
723 extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
724 extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
725
726 SETUP(lefty, (&extracorner), sf->secondary, h);
727 SETUP(righty, sf->primary, (&extracorner), h);
728
729 for (y = h - 1; y > 0; --y) { /* 0 -> h-1 */
730 COLOR_RR(lefty, (&left));
731 COLOR_RR(righty, (&right));
732
733 SETUP(x, (&left), (&right), w);
734
735 for (x = w - 1; x > 0; --x) { /* 0 -> w-1 */
736 *(data++) = COLOR(x);
737
738 NEXT(x);
739 }
740 *(data++) = COLOR(x);
741
742 NEXT(lefty);
743 NEXT(righty);
744 }
745 COLOR_RR(lefty, (&left));
746 COLOR_RR(righty, (&right));
747
748 SETUP(x, (&left), (&right), w);
749
750 for (x = w - 1; x > 0; --x) { /* 0 -> w-1 */
751 *(data++) = COLOR(x);
752
753 NEXT(x);
754 }
755 *data = COLOR(x);
756 }
757
758 static void gradient_pyramid(RrSurface *sf, gint w, gint h)
759 {
760 RrPixel32 *ldata, *rdata;
761 RrPixel32 *cp;
762 RrColor left, right;
763 RrColor extracorner;
764 register gint x, y, halfw, halfh, midx, midy;
765
766 VARS(lefty);
767 VARS(righty);
768 VARS(x);
769
770 extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
771 extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
772 extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
773
774 halfw = w >> 1;
775 halfh = h >> 1;
776 midx = w - halfw - halfw; /* 0 or 1, depending if w is even or odd */
777 midy = h - halfh - halfh; /* 0 or 1, depending if h is even or odd */
778
779 SETUP(lefty, sf->primary, (&extracorner), halfh + midy);
780 SETUP(righty, (&extracorner), sf->secondary, halfh + midy);
781
782 /* draw the top half
783
784 it is faster to draw both top quarters together than to draw one and
785 then copy it over to the other side.
786 */
787
788 ldata = sf->pixel_data;
789 rdata = ldata + w - 1;
790 for (y = halfh + midy; y > 0; --y) { /* 0 -> (h+1)/2 */
791 RrPixel32 c;
792
793 COLOR_RR(lefty, (&left));
794 COLOR_RR(righty, (&right));
795
796 SETUP(x, (&left), (&right), halfw + midx);
797
798 for (x = halfw + midx - 1; x > 0; --x) { /* 0 -> (w+1)/2 */
799 c = COLOR(x);
800 *(ldata++) = *(rdata--) = c;
801
802 NEXT(x);
803 }
804 c = COLOR(x);
805 *ldata = *rdata = c;
806 ldata += halfw + 1;
807 rdata += halfw - 1 + midx + w;
808
809 NEXT(lefty);
810 NEXT(righty);
811 }
812
813 /* copy the top half into the bottom half, mirroring it, so we can only
814 copy one row at a time
815
816 it is faster, to move the writing pointer forward, and the reading
817 pointer backward
818
819 this is the current code, moving the write pointer forward and read
820 pointer backward
821 41.78 4.26 1.78 504 3.53 3.53 gradient_pyramid2
822 this is the opposite, moving the read pointer forward and the write
823 pointer backward
824 42.27 4.40 1.86 504 3.69 3.69 gradient_pyramid2
825
826 */
827 ldata = sf->pixel_data + (halfh - 1) * w;
828 cp = ldata + (midy + 1) * w;
829 for (y = halfh; y > 0; --y) {
830 memcpy(cp, ldata, w * sizeof(RrPixel32));
831 ldata -= w;
832 cp += w;
833 }
834 }
This page took 0.068621 seconds and 3 git commands to generate.