/*
 ============================================================================
 xoblite -> an alternative shell based on Blackbox for Windows
 Copyright © 2002-2005 Karl-Henrik Henriksson [qwilk]
 Copyright © 2001-2004 The Blackbox for Windows Development Team
 http://xoblite.net/ - #bb4win on irc.freenode.net
 ============================================================================

  Blackbox for Windows is free software, released under the
  GNU General Public License (GPL version 2 or later), with an extension
  that allows linking of proprietary modules under a controlled interface.
  What this means is that plugins etc. are allowed to be released
  under any license the author wishes. Please note, however, that the
  original Blackbox gradient math code used in Blackbox for Windows
  is available under the BSD license.

  http://www.fsf.org/licenses/gpl.html
  http://www.fsf.org/licenses/gpl-faq.html#LinkingOverControlledInterface
  http://www.xfree86.org/3.3.6/COPYRIGHT2.html#5

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  GNU General Public License for more details.

  For additional license information, please read the included license.html

 ============================================================================

  The devteam would like to thank Brandon Sneed (nivenh) for his
  contributions to the Blackbox for Windows BImage; without his lmax/lmin
  functions the PipeCross and Rectangle gradients would still be b0rked... :)

 ============================================================================
*/

#include "BImage.h" 
#include <malloc.h> 

unsigned long *sqrt_table = NULL;

//===========================================================================

BImage::BImage()
{
}

BImage::~BImage()
{
	if (sqrt_table) delete sqrt_table;
}

//===========================================================================

// CreateGradientByRect takes a HDC and fills it with a gradient,
// automatically BitBlt's it and returns nothing... lean'n'mean! :)
void BImage::CreateGradientByRect(HDC hdc, RECT rect, int type, COLORREF colour1, COLORREF colour2, bool bInterlaced, int bevelStyle, int bevelPosition, int bevelWidth)
{
	CreateBuffer(hdc, rect, colour1, colour2);
	PaintGradient(type, bInterlaced, bevelStyle, bevelPosition, bevelWidth);
	BitBlt(hdc, rect.left, rect.top, width, height, buf, 0, 0, SRCCOPY);
	DestroyBuffer();
}

//====================

// CreateBorder takes a HDC and draws a border at the edges...
void BImage::CreateBorder(HDC hdc, RECT rect, COLORREF borderColour, int borderWidth)
{
	HPEN borderPen = CreatePen(PS_SOLID, 1, borderColour);
	HPEN oldPen = (HPEN) SelectObject(hdc, borderPen);

	for (int i = 0; i < borderWidth; i++)
	{
		int right = rect.right - i - 1;
		int bottom = rect.bottom - i - 1;

		MoveToEx(hdc, rect.left + i, rect.top + i, NULL);
		LineTo(hdc, right, rect.top + i);
		LineTo(hdc, right, bottom);
		LineTo(hdc, rect.left + i, bottom);
		LineTo(hdc, rect.left + i, rect.top + i);
	}

	SelectObject(hdc, oldPen);
	DeleteObject(borderPen);
}

//===========================================================================

void BImage::CreateBuffer(HDC hdc, RECT rect, COLORREF colour1, COLORREF colour2)
{
	width = rect.right - rect.left;
	height = rect.bottom - rect.top;

	buf = CreateCompatibleDC(NULL);

	BITMAPINFOHEADER bv4info;
	bv4info.biSize = sizeof(BITMAPINFOHEADER);
	bv4info.biWidth = width;
	bv4info.biHeight = height;
	bv4info.biPlanes = 1;
	bv4info.biBitCount = 32;
	bv4info.biCompression = BI_RGB;
	BITMAPINFO bminfo;
	bminfo.bmiHeader = bv4info;
	
	bufbmp = CreateDIBSection(hdc, &bminfo, DIB_RGB_COLORS,(PVOID *) &pixels, NULL, 0);
	oldbuf = (HBITMAP)SelectObject(buf, bufbmp);

	from_red = GetRValue(colour1);
	from_green = GetGValue(colour1);
	from_blue = GetBValue(colour1);
	to_red = GetRValue(colour2);
	to_green = GetGValue(colour2);
	to_blue = GetBValue(colour2);

	xtable = new unsigned int[width * 3];
	ytable = new unsigned int[height * 3];
}

//====================

