|
|
// 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; }
|