#include "stdafx.h"
#include "PPDrawManager.h"

/*
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
*/

/*
	DIBs use RGBQUAD format:
		0xbb 0xgg 0xrr 0x00
*/
#ifndef CLR_TO_RGBQUAD
#define CLR_TO_RGBQUAD(clr)     (RGB(GetBValue(clr), GetGValue(clr), GetRValue(clr)))
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CPPDrawManager::CPPDrawManager()
{

}

CPPDrawManager::~CPPDrawManager()
{

}

void CPPDrawManager::GetSizeOfIcon(HICON hIcon, LPSIZE pSize) const
{
	pSize->cx = 0;
	pSize->cy = 0;
	if (hIcon != NULL)
	{
		ICONINFO ii;
		// Gets icon dimension
		::ZeroMemory(&ii, sizeof(ICONINFO));
		if (::GetIconInfo(hIcon, &ii))
		{
			pSize->cx = (DWORD)(ii.xHotspot * 2);
			pSize->cy = (DWORD)(ii.yHotspot * 2);
			//release icon mask bitmaps
			if(ii.hbmMask)
				::DeleteObject(ii.hbmMask);
			if(ii.hbmColor)
				::DeleteObject(ii.hbmColor);
		} //if
	} //if
} //End GetSizeOfIcon

void CPPDrawManager::GetSizeOfBitmap(HBITMAP hBitmap, LPSIZE pSize) const
{
	pSize->cx = 0;
	pSize->cy = 0;
	if (hBitmap != NULL)
	{
		BITMAP	csBitmapSize;
		// Get bitmap size
		int nRetValue = ::GetObject(hBitmap, sizeof(csBitmapSize), &csBitmapSize);
		if (nRetValue)
		{
			pSize->cx = (DWORD)csBitmapSize.bmWidth;
			pSize->cy = (DWORD)csBitmapSize.bmHeight;
		} //if
	} //if
} //End GetSizeOfBitmap

void CPPDrawManager::AlphaBitBlt(HDC hDestDC, int nDestX, int nDestY, DWORD dwWidth, DWORD dwHeight, HDC hSrcDC, int nSrcX, int nSrcY, int percent /* = 100 */)
{
	_ASSERT ((NULL != hDestDC) || (NULL != hSrcDC));

	if (percent >= 100)
	{
		::BitBlt(hDestDC, nDestX, nDestY, dwWidth, dwHeight, hSrcDC, nSrcX, nSrcY, SRCCOPY);
		return;
	} //if

	HDC hTempDC = ::CreateCompatibleDC(hDestDC);
	if (NULL == hTempDC)
		return;
	
	//Creates Source DIB
	LPBITMAPINFO lpbiSrc;
	// Fill in the BITMAPINFOHEADER
	lpbiSrc = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
	lpbiSrc->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	lpbiSrc->bmiHeader.biWidth = dwWidth;
	lpbiSrc->bmiHeader.biHeight = dwHeight;
	lpbiSrc->bmiHeader.biPlanes = 1;
	lpbiSrc->bmiHeader.biBitCount = 32;
	lpbiSrc->bmiHeader.biCompression = BI_RGB;
	lpbiSrc->bmiHeader.biSizeImage = dwWidth * dwHeight;
	lpbiSrc->bmiHeader.biXPelsPerMeter = 0;
	lpbiSrc->bmiHeader.biYPelsPerMeter = 0;
	lpbiSrc->bmiHeader.biClrUsed = 0;
	lpbiSrc->bmiHeader.biClrImportant = 0;
	
	COLORREF* pSrcBits = NULL;
	HBITMAP hSrcDib = CreateDIBSection (
		hSrcDC, lpbiSrc, DIB_RGB_COLORS, (void **)&pSrcBits,
		NULL, NULL);
	
	if ((NULL != hSrcDib) && (NULL != pSrcBits))
	{
		HBITMAP hOldTempBmp = (HBITMAP)::SelectObject (hTempDC, hSrcDib);
		::BitBlt (hTempDC, 0, 0, dwWidth, dwHeight, hSrcDC, nSrcX, nSrcY, SRCCOPY);
		::SelectObject (hTempDC, hOldTempBmp);
		
		//Creates Destination DIB
		LPBITMAPINFO lpbiDest;
		// Fill in the BITMAPINFOHEADER
		lpbiDest = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
		lpbiDest->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
		lpbiDest->bmiHeader.biWidth = dwWidth;
		lpbiDest->bmiHeader.biHeight = dwHeight;
		lpbiDest->bmiHeader.biPlanes = 1;
		lpbiDest->bmiHeader.biBitCount = 32;
		lpbiDest->bmiHeader.biCompression = BI_RGB;
		lpbiDest->bmiHeader.biSizeImage = dwWidth * dwHeight;
		lpbiDest->bmiHeader.biXPelsPerMeter = 0;
		lpbiDest->bmiHeader.biYPelsPerMeter = 0;
		lpbiDest->bmiHeader.biClrUsed = 0;
		lpbiDest->bmiHeader.biClrImportant = 0;
		
		COLORREF* pDestBits = NULL;
		HBITMAP hDestDib = CreateDIBSection (
			hDestDC, lpbiDest, DIB_RGB_COLORS, (void **)&pDestBits,
			NULL, NULL);
		
		if ((NULL != hDestDib) && (NULL != pDestBits))
		{
			::SelectObject (hTempDC, hDestDib);
			::BitBlt (hTempDC, 0, 0, dwWidth, dwHeight, hDestDC, nDestX, nDestY, SRCCOPY);
			::SelectObject (hTempDC, hOldTempBmp);

			double src_darken = (double)percent / 100.0;
			double dest_darken = 1.0 - src_darken;
			
			for (DWORD pixel = 0; pixel < dwWidth * dwHeight; pixel++, pSrcBits++, pDestBits++)
			{
				*pDestBits = PixelAlpha(*pSrcBits, src_darken, *pDestBits, dest_darken);
			} //for
			
			::SelectObject (hTempDC, hDestDib);
			::BitBlt (hDestDC, nDestX, nDestY, dwWidth, dwHeight, hTempDC, 0, 0, SRCCOPY);
			::SelectObject (hTempDC, hOldTempBmp);

			delete lpbiDest;
			::DeleteObject(hDestDib);
		} //if
		delete lpbiSrc;
		::DeleteObject(hSrcDib);
	} //if

	::DeleteDC(hTempDC);
} //End AlphaBitBlt