void BImage::DestroyBuffer()
{
	SelectObject(buf, oldbuf);
	DeleteDC(buf);
	DeleteObject(bufbmp);
	DeleteObject(oldbuf);

	if (xtable) delete [] xtable;
	if (ytable) delete [] ytable;
}

//===========================================================================

void BImage::PaintGradient(int type, bool bInterlaced, int bevelStyle, int bevelPosition, int bevelWidth)
{
	sunken = false; 
	interlaced = bInterlaced;

	if (bevelStyle == BEVEL_SUNKEN) 
	{
		if (type == B_PIPECROSS || type == B_ELLIPTIC || type == B_RECTANGLE || type == B_PYRAMID)
		{
			BYTE tempcolor;
			// Swap red...
			tempcolor = from_red;
			from_red = to_red;
			to_red = tempcolor;
			// Swap green...
			tempcolor = from_green;
			from_green = to_green;
			to_green = tempcolor;
			// Swap blue...
			tempcolor = from_blue;
			from_blue = to_blue;
			to_blue = tempcolor;
		}

		sunken = true;
	}

	if (type == B_SOLID) // Ugly, I know... ;)
	{
		to_red = from_red;
		to_green = from_green;
		to_blue = from_blue;
		vgradient();
	}
	else if (type == B_VERTICAL) vgradient();
	else if (type == B_DIAGONAL) dgradient();
	else if (type == B_CROSSDIAGONAL) cdgradient();
	else if (type == B_PIPECROSS) pcgradient();
	else if (type == B_ELLIPTIC) egradient();
	else if (type == B_RECTANGLE) rgradient();
	else if (type == B_PYRAMID) pgradient();
	else hgradient(); // B_HORIZONTAL is the default type...

	if (bevelStyle != BEVEL_FLAT)
	{
		if (bevelPosition == BEVEL1) bevel1(sunken);
		else if (bevelPosition == BEVEL2) bevel2(sunken);
	}
}

//===========================================================================

// Fixes to make PipeCross and Rectangle work correctly / nivenh
template <typename T> inline T lmax(T a, T b) { return ((a > b) ? a : b); }
template <typename T> inline T lmin(T a, T b) { return ((a < b) ? a : b); }

//===========================================================================

void BImage::bevel1(bool sunken)
{
	if (width > 2 && height > 2)
	{
		unsigned int count, x, y;
		unsigned int w = ((width * 4) - 4), h = (width * (height-1) * 4);
		unsigned int nextpixel = 4, nextline = (width * 4);

		count = 0;
		for (x = 0; x < width; x++)
		{
			// NOTE: We're using a bottom-up DIB -> origin is the lower-left corner!
			if (!sunken)
			{
				lightenpixel(count+h);		// Upper horizontal bevel for BEVEL_RAISED
				if (x) darkenpixel(count);	// Lower horizontal bevel for BEVEL_RAISED (do not bevelize the first pixel twice!)
			}
			else
			{
				darkenpixel(count+h);		// Upper horizontal bevel for BEVEL_SUNKEN
				if (x) lightenpixel(count);	// Lower horizontal bevel for BEVEL_SUNKEN (do not bevelize the first pixel twice!)
			}

			count += nextpixel;
		}

		count = 0;
		for (y = 0; y < (height-1); y++)
		{
			if (!sunken)
			{
				lightenpixel(count);			// Left vertical bevel for BEVEL_RAISED
				if (y) darkenpixel(count+w);	// Right vertical bevel for BEVEL_RAISED (do not bevelize the first pixel twice!)
			}
			else
			{
				darkenpixel(count);				// Left vertical bevel for BEVEL_SUNKEN
				if (y) lightenpixel(count+w);	// Right vertical bevel for BEVEL_SUNKEN (do not bevelize the first pixel twice!)
			}

			count += nextline;
		}
	}
}

//====================

