Complete disaster-recovery snapshot: engine/game source, game data assets, VC6 toolchain + DX SDKs, build outputs, deployed game, and _UNUSED archive. Large binaries in Git LFS; text preserved byte-for-byte (core.autocrlf=false, no eol attributes). See RECOVERY.md for the one-clone rebuild procedure.
2038 lines
53 KiB
C++
2038 lines
53 KiB
C++
#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
|