#pragma warning (disable:4800)
#include "stdafx.h"
#include "dibsection.hpp"
#include "dibsurf.hpp"      //lint !e537
#include <stack>
#include <vector>

//*******************************************************************
//
//    DESCRIPTION:Implementation file for CDIBSurface class
//
//    AUTHOR: Andrew Farrier
//
//    SourceSafe Version: $Revision: 107 $
//
//******************************************************************
	
std::vector<HDC> *CDIBSurface::m_FreeDC = NULL;
std::vector<DCData> *CDIBSurface::m_AllDCs = NULL;
int CDIBSurface::m_DCStackRefCount = 0;

int g_NumDibSurf = 0;

bool CDIBSurface::Blt (int x,int y,int width,int height,const CDIBSurface *src,int srcx,int srcy,DWORD rop)
  {
		ASSERT (m_DIBData);
		ASSERT (src);
		ASSERT (IsValid ());
		if(!src)
			return false;
		if (rop == SRCCOPY  &&  src->GetBitDepth() == GetBitDepth())
		{	// use non-GDI versions
			if(src->UseMask ()  &&  src->Mask())
				return MaskBltNonGDI (x,y,width,height,*src,srcx,srcy);
			else
				return BltNonGDI (x,y,width,height,*src,srcx,srcy);
		}
		else if(src->UseMask ())
			return MaskBlt (x,y,width,height,src,srcx,srcy);
		else
		{
			HDC dc1,dc2;
			bool toret;

			dc1 = GetDC ();
			dc2 = src->GetDC ();
			if (!(dc1 && dc2))
			{
				if (dc1)
					ReleaseDC (dc1);
				if (dc2)
					src->ReleaseDC (dc2);
				return false;
			}
      toret = (::BitBlt (dc1,x,y,width,height,dc2,srcx,srcy,rop) == TRUE);
			ReleaseDC (dc1);
			src->ReleaseDC (dc2);
			return toret;
		}
  }

void CDIBSurface::UseDC (HDC tempdc)
{
	ASSERT (m_DIBData);
	if (m_DIBData->m_SelectedDC == tempdc)
	{
		m_DIBData->m_SelectedDCRefCount++;
		return;
	}

	HBITMAP bmap = GetBitmap();
	ASSERT (bmap);
	m_DIBData->m_OldBitmap = (HBITMAP) SelectObject (tempdc,bmap);
	m_DIBData->m_SelectedDC = tempdc;
	m_DIBData->m_SelectedDCRefCount=1;
	m_DIBData->m_AllocedDC = false;
	return ;
}

HDC  CDIBSurface::GetDC (void)
{
	HDC tempdc;
	HBITMAP tempbits;

	ASSERT (m_DIBData);
	if (m_DIBData->m_SelectedDC)
	{
		m_DIBData->m_SelectedDCRefCount++;
		return m_DIBData->m_SelectedDC;
	}

	if (m_FreeDC->size () == 0)
	{
		tempdc = CreateCompatibleDC (NULL);
 		ASSERT (tempdc);

		tempbits = (HBITMAP) GetCurrentObject (tempdc,OBJ_BITMAP);
		SelectObject (tempdc,tempbits);

		m_AllDCs->push_back (DCData (tempdc,tempbits));
		m_FreeDC->push_back (tempdc);
	}


	tempdc = m_FreeDC->back ();
	m_FreeDC->pop_back ();

	// asking for a DC only makes sense if you have a bitmap selected in it
	GetBitmap();
	ASSERT (m_DIBData->m_BackBits);

	if (m_DIBData->m_BackBits)
		if (!SelectObject (tempdc,m_DIBData->m_BackBits))
		{
			m_FreeDC->push_back (tempdc);
			return NULL;
		}
	m_DIBData->m_SelectedDC = tempdc;
	m_DIBData->m_SelectedDCRefCount=1;
	m_DIBData->m_AllocedDC = true;
	return tempdc;
}

HDC  CDIBSurface::GetDC (void) const
{
	HDC tempdc;
	HBITMAP tempbits;

	ASSERT (m_DIBData);

	if (m_DIBData->m_SelectedDC)
	{
		m_DIBData->m_SelectedDCRefCount++;
		return m_DIBData->m_SelectedDC;
	}

	if (m_FreeDC->size () == 0)
	{
		tempdc = CreateCompatibleDC (NULL);
 		ASSERT (tempdc);

		tempbits = (HBITMAP) GetCurrentObject (tempdc,OBJ_BITMAP);
		SelectObject (tempdc,tempbits);

		m_AllDCs->push_back (DCData (tempdc,tempbits));
		m_FreeDC->push_back (tempdc);
	}

	tempdc = m_FreeDC->back();
	m_FreeDC->pop_back ();

	// asking for a DC only makes sense if you have a bitmap selected in it
	GetBitmap();
	ASSERT (m_DIBData->m_BackBits);

	if (m_DIBData->m_BackBits)
		if (!SelectObject (tempdc,m_DIBData->m_BackBits))
		{
			m_FreeDC->push_back (tempdc);
			return NULL;
		}
	m_DIBData->m_SelectedDC = tempdc;
	m_DIBData->m_SelectedDCRefCount=1;
	m_DIBData->m_AllocedDC = true;
	return tempdc;
}

void CDIBSurface::ReleaseDC (HDC dc) const
{
	std::vector<DCData>::iterator iter;
	ASSERT (dc);
	ASSERT (m_DIBData);

	m_DIBData->m_SelectedDCRefCount--;
	if (m_DIBData->m_SelectedDCRefCount)
		return;

	if (m_DIBData->m_AllocedDC)
	{
		iter = m_AllDCs->begin ();
		while(iter != m_AllDCs->end ())
		{
			if(iter->thedc == dc)
			{
				HBITMAP temp = (HBITMAP) GetCurrentObject (dc,OBJ_BITMAP);
				if (temp != iter->oldbits)
					SelectObject (dc,iter->oldbits);
				break;
			}
			iter++;
		}
	}
	else
	{
		SelectObject (dc,m_DIBData->m_OldBitmap);
	}
	m_DIBData->m_SelectedDC = NULL;
	if (m_DIBData->m_AllocedDC)
		m_FreeDC->push_back (dc);
}

CDIBSurface::~CDIBSurface (void)
{
	if(m_RefCount)
	{
		Release ();
	}
	m_RefCount = NULL;
	m_DIBData = NULL;
}

CDIBSurface::CDIBSurface (const CDIBSurface& p)
{
	ASSERT (p.m_RefCount);
	ASSERT (p.m_DIBData);
	m_RefCount = p.m_RefCount;
	m_DIBData = p.m_DIBData;
	AddRef ();
}

CDIBSurface& CDIBSurface::operator= (const CDIBSurface& p)
{
	ASSERT (p.m_RefCount);
	ASSERT (p.m_DIBData);
	if(m_DIBData)
	{
		Release ();
	}
	m_RefCount = p.m_RefCount;
	m_DIBData = p.m_DIBData;
	AddRef ();

	return *this;
}

bool CDIBSurface::SplitRef (void)
{	
	DIBData *olddata;

	ASSERT (m_DIBData);
	ASSERT (m_RefCount);
	if(*m_RefCount < 2)
		return true;
	olddata = m_DIBData;

	//m_RefCount--;
	Release ();
//	*m_RefCount -= 1;

	m_RefCount = new UINT;
	*m_RefCount = 0;
	AddRef ();
	m_DIBData = new DIBData;
	ClearData ();
	if(!Create (olddata->m_Width,olddata->m_Height,olddata->m_BitDepth))
		return false;

	UINT tocopy;

	if(m_DIBData->m_Pitch == olddata->m_Pitch)
	{
		tocopy = abs (m_DIBData->m_Pitch) * m_DIBData->m_Height;
		memcpy (m_DIBData->m_Data,olddata->m_Data,tocopy);
	}
	else
	{
		int y;
		unsigned char *dest,*src;

		dest = m_DIBData->m_UpperLeft;
		src = olddata->m_UpperLeft;
		for(y=0;y<m_DIBData->m_Height;y++)
		{
			memcpy (dest,src,m_DIBData->m_Pitch);
			dest += m_DIBData->m_Pitch;
			src += olddata->m_Pitch;
		}
	}
	
	if(olddata->m_Mask)
	{
		if(!CalcMask ())
			return false;
		HDC dc1,dc2;
		dc1 = m_DIBData->m_Mask->GetDC ();
		dc2 = olddata->m_Mask->GetDC ();
		BitBlt (dc1,0,0,m_DIBData->m_Width,m_DIBData->m_Height,dc2,0,0,SRCCOPY);
		m_DIBData->m_Mask->ReleaseDC (dc1);
		olddata->m_Mask->ReleaseDC (dc2);
	}
	m_DIBData->m_UseMask = olddata->m_UseMask;

	return true;
}

CDIBSurface::CDIBSurface (void)
{

	m_RefCount = new UINT;
	ASSERT (m_RefCount);
	*m_RefCount = 0;
	AddRef ();
	m_DIBData = new DIBData;
	ClearData ();
}

unsigned char *CDIBSurface::GetMem( int x, int y )
{
	ASSERT( m_DIBData );
	unsigned char *pBits = NULL;

	if( 0 <= x && GetWidth() > x &&
		0 <= y && GetHeight() > y &&
		m_DIBData->m_Data &&
		GdiFlush() )
	{
		int nPixelSize = GetBitDepth() >> 3;
		int nPitch = GetPitch();

		pBits = m_DIBData->m_Data;
		if( 0 > nPitch )
			pBits -= nPitch * (GetHeight() - y - 1);
		else
			pBits += nPitch * y;

		pBits += nPixelSize * x;
	}

	return( pBits );
}

//****************************************************************
//
// Function Name: CDIBSurface::CDIBSurface
//
// Description: Constructor for CDIBSurface.  Empties the fields and calls Create
//
// Returns:nothing
//
//****************************************************************
CDIBSurface::CDIBSurface (UINT Width,UINT Height,UINT BitDepth)
{
	if(!m_DCStackRefCount)
	{
		m_AllDCs = new std::vector<DCData>;
		m_FreeDC = new std::vector<HDC>;
	}
	m_DCStackRefCount++;

	m_RefCount = new UINT;
	ASSERT (m_RefCount);
	*m_RefCount = 0;
	AddRef ();

	m_DIBData = new DIBData;
	ASSERT (m_DIBData);
	ClearData ();
	if(!Create (Width,Height,BitDepth))
	{
		throw std::runtime_error ("unable to create a blank CDIBSurface");
	}
}

//****************************************************************
//
// Function Name: CDIBSurface::Create
//
// Description: creates a new DIBSection of the specified size
//              If already present of the right size then just clear to black
//              If wrong size then destroy and create a new one
//
// Returns: true if section was created
//
//****************************************************************
bool  CDIBSurface::Create (UINT Width,UINT Height,UINT BitDepth)
{
	RECT arect;

	ASSERT (m_DIBData);
// if we already have a surface with the current size then just repaint it to black
	if((m_DIBData->m_Data) && (Width == m_DIBData->m_Width) && (Height == m_DIBData->m_Height) && (BitDepth == m_DIBData->m_BitDepth))
	{
		arect.left = 0;
		arect.top = 0;
		arect.right = (long) m_DIBData->m_Width;
		arect.bottom = (long) m_DIBData->m_Height;
		HDC dc = GetDC ();
		FillRect (dc,&arect,(HBRUSH) GetStockObject (BLACK_BRUSH));
		ReleaseDC (dc);
		return true;
	}
// delete the current surface if we have one
	if(m_DIBData->m_Data)
		Destroy ();

	g_NumDibSurf++;

	if((Width == 0) || (Height == 0) || (BitDepth == 0))
		return true;

	m_DIBData->m_Width = Width;
	m_DIBData->m_Height = Height;
	m_DIBData->m_BitDepth = BitDepth;

// when we create a DIB section we need to setup a BITMAPINFO structure to pass to CreateDIBSection
// this structure hold all the data about out buffer
	switch(m_DIBData->m_BitDepth)
	{
	case 24:
		m_DIBData->m_Pitch = (int) m_DIBData->m_Width*3;
		m_DIBData->m_Pitch += ((4-(m_DIBData->m_Pitch&0x03))&0x03);
		break;
	case 16:
		m_DIBData->m_Pitch = (int) m_DIBData->m_Width*2;
		m_DIBData->m_Pitch += ((4-(m_DIBData->m_Pitch&0x03))&0x03);
		break;
	case 8:
		m_DIBData->m_Pitch = (int) m_DIBData->m_Width;
		m_DIBData->m_Pitch += ((4-(m_DIBData->m_Pitch&0x03))&0x03);
		break;
	case 4:
		m_DIBData->m_Pitch = (int) ((m_DIBData->m_Width+1)>>1);
		m_DIBData->m_Pitch += ((4-(m_DIBData->m_Pitch&0x03))&0x03);
		break;
	case 1:
		m_DIBData->m_Pitch = (int) ((m_DIBData->m_Width+7)>>3);
		m_DIBData->m_Pitch += ((4-(m_DIBData->m_Pitch&0x03))&0x03);
		break;
	default:
		OutputDebugString ("Unsupported Bitdepth for DibSections");
		return false;
	}

// create a DC to use the DIB section in
#if 0
	m_DIBData->m_BackDC = CreateCompatibleDC (NULL);
	ASSERT(NULL != m_DIBData->m_BackDC);
	if (NULL == m_DIBData->m_BackDC) {
		Destroy ();
		return false;
	}
#endif
  m_DIBData->m_BackBits = NULL;
// select the dib section into the DC from above
//	m_DIBData->m_OldBits = (HBITMAP) SelectObject (m_DIBData->m_BackDC,m_DIBData->m_BackBits);

	m_DIBData->m_Data = new BYTE [abs (m_DIBData->m_Pitch) * m_DIBData->m_Height];
	if (!m_DIBData->m_Data)
	{
		Destroy();
		return false;
	}
	memset (m_DIBData->m_Data,0,abs (m_DIBData->m_Pitch) * m_DIBData->m_Height);

	if(m_DIBData->m_Pitch < 0)		// only the case if we have a bottom-up section
		m_DIBData->m_UpperLeft = (m_DIBData->m_Data+((-1*m_DIBData->m_Pitch)*(((int)m_DIBData->m_Height)-1)));
	else
		m_DIBData->m_UpperLeft = m_DIBData->m_Data;

// init the whole surface to black
	arect.left = 0;
	arect.top = 0;
	arect.right = (long) m_DIBData->m_Width;
	arect.bottom = (long) m_DIBData->m_Height;

//	HDC testdc = CreateCompatibleDC (NULL);
//	HBITMAP testbit = (HBITMAP) SelectObject (testdc,m_DIBData->m_BackBits);
//	dc = GetDC ();
//	FillRect (dc,&arect,(HBRUSH) GetStockObject (BLACK_BRUSH));
//	ReleaseDC (dc);
//	SelectObject (testdc,testbit);
//	DeleteDC (testdc);

	return true;
}

//****************************************************************
//
// Function Name: CDIBSurface::Destroy
//
// Description: clean up after ourselves.
//
// Returns: nothing
//
//****************************************************************
void  CDIBSurface::Destroy (void)
{

	ASSERT (m_DIBData);
	if(!m_DIBData->m_Data)
		return;
	g_NumDibSurf--;
// select the old bitmap back into our DC then delete the DC
//	SelectObject (m_DIBData->m_BackDC,m_DIBData->m_OldBits);
//	DeleteDC (m_DIBData->m_BackDC);
//	m_DIBData->m_BackDC = NULL;
//	m_DIBData->m_OldBits = NULL;
	if (m_DIBData->m_BackBits)	// if you have the bits, then the data is from the dibsection
		DeleteObject (m_DIBData->m_BackBits);
	else
		delete [] m_DIBData->m_Data;	// otherwise the data was new'd
	m_DIBData->m_BackBits = NULL;

	m_DIBData->m_Width = m_DIBData->m_Height = m_DIBData->m_BitDepth = m_DIBData->m_Pitch = 0;
	m_DIBData->m_Data = NULL;
	m_DIBData->m_UpperLeft = NULL;

// select the old mask bitmap back into our DC then delete the DC
	m_DIBData->m_UseMask = false;
	delete m_DIBData->m_Mask;
	m_DIBData->m_Mask = NULL;
}

//****************************************************************
//
// Function Name: CDIBSurface::Fill
//
// Description: Will fill the rectangle passed in with the color requested
//
// Returns: true is successful
//
//****************************************************************
bool CDIBSurface::Fill (const CRect *therect,const COLORREF colorref)
{
	HBRUSH stupid;
	HDC dc;
	bool fred;
	CRect temp;

	ASSERT (m_DIBData);
	ASSERT (therect);
	if(!therect)
		return false;
	temp = *therect;

	temp.right += 1;
	temp.bottom += 1;
	stupid = CreateSolidBrush (colorref);
	dc = GetDC ();

#pragma warning (disable : 4800)
	fred = FillRect (dc,therect,stupid);

	ReleaseDC (dc);
	DeleteObject (stupid);
	return fred;
}

//****************************************************************
//
// Function Name: CDIBSurface::FillHatchBrush
//
// Description: Will fill the rectangle passed in with the color requested
//
// Returns: true is successful
//
//****************************************************************
bool CDIBSurface::FillHatchBrush (const CRect *therect,
				int stockHatchBrushStyle, const COLORREF colorref)
{
	HBRUSH stupid,oldBrush;
	HDC dc;
	bool fred;
	CRect temp;

	ASSERT (m_DIBData);
	ASSERT (therect);
	if(!therect)
		return false;
	temp = *therect;

	temp.right += 1;
	temp.bottom += 1;

	stupid = CreateHatchBrush (stockHatchBrushStyle,colorref);
	dc = GetDC ();

	oldBrush = (HBRUSH)SelectObject(dc,stupid);

#pragma warning (disable : 4800)
	fred = PatBlt(dc, therect->left, therect->top,therect->right, therect->bottom, 0x00A000C9);

	SelectObject(dc,oldBrush);
	ReleaseDC (dc);
	DeleteObject (stupid);
	return fred;
}

//****************************************************************
//
// Function Name: CDIBSurface::GetColor
//
// Description: will get the current color at the location x,y
//
// Returns: current color as a COLORREF
//
//****************************************************************
COLORREF CDIBSurface::GetColor (UINT x,UINT y) const
{
	DWORD value;
	COLORREF toret;
	RGBQUAD temp;
	int red,blue,green;
	HDC dc;

	ASSERT (m_DIBData);
	value = GetValue (x,y);
	switch(m_DIBData->m_BitDepth)
	{
	case 1:
	case 4:
	case 8:
		dc = GetDC ();
		if(GetDIBColorTable (dc,value,1,&temp) == 0)
		{
			ReleaseDC (dc);
			return RGB (0,0,0);
		}
		ReleaseDC (dc);
		toret = RGBQUADtoCOLORREF (temp);
		break;
	case 16:
		red = value >> 7;
		green = value >> 2;
		blue = (int) (value << 3);
		blue &= 0xf8;
		green &= 0xf8;
		red &= 0xf8;
		toret = (blue<<16) + (green<<8) + red;
		break;
	case 24:
		toret = (value);
		break;
	default:
		ASSERT (false);
		toret = false;
		break;
	}
	return toret;
}
	
void CDIBSurface::SetColor (UINT x,UINT y,COLORREF color)
{
	int red,green,blue;
	unsigned char *mem;

	ASSERT (m_DIBData);
	mem = GetMem ();
	mem += GetLocation (x,y);
	switch(m_DIBData->m_BitDepth)
	{
	case 16:
		unsigned short *mem16;
		mem16 = (unsigned short *) mem;
		
		red = color&0xff;
		green = (color>>8) & 0xff;
		blue = (color>>16) & 0xff;
		red >>= 3;
		green >>= 3;
		blue >>= 3;
		(*mem16) = (red<<10)+(green<<5)+blue;
		break;
	case 24:
		red = color&0xff;
		green = (color>>8) & 0xff;
		blue = (color>>16) & 0xff;

		(*mem) = blue;
		mem++;
		(*mem) = green;
		mem++;
		(*mem) = red;
		break;
	default:
		ASSERT (false);
		break;
	}
}

void CDIBSurface::SetColor( COLORREF color )
{
	Fill( 0, 0, m_DIBData->m_Width, m_DIBData->m_Height, color );
}

//****************************************************************
//
// Function Name: CDIBSurface::MaskBlt
//
// Description: will use src and mask to perform a mask blt to this DIBSurface
//          white is tranparent, black is opaque
//
// Returns: true if successful
//
//****************************************************************
bool CDIBSurface::MaskBlt (const int x,const int y,const int width,const int height,const HDC src,const HDC mask,const int srcx,const int srcy)
{
	ASSERT (m_DIBData);
	ASSERT (src);
	ASSERT (mask);
	if(!src)
		return false;
	if(!mask)
		return false;

	HDC dc = GetDC ();
	SetBkColor(dc, RGB(255, 255, 255));			 // 1s --> 0xFFFFFF
	SetTextColor(dc, RGB(0, 0, 0));					 // 0s --> 0x000000

	BitBlt(dc, x, y, width, height, src, srcx, srcy, SRCINVERT);
	BitBlt(dc, x, y, width, height, mask, srcx, srcy, SRCAND);
	BitBlt(dc, x, y, width, height, src, srcx, srcy, SRCINVERT);
	ReleaseDC (dc);
	return true;
}

//****************************************************************
//
// Function Name: CDIBSurface::MaskBlt
//
// Description: will perform a mask blt using the data from src
//
// Returns: true if successful
//
//****************************************************************
bool CDIBSurface::MaskBlt (const int x,const int y,const int width,const int height,const CDIBSurface *src,const int srcx,const int srcy)
{
	ASSERT (m_DIBData);
	ASSERT (src);
	ASSERT (src->m_DIBData);
	if(src == NULL)
		return false;
	ASSERT (src->UseMask ());
	if(!src->UseMask ())
		return false;

	HDC dc = GetDC ();
	SetBkColor(dc, RGB(255, 255, 255));			 // 1s --> 0xFFFFFF
	SetTextColor(dc, RGB(0, 0, 0));					 // 0s --> 0x000000

//  BitBlt(m_BackDC, x, y, width, height, src->m_BackDC, srcx, srcy, SRCINVERT);
	HDC dc2,dc3;
	dc2 = src->m_DIBData->m_Mask->GetDC ();
	dc3 = src->GetDC ();
	BitBlt(dc, x, y, width, height, dc2, srcx, srcy, SRCAND);
	BitBlt(dc, x, y, width, height, dc3, srcx, srcy, SRCPAINT);
	src->m_DIBData->m_Mask->ReleaseDC (dc2);
	src->ReleaseDC (dc3);
	ReleaseDC (dc);
	return true;
}



bool CDIBSurface::RotateBlt( int left, int top, int right, int bottom, const CDIBSurface& src, int x, int y, int ang )
{
#if 1
	//  This only works between similarly-depth'ed surfaces.
	if( GetBitDepth() != src.GetBitDepth() )
		return( Blt( CRect( left, top, right, bottom ), src, CPoint( x, y ) ) );
//		return( false );

	//  Degenerate case
	if( 0 == ang )
		return( Blt( CRect( left, top, right, bottom ), src, CPoint( x, y ) ) );

	int nDstW = GetWidth(), nDstH = GetHeight();
	if( nDstW <= left || nDstH < top || 0 > right || 0 > bottom )
		return( true );

	int nSrcW = src.GetWidth(), nSrcH = src.GetHeight();
	int nSrcP = src.GetPitch(), nDstP = GetPitch();

	if( 0 > left )
	{
		x -= left;
		left = 0;
	}
	if( 0 > top )
	{
		y -= top;
		top = 0;
	}

	if( nDstW < right )
		right = nDstW;
	if( nDstH < bottom )
		bottom = nDstH;

	nDstW = right - left;
	nDstH = bottom - top;

	if( x + nDstW > nSrcW )
	{
		nDstW = nSrcW - x;
		right = left + nDstW;
	}
	if( y + nDstH > nSrcH )
	{
		nDstH = nSrcH - y;
		bottom = top + nDstH;
	}

	if( nDstW != nDstH )
		return( false );

	const BYTE *pSBits = src.GetMem();
	if( 0 > nSrcP )
		pSBits -= nSrcP * (nSrcH - 1);

	BYTE *pDBits = GetMem();
	if( 0 > nDstP )
		pDBits -= nDstP * (nDstH - 1);

	int nOffset, nPixelSize = GetBitDepth() >> 3;
	int nPixelStride, nSrcStride, nDstStride = nDstP - nPixelSize * nDstW;

	switch( ang )
	{
#if 0	//	Handled by short-circuit case above
		case 0:
			nPixelStride = nPixelSize;
			nSrcStride = nSrcP - nDstW * nPixelSize;
			nOffset = 0;
			break;
#endif
		case 90:
			nPixelStride = -nSrcP;
			nSrcStride = nDstH * nSrcP + nPixelSize;
			nOffset = nSrcP * (nDstH - 1);
			break;

		case 180:
			nPixelStride = -nPixelSize;
			nSrcStride = nPixelSize * nDstW - nSrcP;
			nOffset = nSrcP * (nDstH - 1) + nPixelSize * (nDstW - 1);
			break;

		case 270:
			nPixelStride = nSrcP;
			nSrcStride = -(nSrcP * nDstH) - nPixelSize;
			nOffset = (nDstW - 1) * nPixelSize;
			break;

		default:
			return( false );
	}

	pDBits += nDstP * top + nPixelSize * left;
	pSBits += nSrcP * y + nPixelSize * x + nOffset;

	while( 0 < nDstH-- )
	{
		for( int i = 0; i < nDstW; i++ )
		{
			for( int j = 0; j < nPixelSize; j++ )
				*pDBits++ = pSBits[ j ];

			pSBits += nPixelStride;
		}

		pDBits += nDstStride;
		pSBits += nSrcStride;
	}

	return( true );
#else
	//  FIX  implement
	return( Blt( loc, src, srcloc ) );
#endif
}



bool CDIBSurface::TransparentBlt( int left, int top, int right, int bottom, const CDIBSurface& src, int x, int y, const COLORREF bgClr )
{
#if 1
	//  This only works between similarly-depth'ed surfaces.
	if( GetBitDepth() != src.GetBitDepth() )
		return( Blt( CRect( left, top, right, bottom ), src, CPoint( x, y ) ) );
//		return( false );

	int nDstW = GetWidth(), nDstH = GetHeight();
	if( nDstW <= left || nDstH < top || 0 > right || 0 > bottom )
		return( true );

	int nSrcW = src.GetWidth(), nSrcH = src.GetHeight();
	int nSrcP = src.GetPitch(), nDstP = GetPitch();

	if( 0 > left )
	{
		x -= left;
		left = 0;
	}
	if( 0 > top )
	{
		y -= top;
		top = 0;
	}

	if( nDstW < right )
		right = nDstW;
	if( nDstH < bottom )
		bottom = nDstH;

	nDstW = right - left;
	nDstH = bottom - top;

	if( x + nDstW > nSrcW )
	{
		nDstW = nSrcW - x;
		right = left + nDstW;
	}
	if( y + nDstH > nSrcH )
	{
		nDstH = nSrcH - y;
		bottom = top + nDstH;
	}

	const BYTE *pSBits = src.GetMem();
	if( 0 > nSrcP )
		pSBits -= nSrcP * (nSrcH - 1);

	BYTE *pDBits = GetMem();
	if( 0 > nDstP )
		pDBits -= nDstP * (nDstH - 1);

	switch( GetBitDepth() )
	{
		case 16:
		{
			pDBits += nDstP * top + left * sizeof( WORD );
			pSBits += nSrcP * y + x * sizeof( WORD );

			const WORD *pS = (const WORD *)pSBits;
			WORD *pD = (WORD *)pDBits;
			WORD crClr = ConvertColorToWord( bgClr );

			int nSrcS = (nSrcP - nDstW * sizeof( WORD )) / sizeof( WORD );
			int nDstS = (nDstP - nDstW * sizeof( WORD )) / sizeof( WORD );

			while( 0 < nDstH-- )
			{
				for( int i = nDstW; i; i-- )
				{
					if( *pS != crClr )
						*pD = *pS;

					pD++;
					pS++;
				}

				pD += nDstS;
				pS += nSrcS;
			}
			break;
		}

		case 24:
		{
			pDBits += nDstP * top + left * sizeof( RGBTRIPLE );
			pSBits += nSrcP * y + x * sizeof( RGBTRIPLE );

			const RGBTRIPLE *pS = (const RGBTRIPLE *)pSBits;
			RGBTRIPLE *pD = (RGBTRIPLE *)pDBits;
//			RGBTRIPLE crClr = ConvertColorToTriple( bgClr );

			int nSrcS = (nSrcP - nDstW * sizeof( RGBTRIPLE )) / sizeof( RGBTRIPLE );
			int nDstS = (nDstP - nDstW * sizeof( RGBTRIPLE )) / sizeof( RGBTRIPLE );

			while( 0 < nDstH-- )
			{
				for( int i = nDstW; i; i-- )
				{
					if( memcmp( pS, pD, 3 ) )
						*pD = *pS;

					pD++;
					pS++;
				}

				pD += nDstS;
				pS += nSrcS;
			}
			break;
		}

		case 32:
		{
			pDBits += nDstP * top + left * sizeof( DWORD );
			pSBits += nSrcP * y + x * sizeof( DWORD );

			const DWORD *pS = (const DWORD *)pSBits;
			DWORD *pD = (DWORD *)pDBits;
			DWORD crClr = ConvertColorToLong( bgClr );

			int nSrcS = (nSrcP - nDstW * sizeof( DWORD )) / sizeof( DWORD );
			int nDstS = (nDstP - nDstW * sizeof( DWORD )) / sizeof( DWORD );

			while( 0 < nDstH-- )
			{
				for( int i = nDstW; i; i-- )
				{
					if( (0x00ffffff & *pS) != crClr )
						*pD = *pS;

					pD++;
					pS++;
				}

				pD += nDstS;
				pS += nSrcS;
			}
			break;
		}
	}

	return( true );
#else
	//  FIX  implement
	Blt( loc, src, srcloc );
	return( true );
#endif
}

//****************************************************************
//
// Function Name: CDIBSurface::CalcMask
//
// Description: will create a mask for the DIBSurface based on the color passed in
//          all pixels that are the same color as colorref are considered transparent
//
// Returns: true if successful
//
//****************************************************************
bool CDIBSurface::CalcMask (COLORREF colorref)
{
	if(!CalcMask ())
		return false;
	switch(m_DIBData->m_BitDepth)
	{
	case 1:
		m_DIBData->m_UseMask = Create1BitMask (colorref);
		break;
	case 4:
		m_DIBData->m_UseMask = Create4BitMask (colorref);
		break;
	case 8:
		m_DIBData->m_UseMask = Create8BitMask (colorref);
		break;
	case 16:
		m_DIBData->m_UseMask = Create16BitMask (colorref);
		break;
	case 24:
		m_DIBData->m_UseMask = Create24BitMask (colorref);
		break;
	default:
		ASSERT (false);
		break;
	}

	if(!m_DIBData->m_UseMask)
	{
		delete m_DIBData->m_Mask;
		m_DIBData->m_Mask = NULL;
	}
	return m_DIBData->m_UseMask;
}

//****************************************************************
//
// Function Name: CDIBSurface::CalcMask
//
// Description: will create a mask for the DIBSurface the initial image is all opaque
//
// Returns: true if successful
//
//****************************************************************
bool CDIBSurface::CalcMask (void)
{

	ASSERT (m_DIBData);
	delete m_DIBData->m_Mask;
	m_DIBData->m_Mask = NULL;
	m_DIBData->m_Mask = new CDIBSurface ();
	if(!m_DIBData->m_Mask)
		return false;
	if(!m_DIBData->m_Mask->Create (m_DIBData->m_Width,m_DIBData->m_Height,1))		//lint !e539  huh
	{
		delete m_DIBData->m_Mask;
		m_DIBData->m_Mask = NULL;
		return false;
	}
	m_DIBData->m_UseMask = true;

	return true;
}

bool CDIBSurface::DestroyMask (void)
{
	ASSERT (m_DIBData);
	delete m_DIBData->m_Mask;
	m_DIBData->m_Mask = NULL;
	m_DIBData->m_UseMask = false;
	return true;
}

int CDIBSurface::FloodFill (const CPoint& start,const COLORREF color)
{
	COLORREF srccolor,intcolor;
	CPoint temp;
	std::stack<CPoint> data;
	int count=0;

	ASSERT (m_DIBData);
	if(m_DIBData->m_BitDepth == 24)
		return FloodFill24 (start,color);
	intcolor = color;
	if (m_DIBData->m_BitDepth == 16)
		intcolor &= 0x00f8f8f8;
	srccolor = GetColor (start.x,start.y);
	if(srccolor == intcolor)
		return 0;
	data.push (start);
	while(!data.empty ())
	{
		temp = data.top ();
		data.pop ();
		if(GetColor (temp.x,temp.y)==srccolor)
		{
			SetColor (temp.x,temp.y,color);
			count++;
			if(temp.y != 0)
				data.push (CPoint(temp.x,temp.y-1));
			if(temp.y != (m_DIBData->m_Height-1))
				data.push (CPoint(temp.x,temp.y+1));
			if(temp.x != 0)
				data.push (CPoint(temp.x-1,temp.y));
			if(temp.x != (m_DIBData->m_Width-1))
				data.push (CPoint(temp.x+1,temp.y));
		}
	}
	return count;
}

// assume the alpha is an eight bit surface where the indexs are really the alpha values
// 0 in the alpha means to use leave the dest alone
// 255 in the alpha means to be 100% from the source.

bool CDIBSurface::AlphaBlt (const int x,const int y,const int width,const int height,const CDIBSurface *src,const CDIBSurface *alpha,const int srcx,const int srcy,const int alphasrcx,const int alphasrcy)
{
	ASSERT (m_DIBData);
	ASSERT (src->m_DIBData);
	ASSERT (alpha->m_DIBData);
	ASSERT (alpha->GetBitDepth () == 8);
	ASSERT ((GetBitDepth()==16)||(GetBitDepth()==24));
	ASSERT ((src->GetBitDepth()==16)||(src->GetBitDepth()==24));
	ASSERT (GetBitDepth() == src->GetBitDepth ());
	ASSERT ((x+width) <= GetWidth ());
	ASSERT ((srcx+width) <= src->GetWidth ());
	ASSERT ((y+height) <= GetHeight ());
	ASSERT ((srcy+height) <= src->GetHeight ());
	ASSERT (x >= 0);
	ASSERT (y >= 0);
	ASSERT (width >= 0);
	ASSERT (height >= 0);
	ASSERT (srcx >= 0);
	ASSERT (srcy >= 0);
	int asrcx = (alphasrcx < 0) ? srcx : alphasrcx;
	int asrcy = (alphasrcy < 0) ? srcy : alphasrcy;
	ASSERT ((asrcx+width) <= alpha->GetWidth ());
	ASSERT ((asrcy+height) <= alpha->GetHeight ());
	switch(GetBitDepth ())
	{
	case 16:
		return AlphaBlt16 (x,y,width,height,src,alpha,srcx,srcy,asrcx,asrcy);
		break;
	case 24:
		return AlphaBlt24 (x,y,width,height,src,alpha,srcx,srcy,asrcx,asrcy);
		break;
	default:
		ASSERT (false);
		break;
	}
	return false;
}
	
bool CDIBSurface::ColorBlt (const int x,const int y,const int width,const int height,const CDIBSurface* src,const int srcx,const int srcy,COLORREF color,bool addred,bool addgreen,bool addblue,CDIBSurface *altmask)
{
	ASSERT (m_DIBData);
	ASSERT (src->m_DIBData);
	ASSERT ((GetBitDepth()==16)||(GetBitDepth()==24));
	ASSERT (GetBitDepth() == src->GetBitDepth ());
	ASSERT ((src!=this) || ((srcx==x) && (srcy==y)));
	ASSERT ((x+width) <= GetWidth ());
	ASSERT ((srcx+width) <= src->GetWidth ());
	ASSERT ((y+height) <= GetHeight ());
	ASSERT ((srcy+height) <= src->GetHeight ());
	ASSERT (x >= 0);
	ASSERT (y >= 0);
	ASSERT (width >= 0);
	ASSERT (height >= 0);
	ASSERT (srcx >= 0);
	ASSERT (srcy >= 0);
	switch(GetBitDepth ())
	{
	case 16:
		return ColorBlt16 (x,y,width,height,src,srcx,srcy,color,addred,addgreen,addblue,altmask);
		break;
	case 24:
		return ColorBlt24 (x,y,width,height,src,srcx,srcy,color,addred,addgreen,addblue,altmask);
		break;
	default:
		ASSERT (false);
		break;
	}
	return false;
}

bool CDIBSurface::GrayBlt (const int x,const int y,const int width,const int height,const CDIBSurface* src,const int srcx,const int srcy, CDIBSurface *altmask)
{
	ASSERT (m_DIBData);
	ASSERT (src->m_DIBData);
	ASSERT ((GetBitDepth()==16)||(GetBitDepth()==24));
	ASSERT (GetBitDepth() == src->GetBitDepth ());
	ASSERT ((src!=this) || ((srcx==x) && (srcy==y)));
	ASSERT ((x+width) <= GetWidth ());
	ASSERT ((srcx+width) <= src->GetWidth ());
	ASSERT ((y+height) <= GetHeight ());
	ASSERT ((srcy+height) <= src->GetHeight ());
	ASSERT (x >= 0);
	ASSERT (y >= 0);
	ASSERT (width >= 0);
	ASSERT (height >= 0);
	ASSERT (srcx >= 0);
	ASSERT (srcy >= 0);
	switch(GetBitDepth ())
	{
	case 16:
		return GrayBlt16 (x,y,width,height,src,srcx,srcy,altmask);
		break;
	case 24:
		return GrayBlt24 (x,y,width,height,src,srcx,srcy,altmask);
		break;
	default:
		ASSERT (false);
		break;
	}
	return false;
}

bool CDIBSurface::MultBlt (const int x,const int y,const int width,const int height,const CDIBSurface* src,const int srcx,const int srcy,const float red,const float green,const float blue,CDIBSurface *altmask)
{
	ASSERT (m_DIBData);
	ASSERT (src->m_DIBData);
	ASSERT ((GetBitDepth()==16)||(GetBitDepth()==24));
	ASSERT (GetBitDepth() == src->GetBitDepth ());
	ASSERT ((src!=this) || ((srcx==x) && (srcy==y)));

	int nWidth = GetWidth(), nHeight = GetHeight();
	int l = x, t = y, w = width, h = height;

	if( 0 > l )
	{
		w += l;
		l = 0;
	}
	if( 0 > t )
	{
		h += t;
		t = 0;
	}

	if( nWidth < l + w )
		w = nWidth - l;
	if( nHeight < t + h )
		h = nHeight - t;

	ASSERT (w >= 0);
	ASSERT (h >= 0);
	ASSERT ((srcx+w) <= src->GetWidth ());
	ASSERT ((srcy+h) <= src->GetHeight ());
	ASSERT (srcx >= 0);
	ASSERT (srcy >= 0);

//	ASSERT ((x+width) <= GetWidth ());
//	ASSERT ((y+height) <= GetHeight ());
//	ASSERT (x >= 0);
//	ASSERT (y >= 0);

	switch(GetBitDepth ())
	{
	case 16:
		return MultBlt16 (l,t,w,h,src,srcx,srcy,red,green,blue,altmask);
		break;
	case 24:
		return MultBlt24 (l,t,w,h,src,srcx,srcy,red,green,blue,altmask);
		break;
	default:
		ASSERT (false);
		break;
	}
	return false;
}

//****************************************************************
//
// Function Name: MaskBlt
//
// Description: will use src and mask to perform a mask blt to this DIBSurface
//          white is tranparent, black is opaque
//
// Returns: true if successful
//
//****************************************************************
bool MaskBlt (HDC dest,const int x,const int y,const int width,const int height,const HDC src,const HDC mask,const int srcx,const int srcy,const int maskx,const int masky)
{
	ASSERT (src);
	ASSERT (mask);
	if((!src) || (!mask))
		return false;

	SetBkColor(dest, RGB(255, 255, 255));			 // 1s --> 0xFFFFFF
	SetTextColor(dest, RGB(0, 0, 0));					 // 0s --> 0x000000

	BitBlt(dest, x, y, width, height, src, srcx, srcy, SRCINVERT);
	BitBlt(dest, x, y, width, height, mask, maskx, masky, SRCAND);
	BitBlt(dest, x, y, width, height, src, srcx, srcy, SRCINVERT);
	return true;
}
bool MaskBlt (HDC dest,const int x,const int y,const int width,const int height,const HDC src,const HDC mask,const int srcx,const int srcy)
{
	ASSERT (dest);
	ASSERT (src);
	ASSERT (mask);
	if((!src) || (!mask))
		return false;

	SetBkColor(dest, RGB(255, 255, 255));			 // 1s --> 0xFFFFFF
	SetTextColor(dest, RGB(0, 0, 0));					 // 0s --> 0x000000

	BitBlt(dest, x, y, width, height, src, srcx, srcy, SRCINVERT);
	BitBlt(dest, x, y, width, height, mask, srcx, srcy, SRCAND);
	BitBlt(dest, x, y, width, height, src, srcx, srcy, SRCINVERT);
	return true;
}

//****************************************************************
//
// Function Name: MaskBlt
//
// Description: will perform a mask blt using the data from src
//
// Returns: true if successful
//
//****************************************************************
bool MaskBlt (HDC dest,const int x,const int y,const int width,const int height,const CDIBSurface *src,const int srcx,const int srcy)
{
	ASSERT (dest);
	ASSERT (src);
//	ASSERT (src->UseMask ());
	if(!src)
		return false;
	if (src->UseMask ())
	{
		SetBkColor(dest, RGB(255, 255, 255));			 // 1s --> 0xFFFFFF
		SetTextColor(dest, RGB(0, 0, 0));					 // 0s --> 0x000000

		HDC tmphdc;

		/*
		tmphdc = src->GetDC ();
		BitBlt(dest, x, y, width, height, tmphdc, srcx, srcy, SRCINVERT);
		src->ReleaseDC(tmphdc);
		*/

		tmphdc = src->Mask ()->GetDC ();
		BitBlt(dest, x, y, width, height, tmphdc, srcx, srcy, SRCAND);
		src->Mask ()->ReleaseDC(tmphdc);

		tmphdc = src->GetDC ();
		BitBlt(dest, x, y, width, height, tmphdc, srcx, srcy, SRCPAINT);
		src->ReleaseDC(tmphdc);
	}
	else
	{
		HDC tmphdc;
		tmphdc = src->GetDC ();
		BitBlt(dest, x, y, width, height, tmphdc, srcx, srcy, SRCCOPY);
		src->ReleaseDC(tmphdc);
	}

	return true;
}

bool CDIBSurface::CalcMask (const std::vector<COLORREF>& colors)
{
	std::vector<COLORREF>::const_iterator iter;
	UINT x,y;
	COLORREF curcolor;
	COLORREF curmask;

	ASSERT (m_DIBData);

	if(!CalcMask ())
		return false;

	ASSERT (m_DIBData->m_Mask);
	if(!m_DIBData->m_Mask)
		return false;

	iter = colors.begin ();
	while(iter != colors.end ())
	{
		curmask = (*iter);
		for(y=0;y<m_DIBData->m_Height;y++)
		{
			for(x=0;x<m_DIBData->m_Width;x++)
			{
				curcolor = GetColor (x,y);
				if(curcolor == curmask)
					m_DIBData->m_Mask->SetColor (x,y,RGB (255,255,255));
			}
		}
		iter++;
	}
	for(y=0;y<m_DIBData->m_Height;y++)
	{
		for(x=0;x<m_DIBData->m_Width;x++)
		{
			curcolor = m_DIBData->m_Mask->GetColor (x,y);
			if(curcolor == RGB (255,255,255))
				SetColor (x,y,RGB (0,0,0));
		}
	}
	return true;
}

bool CDIBSurface::ConvertBitDepth (int newdepth)
{
	CDIBSurface temp;

	ASSERT (m_DIBData);
	if (m_DIBData->m_BitDepth == newdepth)
		return true;
	if((m_DIBData->m_BitDepth == 24) && (newdepth == 16))
		return Convert24to16 ();
	if(!temp.Create (m_DIBData->m_Width,m_DIBData->m_Height,newdepth))
		return false;

	if (!temp.Blt (0,0,m_DIBData->m_Width,m_DIBData->m_Height,this,0,0))
		return false;
	if(m_DIBData->m_Mask)
	{
		if(!temp.CalcMask ())
			return false;
		HDC dc1,dc2;
		dc1 = temp.m_DIBData->m_Mask->GetDC ();
		dc2 = m_DIBData->m_Mask->GetDC ();
		BitBlt (dc1,0,0,m_DIBData->m_Width,m_DIBData->m_Height,dc2,0,0,SRCCOPY);
		temp.m_DIBData->m_Mask->ReleaseDC (dc1);
		m_DIBData->m_Mask->ReleaseDC (dc2);
	}


//	(*temp.m_RefCount)++;
	temp.AddRef ();
	Destroy ();
	memcpy (m_DIBData,temp.m_DIBData,sizeof (DIBData));
	delete temp.m_DIBData;
	delete temp.m_RefCount;
	temp.m_DIBData = NULL;
	temp.m_RefCount = NULL;
	return true;
}


HBITMAP CDIBSurface::GetBitmap (void) const	// actually creates the DIB section (if needed)
{
	if (m_DIBData->m_BackBits != NULL)
		return m_DIBData->m_BackBits;

	BITMAPINFO *bitinfo = AllocBitmapInfo();

	unsigned char *olddata = m_DIBData->m_Data;

	HDC dc = ::GetDC (NULL);
	m_DIBData->m_BackBits = CreateDIBSection (dc,bitinfo,DIB_RGB_COLORS,(void **) &m_DIBData->m_Data,NULL,NULL);
	if (m_DIBData->m_BackBits == NULL)
	{
		DWORD error = GetLastError ();
		OutputDebugString ("error code is ");
		m_DIBData->m_Data = olddata;
	}
	else	// move data over
	{
//		::SetDIBits (dc, m_DIBData->m_BackBits, 0, bitinfo->bmiHeader.biHeight, olddata, bitinfo, DIB_RGB_COLORS);
		memcpy (m_DIBData->m_Data, olddata, abs (m_DIBData->m_Pitch) * m_DIBData->m_Height);
		delete olddata;
	}
	::ReleaseDC (NULL, dc);

	delete bitinfo;

	if(m_DIBData->m_Pitch < 0)		// only the case if we have a bottom-up section
		m_DIBData->m_UpperLeft = (m_DIBData->m_Data+((-1*m_DIBData->m_Pitch)*(((int)m_DIBData->m_Height)-1)));
	else
		m_DIBData->m_UpperLeft = m_DIBData->m_Data;

	ASSERT(NULL != m_DIBData->m_BackBits);
	return m_DIBData->m_BackBits;
}


void CDIBSurface::ReleaseBitmap (void) const	// call to free up GDI resources
{
	if (m_DIBData->m_BackBits == NULL)
		return;

	unsigned char *newdata = new unsigned char [abs (m_DIBData->m_Pitch) * m_DIBData->m_Height];
	if (!newdata)
		return;	// GDI resource not freed, but bitmap still works

#if 1
	// m_BackBits must not be selected into a DC
	ASSERT (m_DIBData->m_SelectedDC == NULL);
	// (if that's a problem, release the dc here)

	memcpy (newdata, m_DIBData->m_Data, abs (m_DIBData->m_Pitch) * m_DIBData->m_Height);
	DeleteObject (m_DIBData->m_BackBits);
	m_DIBData->m_BackBits = NULL;
	m_DIBData->m_Data = newdata;

	if(m_DIBData->m_Pitch < 0)		// only the case if we have a bottom-up section
		m_DIBData->m_UpperLeft = (m_DIBData->m_Data+((-1*m_DIBData->m_Pitch)*(((int)m_DIBData->m_Height)-1)));
	else
		m_DIBData->m_UpperLeft = m_DIBData->m_Data;
#else
	BITMAPINFO *bitinfo = AllocBitmapInfo();
	if (!bitinfo)
		delete newdata;
	else
	{
		// m_BackBits must not be selected into a DC
		ASSERT (m_DIBData->m_SelectedDC == NULL);
		// (if that's a problem, release the dc here)

		HDC dc = ::GetDC (NULL);
		// move data over
		if (GetDIBits (dc, m_DIBData->m_BackBits, 0, bitinfo->bmiHeader.biHeight, newdata, bitinfo, DIB_RGB_COLORS))
		{
			DeleteObject (m_DIBData->m_BackBits);
			m_DIBData->m_BackBits = NULL;
			m_DIBData->m_Data = newdata;

			if(m_DIBData->m_Pitch < 0)		// only the case if we have a bottom-up section
				m_DIBData->m_UpperLeft = (m_DIBData->m_Data+((-1*m_DIBData->m_Pitch)*(((int)m_DIBData->m_Height)-1)));
			else
				m_DIBData->m_UpperLeft = m_DIBData->m_Data;
		}
		else
		{
			DWORD err = GetLastError();
			DPRINTF ("GetDIBits failed, error 0x%lx\n", err);
			delete newdata;
		}
		::ReleaseDC (NULL, dc);
	}

	delete bitinfo;
#endif
}


