1: /*
2: ============================================================================
3: xoblite™ -> an advanced "extended shell" for Microsoft® Windows® 11
4: Copyright © 2002-2026 Karl Henrik Henriksson [qwilk/@xoblite]
5: Copyright © 2001-2004 The Blackbox for Windows Development Team
6: http://xoblite.net/ + https://github.com/xoblite/
7: ============================================================================
8:
9: Blackbox for Windows is free software, released under the
10: GNU General Public License (GPL version 2 or later), with an extension
11: that allows linking of proprietary modules under a controlled interface.
12: What this means is that plugins etc. are allowed to be released
13: under any license the author wishes. Please note, however, that the
14: original Blackbox gradient math code used in Blackbox for Windows
15: is available under the BSD license.
16:
17: http://www.fsf.org/licenses/gpl.html
18: http://www.fsf.org/licenses/gpl-faq.html#LinkingOverControlledInterface
19: http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5
20:
21: This program is distributed in the hope that it will be useful,
22: but WITHOUT ANY WARRANTY; without even the implied warranty of
23: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24: GNU General Public License for more details.
25:
26: For additional license information, please read the included license.html.
27:
28: ============================================================================
29:
30: The BB4Win dev team would like to thank Brandon Sneed (nivenh) for his
31: contributions to the Blackbox for Windows BImage; without his lmax/lmin
32: functions the PipeCross and Rectangle gradients would still be b0rked... :)
33:
34: ============================================================================
35: */
36:
37: #include "BImage.h"
38: #include <malloc.h>
39:
40: unsigned long *sqrt_table = NULL;
41:
42: //===========================================================================
43:
44: BImage::BImage()
45: {
46: }
47:
48: BImage::~BImage()
49: {
50: if (sqrt_table) delete sqrt_table;
51: }
52:
53: //===========================================================================
54:
55: // DrawGradient takes a HDC and fills it with a gradient,
56: // automatically BitBlt's it and returns nothing... lean'n'mean! :)
57: void BImage::DrawGradient(HDC hdc, RECT rect, int type, COLORREF color1, COLORREF color2, COLORREF color3, COLORREF color4, COLORREF color5, COLORREF color6, COLORREF color7, COLORREF color8, bool bInterlaced, int bevelStyle, int bevelPosition, int bevelWidth)
58: {
59: CreateBuffer(hdc, rect, true);
60:
61: //====================
62:
63: switch (type)
64: {
65: case B_SPLITVERTICAL:
66: case B_MIRRORVERTICAL:
67: {
68: // NOTE: We're using a bottom-up DIB
69: // -> origin is the lower-left corner!
70:
71: int upperHeight = height/2;
72: int lowerHeight = height - upperHeight;
73: xoffset = padding = 0;
74:
75: // Draw the lower half of the gradient...
76: yoffset = 0;
77: height = lowerHeight;
78: if (type == B_SPLITVERTICAL) PaintGradient(B_VERTICAL, color3, color4, bevelStyle);
79: else PaintGradient(B_VERTICAL, color2, color1, bevelStyle);
80:
81: // Draw the upper half of the gradient...
82: yoffset = lowerHeight;
83: height = upperHeight;
84: if (type == B_MIRRORVERTICAL)
85: {
86: // Overlap the gradients to get a single mirror center pixel...
87: yoffset--;
88: height++;
89: }
90: if (type == B_SPLITVERTICAL) PaintGradient(B_VERTICAL, color1, color2, bevelStyle);
91: else PaintGradient(B_VERTICAL, color1, color2, bevelStyle);
92:
93: // ############################################
94: // PERSONAL NOTE:
95: // Maybe I should change the gradient engine
96: // to use e.g. xstart, xstop, ystart, ystop ???
97: // ############################################
98:
99: // Do not forget to reset the height parameter or the functions
100: // below will only draw on a portion of the combined gradient...! =]
101: height = upperHeight + lowerHeight;
102: }
103: break;
104:
105: //====================
106:
107: case B_SPLITHORIZONTAL:
108: case B_MIRRORHORIZONTAL:
109: {
110: // NOTE: We're using a bottom-up DIB
111: // -> origin is the lower-left corner!
112:
113: int leftWidth = width/2;
114: int rightWidth = width - leftWidth;
115: yoffset = 0;
116:
117: // Draw the left half of the gradient...
118: xoffset = 0;
119: width = leftWidth;
120: padding = rightWidth;
121: if (type == B_SPLITHORIZONTAL) PaintGradient(B_HORIZONTAL, color1, color2, bevelStyle);
122: else PaintGradient(B_HORIZONTAL, color1, color2, bevelStyle);
123:
124: // Draw the right half of the gradient...
125: xoffset = padding = leftWidth;
126: width = rightWidth;
127: if (type == B_MIRRORHORIZONTAL)
128: {
129: // Overlap the gradients to get a single mirror center pixel...
130: xoffset--;
131: padding--;
132: width++;
133: }
134: if (type == B_SPLITHORIZONTAL) PaintGradient(B_HORIZONTAL, color3, color4, bevelStyle);
135: else PaintGradient(B_HORIZONTAL, color2, color1, bevelStyle);
136:
137: // ############################################
138: // PERSONAL NOTE:
139: // Maybe I should change the gradient engine
140: // to use e.g. xstart, xstop, ystart, ystop ???
141: // ############################################
142:
143: // Do not forget to reset the width parameter or the functions
144: // below will only draw on a portion of the combined gradient...! =]
145: width = leftWidth + rightWidth;
146: }
147: break;
148:
149: //====================
150:
151: case B_SUPERHORIZONTAL:
152: {
153: int originalWidth = width;
154:
155: if (width >= 14) // Is the available width OK? (nb. we always need 2 pixels per segment at a minimum!)
156: {
157: // -> The width *is* sufficient to accomodate a full 8-colour gradient, so we will
158: // render using all 8 colours (1-2-3-4-5-6-7-8), i.e. through 7 interconnected gradients...
159: int increment = width / 7;
160: int remainder = width % 7;
161: xoffset = 0, yoffset = 0;
162:
163: for (int i=1; i<=7; i++)
164: {
165: // width = increment;
166: if (i<7) width = increment+1; // -> Overlap the outer edges of adjacent gradients to avoid double lines of the same colour (see below)
167: else width = increment;
168: if (CheckRemainder(7, remainder, i)) width++;
169: padding = originalWidth - width;
170:
171: switch (i)
172: {
173: case 1: { PaintGradient(B_HORIZONTAL, color1, color2, BEVEL_FLAT); break; }
174: case 2: { PaintGradient(B_HORIZONTAL, color2, color3, BEVEL_FLAT); break; }
175: case 3: { PaintGradient(B_HORIZONTAL, color3, color4, BEVEL_FLAT); break; }
176: case 4: { PaintGradient(B_HORIZONTAL, color4, color5, BEVEL_FLAT); break; }
177: case 5: { PaintGradient(B_HORIZONTAL, color5, color6, BEVEL_FLAT); break; }
178: case 6: { PaintGradient(B_HORIZONTAL, color6, color7, BEVEL_FLAT); break; }
179: default: { PaintGradient(B_HORIZONTAL, color7, color8, BEVEL_FLAT); break; }
180: }
181:
182: // xoffset += width;
183: xoffset += (width-1); // -> Overlap the outer edges of adjacent gradients to avoid double lines of the same colour (see above)
184: }
185: }
186: else
187: {
188: // -> The width is *not* sufficient to accomodate a full 8-colour gradient, so we will
189: // limit the render to use only 4 colours (1-3-6-8), i.e. through 3 interconnected gradients...
190: int increment = width / 3;
191: int remainder = width % 3;
192: xoffset = 0, yoffset = 0;
193:
194: for (int i=1; i<=3; i++)
195: {
196: // width = increment;
197: if (i<3) width = increment+1; // -> Overlap the outer edges of adjacent gradients to avoid double lines of the same colour (see below)
198: else width = increment;
199: if (CheckRemainder(3, remainder, i)) width++;
200: padding = originalWidth - width;
201:
202: switch (i)
203: {
204: case 1: { PaintGradient(B_HORIZONTAL, color1, color3, BEVEL_FLAT); break; }
205: case 2: { PaintGradient(B_HORIZONTAL, color3, color6, BEVEL_FLAT); break; }
206: default: { PaintGradient(B_HORIZONTAL, color6, color8, BEVEL_FLAT); break; }
207: }
208:
209: // xoffset += width;
210: xoffset += (width-1); // -> Overlap the outer edges of adjacent gradients to avoid double lines of the same colour (see above)
211: }
212: }
213:
214: // Finally, do not forget to reset the width parameter or the functions
215: // below will only draw on a portion of the combined gradient... ;)
216: width = originalWidth;
217: }
218: break;
219:
220: //====================
221:
222: case B_SUPERVERTICAL:
223: {
224: // NOTE: We're using a *bottom-up* DIB!!!
225: // -> Rendering origin is the *lower-left* corner,
226: // so we need to swap segment order and colours accordingly! (see below)
227:
228: int originalHeight = height;
229:
230: if (height >= 14) // Is the available height OK? (nb. we always need 2 pixels per segment at a minimum!)
231: {
232: // -> The height *is* sufficient to accomodate a full 8-colour gradient, so we will
233: // render using all 8 colours (1-2-3-4-5-6-7-8), i.e. through 7 interconnected gradients...
234: int increment = height / 7;
235: int remainder = height % 7;
236: xoffset = 0, yoffset = 0;
237:
238: for (int i=1; i<=7; i++)
239: {
240: // height = increment;
241: if (i<7) height = increment+1; // -> Overlap the outer edges of adjacent gradients to avoid double lines of the same colour (see below)
242: else height = increment;
243: if (CheckRemainder(7, remainder, i)) height++;
244: padding = originalHeight - height;
245:
246: switch (i)
247: {
248: case 1: { PaintGradient(B_VERTICAL, color7, color8, BEVEL_FLAT); break; }
249: case 2: { PaintGradient(B_VERTICAL, color6, color7, BEVEL_FLAT); break; }
250: case 3: { PaintGradient(B_VERTICAL, color5, color6, BEVEL_FLAT); break; }
251: case 4: { PaintGradient(B_VERTICAL, color4, color5, BEVEL_FLAT); break; }
252: case 5: { PaintGradient(B_VERTICAL, color3, color4, BEVEL_FLAT); break; }
253: case 6: { PaintGradient(B_VERTICAL, color2, color3, BEVEL_FLAT); break; }
254: default: { PaintGradient(B_VERTICAL, color1, color2, BEVEL_FLAT); break; }
255: }
256:
257: // yoffset += height;
258: yoffset += (height-1); // -> Overlap the outer edges of adjacent gradients to avoid double lines of the same colour (see above)
259: }
260: }
261: else
262: {
263: // -> The height is *not* sufficient to accomodate a full 8-colour gradient, so we will
264: // limit the render to use only 4 colours (1-3-6-8), i.e. through 3 interconnected gradients...
265: int increment = height / 3;
266: int remainder = height % 3;
267: xoffset = 0, yoffset = 0;
268:
269: for (int i=1; i<=3; i++)
270: {
271: // height = increment;
272: if (i<3) height = increment+1; // -> Overlap the outer edges of adjacent gradients to avoid double lines of the same colour (see below)
273: else height = increment;
274: if (CheckRemainder(3, remainder, i)) height++;
275: padding = originalHeight - height;
276:
277: switch (i)
278: {
279: case 1: { PaintGradient(B_VERTICAL, color6, color8, BEVEL_FLAT); break; }
280: case 2: { PaintGradient(B_VERTICAL, color3, color6, BEVEL_FLAT); break; }
281: default: { PaintGradient(B_VERTICAL, color1, color3, BEVEL_FLAT); break; }
282: }
283:
284: // yoffset += height;
285: yoffset += (height-1); // -> Overlap the outer edges of adjacent gradients to avoid double lines of the same colour (see above)
286: }
287: }
288:
289: // Finally, do not forget to reset the height parameter or the functions
290: // below will only draw on a portion of the combined gradient... ;)
291: height = originalHeight;
292: }
293: break;
294:
295: //====================
296:
297: default: // Regular gradients or SplitSolid (which does not use the gradient engine),
298: // or failsafe (e.g. if the appearance type specifies an image to be used instead of a *box gradient)
299: {
300: xoffset = yoffset = padding = 0;
301: PaintGradient(type, color1, color2, bevelStyle);
302: }
303: }
304:
305: //====================
306:
307: ApplyInterlace(bInterlaced);
308: ApplyBevel(bevelStyle, bevelPosition, bevelWidth);
309: BitBlt(hdc, rect.left, rect.top, width, height, buf, 0, 0, SRCCOPY);
310: DestroyBuffer();
311: }
312:
313: //===========================================================================
314:
315: bool BImage::CheckRemainder(int divider, int remainder, int i)
316: {
317: if (divider == 7)
318: {
319: switch (i)
320: {
321: case 1: { if (remainder >= 6) return true; break; }
322: case 2: { if (remainder >= 4) return true; break; }
323: case 3: { if (remainder >= 2) return true; break; }
324: case 4: { if (remainder >= 1) return true; break; }
325: case 5: { if (remainder >= 3) return true; break; }
326: case 6: { if (remainder >= 5) return true; break; }
327: default: { return false; }
328: }
329: }
330: else if (divider == 3)
331: {
332: switch (i)
333: {
334: case 1: { if (remainder >= 2) return true; break; }
335: case 2: { if (remainder >= 1) return true; break; }
336: default: { return false; }
337: }
338: }
339:
340: return false;
341: }
342:
343: //===========================================================================
344:
345: void BImage::PaintGradient(int type, COLORREF colorFrom, COLORREF colorTo, int bevelStyle)
346: {
347: from_red = GetRValue(colorFrom);
348: from_green = GetGValue(colorFrom);
349: from_blue = GetBValue(colorFrom);
350: to_red = GetRValue(colorTo);
351: to_green = GetGValue(colorTo);
352: to_blue = GetBValue(colorTo);
353:
354: sunken = false;
355:
356: //====================
357:
358: if (bevelStyle == BEVEL_SUNKEN)
359: {
360: switch (type)
361: {
362: case B_PIPECROSS:
363: case B_ELLIPTIC:
364: case B_RECTANGLE:
365: case B_PYRAMID:
366: {
367: BYTE tempcolor;
368: // Swap red...
369: tempcolor = from_red;
370: from_red = to_red;
371: to_red = tempcolor;
372: // Swap green...
373: tempcolor = from_green;
374: from_green = to_green;
375: to_green = tempcolor;
376: // Swap blue...
377: tempcolor = from_blue;
378: from_blue = to_blue;
379: to_blue = tempcolor;
380: }
381: }
382:
383: sunken = true;
384: }
385:
386: //====================
387:
388: switch (type)
389: {
390: case B_VERTICAL:
391: vgradient();
392: break;
393:
394: case B_DIAGONAL:
395: dgradient();
396: break;
397:
398: case B_CROSSDIAGONAL:
399: cdgradient();
400: break;
401:
402: case B_PIPECROSS:
403: pcgradient();
404: break;
405:
406: case B_ELLIPTIC:
407: egradient();
408: break;
409:
410: case B_RECTANGLE:
411: rgradient();
412: break;
413:
414: case B_PYRAMID:
415: pgradient();
416: break;
417:
418: case B_SOLID:
419: {
420: SetRect(&fillRect, 0, 0, width, height);
421: solid_brush = CreateSolidBrush(colorFrom);
422: FillRect(buf, &fillRect, solid_brush);
423: DeleteObject(solid_brush);
424: break;
425: }
426:
427: case B_SPLITSOLID:
428: {
429: // Upper half...
430: SetRect(&fillRect, 0, 0, width, height/2);
431: solid_brush = CreateSolidBrush(colorFrom);
432: FillRect(buf, &fillRect, solid_brush);
433: DeleteObject(solid_brush);
434:
435: // Lower half...
436: fillRect.top = fillRect.bottom;
437: fillRect.bottom = height;
438: solid_brush = CreateSolidBrush(colorTo);
439: FillRect(buf, &fillRect, solid_brush);
440: DeleteObject(solid_brush);
441:
442: break;
443: }
444:
445: //====================
446:
447: default:
448: hgradient(); // B_HORIZONTAL is the default type...
449: }
450: }
451:
452: //===========================================================================
453:
454: // DrawBorder takes a HDC and draws a border at the edges...
455: void BImage::DrawBorder(HDC hdc, RECT rect, COLORREF borderColour, int borderWidth)
456: {
457: RECT borderRect;
458: CopyRect(&borderRect, &rect);
459:
460: HBRUSH borderBrush = CreateSolidBrush(borderColour);
461:
462: for (int i = 0; i < borderWidth; i++)
463: {
464: FrameRect(hdc, &borderRect, borderBrush); // Draw border...
465: InflateRect(&borderRect, -1, -1); // Shrink rectangle by 1 pixel...
466: }
467:
468: DeleteObject(borderBrush);
469: }
470:
471: //===========================================================================
472:
473: void BImage::CreateBuffer(HDC hdc, RECT rect, bool createTables)
474: {
475: width = rect.right - rect.left;
476: height = rect.bottom - rect.top;
477:
478: buf = CreateCompatibleDC(NULL);
479:
480: BITMAPINFOHEADER bv4info;
481: ZeroMemory(&bv4info, sizeof(BITMAPINFOHEADER));
482: bv4info.biSize = sizeof(BITMAPINFOHEADER);
483: bv4info.biWidth = width;
484: bv4info.biHeight = height;
485: bv4info.biPlanes = 1;
486: bv4info.biBitCount = 32;
487: bv4info.biCompression = BI_RGB;
488:
489: BITMAPINFO bminfo;
490: // ZeroMemory(&bminfo, sizeof(BITMAPINFO));
491: bminfo.bmiHeader = bv4info;
492:
493: bufbmp = CreateDIBSection(hdc, &bminfo, DIB_RGB_COLORS,(PVOID *) &pixels, NULL, 0);
494: oldbuf = (HBITMAP)SelectObject(buf, bufbmp);
495:
496: // The x/y tables are only used when rendering gradients,
497: // not needed when setting or applying per pixel alpha...
498: if (createTables)
499: {
500: xtable = new unsigned int[width * 3];
501: ytable = new unsigned int[height * 3];
502: }
503: else xtable = ytable = NULL;
504: }
505:
506: //====================
507:
508: void BImage::DestroyBuffer()
509: {
510: SelectObject(buf, oldbuf);
511: DeleteDC(buf);
512: DeleteObject(bufbmp);
513: DeleteObject(oldbuf);
514:
515: if (xtable) delete [] xtable;
516: if (ytable) delete [] ytable;
517: xtable = ytable = NULL;
518: }
519:
520: //===========================================================================
521:
522: // Fixes to make PipeCross and Rectangle work correctly / nivenh
523: template <typename T> inline T lmax(T a, T b) { return ((a > b) ? a : b); }
524: template <typename T> inline T lmin(T a, T b) { return ((a < b) ? a : b); }
525:
526: //===========================================================================
527:
528: void BImage::ApplyBevel(int bevelStyle, int bevelPosition, int bevelWidth)
529: {
530: if (bevelStyle != BEVEL_FLAT)
531: {
532: switch (bevelPosition)
533: {
534: case BEVEL1:
535: bevel1(sunken);
536: break;
537:
538: case BEVEL2:
539: bevel2(sunken);
540: break;
541: }
542: }
543: }
544:
545: //====================
546:
547: void BImage::bevel1(bool sunken)
548: {
549: if (width > 2 && height > 2)
550: {
551: unsigned int count, x, y;
552: unsigned int w = ((width * 4) - 4), h = (width * (height-1) * 4);
553: unsigned int nextpixel = 4, nextline = (width * 4);
554:
555: //====================
556:
557: count = 0;
558: for (x = 0; x < width; x++)
559: {
560: // NOTE: We're using a bottom-up DIB -> origin is the lower-left corner!
561: if (!sunken)
562: {
563: lightenpixel(count+h); // Upper horizontal bevel for BEVEL_RAISED
564: if (x) darkenpixel(count); // Lower horizontal bevel for BEVEL_RAISED (do not bevelize the first pixel twice!)
565: }
566: else
567: {
568: darkenpixel(count+h); // Upper horizontal bevel for BEVEL_SUNKEN
569: if (x) lightenpixel(count); // Lower horizontal bevel for BEVEL_SUNKEN (do not bevelize the first pixel twice!)
570: }
571:
572: count += nextpixel;
573: }
574:
575: //====================
576:
577: count = 0;
578: for (y = 0; y < (height-1); y++)
579: {
580: if (!sunken)
581: {
582: lightenpixel(count); // Left vertical bevel for BEVEL_RAISED
583: if (y) darkenpixel(count+w); // Right vertical bevel for BEVEL_RAISED (do not bevelize the first pixel twice!)
584: }
585: else
586: {
587: darkenpixel(count); // Left vertical bevel for BEVEL_SUNKEN
588: if (y) lightenpixel(count+w); // Right vertical bevel for BEVEL_SUNKEN (do not bevelize the first pixel twice!)
589: }
590:
591: count += nextline;
592: }
593: }
594: }
595:
596: //====================
597:
598: void BImage::bevel2(bool sunken)
599: {
600: if (width > 4 && height > 4)
601: {
602: unsigned int count, x, y, w = ((width * 4) - 12), h = (width * (height-3) * 4);
603: unsigned int nextpixel = 4, nextline = (width * 4);
604:
605: count = nextline + nextpixel;
606: for (x = 0; x < (width-2); x++)
607: {
608: // NOTE: We're using a bottom-up DIB -> origin is the lower-left corner!
609:
610: if (!sunken)
611: {
612: lightenpixel(count+h); // Upper horizontal bevel for BEVEL_RAISED
613: if (x) darkenpixel(count); // Lower horizontal bevel for BEVEL_RAISED (do not bevelize the first pixel twice!)
614: }
615: else
616: {
617: darkenpixel(count+h); // Upper horizontal bevel for BEVEL_SUNKEN
618: if (x) lightenpixel(count); // Lower horizontal bevel for BEVEL_SUNKEN (do not bevelize the first pixel twice!)
619: }
620:
621: count += nextpixel;
622: }
623:
624: count = nextline + nextpixel;
625: for (y = 0; y < (height-3); y++)
626: {
627: if (!sunken)
628: {
629: lightenpixel(count); // Left vertical bevel for BEVEL_RAISED
630: if (y) darkenpixel(count+w); // Right vertical bevel for BEVEL_RAISED (do not bevelize the first pixel twice!)
631: }
632: else
633: {
634: darkenpixel(count); // Left vertical bevel for BEVEL_SUNKEN
635: if (y) lightenpixel(count+w); // Right vertical bevel for BEVEL_SUNKEN (do not bevelize the first pixel twice!)
636: }
637:
638: count += nextline;
639: }
640: }
641: }
642:
643: //====================
644:
645: void BImage::lightenpixel(unsigned int count)
646: {
647: r = pixels[count + 2];
648: rr = r + (r >> 1);
649: if (rr < r) rr = ~0;
650: g = pixels[count + 1];
651: gg = g + (g >> 1);
652: if (gg < g) gg = ~0;
653: b = pixels[count];
654: bb = b + (b >> 1);
655: if (bb < b) bb = ~0;
656:
657: pixels[count + 2] = rr;
658: pixels[count + 1] = gg;
659: pixels[count] = bb;
660: }
661:
662: //====================
663:
664: void BImage::darkenpixel(unsigned int count)
665: {
666: r = pixels[count + 2];
667: rr = (r >> 2) + (r >> 1);
668: if (rr > r) rr = 0;
669: g = pixels[count + 1];
670: gg = (g >> 2) + (g >> 1);
671: if (gg > g) gg = 0;
672: b = pixels[count];
673: bb = (b >> 2) + (b >> 1);
674: if (bb > b) bb = 0;
675:
676: pixels[count + 2] = rr;
677: pixels[count + 1] = gg;
678: pixels[count] = bb;
679: }
680:
681: //===========================================================================
682:
683: void BImage::ApplyInterlace(bool bInterlaced)
684: {
685: if (!bInterlaced) return;
686: if ((height <= 2) || (width <= 2)) return;
687:
688: UINT x, y, count = 0;
689: unsigned char channel, channel2;
690:
691: for (y = 0; y < height; y++)
692: {
693: for (x =0; x < width; x++)
694: {
695: if (y & 1)
696: {
697: channel = pixels[count + 2];
698: channel2 = (channel >> 1) + (channel >> 2);
699: if (channel2 > channel) channel2 = 0;
700: pixels[count + 2] = channel2;
701:
702: channel = pixels[count + 1];
703: channel2 = (channel >> 1) + (channel >> 2);
704: if (channel2 > channel) channel2 = 0;
705: pixels[count + 1] = channel2;
706:
707: channel = pixels[count];
708: channel2 = (channel >> 1) + (channel >> 2);
709: if (channel2 > channel) channel2 = 0;
710: pixels[count] = channel2;
711: }
712: else
713: {
714: channel = pixels[count + 2];
715: channel2 = channel + (channel >> 3);
716: if (channel2 < channel) channel2 = ~0;
717: pixels[count + 2] = channel2;
718:
719: channel = pixels[count + 1];
720: channel2 = channel + (channel >> 3);
721: if (channel2 < channel) channel2 = ~0;
722: pixels[count + 1] = channel2;
723:
724: channel = pixels[count];
725: channel2 = channel + (channel >> 3);
726: if (channel2 < channel) channel2 = ~0;
727: pixels[count] = channel2;
728: }
729:
730: count += 4;
731: }
732: }
733: }
734:
735: //===========================================================================
736: // Below: The original Blackbox (for the X Window System) math code,
737: // modified to paint directly into the destination DIBSection and
738: // moving the reoccuring interlacing code into a separate function.
739: // The original code is issued under the BSD license,
740: // for more info visit http://sourceforge.net/projects/blackboxwm/
741: // Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
742: // Copyright (c) 1997 - 2000, 2002 Bradley T Hughes <bhughes at trolltech.com>
743: //===========================================================================
744:
745: void BImage::dgradient(void)
746: {
747: if ((height <= 2) || (width <= 2)) return;
748:
749: // diagonal gradient code was written by Mike Cole <mike@mydot.com>
750: // modified for interlacing by Brad Hughes
751:
752: float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0,
753: xr = (float) from_red,
754: xg = (float) from_green,
755: xb = (float) from_blue;
756:
757: UINT w = width * 2, h = height * 2, *xt = xtable, *yt = ytable, x, y, count = 0;
758:
759: dry = drx = (float) (to_red - from_red);
760: dgy = dgx = (float) (to_green - from_green);
761: dby = dbx = (float) (to_blue - from_blue);
762:
763: // Create X table
764: drx /= w;
765: dgx /= w;
766: dbx /= w;
767:
768: for (x = 0; x < width; x++)
769: {
770: *(xt++) = (unsigned char) (xr);
771: *(xt++) = (unsigned char) (xg);
772: *(xt++) = (unsigned char) (xb);
773:
774: xr += drx;
775: xg += dgx;
776: xb += dbx;
777: }
778:
779: // Create Y table
780: dry /= h;
781: dgy /= h;
782: dby /= h;
783:
784: for (yt = (ytable + (height * 3) - 1), y = 0; y < height; y++)
785: {
786: *(yt--) = ((unsigned char) yb);
787: *(yt--) = ((unsigned char) yg);
788: *(yt--) = ((unsigned char) yr);
789:
790: yr += dry;
791: yg += dgy;
792: yb += dby;
793: }
794:
795: // Combine tables to create gradient
796:
797: for (yt = ytable, y = 0; y < height; y++, yt += 3)
798: {
799: for (xt = xtable, x = 0; x < width; x++)
800: {
801: pixels[count + 2] = *(xt++) + *(yt);
802: pixels[count + 1] = *(xt++) + *(yt + 1);
803: pixels[count] = *(xt++) + *(yt + 2);
804: count += 4;
805: }
806: }
807: }
808:
809: //===========================================================================
810:
811: void BImage::hgradient(void)
812: {
813: // if ((height <= 2) || (width <= 2)) return;
814: if ((height < 1) || (width < 1)) return;
815:
816: //====================
817:
818: float xr = (float) from_red;
819: float xg = (float) from_green;
820: float xb = (float) from_blue;
821:
822: float drx = (float) (to_red - from_red);
823: float dgx = (float) (to_green - from_green);
824: float dbx = (float) (to_blue - from_blue);
825:
826: drx /= width;
827: dgx /= width;
828: dbx /= width;
829:
830: //====================
831:
832: unsigned int x, y, count, o = (xoffset*4), w = (width*4), p = (padding*4);
833:
834: // Draw the first row of pixels...
835: count = o;
836: for (x = 0; x < (width-1); x++)
837: {
838: pixels[count+2] = (unsigned char) (xr);
839: pixels[count+1] = (unsigned char) (xg);
840: pixels[count] = (unsigned char) (xb);
841:
842: xr += drx;
843: xg += dgx;
844: xb += dbx;
845:
846: count += 4;
847: }
848: pixels[count+2] = to_red;
849: pixels[count+1] = to_green;
850: pixels[count] = to_blue;
851:
852: // ...then memcpy this first row onto the remaining rows...
853: count = o+w+p;
854: for (y = 1; y < height; y++)
855: {
856: void* dest = &pixels[count];
857: void* src = &pixels[o];
858: memcpy(dest, src, w);
859:
860: count += w;
861: count += p;
862: }
863: }
864:
865: //===========================================================================
866:
867: void BImage::vgradient(void)
868: {
869: // if ((height <= 2) || (width <= 2)) return;
870: if ((height < 1) || (width < 1)) return;
871:
872: //====================
873:
874: float yr = (float) to_red;
875: float yg = (float) to_green;
876: float yb = (float) to_blue;
877:
878: float dry = (float) (from_red - to_red);
879: float dgy = (float) (from_green - to_green);
880: float dby = (float) (from_blue - to_blue);
881:
882: dry /= height;
883: dgy /= height;
884: dby /= height;
885:
886: //====================
887:
888: UINT x, y, count = yoffset*width*4, lastRow = (height-1);
889:
890: for (y = 0; y < height; y++)
891: {
892: for (x = 0; x < width; x++)
893: {
894: if (y == lastRow)
895: {
896: pixels[count+2] = from_red;
897: pixels[count+1] = from_green;
898: pixels[count] = from_blue;
899: }
900: else
901: {
902: pixels[count+2] = (unsigned char) yr;
903: pixels[count+1] = (unsigned char) yg;
904: pixels[count] = (unsigned char) yb;
905: }
906: count += 4;
907: }
908: yr += dry;
909: yg += dgy;
910: yb += dby;
911: }
912: }
913:
914: //===========================================================================
915:
916: void BImage::pgradient(void)
917: {
918: if ((height <= 2) || (width <= 2)) return;
919:
920: // pyramid gradient - based on original dgradient, written by
921: // Mosfet (mosfet@kde.org)
922: // adapted from kde sources for Blackbox by Brad Hughes
923:
924: float yr, yg, yb, drx, dgx, dbx, dry, dgy, dby, xr, xg, xb;
925: int rsign, gsign, bsign;
926: UINT tr = to_red, tg = to_green, tb = to_blue, *xt = xtable, *yt = ytable, x, y, count = 0;
927:
928: dry = drx = (float) (to_red - from_red);
929: dgy = dgx = (float) (to_green - from_green);
930: dby = dbx = (float) (to_blue - from_blue);
931:
932: rsign = (drx < 0) ? -1 : 1;
933: gsign = (dgx < 0) ? -1 : 1;
934: bsign = (dbx < 0) ? -1 : 1;
935:
936: xr = yr = (drx / 2);
937: xg = yg = (dgx / 2);
938: xb = yb = (dbx / 2);
939:
940: // Create X table
941: drx /= width;
942: dgx /= width;
943: dbx /= width;
944:
945: for (x = 0; x < width; x++)
946: {
947: *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
948: *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
949: *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
950:
951: xr -= drx;
952: xg -= dgx;
953: xb -= dbx;
954: }
955:
956: // Create Y table
957: dry /= height;
958: dgy /= height;
959: dby /= height;
960:
961: for (y = 0; y < height; y++)
962: {
963: *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
964: *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
965: *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
966:
967: yr -= dry;
968: yg -= dgy;
969: yb -= dby;
970: }
971:
972: // Combine tables to create gradient
973:
974: for (yt = ytable, y = 0; y < height; y++, yt += 3)
975: {
976: for (xt = xtable, x = 0; x < width; x++)
977: {
978: pixels[count + 2] = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
979: pixels[count + 1] = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
980: pixels[count] = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
981: count += 4;
982: }
983: }
984: }
985:
986: //===========================================================================
987:
988: void BImage::rgradient(void)
989: {
990: if ((height <= 2) || (width <= 2)) return;
991:
992: // rectangle gradient - based on original dgradient, written by
993: // Mosfet (mosfet@kde.org)
994: // adapted from kde sources for Blackbox by Brad Hughes
995:
996: float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb;
997: int rsign, gsign, bsign;
998: unsigned int tr = to_red, tg = to_green, tb = to_blue, *xt = xtable, *yt = ytable;
999:
1000: UINT x, y, count = 0;
1001:
1002: dry = drx = (float) (to_red - from_red);
1003: dgy = dgx = (float) (to_green - from_green);
1004: dby = dbx = (float) (to_blue - from_blue);
1005:
1006: rsign = (drx < 0) ? -2 : 2;
1007: gsign = (dgx < 0) ? -2 : 2;
1008: bsign = (dbx < 0) ? -2 : 2;
1009:
1010: xr = yr = (drx / 2);
1011: xg = yg = (dgx / 2);
1012: xb = yb = (dbx / 2);
1013:
1014: // Create X table
1015: drx /= width;
1016: dgx /= width;
1017: dbx /= width;
1018:
1019: for (x = 0; x < width; x++)
1020: {
1021: *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
1022: *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
1023: *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
1024:
1025: xr -= drx;
1026: xg -= dgx;
1027: xb -= dbx;
1028: }
1029:
1030: // Create Y table
1031: dry /= height;
1032: dgy /= height;
1033: dby /= height;
1034:
1035: for (y = 0; y < height; y++)
1036: {
1037: *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
1038: *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
1039: *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
1040:
1041: yr -= dry;
1042: yg -= dgy;
1043: yb -= dby;
1044: }
1045:
1046: // Combine tables to create gradient
1047:
1048: for (yt = ytable, y = 0; y < height; y++, yt += 3)
1049: {
1050: for (xt = xtable, x = 0; x < width; x++)
1051: {
1052: pixels[count + 2] = (unsigned char) (tr - (rsign * lmax(*(xt++), *(yt))));
1053: pixels[count + 1] = (unsigned char) (tg - (gsign * lmax(*(xt++), *(yt + 1))));
1054: pixels[count] = (unsigned char) (tb - (bsign * lmax(*(xt++), *(yt + 2))));
1055: count += 4;
1056: }
1057: }
1058: }
1059:
1060: //===========================================================================
1061:
1062: void BImage::egradient(void)
1063: {
1064: if ((height <= 2) || (width <= 2)) return;
1065:
1066: // elliptic gradient - based on original dgradient, written by
1067: // Mosfet (mosfet@kde.org)
1068: // adapted from kde sources for Blackbox by Brad Hughes
1069:
1070: float drx, dgx, dbx, dry, dgy, dby, yr, yg, yb, xr, xg, xb;
1071: int rsign, gsign, bsign;
1072: unsigned int *xt = xtable, *yt = ytable,
1073: tr = (unsigned long) to_red,
1074: tg = (unsigned long) to_green,
1075: tb = (unsigned long) to_blue;
1076:
1077: UINT x, y, count = 0;
1078:
1079: dry = drx = (float) (to_red - from_red);
1080: dgy = dgx = (float) (to_green - from_green);
1081: dby = dbx = (float) (to_blue - from_blue);
1082:
1083: rsign = (drx < 0) ? -1 : 1;
1084: gsign = (dgx < 0) ? -1 : 1;
1085: bsign = (dbx < 0) ? -1 : 1;
1086:
1087: xr = yr = (drx / 2);
1088: xg = yg = (dgx / 2);
1089: xb = yb = (dbx / 2);
1090:
1091: // Create X table
1092: drx /= width;
1093: dgx /= width;
1094: dbx /= width;
1095:
1096: for (x = 0; x < width; x++)
1097: {
1098: *(xt++) = (unsigned long) (xr * xr);
1099: *(xt++) = (unsigned long) (xg * xg);
1100: *(xt++) = (unsigned long) (xb * xb);
1101:
1102: xr -= drx;
1103: xg -= dgx;
1104: xb -= dbx;
1105: }
1106:
1107: // Create Y table
1108: dry /= height;
1109: dgy /= height;
1110: dby /= height;
1111:
1112: for (y = 0; y < height; y++)
1113: {
1114: *(yt++) = (unsigned long) (yr * yr);
1115: *(yt++) = (unsigned long) (yg * yg);
1116: *(yt++) = (unsigned long) (yb * yb);
1117:
1118: yr -= dry;
1119: yg -= dgy;
1120: yb -= dby;
1121: }
1122:
1123: // Combine tables to create gradient
1124:
1125: for (yt = ytable, y = 0; y < height; y++, yt += 3)
1126: {
1127: for (xt = xtable, x = 0; x < width; x++)
1128: {
1129: pixels[count + 2] = (unsigned char)
1130: (tr - (rsign * getSqrt(*(xt++) + *(yt))));
1131: pixels[count + 1] = (unsigned char)
1132: (tg - (gsign * getSqrt(*(xt++) + *(yt + 1))));
1133: pixels[count] = (unsigned char)
1134: (tb - (bsign * getSqrt(*(xt++) + *(yt + 2))));
1135: count += 4;
1136: }
1137: }
1138: }
1139:
1140: //===========================================================================
1141:
1142: void BImage::pcgradient(void)
1143: {
1144: if ((height <= 4) || (width <= 4)) return;
1145:
1146: // pipe cross gradient - based on original dgradient, written by
1147: // Mosfet (mosfet@kde.org)
1148: // adapted from kde sources for Blackbox by Brad Hughes
1149:
1150: float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb;
1151: int rsign, gsign, bsign;
1152: unsigned int *xt = xtable, *yt = ytable, tr = to_red, tg = to_green, tb = to_blue;
1153:
1154: UINT x, y, count = 0;
1155:
1156: dry = drx = (float) (to_red - from_red);
1157: dgy = dgx = (float) (to_green - from_green);
1158: dby = dbx = (float) (to_blue - from_blue);
1159:
1160: rsign = (drx < 0) ? -2 : 2;
1161: gsign = (dgx < 0) ? -2 : 2;
1162: bsign = (dbx < 0) ? -2 : 2;
1163:
1164: xr = yr = (drx / 2);
1165: xg = yg = (dgx / 2);
1166: xb = yb = (dbx / 2);
1167:
1168: // Create X table
1169: drx /= width;
1170: dgx /= width;
1171: dbx /= width;
1172:
1173: for (x = 0; x < width; x++)
1174: {
1175: *(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
1176: *(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
1177: *(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);
1178:
1179: xr -= drx;
1180: xg -= dgx;
1181: xb -= dbx;
1182: }
1183:
1184: // Create Y table
1185: dry /= height;
1186: dgy /= height;
1187: dby /= height;
1188:
1189: for (y = 0; y < height; y++)
1190: {
1191: *(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
1192: *(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
1193: *(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));
1194:
1195: yr -= dry;
1196: yg -= dgy;
1197: yb -= dby;
1198: }
1199:
1200: // Combine tables to create gradient
1201:
1202: for (yt = ytable, y = 0; y < height; y++, yt += 3)
1203: {
1204: for (xt = xtable, x = 0; x < width; x++)
1205: {
1206: pixels[count + 2] = (unsigned char) (tr - (rsign * lmin(*(xt++), *(yt))));
1207: pixels[count + 1] = (unsigned char) (tg - (gsign * lmin(*(xt++), *(yt + 1))));
1208: pixels[count] = (unsigned char) (tb - (bsign * lmin(*(xt++), *(yt + 2))));
1209: count += 4;
1210: }
1211: }
1212: }
1213:
1214: //===========================================================================
1215:
1216: void BImage::cdgradient(void)
1217: {
1218: if ((height <= 2) || (width <= 2)) return;
1219:
1220: // cross diagonal gradient - based on original dgradient, written by
1221: // Mosfet (mosfet@kde.org)
1222: // adapted from kde sources for Blackbox by Brad Hughes
1223:
1224: float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0,
1225: xr = (float) from_red,
1226: xg = (float) from_green,
1227: xb = (float) from_blue;
1228:
1229: UINT w = width * 2, h = height * 2, *xt, *yt, x, y, count = 0;
1230:
1231: dry = drx = (float) (to_red - from_red);
1232: dgy = dgx = (float) (to_green - from_green);
1233: dby = dbx = (float) (to_blue - from_blue);
1234:
1235: // Create X table
1236: drx /= w;
1237: dgx /= w;
1238: dbx /= w;
1239:
1240: for (xt = (xtable + (width * 3) - 1), x = 0; x < width; x++)
1241: {
1242: *(xt--) = (unsigned char) xb;
1243: *(xt--) = (unsigned char) xg;
1244: *(xt--) = (unsigned char) xr;
1245:
1246: xr += drx;
1247: xg += dgx;
1248: xb += dbx;
1249: }
1250:
1251: // Create Y table
1252: dry /= h;
1253: dgy /= h;
1254: dby /= h;
1255:
1256: for (yt = (ytable + (height * 3) - 1), y = 0; y < height; y++)
1257: {
1258: *(yt--) = ((unsigned char) yb);
1259: *(yt--) = ((unsigned char) yg);
1260: *(yt--) = ((unsigned char) yr);
1261:
1262: yr += dry;
1263: yg += dgy;
1264: yb += dby;
1265: }
1266:
1267: // Combine tables to create gradient
1268:
1269: for (yt = ytable, y = 0; y < height; y++, yt += 3)
1270: {
1271: for (xt = xtable, x = 0; x < width; x++)
1272: {
1273: pixels[count + 2] = *(xt++) + *(yt);
1274: pixels[count + 1] = *(xt++) + *(yt + 1);
1275: pixels[count] = *(xt++) + *(yt + 2);
1276: count += 4;
1277: }
1278: }
1279: }
1280:
1281: //===========================================================================
1282:
1283: static unsigned long bsqrt(unsigned long x)
1284: {
1285: if (x <= 0) return 0;
1286: if (x == 1) return 1;
1287:
1288: unsigned long r = x >> 1;
1289: unsigned long q;
1290:
1291: while (1)
1292: {
1293: q = x / r;
1294: if (q >= r) return r;
1295: r = (r + q) >> 1;
1296: }
1297: }
1298:
1299: //====================
1300:
1301: unsigned long getSqrt(unsigned int x)
1302: {
1303: if (!sqrt_table)
1304: {
1305: // build sqrt table for use with elliptic gradient
1306: sqrt_table = new unsigned long[(256 * 256 * 2) + 1];
1307:
1308: for (int i = 0; i < (256 * 256 * 2); i++)
1309: *(sqrt_table + i) = bsqrt(i);
1310: }
1311: return (*(sqrt_table + x));
1312: }
1313:
1314: //===========================================================================
1315: