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