Windows2003-3790/windows/advcore/gdiplus/test/simpsons/ddhelper.cpp
2020-09-30 16:53:55 +02:00

781 lines
22 KiB
C++

// File: ddhelper.cpp
// Author: Michael Marr (mikemarr)
#include "StdAfx.h"
#include "DDHelper.h"
#include "Blt.h"
const PALETTEENTRY g_peZero = {0, 0, 0, 0};
const GUID g_guidNULL = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
const DDPIXELFORMAT g_rgDDPF[iPF_Total] = {
{sizeof(DDPIXELFORMAT), 0, 0, 0, 0x00, 0x00, 0x00, 0x00},
{sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_PALETTEINDEXED1, 0, 1, 0x00, 0x00, 0x00, 0x00},
{sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_PALETTEINDEXED2, 0, 2, 0x00, 0x00, 0x00, 0x00},
{sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_PALETTEINDEXED4, 0, 4, 0x00, 0x00, 0x00, 0x00},
{sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_PALETTEINDEXED8, 0, 8, 0x00, 0x00, 0x00, 0x00},
{sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 8, 0xE0, 0x1C, 0x03, 0x00},
{sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0, 16, 0xF00, 0xF0, 0xF, 0xF000},
{sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0xF800, 0x07E0, 0x001F, 0x00},
{sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0x001F, 0x07E0, 0xF800, 0x00},
{sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00, 0x03E0, 0x001F, 0x00},
{sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0, 16, 0x7C00, 0x03E0, 0x001F, 0x8000},
{sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 24, 0xFF0000, 0xFF00, 0xFF, 0x00},
{sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 24, 0xFF, 0xFF00, 0xFF0000, 0x00},
{sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000, 0xFF00, 0xFF, 0x00},
{sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 32, 0xFF, 0xFF00, 0xFF0000, 0x00},
{sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0, 32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000},
{sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0, 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000},
{sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 24, 0xFF0000, 0xFF00, 0xFF, 0x00},
{sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000, 0xFF00, 0xFF, 0x00},
{sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 32, 0xFF, 0xFF00, 0xFF0000, 0x00}
};
/*
const GUID *g_rgpDDPFGUID[iPF_Total] = {
&g_guidNULL,
&DDPF_RGB1, &DDPF_RGB2, &DDPF_RGB4, &DDPF_RGB8,
&DDPF_RGB332, &DDPF_ARGB4444, &DDPF_RGB565, &DDPF_BGR565, &DDPF_RGB555,
&DDPF_ARGB1555, &DDPF_RGB24, &DDPF_BGR24, &DDPF_RGB32, &DDPF_BGR32,
&DDPF_ARGB32, &DDPF_ABGR32, &DDPF_RGB24, &DDPF_RGB32, &DDPF_BGR32
};
DWORD
GetPixelFormat(const GUID *pGUID)
{
for (DWORD i = 0; i < iPF_RGBTRIPLE; i++) {
if ((pGUID == g_rgpDDPFGUID[i]) ||
IsEqualGUID(*pGUID, *g_rgpDDPFGUID[i]))
return i;
}
return iPF_NULL;
}
*/
const CPixelInfo g_rgPIXI[iPF_Total] = {
CPixelInfo(0), CPixelInfo(1), CPixelInfo(2), CPixelInfo(4), CPixelInfo(8),
CPixelInfo(8, 0xE0, 0x1C, 0x03, 0x00),
CPixelInfo(16, 0xF00, 0xF0, 0xF, 0xF000),
CPixelInfo(16, 0xF800, 0x07E0, 0x001F, 0x00),
CPixelInfo(16, 0x001F, 0x07E0, 0xF800, 0x00),
CPixelInfo(16, 0x7C00, 0x03E0, 0x001F, 0x00),
CPixelInfo(16, 0x7C00, 0x03E0, 0x001F, 0x8000),
CPixelInfo(24, 0xFF0000, 0xFF00, 0xFF, 0x00),
CPixelInfo(24, 0xFF, 0xFF00, 0xFF0000, 0x00),
CPixelInfo(32, 0xFF0000, 0xFF00, 0xFF, 0x00),
CPixelInfo(32, 0xFF, 0xFF00, 0xFF0000, 0x00),
CPixelInfo(32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000),
CPixelInfo(32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000),
CPixelInfo(24, 0xFF0000, 0xFF00, 0xFF, 0x00),
CPixelInfo(32, 0xFF0000, 0xFF00, 0xFF, 0x00),
CPixelInfo(32, 0xFF, 0xFF00, 0xFF0000, 0x00)
};
DWORD
GetPixelFormat(const DDPIXELFORMAT &ddpf)
{
for (DWORD i = 0; i < iPF_RGBTRIPLE; i++) {
if (ddpf == g_rgDDPF[i])
return i;
}
return iPF_NULL;
}
DWORD
GetPixelFormat(const CPixelInfo &pixi)
{
for (DWORD i = 0; i < iPF_RGBTRIPLE; i++)
if (pixi == g_rgPIXI[i])
return i;
return iPF_NULL;
}
DWORD g_rgdwBPPToPalFlags[9] = {
0, DDPCAPS_1BIT, DDPCAPS_2BIT, 0, DDPCAPS_4BIT,
0, 0, 0, DDPCAPS_8BIT};
DWORD g_rgdwBPPToPixFlags[9] = {
0, DDPF_PALETTEINDEXED1, DDPF_PALETTEINDEXED2, 0,
DDPF_PALETTEINDEXED4, 0, 0, 0, DDPF_PALETTEINDEXED8};
DWORD
PaletteToPixelFlags(DWORD dwFlags)
{
if (dwFlags & DDPCAPS_8BIT) return DDPF_PALETTEINDEXED8;
if (dwFlags & DDPCAPS_4BIT) return DDPF_PALETTEINDEXED4;
if (dwFlags & DDPCAPS_2BIT) return DDPF_PALETTEINDEXED2;
if (dwFlags & DDPCAPS_1BIT) return DDPF_PALETTEINDEXED1;
return 0;
}
DWORD
PixelToPaletteFlags(DWORD dwFlags)
{
if (dwFlags & DDPF_PALETTEINDEXED8) return DDPCAPS_8BIT;
if (dwFlags & DDPF_PALETTEINDEXED4) return DDPCAPS_4BIT;
if (dwFlags & DDPF_PALETTEINDEXED2) return DDPCAPS_2BIT;
if (dwFlags & DDPF_PALETTEINDEXED1) return DDPCAPS_1BIT;
return 0;
}
BYTE
PixelFlagsToBPP(DWORD dwFlags)
{
if (dwFlags & DDPF_PALETTEINDEXED8) return (BYTE) 8;
if (dwFlags & DDPF_PALETTEINDEXED4) return (BYTE) 4;
if (dwFlags & DDPF_PALETTEINDEXED2) return (BYTE) 2;
if (dwFlags & DDPF_PALETTEINDEXED1) return (BYTE) 1;
return (BYTE) 0;
}
BYTE
PaletteFlagsToBPP(DWORD dwFlags)
{
if (dwFlags & DDPCAPS_8BIT) return (BYTE) 8;
if (dwFlags & DDPCAPS_4BIT) return (BYTE) 4;
if (dwFlags & DDPCAPS_2BIT) return (BYTE) 2;
if (dwFlags & DDPCAPS_1BIT) return (BYTE) 1;
return (BYTE) 0;
}
HRESULT
CreatePlainSurface(IDirectDraw *pDD, DWORD nWidth, DWORD nHeight,
const DDPIXELFORMAT &ddpf, IDirectDrawPalette *pddp,
DWORD dwTransColor, bool bTransparent,
IDirectDrawSurface **ppdds)
{
if (!pDD || !ppdds)
return E_INVALIDARG;
HRESULT hr;
DDSURFACEDESC ddsd;
INIT_DXSTRUCT(ddsd);
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
ddsd.dwWidth = nWidth;
ddsd.dwHeight = nHeight;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
ddsd.ddpfPixelFormat = ddpf;
LPDIRECTDRAWSURFACE pdds;
if (FAILED(hr = pDD->CreateSurface(&ddsd, &pdds, NULL)))
return hr;
// attach palette if it exists
if (pddp && FAILED(hr = pdds->SetPalette(pddp))) {
pdds->Release();
return hr;
}
// set the source color key
if (bTransparent) {
DDCOLORKEY ddck = {dwTransColor, dwTransColor};
if (FAILED(hr = pdds->SetColorKey(DDCKEY_SRCBLT, &ddck))) {
pdds->Release();
return hr;
}
}
*ppdds = pdds;
return hr;
}
HRESULT
CreatePalette(IDirectDraw *pDD, const BYTE *pPalette, DWORD cEntries,
BYTE nBPPTarget, const CPixelInfo &pixiPalFmt,
IDirectDrawPalette **ppddp)
{
if (!ppddp)
return E_POINTER;
if (!pDD || !pPalette || (cEntries > 256) || (nBPPTarget == 0) || (nBPPTarget > 8))
return E_INVALIDARG;
HRESULT hr;
PALETTEENTRY rgpe[256];
if ((pixiPalFmt != g_rgPIXI[iPF_PALETTEENTRY]) || (cEntries < (DWORD(1) << nBPPTarget))) {
// copy info to palette
if (FAILED(hr = BltFastRGBToRGB(pPalette, 0, (LPBYTE) rgpe, 0, cEntries,
1, pixiPalFmt, g_rgPIXI[iPF_PALETTEENTRY])))
return hr;
// zero out extra palette entries
ZeroDWORDAligned((LPDWORD) rgpe + cEntries, 256 - cEntries);
pPalette = (const BYTE *) rgpe;
}
DWORD dwPalFlags = BPPToPaletteFlags(nBPPTarget) | DDPCAPS_ALLOW256;
return pDD->CreatePalette(dwPalFlags, (LPPALETTEENTRY) pPalette, ppddp, NULL);
}
HRESULT
ClearToColor(LPRECT prDst, LPDIRECTDRAWSURFACE pdds, DWORD dwColor)
{
HRESULT hr;
MMASSERT(pdds);
DDBLTFX ddbfx;
INIT_DXSTRUCT(ddbfx);
ddbfx.dwFillColor = dwColor;
RECT rDst;
if (prDst == NULL) {
::GetSurfaceDimensions(pdds, &rDst);
prDst = &rDst;
}
hr = pdds->Blt(prDst, NULL, NULL, DDBLT_COLORFILL | DDBLT_ASYNC, &ddbfx);
if (hr == E_NOTIMPL) {
// fill by hand
DDSURFACEDESC(ddsd);
INIT_DXSTRUCT(ddsd);
CHECK_HR(hr = pdds->Lock(&rDst, &ddsd, DDLOCK_WAIT, NULL));
CHECK_HR(hr = DrawFilledBox(ddsd, rDst, dwColor));
e_Exit:
pdds->Unlock(ddsd.lpSurface);
return hr;
} else {
return hr;
}
}
// blue is assumed to have a weight of 1.f
#define fSimpleRedWeight 2.1f
#define fSimpleGreenWeight 2.4f
#define fMaxColorDistance ((1.f + fSimpleRedWeight + fSimpleGreenWeight) * float(257 * 256))
static inline float
_ColorDistance(const PALETTEENTRY &pe1, const PALETTEENTRY &pe2)
{
float fTotal, fTmpR, fTmpG, fTmpB;
fTmpR = (float) (pe1.peRed - pe2.peRed);
fTotal = fSimpleRedWeight * fTmpR * fTmpR;
fTmpG = (float) (pe1.peGreen - pe2.peRed);
fTotal += fSimpleGreenWeight * fTmpG * fTmpG;
fTmpB = (float) (pe1.peBlue - pe2.peRed);
// blue is assumed to have a weight of 1.f
fTotal += fTmpB * fTmpB;
return fTotal;
}
DWORD
SimpleFindClosestIndex(const PALETTEENTRY *rgpePalette, DWORD cEntries,
const PALETTEENTRY &peQuery)
{
MMASSERT(rgpePalette);
float fTmp, fMinDistance = fMaxColorDistance;
DWORD nMinIndex = cEntries;
for (DWORD i = 0; i < cEntries; i++) {
const PALETTEENTRY &peTmp = rgpePalette[i];
if (!(peTmp.peFlags & (PC_RESERVED | PC_EXPLICIT))) {
if ((fTmp = _ColorDistance(peTmp, peQuery)) < fMinDistance) {
// check for exact match
if (fTmp == 0.f)
return i;
nMinIndex = i;
fMinDistance = fTmp;
}
}
}
MMASSERT(nMinIndex < cEntries);
return nMinIndex;
}
// Function: GetColors
// Compute packed/indexed color values for the given surface that most closely
// matches the given color values. Alpha can be expressed by using the peFlags
// field.
HRESULT
GetColors(LPDIRECTDRAWSURFACE pdds, const PALETTEENTRY *rgpeQuery,
DWORD cEntries, LPDWORD pdwColors)
{
HRESULT hr;
if (!pdwColors)
return E_POINTER;
if (!pdds || !rgpeQuery || (cEntries == 0))
return E_INVALIDARG;
DDSURFACEDESC ddsd;
ddsd.dwSize = sizeof(DDSURFACEDESC);
if (FAILED(hr = pdds->GetSurfaceDesc(&ddsd)))
return hr;
CPixelInfo pixi(ddsd.ddpfPixelFormat);
if (pixi.IsRGB()) {
for (DWORD i = 0; i < cEntries; i++)
pdwColors[i] = pixi.Pack(rgpeQuery[i]);
} else {
LPDIRECTDRAWPALETTE pddp = NULL;
PALETTEENTRY rgpe[256];
if (FAILED(hr = pdds->GetPalette(&pddp)) ||
FAILED(hr = pddp->GetEntries(0, 0, 256, rgpe)))
return hr;
for (DWORD i = 0; i < cEntries; i++) {
// what if the palette is not 8 bit?
pdwColors[i] = SimpleFindClosestIndex(rgpe, 256, rgpeQuery[i]);
}
}
return S_OK;
}
HRESULT
GetSurfaceDimensions(LPDIRECTDRAWSURFACE pdds, LPRECT prDim)
{
MMASSERT(pdds && prDim);
HRESULT hr;
DDSURFACEDESC ddsd;
ddsd.dwSize = sizeof(DDSURFACEDESC);
if (FAILED(hr = pdds->GetSurfaceDesc(&ddsd))) {
return hr;
}
prDim->left = prDim->top = 0;
prDim->right = (long) ddsd.dwWidth;
prDim->bottom = (long) ddsd.dwHeight;
return S_OK;
}
HRESULT
CopyPixels8ToDDS(const BYTE *pSrcPixels, RECT rSrc, long nSrcPitch,
LPDIRECTDRAWSURFACE pddsDst, DWORD nXPos, DWORD nYPos)
{
if (!pddsDst || !pSrcPixels)
return E_INVALIDARG;
HRESULT hr;
bool bLocked = FALSE;
DDSURFACEDESC ddsd;
INIT_DXSTRUCT(ddsd);
DWORD nSrcWidth = rSrc.right - rSrc.left;
DWORD nSrcHeight = rSrc.bottom - rSrc.top;
LPBYTE pDstPixels = NULL;
RECT rDst = {nXPos, nYPos, nXPos + nSrcWidth, nYPos + nSrcHeight};
// lock the surface for writing
if (FAILED(hr = pddsDst->Lock(&rDst, &ddsd, DDLOCK_WAIT, NULL)))
return hr;
bLocked = TRUE;
// check that the surface is the right size for the copy
if (((ddsd.dwWidth - nXPos) < nSrcWidth) ||
((ddsd.dwHeight - nYPos) < nSrcHeight) ||
(ddsd.ddpfPixelFormat.dwRGBBitCount != 8))
{
hr = E_INVALIDARG;
goto e_CopyPixelsToDDS;
}
//
// copy the pixels
//
pDstPixels = (LPBYTE) ddsd.lpSurface;
// position the source pixel pointer
pSrcPixels += rSrc.top * nSrcPitch + rSrc.left;
hr = BltFast(pSrcPixels, nSrcPitch, pDstPixels, ddsd.lPitch,
nSrcWidth, nSrcHeight);
e_CopyPixelsToDDS:
if (bLocked)
pddsDst->Unlock(ddsd.lpSurface);
return hr;
}
HRESULT
CreateSurfaceWithText(LPDIRECTDRAW pDD, LPDIRECTDRAWPALETTE pddp,
bool bTransparent, DWORD iTrans,
const char *szText, HFONT hFont,
bool bShadowed, SIZE *psiz,
LPDIRECTDRAWSURFACE *ppdds)
{
MMASSERT(ppdds && psiz);
// check arguments
if ((szText == NULL) || (szText[0] == '\0') || (hFont == NULL) || (pDD == NULL) ||
(iTrans >= 256))
return E_INVALIDARG;
HRESULT hr;
HDC hDC = NULL;
HGDIOBJ hOldFont = NULL, hOldDIB = NULL;
LPDIRECTDRAWSURFACE pdds = NULL;
BOOL b = FALSE;
SIZE sizText;
RECT rText;
DDCOLORKEY ddck;
ddck.dwColorSpaceLowValue = ddck.dwColorSpaceHighValue = iTrans;
if (bTransparent == FALSE)
iTrans = 0;
int cTextLength = strlen(szText);
//
// compute the size and create the DDS
//
hr = E_FAIL;
// open the DC
b =(((hDC = GetDC(NULL)) == NULL) ||
// select the font into the DC
((hOldFont = SelectObject(hDC, hFont)) == NULL) ||
// compute the size of the fontified string in pixels
(GetTextExtentPoint32(hDC, szText, cTextLength, &sizText) == 0)) ||
// set the size of the rect
((SetRect(&rText, 0, 0, GetClosestMultipleOf4(sizText.cx, TRUE),
GetClosestMultipleOf4(sizText.cy, TRUE)) == 0) ||
// create the DDS based on the extent
FAILED(hr = CreatePlainSurface(pDD, rText.right, rText.bottom,
g_rgDDPF[iPF_Palette8], pddp, iTrans, bTransparent, &pdds)) ||
// clear the surface to the transparency color
FAILED(hr = ClearToColor(&rText, pdds, iTrans)));
int nXOffset = (rText.right - sizText.cx) >> 1;
int nYOffset = (rText.bottom - sizText.cy) >> 1;
// update the size
sizText.cx = rText.right;
sizText.cy = rText.bottom;
// clean up the DC
if (hDC) {
if (hOldFont) {
// select the old object back into the DC
SelectObject(hDC, hOldFont);
hOldFont = NULL;
}
ReleaseDC(NULL, hDC);
hDC = NULL;
}
if (b)
return hr;
//
// output the font to the DDS
//
#ifdef __GetDCWorksOnOffscreenSurfaces
// open the DC on the surface
b =(FAILED(hr = pdds->GetDC(&hDC)) ||
// select in the font
((hOldFont = SelectObject(hDC, hFont)) == NULL) ||
// set the color of the text (the background is transparent)
(SetTextColor(hDC, RGB(255,255,255)) == CLR_INVALID) ||
(SetBkMode(hDC, TRANSPARENT) == 0) ||
// output the text to the surface
(ExtTextOut(hDC, 0, 0, 0, &rText, szText, cTextLength, NULL) == 0));
// clean up the DC again
if (hDC) {
pdds->ReleaseDC(hDC);
hDC = NULL;
}
if (b) {
MMRELEASE(pdds);
return (hr == S_OK ? E_FAIL : hr);
}
#else
HBITMAP hDIB = NULL;
LPBYTE pDIBPixels = NULL;
PALETTEENTRY rgpe[256];
HDC hdcMem = NULL;
PALETTEENTRY &peTrans = rgpe[iTrans];
MMASSERT((hOldDIB == NULL) && (hOldFont == NULL));
// get the DC again
hDC = GetDC(NULL);
MMASSERT(hDC != NULL);
// get the palette entries for the DIB section
b =(FAILED(hr = pddp->GetEntries(0, 0, 256, rgpe)) ||
// create an empty DIB section
FAILED(hr = CreatePlainDIBSection(hDC, rText.right, rText.bottom, 8,
rgpe, &hDIB, &pDIBPixels)) ||
// create a memory DC
((hdcMem = CreateCompatibleDC(hDC)) == NULL) ||
// select DIB section and font into DC
((hOldDIB = SelectObject(hdcMem, hDIB)) == NULL) ||
((hOldFont = SelectObject(hdcMem, hFont)) == NULL) ||
(SetBkColor(hdcMem, RGB(peTrans.peRed, peTrans.peGreen, peTrans.peBlue)) == CLR_INVALID) ||
(SetBkMode(hdcMem, OPAQUE) == 0));
UINT fuOptions = ETO_OPAQUE;
if (!b && bShadowed) {
// set the color of the shadow text
b =((SetTextColor(hdcMem, RGB(0,0,0)) == CLR_INVALID) || // black
// output the shadow text
(ExtTextOut(hdcMem, nXOffset + 2, nYOffset + 2, fuOptions, &rText, szText,
cTextLength, NULL) == 0) ||
(SetBkMode(hdcMem, TRANSPARENT) == 0));
fuOptions = 0; // transparent
}
if (!b) {
// set the color of the foreground text
b =((SetTextColor(hdcMem, RGB(255,255,255)) == CLR_INVALID) || // white
// output the foreground text to the surface
(ExtTextOut(hdcMem, nXOffset, nYOffset, fuOptions, &rText, szText,
cTextLength, NULL) == 0));
}
if (hdcMem) {
if (hOldDIB)
SelectObject(hdcMem, hOldDIB);
if (hOldFont)
SelectObject(hdcMem, hOldFont);
ReleaseDC(NULL, hdcMem);
hdcMem = NULL;
}
ReleaseDC(NULL, hDC);
if (!b) {
// copy the DIB pixels into the DDS
hr = CopyPixels8ToDDS(pDIBPixels, rText, rText.right, pdds, 0, 0);
}
// clean up the DIB that we created
if (hDIB) {
DeleteObject(hDIB);
pDIBPixels = NULL;
}
if (b || FAILED(hr))
return (FAILED(hr) ? hr : E_FAIL);
#endif
*psiz = sizText;
*ppdds = pdds;
return S_OK;
}
HRESULT
CreatePlainDIBSection(HDC hDC, DWORD nWidth, DWORD nHeight, DWORD nBPP,
const PALETTEENTRY *rgpePalette, HBITMAP *phbm, LPBYTE *ppPixels)
{
MMASSERT(rgpePalette && ppPixels && phbm);
HRESULT hr = S_OK;
if (nBPP != 8) {
return E_INVALIDARG;
}
DWORD i, cPalEntries = (1 << nBPP);
HBITMAP hbm = NULL;
// allocate bitmap info structure
BITMAPINFO *pbmi = NULL;
pbmi = (BITMAPINFO *) new BYTE[sizeof(BITMAPINFOHEADER) + cPalEntries * sizeof(RGBQUAD)];
if (pbmi == NULL)
return E_OUTOFMEMORY;
// specify bitmip info
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biPlanes = 1;
pbmi->bmiHeader.biSizeImage = 0;
pbmi->bmiHeader.biClrUsed = 0;
pbmi->bmiHeader.biClrImportant = 0;
pbmi->bmiHeader.biBitCount = (WORD) nBPP;
pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biWidth = (LONG) nWidth;
pbmi->bmiHeader.biHeight = -(LONG) nHeight;
// copy palette into bmi
for(i = 0; i < cPalEntries; i++) {
pbmi->bmiColors[i].rgbRed = rgpePalette[i].peRed;
pbmi->bmiColors[i].rgbGreen= rgpePalette[i].peGreen;
pbmi->bmiColors[i].rgbBlue = rgpePalette[i].peBlue;
pbmi->bmiColors[i].rgbReserved = 0;
}
// create bitmap
LPVOID pvBits = NULL;
hbm = ::CreateDIBSection(hDC, pbmi, DIB_RGB_COLORS, &pvBits, NULL, 0);
if (hbm == NULL) {
hr = E_FAIL;
goto e_CreatePlainDIBSection;
}
*phbm = hbm;
*ppPixels = (LPBYTE) pvBits;
e_CreatePlainDIBSection:
MMDELETE(pbmi);
return hr;
}
bool
ClipRect(const RECT &rTarget, RECT &rSrc)
{
MMASSERT((rTarget.left <= rTarget.right) && (rTarget.top <= rTarget.bottom) &&
(rSrc.left <= rSrc.right) && (rSrc.top <= rSrc.bottom));
CLAMPMIN(rSrc.left, rTarget.left);
CLAMPMIN(rSrc.top, rTarget.top);
CLAMPMAX(rSrc.right, rTarget.right);
CLAMPMAX(rSrc.bottom, rTarget.bottom);
// make sure we still have a valid rectangle
CLAMPMIN(rSrc.right, rSrc.left);
CLAMPMIN(rSrc.bottom, rSrc.top);
return ((rSrc.left != rSrc.right) && (rSrc.top != rSrc.bottom));
}
bool
ClipRect(long nWidth, long nHeight, RECT &rSrc)
{
MMASSERT((rSrc.left <= rSrc.right) && (rSrc.top <= rSrc.bottom));
CLAMPMIN(rSrc.left, 0);
CLAMPMIN(rSrc.top, 0);
CLAMPMAX(rSrc.right, nWidth);
CLAMPMAX(rSrc.bottom, nHeight);
// make sure we still have a valid rectangle
CLAMPMIN(rSrc.right, rSrc.left);
CLAMPMIN(rSrc.bottom, rSrc.top);
return ((rSrc.left != rSrc.right) && (rSrc.top != rSrc.bottom));
}
// Function: CreatePaletteFromSystem
// This function creates a DDPalette from the current system palette
HRESULT
CreatePaletteFromSystem(HDC hDC, IDirectDraw *pDD, IDirectDrawPalette **ppddp)
{
HRESULT hr = E_INVALIDARG;
if (ppddp == NULL)
return E_POINTER;
if ((hDC == NULL) || (pDD == NULL))
return E_INVALIDARG;
PALETTEENTRY rgPE[256];
DWORD cEntries = 0, i;
if ((cEntries = ::GetSystemPaletteEntries(hDC, 0, 256, rgPE)) == 0)
return E_INVALIDARG;
// fill palette entries
for (i = 0; i < cEntries; i++)
rgPE[i].peFlags = PC_NOCOLLAPSE;
for (; i < 256; i++) {
rgPE[i].peRed = rgPE[i].peGreen = rgPE[i].peBlue = 0;
rgPE[i].peFlags = PC_NOCOLLAPSE;
}
if (FAILED(hr = pDD->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE, rgPE, ppddp, NULL)))
return hr;
return S_OK;
}
HRESULT
DrawPoints(LPBYTE pPixels, DWORD nWidth, DWORD nHeight, DWORD nPitch,
DWORD nBytesPerPixel, const Point2 *rgpnt, DWORD cPoints,
DWORD dwColor, DWORD nRadius)
{
MMASSERT(pPixels && rgpnt && cPoints && nWidth && nHeight &&
(nPitch >= nWidth) && INRANGE(nBytesPerPixel, 1, 4));
RECT rSafe = {nRadius, nRadius, nWidth - nRadius, nHeight - nRadius};
for (DWORD i = 0; i < cPoints; i++) {
const Point2 &pnt = rgpnt[i];
// REVIEW: HACK! for now
POINT pt;
pt.x = long(pnt.x);
pt.y = long(pnt.y);
if (IsInside(pt.x, pt.y, rSafe)) {
DWORD nX = pt.x - nRadius, nY = pt.y - nRadius;
DWORD nSize = nRadius * 2 + 1;
g_rgColorFillFn[nBytesPerPixel](
pPixels + PixelOffset(nX, nY, nPitch, nBytesPerPixel),
nPitch, nSize, nSize, dwColor);
} else {
// REVIEW: clip the point for now
}
}
return S_OK;
}
HRESULT
DrawBox(LPBYTE pPixels, DWORD nWidth, DWORD nHeight, DWORD nPitch,
DWORD nBytesPerPixel, const RECT &rSrc, DWORD dwColor, DWORD nThickness)
{
MMASSERT(pPixels && nWidth && nHeight && (nPitch >= nWidth) &&
nThickness && INRANGE(nBytesPerPixel, 1, 4));
RECT r = rSrc;
if (ClipRect(long(nWidth), long(nHeight), r)) {
// compute pixel offset
pPixels += PixelOffset(r.left, r.top, nPitch, nBytesPerPixel);
DWORD nBoxWidth = r.right - r.left;
DWORD nBoxHeight = r.bottom - r.top;
// top
g_rgColorFillFn[nBytesPerPixel](pPixels, nPitch, nBoxWidth, 1, dwColor);
// left
g_rgColorFillFn[nBytesPerPixel](pPixels, nPitch, 1, nBoxHeight, dwColor);
// right
g_rgColorFillFn[nBytesPerPixel](pPixels + nBoxWidth * nBytesPerPixel, nPitch, 1, nBoxHeight, dwColor);
// bottom
g_rgColorFillFn[nBytesPerPixel](pPixels + nBoxHeight * nPitch, nPitch, nBoxWidth, 1, dwColor);
}
return S_OK;
}
HRESULT
DrawFilledBox(LPBYTE pPixels, DWORD nWidth, DWORD nHeight, DWORD nPitch,
DWORD nBytesPerPixel, const RECT &rSrc, DWORD dwColor)
{
HRESULT hr;
MMASSERT(pPixels && nWidth && nHeight && (nPitch >= nWidth) && INRANGE(nBytesPerPixel, 1, 4));
RECT r = rSrc;
if (ClipRect(long(nWidth), long(nHeight), r)) {
pPixels += PixelOffset(r.left, r.top, nPitch, nBytesPerPixel);
DWORD nBoxWidth = r.right - r.left;
DWORD nBoxHeight = r.bottom - r.top;
hr = g_rgColorFillFn[nBytesPerPixel](pPixels, nPitch, nBoxWidth, nBoxHeight, dwColor);
}
return hr;
}