748 lines
18 KiB
C++
748 lines
18 KiB
C++
|
//-----------------------------------------------------------------------------
|
||
|
// File: Cbitmap.cpp
|
||
|
//
|
||
|
// Desc: CBitmap class is an object that wraps around a Windows bitmap.
|
||
|
//
|
||
|
// Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
|
||
|
//-----------------------------------------------------------------------------
|
||
|
|
||
|
#include "common.hpp"
|
||
|
#include "id3dsurf.h"
|
||
|
|
||
|
//@@BEGIN_MSINTERNAL
|
||
|
#ifdef DDKBUILD
|
||
|
//HMODULE g_MSImg32 = NULL;
|
||
|
//ALPHABLEND g_AlphaBlend = NULL;
|
||
|
#endif
|
||
|
//@@END_MSINTERNAL
|
||
|
|
||
|
BOOL DI_AlphaBlend(
|
||
|
HDC hdcDest, // handle to destination DC
|
||
|
int nXOriginDest, // x-coord of upper-left corner
|
||
|
int nYOriginDest, // y-coord of upper-left corner
|
||
|
int nWidthDest, // destination width
|
||
|
int nHeightDest, // destination height
|
||
|
HDC hdcSrc, // handle to source DC
|
||
|
int nXOriginSrc, // x-coord of upper-left corner
|
||
|
int nYOriginSrc, // y-coord of upper-left corner
|
||
|
int nWidthSrc, // source width
|
||
|
int nHeightSrc // source height
|
||
|
)
|
||
|
{
|
||
|
LPBYTE pbDestBits = NULL;
|
||
|
HBITMAP hTempDestDib = NULL;
|
||
|
int nXOriginDestLogical = nXOriginDest, nYOriginDestLogical = nYOriginDest;
|
||
|
|
||
|
// Convert nXOriginDest and nYOriginDest from logical coord to device coord
|
||
|
POINT pt = {nXOriginDest, nYOriginDest};
|
||
|
LPtoDP(hdcDest, &pt, 1);
|
||
|
nXOriginDest = pt.x;
|
||
|
nYOriginDest = pt.y;
|
||
|
// Convert nXOriginSrc and nYOriginSrc from logical coord to device coord
|
||
|
pt.x = nXOriginSrc;
|
||
|
pt.y = nYOriginSrc;
|
||
|
LPtoDP(hdcSrc, &pt, 1);
|
||
|
nXOriginSrc = pt.x;
|
||
|
nYOriginSrc = pt.y;
|
||
|
|
||
|
// Get the bits for both source and destination first
|
||
|
// Every BITMAP used in the UI is created with CreateDIBSection, so we know we can get the bits.
|
||
|
HBITMAP hSrcBmp, hDestBmp;
|
||
|
DIBSECTION SrcDibSec, DestDibSec;
|
||
|
hSrcBmp = (HBITMAP)GetCurrentObject(hdcSrc, OBJ_BITMAP);
|
||
|
GetObject(hSrcBmp, sizeof(DIBSECTION), &SrcDibSec);
|
||
|
hDestBmp = (HBITMAP)GetCurrentObject(hdcDest, OBJ_BITMAP);
|
||
|
GetObject(hDestBmp, sizeof(DIBSECTION), &DestDibSec);
|
||
|
if (!SrcDibSec.dsBm.bmBits) return FALSE; // Not necessary, but to be absolutely safe.
|
||
|
|
||
|
// Calculate the rectangle to perform the operation.
|
||
|
if (nXOriginSrc + nWidthSrc > SrcDibSec.dsBm.bmWidth) nWidthSrc = SrcDibSec.dsBm.bmWidth - nXOriginSrc;
|
||
|
if (nYOriginSrc + nHeightSrc > SrcDibSec.dsBm.bmHeight) nHeightSrc = SrcDibSec.dsBm.bmHeight - nYOriginSrc;
|
||
|
if (nXOriginDest + nWidthDest > DestDibSec.dsBm.bmWidth) nWidthDest = DestDibSec.dsBm.bmWidth - nXOriginDest;
|
||
|
if (nYOriginDest + nHeightDest > DestDibSec.dsBm.bmHeight) nHeightDest = DestDibSec.dsBm.bmHeight - nYOriginDest;
|
||
|
|
||
|
if (nWidthDest > nWidthSrc) nWidthDest = nWidthSrc;
|
||
|
if (nHeightDest > nHeightSrc) nHeightDest = nHeightSrc;
|
||
|
if (nWidthSrc > nWidthDest) nWidthSrc = nWidthDest;
|
||
|
if (nHeightSrc > nHeightDest) nHeightSrc = nHeightDest;
|
||
|
|
||
|
BITMAPINFO bmi;
|
||
|
ZeroMemory(&bmi.bmiHeader, sizeof(BITMAPINFOHEADER));
|
||
|
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||
|
bmi.bmiHeader.biWidth = nWidthDest;
|
||
|
bmi.bmiHeader.biHeight = nHeightDest;
|
||
|
bmi.bmiHeader.biPlanes = 1;
|
||
|
bmi.bmiHeader.biBitCount = 32;
|
||
|
bmi.bmiHeader.biCompression = BI_RGB;
|
||
|
|
||
|
// Bitmap will have the same width as the dest, but only lines covered in the subrect.
|
||
|
hTempDestDib = CreateDIBSection(hdcDest, &bmi, DIB_RGB_COLORS, (LPVOID*)&pbDestBits, NULL, NULL);
|
||
|
if (!hTempDestDib)
|
||
|
return FALSE;
|
||
|
|
||
|
HDC hTempDC = CreateCompatibleDC(hdcDest);
|
||
|
if (!hTempDC)
|
||
|
{
|
||
|
DeleteObject(hTempDestDib);
|
||
|
return FALSE;
|
||
|
}
|
||
|
HBITMAP hOldTempBmp = (HBITMAP)SelectObject(hTempDC, hTempDestDib);
|
||
|
BOOL res = BitBlt(hTempDC, 0, 0, nWidthDest, nHeightDest, hdcDest, nXOriginDestLogical, nYOriginDestLogical, SRCCOPY);
|
||
|
SelectObject(hTempDC, hOldTempBmp);
|
||
|
DeleteDC(hTempDC);
|
||
|
if (!res)
|
||
|
{
|
||
|
DeleteObject(hTempDestDib);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// We have the bits. Now do the blend.
|
||
|
for (int j = 0; j < nHeightSrc; ++j)
|
||
|
{
|
||
|
assert(j >= 0 &&
|
||
|
j < nHeightDest);
|
||
|
LPBYTE pbDestRGB = (LPBYTE)&((DWORD*)pbDestBits)[j * nWidthDest];
|
||
|
|
||
|
assert(nYOriginSrc+SrcDibSec.dsBm.bmHeight-nHeightSrc >= 0 &&
|
||
|
nYOriginSrc+SrcDibSec.dsBm.bmHeight-nHeightSrc < SrcDibSec.dsBm.bmHeight);
|
||
|
LPBYTE pbSrcRGBA = (LPBYTE)&((DWORD*)SrcDibSec.dsBm.bmBits)[(j+nYOriginSrc+SrcDibSec.dsBm.bmHeight-nHeightSrc)
|
||
|
* SrcDibSec.dsBm.bmWidth + nXOriginSrc];
|
||
|
|
||
|
for (int i = 0; i < nWidthSrc; ++i)
|
||
|
{
|
||
|
// Blend
|
||
|
if (pbSrcRGBA[3] == 255)
|
||
|
{
|
||
|
// Alpha is 255. straight copy.
|
||
|
*(LPDWORD)pbDestRGB = *(LPDWORD)pbSrcRGBA;
|
||
|
} else
|
||
|
if (pbSrcRGBA[3])
|
||
|
{
|
||
|
// Alpha is non-zero
|
||
|
pbDestRGB[0] = pbSrcRGBA[0] + (((255-pbSrcRGBA[3]) * pbDestRGB[0]) >> 8);
|
||
|
pbDestRGB[1] = pbSrcRGBA[1] + (((255-pbSrcRGBA[3]) * pbDestRGB[1]) >> 8);
|
||
|
pbDestRGB[2] = pbSrcRGBA[2] + (((255-pbSrcRGBA[3]) * pbDestRGB[2]) >> 8);
|
||
|
}
|
||
|
pbDestRGB += sizeof(DWORD);
|
||
|
pbSrcRGBA += sizeof(DWORD);
|
||
|
} // for
|
||
|
} // for
|
||
|
|
||
|
HDC hdcTempDest = CreateCompatibleDC(hdcDest);
|
||
|
if (hdcTempDest)
|
||
|
{
|
||
|
HBITMAP hOldTempBmp = (HBITMAP)SelectObject(hdcTempDest, hTempDestDib); // Select the temp dib for blitting
|
||
|
// Get logical coord for device coord of dest origin
|
||
|
POINT pt = {nXOriginDest, nYOriginDest};
|
||
|
DPtoLP(hdcDest, &pt, 1);
|
||
|
BitBlt(hdcDest, pt.x, pt.y, nWidthDest, nHeightDest,
|
||
|
hdcTempDest, 0, 0, SRCCOPY);
|
||
|
SelectObject(hdcTempDest, hOldTempBmp);
|
||
|
DeleteDC(hdcTempDest);
|
||
|
}
|
||
|
|
||
|
DeleteObject(hTempDestDib);
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
CBitmap::~CBitmap()
|
||
|
{
|
||
|
if (m_hbm != NULL)
|
||
|
DeleteObject(m_hbm);
|
||
|
m_hbm = NULL;
|
||
|
m_bSizeKnown = FALSE;
|
||
|
}
|
||
|
|
||
|
HDC CreateAppropDC(HDC hDC)
|
||
|
{
|
||
|
return CreateCompatibleDC(hDC);
|
||
|
}
|
||
|
|
||
|
HBITMAP CreateAppropBitmap(HDC hDC, int cx, int cy)
|
||
|
{
|
||
|
if (hDC != NULL)
|
||
|
return CreateCompatibleBitmap(hDC, cx, cy);
|
||
|
|
||
|
HWND hWnd = GetDesktopWindow();
|
||
|
HDC hWDC = GetWindowDC(hWnd);
|
||
|
HBITMAP hbm = NULL;
|
||
|
if (hWDC != NULL)
|
||
|
{
|
||
|
hbm = CreateCompatibleBitmap(hWDC, cx, cy);
|
||
|
ReleaseDC(hWnd, hWDC);
|
||
|
}
|
||
|
|
||
|
return hbm;
|
||
|
}
|
||
|
|
||
|
CBitmap *CBitmap::CreateFromResource(HINSTANCE hInst, LPCTSTR tszName)
|
||
|
{
|
||
|
return CreateViaLoadImage(hInst, tszName, IMAGE_BITMAP, 0, 0,
|
||
|
LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
|
||
|
}
|
||
|
|
||
|
CBitmap *CBitmap::CreateFromFile(LPCTSTR tszFileName)
|
||
|
{
|
||
|
return CreateViaD3DX(tszFileName);
|
||
|
}
|
||
|
|
||
|
// Use D3DX API to load our surface with image content.
|
||
|
CBitmap *CBitmap::CreateViaD3DX(LPCTSTR tszFileName, LPDIRECT3DSURFACE8 pUISurf)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
LPDIRECT3D8 pD3D = NULL;
|
||
|
LPDIRECT3DDEVICE8 pD3DDev = NULL;
|
||
|
LPDIRECT3DTEXTURE8 pTex = NULL;
|
||
|
LPDIRECT3DSURFACE8 pSurf = NULL;
|
||
|
HBITMAP hDIB = NULL;
|
||
|
|
||
|
__try
|
||
|
{
|
||
|
//@@BEGIN_MSINTERNAL
|
||
|
pSurf = GetCloneSurface(512, 512); /*
|
||
|
//@@END_MSINTERNAL
|
||
|
|
||
|
// If the UI surface is NULL, create a new device. Otherwise, use existing device.
|
||
|
if (!pUISurf)
|
||
|
{
|
||
|
pD3D = Direct3DCreate8(D3D_SDK_VERSION);
|
||
|
if (!pD3D)
|
||
|
return NULL;
|
||
|
OutputDebugString(_T("D3D created\n"));
|
||
|
D3DDISPLAYMODE Mode;
|
||
|
pD3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &Mode);
|
||
|
D3DPRESENT_PARAMETERS d3dpp;
|
||
|
d3dpp.BackBufferWidth = 1;
|
||
|
d3dpp.BackBufferHeight = 1;
|
||
|
d3dpp.BackBufferFormat = Mode.Format;
|
||
|
d3dpp.BackBufferCount = 1;
|
||
|
d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE;
|
||
|
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
|
||
|
d3dpp.hDeviceWindow = NULL;
|
||
|
d3dpp.Windowed = TRUE;
|
||
|
d3dpp.EnableAutoDepthStencil = FALSE;
|
||
|
d3dpp.FullScreen_RefreshRateInHz = 0;
|
||
|
d3dpp.FullScreen_PresentationInterval = 0;
|
||
|
d3dpp.Flags = 0;
|
||
|
hr = pD3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, GetActiveWindow(), D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pD3DDev);
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
TCHAR tszMsg[MAX_PATH];
|
||
|
|
||
|
_stprintf(tszMsg, _T("CreateDevice returned 0x%X\n"), hr);
|
||
|
OutputDebugString(tszMsg);
|
||
|
return NULL;
|
||
|
}
|
||
|
} else
|
||
|
{
|
||
|
hr = pUISurf->GetDevice(&pD3DDev);
|
||
|
if (FAILED(hr))
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
OutputDebugString(_T("D3D device createed\n"));
|
||
|
hr = pD3DDev->CreateTexture(512, 512, 0, 0, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, &pTex);
|
||
|
if (FAILED(hr))
|
||
|
return NULL;
|
||
|
OutputDebugString(_T("D3D texture createed\n"));
|
||
|
hr = pTex->GetSurfaceLevel(0, &pSurf);
|
||
|
if (FAILED(hr))
|
||
|
return NULL;
|
||
|
OutputDebugString(_T("Surface interface obtained\n"));
|
||
|
|
||
|
//@@BEGIN_MSINTERNAL
|
||
|
*/
|
||
|
//@@END_MSINTERNAL
|
||
|
D3DXIMAGE_INFO d3dii;
|
||
|
if (FAILED(D3DXLoadSurfaceFromFile(pSurf, NULL, NULL, tszFileName, NULL, D3DX_FILTER_NONE, 0, &d3dii)))
|
||
|
return NULL;
|
||
|
|
||
|
// Create a bitmap and copy the texture content onto it.
|
||
|
int iDibWidth = d3dii.Width, iDibHeight = d3dii.Height;
|
||
|
if (iDibWidth > 430) iDibWidth = 430;
|
||
|
if (iDibHeight > 310) iDibHeight = 310;
|
||
|
LPBYTE pDIBBits;
|
||
|
BITMAPINFO bmi;
|
||
|
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
|
||
|
bmi.bmiHeader.biWidth = iDibWidth;
|
||
|
bmi.bmiHeader.biHeight = iDibHeight;
|
||
|
bmi.bmiHeader.biPlanes = 1;
|
||
|
bmi.bmiHeader.biBitCount = 32;
|
||
|
bmi.bmiHeader.biCompression = BI_RGB;
|
||
|
bmi.bmiHeader.biSizeImage = 0;
|
||
|
bmi.bmiHeader.biXPelsPerMeter = 0;
|
||
|
bmi.bmiHeader.biYPelsPerMeter = 0;
|
||
|
bmi.bmiHeader.biClrUsed = 0;
|
||
|
bmi.bmiHeader.biClrImportant = 0;
|
||
|
hDIB = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (LPVOID*)&pDIBBits, NULL, 0);
|
||
|
if (!hDIB)
|
||
|
return NULL;
|
||
|
|
||
|
// Pre-process the pixel data based on alpha for AlphaBlend()
|
||
|
D3DLOCKED_RECT lrc;
|
||
|
pSurf->LockRect(&lrc, NULL, NULL);
|
||
|
BYTE *pbData = (LPBYTE)lrc.pBits;
|
||
|
{
|
||
|
for (DWORD i = 0; i < 512 * 512; ++i)
|
||
|
{
|
||
|
BYTE bAlpha = pbData[i * 4 + 3];
|
||
|
pbData[i * 4] = pbData[i * 4] * bAlpha / 255;
|
||
|
pbData[i * 4 + 1] = pbData[i * 4 + 1] * bAlpha / 255;
|
||
|
pbData[i * 4 + 2] = pbData[i * 4 + 2] * bAlpha / 255;
|
||
|
}
|
||
|
}
|
||
|
pSurf->UnlockRect();
|
||
|
|
||
|
// Lock the surface
|
||
|
D3DLOCKED_RECT D3DRect;
|
||
|
hr = pSurf->LockRect(&D3DRect, NULL, 0);
|
||
|
if (FAILED(hr))
|
||
|
return NULL;
|
||
|
|
||
|
// Copy the bits
|
||
|
// Note that the image is reversed in Y direction, so we need to re-reverse it.
|
||
|
for (int y = 0; y < iDibHeight; ++y)
|
||
|
CopyMemory(pDIBBits + ((iDibHeight-1-y) * iDibWidth * 4), (LPBYTE)D3DRect.pBits + (y * D3DRect.Pitch), iDibWidth * 4);
|
||
|
|
||
|
// Unlock
|
||
|
pSurf->UnlockRect();
|
||
|
|
||
|
CBitmap *pbm = new CBitmap;
|
||
|
if (!pbm) return NULL;
|
||
|
pbm->m_hbm = hDIB;
|
||
|
hDIB = NULL;
|
||
|
pbm->FigureSize();
|
||
|
|
||
|
return pbm;
|
||
|
}
|
||
|
__finally
|
||
|
{
|
||
|
if (hDIB) DeleteObject(hDIB);
|
||
|
if (pSurf) pSurf->Release();
|
||
|
if (pTex) pTex->Release();
|
||
|
if (pD3DDev) pD3DDev->Release();
|
||
|
if (pD3D) pD3D->Release();
|
||
|
}
|
||
|
//@@BEGIN_MSINTERNAL
|
||
|
/*
|
||
|
//@@END_MSINTERNAL
|
||
|
return NULL;
|
||
|
//@@BEGIN_MSINTERNAL
|
||
|
*/
|
||
|
//@@END_MSINTERNAL
|
||
|
}
|
||
|
|
||
|
CBitmap *CBitmap::CreateViaLoadImage(HINSTANCE hInst, LPCTSTR tszName, UINT uType, int cx, int cy, UINT fuLoad)
|
||
|
{
|
||
|
if (fuLoad & LR_SHARED)
|
||
|
{
|
||
|
assert(0);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
CBitmap *pbm = new CBitmap;
|
||
|
if (pbm == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
HANDLE handle = ::LoadImage(hInst, tszName, uType, cx, cy, fuLoad);
|
||
|
|
||
|
if (handle == NULL)
|
||
|
{
|
||
|
delete pbm;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
pbm->m_hbm = (HBITMAP)handle;
|
||
|
|
||
|
pbm->FigureSize();
|
||
|
|
||
|
return pbm;
|
||
|
}
|
||
|
|
||
|
BOOL CBitmap::FigureSize()
|
||
|
{
|
||
|
BITMAP bm;
|
||
|
|
||
|
if (0 == GetObject((HGDIOBJ)m_hbm, sizeof(BITMAP), (LPVOID)&bm))
|
||
|
return FALSE;
|
||
|
|
||
|
m_size.cx = abs(bm.bmWidth);
|
||
|
m_size.cy = abs(bm.bmHeight);
|
||
|
|
||
|
return m_bSizeKnown = TRUE;
|
||
|
}
|
||
|
|
||
|
CBitmap *CBitmap::StealToCreate(HBITMAP &refbm)
|
||
|
{
|
||
|
if (refbm == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
CBitmap *pbm = new CBitmap;
|
||
|
if (pbm == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
pbm->m_hbm = refbm;
|
||
|
refbm = NULL;
|
||
|
|
||
|
pbm->FigureSize();
|
||
|
|
||
|
return pbm;
|
||
|
}
|
||
|
|
||
|
BOOL CBitmap::GetSize(SIZE *psize)
|
||
|
{
|
||
|
if (m_hbm == NULL || !m_bSizeKnown || psize == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
*psize = m_size;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
void CBitmap::AssumeSize(SIZE size)
|
||
|
{
|
||
|
m_size = size;
|
||
|
m_bSizeKnown = TRUE; //m_hbm != NULL;
|
||
|
}
|
||
|
|
||
|
CBitmap *CBitmap::CreateResizedTo(SIZE size, HDC hDC, int iStretchMode, BOOL bStretch)
|
||
|
{
|
||
|
CBitmap *pbm = new CBitmap;
|
||
|
HDC hSrcDC = NULL;
|
||
|
HDC hDestDC = NULL;
|
||
|
HBITMAP hBitmap = NULL;
|
||
|
HGDIOBJ hOldSrcBitmap = NULL, hOldDestBitmap = NULL;
|
||
|
BOOL bRet = FALSE;
|
||
|
int oldsm = 0;
|
||
|
POINT brushorg;
|
||
|
|
||
|
if (pbm == NULL || size.cx < 1 || size.cy < 1 || m_hbm == NULL || !m_bSizeKnown)
|
||
|
goto error;
|
||
|
|
||
|
hSrcDC = CreateAppropDC(hDC);
|
||
|
hDestDC = CreateAppropDC(hDC);
|
||
|
if (hSrcDC == NULL || hDestDC == NULL)
|
||
|
goto error;
|
||
|
|
||
|
hBitmap = CreateAppropBitmap(hDC, size.cx, size.cy);
|
||
|
if (hBitmap == NULL)
|
||
|
goto error;
|
||
|
|
||
|
if (bStretch)
|
||
|
{
|
||
|
if (GetStretchBltMode(hDestDC) != iStretchMode)
|
||
|
{
|
||
|
if (iStretchMode == HALFTONE)
|
||
|
GetBrushOrgEx(hDestDC, &brushorg);
|
||
|
oldsm = SetStretchBltMode(hDestDC, iStretchMode);
|
||
|
if (iStretchMode == HALFTONE)
|
||
|
SetBrushOrgEx(hDestDC, brushorg.x, brushorg.y, NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
hOldSrcBitmap = SelectObject(hSrcDC, m_hbm);
|
||
|
hOldDestBitmap = SelectObject(hDestDC, hBitmap);
|
||
|
if (bStretch)
|
||
|
bRet = StretchBlt(hDestDC, 0, 0, size.cx, size.cy, hSrcDC, 0, 0, m_size.cx, m_size.cy, SRCCOPY);
|
||
|
else
|
||
|
bRet = BitBlt(hDestDC, 0, 0, size.cx, size.cy, hSrcDC, 0, 0, SRCCOPY);
|
||
|
SelectObject(hDestDC, hOldDestBitmap);
|
||
|
SelectObject(hSrcDC, hOldSrcBitmap);
|
||
|
|
||
|
if (bStretch)
|
||
|
{
|
||
|
if (oldsm != 0)
|
||
|
{
|
||
|
if (oldsm == HALFTONE)
|
||
|
GetBrushOrgEx(hDestDC, &brushorg);
|
||
|
SetStretchBltMode(hDestDC, oldsm);
|
||
|
if (oldsm == HALFTONE)
|
||
|
SetBrushOrgEx(hDestDC, brushorg.x, brushorg.y, NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!bRet)
|
||
|
goto error;
|
||
|
|
||
|
pbm->m_hbm = hBitmap;
|
||
|
hBitmap = NULL;
|
||
|
pbm->AssumeSize(size);
|
||
|
|
||
|
goto cleanup;
|
||
|
error:
|
||
|
if (pbm != NULL)
|
||
|
delete pbm;
|
||
|
pbm = NULL;
|
||
|
cleanup:
|
||
|
if (hBitmap != NULL)
|
||
|
DeleteObject(hBitmap);
|
||
|
if (hSrcDC != NULL)
|
||
|
DeleteDC(hSrcDC);
|
||
|
if (hDestDC != NULL)
|
||
|
DeleteDC(hDestDC);
|
||
|
|
||
|
return pbm;
|
||
|
}
|
||
|
|
||
|
HDC CBitmap::BeginPaintInto(HDC hCDC)
|
||
|
{
|
||
|
if (m_hDCInto != NULL)
|
||
|
{
|
||
|
assert(0);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
m_hDCInto = CreateAppropDC(hCDC);
|
||
|
if (m_hDCInto == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
m_hOldBitmap = SelectObject(m_hDCInto, m_hbm);
|
||
|
|
||
|
return m_hDCInto;
|
||
|
}
|
||
|
|
||
|
void CBitmap::EndPaintInto(HDC &hDC)
|
||
|
{
|
||
|
if (hDC == NULL || hDC != m_hDCInto)
|
||
|
{
|
||
|
assert(0);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
SelectObject(m_hDCInto, m_hOldBitmap);
|
||
|
DeleteDC(m_hDCInto);
|
||
|
m_hDCInto = NULL;
|
||
|
hDC = NULL;
|
||
|
}
|
||
|
|
||
|
void CBitmap::PopOut()
|
||
|
{
|
||
|
if (m_hDCInto == NULL)
|
||
|
{
|
||
|
assert(0);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
SelectObject(m_hDCInto, m_hOldBitmap);
|
||
|
}
|
||
|
|
||
|
void CBitmap::PopIn()
|
||
|
{
|
||
|
if (m_hDCInto == NULL)
|
||
|
{
|
||
|
assert(0);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
m_hOldBitmap = SelectObject(m_hDCInto, m_hbm);
|
||
|
}
|
||
|
|
||
|
BOOL CBitmap::Draw(HDC hDC, POINT origin, SIZE crop, BOOL bAll)
|
||
|
{
|
||
|
if (hDC == NULL || m_hbm == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
if (bAll && !m_bSizeKnown)
|
||
|
return FALSE;
|
||
|
|
||
|
if (bAll)
|
||
|
crop = m_size;
|
||
|
|
||
|
HDC hDCbm = CreateAppropDC(hDC);
|
||
|
if (hDCbm == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
BOOL bPop = m_hDCInto != NULL;
|
||
|
|
||
|
if (bPop)
|
||
|
PopOut();
|
||
|
|
||
|
HGDIOBJ hOldBitmap = SelectObject(hDCbm, m_hbm);
|
||
|
BOOL bRet = BitBlt(hDC, origin.x, origin.y, crop.cx, crop.cy, hDCbm, 0, 0, SRCCOPY);
|
||
|
SelectObject(hDCbm, hOldBitmap);
|
||
|
DeleteDC(hDCbm);
|
||
|
|
||
|
if (bPop)
|
||
|
PopIn();
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
BOOL CBitmap::Blend(HDC hDC, POINT origin, SIZE crop, BOOL bAll)
|
||
|
{
|
||
|
if (hDC == NULL || m_hbm == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
if (bAll && !m_bSizeKnown)
|
||
|
return FALSE;
|
||
|
|
||
|
if (bAll)
|
||
|
crop = m_size;
|
||
|
|
||
|
HDC hDCbm = CreateAppropDC(hDC);
|
||
|
if (hDCbm == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
BOOL bPop = m_hDCInto != NULL;
|
||
|
|
||
|
if (bPop)
|
||
|
PopOut();
|
||
|
|
||
|
#ifndef AC_SRC_ALPHA
|
||
|
#define AC_SRC_ALPHA AC_SRC_NO_PREMULT_ALPHA
|
||
|
#endif
|
||
|
|
||
|
HGDIOBJ hOldBitmap = SelectObject(hDCbm, m_hbm);
|
||
|
BOOL bRet;
|
||
|
|
||
|
//@@BEGIN_MSINTERNAL
|
||
|
/* if (!g_AlphaBlend) // If AlphaBlend is not available, use BitBlt instead.
|
||
|
{
|
||
|
bRet = BitBlt(hDC, origin.x, origin.y, crop.cx, crop.cy, hDCbm, 0, 0, SRCPAINT);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
BLENDFUNCTION blendfn = {AC_SRC_OVER, 0, 255, AC_SRC_ALPHA};
|
||
|
bRet = g_AlphaBlend(hDC, origin.x, origin.y, crop.cx, crop.cy, hDCbm, 0, 0, m_size.cx, m_size.cy, blendfn);
|
||
|
}*/
|
||
|
//@@END_MSINTERNAL
|
||
|
bRet = DI_AlphaBlend(hDC, origin.x, origin.y, crop.cx, crop.cy, hDCbm, 0, 0, m_size.cx, m_size.cy);
|
||
|
SelectObject(hDCbm, hOldBitmap);
|
||
|
DeleteDC(hDCbm);
|
||
|
|
||
|
if (bPop)
|
||
|
PopIn();
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
CBitmap *CBitmap::Dup()
|
||
|
{
|
||
|
SIZE t;
|
||
|
if (!GetSize(&t))
|
||
|
return NULL;
|
||
|
return CreateResizedTo(t, NULL, COLORONCOLOR, FALSE);
|
||
|
}
|
||
|
|
||
|
CBitmap *CBitmap::Create(SIZE size, HDC hCDC)
|
||
|
{
|
||
|
CBitmap *pbm = new CBitmap;
|
||
|
if (pbm == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
pbm->m_hbm = CreateAppropBitmap(hCDC, size.cx, size.cy);
|
||
|
if (pbm->m_hbm == NULL)
|
||
|
{
|
||
|
delete pbm;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
pbm->AssumeSize(size);
|
||
|
|
||
|
return pbm;
|
||
|
}
|
||
|
|
||
|
CBitmap *CBitmap::Create(SIZE size, COLORREF color, HDC hCDC)
|
||
|
{
|
||
|
CBitmap *pbm = Create(size, hCDC);
|
||
|
if (pbm == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
HDC hDC = pbm->BeginPaintInto();
|
||
|
if (hDC == NULL)
|
||
|
{
|
||
|
delete pbm;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
HGDIOBJ hBrush = (HGDIOBJ)CreateSolidBrush(color), hOldBrush;
|
||
|
|
||
|
if (hBrush)
|
||
|
{
|
||
|
hOldBrush = SelectObject(hDC, hBrush);
|
||
|
Rectangle(hDC, -1, -1, size.cx + 1, size.cy + 1);
|
||
|
SelectObject(hDC, hOldBrush);
|
||
|
DeleteObject(hBrush);
|
||
|
}
|
||
|
|
||
|
pbm->EndPaintInto(hDC);
|
||
|
|
||
|
return pbm;
|
||
|
}
|
||
|
|
||
|
BOOL CBitmap::Get(HDC hDC, POINT point)
|
||
|
{
|
||
|
if (!m_bSizeKnown)
|
||
|
return FALSE;
|
||
|
return Get(hDC, point, m_size);
|
||
|
}
|
||
|
|
||
|
BOOL CBitmap::Get(HDC hDC, POINT point, SIZE size)
|
||
|
{
|
||
|
if (m_hDCInto != NULL || hDC == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
HDC hDCInto = BeginPaintInto(hDC);
|
||
|
if (hDCInto == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
BOOL bRet = BitBlt(hDCInto, 0, 0, size.cx, size.cy, hDC, point.x, point.y, SRCCOPY);
|
||
|
|
||
|
EndPaintInto(hDCInto);
|
||
|
|
||
|
return bRet;
|
||
|
}
|
||
|
|
||
|
CBitmap *CBitmap::CreateHorzGradient(const RECT &rect, COLORREF rgbLeft, COLORREF rgbRight)
|
||
|
{
|
||
|
SIZE size = GetRectSize(rect);
|
||
|
COLORREF rgbMid = RGB(
|
||
|
(int(GetRValue(rgbLeft)) + int(GetRValue(rgbRight))) / 2,
|
||
|
(int(GetGValue(rgbLeft)) + int(GetGValue(rgbRight))) / 2,
|
||
|
(int(GetBValue(rgbLeft)) + int(GetBValue(rgbRight))) / 2);
|
||
|
return Create(size, rgbMid);
|
||
|
}
|
||
|
|
||
|
BOOL CBitmap::MapToDC(HDC hDCTo, HDC hDCMapFrom)
|
||
|
{
|
||
|
if (hDCTo == NULL || !m_bSizeKnown || m_hDCInto != NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
HBITMAP hbm = CreateAppropBitmap(hDCTo, m_size.cx, m_size.cy);
|
||
|
if (hbm == NULL)
|
||
|
return FALSE;
|
||
|
|
||
|
HDC hDCFrom = NULL;
|
||
|
HDC hDCInto = NULL;
|
||
|
HGDIOBJ hOld = NULL;
|
||
|
BOOL bRet = FALSE;
|
||
|
|
||
|
hDCFrom = BeginPaintInto(hDCMapFrom);
|
||
|
if (!hDCFrom)
|
||
|
goto cleanup;
|
||
|
|
||
|
hDCInto = CreateCompatibleDC(hDCTo);
|
||
|
if (!hDCInto)
|
||
|
goto cleanup;
|
||
|
|
||
|
hOld = SelectObject(hDCInto, (HGDIOBJ)hbm);
|
||
|
bRet = BitBlt(hDCInto, 0, 0, m_size.cx, m_size.cy, hDCFrom, 0, 0, SRCCOPY);
|
||
|
SelectObject(hDCInto, hOld);
|
||
|
|
||
|
cleanup:
|
||
|
if (hDCFrom)
|
||
|
EndPaintInto(hDCFrom);
|
||
|
if (hDCInto)
|
||
|
DeleteDC(hDCInto);
|
||
|
if (bRet)
|
||
|
{
|
||
|
if (m_hbm)
|
||
|
DeleteObject((HGDIOBJ)m_hbm);
|
||
|
m_hbm = hbm;
|
||
|
hbm = NULL;
|
||
|
}
|
||
|
if (hbm)
|
||
|
DeleteObject((HGDIOBJ)hbm);
|
||
|
|
||
|
return bRet;
|
||
|
}
|