void BImage::bevel2(bool sunken)
{
	if (width > 4 && height > 4)
	{
		unsigned int count, x, y, w = ((width * 4) - 12), h = (width * (height-3) * 4);
		unsigned int nextpixel = 4, nextline = (width * 4);

		count = nextline + nextpixel;
		for (x = 0; x < (width-2); x++)
		{
			// NOTE: We're using a bottom-up DIB -> origin is the lower-left corner!

			if (!sunken)
			{
				lightenpixel(count+h);		// Upper horizontal bevel for BEVEL_RAISED
				if (x) darkenpixel(count);	// Lower horizontal bevel for BEVEL_RAISED (do not bevelize the first pixel twice!)
			}
			else
			{
				darkenpixel(count+h);		// Upper horizontal bevel for BEVEL_SUNKEN
				if (x) lightenpixel(count);	// Lower horizontal bevel for BEVEL_SUNKEN (do not bevelize the first pixel twice!)
			}

			count += nextpixel;
		}

		count = nextline + nextpixel;
		for (y = 0; y < (height-3); y++)
		{
			if (!sunken)
			{
				lightenpixel(count);			// Left vertical bevel for BEVEL_RAISED
				if (y) darkenpixel(count+w);	// Right vertical bevel for BEVEL_RAISED (do not bevelize the first pixel twice!)
			}
			else
			{
				darkenpixel(count);				// Left vertical bevel for BEVEL_SUNKEN
				if (y) lightenpixel(count+w);	// Right vertical bevel for BEVEL_SUNKEN (do not bevelize the first pixel twice!)
			}

			count += nextline;
		}
	}
}

//====================

void BImage::lightenpixel(unsigned int count)
{
	r = pixels[count + 2];
	rr = r + (r >> 1);
	if (rr < r) rr = ~0;
	g = pixels[count + 1];
	gg = g + (g >> 1);
	if (gg < g) gg = ~0;
	b = pixels[count];
	bb = b + (b >> 1);
	if (bb < b) bb = ~0;

	pixels[count + 2] = rr;
	pixels[count + 1] = gg;
	pixels[count] = bb;
}

//====================

void BImage::darkenpixel(unsigned int count)
{
	r = pixels[count + 2];
	rr = (r >> 2) + (r >> 1);
	if (rr > r) rr = 0;
	g = pixels[count + 1];
	gg = (g >> 2) + (g >> 1);
	if (gg > g) gg = 0;
	b = pixels[count];
	bb = (b >> 2) + (b >> 1);
	if (bb > b) bb = 0;

	pixels[count + 2] = rr;
	pixels[count + 1] = gg;
	pixels[count] = bb;
}

//===========================================================================
// Below:	The original Blackbox (for the X Window System) math code,
//			modified to paint directly into the destination DIBSection! :D
//			The original code is issued under the BSD license,
//			for more info visit http://sourceforge.net/projects/blackboxwm/
//			Copyright (c) 2001 - 2002 Sean 'Shaleh' Perry <shaleh at debian.org>
//			Copyright (c) 1997 - 2000, 2002 Bradley T Hughes <bhughes at trolltech.com>
//===========================================================================

void BImage::dgradient(void)
{
	if (!(height > 2) || !(width > 2))
		return;

	// diagonal gradient code was written by Mike Cole <mike@mydot.com>
	// modified for interlacing by Brad Hughes

	float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0,
	xr = (float) from_red,
	xg = (float) from_green,
	xb = (float) from_blue;

	UINT w = width * 2, h = height * 2, *xt = xtable, *yt = ytable, x, y, count = 0;

	dry = drx = (float) (to_red - from_red);
	dgy = dgx = (float) (to_green - from_green);
	dby = dbx = (float) (to_blue - from_blue);

	// Create X table
	drx /= w;
	dgx /= w;
	dbx /= w;

	for (x = 0; x < width; x++)
	{
		*(xt++) = (unsigned char) (xr);
		*(xt++) = (unsigned char) (xg);
		*(xt++) = (unsigned char) (xb);

		xr += drx;
		xg += dgx;
		xb += dbx;
	}

	// Create Y table
	dry /= h;
	dgy /= h;
	dby /= h;

	for (yt = (ytable + (height * 3) - 1), y = 0; y < height; y++)
	{
		*(yt--) = ((unsigned char) yb);
		*(yt--) = ((unsigned char) yg);
		*(yt--) = ((unsigned char) yr);

		yr += dry;
		yg += dgy;
		yb += dby;
	}

	// Combine tables to create gradient

	if (!interlaced)
	{
		// normal dgradient
		for (yt = ytable, y = 0; y < height; y++, yt += 3)
		{
			for (xt = xtable, x = 0; x < width; x++)
			{
				pixels[count + 2] = *(xt++) + *(yt);
				pixels[count + 1] = *(xt++) + *(yt + 1);
				pixels[count] = *(xt++) + *(yt + 2);
				count += 4;
			}
		}
	}
	else
	{
		// faked interlacing effect
		unsigned char channel, channel2;

		for (yt = ytable, y = 0; y < height; y++, yt += 3)
		{
			for (xt = xtable, x = 0; x < width; x++)
			{
				if (y & 1)
				{
					channel = *(xt++) + *(yt);
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count + 2] = channel2;

					channel = *(xt++) + *(yt + 1);
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count + 1] = channel2;

					channel = *(xt++) + *(yt + 2);
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count] = channel2;
				}
				else
				{
					channel = *(xt++) + *(yt);
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count + 2] = channel2;

					channel = *(xt++) + *(yt + 1);
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count + 1] = channel2;

					channel = *(xt++) + *(yt + 2);
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count] = channel2;
				}
				count += 4;
			}
		}
	}
}