void CPPDrawManager::AlphaChannelBitBlt(HDC hDestDC, int nDestX, int nDestY, DWORD dwWidth, DWORD dwHeight, HDC hSrcDC, int nSrcX, int nSrcY)
{
	_ASSERT ((NULL != hDestDC) || (NULL != hSrcDC));

	HDC hTempDC = ::CreateCompatibleDC(hDestDC);
	if (NULL == hTempDC)
		return;
	
	//Creates Source DIB
	LPBITMAPINFO lpbiSrc;
	// Fill in the BITMAPINFOHEADER
	lpbiSrc = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
	lpbiSrc->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	lpbiSrc->bmiHeader.biWidth = dwWidth;
	lpbiSrc->bmiHeader.biHeight = dwHeight;
	lpbiSrc->bmiHeader.biPlanes = 1;
	lpbiSrc->bmiHeader.biBitCount = 32;
	lpbiSrc->bmiHeader.biCompression = BI_RGB;
	lpbiSrc->bmiHeader.biSizeImage = dwWidth * dwHeight;
	lpbiSrc->bmiHeader.biXPelsPerMeter = 0;
	lpbiSrc->bmiHeader.biYPelsPerMeter = 0;
	lpbiSrc->bmiHeader.biClrUsed = 0;
	lpbiSrc->bmiHeader.biClrImportant = 0;
	
	COLORREF* pSrcBits = NULL;
	HBITMAP hSrcDib = CreateDIBSection (
		hSrcDC, lpbiSrc, DIB_RGB_COLORS, (void **)&pSrcBits,
		NULL, NULL);
	
	if ((NULL != hSrcDib) && (NULL != pSrcBits))
	{
		HBITMAP hOldTempBmp = (HBITMAP)::SelectObject (hTempDC, hSrcDib);
		::BitBlt (hTempDC, 0, 0, dwWidth, dwHeight, hSrcDC, nSrcX, nSrcY, SRCCOPY);
		::SelectObject (hTempDC, hOldTempBmp);
		
		//Creates Destination DIB
		LPBITMAPINFO lpbiDest;
		// Fill in the BITMAPINFOHEADER
		lpbiDest = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
		lpbiDest->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
		lpbiDest->bmiHeader.biWidth = dwWidth;
		lpbiDest->bmiHeader.biHeight = dwHeight;
		lpbiDest->bmiHeader.biPlanes = 1;
		lpbiDest->bmiHeader.biBitCount = 32;
		lpbiDest->bmiHeader.biCompression = BI_RGB;
		lpbiDest->bmiHeader.biSizeImage = dwWidth * dwHeight;
		lpbiDest->bmiHeader.biXPelsPerMeter = 0;
		lpbiDest->bmiHeader.biYPelsPerMeter = 0;
		lpbiDest->bmiHeader.biClrUsed = 0;
		lpbiDest->bmiHeader.biClrImportant = 0;
		
		COLORREF* pDestBits = NULL;
		HBITMAP hDestDib = CreateDIBSection (
			hDestDC, lpbiDest, DIB_RGB_COLORS, (void **)&pDestBits,
			NULL, NULL);
		
		if ((NULL != hDestDib) && (NULL != pDestBits))
		{
			::SelectObject (hTempDC, hDestDib);
			::BitBlt (hTempDC, 0, 0, dwWidth, dwHeight, hDestDC, nDestX, nDestY, SRCCOPY);
			::SelectObject (hTempDC, hOldTempBmp);

			double src_darken;
			BYTE nAlpha;
			
			for (DWORD pixel = 0; pixel < dwWidth * dwHeight; pixel++, pSrcBits++, pDestBits++)
			{
				nAlpha = LOBYTE(*pSrcBits >> 24);
				src_darken = (double)nAlpha / 255.0;
				*pDestBits = PixelAlpha(*pSrcBits, src_darken, *pDestBits, 1.0 - src_darken);
			} //for
			
			::SelectObject (hTempDC, hDestDib);
			::BitBlt (hDestDC, nDestX, nDestY, dwWidth, dwHeight, hTempDC, 0, 0, SRCCOPY);
			::SelectObject (hTempDC, hOldTempBmp);

			delete lpbiDest;
			::DeleteObject(hDestDib);
		} //if
		delete lpbiSrc;
		::DeleteObject(hSrcDib);
	} //if

	::DeleteDC(hTempDC);
} //End of AlphaChannelBitBlt

HBITMAP CPPDrawManager::CreateImageEffect(HBITMAP hBitmap, DWORD dwWidth, DWORD dwHeight, DWORD dwEffect, BOOL bUseMask /* = TRUE */, COLORREF clrMask /* = RGB(255, 0, 255) */, COLORREF clrMono /* = RGB(255, 255, 255) */)
{
	HBITMAP hOldSrcBmp = NULL;
	HBITMAP hOldResBmp = NULL;  
	HDC hMainDC = NULL;
	HDC hSrcDC = NULL;
	HDC hResDC = NULL;
	
	hMainDC = ::GetDC(NULL);
	hSrcDC = ::CreateCompatibleDC(hMainDC);
	hResDC = ::CreateCompatibleDC(hMainDC);

	hOldSrcBmp = (HBITMAP)::SelectObject(hSrcDC, hBitmap);

	LPBITMAPINFO lpbi;

	// Fill in the BITMAPINFOHEADER
	lpbi = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
	lpbi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	lpbi->bmiHeader.biWidth = dwWidth;
	lpbi->bmiHeader.biHeight = dwHeight;
	lpbi->bmiHeader.biPlanes = 1;
	lpbi->bmiHeader.biBitCount = 32;
	lpbi->bmiHeader.biCompression = BI_RGB;
	lpbi->bmiHeader.biSizeImage = dwWidth * dwHeight;
	lpbi->bmiHeader.biXPelsPerMeter = 0;
	lpbi->bmiHeader.biYPelsPerMeter = 0;
	lpbi->bmiHeader.biClrUsed = 0;
	lpbi->bmiHeader.biClrImportant = 0;

	COLORREF* pBits = NULL;
	HBITMAP hDibBmp = CreateDIBSection (
		hSrcDC, lpbi, DIB_RGB_COLORS, (void **)&pBits,
		NULL, NULL);

	if (hDibBmp == NULL || pBits == NULL)
	{
		delete lpbi;
		_ASSERT (FALSE);
		return NULL;
	} //if

	hOldResBmp = (HBITMAP)::SelectObject (hResDC, hDibBmp);
	::BitBlt (hResDC, 0, 0, dwWidth, dwHeight, hSrcDC, 0, 0, SRCCOPY);

	clrMask = CLR_TO_RGBQUAD(clrMask);
	clrMono = CLR_TO_RGBQUAD(clrMono);

	DWORD dwAlpha;
	for (DWORD pixel = 0; pixel < dwWidth * dwHeight; pixel++, *pBits++)
	{
		COLORREF color = (COLORREF)*pBits;
		//ENG: Extract an original alpha value
		dwAlpha = color & 0xFF000000;
		if (dwAlpha != 0) 
			m_bIsAlpha = TRUE;
		if (bUseMask && (color == clrMask))
		{
			//This is transparent area
			color = RGB(0, 0, 0);
		}
		else 
		{
			//ENG: Color conversion
			if (dwEffect & IMAGE_EFFECT_GRAYEN) color = GrayMirrorColor(color);
			if (dwEffect & IMAGE_EFFECT_DARKEN) color = DarkenColor(color, 0.75);
			if (dwEffect & IMAGE_EFFECT_LIGHTEN) color = LightenColor(color, 0.25);
			if (dwEffect & IMAGE_EFFECT_MONOCHROME) color = clrMono;
		} //if
		if (dwEffect & IMAGE_EFFECT_INVERT) color = InvertColor(color);
		//ENG: Merges a color with an original alpha value
		*pBits = (color | dwAlpha);
	} //for

	::SelectObject(hSrcDC, hOldSrcBmp);
	::SelectObject(hResDC, hOldResBmp);
	::DeleteDC(hSrcDC);
	::DeleteDC(hResDC);
	::ReleaseDC(NULL, hMainDC);
	
	delete lpbi;

	return hDibBmp;
} //End CreateImageEffect

//----------------------------------------------------------
// CPPDrawManager::GrayMirrorColor()
//	Graying color in RGBQUAD format
//----------------------------------------------------------
// Parameter:
//	clrColor	- RGBQUAD value from DIB
// Return value:
//	A grayed color in the RGBQUAD format
//----------------------------------------------------------
COLORREF CPPDrawManager::GrayMirrorColor(COLORREF clrColor)
{
	BYTE nGrayColor = (BYTE)((GetBValue(clrColor) * 0.299) + (GetGValue(clrColor) * 0.587) + (GetRValue(clrColor) * 0.114));
	
	return RGB(nGrayColor, nGrayColor, nGrayColor);
} //End of GrayMirrorColor

COLORREF CPPDrawManager::GrayColor(COLORREF clrColor)
{
	BYTE nGrayColor = (BYTE)((GetRValue(clrColor) * 0.299) + (GetGValue(clrColor) * 0.587) + (GetBValue(clrColor) * 0.114));
	
	return RGB(nGrayColor, nGrayColor, nGrayColor);
} //End GrayColor

COLORREF CPPDrawManager::InvertColor(COLORREF clrColor)
{
	return RGB(255 - GetRValue(clrColor), 255 - GetGValue(clrColor), 255 - GetBValue(clrColor));
} //End InvertColor

COLORREF CPPDrawManager::DarkenColor(COLORREF clrColor, double darken)
{
	if (darken >= 0.0 && darken < 1.0)
	{
		BYTE color_r, color_g, color_b;
		color_r = (BYTE)(GetRValue(clrColor) * darken);
		color_g = (BYTE)(GetGValue(clrColor) * darken);
		color_b = (BYTE)(GetBValue(clrColor) * darken);
		clrColor = RGB(color_r, color_g, color_b);
	} //if
	
	return clrColor;
} //End DarkenColor

COLORREF CPPDrawManager::LightenColor(COLORREF clrColor, double lighten)
{
	if (lighten > 0.0 && lighten <= 1.0)
	{
		BYTE color_r, color_g, color_b;
		
		lighten += 1.0;
		color_r = (BYTE)min((DWORD)GetRValue(clrColor) * lighten, 255.0);
		color_g = (BYTE)min((DWORD)GetGValue(clrColor) * lighten, 255.0);
		color_b = (BYTE)min((DWORD)GetBValue(clrColor) * lighten, 255.0);
		clrColor = RGB(color_r, color_g, color_b);
/*		
		lighten *= 255
		color_r = (BYTE)max(0, min(255, (int)((color_r - 128) * 2.0 + 128 + lighten)));
		color_g = (BYTE)max(0, min(255, (int)((color_g - 128) * 2.0 + 128 + lighten)));
		color_b = (BYTE)max(0, min(255, (int)((color_b - 128) * 2.0 + 128 + lighten)));
		clrColor = RGB(color_r, color_g, color_b);
*/
	} //if
	
	return clrColor;
} //End LightenColor

COLORREF CPPDrawManager::PixelAlpha(COLORREF clrSrc, double src_darken, COLORREF clrDest, double dest_darken)
{
	return RGB (GetRValue (clrSrc) * src_darken + GetRValue (clrDest) * dest_darken, 
				GetGValue (clrSrc) * src_darken + GetGValue (clrDest) * dest_darken, 
				GetBValue (clrSrc) * src_darken + GetBValue (clrDest) * dest_darken);
	
} //End PixelAlpha

