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