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