HICON CPPDrawManager::StretchIcon(HICON hIcon, DWORD dwWidth, DWORD dwHeight)
{
	HICON hStretchedIcon = NULL;
	HDC   hMainDC = NULL;
	HDC   hSrcDC = NULL;
	HDC   hDestDC = NULL;
	BITMAP bmp;
	HBITMAP hOldSrcBitmap = NULL;
	HBITMAP hOldDestBitmap = NULL;
	ICONINFO csOriginal, csStretched;
	
	if (!::GetIconInfo(hIcon, &csOriginal))
		return FALSE;
	
	hMainDC = ::GetDC(NULL);
	hSrcDC = ::CreateCompatibleDC(hMainDC);
	hDestDC = ::CreateCompatibleDC(hMainDC);
	
	if ((NULL == hMainDC) || (NULL == hSrcDC) || (NULL == hDestDC))
		return NULL;
	
	if (::GetObject(csOriginal.hbmColor, sizeof(BITMAP), &bmp))
	{
		DWORD	dwWidthOrg = csOriginal.xHotspot * 2;
		DWORD	dwHeightOrg = csOriginal.yHotspot * 2;
		
		csStretched.hbmColor = ::CreateBitmap(dwWidth, dwHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
		if (NULL != csStretched.hbmColor)
		{
			hOldSrcBitmap = (HBITMAP)::SelectObject(hSrcDC, csOriginal.hbmColor);
			hOldDestBitmap = (HBITMAP)::SelectObject(hDestDC, csStretched.hbmColor);
			::StretchBlt(hDestDC, 0, 0, dwWidth, dwHeight, hSrcDC, 0, 0, dwWidthOrg, dwHeightOrg, SRCCOPY);
			if (::GetObject(csOriginal.hbmMask, sizeof(BITMAP), &bmp))
			{
				csStretched.hbmMask = ::CreateBitmap(dwWidth, dwHeight, bmp.bmPlanes, bmp.bmBitsPixel, NULL);
				if (NULL != csStretched.hbmMask)
				{
					::SelectObject(hSrcDC, csOriginal.hbmMask);
					::SelectObject(hDestDC, csStretched.hbmMask);
					::StretchBlt(hDestDC, 0, 0, dwWidth, dwHeight, hSrcDC, 0, 0, dwWidthOrg, dwHeightOrg, SRCCOPY);
				} //if
			} //if
			::SelectObject(hSrcDC, hOldSrcBitmap);
			::SelectObject(hDestDC, hOldDestBitmap);
			csStretched.fIcon = TRUE;
			hStretchedIcon = ::CreateIconIndirect(&csStretched);
		} //if
		::DeleteObject(csStretched.hbmColor);
		::DeleteObject(csStretched.hbmMask);
	} //if
	
	::DeleteObject(csOriginal.hbmColor);
	::DeleteObject(csOriginal.hbmMask);
	::DeleteDC(hSrcDC);
	::DeleteDC(hDestDC);
	::ReleaseDC(NULL, hMainDC);
	
	return hStretchedIcon;
} //End StretchIcon

void CPPDrawManager::FillGradient (HDC hDC, LPCRECT lpRect, 
								COLORREF colorStart, COLORREF colorFinish, 
								BOOL bHorz/* = TRUE*/)
{
    // this will make 2^6 = 64 fountain steps
    int nShift = 6;
    int nSteps = 1 << nShift;

	RECT r2;
	r2.top = lpRect->top;
	r2.left = lpRect->left;
	r2.right = lpRect->right;
	r2.bottom = lpRect->bottom;

	int nHeight = lpRect->bottom - lpRect->top;
	int nWidth = lpRect->right - lpRect->left;

	for (int i = 0; i < nSteps; i++)
    {
        // do a little alpha blending
        BYTE bR = (BYTE) ((GetRValue(colorStart) * (nSteps - i) +
                   GetRValue(colorFinish) * i) >> nShift);
        BYTE bG = (BYTE) ((GetGValue(colorStart) * (nSteps - i) +
                   GetGValue(colorFinish) * i) >> nShift);
        BYTE bB = (BYTE) ((GetBValue(colorStart) * (nSteps - i) +
                   GetBValue(colorFinish) * i) >> nShift);

		HBRUSH hBrush = ::CreateSolidBrush(RGB(bR, bG, bB));
		
        // then paint with the resulting color

        if (!bHorz)
        {
            r2.top = lpRect->top + ((i * nHeight) >> nShift);
            r2.bottom = lpRect->top + (((i + 1) * nHeight) >> nShift);
            if ((r2.bottom - r2.top) > 0)
                ::FillRect(hDC, &r2, hBrush);
        }
        else
        {
            r2.left = lpRect->left + ((i * nWidth) >> nShift);
            r2.right = lpRect->left + (((i + 1) * nWidth) >> nShift);
            if ((r2.right - r2.left) > 0)
                ::FillRect(hDC, &r2, hBrush);
        } //if
		
		if (NULL != hBrush)
		{
			::DeleteObject(hBrush);
			hBrush = NULL;
		} //if
    } //for
} //End FillGradient

#ifdef USE_SHADE
void CPPDrawManager::SetShade(LPCRECT lpRect, UINT shadeID /* = 0 */, BYTE granularity /* = 8 */, 
						  BYTE coloring /* = 0 */, COLORREF hicr /* = 0 */, COLORREF midcr /* = 0 */, COLORREF locr /* = 0 */)
{
	long	sXSize,sYSize,bytes,j,i,k,h;
	BYTE	*iDst ,*posDst;
	
	sYSize = lpRect->bottom - lpRect->top; 
	sXSize = lpRect->right - lpRect->left; 

	m_dNormal.Create(sXSize,sYSize,8);					//create the default bitmap

	long r,g,b;											//build the shaded palette
	for(i = 0; i < 129; i++)
	{
		r=((128-i)*GetRValue(locr)+i*GetRValue(midcr))/128;
		g=((128-i)*GetGValue(locr)+i*GetGValue(midcr))/128;
		b=((128-i)*GetBValue(locr)+i*GetBValue(midcr))/128;
		m_dNormal.SetPaletteIndex((BYTE)i,(BYTE)r,(BYTE)g,(BYTE)b);
	} //for
	for(i=1;i<129;i++){
		r=((128-i)*GetRValue(midcr)+i*GetRValue(hicr))/128;
		g=((128-i)*GetGValue(midcr)+i*GetGValue(hicr))/128;
		b=((128-i)*GetBValue(midcr)+i*GetBValue(hicr))/128;
		m_dNormal.SetPaletteIndex((BYTE)(i+127),(BYTE)r,(BYTE)g,(BYTE)b);
	} //for

	m_dNormal.BlendPalette(hicr,coloring);	//color the palette

	bytes = m_dNormal.GetLineWidth();
	iDst = m_dNormal.GetBits();
	posDst =iDst;
	long a,x,y,d,xs,idxmax,idxmin;

	int grainx2 = RAND_MAX/(max(1,2*granularity));
	idxmax=255-granularity;
	idxmin=granularity;

	switch (shadeID)
	{
//----------------------------------------------------
	case EFFECT_METAL:
		m_dNormal.Clear();
		// create the strokes
		k=40;	//stroke granularity
		for(a=0;a<200;a++){
			x=rand()/(RAND_MAX/sXSize); //stroke postion
			y=rand()/(RAND_MAX/sYSize);	//stroke position
			xs=rand()/(RAND_MAX/min(sXSize,sYSize))/2; //stroke lenght
			d=rand()/(RAND_MAX/k);	//stroke color
			for(i=0;i<xs;i++){
				if (((x-i)>0)&&((y+i)<sYSize))
					m_dNormal.SetPixelIndex(x-i,y+i,(BYTE)d);
				if (((x+i)<sXSize)&&((y-i)>0))
					m_dNormal.SetPixelIndex(sXSize-x+i,y-i,(BYTE)d);
			} //for
		} //for
		//blend strokes with SHS_DIAGONAL
		posDst =iDst;
		a=(idxmax-idxmin-k)/2;
		for(i = 0; i < sYSize; i++) {
			for(j = 0; j < sXSize; j++) {
				d=posDst[j]+((a*i)/sYSize+(a*(sXSize-j))/sXSize);
				posDst[j]=(BYTE)d;
				posDst[j]+=rand()/grainx2;
			} //for
			posDst+=bytes;
		} //for

		break;
//----------------------------------------------------
	case EFFECT_HARDBUMP:	// 
		//set horizontal bump
		for(i = 0; i < sYSize; i++) {
			k=(255*i/sYSize)-127;
			k=(k*(k*k)/128)/128;
			k=(k*(128-granularity*2))/128+128;
			for(j = 0; j < sXSize; j++) {
				posDst[j]=(BYTE)k;
				posDst[j]+=rand()/grainx2-granularity;
			} //for
			posDst+=bytes;
		} //for
		//set vertical bump
		d=min(16,sXSize/6);	//max edge=16
		a=sYSize*sYSize/4;
		posDst =iDst;
		for(i = 0; i < sYSize; i++) {
			y=i-sYSize/2;
			for(j = 0; j < sXSize; j++) {
				x=j-sXSize/2;
				xs=sXSize/2-d+(y*y*d)/a;
				if (x>xs) posDst[j]=(BYTE)idxmin+(BYTE)(((sXSize-j)*128)/d);
				if ((x+xs)<0) posDst[j]=(BYTE)idxmax-(BYTE)((j*128)/d);
				posDst[j]+=rand()/grainx2-granularity;
			} //for
			posDst+=bytes;
		} //for
		break;
//----------------------------------------------------
	case EFFECT_SOFTBUMP: //
		for(i = 0; i < sYSize; i++) {
			h=(255*i/sYSize)-127;
			for(j = 0; j < sXSize; j++) {
				k=(255*(sXSize-j)/sXSize)-127;
				k=(h*(h*h)/128)/128+(k*(k*k)/128)/128;
				k=k*(128-granularity)/128+128;
				if (k<idxmin) k=idxmin;
				if (k>idxmax) k=idxmax;
				posDst[j]=(BYTE)k;
				posDst[j]+=rand()/grainx2-granularity;
			} //for
			posDst+=bytes;
		} //for
		break;
//----------------------------------------------------
	case EFFECT_VBUMP: // 
		for(j = 0; j < sXSize; j++) {
			k=(255*(sXSize-j)/sXSize)-127;
			k=(k*(k*k)/128)/128;
			k=(k*(128-granularity))/128+128;
			for(i = 0; i < sYSize; i++) {
				posDst[j+i*bytes]=(BYTE)k;
				posDst[j+i*bytes]+=rand()/grainx2-granularity;
			} //for
		} //for
		break;
//----------------------------------------------------
	case EFFECT_HBUMP: //
		for(i = 0; i < sYSize; i++) {
			k=(255*i/sYSize)-127;
			k=(k*(k*k)/128)/128;
			k=(k*(128-granularity))/128+128;
			for(j = 0; j < sXSize; j++) {
				posDst[j]=(BYTE)k;
				posDst[j]+=rand()/grainx2-granularity;
			} //for
			posDst+=bytes;
		} //for
		break;
//----------------------------------------------------
	case EFFECT_DIAGSHADE:	//
		a=(idxmax-idxmin)/2;
		for(i = 0; i < sYSize; i++) {
			for(j = 0; j < sXSize; j++) {
				posDst[j]=(BYTE)(idxmin+a*i/sYSize+a*(sXSize-j)/sXSize);
				posDst[j]+=rand()/grainx2-granularity;
			} //for
			posDst+=bytes;
		} //for
		break;
//----------------------------------------------------
	case EFFECT_HSHADE:	//
		a=idxmax-idxmin;
		for(i = 0; i < sYSize; i++) {
			k=a*i/sYSize+idxmin;
			for(j = 0; j < sXSize; j++) {
				posDst[j]=(BYTE)k;
				posDst[j]+=rand()/grainx2-granularity;
			} //for
			posDst+=bytes;
		} //for
		break;
//----------------------------------------------------
	case EFFECT_VSHADE:	//:
		a=idxmax-idxmin;
		for(j = 0; j < sXSize; j++) {
			k=a*(sXSize-j)/sXSize+idxmin;
			for(i = 0; i < sYSize; i++) {
				posDst[j+i*bytes]=(BYTE)k;
				posDst[j+i*bytes]+=rand()/grainx2-granularity;
			} //for
		} //for
		break;
//----------------------------------------------------
	case EFFECT_NOISE:
		for(i = 0; i < sYSize; i++) {
			for(j = 0; j < sXSize; j++) {
				posDst[j]=128+rand()/grainx2-granularity;
			} //for
			posDst+=bytes;
		} //for
	} //switch
//----------------------------------------------------
} //End SetShade
#endif

void CPPDrawManager::FillEffect(HDC hDC, DWORD dwEffect, LPCRECT lpRect, COLORREF clrBegin, COLORREF clrMid /* = 0 */, COLORREF clrEnd /* = 0 */,  BYTE granularity /* = 0 */, BYTE coloring /* = 0 */)
{
	HBRUSH hBrush = NULL;

	RECT rect;
	rect.left = lpRect->left;
	rect.top = lpRect->top;
	rect.right = lpRect->right;
	rect.bottom = lpRect->bottom;

	int nHeight = rect.bottom - rect.top;
	int nWidth = rect.right - rect.left;
	
	switch (dwEffect)
	{
	default:
		hBrush = ::CreateSolidBrush(clrBegin);
		::FillRect(hDC, lpRect, hBrush);
		break;
	case EFFECT_HGRADIENT:
		FillGradient(hDC, lpRect, clrBegin, clrEnd, TRUE);
		break;
	case EFFECT_VGRADIENT:
		FillGradient(hDC, lpRect, clrBegin, clrEnd, FALSE);
		break;
	case EFFECT_HCGRADIENT:
		rect.right = rect.left + nWidth / 2;
		FillGradient(hDC, &rect, clrBegin, clrEnd, TRUE);
		rect.left = rect.right;
		rect.right = lpRect->right;
		FillGradient(hDC, &rect, clrEnd, clrBegin, TRUE);
		break;
	case EFFECT_3HGRADIENT:
		rect.right = rect.left + nWidth / 2;
		FillGradient(hDC, &rect, clrBegin, clrMid, TRUE);
		rect.left = rect.right;
		rect.right = lpRect->right;
		FillGradient(hDC, &rect, clrMid, clrEnd, TRUE);
		break;
	case EFFECT_VCGRADIENT:
		rect.bottom = rect.top + nHeight / 2;
		FillGradient(hDC, &rect, clrBegin, clrEnd, FALSE);
		rect.top = rect.bottom;
		rect.bottom = lpRect->bottom;
		FillGradient(hDC, &rect, clrEnd, clrBegin, FALSE);
		break;
	case EFFECT_3VGRADIENT:
		rect.bottom = rect.top + nHeight / 2;
		FillGradient(hDC, &rect, clrBegin, clrMid, FALSE);
		rect.top = rect.bottom;
		rect.bottom = lpRect->bottom;
		FillGradient(hDC, &rect, clrMid, clrEnd, FALSE);
		break;
#ifdef USE_SHADE
	case EFFECT_NOISE:
	case EFFECT_DIAGSHADE:
	case EFFECT_HSHADE:
	case EFFECT_VSHADE:
	case EFFECT_HBUMP:
	case EFFECT_VBUMP:
	case EFFECT_SOFTBUMP:
	case EFFECT_HARDBUMP:
	case EFFECT_METAL:
		rect.left = 0;
		rect.top = 0;
		rect.right = nWidth;
		rect.bottom = nHeight;
		SetShade(&rect, dwEffect, granularity, coloring, clrBegin, clrMid, clrEnd);
		m_dNormal.Draw(hDC, lpRect->left, lpRect->top);
		break; 
#endif
	} //switch

	if (NULL != hBrush)
	{
		::DeleteObject(hBrush);
		hBrush = NULL;
	} //if
} //End FillEffect

void CPPDrawManager::MultipleCopy(HDC hDestDC, int nDestX, int nDestY, DWORD dwDestWidth, DWORD dwDestHeight, 
										HDC hSrcDC, int nSrcX, int nSrcY, DWORD dwSrcWidth, DWORD dwSrcHeight)
{
	// Horizontal copying
	int right, bottom;
	int nDestRight = (int)(nDestX + dwDestWidth);
	int nDestBottom = (int)(nDestY + dwDestHeight);
	for (int x = nDestX; x < nDestRight; x+= dwSrcWidth)
	{
		right = min (x + (int)dwSrcWidth, nDestRight);
		// Vertical copying
		for (int y = nDestY; y < nDestBottom; y+= dwSrcHeight)
		{
			bottom = min (y + (int)dwSrcHeight, nDestBottom);
			::BitBlt(hDestDC, x, y, right - x, bottom - y, hSrcDC, nSrcX, nSrcY, SRCCOPY);
		} //for
	} //for
} //End MultipleCopy

void CPPDrawManager::DrawBitmap(HDC hDC, int x, int y, DWORD dwWidth, DWORD dwHeight, HBITMAP hSrcBitmap,
					BOOL bUseMask, COLORREF crMask, 
					DWORD dwEffect /* = IMAGE_EFFECT_NONE */, 
					BOOL bShadow /* = FALSE */, 
					DWORD dwCxShadow /* = PPDRAWMANAGER_SHADOW_XOFFSET */, 
					DWORD dwCyShadow /* = PPDRAWMANAGER_SHADOW_YOFFSET */,
					DWORD dwCxDepth /* = PPDRAWMANAGER_SHADOW_XDEPTH */, 
					DWORD dwCyDepth /* = PPDRAWMANAGER_SHADOW_YDEPTH */,
					COLORREF clrShadow /* = PPDRAWMANAGER_SHADOW_COLOR */)
{
	m_bIsAlpha = FALSE;
	if (NULL == hSrcBitmap)
		return;

	SIZE sz;
	GetSizeOfBitmap(hSrcBitmap, &sz);

	HDC hSrcDC = ::CreateCompatibleDC(hDC);
	HDC hDestDC = ::CreateCompatibleDC(hDC);
	
	HBITMAP hBitmapTemp = ::CreateCompatibleBitmap(hDC, dwWidth, dwHeight);

	HBITMAP hOldSrcBitmap = (HBITMAP)::SelectObject(hSrcDC, hSrcBitmap);
	HBITMAP hOldDestBitmap = (HBITMAP)::SelectObject(hDestDC, hBitmapTemp);

	//Scales a bitmap if need
	if (((DWORD)sz.cx != dwWidth) || ((DWORD)sz.cy != dwHeight))
		::StretchBlt(hDestDC, 0, 0, dwWidth, dwHeight, hSrcDC, 0, 0, sz.cx, sz.cy, SRCCOPY);
	else
		::BitBlt(hDestDC, 0, 0, dwWidth, dwHeight, hSrcDC, 0, 0, SRCCOPY);

	::SelectObject(hDestDC, hOldDestBitmap);
	
	HBITMAP hMaskBmp = CreateImageEffect(hBitmapTemp, dwWidth, dwHeight, IMAGE_EFFECT_MASK, bUseMask, crMask);
	HBITMAP hBitmap = CreateImageEffect(hBitmapTemp, dwWidth, dwHeight, dwEffect, bUseMask, crMask, clrShadow);
	
	if (bShadow)
	{
		if (dwEffect & IMAGE_EFFECT_SHADOW)
		{
			POINT ptShadow;
			ptShadow.x = x + dwCxShadow;
			ptShadow.y = y + dwCyShadow;
			HBITMAP hShadowBmp =  CreateImageEffect(hBitmapTemp, dwWidth, dwHeight, IMAGE_EFFECT_MASK, bUseMask, crMask, InvertColor(clrShadow));
			DrawShadow(hDC, ptShadow.x, ptShadow.y, dwWidth, dwHeight, hShadowBmp, dwEffect & IMAGE_EFFECT_GRADIENT_SHADOW, dwCxDepth, dwCyDepth);
			::DeleteObject(hShadowBmp);
		}
		else
		{
			x += dwCxShadow;
			y += dwCyShadow;
		} //if
	} //if
	
	if (m_bIsAlpha)
	{
		::SelectObject(hSrcDC, hBitmap);
		AlphaChannelBitBlt(hDC, x, y, dwWidth, dwHeight, hSrcDC, 0, 0);
	}
	else
	{
		//Merge the image mask with background
		::SelectObject(hSrcDC, hMaskBmp);
		::BitBlt(hDC, x, y, dwWidth, dwHeight, hSrcDC, 0, 0, SRCAND);
		
		//Draw the image
		::SelectObject(hSrcDC, hBitmap);
		::BitBlt(hDC, x, y, dwWidth, dwHeight, hSrcDC, 0, 0, SRCPAINT);
	}
	
	::SelectObject(hSrcDC, hOldSrcBitmap);
	
	::DeleteDC(hDestDC);
	::DeleteDC(hSrcDC);

	::DeleteObject(hBitmap);
	::DeleteObject(hMaskBmp);
	::DeleteObject(hBitmapTemp);
} //End DrawBitmap

void CPPDrawManager::DrawIcon(HDC hDC, int x, int y, DWORD dwWidth, DWORD dwHeight, HICON hSrcIcon,
  							DWORD dwEffect /* = IMAGE_EFFECT_NONE */, 
							BOOL bShadow /* = FALSE */, 
							DWORD dwCxShadow /* = PPDRAWMANAGER_SHADOW_XOFFSET */, 
							DWORD dwCyShadow /* = PPDRAWMANAGER_SHADOW_YOFFSET */,
							DWORD dwCxDepth /* = PPDRAWMANAGER_SHADOW_XDEPTH */, 
							DWORD dwCyDepth /* = PPDRAWMANAGER_SHADOW_YDEPTH */,
							COLORREF clrShadow /* = PPDRAWMANAGER_SHADOW_COLOR */)
{
	m_bIsAlpha = FALSE;
	if (NULL == hSrcIcon)
		return;

	SIZE sz;
	GetSizeOfIcon(hSrcIcon, &sz);

	HICON hIcon = NULL;

	if (((DWORD)sz.cx == dwWidth) && ((DWORD)sz.cy == dwHeight))
		hIcon = ::CopyIcon(hSrcIcon);
	else hIcon = StretchIcon(hSrcIcon, dwWidth, dwHeight);
	
	ICONINFO csOriginal;

	if (!::GetIconInfo(hIcon, &csOriginal))
		return;

	HDC hSrcDC = ::CreateCompatibleDC(hDC);
	
	HBITMAP hBitmap;
	if (dwEffect & IMAGE_EFFECT_MONOCHROME)
		hBitmap = CreateImageEffect(csOriginal.hbmMask, dwWidth, dwHeight, dwEffect, TRUE, RGB(255, 255, 255), clrShadow);
	else
		hBitmap = CreateImageEffect(csOriginal.hbmColor, dwWidth, dwHeight, dwEffect, TRUE, RGB(0, 0, 0), clrShadow);
	HBITMAP hOldSrcBitmap = (HBITMAP)::SelectObject(hSrcDC, hBitmap);

	if (bShadow)
	{
		if (dwEffect & IMAGE_EFFECT_SHADOW)
		{
			POINT ptShadow;
			ptShadow.x = x + dwCxShadow;
			ptShadow.y = y + dwCyShadow;
			HBITMAP hShadowBmp =  CreateImageEffect(csOriginal.hbmMask, dwWidth, dwHeight, IMAGE_EFFECT_MASK, TRUE, RGB(255, 255, 255), InvertColor(clrShadow));
			DrawShadow(hDC, ptShadow.x, ptShadow.y, dwWidth, dwHeight, hShadowBmp, dwEffect & IMAGE_EFFECT_GRADIENT_SHADOW, dwCxDepth, dwCyDepth);
			::DeleteObject(hShadowBmp);
		}
		else
		{
			x += dwCxShadow;
			y += dwCyShadow;
		} //if
	} //if
	
	if (m_bIsAlpha)
	{
//		::SelectObject(hSrcDC, hBitmap);
		AlphaChannelBitBlt(hDC, x, y, dwWidth, dwHeight, hSrcDC, 0, 0);
	}
	else
	{
		//-------------------------------------------------------------------
		// !!! ATTENTION !!!
		// I don't know why a icon uses text's color
		// Therefore I change a text's color to BLACK and after draw I restore
		// original color
		//-------------------------------------------------------------------
		COLORREF crOldColor = ::SetTextColor(hDC, RGB(0, 0, 0));
		//Merge the image mask with background
		::SelectObject(hSrcDC, csOriginal.hbmMask);
		::BitBlt(hDC, x, y, dwWidth, dwHeight, hSrcDC, 0, 0, SRCAND);
		//Draw the image
		::SelectObject(hSrcDC, hBitmap);
		::BitBlt(hDC, x, y, dwWidth, dwHeight, hSrcDC, 0, 0, SRCPAINT);
		::SetTextColor(hDC, crOldColor);
	} //if

	::SelectObject(hSrcDC, hOldSrcBitmap);
	::DeleteDC(hSrcDC);
	::DeleteObject(hBitmap);
	::DestroyIcon(hIcon);

	::DeleteObject(csOriginal.hbmColor);
	::DeleteObject(csOriginal.hbmMask);
} //End DrawIcon

void CPPDrawManager::DrawShadow(HDC hDestDC, int nDestX, int nDestY, DWORD dwWidth, DWORD dwHeight, HBITMAP hMask, BOOL bGradient /* = FALSE */, DWORD dwDepthX /* = PPDRAWMANAGER_SHADOW_YOFFSET */, DWORD dwDepthY /* = PPDRAWMANAGER_SHADOW_XOFFSET */)
{
	HDC hSrcDC = ::CreateCompatibleDC(hDestDC);
	if (NULL == hSrcDC)
		return;

	HDC hTempDC = ::CreateCompatibleDC(hDestDC);
	if (NULL == hTempDC)
	{
		::DeleteDC(hSrcDC);
		return;
	} // if
	
	//Creates Source DIB
	LPBITMAPINFO lpbiSrc;
	// Fill in the BITMAPINFOHEADER
	lpbiSrc = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
	lpbiSrc->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	lpbiSrc->bmiHeader.biWidth = dwWidth;
	lpbiSrc->bmiHeader.biHeight = dwHeight;
	lpbiSrc->bmiHeader.biPlanes = 1;
	lpbiSrc->bmiHeader.biBitCount = 32;
	lpbiSrc->bmiHeader.biCompression = BI_RGB;
	lpbiSrc->bmiHeader.biSizeImage = dwWidth * dwHeight;
	lpbiSrc->bmiHeader.biXPelsPerMeter = 0;
	lpbiSrc->bmiHeader.biYPelsPerMeter = 0;
	lpbiSrc->bmiHeader.biClrUsed = 0;
	lpbiSrc->bmiHeader.biClrImportant = 0;
	
	COLORREF* pSrcBits = NULL;
	HBITMAP hSrcDib = CreateDIBSection (
		hSrcDC, lpbiSrc, DIB_RGB_COLORS, (void **)&pSrcBits,
		NULL, NULL);
	
	if ((NULL != hSrcDib) && (NULL != pSrcBits))
	{
		HBITMAP hOldSrcBmp = (HBITMAP)::SelectObject (hSrcDC, hSrcDib);
		HBITMAP hOldTempBmp = (HBITMAP)::SelectObject (hTempDC, hMask);
		if (bGradient)
		{
			if (!(dwDepthX & 0x1)) dwDepthX++;
			if (!(dwDepthY & 0x1)) dwDepthY++;
			::BitBlt(hSrcDC, 0, 0, dwWidth, dwHeight, hTempDC, 0, 0, WHITENESS);
			::StretchBlt (hSrcDC, dwDepthX / 2, dwDepthY / 2, dwWidth - dwDepthX, dwHeight - dwDepthY, hTempDC, 0, 0, dwWidth, dwHeight, SRCCOPY);
		}
		else
		{
			::BitBlt(hSrcDC, 0, 0, dwWidth, dwHeight, hTempDC, 0, 0, SRCCOPY);
		} //if
		::SelectObject (hTempDC, hOldTempBmp);
		::SelectObject (hSrcDC, hOldSrcBmp);
		
		//Creates Destination DIB
		LPBITMAPINFO lpbiDest;
		// Fill in the BITMAPINFOHEADER
		lpbiDest = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
		lpbiDest->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
		lpbiDest->bmiHeader.biWidth = dwWidth;
		lpbiDest->bmiHeader.biHeight = dwHeight;
		lpbiDest->bmiHeader.biPlanes = 1;
		lpbiDest->bmiHeader.biBitCount = 32;
		lpbiDest->bmiHeader.biCompression = BI_RGB;
		lpbiDest->bmiHeader.biSizeImage = dwWidth * dwHeight;
		lpbiDest->bmiHeader.biXPelsPerMeter = 0;
		lpbiDest->bmiHeader.biYPelsPerMeter = 0;
		lpbiDest->bmiHeader.biClrUsed = 0;
		lpbiDest->bmiHeader.biClrImportant = 0;
		
		COLORREF* pDestBits = NULL;
		HBITMAP hDestDib = CreateDIBSection (
			hDestDC, lpbiDest, DIB_RGB_COLORS, (void **)&pDestBits,
			NULL, NULL);
		
		if ((NULL != hDestDib) && (NULL != pDestBits))
		{
			::SelectObject (hTempDC, hDestDib);
			::BitBlt (hTempDC, 0, 0, dwWidth, dwHeight, hDestDC, nDestX, nDestY, SRCCOPY);
			::SelectObject (hTempDC, hOldTempBmp);
			
			if (bGradient)
			{
				double * depth = new double [dwWidth * dwHeight];
				SmoothMaskImage(dwWidth, dwHeight, pSrcBits, dwDepthX, dwDepthY, depth);
				for(DWORD pixel = 0; pixel < dwWidth * dwHeight; pixel++, pDestBits++)
					*pDestBits = DarkenColor(*pDestBits, *(depth + pixel));
				delete [] depth;
			}
			else
			{
				for(DWORD pixel = 0; pixel < dwWidth * dwHeight; pixel++, pSrcBits++, pDestBits++)
					*pDestBits = DarkenColor(*pDestBits, (double)GetRValue(*pSrcBits) / 255.0);
			} //if
				
			
			::SelectObject (hTempDC, hDestDib);
			::BitBlt (hDestDC, nDestX, nDestY, dwWidth, dwHeight, hTempDC, 0, 0, SRCCOPY);
			::SelectObject (hTempDC, hOldTempBmp);

			delete lpbiDest;
			::DeleteObject(hDestDib);
		} //if
		delete lpbiSrc;
		::DeleteObject(hSrcDib);
	} //if
	::DeleteDC(hTempDC);
	::DeleteDC(hSrcDC);
} //End DrawIcon

void CPPDrawManager::DrawImageList(HDC hDC, int x, int y, DWORD dwWidth, DWORD dwHeight, HBITMAP hSrcBitmap,
					int nIndex, int cx, int cy,
					BOOL bUseMask, COLORREF crMask, 
					DWORD dwEffect /*= IMAGE_EFFECT_NONE*/, 
					BOOL bShadow /*= FALSE*/, 
					DWORD dwCxShadow /*= PPDRAWMANAGER_SHADOW_XOFFSET*/, 
					DWORD dwCyShadow /*= PPDRAWMANAGER_SHADOW_YOFFSET*/,
					DWORD dwCxDepth /*= PPDRAWMANAGER_SHADOW_XDEPTH*/, 
					DWORD dwCyDepth /*= PPDRAWMANAGER_SHADOW_YDEPTH*/,
					COLORREF clrShadow /*= PPDRAWMANAGER_SHADOW_COLOR*/)
{
	if ((NULL == hSrcBitmap) || !cx || !cy)
		return;

	SIZE sz;
	GetSizeOfBitmap(hSrcBitmap, &sz);

	//ENG: Gets a max columns and rows of the images on the bitmap
	//RUS: Получаем максимальное число колонок и строк изображений на битмапке
	int nMaxCol = sz.cx / cx;
	int nMaxRow = sz.cy / cy;
	int nMaxImages = nMaxCol * nMaxRow;

	if ((nIndex < nMaxImages) && nMaxCol && nMaxRow)
	{
		//ENG: Gets an specified image from the bitmap
		//RUS: Получаем указанное изображение из битмапа
		HDC hSrcDC = ::CreateCompatibleDC(hDC);
		HDC hDestDC = ::CreateCompatibleDC(hDC);
		HBITMAP hIconBmp = ::CreateCompatibleBitmap(hDC, cx, cy);
		HBITMAP hOldSrcBmp = (HBITMAP)::SelectObject(hSrcDC, hSrcBitmap);
		HBITMAP hOldDestBmp = (HBITMAP)::SelectObject(hDestDC, hIconBmp);
		::BitBlt(hDestDC, 0, 0, cx, cy, hSrcDC, (nIndex % nMaxCol) * cx, (nIndex / nMaxCol) * cy, SRCCOPY);
		::SelectObject(hSrcDC, hOldSrcBmp);
		::SelectObject(hDestDC, hOldDestBmp);
		::DeleteDC(hSrcDC);
		::DeleteDC(hDestDC);
		DrawBitmap( hDC, x, y, dwWidth, dwHeight, hIconBmp, 
					bUseMask, crMask, dwEffect, 
					bShadow, dwCxShadow, dwCyShadow, 
					dwCxDepth, dwCyDepth, clrShadow);
		::DeleteObject(hIconBmp);
	} //if
} //End of DrawImageList

void CPPDrawManager::MaskToDepth(HDC hDC, DWORD dwWidth, DWORD dwHeight, HBITMAP hMask, double * pDepth, BOOL bGradient /* = FALSE */, DWORD dwDepthX /* = PPDRAWMANAGER_CXSHADOW */, DWORD dwDepthY /* = PPDRAWMANAGER_CYSHADOW */)
{
	HDC hSrcDC = ::CreateCompatibleDC(hDC);
	if (NULL == hSrcDC)
	{
		::DeleteDC(hSrcDC);
		hSrcDC = NULL;
		return;
	} //if

	HDC hTempDC = ::CreateCompatibleDC(hDC);
	if (NULL == hTempDC)
	{
		::DeleteDC(hTempDC);
		hTempDC = NULL;
		return;
	} //if
	
	//Creates Source DIB
	LPBITMAPINFO lpbiSrc;
	// Fill in the BITMAPINFOHEADER
	lpbiSrc = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
	lpbiSrc->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	lpbiSrc->bmiHeader.biWidth = dwWidth;
	lpbiSrc->bmiHeader.biHeight = dwHeight;
	lpbiSrc->bmiHeader.biPlanes = 1;
	lpbiSrc->bmiHeader.biBitCount = 32;
	lpbiSrc->bmiHeader.biCompression = BI_RGB;
	lpbiSrc->bmiHeader.biSizeImage = dwWidth * dwHeight;
	lpbiSrc->bmiHeader.biXPelsPerMeter = 0;
	lpbiSrc->bmiHeader.biYPelsPerMeter = 0;
	lpbiSrc->bmiHeader.biClrUsed = 0;
	lpbiSrc->bmiHeader.biClrImportant = 0;
	
	COLORREF* pSrcBits = NULL;
	HBITMAP hSrcDib = CreateDIBSection (
		hSrcDC, lpbiSrc, DIB_RGB_COLORS, (void **)&pSrcBits,
		NULL, NULL);
	
	if ((NULL != hSrcDib) && (NULL != pSrcBits))
	{
		HBITMAP hOldSrcBmp = (HBITMAP)::SelectObject (hSrcDC, hSrcDib);
		HBITMAP hOldTempBmp = (HBITMAP)::SelectObject (hTempDC, hMask);
		if (bGradient)
		{
			if (!(dwDepthX & 0x1)) dwDepthX++;
			if (!(dwDepthY & 0x1)) dwDepthY++;
			::BitBlt(hSrcDC, 0, 0, dwWidth, dwHeight, hTempDC, 0, 0, WHITENESS);
			::StretchBlt (hSrcDC, dwDepthX / 2, dwDepthY / 2, dwWidth - dwDepthX, dwHeight - dwDepthY, hTempDC, 0, 0, dwWidth, dwHeight, SRCCOPY);
		}
		else
		{
			::BitBlt(hSrcDC, 0, 0, dwWidth, dwHeight, hTempDC, 0, 0, SRCCOPY);
		} //if
		::SelectObject (hTempDC, hOldTempBmp);
		::SelectObject (hSrcDC, hOldSrcBmp);
		
		if (bGradient)
		{
			SmoothMaskImage(dwWidth, dwHeight, pSrcBits, dwDepthX, dwDepthY, pDepth);
		}
		else
		{
			for (DWORD pixel = 0; pixel < (dwHeight * dwWidth); pixel++, pSrcBits++, pDepth++)
			{
				*pDepth = GetRValue(*pSrcBits) / 255;
			} //for
		} //if
		delete lpbiSrc;
		::DeleteObject(hSrcDib);
	} //if
	::DeleteDC(hTempDC);
	::DeleteDC(hSrcDC);
} //End MaskToDepth

void CPPDrawManager::DarkenByDepth(HDC hDC, int x, int y, DWORD dwWidth, DWORD dwHeight, double * pDepth)
{
	HDC hSrcDC = ::CreateCompatibleDC(hDC);
	if (NULL == hSrcDC)
	{
		::DeleteDC(hSrcDC);
		hSrcDC = NULL;
		return;
	} //if
	
	//Creates Source DIB
	LPBITMAPINFO lpbiSrc;
	// Fill in the BITMAPINFOHEADER
	lpbiSrc = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)];
	lpbiSrc->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	lpbiSrc->bmiHeader.biWidth = dwWidth;
	lpbiSrc->bmiHeader.biHeight = dwHeight;
	lpbiSrc->bmiHeader.biPlanes = 1;
	lpbiSrc->bmiHeader.biBitCount = 32;
	lpbiSrc->bmiHeader.biCompression = BI_RGB;
	lpbiSrc->bmiHeader.biSizeImage = dwWidth * dwHeight;
	lpbiSrc->bmiHeader.biXPelsPerMeter = 0;
	lpbiSrc->bmiHeader.biYPelsPerMeter = 0;
	lpbiSrc->bmiHeader.biClrUsed = 0;
	lpbiSrc->bmiHeader.biClrImportant = 0;
	
	COLORREF* pSrcBits = NULL;
	HBITMAP hSrcDib = CreateDIBSection (
		hSrcDC, lpbiSrc, DIB_RGB_COLORS, (void **)&pSrcBits,
		NULL, NULL);
	
	if ((NULL != hSrcDib) && (NULL != pSrcBits))
	{
		HBITMAP hOldSrcBmp = (HBITMAP)::SelectObject (hSrcDC, hSrcDib);
		::BitBlt(hSrcDC, 0, 0, dwWidth, dwHeight, hDC, x, y, SRCCOPY);
		::SelectObject (hSrcDC, hOldSrcBmp);
		
		for (DWORD pixel = 0; pixel < (dwHeight * dwWidth); pixel++, pSrcBits++, pDepth++)
		{
			*pSrcBits = DarkenColor(*pSrcBits, *pDepth);
		} //for

		hOldSrcBmp = (HBITMAP)::SelectObject (hSrcDC, hSrcDib);
		::BitBlt(hDC, x, y, dwWidth, dwHeight, hSrcDC, 0, 0, SRCCOPY);
		::SelectObject (hSrcDC, hOldSrcBmp);

		delete lpbiSrc;
		::DeleteObject(hSrcDib);
	} //if
	::DeleteDC(hSrcDC);
} //DarkenByDepth

