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
)
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
)
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
, i
;
273 g_assert (a
->surface
.parent
);
274 g_assert (a
->surface
.parent
->w
);
276 sw
= a
->surface
.parent
->w
;
277 sh
= a
->surface
.parent
->h
;
279 /* This is a little hack. When a texture is parentrelative, and the same
280 area as the parent, and has a bevel, it will draw its bevel on top
281 of the parent's, amplifying it. So instead, rerender the child with
282 the parent's settings, but the child's bevel and interlace */
283 if (a
->surface
.relief
!= RR_RELIEF_FLAT
&&
284 (a
->surface
.parent
->surface
.relief
!= RR_RELIEF_FLAT
||
285 a
->surface
.parent
->surface
.border
) &&
286 !a
->surface
.parentx
&& !a
->surface
.parenty
&&
289 RrSurface old
= a
->surface
;
290 a
->surface
= a
->surface
.parent
->surface
;
292 /* turn these off for the parent */
293 a
->surface
.relief
= RR_RELIEF_FLAT
;
294 a
->surface
.border
= FALSE
;
296 a
->surface
.pixel_data
= old
.pixel_data
;
301 source
= (a
->surface
.parent
->surface
.pixel_data
+
302 a
->surface
.parentx
+ sw
* a
->surface
.parenty
);
303 dest
= a
->surface
.pixel_data
;
305 if (a
->surface
.parentx
+ w
> sw
) {
306 partial_w
= sw
- a
->surface
.parentx
;
307 } else partial_w
= w
;
309 if (a
->surface
.parenty
+ h
> sh
) {
310 partial_h
= sh
- a
->surface
.parenty
;
311 } else partial_h
= h
;
313 for (i
= 0; i
< partial_h
; i
++, source
+= sw
, dest
+= w
) {
314 memcpy(dest
, source
, partial_w
* sizeof(RrPixel32
));
319 static void gradient_solid(RrAppearance
*l
, gint w
, gint h
)
323 RrPixel32
*data
= l
->surface
.pixel_data
;
324 RrSurface
*sp
= &l
->surface
;
325 gint left
= 0, top
= 0, right
= w
- 1, bottom
= h
- 1;
327 pix
= (sp
->primary
->r
<< RrDefaultRedOffset
)
328 + (sp
->primary
->g
<< RrDefaultGreenOffset
)
329 + (sp
->primary
->b
<< RrDefaultBlueOffset
);
331 for (i
= 0; i
< w
* h
; i
++)
337 XFillRectangle(RrDisplay(l
->inst
), l
->pixmap
, RrColorGC(sp
->primary
),
340 switch (sp
->relief
) {
341 case RR_RELIEF_RAISED
:
343 create_bevel_colors(l
);
347 XDrawLine(RrDisplay(l
->inst
), l
->pixmap
, RrColorGC(sp
->bevel_dark
),
348 left
, bottom
, right
, bottom
);
349 XDrawLine(RrDisplay(l
->inst
), l
->pixmap
, RrColorGC(sp
->bevel_dark
),
350 right
, bottom
, right
, top
);
352 XDrawLine(RrDisplay(l
->inst
), l
->pixmap
,RrColorGC(sp
->bevel_light
),
353 left
, top
, right
, top
);
354 XDrawLine(RrDisplay(l
->inst
), l
->pixmap
,RrColorGC(sp
->bevel_light
),
355 left
, bottom
, left
, top
);
358 XDrawLine(RrDisplay(l
->inst
), l
->pixmap
, RrColorGC(sp
->bevel_dark
),
359 left
+ 2, bottom
- 1, right
- 2, bottom
- 1);
360 XDrawLine(RrDisplay(l
->inst
), l
->pixmap
, RrColorGC(sp
->bevel_dark
),
361 right
- 1, bottom
- 1, right
- 1, top
+ 1);
363 XDrawLine(RrDisplay(l
->inst
), l
->pixmap
,RrColorGC(sp
->bevel_light
),
364 left
+ 2, top
+ 1, right
- 2, top
+ 1);
365 XDrawLine(RrDisplay(l
->inst
), l
->pixmap
,RrColorGC(sp
->bevel_light
),
366 left
+ 1, bottom
- 1, left
+ 1, top
+ 1);
369 g_assert_not_reached(); /* unhandled BevelType */
372 case RR_RELIEF_SUNKEN
:
374 create_bevel_colors(l
);
378 XDrawLine(RrDisplay(l
->inst
), l
->pixmap
,RrColorGC(sp
->bevel_light
),
379 left
, bottom
, right
, bottom
);
380 XDrawLine(RrDisplay(l
->inst
), l
->pixmap
,RrColorGC(sp
->bevel_light
),
381 right
, bottom
, right
, top
);
383 XDrawLine(RrDisplay(l
->inst
), l
->pixmap
, RrColorGC(sp
->bevel_dark
),
384 left
, top
, right
, top
);
385 XDrawLine(RrDisplay(l
->inst
), l
->pixmap
, RrColorGC(sp
->bevel_dark
),
386 left
, bottom
, left
, top
);
389 XDrawLine(RrDisplay(l
->inst
), l
->pixmap
,RrColorGC(sp
->bevel_light
),
390 left
+ 2, bottom
- 1, right
- 2, bottom
- 1);
391 XDrawLine(RrDisplay(l
->inst
), l
->pixmap
,RrColorGC(sp
->bevel_light
),
392 right
- 1, bottom
- 1, right
- 1, top
+ 1);
394 XDrawLine(RrDisplay(l
->inst
), l
->pixmap
, RrColorGC(sp
->bevel_dark
),
395 left
+ 2, top
+ 1, right
- 2, top
+ 1);
396 XDrawLine(RrDisplay(l
->inst
), l
->pixmap
, RrColorGC(sp
->bevel_dark
),
397 left
+ 1, bottom
- 1, left
+ 1, top
+ 1);
400 g_assert_not_reached(); /* unhandled BevelType */
405 XDrawRectangle(RrDisplay(l
->inst
), l
->pixmap
,
406 RrColorGC(sp
->border_color
),
407 left
, top
, right
, bottom
);
411 g_assert_not_reached(); /* unhandled ReliefType */
415 /* * * * * * * * * * * * * * GRADIENT MAGIC WOOT * * * * * * * * * * * * * * */
419 gint len##x, cdelta##x[3], error##x[3] = { 0, 0, 0 }, inc##x[3]; \
420 gboolean bigslope##x[3] /* color slope > 1 */
422 #define SETUP(x, from, to, w) \
425 color##x[0] = from->r; \
426 color##x[1] = from->g; \
427 color##x[2] = from->b; \
429 cdelta##x[0] = to->r - from->r; \
430 cdelta##x[1] = to->g - from->g; \
431 cdelta##x[2] = to->b - from->b; \
433 if (cdelta##x[0] < 0) { \
434 cdelta##x[0] = -cdelta##x[0]; \
438 if (cdelta##x[1] < 0) { \
439 cdelta##x[1] = -cdelta##x[1]; \
443 if (cdelta##x[2] < 0) { \
444 cdelta##x[2] = -cdelta##x[2]; \
448 bigslope##x[0] = cdelta##x[0] > w;\
449 bigslope##x[1] = cdelta##x[1] > w;\
450 bigslope##x[2] = cdelta##x[2] > w
452 #define COLOR_RR(x, c) \
453 c->r = color##x[0]; \
454 c->g = color##x[1]; \
458 ((color##x[0] << RrDefaultRedOffset) + \
459 (color##x[1] << RrDefaultGreenOffset) + \
460 (color##x[2] << RrDefaultBlueOffset))
462 #define INCREMENT(x, i) \
468 for (i = 2; i >= 0; --i) { \
469 if (!cdelta##x[i]) continue; \
471 if (!bigslope##x[i]) { \
472 /* Y (color) is dependant on X */ \
473 error##x[i] += cdelta##x[i]; \
474 if ((error##x[i] << 1) >= len##x) { \
475 color##x[i] += INCREMENT(x, i); \
476 error##x[i] -= len##x; \
479 /* X is dependant on Y (color) */ \
481 color##x[i] += INCREMENT(x, i); \
482 error##x[i] += len##x; \
483 if ((error##x[i] << 1) >= cdelta##x[i]) { \
484 error##x[i] -= cdelta##x[i]; \
492 static void gradient_splitvertical(RrAppearance
*a
, gint w
, gint h
)
495 RrSurface
*sf
= &a
->surface
;
497 gint y1sz
, y2sz
, y3sz
;
503 /* if h <= 5, then a 0 or 1px middle gradient.
504 if h > 5, then always a 1px middle gradient.
508 y2sz
= (h
< 3 ? 0 : h
% 2);
512 y1sz
= h
/2 - (1 - (h
% 2));
517 SETUP(y1
, sf
->split_primary
, sf
->primary
, y1sz
);
519 /* setup to get the colors _in between_ these other 2 */
520 SETUP(y2
, sf
->primary
, sf
->secondary
, y2sz
+ 2);
521 NEXT(y2
); /* skip the first one, its the same as the last of y1 */
523 SETUP(y3
, sf
->secondary
, sf
->split_secondary
, y3sz
);
525 /* find the color for the first pixel of each row first */
526 data
= sf
->pixel_data
;
528 for (y1
= y1sz
-1; y1
> 0; --y1
) {
535 for (y2
= y2sz
-1; y2
> 0; --y2
) {
542 for (y3
= y3sz
-1; y3
> 0; --y3
) {
549 /* copy the first pixels into the whole rows */
550 data
= sf
->pixel_data
;
551 for (y1
= h
; y1
> 0; --y1
) {
552 repeat_pixel(data
, w
);
557 static void gradient_horizontal(RrSurface
*sf
, gint w
, gint h
)
560 RrPixel32
*data
= sf
->pixel_data
, *datav
;
564 SETUP(x
, sf
->primary
, sf
->secondary
, w
);
566 /* set the color values for the first row */
568 for (x
= w
- 1; x
> 0; --x
) { /* 0 -> w - 1 */
576 /* copy the first row to the rest in O(logn) copies */
577 datac
= (gchar
*)datav
;
578 cpbytes
= 1 * w
* sizeof(RrPixel32
);
579 for (y
= (h
- 1) * w
* sizeof(RrPixel32
); y
> 0;) {
580 memcpy(datac
, data
, cpbytes
);
589 static void gradient_mirrorhorizontal(RrSurface
*sf
, gint w
, gint h
)
591 gint x
, y
, half1
, half2
, cpbytes
;
592 RrPixel32
*data
= sf
->pixel_data
, *datav
;
600 /* set the color values for the first row */
602 SETUP(x
, sf
->primary
, sf
->secondary
, half1
);
604 for (x
= half1
- 1; x
> 0; --x
) { /* 0 -> half1 - 1 */
613 SETUP(x
, sf
->secondary
, sf
->primary
, half2
);
614 for (x
= half2
- 1; x
> 0; --x
) { /* 0 -> half2 - 1 */
623 /* copy the first row to the rest in O(logn) copies */
624 datac
= (gchar
*)datav
;
625 cpbytes
= 1 * w
* sizeof(RrPixel32
);
626 for (y
= (h
- 1) * w
* sizeof(RrPixel32
); y
> 0;) {
627 memcpy(datac
, data
, cpbytes
);
636 static void gradient_vertical(RrSurface
*sf
, gint w
, gint h
)
642 SETUP(y
, sf
->primary
, sf
->secondary
, h
);
644 /* find the color for the first pixel of each row first */
645 data
= sf
->pixel_data
;
647 for (y
= h
- 1; y
> 0; --y
) { /* 0 -> h-1 */
654 /* copy the first pixels into the whole rows */
655 data
= sf
->pixel_data
;
656 for (y
= h
; y
> 0; --y
) {
657 repeat_pixel(data
, w
);
663 static void gradient_diagonal(RrSurface
*sf
, gint w
, gint h
)
666 RrPixel32
*data
= sf
->pixel_data
;
674 extracorner
.r
= (sf
->primary
->r
+ sf
->secondary
->r
) / 2;
675 extracorner
.g
= (sf
->primary
->g
+ sf
->secondary
->g
) / 2;
676 extracorner
.b
= (sf
->primary
->b
+ sf
->secondary
->b
) / 2;
678 SETUP(lefty
, sf
->primary
, (&extracorner
), h
);
679 SETUP(righty
, (&extracorner
), sf
->secondary
, h
);
681 for (y
= h
- 1; y
> 0; --y
) { /* 0 -> h-1 */
682 COLOR_RR(lefty
, (&left
));
683 COLOR_RR(righty
, (&right
));
685 SETUP(x
, (&left
), (&right
), w
);
687 for (x
= w
- 1; x
> 0; --x
) { /* 0 -> w-1 */
688 *(data
++) = COLOR(x
);
692 *(data
++) = COLOR(x
);
697 COLOR_RR(lefty
, (&left
));
698 COLOR_RR(righty
, (&right
));
700 SETUP(x
, (&left
), (&right
), w
);
702 for (x
= w
- 1; x
> 0; --x
) { /* 0 -> w-1 */
703 *(data
++) = COLOR(x
);
710 static void gradient_crossdiagonal(RrSurface
*sf
, gint w
, gint h
)
713 RrPixel32
*data
= sf
->pixel_data
;
721 extracorner
.r
= (sf
->primary
->r
+ sf
->secondary
->r
) / 2;
722 extracorner
.g
= (sf
->primary
->g
+ sf
->secondary
->g
) / 2;
723 extracorner
.b
= (sf
->primary
->b
+ sf
->secondary
->b
) / 2;
725 SETUP(lefty
, (&extracorner
), sf
->secondary
, h
);
726 SETUP(righty
, sf
->primary
, (&extracorner
), h
);
728 for (y
= h
- 1; y
> 0; --y
) { /* 0 -> h-1 */
729 COLOR_RR(lefty
, (&left
));
730 COLOR_RR(righty
, (&right
));
732 SETUP(x
, (&left
), (&right
), w
);
734 for (x
= w
- 1; x
> 0; --x
) { /* 0 -> w-1 */
735 *(data
++) = COLOR(x
);
739 *(data
++) = COLOR(x
);
744 COLOR_RR(lefty
, (&left
));
745 COLOR_RR(righty
, (&right
));
747 SETUP(x
, (&left
), (&right
), w
);
749 for (x
= w
- 1; x
> 0; --x
) { /* 0 -> w-1 */
750 *(data
++) = COLOR(x
);
757 static void gradient_pyramid(RrSurface
*sf
, gint w
, gint h
)
759 RrPixel32
*ldata
, *rdata
;
763 gint x
, y
, halfw
, halfh
, midx
, midy
;
769 extracorner
.r
= (sf
->primary
->r
+ sf
->secondary
->r
) / 2;
770 extracorner
.g
= (sf
->primary
->g
+ sf
->secondary
->g
) / 2;
771 extracorner
.b
= (sf
->primary
->b
+ sf
->secondary
->b
) / 2;
775 midx
= w
- halfw
- halfw
; /* 0 or 1, depending if w is even or odd */
776 midy
= h
- halfh
- halfh
; /* 0 or 1, depending if h is even or odd */
778 SETUP(lefty
, sf
->primary
, (&extracorner
), halfh
+ midy
);
779 SETUP(righty
, (&extracorner
), sf
->secondary
, halfh
+ midy
);
783 it is faster to draw both top quarters together than to draw one and
784 then copy it over to the other side.
787 ldata
= sf
->pixel_data
;
788 rdata
= ldata
+ w
- 1;
789 for (y
= halfh
+ midy
; y
> 0; --y
) { /* 0 -> (h+1)/2 */
792 COLOR_RR(lefty
, (&left
));
793 COLOR_RR(righty
, (&right
));
795 SETUP(x
, (&left
), (&right
), halfw
+ midx
);
797 for (x
= halfw
+ midx
- 1; x
> 0; --x
) { /* 0 -> (w+1)/2 */
799 *(ldata
++) = *(rdata
--) = c
;
806 rdata
+= halfw
- 1 + midx
+ w
;
812 /* copy the top half into the bottom half, mirroring it, so we can only
813 copy one row at a time
815 it is faster, to move the writing pointer forward, and the reading
818 this is the current code, moving the write pointer forward and read
820 41.78 4.26 1.78 504 3.53 3.53 gradient_pyramid2
821 this is the opposite, moving the read pointer forward and the write
823 42.27 4.40 1.86 504 3.69 3.69 gradient_pyramid2
826 ldata
= sf
->pixel_data
+ (halfh
- 1) * w
;
827 cp
= ldata
+ (midy
+ 1) * w
;
828 for (y
= halfh
; y
> 0; --y
) {
829 memcpy(cp
, ldata
, w
* sizeof(RrPixel32
));