1 /* -*- indent-tabs-mode: nil; tab-width: 4; c-basic-offset: 4; -*-
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
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.
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.
18 See the COPYING file for a copy of the GNU General Public License.
27 static void highlight(RrSurface
*s
, RrPixel32
*x
, RrPixel32
*y
,
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
);
39 void RrRender(RrAppearance
*a
, gint w
, gint h
)
41 RrPixel32
*data
= a
->surface
.pixel_data
;
46 switch (a
->surface
.grad
) {
47 case RR_SURFACE_PARENTREL
:
48 gradient_parentrelative(a
, w
, h
);
50 case RR_SURFACE_SOLID
:
51 gradient_solid(a
, w
, h
);
53 case RR_SURFACE_SPLIT_VERTICAL
:
54 gradient_splitvertical(a
, w
, h
);
56 case RR_SURFACE_VERTICAL
:
57 gradient_vertical(&a
->surface
, w
, h
);
59 case RR_SURFACE_HORIZONTAL
:
60 gradient_horizontal(&a
->surface
, w
, h
);
62 case RR_SURFACE_MIRROR_HORIZONTAL
:
63 gradient_mirrorhorizontal(&a
->surface
, w
, h
);
65 case RR_SURFACE_DIAGONAL
:
66 gradient_diagonal(&a
->surface
, w
, h
);
68 case RR_SURFACE_CROSS_DIAGONAL
:
69 gradient_crossdiagonal(&a
->surface
, w
, h
);
71 case RR_SURFACE_PYRAMID
:
72 gradient_pyramid(&a
->surface
, w
, h
);
75 g_assert_not_reached(); /* unhandled gradient */
79 if (a
->surface
.interlaced
) {
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
);
90 for (i
= 0; i
< h
; i
+= 2, p
+= w
)
91 for (x
= 0; x
< w
; ++x
, ++p
)
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
;
106 for (off
= 0, x
= 0; x
< h
; ++x
, off
++) {
107 *(data
+ (off
* w
)) = current
;
108 *(data
+ (off
* w
) + w
- 1) = current
;
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
);
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
);
137 static void highlight(RrSurface
*s
, RrPixel32
*x
, RrPixel32
*y
, gboolean raised
)
139 register gint r
, g
, b
;
141 RrPixel32
*up
, *down
;
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
);
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
);
172 static void create_bevel_colors(RrAppearance
*l
)
174 register gint r
, g
, b
;
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
);
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
);
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
206 static inline void repeat_pixel(RrPixel32
*start
, gint w
)
213 /* for really small things, just copy ourselves */
215 for (x
= w
-1; x
> 0; --x
)
219 /* for >= 8, then use O(log n) memcpy's... */
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
227 this is faster than doing memcpy for 1 or 2 words at a time
229 for (x
= 3; x
> 0; --x
)
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
235 lenbytes is the amount of bytes that we will be copying each
236 iteration. this doubles each time through the loop.
238 x is the number of bytes left to copy into. lenbytes will alwaysa
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:
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
255 cdest
= (gchar
*)dest
;
256 lenbytes
= 4 * sizeof(RrPixel32
);
257 for (x
= (w
- 4) * sizeof(RrPixel32
); x
> 0;) {
258 memcpy(cdest
, start
, lenbytes
);
268 static void gradient_parentrelative(RrAppearance
*a
, gint w
, gint h
)
270 RrPixel32
*source
, *dest
;
271 gint sw
, sh
, partial_w
, partial_h
;
274 g_assert (a
->surface
.parent
);
275 g_assert (a
->surface
.parent
->w
);
277 sw
= a
->surface
.parent
->w
;
278 sh
= a
->surface
.parent
->h
;
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
&&
290 RrSurface old
= a
->surface
;
291 a
->surface
= a
->surface
.parent
->surface
;
293 /* turn these off for the parent */
294 a
->surface
.relief
= RR_RELIEF_FLAT
;
295 a
->surface
.border
= FALSE
;
297 a
->surface
.pixel_data
= old
.pixel_data
;
302 source
= (a
->surface
.parent
->surface
.pixel_data
+
303 a
->surface
.parentx
+ sw
* a
->surface
.parenty
);
304 dest
= a
->surface
.pixel_data
;
306 if (a
->surface
.parentx
+ w
> sw
) {
307 partial_w
= sw
- a
->surface
.parentx
;
308 } else partial_w
= w
;
310 if (a
->surface
.parenty
+ h
> sh
) {
311 partial_h
= sh
- a
->surface
.parenty
;
312 } else partial_h
= h
;
314 for (i
= 0; i
< partial_h
; i
++, source
+= sw
, dest
+= w
) {
315 memcpy(dest
, source
, partial_w
* sizeof(RrPixel32
));
320 static void gradient_solid(RrAppearance
*l
, gint w
, gint h
)
324 RrPixel32
*data
= l
->surface
.pixel_data
;
325 RrSurface
*sp
= &l
->surface
;
326 gint left
= 0, top
= 0, right
= w
- 1, bottom
= h
- 1;
328 pix
= (sp
->primary
->r
<< RrDefaultRedOffset
)
329 + (sp
->primary
->g
<< RrDefaultGreenOffset
)
330 + (sp
->primary
->b
<< RrDefaultBlueOffset
);
332 for (i
= 0; i
< w
* h
; i
++)
338 XFillRectangle(RrDisplay(l
->inst
), l
->pixmap
, RrColorGC(sp
->primary
),
341 switch (sp
->relief
) {
342 case RR_RELIEF_RAISED
:
344 create_bevel_colors(l
);
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
);
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
);
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);
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);
370 g_assert_not_reached(); /* unhandled BevelType */
373 case RR_RELIEF_SUNKEN
:
375 create_bevel_colors(l
);
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
);
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
);
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);
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);
401 g_assert_not_reached(); /* unhandled BevelType */
406 XDrawRectangle(RrDisplay(l
->inst
), l
->pixmap
,
407 RrColorGC(sp
->border_color
),
408 left
, top
, right
, bottom
);
412 g_assert_not_reached(); /* unhandled ReliefType */
416 /* * * * * * * * * * * * * * GRADIENT MAGIC WOOT * * * * * * * * * * * * * * */
419 register gint len##x; \
421 gint cdelta##x[3], error##x[3] = { 0, 0, 0 }, inc##x[3]; \
422 gboolean bigslope##x[3] /* color slope > 1 */
424 #define SETUP(x, from, to, w) \
427 color##x[0] = from->r; \
428 color##x[1] = from->g; \
429 color##x[2] = from->b; \
431 cdelta##x[0] = to->r - from->r; \
432 cdelta##x[1] = to->g - from->g; \
433 cdelta##x[2] = to->b - from->b; \
435 if (cdelta##x[0] < 0) { \
436 cdelta##x[0] = -cdelta##x[0]; \
440 if (cdelta##x[1] < 0) { \
441 cdelta##x[1] = -cdelta##x[1]; \
445 if (cdelta##x[2] < 0) { \
446 cdelta##x[2] = -cdelta##x[2]; \
450 bigslope##x[0] = cdelta##x[0] > w;\
451 bigslope##x[1] = cdelta##x[1] > w;\
452 bigslope##x[2] = cdelta##x[2] > w
454 #define COLOR_RR(x, c) \
455 c->r = color##x[0]; \
456 c->g = color##x[1]; \
460 ((color##x[0] << RrDefaultRedOffset) + \
461 (color##x[1] << RrDefaultGreenOffset) + \
462 (color##x[2] << RrDefaultBlueOffset))
464 #define INCREMENT(x, i) \
470 for (i = 2; i >= 0; --i) { \
471 if (!cdelta##x[i]) continue; \
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; \
481 /* X is dependant on Y (color) */ \
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]; \
494 static void gradient_splitvertical(RrAppearance
*a
, gint w
, gint h
)
496 register gint y1
, y2
, y3
;
497 RrSurface
*sf
= &a
->surface
;
499 register gint y1sz
, y2sz
, y3sz
;
505 /* if h <= 5, then a 0 or 1px middle gradient.
506 if h > 5, then always a 1px middle gradient.
510 y2sz
= (h
< 3) ? 0 : (h
& 1);
514 y1sz
= h
/2 - (1 - (h
& 1));
519 SETUP(y1
, sf
->split_primary
, sf
->primary
, y1sz
);
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 */
525 SETUP(y3
, sf
->secondary
, sf
->split_secondary
, y3sz
);
527 /* find the color for the first pixel of each row first */
528 data
= sf
->pixel_data
;
531 for (y1
= y1sz
-1; y1
> 0; --y1
) {
540 for (y2
= y2sz
-1; y2
> 0; --y2
) {
548 for (y3
= y3sz
-1; y3
> 0; --y3
) {
555 /* copy the first pixels into the whole rows */
556 data
= sf
->pixel_data
;
557 for (y1
= h
; y1
> 0; --y1
) {
558 repeat_pixel(data
, w
);
563 static void gradient_horizontal(RrSurface
*sf
, gint w
, gint h
)
565 register gint x
, y
, cpbytes
;
566 RrPixel32
*data
= sf
->pixel_data
, *datav
;
570 SETUP(x
, sf
->primary
, sf
->secondary
, w
);
572 /* set the color values for the first row */
574 for (x
= w
- 1; x
> 0; --x
) { /* 0 -> w - 1 */
582 /* copy the first row to the rest in O(logn) copies */
583 datac
= (gchar
*)datav
;
584 cpbytes
= 1 * w
* sizeof(RrPixel32
);
585 for (y
= (h
- 1) * w
* sizeof(RrPixel32
); y
> 0;) {
586 memcpy(datac
, data
, cpbytes
);
595 static void gradient_mirrorhorizontal(RrSurface
*sf
, gint w
, gint h
)
597 register gint x
, y
, half1
, half2
, cpbytes
;
598 RrPixel32
*data
= sf
->pixel_data
, *datav
;
606 /* set the color values for the first row */
608 SETUP(x
, sf
->primary
, sf
->secondary
, half1
);
610 for (x
= half1
- 1; x
> 0; --x
) { /* 0 -> half1 - 1 */
619 SETUP(x
, sf
->secondary
, sf
->primary
, half2
);
620 for (x
= half2
- 1; x
> 0; --x
) { /* 0 -> half2 - 1 */
629 /* copy the first row to the rest in O(logn) copies */
630 datac
= (gchar
*)datav
;
631 cpbytes
= 1 * w
* sizeof(RrPixel32
);
632 for (y
= (h
- 1) * w
* sizeof(RrPixel32
); y
> 0;) {
633 memcpy(datac
, data
, cpbytes
);
642 static void gradient_vertical(RrSurface
*sf
, gint w
, gint h
)
648 SETUP(y
, sf
->primary
, sf
->secondary
, h
);
650 /* find the color for the first pixel of each row first */
651 data
= sf
->pixel_data
;
653 for (y
= h
- 1; y
> 0; --y
) { /* 0 -> h-1 */
660 /* copy the first pixels into the whole rows */
661 data
= sf
->pixel_data
;
662 for (y
= h
; y
> 0; --y
) {
663 repeat_pixel(data
, w
);
668 static void gradient_diagonal(RrSurface
*sf
, gint w
, gint h
)
671 RrPixel32
*data
= sf
->pixel_data
;
679 extracorner
.r
= (sf
->primary
->r
+ sf
->secondary
->r
) / 2;
680 extracorner
.g
= (sf
->primary
->g
+ sf
->secondary
->g
) / 2;
681 extracorner
.b
= (sf
->primary
->b
+ sf
->secondary
->b
) / 2;
683 SETUP(lefty
, sf
->primary
, (&extracorner
), h
);
684 SETUP(righty
, (&extracorner
), sf
->secondary
, h
);
686 for (y
= h
- 1; y
> 0; --y
) { /* 0 -> h-1 */
687 COLOR_RR(lefty
, (&left
));
688 COLOR_RR(righty
, (&right
));
690 SETUP(x
, (&left
), (&right
), w
);
692 for (x
= w
- 1; x
> 0; --x
) { /* 0 -> w-1 */
693 *(data
++) = COLOR(x
);
697 *(data
++) = COLOR(x
);
702 COLOR_RR(lefty
, (&left
));
703 COLOR_RR(righty
, (&right
));
705 SETUP(x
, (&left
), (&right
), w
);
707 for (x
= w
- 1; x
> 0; --x
) { /* 0 -> w-1 */
708 *(data
++) = COLOR(x
);
715 static void gradient_crossdiagonal(RrSurface
*sf
, gint w
, gint h
)
718 RrPixel32
*data
= sf
->pixel_data
;
726 extracorner
.r
= (sf
->primary
->r
+ sf
->secondary
->r
) / 2;
727 extracorner
.g
= (sf
->primary
->g
+ sf
->secondary
->g
) / 2;
728 extracorner
.b
= (sf
->primary
->b
+ sf
->secondary
->b
) / 2;
730 SETUP(lefty
, (&extracorner
), sf
->secondary
, h
);
731 SETUP(righty
, sf
->primary
, (&extracorner
), h
);
733 for (y
= h
- 1; y
> 0; --y
) { /* 0 -> h-1 */
734 COLOR_RR(lefty
, (&left
));
735 COLOR_RR(righty
, (&right
));
737 SETUP(x
, (&left
), (&right
), w
);
739 for (x
= w
- 1; x
> 0; --x
) { /* 0 -> w-1 */
740 *(data
++) = COLOR(x
);
744 *(data
++) = COLOR(x
);
749 COLOR_RR(lefty
, (&left
));
750 COLOR_RR(righty
, (&right
));
752 SETUP(x
, (&left
), (&right
), w
);
754 for (x
= w
- 1; x
> 0; --x
) { /* 0 -> w-1 */
755 *(data
++) = COLOR(x
);
762 static void gradient_pyramid(RrSurface
*sf
, gint w
, gint h
)
764 RrPixel32
*ldata
, *rdata
;
768 register gint x
, y
, halfw
, halfh
, midx
, midy
;
774 extracorner
.r
= (sf
->primary
->r
+ sf
->secondary
->r
) / 2;
775 extracorner
.g
= (sf
->primary
->g
+ sf
->secondary
->g
) / 2;
776 extracorner
.b
= (sf
->primary
->b
+ sf
->secondary
->b
) / 2;
780 midx
= w
- halfw
- halfw
; /* 0 or 1, depending if w is even or odd */
781 midy
= h
- halfh
- halfh
; /* 0 or 1, depending if h is even or odd */
783 SETUP(lefty
, sf
->primary
, (&extracorner
), halfh
+ midy
);
784 SETUP(righty
, (&extracorner
), sf
->secondary
, halfh
+ midy
);
788 it is faster to draw both top quarters together than to draw one and
789 then copy it over to the other side.
792 ldata
= sf
->pixel_data
;
793 rdata
= ldata
+ w
- 1;
794 for (y
= halfh
+ midy
; y
> 0; --y
) { /* 0 -> (h+1)/2 */
797 COLOR_RR(lefty
, (&left
));
798 COLOR_RR(righty
, (&right
));
800 SETUP(x
, (&left
), (&right
), halfw
+ midx
);
802 for (x
= halfw
+ midx
- 1; x
> 0; --x
) { /* 0 -> (w+1)/2 */
804 *(ldata
++) = *(rdata
--) = c
;
811 rdata
+= halfw
- 1 + midx
+ w
;
817 /* copy the top half into the bottom half, mirroring it, so we can only
818 copy one row at a time
820 it is faster, to move the writing pointer forward, and the reading
823 this is the current code, moving the write pointer forward and read
825 41.78 4.26 1.78 504 3.53 3.53 gradient_pyramid2
826 this is the opposite, moving the read pointer forward and the write
828 42.27 4.40 1.86 504 3.69 3.69 gradient_pyramid2
831 ldata
= sf
->pixel_data
+ (halfh
- 1) * w
;
832 cp
= ldata
+ (midy
+ 1) * w
;
833 for (y
= halfh
; y
> 0; --y
) {
834 memcpy(cp
, ldata
, w
* sizeof(RrPixel32
));