void CPPDrawManager::SmoothMaskImage(const int ImageWidth, 
									 const int ImageHeight,
									 const COLORREF* const pInitImg,
									 const int KerWidth,
									 const int KerHeight,
									 double* const pResImg_R /*= NULL*/)
{
	double* const pfBuff1 = new double[(ImageWidth  + KerWidth  - 1) * 
		(ImageHeight + KerHeight - 1)];
	double* const pfBuff2 = new double[(ImageWidth  + KerWidth  - 1) * 
		(ImageHeight + KerHeight - 1)];
	
	// expanding initial image with a padding procdure
	double* p = pfBuff1;
	const COLORREF * pInitImg_It = pInitImg;
	if(NULL != pResImg_R)
	{
		for(int _i = - KerHeight/2; _i < ImageHeight +  KerHeight/2; _i++)
		{
			for(int _j = -KerWidth/2; _j < ImageWidth + KerWidth/2;  _j++, p++)
			{
				if ((_i >= 0) && (_i < ImageHeight) && (_j >= 0) && (_j < ImageWidth))
				{
					*p = GetRValue(*pInitImg_It++);
					//					pInitImg_It++;
				}
				else
					*p = 255;
			} //for
		} //for
		
		//---
		GetPartialSums(pfBuff1,
			(ImageHeight + KerHeight - 1),
			(ImageWidth  + KerWidth  - 1),
			KerHeight,
			KerWidth,
			pfBuff2,
			pResImg_R);
		
		for(int i = 0; i < ImageHeight*ImageWidth; i++)
			*(pResImg_R + i) /= KerHeight*KerWidth*255;
	} //if
	
	
	delete []pfBuff1;
	delete []pfBuff2;
} //End SmoothMaskImage

