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