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