void CPPDrawManager::GetPartialSums(const double* const pM,
									unsigned int nMRows,
									unsigned int nMCols,
									unsigned int nPartRows,
									unsigned int nPartCols,
									double* const pBuff,
									double* const pRes)
{
	const double* it1;
	const double* it2;
	const double* it3;
	
	double* pRowsPartSums;
	const unsigned int nRowsPartSumsMRows = nMRows;
	const unsigned int nRowsPartSumsMCols = nMCols - nPartCols + 1;	
	
	const unsigned int nResMRows = nMRows - nPartRows + 1;
	const unsigned int nResMCols = nMCols - nPartCols + 1;
	
	
	unsigned int i,j;
	double s;
	
	// частичные суммы строк
	it1          = pM;
	pRowsPartSums = pBuff;
	
	for(i = 0; i < nMRows; i++)
	{
		//-------------
		it2 = it1;
		s = 0;
		for(j = 0;j < nPartCols;j++)s+=*it2++;
		//-------------
		it3 = it1;
		*pRowsPartSums++ = s;
		for(/*j = nPartCols*/; j < nMCols; j++)
		{
			s+=*it2 - *it3;
			*pRowsPartSums++ = s;
			it2++;
			it3++;
		} //for
		//--
		it1 += nMCols;
	} //for
	// формирование резуьтата
	const double* it4;
	const double* it5;
	const double* it6;
	
	double* pResIt;
	
	it4    = pBuff;
	pResIt = pRes;
	
	for(j = 0; j < nRowsPartSumsMCols; j++)
	{
		pResIt = pRes + j;
		//-------------
		it5 = it4;
		s = 0;
		for(i = 0; i < nPartRows; i++)
		{
			s += *it5;
			it5 += nRowsPartSumsMCols; 
		} //for
		//-------------
		it6 = it4;
		*pResIt = s;
		pResIt += nRowsPartSumsMCols;
		
		for(; i < nRowsPartSumsMRows; i++)
		{
			s += *it5 - *it6;//cout<<s<<endl;
			*pResIt = s;
			pResIt += nResMCols;
			it5 += nRowsPartSumsMCols;
			it6 += nRowsPartSumsMCols;
		} //for
		//--
		it4 ++;
	} //for
} //End GetPartialSums