//====================

void BImage::hgradient(void)
{
	if (!(height > 2) || !(width > 2))
		return;

	float drx, dgx, dbx,
	xr = (float) from_red,
	xg = (float) from_green,
	xb = (float) from_blue;

	UINT x, y, count = 0, original = 0;

	drx = (float) (to_red - from_red);
	dgx = (float) (to_green - from_green);
	dbx = (float) (to_blue - from_blue);

	drx /= width;
	dgx /= width;
	dbx /= width;

	if (interlaced && height > 2)
	{
		// faked interlacing effect
		unsigned char channel, channel2;

		for (x = 0; x < width; x++)
		{
			channel = (unsigned char) xr;
			channel2 = (channel >> 1) + (channel >> 2);
			if (channel2 > channel) channel2 = 0;
			pixels[count + 2] = channel2;

			channel = (unsigned char) xg;
			channel2 = (channel >> 1) + (channel >> 2);
			if (channel2 > channel) channel2 = 0;
			pixels[count + 1] = channel2;

			channel = (unsigned char) xb;
			channel2 = (channel >> 1) + (channel >> 2);
			if (channel2 > channel) channel2 = 0;
			pixels[count] = channel2;

			channel = (unsigned char) xr;
			channel2 = channel + (channel >> 3);
			if (channel2 < channel) channel2 = ~0;
			pixels[count + 2 + (width * 4)] = channel2;

			channel = (unsigned char) xg;
			channel2 = channel + (channel >> 3);
			if (channel2 < channel) channel2 = ~0;
			pixels[count + 1 + (width * 4)] = channel2;

			channel = (unsigned char) xb;
			channel2 = channel + (channel >> 3);
			if (channel2 < channel) channel2 = ~0;
			pixels[count + (width * 4)] = channel2;

			xr += drx;
			xg += dgx;
			xb += dbx;

			count += 4;
		}

		count += (width * 4);

		int offset;

		for (y = 2; y < height; y++)
		{
			if (y & 1) offset = (width * 4);
			else offset = 0;

			original = 0;

			for (x =0; x < width; x++)
			{
				pixels[count + 2] = pixels[original + 2 + offset];
				pixels[count + 1] = pixels[original + 1 + offset];
				pixels[count] = pixels[original + offset];

				count += 4;
				original += 4;
			}
		}
	}
	else
	{
		// normal hgradient
		for (x = 0; x < width; x++)
		{
			pixels[count + 2] = (unsigned char) (xr);
			pixels[count + 1] = (unsigned char) (xg);
			pixels[count] = (unsigned char) (xb);

			xr += drx;
			xg += dgx;
			xb += dbx;

			count += 4;
		}

		for (y = 1; y < height; y++)
		{
			original = 0;
			for (x =0; x < width; x++)
			{
				pixels[count + 2] = pixels[original + 2];
				pixels[count + 1] = pixels[original + 1];
				pixels[count] = pixels[original];

				count += 4;
				original += 4;
			}
		}
	}
}

//====================

void BImage::vgradient(void)
{
	if (!(height > 2) || !(width > 2))
		return;

	float dry, dgy, dby,
	yr = (float) to_red,
	yg = (float) to_green,
	yb = (float) to_blue;

	UINT x, y, count = 0;

	dry = (float) (from_red - to_red);
	dgy = (float) (from_green - to_green);
	dby = (float) (from_blue - to_blue);

	dry /= height;
	dgy /= height;
	dby /= height;

	if (interlaced)
	{
		// faked interlacing effect
		unsigned char channel, channel2;

		for (y = 0; y < height; y++)
		{
			for (x =0; x < width; x++)
			{
				if (y & 1)
				{
					channel = (unsigned char) yr;
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count + 2] = channel2;

					channel = (unsigned char) yg;
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count + 1] = channel2;

					channel = (unsigned char) yb;
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count] = channel2;
				}
				else
				{
					channel = (unsigned char) yr;
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count + 2] = channel2;

					channel = (unsigned char) yg;
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count + 1] = channel2;

					channel = (unsigned char) yb;
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count] = channel2;
				}
				count += 4;
			}
			yr += dry;
			yg += dgy;
			yb += dby;
		}
	}
	else
	{
		// normal vgradient
		for (y =0; y < height ; y++)
		{
			for (x =0; x < width; x++)
			{
				pixels[count + 2] = (unsigned char) yr;
				pixels[count + 1] = (unsigned char) yg;
				pixels[count] = (unsigned char) yb;

				count += 4;
			}
			yr += dry;
			yg += dgy;
			yb += dby;
		}
	}
}

//====================

void BImage::pgradient(void)
{
	if (!(height > 2) || !(width > 2))
		return;

	// pyramid gradient -  based on original dgradient, written by
	// Mosfet (mosfet@kde.org)
	// adapted from kde sources for Blackbox by Brad Hughes

	float yr, yg, yb, drx, dgx, dbx, dry, dgy, dby, xr, xg, xb;
	int rsign, gsign, bsign;
	UINT tr = to_red, tg = to_green, tb = to_blue, *xt = xtable, *yt = ytable, x, y, count = 0;

	dry = drx = (float) (to_red - from_red);
	dgy = dgx = (float) (to_green - from_green);
	dby = dbx = (float) (to_blue - from_blue);

	rsign = (drx < 0) ? -1 : 1;
	gsign = (dgx < 0) ? -1 : 1;
	bsign = (dbx < 0) ? -1 : 1;

	xr = yr = (drx / 2);
	xg = yg = (dgx / 2);
	xb = yb = (dbx / 2);

	// Create X table
	drx /= width;
	dgx /= width;
	dbx /= width;

	for (x = 0; x < width; x++)
	{
		*(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
		*(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
		*(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);

		xr -= drx;
		xg -= dgx;
		xb -= dbx;
	}

	// Create Y table
	dry /= height;
	dgy /= height;
	dby /= height;

	for (y = 0; y < height; y++)
	{
		*(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
		*(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
		*(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));

		yr -= dry;
		yg -= dgy;
		yb -= dby;
	}

	// Combine tables to create gradient

	if (!interlaced)
	{
		// normal pgradient
		for (yt = ytable, y = 0; y < height; y++, yt += 3)
		{
			for (xt = xtable, x = 0; x < width; x++)
			{
				pixels[count + 2] = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
				pixels[count + 1] = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
				pixels[count] = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
				count += 4;
			}
		}
	}
	else
	{
		// faked interlacing effect
		unsigned char channel, channel2;

		for (yt = ytable, y = 0; y < height; y++, yt += 3)
		{
			for (xt = xtable, x = 0; x < width; x++)
			{
				if (y & 1)
				{
					channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count + 2] = channel2;

					channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count + 1] = channel2;

					channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count] = channel2;
				}
				else
				{
					channel = (unsigned char) (tr - (rsign * (*(xt++) + *(yt))));
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count + 2] = channel2;

					channel = (unsigned char) (tg - (gsign * (*(xt++) + *(yt + 1))));
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count + 1] = channel2;

					channel = (unsigned char) (tb - (bsign * (*(xt++) + *(yt + 2))));
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count] = channel2;
				}
				count += 4;
			}
		}
	}
}

//====================

void BImage::rgradient(void)
{
	if (!(height > 2) || !(width > 2))
		return;

	// rectangle gradient -  based on original dgradient, written by
	// Mosfet (mosfet@kde.org)
	// adapted from kde sources for Blackbox by Brad Hughes

	float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb;
	int rsign, gsign, bsign;
	unsigned int tr = to_red, tg = to_green, tb = to_blue, *xt = xtable, *yt = ytable;

	UINT x, y, count = 0;

	dry = drx = (float) (to_red - from_red);
	dgy = dgx = (float) (to_green - from_green);
	dby = dbx = (float) (to_blue - from_blue);

	rsign = (drx < 0) ? -2 : 2;
	gsign = (dgx < 0) ? -2 : 2;
	bsign = (dbx < 0) ? -2 : 2;

	xr = yr = (drx / 2);
	xg = yg = (dgx / 2);
	xb = yb = (dbx / 2);

	// Create X table
	drx /= width;
	dgx /= width;
	dbx /= width;

	for (x = 0; x < width; x++)
	{
		*(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
		*(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
		*(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);

		xr -= drx;
		xg -= dgx;
		xb -= dbx;
	}

	// Create Y table
	dry /= height;
	dgy /= height;
	dby /= height;

	for (y = 0; y < height; y++)
	{
		*(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
		*(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
		*(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));

		yr -= dry;
		yg -= dgy;
		yb -= dby;
	}

	// Combine tables to create gradient

	if (!interlaced)
	{
		// normal rgradient
		for (yt = ytable, y = 0; y < height; y++, yt += 3)
		{
			for (xt = xtable, x = 0; x < width; x++)
			{
				pixels[count + 2] = (unsigned char) (tr - (rsign * lmax(*(xt++), *(yt))));
				pixels[count + 1] = (unsigned char) (tg - (gsign * lmax(*(xt++), *(yt + 1))));
				pixels[count] = (unsigned char) (tb - (bsign * lmax(*(xt++), *(yt + 2))));
				count += 4;
			}
		}
	}
	else
	{
		// faked interlacing effect
		unsigned char channel, channel2;

		for (yt = ytable, y = 0; y < height; y++, yt += 3)
		{
			for (xt = xtable, x = 0; x < width; x++)
			{
				if (y & 1)
				{
					channel = (unsigned char) (tr - (rsign * lmax(*(xt++), *(yt))));
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count + 2] = channel2;

					channel = (unsigned char) (tg - (gsign * lmax(*(xt++), *(yt + 1))));
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count + 1] = channel2;

					channel = (unsigned char) (tb - (bsign * lmax(*(xt++), *(yt + 2))));
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count] = channel2;
				}
				else
				{
					channel = (unsigned char) (tr - (rsign * lmax(*(xt++), *(yt))));
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count + 2] = channel2;

					channel = (unsigned char) (tg - (gsign * lmax(*(xt++), *(yt + 1))));
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count + 1] = channel2;

					channel = (unsigned char) (tb - (bsign * lmax(*(xt++), *(yt + 2))));
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count] = channel2;
				}
				count += 4;
			}
		}
	}
}

//====================

void BImage::egradient(void)
{
	if (!(height > 2) || !(width > 2))
		return;

	// elliptic gradient -  based on original dgradient, written by
	// Mosfet (mosfet@kde.org)
	// adapted from kde sources for Blackbox by Brad Hughes

	float drx, dgx, dbx, dry, dgy, dby, yr, yg, yb, xr, xg, xb;
	int rsign, gsign, bsign;
	unsigned int *xt = xtable, *yt = ytable,
	tr = (unsigned long) to_red,
	tg = (unsigned long) to_green,
	tb = (unsigned long) to_blue;

	UINT x, y, count = 0;

	dry = drx = (float) (to_red - from_red);
	dgy = dgx = (float) (to_green - from_green);
	dby = dbx = (float) (to_blue - from_blue);

	rsign = (drx < 0) ? -1 : 1;
	gsign = (dgx < 0) ? -1 : 1;
	bsign = (dbx < 0) ? -1 : 1;

	xr = yr = (drx / 2);
	xg = yg = (dgx / 2);
	xb = yb = (dbx / 2);

	// Create X table
	drx /= width;
	dgx /= width;
	dbx /= width;

	for (x = 0; x < width; x++)
	{
		*(xt++) = (unsigned long) (xr * xr);
		*(xt++) = (unsigned long) (xg * xg);
		*(xt++) = (unsigned long) (xb * xb);

		xr -= drx;
		xg -= dgx;
		xb -= dbx;
	}

	// Create Y table
	dry /= height;
	dgy /= height;
	dby /= height;

	for (y = 0; y < height; y++)
	{
		*(yt++) = (unsigned long) (yr * yr);
		*(yt++) = (unsigned long) (yg * yg);
		*(yt++) = (unsigned long) (yb * yb);

		yr -= dry;
		yg -= dgy;
		yb -= dby;
	}

	// Combine tables to create gradient

	if (!interlaced)
	{
		// normal egradient
		for (yt = ytable, y = 0; y < height; y++, yt += 3)
		{
			for (xt = xtable, x = 0; x < width; x++)
			{
				pixels[count + 2] = (unsigned char)
				(tr - (rsign * getSqrt(*(xt++) + *(yt))));
				pixels[count + 1] = (unsigned char)
				(tg - (gsign * getSqrt(*(xt++) + *(yt + 1))));
				pixels[count] = (unsigned char)
				(tb - (bsign * getSqrt(*(xt++) + *(yt + 2))));
				count += 4;
			}
		}
	}
	else
	{
		// faked interlacing effect
		unsigned char channel, channel2;

		for (yt = ytable, y = 0; y < height; y++, yt += 3)
		{
			for (xt = xtable, x = 0; x < width; x++)
			{
				if (y & 1)
				{
					channel = (unsigned char)
					(tr - (rsign * getSqrt(*(xt++) + *(yt))));
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count + 2] = channel2;

					channel = (unsigned char)
					(tg - (gsign * getSqrt(*(xt++) + *(yt + 1))));
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count + 1] = channel2;

					channel = (unsigned char)
					(tb - (bsign * getSqrt(*(xt++) + *(yt + 2))));
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count] = channel2;
				}
				else
				{
					channel = (unsigned char)
					(tr - (rsign * getSqrt(*(xt++) + *(yt))));
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count + 2] = channel2;

					channel = (unsigned char)
					(tg - (gsign * getSqrt(*(xt++) + *(yt + 1))));
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count + 1] = channel2;

					channel = (unsigned char)
					(tb - (bsign * getSqrt(*(xt++) + *(yt + 2))));
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count] = channel2;
				}
				count += 4;
			}
		}
	}
}

