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: