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