BITMAPINFO *CDIBSurface::AllocBitmapInfo (void) const	// delete when done with it
{
	short index;
	BITMAPINFO *bitinfo;

// when we create a DIB section we need to setup a BITMAPINFO structure to pass to CreateDIBSection
// this structure hold all the data about out buffer
	switch(m_DIBData->m_BitDepth)
	{
	case 24:
		bitinfo = (BITMAPINFO *) new BYTE[sizeof (BITMAPINFO)];
		if(bitinfo == NULL)
			return NULL;
		memset (bitinfo,0,sizeof (BITMAPINFO));

		bitinfo->bmiHeader.biBitCount = 24;
		break;
	case 16:
		bitinfo = (BITMAPINFO *) new BYTE[sizeof (BITMAPINFO)];
		if(bitinfo == NULL)
			return NULL;
		memset (bitinfo,0,sizeof (BITMAPINFO));

		bitinfo->bmiHeader.biBitCount = 16;
		break;
	case 8:
		bitinfo = (BITMAPINFO *) new BYTE[sizeof (BITMAPINFO)+(sizeof (PALETTEENTRY)*256)];
		if(bitinfo == NULL)
			return NULL;			//lint !e525  huh
		memset (bitinfo,0,sizeof (BITMAPINFO)+(sizeof (PALETTEENTRY)*256));	//lint !e419 ok size good
		for(index = 0;index<256;index++)
		{
			bitinfo->bmiColors[index].rgbRed = 0;		//lint !e662  !e661		ok
			bitinfo->bmiColors[index].rgbGreen = 0;	//lint !e662  !e661		ok
			bitinfo->bmiColors[index].rgbBlue = 0;	//lint !e662  !e661		ok
		}

		bitinfo->bmiHeader.biBitCount = 8;
		break;
	case 4:
		bitinfo = (BITMAPINFO *) new BYTE[sizeof (BITMAPINFO)+(sizeof (PALETTEENTRY)*16)];
		if(bitinfo == NULL)
			return NULL;					//lint !e525  huh
		memset (bitinfo,0,sizeof (BITMAPINFO)+(sizeof (PALETTEENTRY)*16));	//lint !e419 size is good
		for(index = 0;index<16;index++)
		{
			bitinfo->bmiColors[index].rgbRed = 0;		//lint !e662  !e661		ok
			bitinfo->bmiColors[index].rgbGreen = 0;	//lint !e662  !e661		ok
			bitinfo->bmiColors[index].rgbBlue = 0;	//lint !e662  !e661		ok
		}

		bitinfo->bmiHeader.biBitCount = 4;
		break;
	case 1:
		bitinfo = (BITMAPINFO *) new BYTE[sizeof (BITMAPINFO)+(sizeof (PALETTEENTRY)*2)];
		if(bitinfo == NULL)
			return NULL;					//lint !e525  huh
		memset (bitinfo,0,sizeof (BITMAPINFO)+(sizeof (PALETTEENTRY)*2));	//lint !e419 size is good

		bitinfo->bmiColors[0].rgbRed = 0;				//line !e662  !e661
		bitinfo->bmiColors[0].rgbGreen = 0;			//line !e662  !e661
		bitinfo->bmiColors[0].rgbBlue = 0;			//line !e662  !e661

		bitinfo->bmiColors[1].rgbRed = 255;			//lint !e415   ok
		bitinfo->bmiColors[1].rgbGreen = 255;		//lint !e415		ok
		bitinfo->bmiColors[1].rgbBlue = 255;		//lint !e415		ok

		bitinfo->bmiHeader.biBitCount = 1;
		break;
	default:
		OutputDebugString ("Unsupported Bitdepth for DibSections");
		return NULL;
	}
// these are our generic fields for both 8 and 16-bit
	bitinfo->bmiHeader.biHeight = (long) (-1*((int) m_DIBData->m_Height));	 // we use a negative height to mean a top-down bitmap
	bitinfo->bmiHeader.biWidth = (long) m_DIBData->m_Width;
	bitinfo->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);
	bitinfo->bmiHeader.biPlanes = 1;
	bitinfo->bmiHeader.biCompression = BI_RGB;
	bitinfo->bmiHeader.biSizeImage = 0;
	bitinfo->bmiHeader.biXPelsPerMeter = 0;
	bitinfo->bmiHeader.biYPelsPerMeter = 0;
	bitinfo->bmiHeader.biClrUsed = 0;
	bitinfo->bmiHeader.biClrImportant = 0;

	return bitinfo;
}


#ifdef USE_FEWER_GDI_RES
using namespace NWarp;

namespace {
bool intersectintervals (int width, int srcx, int srcmax, int destx, int destmax, int& srcoffx, int& destoffx, int& interw)
{
	if (destx + width <= 0  ||  destx >= destmax  ||  srcx + width <= 0  ||  srcx >= srcmax)
		return false;

	// clip by minimum dest coord
	if (destx < 0)
	{
		destoffx = 0;
		srcoffx = srcx - destx;
		interw = width + destx;
	}
	else
	{
		destoffx = destx;
		srcoffx = srcx;
		interw = width;
	}

	// clip by minimum src coord
	if (srcx < 0)
	{
		destoffx -= srcx;
		srcoffx -= srcx;
		interw += srcx;
	}

	// clip by maximum source and dest coords
	if (srcoffx + interw > srcmax)
		interw = srcmax - srcoffx;
	if (destoffx + interw > destmax)
		interw = destmax - destoffx;

	ASSERT (srcoffx >= 0);
	ASSERT (srcoffx < srcmax);
	ASSERT (destoffx >= 0);
	ASSERT (destoffx < destmax);
	ASSERT (interw > 0);
	ASSERT (interw <= width);

	return true;
}
}

// this version does not have the rop argument, assumes SRC_COPY
template <class PixelHandlerType>
bool BltNonGDI (PixelHandlerType& pixelhandler, const CDIBSurface& dest,const int destx,const int desty,const int width,const int height,const CDIBSurface& src,const int srcx,const int srcy)
{
	ASSERT (pixelhandler.Depth() == src.GetBitDepth());
	ASSERT (pixelhandler.Depth() == dest.GetBitDepth());

	int srcoffx, destoffx, interw;
	int srcoffy, destoffy, interh;

	if (!intersectintervals (width, srcx, src.GetWidth(), destx, dest.GetWidth(), srcoffx, destoffx, interw))
		return true;	// nothing to blit
	if (!intersectintervals (height, srcy, src.GetHeight(), desty, dest.GetHeight(), srcoffy, destoffy, interh))
		return true;	// nothing to blit

	const unsigned char *srcscanline = src.GetMem() + srcoffy * src.GetPitch();
	const unsigned char *destscanline = dest.GetMem() + destoffy * dest.GetPitch();

	// can be made much faster by doing larger reads/writes on aligned data
#if 1
	if ((pixelhandler.Depth() & 0x7) == 0)
	{
		const int pixsize = (pixelhandler.Depth() >> 3);
		for (int j = 0; j < interh; j++)
		{
			memcpy ((void*)(destscanline + destoffx * pixsize), (void*)(srcscanline + srcoffx * pixsize), interw * pixsize);
			srcscanline += src.GetPitch();
			destscanline += dest.GetPitch();
		}
	}
	else
#endif
		for (int j = 0; j < interh; j++)
		{
			CPixelAddress s = pixelhandler.Increment (pixelhandler.PixelAddress ((void*)srcscanline), srcoffx);
			CPixelAddress d = pixelhandler.Increment (pixelhandler.PixelAddress ((void*)destscanline), destoffx);
			for (int i = 0; i < interw; i++)
			{
				CPixel pixel = pixelhandler.Get (s);
				pixelhandler.Set (d, pixel);
				s = pixelhandler.Increment (s);
				d = pixelhandler.Increment (d);
			}
			srcscanline += src.GetPitch();
			destscanline += dest.GetPitch();
		}
	return true;
}


#pragma intrinsic(memcpy)

// this version does not have the rop argument, assumes SRC_COPY
bool BltNonGDI16 (const CDIBSurface& dest,const int destx,const int desty,const int width,const int height,const CDIBSurface& src,const int srcx,const int srcy)
{
	ASSERT (16 == src.GetBitDepth());
	ASSERT (16 == dest.GetBitDepth());

	int srcoffx, destoffx, interw;
	int srcoffy, destoffy, interh;

	if (!intersectintervals (width, srcx, src.GetWidth(), destx, dest.GetWidth(), srcoffx, destoffx, interw))
		return true;	// nothing to blit
	if (!intersectintervals (height, srcy, src.GetHeight(), desty, dest.GetHeight(), srcoffy, destoffy, interh))
		return true;	// nothing to blit

	const int srcpitch = src.GetPitch();
	const int destpitch = dest.GetPitch();
	const unsigned char *srcscanline = src.GetMem() + srcoffy * srcpitch;
	const unsigned char *destscanline = dest.GetMem() + destoffy * destpitch;

	const unsigned char *s = srcscanline + (srcoffx << 1);
	const unsigned char *d = destscanline + (destoffx << 1);
	const unsigned char *q = s + interh * srcpitch;
	ASSERT (((DWORD)s & 0x03) != 3);	// these addresses cause stalls, but should not happen
	ASSERT (((DWORD)d & 0x03) != 3);	// these addresses cause stalls, but should not happen
	while (s != q)
	{
		memcpy ((void*)d, s, interw << 1);
		s += srcpitch;
		d += destpitch;
	}

	return true;
}


// this version does not have the rop argument, assumes SRC_COPY
template <class PixelHandlerType>
bool MaskBltNonGDI (PixelHandlerType& pixelhandler, const CDIBSurface& dest,const int destx,const int desty,int width,int height,const CDIBSurface& src,int srcx,int srcy)
{
	ASSERT (pixelhandler.Depth() == src.GetBitDepth());
	ASSERT (pixelhandler.Depth() == dest.GetBitDepth());
	ASSERT (src.UseMask());
	if(!src.UseMask ())
		return false;

	CPixelHandler1 pixelhandler1;
	int srcoffx, destoffx, interw;
	int srcoffy, destoffy, interh;

	if (width <= 0  ||  !intersectintervals (width, srcx, src.GetWidth(), destx, dest.GetWidth(), srcoffx, destoffx, interw))
		return true;	// nothing to blit
	if (height <= 0  ||  !intersectintervals (height, srcy, src.GetHeight(), desty, dest.GetHeight(), srcoffy, destoffy, interh))
		return true;	// nothing to blit

	const unsigned char *srcscanline = src.GetMem() + srcoffy * src.GetPitch();
	const unsigned char *maskscanline = src.Mask()->GetMem() + srcoffy * src.Mask()->GetPitch();
	const unsigned char *destscanline = dest.GetMem() + destoffy * dest.GetPitch();

	// can be made much faster by doing larger reads/writes on aligned data
	for (int j = 0; j < interh; j++)
	{
		CPixelAddress m = pixelhandler1.Increment (pixelhandler1.PixelAddress ((void*)maskscanline), srcoffx);
		CPixelAddress s = pixelhandler.Increment (pixelhandler.PixelAddress ((void*)srcscanline), srcoffx);
		CPixelAddress d = pixelhandler.Increment (pixelhandler.PixelAddress ((void*)destscanline), destoffx);
		for (int i = 0; i < interw; i++)
		{
			if (pixelhandler1.Get (m) == 0)
				pixelhandler.Set (d, pixelhandler.Get (s));

			m = pixelhandler1.Increment (m);
			s = pixelhandler.Increment (s);
			d = pixelhandler.Increment (d);
		}
		maskscanline += src.Mask()->GetPitch();
		srcscanline += src.GetPitch();
		destscanline += dest.GetPitch();
	}
	return true;
}