void CPPDrawManager::DrawRectangle(HDC hDC, LPRECT lpRect, COLORREF crLight, COLORREF crDark, int nStyle /* = PEN_SOLID */, int nSize /* = 1 */)
{
	DrawRectangle(hDC, lpRect->left, lpRect->top, lpRect->right, lpRect->bottom, crLight, crDark, nStyle, nSize);
}

void CPPDrawManager::DrawRectangle(HDC hDC, int left, int top, int right, int bottom, 
								   COLORREF crLight, COLORREF crDark, int nStyle /* = PEN_SOLID */, 
								   int nSize /* = 1 */)
{
	if ((PEN_NULL == nStyle) || (nSize < 1))
		return;

	int nSysPenStyle = PS_SOLID;
	int nDoubleLineOffset = nSize * 2;
	switch (nStyle)
	{
	case PEN_DASH: nSysPenStyle = PS_DASH; break;
	case PEN_DOT: nSysPenStyle = PS_DOT; break;
	case PEN_DASHDOT: nSysPenStyle = PS_DASHDOT; break;
	case PEN_DASHDOTDOT: nSysPenStyle = PS_DASHDOTDOT; break;
	case PEN_DOUBLE:
	case PEN_SOLID:
	default:
		nSysPenStyle = PS_SOLID; 
		break;
	} //switch

	//Insideframe
	left += nSize / 2;
	top += nSize / 2;
	right -= nSize / 2;
	bottom -= nSize / 2;

	//Creates a light pen
	HPEN hPen = ::CreatePen(nSysPenStyle, nSize, crLight);
	HPEN hOldPen = (HPEN)::SelectObject(hDC, hPen);

	//Draw light border
	::MoveToEx(hDC, left, bottom, NULL);
	::LineTo(hDC, left, top);
	::LineTo(hDC, right, top);
	if (PEN_DOUBLE == nStyle)
	{
		::MoveToEx(hDC, left + nDoubleLineOffset, bottom - nDoubleLineOffset, NULL);
		::LineTo(hDC, left + nDoubleLineOffset, top + nDoubleLineOffset);
		::LineTo(hDC, right - nDoubleLineOffset, top + nDoubleLineOffset);
	} //if

	//Creates a dark pen if needed
	if (crLight != crDark)
	{
		SelectObject(hDC, hOldPen);
		::DeleteObject(hPen);
		hPen = ::CreatePen(nSysPenStyle, nSize, crDark);
		hOldPen = (HPEN)::SelectObject(hDC, hPen);
	} //if

	//Draw dark border
	::MoveToEx(hDC, right, top, NULL);
	::LineTo(hDC, right, bottom);
	::LineTo(hDC, left, bottom);
	if (PEN_DOUBLE == nStyle)
	{
		::MoveToEx(hDC, right - nDoubleLineOffset, top + nDoubleLineOffset, NULL);
		::LineTo(hDC, right - nDoubleLineOffset, bottom - nDoubleLineOffset);
		::LineTo(hDC, left + nDoubleLineOffset, bottom - nDoubleLineOffset);
	} //if

	SelectObject(hDC, hOldPen);
	::DeleteObject(hPen);
} //End DrawRectangle