//====================

void BImage::pcgradient(void)
{
	if(!(height > 4) || !(width > 4))
		return;

	// pipe cross gradient - based on original dgradient, written by
	// Mosfet (mosfet@kde.org)
	// adapted from kde sources for Blackbox by Brad Hughes

	float drx, dgx, dbx, dry, dgy, dby, xr, xg, xb, yr, yg, yb;
	int rsign, gsign, bsign;
	unsigned int *xt = xtable, *yt = ytable, tr = to_red, tg = to_green, tb = to_blue;

	UINT x, y, count = 0;

	dry = drx = (float) (to_red - from_red);
	dgy = dgx = (float) (to_green - from_green);
	dby = dbx = (float) (to_blue - from_blue);

	rsign = (drx < 0) ? -2 : 2;
	gsign = (dgx < 0) ? -2 : 2;
	bsign = (dbx < 0) ? -2 : 2;

	xr = yr = (drx / 2);
	xg = yg = (dgx / 2);
	xb = yb = (dbx / 2);

	// Create X table
	drx /= width;
	dgx /= width;
	dbx /= width;

	for (x = 0; x < width; x++)
	{
		*(xt++) = (unsigned char) ((xr < 0) ? -xr : xr);
		*(xt++) = (unsigned char) ((xg < 0) ? -xg : xg);
		*(xt++) = (unsigned char) ((xb < 0) ? -xb : xb);

		xr -= drx;
		xg -= dgx;
		xb -= dbx;
	}

	// Create Y table
	dry /= height;
	dgy /= height;
	dby /= height;

	for (y = 0; y < height; y++)
	{
		*(yt++) = ((unsigned char) ((yr < 0) ? -yr : yr));
		*(yt++) = ((unsigned char) ((yg < 0) ? -yg : yg));
		*(yt++) = ((unsigned char) ((yb < 0) ? -yb : yb));

		yr -= dry;
		yg -= dgy;
		yb -= dby;
	}

	// Combine tables to create gradient

	if (!interlaced)
	{
		// normal pcgradient
		for (yt = ytable, y = 0; y < height; y++, yt += 3)
		{
			for (xt = xtable, x = 0; x < width; x++)
			{
				pixels[count + 2] = (unsigned char) (tr - (rsign * lmin(*(xt++), *(yt))));
				pixels[count + 1] = (unsigned char) (tg - (gsign * lmin(*(xt++), *(yt + 1))));
				pixels[count] = (unsigned char) (tb - (bsign * lmin(*(xt++), *(yt + 2))));
				count += 4;
			}
		}
	}
	else
	{
		// faked interlacing effect
		unsigned char channel, channel2;

		for (yt = ytable, y = 0; y < height; y++, yt += 3)
		{
			for (xt = xtable, x = 0; x < width; x++)
			{
				if (y & 1)
				{
					channel = (unsigned char) (tr - (rsign * lmin(*(xt++), *(yt))));
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count + 2] = channel2;

					channel = (unsigned char) (tg - (bsign * lmin(*(xt++), *(yt + 1))));
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count + 1] = channel2;

					channel = (unsigned char) (tb - (gsign * lmin(*(xt++), *(yt + 2))));
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count] = channel2;
				}
				else
				{
					channel = (unsigned char) (tr - (rsign * lmin(*(xt++), *(yt))));
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count + 2] = channel2;

					channel = (unsigned char) (tg - (gsign * lmin(*(xt++), *(yt + 1))));
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count + 1] = channel2;

					channel = (unsigned char) (tb - (bsign * lmin(*(xt++), *(yt + 2))));
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count] = channel2;
				}
				count += 4;
			}
		}
	}
}