// this version does not have the rop argument, assumes SRC_COPY
bool MaskBltNonGDI16 (const CDIBSurface& dest,const int destx,const int desty,int width,int height,const CDIBSurface& src,int srcx,int srcy)
{
	ASSERT (16 == src.GetBitDepth());
	ASSERT (16 == dest.GetBitDepth());
	ASSERT (src.UseMask());
	if(!src.UseMask ())
		return false;

	int srcoffx, destoffx, interw;
	int srcoffy, destoffy, interh;

	if (!intersectintervals (width, srcx, src.GetWidth(), destx, dest.GetWidth(), srcoffx, destoffx, interw))
		return true;	// nothing to blit
	if (!intersectintervals (height, srcy, src.GetHeight(), desty, dest.GetHeight(), srcoffy, destoffy, interh))
		return true;	// nothing to blit

	CPixelHandler1 pixelhandler1;

	const int srcpitch = src.GetPitch();
	const int destpitch = dest.GetPitch();
	const int maskpitch = src.Mask()->GetPitch();
	const unsigned char *srcscanline = src.GetMem() + srcoffy * srcpitch;
	const unsigned char *maskscanline = src.Mask()->GetMem() + srcoffy * maskpitch;
	const unsigned char *destscanline = dest.GetMem() + destoffy * destpitch;

	const unsigned char *s = srcscanline + (srcoffx << 1);
	const unsigned char *d = destscanline + (destoffx << 1);
	const unsigned char *q = s + interh * srcpitch;
	ASSERT (((DWORD)s & 0x03) != 3);	// these addresses cause stalls, but should not happen
	ASSERT (((DWORD)d & 0x03) != 3);	// these addresses cause stalls, but should not happen
	while (s != q)
	{
		CPixelAddress m = pixelhandler1.Increment (pixelhandler1.PixelAddress ((void*)maskscanline), srcoffx);
		const unsigned short *is = (const unsigned short *)s;
		const unsigned short *iq = (const unsigned short *)s + interw;
		unsigned short *id = (unsigned short *)d;
		while (is != iq)
		{
			if (pixelhandler1.Get (m) == 0)
				*id = *is;
			m = pixelhandler1.Increment (m);
			++is, ++id;
		}
		s += srcpitch;
		d += destpitch;
		maskscanline += maskpitch;
	}

	return true;
}


// this version does not have the rop argument, assumes SRC_COPY
bool CDIBSurface::BltNonGDI (int x,int y,int width,int height,const CDIBSurface& src,int srcx,int srcy)
{
#ifdef _DEBUG
	static int doit = 0;
	if (doit)
	{	// revert back to traditional blit for tests
		HDC dc1,dc2;
		bool toret;

		dc1 = GetDC ();
		dc2 = src.GetDC ();
		if (!(dc1 && dc2))
		{
			if (dc1)
				ReleaseDC (dc1);
			if (dc2)
				src.ReleaseDC (dc2);
			return false;
		}
		toret = (::BitBlt (dc1,x,y,width,height,dc2,srcx,srcy,SRCCOPY) == TRUE);
		ReleaseDC (dc1);
		src.ReleaseDC (dc2);
		return toret;
	}
#endif

	ASSERT (GetBitDepth() == src.GetBitDepth());
	switch (GetBitDepth())
	{
		case 1:
			return ::BltNonGDI (CPixelHandler1(), *this,x,y,width,height,src,srcx,srcy);
		case 8:
			return ::BltNonGDI (CPixelHandler8(), *this,x,y,width,height,src,srcx,srcy);
		case 16:
			return ::BltNonGDI16 (*this,x,y,width,height,src,srcx,srcy);
		case 24:
			return ::BltNonGDI (CPixelHandler24(), *this,x,y,width,height,src,srcx,srcy);
		case 32:
			return ::BltNonGDI (CPixelHandler32(), *this,x,y,width,height,src,srcx,srcy);
		default:
			ASSERT (0);
			return false;
	}
}


// this version does not have the rop argument, assumes SRC_COPY
bool CDIBSurface::MaskBltNonGDI (int x,int y,int width,int height,const CDIBSurface& src,int srcx,int srcy)
{
#ifdef _DEBUG
	static int doit = 0;
	if (doit)
	{	// revert back to traditional blit for tests
		ASSERT (m_DIBData);
		ASSERT (src.m_DIBData);
		ASSERT (src.UseMask ());
		if(!src.UseMask ())
			return false;

		HDC dc = GetDC ();
		SetBkColor(dc, RGB(255, 255, 255));			 // 1s --> 0xFFFFFF
		SetTextColor(dc, RGB(0, 0, 0));					 // 0s --> 0x000000

	//  BitBlt(m_BackDC, x, y, width, height, src->m_BackDC, srcx, srcy, SRCINVERT);
		HDC dc2,dc3;
		dc2 = src.m_DIBData->m_Mask->GetDC ();
		dc3 = src.GetDC ();
		BitBlt(dc, x, y, width, height, dc2, srcx, srcy, SRCAND);
		BitBlt(dc, x, y, width, height, dc3, srcx, srcy, SRCPAINT);
		src.m_DIBData->m_Mask->ReleaseDC (dc2);
		src.ReleaseDC (dc3);
		ReleaseDC (dc);
		return true;
	}
#endif

	ASSERT (GetBitDepth() == src.GetBitDepth());
	switch (GetBitDepth())
	{
		case 1:
			return ::MaskBltNonGDI (CPixelHandler1(), *this,x,y,width,height,src,srcx,srcy);
		case 8:
			return ::MaskBltNonGDI (CPixelHandler8(), *this,x,y,width,height,src,srcx,srcy);
		case 16:
			return ::MaskBltNonGDI (CPixelHandler16(), *this,x,y,width,height,src,srcx,srcy);
		case 24:
			return ::MaskBltNonGDI (CPixelHandler24(), *this,x,y,width,height,src,srcx,srcy);
		case 32:
			return ::MaskBltNonGDI (CPixelHandler32(), *this,x,y,width,height,src,srcx,srcy);
		default:
			ASSERT (0);
			return false;
	}
}
#else
bool CDIBSurface::BltNonGDI (int x,int y,int width,int height,const CDIBSurface& src,int srcx,int srcy)
{
	HDC dc1,dc2;
	bool toret;

	dc1 = GetDC ();
	dc2 = src.GetDC ();
	if (!(dc1 && dc2))
	{
		if (dc1)
			ReleaseDC (dc1);
		if (dc2)
			src.ReleaseDC (dc2);
		return false;
	}
  toret = (::BitBlt (dc1,x,y,width,height,dc2,srcx,srcy,SRCCOPY) == TRUE);
	ReleaseDC (dc1);
	src.ReleaseDC (dc2);
	return toret;
}
bool CDIBSurface::MaskBltNonGDI (int x,int y,int width,int height,const CDIBSurface& src,int srcx,int srcy)
{
	ASSERT (m_DIBData);
	ASSERT (src.m_DIBData);
	ASSERT (src.UseMask ());
	if(!src.UseMask ())
		return false;

	HDC dc = GetDC ();
	SetBkColor(dc, RGB(255, 255, 255));			 // 1s --> 0xFFFFFF
	SetTextColor(dc, RGB(0, 0, 0));					 // 0s --> 0x000000

//  BitBlt(m_BackDC, x, y, width, height, src->m_BackDC, srcx, srcy, SRCINVERT);
	HDC dc2,dc3;
	dc2 = src.m_DIBData->m_Mask->GetDC ();
	dc3 = src.GetDC ();
	BitBlt(dc, x, y, width, height, dc2, srcx, srcy, SRCAND);
	BitBlt(dc, x, y, width, height, dc3, srcx, srcy, SRCPAINT);
	src.m_DIBData->m_Mask->ReleaseDC (dc2);
	src.ReleaseDC (dc3);
	ReleaseDC (dc);
	return true;
}
#endif
