]> icculus.org git repositories - dana/openbox.git/blob - otk/image.cc
adding toolkit beginnings
[dana/openbox.git] / otk / image.cc
1 // -*- mode: C++; indent-tabs-mode: nil; -*-
2
3 #ifdef    HAVE_CONFIG_H
4 #  include "../config.h"
5 #endif // HAVE_CONFIG_H
6
7 #ifdef    HAVE_STDIO_H
8 #  include <stdio.h>
9 #endif // HAVE_STDIO_H
10
11 #include <algorithm>
12 using std::max;
13 using std::min;
14
15 #include "blackbox.hh"
16 #include "basedisplay.hh"
17 #include "gccache.hh"
18 #include "image.hh"
19 #include "texture.hh"
20
21
22 BImage::BImage(BImageControl *c, int w, int h) {
23   control = c;
24
25   width = (w > 0) ? w : 1;
26   height = (h > 0) ? h : 1;
27
28   red = new unsigned char[width * height];
29   green = new unsigned char[width * height];
30   blue = new unsigned char[width * height];
31
32   xtable = ytable = (unsigned int *) 0;
33
34   cpc = control->getColorsPerChannel();
35   cpccpc = cpc * cpc;
36
37   control->getColorTables(&red_table, &green_table, &blue_table,
38                           &red_offset, &green_offset, &blue_offset,
39                           &red_bits, &green_bits, &blue_bits);
40
41   if (control->getVisual()->c_class != TrueColor)
42     control->getXColorTable(&colors, &ncolors);
43 }
44
45
46 BImage::~BImage(void) {
47   delete [] red;
48   delete [] green;
49   delete [] blue;
50 }
51
52
53 Pixmap BImage::render(const BTexture &texture) {
54   if (texture.texture() & BTexture::Parent_Relative)
55     return ParentRelative;
56   else if (texture.texture() & BTexture::Solid)
57     return render_solid(texture);
58   else if (texture.texture() & BTexture::Gradient)
59     return render_gradient(texture);
60   return None;
61 }
62
63
64 Pixmap BImage::render_solid(const BTexture &texture) {
65   Pixmap pixmap = XCreatePixmap(control->getBaseDisplay()->getXDisplay(),
66                                 control->getDrawable(), width,
67                                 height, control->getDepth());
68   if (pixmap == None) {
69     fprintf(stderr, "BImage::render_solid: error creating pixmap\n");
70     return None;
71   }
72
73   Display *display = control->getBaseDisplay()->getXDisplay();
74
75   BPen pen(texture.color());
76   BPen penlight(texture.lightColor());
77   BPen penshadow(texture.shadowColor());
78
79   XFillRectangle(display, pixmap, pen.gc(), 0, 0, width, height);
80
81   if (texture.texture() & BTexture::Interlaced) {
82     BPen peninterlace(texture.colorTo());
83     for (unsigned int i = 0; i < height; i += 2)
84       XDrawLine(display, pixmap, peninterlace.gc(), 0, i, width, i);
85   }
86
87   int left = 0, top = 0, right = width - 1, bottom = height - 1;
88
89   if (texture.texture() & BTexture::Border) {
90     BPen penborder(texture.borderColor());
91     XDrawRectangle(display, pixmap, penborder.gc(),
92                    left, top, right, bottom);
93   }
94
95   if (texture.texture() & BTexture::Bevel1) {
96     if (texture.texture() & BTexture::Raised) {
97       XDrawLine(display, pixmap, penshadow.gc(),
98                 left, bottom, right, bottom);
99       XDrawLine(display, pixmap, penshadow.gc(),
100                 right, bottom, right, top);
101
102       XDrawLine(display, pixmap, penlight.gc(),
103                 left, top, right, top);
104       XDrawLine(display, pixmap, penlight.gc(),
105                 left, bottom, left, top);
106     } else if (texture.texture() & BTexture::Sunken) {
107       XDrawLine(display, pixmap, penlight.gc(),
108                 left, bottom, right, bottom);
109       XDrawLine(display, pixmap, penlight.gc(),
110                 right, bottom, right, top);
111
112       XDrawLine(display, pixmap, penshadow.gc(),
113                 left, top, right, top);
114       XDrawLine(display, pixmap, penshadow.gc(),
115                 left, bottom, left, top);
116     }
117   } else if (texture.texture() & BTexture::Bevel2) {
118     if (texture.texture() & BTexture::Raised) {
119       XDrawLine(display, pixmap, penshadow.gc(),
120                 left + 1, bottom - 2, right - 2, bottom - 2);
121       XDrawLine(display, pixmap, penshadow.gc(),
122                 right - 2, bottom - 2, right - 2, top + 1);
123
124       XDrawLine(display, pixmap, penlight.gc(),
125                 left + 1, top + 1, right - 2, top + 1);
126       XDrawLine(display, pixmap, penlight.gc(),
127                 left + 1, bottom - 2, left + 1, top + 1);
128     } else if (texture.texture() & BTexture::Sunken) {
129       XDrawLine(display, pixmap, penlight.gc(),
130                 left + 1, bottom - 2, right - 2, bottom - 2);
131       XDrawLine(display, pixmap, penlight.gc(),
132                 right - 2, bottom - 2, right - 2, top + 1);
133
134       XDrawLine(display, pixmap, penshadow.gc(),
135                 left + 1, top + 1, right - 2, top + 1);
136       XDrawLine(display, pixmap, penshadow.gc(),
137                 left + 1, bottom - 2, left + 1, top + 1);
138     }
139   }
140
141   return pixmap;
142 }
143
144
145 Pixmap BImage::render_gradient(const BTexture &texture) {
146   bool inverted = False;
147
148   interlaced = texture.texture() & BTexture::Interlaced;
149
150   if (texture.texture() & BTexture::Sunken) {
151     from = texture.colorTo();
152     to = texture.color();
153
154     if (! (texture.texture() & BTexture::Invert)) inverted = True;
155   } else {
156     from = texture.color();
157     to = texture.colorTo();
158
159     if (texture.texture() & BTexture::Invert) inverted = True;
160   }
161
162   control->getGradientBuffers(width, height, &xtable, &ytable);
163
164   if (texture.texture() & BTexture::Diagonal) dgradient();
165   else if (texture.texture() & BTexture::Elliptic) egradient();
166   else if (texture.texture() & BTexture::Horizontal) hgradient();
167   else if (texture.texture() & BTexture::Pyramid) pgradient();
168   else if (texture.texture() & BTexture::Rectangle) rgradient();
169   else if (texture.texture() & BTexture::Vertical) vgradient();
170   else if (texture.texture() & BTexture::CrossDiagonal) cdgradient();
171   else if (texture.texture() & BTexture::PipeCross) pcgradient();
172
173   if (texture.texture() & BTexture::Bevel1) bevel1();
174   else if (texture.texture() & BTexture::Bevel2) bevel2();
175
176   if (texture.texture() & BTexture::Border) border(texture);
177
178   if (inverted) invert();
179
180   return renderPixmap();
181
182 }
183
184
185 static const unsigned char dither4[4][4] = {
186   {0, 4, 1, 5},
187   {6, 2, 7, 3},
188   {1, 5, 0, 4},
189   {7, 3, 6, 2}
190 };
191
192
193 /*
194  * Helper function for TrueColorDither and renderXImage
195  *
196  * This handles the proper setting of the image data based on the image depth
197  * and the machine's byte ordering
198  */
199 static inline
200 void assignPixelData(unsigned int bit_depth, unsigned char **data,
201                      unsigned long pixel) {
202   unsigned char *pixel_data = *data;
203   switch (bit_depth) {
204   case  8: //  8bpp
205     *pixel_data++ = pixel;
206     break;
207
208   case 16: // 16bpp LSB
209     *pixel_data++ = pixel;
210     *pixel_data++ = pixel >> 8;
211     break;
212
213   case 17: // 16bpp MSB
214     *pixel_data++ = pixel >> 8;
215     *pixel_data++ = pixel;
216     break;
217
218   case 24: // 24bpp LSB
219     *pixel_data++ = pixel;
220     *pixel_data++ = pixel >> 8;
221     *pixel_data++ = pixel >> 16;
222     break;
223
224   case 25: // 24bpp MSB
225     *pixel_data++ = pixel >> 16;
226     *pixel_data++ = pixel >> 8;
227     *pixel_data++ = pixel;
228     break;
229
230   case 32: // 32bpp LSB
231     *pixel_data++ = pixel;
232     *pixel_data++ = pixel >> 8;
233     *pixel_data++ = pixel >> 16;
234     *pixel_data++ = pixel >> 24;
235     break;
236
237   case 33: // 32bpp MSB
238     *pixel_data++ = pixel >> 24;
239     *pixel_data++ = pixel >> 16;
240     *pixel_data++ = pixel >> 8;
241     *pixel_data++ = pixel;
242     break;
243   }
244   *data = pixel_data; // assign back so we don't lose our place
245 }
246
247
248 // algorithm: ordered dithering... many many thanks to rasterman
249 // (raster@rasterman.com) for telling me about this... portions of this
250 // code is based off of his code in Imlib
251 void BImage::TrueColorDither(unsigned int bit_depth, int bytes_per_line,
252                              unsigned char *pixel_data) {
253   unsigned int x, y, dithx, dithy, r, g, b, er, eg, eb, offset;
254   unsigned char *ppixel_data = pixel_data;
255   unsigned long pixel;
256
257   for (y = 0, offset = 0; y < height; y++) {
258     dithy = y & 0x3;
259
260     for (x = 0; x < width; x++, offset++) {
261       dithx = x & 0x3;
262       r = red[offset];
263       g = green[offset];
264       b = blue[offset];
265
266       er = r & (red_bits - 1);
267       eg = g & (green_bits - 1);
268       eb = b & (blue_bits - 1);
269
270       r = red_table[r];
271       g = green_table[g];
272       b = blue_table[b];
273
274       if ((dither4[dithy][dithx] < er) && (r < red_table[255])) r++;
275       if ((dither4[dithy][dithx] < eg) && (g < green_table[255])) g++;
276       if ((dither4[dithy][dithx] < eb) && (b < blue_table[255])) b++;
277
278       pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset);
279       assignPixelData(bit_depth, &pixel_data, pixel);
280     }
281
282     pixel_data = (ppixel_data += bytes_per_line);
283   }
284 }
285
286 #ifdef ORDEREDPSEUDO
287 const static unsigned char dither8[8][8] = {
288   { 0,  32, 8,  40, 2,  34, 10, 42},
289   { 48, 16, 56, 24, 50, 18, 58, 26},
290   { 12, 44, 4,  36, 14, 46, 6,  38},
291   { 60, 28, 52, 20, 62, 30, 54, 22},
292   { 3,  35, 11, 43, 1,  33, 9,  41},
293   { 51, 19, 59, 27, 49, 17, 57, 25},
294   { 15, 47, 7,  39, 13, 45, 5,  37},
295   { 63, 31, 55, 23, 61, 29, 53, 21}
296 };
297
298 void BImage::OrderedPseudoColorDither(int bytes_per_line,
299                                       unsigned char *pixel_data) {
300   unsigned int x, y, dithx, dithy, r, g, b, er, eg, eb, offset;
301   unsigned long pixel;
302   unsigned char *ppixel_data = pixel_data;
303
304   for (y = 0, offset = 0; y < height; y++) {
305     dithy = y & 7;
306
307     for (x = 0; x < width; x++, offset++) {
308       dithx = x & 7;
309
310       r = red[offset];
311       g = green[offset];
312       b = blue[offset];
313
314       er = r & (red_bits - 1);
315       eg = g & (green_bits - 1);
316       eb = b & (blue_bits - 1);
317
318       r = red_table[r];
319       g = green_table[g];
320       b = blue_table[b];
321
322       if ((dither8[dithy][dithx] < er) && (r < red_table[255])) r++;
323       if ((dither8[dithy][dithx] < eg) && (g < green_table[255])) g++;
324       if ((dither8[dithy][dithx] < eb) && (b < blue_table[255])) b++;
325
326       pixel = (r * cpccpc) + (g * cpc) + b;
327       *(pixel_data++) = colors[pixel].pixel;
328     }
329
330     pixel_data = (ppixel_data += bytes_per_line);
331   }
332 }
333 #endif
334
335 void BImage::PseudoColorDither(int bytes_per_line, unsigned char *pixel_data) {
336   short *terr,
337     *rerr = new short[width + 2],
338     *gerr = new short[width + 2],
339     *berr = new short[width + 2],
340     *nrerr = new short[width + 2],
341     *ngerr = new short[width + 2],
342     *nberr = new short[width + 2];
343
344   int rr, gg, bb, rer, ger, ber;
345   int dd = 255 / control->getColorsPerChannel();
346   unsigned int x, y, r, g, b, offset;
347   unsigned long pixel;
348   unsigned char *ppixel_data = pixel_data;
349
350   for (x = 0; x < width; x++) {
351     *(rerr + x) = *(red + x);
352     *(gerr + x) = *(green + x);
353     *(berr + x) = *(blue + x);
354   }
355
356   *(rerr + x) = *(gerr + x) = *(berr + x) = 0;
357
358   for (y = 0, offset = 0; y < height; y++) {
359     if (y < (height - 1)) {
360       int i = offset + width;
361       for (x = 0; x < width; x++, i++) {
362         *(nrerr + x) = *(red + i);
363         *(ngerr + x) = *(green + i);
364         *(nberr + x) = *(blue + i);
365       }
366
367       *(nrerr + x) = *(red + (--i));
368       *(ngerr + x) = *(green + i);
369       *(nberr + x) = *(blue + i);
370     }
371
372     for (x = 0; x < width; x++) {
373       rr = rerr[x];
374       gg = gerr[x];
375       bb = berr[x];
376
377       if (rr > 255) rr = 255; else if (rr < 0) rr = 0;
378       if (gg > 255) gg = 255; else if (gg < 0) gg = 0;
379       if (bb > 255) bb = 255; else if (bb < 0) bb = 0;
380
381       r = red_table[rr];
382       g = green_table[gg];
383       b = blue_table[bb];
384
385       rer = rerr[x] - r*dd;
386       ger = gerr[x] - g*dd;
387       ber = berr[x] - b*dd;
388
389       pixel = (r * cpccpc) + (g * cpc) + b;
390       *pixel_data++ = colors[pixel].pixel;
391
392       r = rer >> 1;
393       g = ger >> 1;
394       b = ber >> 1;
395       rerr[x+1] += r;
396       gerr[x+1] += g;
397       berr[x+1] += b;
398       nrerr[x] += r;
399       ngerr[x] += g;
400       nberr[x] += b;
401     }
402
403     offset += width;
404
405     pixel_data = (ppixel_data += bytes_per_line);
406
407     terr = rerr;
408     rerr = nrerr;
409     nrerr = terr;
410
411     terr = gerr;
412     gerr = ngerr;
413     ngerr = terr;
414
415     terr = berr;
416     berr = nberr;
417     nberr = terr;
418   }
419
420   delete [] rerr;
421   delete [] gerr;
422   delete [] berr;
423   delete [] nrerr;
424   delete [] ngerr;
425   delete [] nberr;
426 }
427
428 XImage *BImage::renderXImage(void) {
429   XImage *image =
430     XCreateImage(control->getBaseDisplay()->getXDisplay(),
431                  control->getVisual(), control->getDepth(), ZPixmap, 0, 0,
432                  width, height, 32, 0);
433
434   if (! image) {
435     fprintf(stderr, "BImage::renderXImage: error creating XImage\n");
436     return (XImage *) 0;
437   }
438
439   // insurance policy
440   image->data = (char *) 0;
441
442   unsigned char *d = new unsigned char[image->bytes_per_line * (height + 1)];
443
444   unsigned int o = image->bits_per_pixel +
445     ((image->byte_order == MSBFirst) ? 1 : 0);
446
447   bool unsupported = False;
448
449   if (control->doDither() && width > 1 && height > 1) {
450     switch (control->getVisual()->c_class) {
451     case TrueColor:
452       TrueColorDither(o, image->bytes_per_line, d);
453       break;
454
455     case StaticColor:
456     case PseudoColor: {
457 #ifdef ORDEREDPSEUDO
458       OrderedPseudoColorDither(image->bytes_per_line, d);
459 #else
460       PseudoColorDither(image->bytes_per_line, d);
461 #endif
462       break;
463     }
464
465     default:
466       unsupported = True;
467     }
468   } else {
469     unsigned int x, y, r, g, b, offset;
470     unsigned char *pixel_data = d, *ppixel_data = d;
471     unsigned long pixel;
472
473     switch (control->getVisual()->c_class) {
474     case StaticColor:
475     case PseudoColor:
476       for (y = 0, offset = 0; y < height; ++y) {
477         for (x = 0; x < width; ++x, ++offset) {
478           r = red_table[red[offset]];
479           g = green_table[green[offset]];
480           b = blue_table[blue[offset]];
481
482           pixel = (r * cpccpc) + (g * cpc) + b;
483           *pixel_data++ = colors[pixel].pixel;
484         }
485
486         pixel_data = (ppixel_data += image->bytes_per_line);
487       }
488
489       break;
490
491     case TrueColor:
492       for (y = 0, offset = 0; y < height; y++) {
493         for (x = 0; x < width; x++, offset++) {
494           r = red_table[red[offset]];
495           g = green_table[green[offset]];
496           b = blue_table[blue[offset]];
497
498           pixel = (r << red_offset) | (g << green_offset) | (b << blue_offset);
499           assignPixelData(o, &pixel_data, pixel);
500         }
501
502         pixel_data = (ppixel_data += image->bytes_per_line);
503       }
504
505       break;
506
507     case StaticGray:
508     case GrayScale:
509       for (y = 0, offset = 0; y < height; y++) {
510         for (x = 0; x < width; x++, offset++) {
511           r = *(red_table + *(red + offset));
512           g = *(green_table + *(green + offset));
513           b = *(blue_table + *(blue + offset));
514
515           g = ((r * 30) + (g * 59) + (b * 11)) / 100;
516           *pixel_data++ = colors[g].pixel;
517         }
518
519         pixel_data = (ppixel_data += image->bytes_per_line);
520       }
521
522       break;
523
524     default:
525       unsupported = True;
526     }
527   }
528
529   if (unsupported) {
530     fprintf(stderr, "BImage::renderXImage: unsupported visual\n");
531     delete [] d;
532     XDestroyImage(image);
533     return (XImage *) 0;
534   }
535
536   image->data = (char *) d;
537
538   return image;
539 }
540
541
542 Pixmap BImage::renderPixmap(void) {
543   Pixmap pixmap =
544     XCreatePixmap(control->getBaseDisplay()->getXDisplay(),
545                   control->getDrawable(), width, height, control->getDepth());
546
547   if (pixmap == None) {
548     fprintf(stderr, "BImage::renderPixmap: error creating pixmap\n");
549     return None;
550   }
551
552   XImage *image = renderXImage();
553
554   if (! image) {
555     XFreePixmap(control->getBaseDisplay()->getXDisplay(), pixmap);
556     return None;
557   }
558
559   if (! image->data) {
560     XDestroyImage(image);
561     XFreePixmap(control->getBaseDisplay()->getXDisplay(), pixmap);
562     return None;
563   }
564
565   XPutImage(control->getBaseDisplay()->getXDisplay(), pixmap,
566             DefaultGC(control->getBaseDisplay()->getXDisplay(),
567                       control->getScreenInfo()->getScreenNumber()),
568             image, 0, 0, 0, 0, width, height);
569
570   if (image->data) {
571     delete [] image->data;
572     image->data = NULL;
573   }
574
575   XDestroyImage(image);
576
577   return pixmap;
578 }
579
580
581 void BImage::bevel1(void) {
582   if (width > 2 && height > 2) {
583     unsigned char *pr = red, *pg = green, *pb = blue;
584
585     register unsigned char r, g, b, rr ,gg ,bb;
586     register unsigned int w = width, h = height - 1, wh = w * h;
587
588     while (--w) {
589       r = *pr;
590       rr = r + (r >> 1);
591       if (rr < r) rr = ~0;
592       g = *pg;
593       gg = g + (g >> 1);
594       if (gg < g) gg = ~0;
595       b = *pb;
596       bb = b + (b >> 1);
597       if (bb < b) bb = ~0;
598
599       *pr = rr;
600       *pg = gg;
601       *pb = bb;
602
603       r = *(pr + wh);
604       rr = (r >> 2) + (r >> 1);
605       if (rr > r) rr = 0;
606       g = *(pg + wh);
607       gg = (g >> 2) + (g >> 1);
608       if (gg > g) gg = 0;
609       b = *(pb + wh);
610       bb = (b >> 2) + (b >> 1);
611       if (bb > b) bb = 0;
612
613       *((pr++) + wh) = rr;
614       *((pg++) + wh) = gg;
615       *((pb++) + wh) = bb;
616     }
617
618     r = *pr;
619     rr = r + (r >> 1);
620     if (rr < r) rr = ~0;
621     g = *pg;
622     gg = g + (g >> 1);
623     if (gg < g) gg = ~0;
624     b = *pb;
625     bb = b + (b >> 1);
626     if (bb < b) bb = ~0;
627
628     *pr = rr;
629     *pg = gg;
630     *pb = bb;
631
632     r = *(pr + wh);
633     rr = (r >> 2) + (r >> 1);
634     if (rr > r) rr = 0;
635     g = *(pg + wh);
636     gg = (g >> 2) + (g >> 1);
637     if (gg > g) gg = 0;
638     b = *(pb + wh);
639     bb = (b >> 2) + (b >> 1);
640     if (bb > b) bb = 0;
641
642     *(pr + wh) = rr;
643     *(pg + wh) = gg;
644     *(pb + wh) = bb;
645
646     pr = red + width;
647     pg = green + width;
648     pb = blue + width;
649
650     while (--h) {
651       r = *pr;
652       rr = r + (r >> 1);
653       if (rr < r) rr = ~0;
654       g = *pg;
655       gg = g + (g >> 1);
656       if (gg < g) gg = ~0;
657       b = *pb;
658       bb = b + (b >> 1);
659       if (bb < b) bb = ~0;
660
661       *pr = rr;
662       *pg = gg;
663       *pb = bb;
664
665       pr += width - 1;
666       pg += width - 1;
667       pb += width - 1;
668
669       r = *pr;
670       rr = (r >> 2) + (r >> 1);
671       if (rr > r) rr = 0;
672       g = *pg;
673       gg = (g >> 2) + (g >> 1);
674       if (gg > g) gg = 0;
675       b = *pb;
676       bb = (b >> 2) + (b >> 1);
677       if (bb > b) bb = 0;
678
679       *(pr++) = rr;
680       *(pg++) = gg;
681       *(pb++) = bb;
682     }
683
684     r = *pr;
685     rr = r + (r >> 1);
686     if (rr < r) rr = ~0;
687     g = *pg;
688     gg = g + (g >> 1);
689     if (gg < g) gg = ~0;
690     b = *pb;
691     bb = b + (b >> 1);
692     if (bb < b) bb = ~0;
693
694     *pr = rr;
695     *pg = gg;
696     *pb = bb;
697
698     pr += width - 1;
699     pg += width - 1;
700     pb += width - 1;
701
702     r = *pr;
703     rr = (r >> 2) + (r >> 1);
704     if (rr > r) rr = 0;
705     g = *pg;
706     gg = (g >> 2) + (g >> 1);
707     if (gg > g) gg = 0;
708     b = *pb;
709     bb = (b >> 2) + (b >> 1);
710     if (bb > b) bb = 0;
711
712     *pr = rr;
713     *pg = gg;
714     *pb = bb;
715   }
716 }
717
718
719 void BImage::bevel2(void) {
720   if (width > 4 && height > 4) {
721     unsigned char r, g, b, rr ,gg ,bb, *pr = red + width + 1,
722       *pg = green + width + 1, *pb = blue + width + 1;
723     unsigned int w = width - 2, h = height - 1, wh = width * (height - 3);
724
725     while (--w) {
726       r = *pr;
727       rr = r + (r >> 1);
728       if (rr < r) rr = ~0;
729       g = *pg;
730       gg = g + (g >> 1);
731       if (gg < g) gg = ~0;
732       b = *pb;
733       bb = b + (b >> 1);
734       if (bb < b) bb = ~0;
735
736       *pr = rr;
737       *pg = gg;
738       *pb = bb;
739
740       r = *(pr + wh);
741       rr = (r >> 2) + (r >> 1);
742       if (rr > r) rr = 0;
743       g = *(pg + wh);
744       gg = (g >> 2) + (g >> 1);
745       if (gg > g) gg = 0;
746       b = *(pb + wh);
747       bb = (b >> 2) + (b >> 1);
748       if (bb > b) bb = 0;
749
750       *((pr++) + wh) = rr;
751       *((pg++) + wh) = gg;
752       *((pb++) + wh) = bb;
753     }
754
755     pr = red + width;
756     pg = green + width;
757     pb = blue + width;
758
759     while (--h) {
760       r = *pr;
761       rr = r + (r >> 1);
762       if (rr < r) rr = ~0;
763       g = *pg;
764       gg = g + (g >> 1);
765       if (gg < g) gg = ~0;
766       b = *pb;
767       bb = b + (b >> 1);
768       if (bb < b) bb = ~0;
769
770       *(++pr) = rr;
771       *(++pg) = gg;
772       *(++pb) = bb;
773
774       pr += width - 3;
775       pg += width - 3;
776       pb += width - 3;
777
778       r = *pr;
779       rr = (r >> 2) + (r >> 1);
780       if (rr > r) rr = 0;
781       g = *pg;
782       gg = (g >> 2) + (g >> 1);
783       if (gg > g) gg = 0;
784       b = *pb;
785       bb = (b >> 2) + (b >> 1);
786       if (bb > b) bb = 0;
787
788       *(pr++) = rr;
789       *(pg++) = gg;
790       *(pb++) = bb;
791
792       pr++; pg++; pb++;
793     }
794   }
795 }
796
797
798 void BImage::border(const BTexture &texture) {
799   if (width < 2 || height < 2) return;
800   
801   register unsigned int i;
802   int r = texture.borderColor().red(),
803     g = texture.borderColor().green(),
804     b = texture.borderColor().blue();
805
806   unsigned char *pr, *pg, *pb;
807
808   // top line
809   pr = red;
810   pg = green;
811   pb = blue;
812   for (i = 0; i < width; ++i) {
813     *pr++ = r;
814     *pg++ = g;
815     *pb++ = b;
816   }
817
818   if (height > 2) {
819     // left and right lines (pr,pg,pb are already lined up)
820     for (i = 1; i < height - 1; ++i) {
821       *pr = r;
822       *pg = g;
823       *pb = b;
824       pr += width - 1;
825       pg += width - 1;
826       pb += width - 1;
827       *pr++ = r;
828       *pg++ = g;
829       *pb++ = b;
830     }
831   }
832
833   // bottom line (pr,pg,pb are already lined up)
834   for (i = 0; i < width; ++i) {
835     *pr++ = r;
836     *pg++ = g;
837     *pb++ = b;
838   }
839 }
840
841
842 void BImage::invert(void) {
843   register unsigned int i, j, wh = (width * height) - 1;
844   unsigned char tmp;
845
846   for (i = 0, j = wh; j > i; j--, i++) {
847     tmp = *(red + j);
848     *(red + j) = *(red + i);
849     *(red + i) = tmp;
850
851     tmp = *(green + j);
852     *(green + j) = *(green + i);
853     *(green + i) = tmp;
854
855     tmp = *(blue + j);
856     *(blue + j) = *(blue + i);
857     *(blue + i) = tmp;
858   }
859 }
860
861
862 void BImage::dgradient(void) {
863   // diagonal gradient code was written by Mike Cole <mike@mydot.com>
864   // modified for interlacing by Brad Hughes
865
866   float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0,
867     xr = (float) from.red(),
868     xg = (float) from.green(),
869     xb = (float) from.blue();
870   unsigned char *pr = red, *pg = green, *pb = blue;
871   unsigned int w = width * 2, h = height * 2, *xt = xtable, *yt = ytable;
872
873   register unsigned int x, y;
874
875   dry = drx = (float) (to.red() - from.red());
876   dgy = dgx = (float) (to.green() - from.green());
877   dby = dbx = (float) (to.blue() - from.blue());
878
879   // Create X table
880   drx /= w;
881   dgx /= w;
882   dbx /= w;
883
884   for (x = 0; x < width; x++) {
885     *(xt++) = (unsigned char) (xr);
886     *(xt++) = (unsigned char) (xg);
887     *(xt++) = (unsigned char) (xb);
888
889     xr += drx;
890     xg += dgx;
891     xb += dbx;
892   }
893
894   // Create Y table
895   dry /= h;
896   dgy /= h;
897   dby /= h;
898
899   for (y = 0; y < height; y++) {
900     *(yt++) = ((unsigned char) yr);
901     *(yt++) = ((unsigned char) yg);
902     *(yt++) = ((unsigned char) yb);
903
904     yr += dry;
905     yg += dgy;
906     yb += dby;
907   }
908
909   // Combine tables to create gradient
910
911   if (! interlaced) {
912     // normal dgradient
913     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
914       for (xt = xtable, x = 0; x < width; x++) {
915         *(pr++) = *(xt++) + *(yt);
916         *(pg++) = *(xt++) + *(yt + 1);
917         *(pb++) = *(xt++) + *(yt + 2);
918       }
919     }
920   } else {
921     // faked interlacing effect
922     unsigned char channel, channel2;
923
924     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
925       for (xt = xtable, x = 0; x < width; x++) {
926         if (y & 1) {
927           channel = *(xt++) + *(yt);
928           channel2 = (channel >> 1) + (channel >> 2);
929           if (channel2 > channel) channel2 = 0;
930           *(pr++) = channel2;
931
932           channel = *(xt++) + *(yt + 1);
933           channel2 = (channel >> 1) + (channel >> 2);
934           if (channel2 > channel) channel2 = 0;
935           *(pg++) = channel2;
936
937           channel = *(xt++) + *(yt + 2);
938           channel2 = (channel >> 1) + (channel >> 2);
939           if (channel2 > channel) channel2 = 0;
940           *(pb++) = channel2;
941         } else {
942           channel = *(xt++) + *(yt);
943           channel2 = channel + (channel >> 3);
944           if (channel2 < channel) channel2 = ~0;
945           *(pr++) = channel2;
946
947           channel = *(xt++) + *(yt + 1);
948           channel2 = channel + (channel >> 3);
949           if (channel2 < channel) channel2 = ~0;
950           *(pg++) = channel2;
951
952           channel = *(xt++) + *(yt + 2);
953           channel2 = channel + (channel >> 3);
954           if (channel2 < channel) channel2 = ~0;
955           *(pb++) = channel2;
956         }
957       }
958     }
959   }
960 }
961
962
963 void BImage::hgradient(void) {
964   float drx, dgx, dbx,
965     xr = (float) from.red(),
966     xg = (float) from.green(),
967     xb = (float) from.blue();
968   unsigned char *pr = red, *pg = green, *pb = blue;
969
970   register unsigned int x, y;
971
972   drx = (float) (to.red() - from.red());
973   dgx = (float) (to.green() - from.green());
974   dbx = (float) (to.blue() - from.blue());
975
976   drx /= width;
977   dgx /= width;
978   dbx /= width;
979
980   if (interlaced && height > 2) {
981     // faked interlacing effect
982     unsigned char channel, channel2;
983
984     for (x = 0; x < width; x++, pr++, pg++, pb++) {
985       channel = (unsigned char) xr;
986       channel2 = (channel >> 1) + (channel >> 2);
987       if (channel2 > channel) channel2 = 0;
988       *pr = channel2;
989
990       channel = (unsigned char) xg;
991       channel2 = (channel >> 1) + (channel >> 2);
992       if (channel2 > channel) channel2 = 0;
993       *pg = channel2;
994
995       channel = (unsigned char) xb;
996       channel2 = (channel >> 1) + (channel >> 2);
997       if (channel2 > channel) channel2 = 0;
998       *pb = channel2;
999
1000
1001       channel = (unsigned char) xr;
1002       channel2 = channel + (channel >> 3);
1003       if (channel2 < channel) channel2 = ~0;
1004       *(pr + width) = channel2;
1005
1006       channel = (unsigned char) xg;
1007       channel2 = channel + (channel >> 3);
1008       if (channel2 < channel) channel2 = ~0;
1009       *(pg + width) = channel2;
1010
1011       channel = (unsigned char) xb;
1012       channel2 = channel + (channel >> 3);
1013       if (channel2 < channel) channel2 = ~0;
1014       *(pb + width) = channel2;
1015
1016       xr += drx;
1017       xg += dgx;
1018       xb += dbx;
1019     }
1020
1021     pr += width;
1022     pg += width;
1023     pb += width;
1024
1025     int offset;
1026
1027     for (y = 2; y < height; y++, pr += width, pg += width, pb += width) {
1028       if (y & 1) offset = width; else offset = 0;
1029
1030       memcpy(pr, (red + offset), width);
1031       memcpy(pg, (green + offset), width);
1032       memcpy(pb, (blue + offset), width);
1033     }
1034   } else {
1035     // normal hgradient
1036     for (x = 0; x < width; x++) {
1037       *(pr++) = (unsigned char) (xr);
1038       *(pg++) = (unsigned char) (xg);
1039       *(pb++) = (unsigned char) (xb);
1040
1041       xr += drx;
1042       xg += dgx;
1043       xb += dbx;
1044     }
1045
1046     for (y = 1; y < height; y++, pr += width, pg += width, pb += width) {
1047       memcpy(pr, red, width);
1048       memcpy(pg, green, width);
1049       memcpy(pb, blue, width);
1050     }
1051   }
1052 }
1053
1054
1055 void BImage::vgradient(void) {
1056   float dry, dgy, dby,
1057     yr = (float) from.red(),
1058     yg = (float) from.green(),
1059     yb = (float) from.blue();
1060   unsigned char *pr = red, *pg = green, *pb = blue;
1061
1062   register unsigned int y;
1063
1064   dry = (float) (to.red() - from.red());
1065   dgy = (float) (to.green() - from.green());
1066   dby = (float) (to.blue() - from.blue());
1067
1068   dry /= height;
1069   dgy /= height;
1070   dby /= height;
1071
1072   if (interlaced) {
1073     // faked interlacing effect
1074     unsigned char channel, channel2;
1075
1076     for (y = 0; y < height; y++, pr += width, pg += width, pb += width) {
1077       if (y & 1) {
1078         channel = (unsigned char) yr;
1079         channel2 = (channel >> 1) + (channel >> 2);
1080         if (channel2 > channel) channel2 = 0;
1081         memset(pr, channel2, width);
1082
1083         channel = (unsigned char) yg;
1084         channel2 = (channel >> 1) + (channel >> 2);
1085         if (channel2 > channel) channel2 = 0;
1086         memset(pg, channel2, width);
1087
1088         channel = (unsigned char) yb;
1089         channel2 = (channel >> 1) + (channel >> 2);
1090         if (channel2 > channel) channel2 = 0;
1091         memset(pb, channel2, width);
1092       } else {
1093         channel = (unsigned char) yr;
1094         channel2 = channel + (channel >> 3);
1095         if (channel2 < channel) channel2 = ~0;
1096         memset(pr, channel2, width);
1097
1098         channel = (unsigned char) yg;
1099         channel2 = channel + (channel >> 3);
1100         if (channel2 < channel) channel2 = ~0;
1101         memset(pg, channel2, width);
1102
1103         channel = (unsigned char) yb;
1104         channel2 = channel + (channel >> 3);
1105         if (channel2 < channel) channel2 = ~0;
1106         memset(pb, channel2, width);
1107       }
1108
1109       yr += dry;
1110       yg += dgy;
1111       yb += dby;
1112     }
1113   } else {
1114     // normal vgradient
1115     for (y = 0; y < height; y++, pr += width, pg += width, pb += width) {
1116       memset(pr, (unsigned char) yr, width);
1117       memset(pg, (unsigned char) yg, width);
1118       memset(pb, (unsigned char) yb, width);
1119
1120       yr += dry;
1121       yg += dgy;
1122       yb += dby;
1123     }
1124   }
1125 }
1126
1127
1128 void BImage::pgradient(void) {
1129   // pyramid gradient -  based on original dgradient, written by
1130   // Mosfet (mosfet@kde.org)
1131   // adapted from kde sources for Blackbox by Brad Hughes
1132
1133   float yr, yg, yb, drx, dgx, dbx, dry, dgy, dby,
1134     xr, xg, xb;
1135   int rsign, gsign, bsign;
1136   unsigned char *pr = red, *pg = green, *pb = blue;
1137   unsigned int tr = to.red(), tg = to.green(), tb = to.blue(),
1138     *xt = xtable, *yt = ytable;
1139
1140   register unsigned int x, y;
1141
1142   dry = drx = (float) (to.red() - from.red());
1143   dgy = dgx = (float) (to.green() - from.green());
1144   dby = dbx = (float) (to.blue() - from.blue());
1145
1146   rsign = (drx < 0) ? -1 : 1;
1147   gsign = (dgx < 0) ? -1 : 1;
1148   bsign = (dbx < 0) ? -1 : 1;
1149
1150   xr = yr = (drx / 2);
1151   xg = yg = (dgx / 2);
1152   xb = yb = (dbx / 2);
1153
1154   // Create X table
1155   drx /= width;
1156   dgx /= width;
1157   dbx /= width;
1158
1159   for (x = 0; x < width; x++) {
1160     *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
1161     *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
1162     *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
1163
1164     xr -= drx;
1165     xg -= dgx;
1166     xb -= dbx;
1167   }
1168
1169   // Create Y table
1170   dry /= height;
1171   dgy /= height;
1172   dby /= height;
1173
1174   for (y = 0; y < height; y++) {
1175     *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
1176     *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
1177     *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
1178
1179     yr -= dry;
1180     yg -= dgy;
1181     yb -= dby;
1182   }
1183
1184   // Combine tables to create gradient
1185
1186   if (! interlaced) {
1187     // normal pgradient
1188     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1189       for (xt = xtable, x = 0; x < width; x++) {
1190         *(pr++) = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
1191         *(pg++) = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
1192         *(pb++) = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
1193       }
1194     }
1195   } else {
1196     // faked interlacing effect
1197     unsigned char channel, channel2;
1198
1199     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1200       for (xt = xtable, x = 0; x < width; x++) {
1201         if (y & 1) {
1202           channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
1203           channel2 = (channel >> 1) + (channel >> 2);
1204           if (channel2 > channel) channel2 = 0;
1205           *(pr++) = channel2;
1206
1207           channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
1208           channel2 = (channel >> 1) + (channel >> 2);
1209           if (channel2 > channel) channel2 = 0;
1210           *(pg++) = channel2;
1211
1212           channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
1213           channel2 = (channel >> 1) + (channel >> 2);
1214           if (channel2 > channel) channel2 = 0;
1215           *(pb++) = channel2;
1216         } else {
1217           channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
1218           channel2 = channel + (channel >> 3);
1219           if (channel2 < channel) channel2 = ~0;
1220           *(pr++) = channel2;
1221
1222           channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
1223           channel2 = channel + (channel >> 3);
1224           if (channel2 < channel) channel2 = ~0;
1225           *(pg++) = channel2;
1226
1227           channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
1228           channel2 = channel + (channel >> 3);
1229           if (channel2 < channel) channel2 = ~0;
1230           *(pb++) = channel2;
1231         }
1232       }
1233     }
1234   }
1235 }
1236
1237
1238 void BImage::rgradient(void) {
1239   // rectangle gradient -  based on original dgradient, written by
1240   // Mosfet (mosfet@kde.org)
1241   // adapted from kde sources for Blackbox by Brad Hughes
1242
1243   float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb;
1244   int rsign, gsign, bsign;
1245   unsigned char *pr = red, *pg = green, *pb = blue;
1246   unsigned int tr = to.red(), tg = to.green(), tb = to.blue(),
1247     *xt = xtable, *yt = ytable;
1248
1249   register unsigned int x, y;
1250
1251   dry = drx = (float) (to.red() - from.red());
1252   dgy = dgx = (float) (to.green() - from.green());
1253   dby = dbx = (float) (to.blue() - from.blue());
1254
1255   rsign = (drx < 0) ? -2 : 2;
1256   gsign = (dgx < 0) ? -2 : 2;
1257   bsign = (dbx < 0) ? -2 : 2;
1258
1259   xr = yr = (drx / 2);
1260   xg = yg = (dgx / 2);
1261   xb = yb = (dbx / 2);
1262
1263   // Create X table
1264   drx /= width;
1265   dgx /= width;
1266   dbx /= width;
1267
1268   for (x = 0; x < width; x++) {
1269     *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
1270     *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
1271     *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
1272
1273     xr -= drx;
1274     xg -= dgx;
1275     xb -= dbx;
1276   }
1277
1278   // Create Y table
1279   dry /= height;
1280   dgy /= height;
1281   dby /= height;
1282
1283   for (y = 0; y < height; y++) {
1284     *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
1285     *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
1286     *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
1287
1288     yr -= dry;
1289     yg -= dgy;
1290     yb -= dby;
1291   }
1292
1293   // Combine tables to create gradient
1294
1295   if (! interlaced) {
1296     // normal rgradient
1297     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1298       for (xt = xtable, x = 0; x < width; x++) {
1299         *(pr++) = (unsigned char) (tr - (rsign * max(*(xt++), *(yt))));
1300         *(pg++) = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1))));
1301         *(pb++) = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2))));
1302       }
1303     }
1304   } else {
1305     // faked interlacing effect
1306     unsigned char channel, channel2;
1307
1308     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1309       for (xt = xtable, x = 0; x < width; x++) {
1310         if (y & 1) {
1311           channel = (unsigned char) (tr - (rsign * max(*(xt++), *(yt))));
1312           channel2 = (channel >> 1) + (channel >> 2);
1313           if (channel2 > channel) channel2 = 0;
1314           *(pr++) = channel2;
1315
1316           channel = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1))));
1317           channel2 = (channel >> 1) + (channel >> 2);
1318           if (channel2 > channel) channel2 = 0;
1319           *(pg++) = channel2;
1320
1321           channel = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2))));
1322           channel2 = (channel >> 1) + (channel >> 2);
1323           if (channel2 > channel) channel2 = 0;
1324           *(pb++) = channel2;
1325         } else {
1326           channel = (unsigned char) (tr - (rsign * max(*(xt++), *(yt))));
1327           channel2 = channel + (channel >> 3);
1328           if (channel2 < channel) channel2 = ~0;
1329           *(pr++) = channel2;
1330
1331           channel = (unsigned char) (tg - (gsign * max(*(xt++), *(yt + 1))));
1332           channel2 = channel + (channel >> 3);
1333           if (channel2 < channel) channel2 = ~0;
1334           *(pg++) = channel2;
1335
1336           channel = (unsigned char) (tb - (bsign * max(*(xt++), *(yt + 2))));
1337           channel2 = channel + (channel >> 3);
1338           if (channel2 < channel) channel2 = ~0;
1339           *(pb++) = channel2;
1340         }
1341       }
1342     }
1343   }
1344 }
1345
1346
1347 void BImage::egradient(void) {
1348   // elliptic gradient -  based on original dgradient, written by
1349   // Mosfet (mosfet@kde.org)
1350   // adapted from kde sources for Blackbox by Brad Hughes
1351
1352   float drx, dgx, dbx, dry, dgy, dby, yr, yg, yb, xr, xg, xb;
1353   int rsign, gsign, bsign;
1354   unsigned char *pr = red, *pg = green, *pb = blue;
1355   unsigned int *xt = xtable, *yt = ytable,
1356     tr = (unsigned long) to.red(),
1357     tg = (unsigned long) to.green(),
1358     tb = (unsigned long) to.blue();
1359
1360   register unsigned int x, y;
1361
1362   dry = drx = (float) (to.red() - from.red());
1363   dgy = dgx = (float) (to.green() - from.green());
1364   dby = dbx = (float) (to.blue() - from.blue());
1365
1366   rsign = (drx < 0) ? -1 : 1;
1367   gsign = (dgx < 0) ? -1 : 1;
1368   bsign = (dbx < 0) ? -1 : 1;
1369
1370   xr = yr = (drx / 2);
1371   xg = yg = (dgx / 2);
1372   xb = yb = (dbx / 2);
1373
1374   // Create X table
1375   drx /= width;
1376   dgx /= width;
1377   dbx /= width;
1378
1379   for (x = 0; x < width; x++) {
1380     *(xt++) = (unsigned long) (xr * xr);
1381     *(xt++) = (unsigned long) (xg * xg);
1382     *(xt++) = (unsigned long) (xb * xb);
1383
1384     xr -= drx;
1385     xg -= dgx;
1386     xb -= dbx;
1387   }
1388
1389   // Create Y table
1390   dry /= height;
1391   dgy /= height;
1392   dby /= height;
1393
1394   for (y = 0; y < height; y++) {
1395     *(yt++) = (unsigned long) (yr * yr);
1396     *(yt++) = (unsigned long) (yg * yg);
1397     *(yt++) = (unsigned long) (yb * yb);
1398
1399     yr -= dry;
1400     yg -= dgy;
1401     yb -= dby;
1402   }
1403
1404   // Combine tables to create gradient
1405
1406   if (! interlaced) {
1407     // normal egradient
1408     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1409       for (xt = xtable, x = 0; x < width; x++) {
1410         *(pr++) = (unsigned char)
1411           (tr - (rsign * control->getSqrt(*(xt++) + *(yt))));
1412         *(pg++) = (unsigned char)
1413           (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1))));
1414         *(pb++) = (unsigned char)
1415           (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2))));
1416       }
1417     }
1418   } else {
1419     // faked interlacing effect
1420     unsigned char channel, channel2;
1421
1422     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1423       for (xt = xtable, x = 0; x < width; x++) {
1424         if (y & 1) {
1425           channel = (unsigned char)
1426             (tr - (rsign * control->getSqrt(*(xt++) + *(yt))));
1427           channel2 = (channel >> 1) + (channel >> 2);
1428           if (channel2 > channel) channel2 = 0;
1429           *(pr++) = channel2;
1430
1431           channel = (unsigned char)
1432             (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1))));
1433           channel2 = (channel >> 1) + (channel >> 2);
1434           if (channel2 > channel) channel2 = 0;
1435           *(pg++) = channel2;
1436
1437           channel = (unsigned char)
1438             (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2))));
1439           channel2 = (channel >> 1) + (channel >> 2);
1440           if (channel2 > channel) channel2 = 0;
1441           *(pb++) = channel2;
1442         } else {
1443           channel = (unsigned char)
1444             (tr - (rsign * control->getSqrt(*(xt++) + *(yt))));
1445           channel2 = channel + (channel >> 3);
1446           if (channel2 < channel) channel2 = ~0;
1447           *(pr++) = channel2;
1448
1449           channel = (unsigned char)
1450           (tg - (gsign * control->getSqrt(*(xt++) + *(yt + 1))));
1451           channel2 = channel + (channel >> 3);
1452           if (channel2 < channel) channel2 = ~0;
1453           *(pg++) = channel2;
1454
1455           channel = (unsigned char)
1456             (tb - (bsign * control->getSqrt(*(xt++) + *(yt + 2))));
1457           channel2 = channel + (channel >> 3);
1458           if (channel2 < channel) channel2 = ~0;
1459           *(pb++) = channel2;
1460         }
1461       }
1462     }
1463   }
1464 }
1465
1466
1467 void BImage::pcgradient(void) {
1468   // pipe cross gradient -  based on original dgradient, written by
1469   // Mosfet (mosfet@kde.org)
1470   // adapted from kde sources for Blackbox by Brad Hughes
1471
1472   float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb;
1473   int rsign, gsign, bsign;
1474   unsigned char *pr = red, *pg = green, *pb = blue;
1475   unsigned int *xt = xtable, *yt = ytable,
1476     tr = to.red(),
1477     tg = to.green(),
1478     tb = to.blue();
1479
1480   register unsigned int x, y;
1481
1482   dry = drx = (float) (to.red() - from.red());
1483   dgy = dgx = (float) (to.green() - from.green());
1484   dby = dbx = (float) (to.blue() - from.blue());
1485
1486   rsign = (drx < 0) ? -2 : 2;
1487   gsign = (dgx < 0) ? -2 : 2;
1488   bsign = (dbx < 0) ? -2 : 2;
1489
1490   xr = yr = (drx / 2);
1491   xg = yg = (dgx / 2);
1492   xb = yb = (dbx / 2);
1493
1494   // Create X table
1495   drx /= width;
1496   dgx /= width;
1497   dbx /= width;
1498
1499   for (x = 0; x < width; x++) {
1500     *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
1501     *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
1502     *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
1503
1504     xr -= drx;
1505     xg -= dgx;
1506     xb -= dbx;
1507   }
1508
1509   // Create Y table
1510   dry /= height;
1511   dgy /= height;
1512   dby /= height;
1513
1514   for (y = 0; y < height; y++) {
1515     *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
1516     *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
1517     *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
1518
1519     yr -= dry;
1520     yg -= dgy;
1521     yb -= dby;
1522   }
1523
1524   // Combine tables to create gradient
1525
1526   if (! interlaced) {
1527     // normal pcgradient
1528     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1529       for (xt = xtable, x = 0; x < width; x++) {
1530         *(pr++) = (unsigned char) (tr - (rsign * min(*(xt++), *(yt))));
1531         *(pg++) = (unsigned char) (tg - (gsign * min(*(xt++), *(yt + 1))));
1532         *(pb++) = (unsigned char) (tb - (bsign * min(*(xt++), *(yt + 2))));
1533       }
1534     }
1535   } else {
1536     // faked interlacing effect
1537     unsigned char channel, channel2;
1538
1539     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1540       for (xt = xtable, x = 0; x < width; x++) {
1541         if (y & 1) {
1542           channel = (unsigned char) (tr - (rsign * min(*(xt++), *(yt))));
1543           channel2 = (channel >> 1) + (channel >> 2);
1544           if (channel2 > channel) channel2 = 0;
1545           *(pr++) = channel2;
1546
1547           channel = (unsigned char) (tg - (bsign * min(*(xt++), *(yt + 1))));
1548           channel2 = (channel >> 1) + (channel >> 2);
1549           if (channel2 > channel) channel2 = 0;
1550           *(pg++) = channel2;
1551
1552           channel = (unsigned char) (tb - (gsign * min(*(xt++), *(yt + 2))));
1553           channel2 = (channel >> 1) + (channel >> 2);
1554           if (channel2 > channel) channel2 = 0;
1555           *(pb++) = channel2;
1556         } else {
1557           channel = (unsigned char) (tr - (rsign * min(*(xt++), *(yt))));
1558           channel2 = channel + (channel >> 3);
1559           if (channel2 < channel) channel2 = ~0;
1560           *(pr++) = channel2;
1561
1562           channel = (unsigned char) (tg - (gsign * min(*(xt++), *(yt + 1))));
1563           channel2 = channel + (channel >> 3);
1564           if (channel2 < channel) channel2 = ~0;
1565           *(pg++) = channel2;
1566
1567           channel = (unsigned char) (tb - (bsign * min(*(xt++), *(yt + 2))));
1568           channel2 = channel + (channel >> 3);
1569           if (channel2 < channel) channel2 = ~0;
1570           *(pb++) = channel2;
1571         }
1572       }
1573     }
1574   }
1575 }
1576
1577
1578 void BImage::cdgradient(void) {
1579   // cross diagonal gradient -  based on original dgradient, written by
1580   // Mosfet (mosfet@kde.org)
1581   // adapted from kde sources for Blackbox by Brad Hughes
1582
1583   float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0,
1584     xr = (float) from.red(),
1585     xg = (float) from.green(),
1586     xb = (float) from.blue();
1587   unsigned char *pr = red, *pg = green, *pb = blue;
1588   unsigned int w = width * 2, h = height * 2, *xt, *yt;
1589
1590   register unsigned int x, y;
1591
1592   dry = drx = (float) (to.red() - from.red());
1593   dgy = dgx = (float) (to.green() - from.green());
1594   dby = dbx = (float) (to.blue() - from.blue());
1595
1596   // Create X table
1597   drx /= w;
1598   dgx /= w;
1599   dbx /= w;
1600
1601   for (xt = (xtable + (width * 3) - 1), x = 0; x < width; x++) {
1602     *(xt--) = (unsigned char) xb;
1603     *(xt--) = (unsigned char) xg;
1604     *(xt--) = (unsigned char) xr;
1605
1606     xr += drx;
1607     xg += dgx;
1608     xb += dbx;
1609   }
1610
1611   // Create Y table
1612   dry /= h;
1613   dgy /= h;
1614   dby /= h;
1615
1616   for (yt = ytable, y = 0; y < height; y++) {
1617     *(yt++) = (unsigned char) yr;
1618     *(yt++) = (unsigned char) yg;
1619     *(yt++) = (unsigned char) yb;
1620
1621     yr += dry;
1622     yg += dgy;
1623     yb += dby;
1624   }
1625
1626   // Combine tables to create gradient
1627
1628   if (! interlaced) {
1629     // normal cdgradient
1630     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1631       for (xt = xtable, x = 0; x < width; x++) {
1632         *(pr++) = *(xt++) + *(yt);
1633         *(pg++) = *(xt++) + *(yt + 1);
1634         *(pb++) = *(xt++) + *(yt + 2);
1635       }
1636     }
1637   } else {
1638     // faked interlacing effect
1639     unsigned char channel, channel2;
1640
1641     for (yt = ytable, y = 0; y < height; y++, yt += 3) {
1642       for (xt = xtable, x = 0; x < width; x++) {
1643         if (y & 1) {
1644           channel = *(xt++) + *(yt);
1645           channel2 = (channel >> 1) + (channel >> 2);
1646           if (channel2 > channel) channel2 = 0;
1647           *(pr++) = channel2;
1648
1649           channel = *(xt++) + *(yt + 1);
1650           channel2 = (channel >> 1) + (channel >> 2);
1651           if (channel2 > channel) channel2 = 0;
1652           *(pg++) = channel2;
1653
1654           channel = *(xt++) + *(yt + 2);
1655           channel2 = (channel >> 1) + (channel >> 2);
1656           if (channel2 > channel) channel2 = 0;
1657           *(pb++) = channel2;
1658         } else {
1659           channel = *(xt++) + *(yt);
1660           channel2 = channel + (channel >> 3);
1661           if (channel2 < channel) channel2 = ~0;
1662           *(pr++) = channel2;
1663
1664           channel = *(xt++) + *(yt + 1);
1665           channel2 = channel + (channel >> 3);
1666           if (channel2 < channel) channel2 = ~0;
1667           *(pg++) = channel2;
1668
1669           channel = *(xt++) + *(yt + 2);
1670           channel2 = channel + (channel >> 3);
1671           if (channel2 < channel) channel2 = ~0;
1672           *(pb++) = channel2;
1673         }
1674       }
1675     }
1676   }
1677 }