]> Dogcows Code - chaz/openbox/blob - render/gradient.c
Remove double newlines.
[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 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 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 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 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, i;
272
273 g_assert (a->surface.parent);
274 g_assert (a->surface.parent->w);
275
276 sw = a->surface.parent->w;
277 sh = a->surface.parent->h;
278
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 &&
287 sw == w && sh == h)
288 {
289 RrSurface old = a->surface;
290 a->surface = a->surface.parent->surface;
291
292 /* turn these off for the parent */
293 a->surface.relief = RR_RELIEF_FLAT;
294 a->surface.border = FALSE;
295
296 a->surface.pixel_data = old.pixel_data;
297
298 RrRender(a, w, h);
299 a->surface = old;
300 } else {
301 source = (a->surface.parent->surface.pixel_data +
302 a->surface.parentx + sw * a->surface.parenty);
303 dest = a->surface.pixel_data;
304
305 if (a->surface.parentx + w > sw) {
306 partial_w = sw - a->surface.parentx;
307 } else partial_w = w;
308
309 if (a->surface.parenty + h > sh) {
310 partial_h = sh - a->surface.parenty;
311 } else partial_h = h;
312
313 for (i = 0; i < partial_h; i++, source += sw, dest += w) {
314 memcpy(dest, source, partial_w * sizeof(RrPixel32));
315 }
316 }
317 }
318
319 static void gradient_solid(RrAppearance *l, gint w, gint h)
320 {
321 gint i;
322 RrPixel32 pix;
323 RrPixel32 *data = l->surface.pixel_data;
324 RrSurface *sp = &l->surface;
325 gint left = 0, top = 0, right = w - 1, bottom = h - 1;
326
327 pix = (sp->primary->r << RrDefaultRedOffset)
328 + (sp->primary->g << RrDefaultGreenOffset)
329 + (sp->primary->b << RrDefaultBlueOffset);
330
331 for (i = 0; i < w * h; i++)
332 *data++ = pix;
333
334 if (sp->interlaced)
335 return;
336
337 XFillRectangle(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->primary),
338 0, 0, w, h);
339
340 switch (sp->relief) {
341 case RR_RELIEF_RAISED:
342 if (!sp->bevel_dark)
343 create_bevel_colors(l);
344
345 switch (sp->bevel) {
346 case RR_BEVEL_1:
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);
351
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);
356 break;
357 case RR_BEVEL_2:
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);
362
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);
367 break;
368 default:
369 g_assert_not_reached(); /* unhandled BevelType */
370 }
371 break;
372 case RR_RELIEF_SUNKEN:
373 if (!sp->bevel_dark)
374 create_bevel_colors(l);
375
376 switch (sp->bevel) {
377 case RR_BEVEL_1:
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);
382
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);
387 break;
388 case RR_BEVEL_2:
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);
393
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);
398 break;
399 default:
400 g_assert_not_reached(); /* unhandled BevelType */
401 }
402 break;
403 case RR_RELIEF_FLAT:
404 if (sp->border) {
405 XDrawRectangle(RrDisplay(l->inst), l->pixmap,
406 RrColorGC(sp->border_color),
407 left, top, right, bottom);
408 }
409 break;
410 default:
411 g_assert_not_reached(); /* unhandled ReliefType */
412 }
413 }
414
415 /* * * * * * * * * * * * * * GRADIENT MAGIC WOOT * * * * * * * * * * * * * * */
416
417 #define VARS(x) \
418 guint color##x[3]; \
419 gint len##x, cdelta##x[3], error##x[3] = { 0, 0, 0 }, inc##x[3]; \
420 gboolean bigslope##x[3] /* color slope > 1 */
421
422 #define SETUP(x, from, to, w) \
423 len##x = w; \
424 \
425 color##x[0] = from->r; \
426 color##x[1] = from->g; \
427 color##x[2] = from->b; \
428 \
429 cdelta##x[0] = to->r - from->r; \
430 cdelta##x[1] = to->g - from->g; \
431 cdelta##x[2] = to->b - from->b; \
432 \
433 if (cdelta##x[0] < 0) { \
434 cdelta##x[0] = -cdelta##x[0]; \
435 inc##x[0] = -1; \
436 } else \
437 inc##x[0] = 1; \
438 if (cdelta##x[1] < 0) { \
439 cdelta##x[1] = -cdelta##x[1]; \
440 inc##x[1] = -1; \
441 } else \
442 inc##x[1] = 1; \
443 if (cdelta##x[2] < 0) { \
444 cdelta##x[2] = -cdelta##x[2]; \
445 inc##x[2] = -1; \
446 } else \
447 inc##x[2] = 1; \
448 bigslope##x[0] = cdelta##x[0] > w;\
449 bigslope##x[1] = cdelta##x[1] > w;\
450 bigslope##x[2] = cdelta##x[2] > w
451
452 #define COLOR_RR(x, c) \
453 c->r = color##x[0]; \
454 c->g = color##x[1]; \
455 c->b = color##x[2]
456
457 #define COLOR(x) \
458 ((color##x[0] << RrDefaultRedOffset) + \
459 (color##x[1] << RrDefaultGreenOffset) + \
460 (color##x[2] << RrDefaultBlueOffset))
461
462 #define INCREMENT(x, i) \
463 (inc##x[i])
464
465 #define NEXT(x) \
466 { \
467 gint i; \
468 for (i = 2; i >= 0; --i) { \
469 if (!cdelta##x[i]) continue; \
470 \
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; \
477 } \
478 } else { \
479 /* X is dependant on Y (color) */ \
480 while (1) { \
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]; \
485 break; \
486 } \
487 } \
488 } \
489 } \
490 }
491
492 static void gradient_splitvertical(RrAppearance *a, gint w, gint h)
493 {
494 gint y1, y2, y3;
495 RrSurface *sf = &a->surface;
496 RrPixel32 *data;
497 gint y1sz, y2sz, y3sz;
498
499 VARS(y1);
500 VARS(y2);
501 VARS(y3);
502
503 /* if h <= 5, then a 0 or 1px middle gradient.
504 if h > 5, then always a 1px middle gradient.
505 */
506 if (h <= 5) {
507 y1sz = MAX(h/2, 0);
508 y2sz = (h < 3 ? 0 : h % 2);
509 y3sz = MAX(h/2, 1);
510 }
511 else {
512 y1sz = h/2 - (1 - (h % 2));
513 y2sz = 1;
514 y3sz = h/2;
515 }
516
517 SETUP(y1, sf->split_primary, sf->primary, y1sz);
518 if (y2sz) {
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 */
522 }
523 SETUP(y3, sf->secondary, sf->split_secondary, y3sz);
524
525 /* find the color for the first pixel of each row first */
526 data = sf->pixel_data;
527
528 for (y1 = y1sz-1; y1 > 0; --y1) {
529 *data = COLOR(y1);
530 data += w;
531 NEXT(y1);
532 }
533 *data = COLOR(y1);
534 data += w;
535 for (y2 = y2sz-1; y2 > 0; --y2) {
536 *data = COLOR(y2);
537 data += w;
538 NEXT(y2);
539 }
540 *data = COLOR(y2);
541 data += w;
542 for (y3 = y3sz-1; y3 > 0; --y3) {
543 *data = COLOR(y3);
544 data += w;
545 NEXT(y3);
546 }
547 *data = COLOR(y3);
548
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);
553 data += w;
554 }
555 }
556
557 static void gradient_horizontal(RrSurface *sf, gint w, gint h)
558 {
559 gint x, y, cpbytes;
560 RrPixel32 *data = sf->pixel_data, *datav;
561 gchar *datac;
562
563 VARS(x);
564 SETUP(x, sf->primary, sf->secondary, w);
565
566 /* set the color values for the first row */
567 datav = data;
568 for (x = w - 1; x > 0; --x) { /* 0 -> w - 1 */
569 *datav = COLOR(x);
570 ++datav;
571 NEXT(x);
572 }
573 *datav = COLOR(x);
574 ++datav;
575
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);
581 y -= cpbytes;
582 datac += cpbytes;
583 cpbytes <<= 1;
584 if (cpbytes > y)
585 cpbytes = y;
586 }
587 }
588
589 static void gradient_mirrorhorizontal(RrSurface *sf, gint w, gint h)
590 {
591 gint x, y, half1, half2, cpbytes;
592 RrPixel32 *data = sf->pixel_data, *datav;
593 gchar *datac;
594
595 VARS(x);
596
597 half1 = (w + 1) / 2;
598 half2 = w / 2;
599
600 /* set the color values for the first row */
601
602 SETUP(x, sf->primary, sf->secondary, half1);
603 datav = data;
604 for (x = half1 - 1; x > 0; --x) { /* 0 -> half1 - 1 */
605 *datav = COLOR(x);
606 ++datav;
607 NEXT(x);
608 }
609 *datav = COLOR(x);
610 ++datav;
611
612 if (half2 > 0) {
613 SETUP(x, sf->secondary, sf->primary, half2);
614 for (x = half2 - 1; x > 0; --x) { /* 0 -> half2 - 1 */
615 *datav = COLOR(x);
616 ++datav;
617 NEXT(x);
618 }
619 *datav = COLOR(x);
620 ++datav;
621 }
622
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);
628 y -= cpbytes;
629 datac += cpbytes;
630 cpbytes <<= 1;
631 if (cpbytes > y)
632 cpbytes = y;
633 }
634 }
635
636 static void gradient_vertical(RrSurface *sf, gint w, gint h)
637 {
638 gint y;
639 RrPixel32 *data;
640
641 VARS(y);
642 SETUP(y, sf->primary, sf->secondary, h);
643
644 /* find the color for the first pixel of each row first */
645 data = sf->pixel_data;
646
647 for (y = h - 1; y > 0; --y) { /* 0 -> h-1 */
648 *data = COLOR(y);
649 data += w;
650 NEXT(y);
651 }
652 *data = COLOR(y);
653
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);
658 data += w;
659 }
660 }
661
662 static void gradient_diagonal(RrSurface *sf, gint w, gint h)
663 {
664 gint x, y;
665 RrPixel32 *data = sf->pixel_data;
666 RrColor left, right;
667 RrColor extracorner;
668
669 VARS(lefty);
670 VARS(righty);
671 VARS(x);
672
673 extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
674 extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
675 extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
676
677 SETUP(lefty, sf->primary, (&extracorner), h);
678 SETUP(righty, (&extracorner), sf->secondary, h);
679
680 for (y = h - 1; y > 0; --y) { /* 0 -> h-1 */
681 COLOR_RR(lefty, (&left));
682 COLOR_RR(righty, (&right));
683
684 SETUP(x, (&left), (&right), w);
685
686 for (x = w - 1; x > 0; --x) { /* 0 -> w-1 */
687 *(data++) = COLOR(x);
688
689 NEXT(x);
690 }
691 *(data++) = COLOR(x);
692
693 NEXT(lefty);
694 NEXT(righty);
695 }
696 COLOR_RR(lefty, (&left));
697 COLOR_RR(righty, (&right));
698
699 SETUP(x, (&left), (&right), w);
700
701 for (x = w - 1; x > 0; --x) { /* 0 -> w-1 */
702 *(data++) = COLOR(x);
703
704 NEXT(x);
705 }
706 *data = COLOR(x);
707 }
708
709 static void gradient_crossdiagonal(RrSurface *sf, gint w, gint h)
710 {
711 gint x, y;
712 RrPixel32 *data = sf->pixel_data;
713 RrColor left, right;
714 RrColor extracorner;
715
716 VARS(lefty);
717 VARS(righty);
718 VARS(x);
719
720 extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
721 extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
722 extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
723
724 SETUP(lefty, (&extracorner), sf->secondary, h);
725 SETUP(righty, sf->primary, (&extracorner), h);
726
727 for (y = h - 1; y > 0; --y) { /* 0 -> h-1 */
728 COLOR_RR(lefty, (&left));
729 COLOR_RR(righty, (&right));
730
731 SETUP(x, (&left), (&right), w);
732
733 for (x = w - 1; x > 0; --x) { /* 0 -> w-1 */
734 *(data++) = COLOR(x);
735
736 NEXT(x);
737 }
738 *(data++) = COLOR(x);
739
740 NEXT(lefty);
741 NEXT(righty);
742 }
743 COLOR_RR(lefty, (&left));
744 COLOR_RR(righty, (&right));
745
746 SETUP(x, (&left), (&right), w);
747
748 for (x = w - 1; x > 0; --x) { /* 0 -> w-1 */
749 *(data++) = COLOR(x);
750
751 NEXT(x);
752 }
753 *data = COLOR(x);
754 }
755
756 static void gradient_pyramid(RrSurface *sf, gint w, gint h)
757 {
758 RrPixel32 *ldata, *rdata;
759 RrPixel32 *cp;
760 RrColor left, right;
761 RrColor extracorner;
762 gint x, y, halfw, halfh, midx, midy;
763
764 VARS(lefty);
765 VARS(righty);
766 VARS(x);
767
768 extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
769 extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
770 extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
771
772 halfw = w >> 1;
773 halfh = h >> 1;
774 midx = w - halfw - halfw; /* 0 or 1, depending if w is even or odd */
775 midy = h - halfh - halfh; /* 0 or 1, depending if h is even or odd */
776
777 SETUP(lefty, sf->primary, (&extracorner), halfh + midy);
778 SETUP(righty, (&extracorner), sf->secondary, halfh + midy);
779
780 /* draw the top half
781
782 it is faster to draw both top quarters together than to draw one and
783 then copy it over to the other side.
784 */
785
786 ldata = sf->pixel_data;
787 rdata = ldata + w - 1;
788 for (y = halfh + midy; y > 0; --y) { /* 0 -> (h+1)/2 */
789 RrPixel32 c;
790
791 COLOR_RR(lefty, (&left));
792 COLOR_RR(righty, (&right));
793
794 SETUP(x, (&left), (&right), halfw + midx);
795
796 for (x = halfw + midx - 1; x > 0; --x) { /* 0 -> (w+1)/2 */
797 c = COLOR(x);
798 *(ldata++) = *(rdata--) = c;
799
800 NEXT(x);
801 }
802 c = COLOR(x);
803 *ldata = *rdata = c;
804 ldata += halfw + 1;
805 rdata += halfw - 1 + midx + w;
806
807 NEXT(lefty);
808 NEXT(righty);
809 }
810
811 /* copy the top half into the bottom half, mirroring it, so we can only
812 copy one row at a time
813
814 it is faster, to move the writing pointer forward, and the reading
815 pointer backward
816
817 this is the current code, moving the write pointer forward and read
818 pointer backward
819 41.78 4.26 1.78 504 3.53 3.53 gradient_pyramid2
820 this is the opposite, moving the read pointer forward and the write
821 pointer backward
822 42.27 4.40 1.86 504 3.69 3.69 gradient_pyramid2
823
824 */
825 ldata = sf->pixel_data + (halfh - 1) * w;
826 cp = ldata + (midy + 1) * w;
827 for (y = halfh; y > 0; --y) {
828 memcpy(cp, ldata, w * sizeof(RrPixel32));
829 ldata -= w;
830 cp += w;
831 }
832 }
This page took 0.069141 seconds and 4 git commands to generate.