//====================

void BImage::cdgradient(void)
{
	if (!(height > 2) || !(width > 2))
		return;

	// cross diagonal gradient -  based on original dgradient, written by
	// Mosfet (mosfet@kde.org)
	// adapted from kde sources for Blackbox by Brad Hughes

	float drx, dgx, dbx, dry, dgy, dby, yr = 0.0, yg = 0.0, yb = 0.0,
	xr = (float) from_red,
	xg = (float) from_green,
	xb = (float) from_blue;

	UINT w = width * 2, h = height * 2, *xt, *yt, x, y, count = 0;

	dry = drx = (float) (to_red - from_red);
	dgy = dgx = (float) (to_green - from_green);
	dby = dbx = (float) (to_blue - from_blue);

	// Create X table
	drx /= w;
	dgx /= w;
	dbx /= w;

	for (xt = (xtable + (width * 3) - 1), x = 0; x < width; x++)
	{
		*(xt--) = (unsigned char) xb;
		*(xt--) = (unsigned char) xg;
		*(xt--) = (unsigned char) xr;

		xr += drx;
		xg += dgx;
		xb += dbx;
	}

	// Create Y table
	dry /= h;
	dgy /= h;
	dby /= h;

	for (yt = (ytable + (height * 3) - 1), y = 0; y < height; y++)
	{
		*(yt--) = ((unsigned char) yb);
		*(yt--) = ((unsigned char) yg);
		*(yt--) = ((unsigned char) yr);

		yr += dry;
		yg += dgy;
		yb += dby;
	}

	// Combine tables to create gradient

	if (!interlaced)
	{
		// normal cdgradient
		for (yt = ytable, y = 0; y < height; y++, yt += 3)
		{
			for (xt = xtable, x = 0; x < width; x++)
			{
				pixels[count + 2] = *(xt++) + *(yt);
				pixels[count + 1] = *(xt++) + *(yt + 1);
				pixels[count] = *(xt++) + *(yt + 2);
				count += 4;
			}
		}
	}
	else
	{
		// faked interlacing effect
		unsigned char channel, channel2;

		for (yt = ytable, y = 0; y < height; y++, yt += 3)
		{
			for (xt = xtable, x = 0; x < width; x++)
			{
				if (y & 1)
				{
					channel = *(xt++) + *(yt);
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count + 2] = channel2;

					channel = *(xt++) + *(yt + 1);
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count + 1] = channel2;

					channel = *(xt++) + *(yt + 2);
					channel2 = (channel >> 1) + (channel >> 2);
					if (channel2 > channel) channel2 = 0;
					pixels[count] = channel2;
				}
				else
				{
					channel = *(xt++) + *(yt);
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count + 2] = channel2;

					channel = *(xt++) + *(yt + 1);
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count + 1] = channel2;

					channel = *(xt++) + *(yt + 2);
					channel2 = channel + (channel >> 3);
					if (channel2 < channel) channel2 = ~0;
					pixels[count] = channel2;
				}
				count += 4;
			}
		}
	}
}

//===========================================================================

static unsigned long bsqrt(unsigned long x)
{
	if (x <= 0) return 0;
	if (x == 1) return 1;

	unsigned long r = x >> 1;
	unsigned long q;

	while (1)
	{
		q = x / r;
		if (q >= r) return r;
		r = (r + q) >> 1;
	}
}

//====================

unsigned long getSqrt(unsigned int x)
{
	if (!sqrt_table)
	{
		// build sqrt table for use with elliptic gradient
		sqrt_table = new unsigned long[(256 * 256 * 2) + 1];

		for (int i = 0; i < (256 * 256 * 2); i++)
			*(sqrt_table + i) = bsqrt(i);
	}
	return (*(sqrt_table + x));
}

//===========================================================================





syntax highlighting by

w e b c p p
web c plus plus