void CPPDrawManager::DrawLine(HDC hDC, 
							  int xStart, int yStart, int xEnd, int yEnd, 
							  COLORREF color, int nStyle /* = PEN_SOLID */, 
							  int nSize /* = 1 */) const
{
	if ((PEN_NULL == nStyle) || (nSize < 1))
		return;
	
	int nSysPenStyle;
	int nDoubleLineOffset = nSize * 2;
	switch (nStyle)
	{
	case PEN_DASH: nSysPenStyle = PS_DASH; break;
	case PEN_DOT: nSysPenStyle = PS_DOT; break;
	case PEN_DASHDOT: nSysPenStyle = PS_DASHDOT; break;
	case PEN_DASHDOTDOT: nSysPenStyle = PS_DASHDOTDOT; break;
	case PEN_DOUBLE:
	case PEN_SOLID:
	default:
		nSysPenStyle = PS_SOLID; 
		break;
	} //switch

	HPEN hPen = ::CreatePen(nSysPenStyle, nSize, color);
	HPEN hOldPen = (HPEN)::SelectObject(hDC, hPen);

	::MoveToEx(hDC, xStart, yStart, NULL);
	::LineTo(hDC, xEnd, yEnd);
	
	if (PEN_DOUBLE == nStyle)
	{
		if (xStart != xEnd)
		{
			yStart += nDoubleLineOffset;
			yEnd += nDoubleLineOffset;
		} //if
		
		if (yStart != yEnd)
		{
			xStart += nDoubleLineOffset;
			xEnd += nDoubleLineOffset;
		} //if
		::MoveToEx(hDC, xStart, yStart, NULL);
		::LineTo(hDC, xEnd, yEnd);
	} //if
	SelectObject(hDC, hOldPen);
	::DeleteObject(hPen);
} //End DrawLine

