]> icculus.org git repositories - dana/openbox.git/blob - render/gradient.c
patch from thorsten vollmer to fix bug #2506, interlaces and bevels not drawing correctly
[dana/openbox.git] / 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) 2003        Ben Jansens
5    Copyright (c) 2003        Derek Foreman
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    See the COPYING file for a copy of the GNU General Public License.
18 */
19
20 #include "render.h"
21 #include "gradient.h"
22 #include "color.h"
23 #include <glib.h>
24
25 static void highlight(RrPixel32 *x, RrPixel32 *y, gboolean raised);
26 static void gradient_solid(RrAppearance *l, gint w, gint h);
27 static void gradient_split(RrAppearance *a, gint w, gint h);
28 static void gradient_vertical(RrSurface *sf, gint w, gint h);
29 static void gradient_horizontal(RrSurface *sf, gint w, gint h);
30 static void gradient_osx(RrSurface *sf, gint w, gint h);
31 static void gradient_diagonal(RrSurface *sf, gint w, gint h);
32 static void gradient_crossdiagonal(RrSurface *sf, gint w, gint h);
33 static void gradient_pyramid(RrSurface *sf, gint inw, gint inh);
34
35 void RrRender(RrAppearance *a, gint w, gint h)
36 {
37     RrPixel32 *data = a->surface.pixel_data;
38     RrPixel32 current;
39     guint r,g,b;
40     gint off, x;
41
42     switch (a->surface.grad) {
43     case RR_SURFACE_SOLID:
44         gradient_solid(a, w, h);
45         break;
46     case RR_SURFACE_SPLIT:
47         gradient_split(a, w, h);
48         break;
49     case RR_SURFACE_VERTICAL:
50         gradient_vertical(&a->surface, w, h);
51         break;
52     case RR_SURFACE_HORIZONTAL:
53         gradient_horizontal(&a->surface, w, h);
54         break;
55     case RR_SURFACE_OSX:
56         gradient_osx(&a->surface, w, h);
57         break;
58     case RR_SURFACE_DIAGONAL:
59         gradient_diagonal(&a->surface, w, h);
60         break;
61     case RR_SURFACE_CROSS_DIAGONAL:
62         gradient_crossdiagonal(&a->surface, w, h);
63         break;
64     case RR_SURFACE_PYRAMID:
65         gradient_pyramid(&a->surface, w, h);
66         break;
67     default:
68         g_assert_not_reached(); /* unhandled gradient */
69         return;
70     }
71   
72     if (a->surface.interlaced) {
73         gint i;
74         RrPixel32 *p;
75
76         r = a->surface.interlace_color->r;
77         g = a->surface.interlace_color->g;
78         b = a->surface.interlace_color->b;
79         current = (r << RrDefaultRedOffset)
80             + (g << RrDefaultGreenOffset)
81             + (b << RrDefaultBlueOffset);
82         p = data;
83         for (i = 0; i < h; i += 2, p += w)
84             for (x = 0; x < w; ++x, ++p)
85                 *p = current;
86     }
87
88     if (a->surface.relief == RR_RELIEF_FLAT && a->surface.border) {
89         r = a->surface.border_color->r;
90         g = a->surface.border_color->g;
91         b = a->surface.border_color->b;
92         current = (r << RrDefaultRedOffset)
93             + (g << RrDefaultGreenOffset)
94             + (b << RrDefaultBlueOffset);
95         for (off = 0, x = 0; x < w; ++x, off++) {
96             *(data + off) = current;
97             *(data + off + ((h-1) * w)) = current;
98         }
99         for (off = 0, x = 0; x < h; ++x, off++) {
100             *(data + (off * w)) = current;
101             *(data + (off * w) + w - 1) = current;
102         }
103     }
104
105     if (a->surface.relief != RR_RELIEF_FLAT) {
106         if (a->surface.bevel == RR_BEVEL_1) {
107             for (off = 1, x = 1; x < w - 1; ++x, off++)
108                 highlight(data + off,
109                           data + off + (h-1) * w,
110                           a->surface.relief==RR_RELIEF_RAISED);
111             for (off = 0, x = 0; x < h; ++x, off++)
112                 highlight(data + off * w,
113                           data + off * w + w - 1,
114                           a->surface.relief==RR_RELIEF_RAISED);
115         }
116
117         if (a->surface.bevel == RR_BEVEL_2) {
118             for (off = 2, x = 2; x < w - 2; ++x, off++)
119                 highlight(data + off + w,
120                           data + off + (h-2) * w,
121                           a->surface.relief==RR_RELIEF_RAISED);
122             for (off = 1, x = 1; x < h-1; ++x, off++)
123                 highlight(data + off * w + 1,
124                           data + off * w + w - 2,
125                           a->surface.relief==RR_RELIEF_RAISED);
126         }
127     }
128 }
129
130 static void highlight(RrPixel32 *x, RrPixel32 *y, gboolean raised)
131 {
132     gint r, g, b;
133
134     RrPixel32 *up, *down;
135     if (raised) {
136         up = x;
137         down = y;
138     } else {
139         up = y;
140         down = x;
141     }
142     r = (*up >> RrDefaultRedOffset) & 0xFF;
143     r += r >> 1;
144     g = (*up >> RrDefaultGreenOffset) & 0xFF;
145     g += g >> 1;
146     b = (*up >> RrDefaultBlueOffset) & 0xFF;
147     b += b >> 1;
148     if (r > 0xFF) r = 0xFF;
149     if (g > 0xFF) g = 0xFF;
150     if (b > 0xFF) b = 0xFF;
151     *up = (r << RrDefaultRedOffset) + (g << RrDefaultGreenOffset)
152         + (b << RrDefaultBlueOffset);
153   
154     r = (*down >> RrDefaultRedOffset) & 0xFF;
155     r = (r >> 1) + (r >> 2);
156     g = (*down >> RrDefaultGreenOffset) & 0xFF;
157     g = (g >> 1) + (g >> 2);
158     b = (*down >> RrDefaultBlueOffset) & 0xFF;
159     b = (b >> 1) + (b >> 2);
160     *down = (r << RrDefaultRedOffset) + (g << RrDefaultGreenOffset)
161         + (b << RrDefaultBlueOffset);
162 }
163
164 static void create_bevel_colors(RrAppearance *l)
165 {
166     gint r, g, b;
167
168     /* light color */
169     r = l->surface.primary->r;
170     r += r >> 1;
171     g = l->surface.primary->g;
172     g += g >> 1;
173     b = l->surface.primary->b;
174     b += b >> 1;
175     if (r > 0xFF) r = 0xFF;
176     if (g > 0xFF) g = 0xFF;
177     if (b > 0xFF) b = 0xFF;
178     g_assert(!l->surface.bevel_light);
179     l->surface.bevel_light = RrColorNew(l->inst, r, g, b);
180
181     /* dark color */
182     r = l->surface.primary->r;
183     r = (r >> 1) + (r >> 2);
184     g = l->surface.primary->g;
185     g = (g >> 1) + (g >> 2);
186     b = l->surface.primary->b;
187     b = (b >> 1) + (b >> 2);
188     g_assert(!l->surface.bevel_dark);
189     l->surface.bevel_dark = RrColorNew(l->inst, r, g, b);
190 }
191
192 static void gradient_solid(RrAppearance *l, gint w, gint h) 
193 {
194     gint i;
195     RrPixel32 pix;
196     RrPixel32 *data = l->surface.pixel_data;
197     RrSurface *sp = &l->surface;
198     gint left = 0, top = 0, right = w - 1, bottom = h - 1;
199
200     pix = (sp->primary->r << RrDefaultRedOffset)
201         + (sp->primary->g << RrDefaultGreenOffset)
202         + (sp->primary->b << RrDefaultBlueOffset);
203
204     for (i = 0; i < w * h; i++)
205         *data++ = pix;
206
207     if (sp->interlaced)
208         return;
209
210     XFillRectangle(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->primary),
211                    0, 0, w, h);
212
213     switch (sp->relief) {
214     case RR_RELIEF_RAISED:
215         if (!sp->bevel_dark)
216             create_bevel_colors(l);
217
218         switch (sp->bevel) {
219         case RR_BEVEL_1:
220             XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
221                       left, bottom, right, bottom);
222             XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
223                       right, bottom, right, top);
224                 
225             XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
226                       left, top, right, top);
227             XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
228                       left, bottom, left, top);
229             break;
230         case RR_BEVEL_2:
231             XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
232                       left + 2, bottom - 1, right - 2, bottom - 1);
233             XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
234                       right - 1, bottom - 1, right - 1, top + 1);
235
236             XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
237                       left + 2, top + 1, right - 2, top + 1);
238             XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
239                       left + 1, bottom - 1, left + 1, top + 1);
240             break;
241         default:
242             g_assert_not_reached(); /* unhandled BevelType */
243         }
244         break;
245     case RR_RELIEF_SUNKEN:
246         if (!sp->bevel_dark)
247             create_bevel_colors(l);
248
249         switch (sp->bevel) {
250         case RR_BEVEL_1:
251             XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
252                       left, bottom, right, bottom);
253             XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
254                       right, bottom, right, top);
255       
256             XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
257                       left, top, right, top);
258             XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
259                       left, bottom, left, top);
260             break;
261         case RR_BEVEL_2:
262             XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
263                       left + 2, bottom - 1, right - 2, bottom - 1);
264             XDrawLine(RrDisplay(l->inst), l->pixmap,RrColorGC(sp->bevel_light),
265                       right - 1, bottom - 1, right - 1, top + 1);
266
267             XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
268                       left + 2, top + 1, right - 2, top + 1);
269             XDrawLine(RrDisplay(l->inst), l->pixmap, RrColorGC(sp->bevel_dark),
270                       left + 1, bottom - 1, left + 1, top + 1);
271             break;
272         default:
273             g_assert_not_reached(); /* unhandled BevelType */
274         }
275         break;
276     case RR_RELIEF_FLAT:
277         if (sp->border) {
278             XDrawRectangle(RrDisplay(l->inst), l->pixmap,
279                            RrColorGC(sp->border_color),
280                            left, top, right, bottom);
281         }
282         break;
283     default:  
284         g_assert_not_reached(); /* unhandled ReliefType */
285     }
286 }
287
288 /* * * * * * * * * * * * * * GRADIENT MAGIC WOOT * * * * * * * * * * * * * * */
289
290 #define VARS(x)                                                     \
291     guint color##x[3];                                       \
292     gint len##x, cdelta##x[3], error##x[3] = { 0, 0, 0 }, inc##x[3]; \
293     gboolean bigslope##x[3] /* color slope > 1 */
294
295 #define SETUP(x, from, to, w)         \
296     len##x = w;                       \
297                                       \
298     color##x[0] = from->r;            \
299     color##x[1] = from->g;            \
300     color##x[2] = from->b;            \
301                                       \
302     cdelta##x[0] = to->r - from->r;   \
303     cdelta##x[1] = to->g - from->g;   \
304     cdelta##x[2] = to->b - from->b;   \
305                                       \
306     if (cdelta##x[0] < 0) {           \
307         cdelta##x[0] = -cdelta##x[0]; \
308         inc##x[0] = -1;               \
309     } else                            \
310         inc##x[0] = 1;                \
311     if (cdelta##x[1] < 0) {           \
312         cdelta##x[1] = -cdelta##x[1]; \
313         inc##x[1] = -1;               \
314     } else                            \
315         inc##x[1] = 1;                \
316     if (cdelta##x[2] < 0) {           \
317         cdelta##x[2] = -cdelta##x[2]; \
318         inc##x[2] = -1;               \
319     } else                            \
320         inc##x[2] = 1;                \
321     bigslope##x[0] = cdelta##x[0] > w;\
322     bigslope##x[1] = cdelta##x[1] > w;\
323     bigslope##x[2] = cdelta##x[2] > w
324
325 #define COLOR_RR(x, c)                       \
326     c->r = color##x[0];                      \
327     c->g = color##x[1];                      \
328     c->b = color##x[2]
329
330 #define COLOR(x)                             \
331     ((color##x[0] << RrDefaultRedOffset) +   \
332      (color##x[1] << RrDefaultGreenOffset) + \
333      (color##x[2] << RrDefaultBlueOffset))
334
335 #define INCREMENT(x, i) \
336     (inc##x[i])
337
338 #define NEXT(x)                                           \
339 {                                                         \
340     gint i;                                                \
341     for (i = 2; i >= 0; --i) {                            \
342         if (!cdelta##x[i]) continue;                      \
343                                                           \
344         if (!bigslope##x[i]) {                            \
345             /* Y (color) is dependant on X */             \
346             error##x[i] += cdelta##x[i];                  \
347             if ((error##x[i] << 1) >= len##x) {           \
348                 color##x[i] += INCREMENT(x, i);           \
349                 error##x[i] -= len##x;                    \
350             }                                             \
351         } else {                                          \
352             /* X is dependant on Y (color) */             \
353             while (1) {                                   \
354                 color##x[i] += INCREMENT(x, i);           \
355                 error##x[i] += len##x;                    \
356                 if ((error##x[i] << 1) >= cdelta##x[i]) { \
357                     error##x[i] -= cdelta##x[i];          \
358                     break;                                \
359                 }                                         \
360             }                                             \
361         }                                                 \
362     }                                                     \
363 }
364
365 static void gradient_split(RrAppearance *a, gint w, gint h)
366 {
367     gint x, y1, y3, r, g, b;
368     RrSurface *sf = &a->surface;
369     RrPixel32 *data = sf->pixel_data;
370     RrPixel32 current;
371     RrColor *primary_light, *secondary_light;
372
373     r = sf->primary->r;
374     r += r >> 2;
375     g = sf->primary->g;
376     g += g >> 2;
377     b = sf->primary->b;
378     b += b >> 2;
379     if (r > 0xFF) r = 0xFF;
380     if (g > 0xFF) g = 0xFF;
381     if (b > 0xFF) b = 0xFF;
382       primary_light = RrColorNew(a->inst, r, g, b);
383
384     r = sf->secondary->r;
385     r += r >> 4;
386     g = sf->secondary->g;
387     g += g >> 4;
388     b = sf->secondary->b;
389     b += b >> 4;
390     if (r > 0xFF) r = 0xFF;
391     if (g > 0xFF) g = 0xFF;
392     if (b > 0xFF) b = 0xFF;
393     secondary_light = RrColorNew(a->inst, r, g, b);
394
395     VARS(y1);
396     SETUP(y1, primary_light, sf->primary, (h / 2) -1);
397   
398     VARS(y3);
399     SETUP(y3, sf->secondary, secondary_light,  (h / 2) -1);
400
401     for (y1 = h - 1; y1 > (h / 2) -1; --y1) {  /* 0 -> h-1 */
402         current = COLOR(y1);
403         for (x = w - 1; x >= 0; --x)  /* 0 -> w */
404             *(data++) = current;
405
406         NEXT(y1);
407     }
408
409     
410     for (y3 = (h / 2) - 1; y3 > 0; --y3) {
411         current = COLOR(y3);
412         for (x = w - 1; x >= 0; --x)
413             *(data++) = current;
414
415         NEXT(y3);
416     }
417
418     current = COLOR(y3);
419     for (x = w - 1; x >= 0; --x)  /* 0 -> w */
420         *(data++) = current;
421
422     RrColorFree(primary_light);
423     RrColorFree(secondary_light);
424 }
425
426 static void gradient_horizontal(RrSurface *sf, gint w, gint h)
427 {
428     gint x, y;
429     RrPixel32 *data = sf->pixel_data, *datav;
430     RrPixel32 current;
431
432     VARS(x);
433     SETUP(x, sf->primary, sf->secondary, w);
434
435     for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
436         current = COLOR(x);
437         datav = data;
438         for (y = h - 1; y >= 0; --y) {  /* 0 -> h */
439             *datav = current;
440             datav += w;
441         }
442         ++data;
443
444         NEXT(x);
445     }
446     current = COLOR(x);
447     for (y = h - 1; y >= 0; --y)  /* 0 -> h */
448         *(data + y * w) = current;
449 }
450
451 static void gradient_osx(RrSurface *sf, gint w, gint h)
452 {
453     gint x, y;
454     RrPixel32 *data = sf->pixel_data, *datav;
455     RrPixel32 current;
456
457     VARS(x);
458     SETUP(x, sf->primary, sf->secondary, w/2);
459
460     for (x = w - 1; x > w/2-1; --x) {  /* 0 -> w-1 */
461         current = COLOR(x);
462         datav = data;
463         for (y = h - 1; y >= 0; --y) {  /* 0 -> h */
464             *datav = current;
465             datav += w;
466         }
467         ++data;
468
469         NEXT(x);
470     }
471     SETUP(x, sf->secondary, sf->primary, w/2);
472     for (x = w/2 - 1; x > 0; --x) {  /* 0 -> w-1 */
473         current = COLOR(x);
474         datav = data;
475         for (y = h - 1; y >= 0; --y) {  /* 0 -> h */
476             *datav = current;
477             datav += w;
478         }
479         ++data;
480
481         NEXT(x);
482     }
483     current = COLOR(x);
484     for (y = h - 1; y >= 0; --y)  /* 0 -> h */
485         *(data + y * w) = current;
486 }
487
488 static void gradient_vertical(RrSurface *sf, gint w, gint h)
489 {
490     gint x, y;
491     RrPixel32 *data = sf->pixel_data;
492     RrPixel32 current;
493
494     VARS(y);
495     SETUP(y, sf->primary, sf->secondary, h);
496
497     for (y = h - 1; y > 0; --y) {  /* 0 -> h-1 */
498         current = COLOR(y);
499         for (x = w - 1; x >= 0; --x)  /* 0 -> w */
500             *(data++) = current;
501
502         NEXT(y);
503     }
504     current = COLOR(y);
505     for (x = w - 1; x >= 0; --x)  /* 0 -> w */
506         *(data++) = current;
507 }
508
509
510 static void gradient_diagonal(RrSurface *sf, gint w, gint h)
511 {
512     gint x, y;
513     RrPixel32 *data = sf->pixel_data;
514     RrColor left, right;
515     RrColor extracorner;
516
517     VARS(lefty);
518     VARS(righty);
519     VARS(x);
520
521     extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
522     extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
523     extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
524
525     SETUP(lefty, sf->primary, (&extracorner), h);
526     SETUP(righty, (&extracorner), sf->secondary, h);
527
528     for (y = h - 1; y > 0; --y) {  /* 0 -> h-1 */
529         COLOR_RR(lefty, (&left));
530         COLOR_RR(righty, (&right));
531
532         SETUP(x, (&left), (&right), w);
533
534         for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
535             *(data++) = COLOR(x);
536
537             NEXT(x);
538         }
539         *(data++) = COLOR(x);
540
541         NEXT(lefty);
542         NEXT(righty);
543     }
544     COLOR_RR(lefty, (&left));
545     COLOR_RR(righty, (&right));
546
547     SETUP(x, (&left), (&right), w);
548
549     for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
550         *(data++) = COLOR(x);
551         
552         NEXT(x);
553     }
554     *data = COLOR(x);
555 }
556
557 static void gradient_crossdiagonal(RrSurface *sf, gint w, gint h)
558 {
559     gint x, y;
560     RrPixel32 *data = sf->pixel_data;
561     RrColor left, right;
562     RrColor extracorner;
563
564     VARS(lefty);
565     VARS(righty);
566     VARS(x);
567
568     extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
569     extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
570     extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
571
572     SETUP(lefty, (&extracorner), sf->secondary, h);
573     SETUP(righty, sf->primary, (&extracorner), h);
574
575     for (y = h - 1; y > 0; --y) {  /* 0 -> h-1 */
576         COLOR_RR(lefty, (&left));
577         COLOR_RR(righty, (&right));
578
579         SETUP(x, (&left), (&right), w);
580
581         for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
582             *(data++) = COLOR(x);
583
584             NEXT(x);
585         }
586         *(data++) = COLOR(x);
587
588         NEXT(lefty);
589         NEXT(righty);
590     }
591     COLOR_RR(lefty, (&left));
592     COLOR_RR(righty, (&right));
593
594     SETUP(x, (&left), (&right), w);
595
596     for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
597         *(data++) = COLOR(x);
598         
599         NEXT(x);
600     }
601     *data = COLOR(x);
602 }
603
604 static void gradient_pyramid(RrSurface *sf, gint inw, gint inh)
605 {
606     gint x, y, w = (inw >> 1) + 1, h = (inh >> 1) + 1;
607     RrPixel32 *data = sf->pixel_data;
608     RrPixel32 *end = data + inw*inh - 1;
609     RrPixel32 current;
610     RrColor left, right;
611     RrColor extracorner;
612
613     VARS(lefty);
614     VARS(righty);
615     VARS(x);
616
617     extracorner.r = (sf->primary->r + sf->secondary->r) / 2;
618     extracorner.g = (sf->primary->g + sf->secondary->g) / 2;
619     extracorner.b = (sf->primary->b + sf->secondary->b) / 2;
620
621     SETUP(lefty, (&extracorner), sf->secondary, h);
622     SETUP(righty, sf->primary, (&extracorner), h);
623
624     for (y = h - 1; y > 0; --y) {  /* 0 -> h-1 */
625         COLOR_RR(lefty, (&left));
626         COLOR_RR(righty, (&right));
627
628         SETUP(x, (&left), (&right), w);
629
630         for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
631             current = COLOR(x);
632             *(data+x) = current;
633             *(data+inw-x) = current;
634             *(end-x) = current;
635             *(end-(inw-x)) = current;
636
637             NEXT(x);
638         }
639         current = COLOR(x);
640         *(data+x) = current;
641         *(data+inw-x) = current;
642         *(end-x) = current;
643         *(end-(inw-x)) = current;
644
645         data+=inw;
646         end-=inw;
647
648         NEXT(lefty);
649         NEXT(righty);
650     }
651     COLOR_RR(lefty, (&left));
652     COLOR_RR(righty, (&right));
653
654     SETUP(x, (&left), (&right), w);
655
656     for (x = w - 1; x > 0; --x) {  /* 0 -> w-1 */
657         current = COLOR(x);
658         *(data+x) = current;
659         *(data+inw-x) = current;
660         *(end-x) = current;
661         *(end-(inw-x)) = current;
662         
663         NEXT(x);
664     }
665     current = COLOR(x);
666     *(data+x) = current;
667     *(data+inw-x) = current;
668     *(end-x) = current;
669     *(end-(inw-x)) = current;
670 }
671