Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

780 lines
22 KiB

  1. // File: ddhelper.cpp
  2. // Author: Michael Marr (mikemarr)
  3. #include "StdAfx.h"
  4. #include "DDHelper.h"
  5. #include "Blt.h"
  6. const PALETTEENTRY g_peZero = {0, 0, 0, 0};
  7. const GUID g_guidNULL = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0};
  8. const DDPIXELFORMAT g_rgDDPF[iPF_Total] = {
  9. {sizeof(DDPIXELFORMAT), 0, 0, 0, 0x00, 0x00, 0x00, 0x00},
  10. {sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_PALETTEINDEXED1, 0, 1, 0x00, 0x00, 0x00, 0x00},
  11. {sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_PALETTEINDEXED2, 0, 2, 0x00, 0x00, 0x00, 0x00},
  12. {sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_PALETTEINDEXED4, 0, 4, 0x00, 0x00, 0x00, 0x00},
  13. {sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_PALETTEINDEXED8, 0, 8, 0x00, 0x00, 0x00, 0x00},
  14. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 8, 0xE0, 0x1C, 0x03, 0x00},
  15. {sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0, 16, 0xF00, 0xF0, 0xF, 0xF000},
  16. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0xF800, 0x07E0, 0x001F, 0x00},
  17. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0x001F, 0x07E0, 0xF800, 0x00},
  18. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 16, 0x7C00, 0x03E0, 0x001F, 0x00},
  19. {sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0, 16, 0x7C00, 0x03E0, 0x001F, 0x8000},
  20. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 24, 0xFF0000, 0xFF00, 0xFF, 0x00},
  21. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 24, 0xFF, 0xFF00, 0xFF0000, 0x00},
  22. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000, 0xFF00, 0xFF, 0x00},
  23. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 32, 0xFF, 0xFF00, 0xFF0000, 0x00},
  24. {sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0, 32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000},
  25. {sizeof(DDPIXELFORMAT), DDPF_RGB | DDPF_ALPHAPIXELS, 0, 32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000},
  26. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 24, 0xFF0000, 0xFF00, 0xFF, 0x00},
  27. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 32, 0xFF0000, 0xFF00, 0xFF, 0x00},
  28. {sizeof(DDPIXELFORMAT), DDPF_RGB, 0, 32, 0xFF, 0xFF00, 0xFF0000, 0x00}
  29. };
  30. /*
  31. const GUID *g_rgpDDPFGUID[iPF_Total] = {
  32. &g_guidNULL,
  33. &DDPF_RGB1, &DDPF_RGB2, &DDPF_RGB4, &DDPF_RGB8,
  34. &DDPF_RGB332, &DDPF_ARGB4444, &DDPF_RGB565, &DDPF_BGR565, &DDPF_RGB555,
  35. &DDPF_ARGB1555, &DDPF_RGB24, &DDPF_BGR24, &DDPF_RGB32, &DDPF_BGR32,
  36. &DDPF_ARGB32, &DDPF_ABGR32, &DDPF_RGB24, &DDPF_RGB32, &DDPF_BGR32
  37. };
  38. DWORD
  39. GetPixelFormat(const GUID *pGUID)
  40. {
  41. for (DWORD i = 0; i < iPF_RGBTRIPLE; i++) {
  42. if ((pGUID == g_rgpDDPFGUID[i]) ||
  43. IsEqualGUID(*pGUID, *g_rgpDDPFGUID[i]))
  44. return i;
  45. }
  46. return iPF_NULL;
  47. }
  48. */
  49. const CPixelInfo g_rgPIXI[iPF_Total] = {
  50. CPixelInfo(0), CPixelInfo(1), CPixelInfo(2), CPixelInfo(4), CPixelInfo(8),
  51. CPixelInfo(8, 0xE0, 0x1C, 0x03, 0x00),
  52. CPixelInfo(16, 0xF00, 0xF0, 0xF, 0xF000),
  53. CPixelInfo(16, 0xF800, 0x07E0, 0x001F, 0x00),
  54. CPixelInfo(16, 0x001F, 0x07E0, 0xF800, 0x00),
  55. CPixelInfo(16, 0x7C00, 0x03E0, 0x001F, 0x00),
  56. CPixelInfo(16, 0x7C00, 0x03E0, 0x001F, 0x8000),
  57. CPixelInfo(24, 0xFF0000, 0xFF00, 0xFF, 0x00),
  58. CPixelInfo(24, 0xFF, 0xFF00, 0xFF0000, 0x00),
  59. CPixelInfo(32, 0xFF0000, 0xFF00, 0xFF, 0x00),
  60. CPixelInfo(32, 0xFF, 0xFF00, 0xFF0000, 0x00),
  61. CPixelInfo(32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000),
  62. CPixelInfo(32, 0xFF, 0xFF00, 0xFF0000, 0xFF000000),
  63. CPixelInfo(24, 0xFF0000, 0xFF00, 0xFF, 0x00),
  64. CPixelInfo(32, 0xFF0000, 0xFF00, 0xFF, 0x00),
  65. CPixelInfo(32, 0xFF, 0xFF00, 0xFF0000, 0x00)
  66. };
  67. DWORD
  68. GetPixelFormat(const DDPIXELFORMAT &ddpf)
  69. {
  70. for (DWORD i = 0; i < iPF_RGBTRIPLE; i++) {
  71. if (ddpf == g_rgDDPF[i])
  72. return i;
  73. }
  74. return iPF_NULL;
  75. }
  76. DWORD
  77. GetPixelFormat(const CPixelInfo &pixi)
  78. {
  79. for (DWORD i = 0; i < iPF_RGBTRIPLE; i++)
  80. if (pixi == g_rgPIXI[i])
  81. return i;
  82. return iPF_NULL;
  83. }
  84. DWORD g_rgdwBPPToPalFlags[9] = {
  85. 0, DDPCAPS_1BIT, DDPCAPS_2BIT, 0, DDPCAPS_4BIT,
  86. 0, 0, 0, DDPCAPS_8BIT};
  87. DWORD g_rgdwBPPToPixFlags[9] = {
  88. 0, DDPF_PALETTEINDEXED1, DDPF_PALETTEINDEXED2, 0,
  89. DDPF_PALETTEINDEXED4, 0, 0, 0, DDPF_PALETTEINDEXED8};
  90. DWORD
  91. PaletteToPixelFlags(DWORD dwFlags)
  92. {
  93. if (dwFlags & DDPCAPS_8BIT) return DDPF_PALETTEINDEXED8;
  94. if (dwFlags & DDPCAPS_4BIT) return DDPF_PALETTEINDEXED4;
  95. if (dwFlags & DDPCAPS_2BIT) return DDPF_PALETTEINDEXED2;
  96. if (dwFlags & DDPCAPS_1BIT) return DDPF_PALETTEINDEXED1;
  97. return 0;
  98. }
  99. DWORD
  100. PixelToPaletteFlags(DWORD dwFlags)
  101. {
  102. if (dwFlags & DDPF_PALETTEINDEXED8) return DDPCAPS_8BIT;
  103. if (dwFlags & DDPF_PALETTEINDEXED4) return DDPCAPS_4BIT;
  104. if (dwFlags & DDPF_PALETTEINDEXED2) return DDPCAPS_2BIT;
  105. if (dwFlags & DDPF_PALETTEINDEXED1) return DDPCAPS_1BIT;
  106. return 0;
  107. }
  108. BYTE
  109. PixelFlagsToBPP(DWORD dwFlags)
  110. {
  111. if (dwFlags & DDPF_PALETTEINDEXED8) return (BYTE) 8;
  112. if (dwFlags & DDPF_PALETTEINDEXED4) return (BYTE) 4;
  113. if (dwFlags & DDPF_PALETTEINDEXED2) return (BYTE) 2;
  114. if (dwFlags & DDPF_PALETTEINDEXED1) return (BYTE) 1;
  115. return (BYTE) 0;
  116. }
  117. BYTE
  118. PaletteFlagsToBPP(DWORD dwFlags)
  119. {
  120. if (dwFlags & DDPCAPS_8BIT) return (BYTE) 8;
  121. if (dwFlags & DDPCAPS_4BIT) return (BYTE) 4;
  122. if (dwFlags & DDPCAPS_2BIT) return (BYTE) 2;
  123. if (dwFlags & DDPCAPS_1BIT) return (BYTE) 1;
  124. return (BYTE) 0;
  125. }
  126. HRESULT
  127. CreatePlainSurface(IDirectDraw *pDD, DWORD nWidth, DWORD nHeight,
  128. const DDPIXELFORMAT &ddpf, IDirectDrawPalette *pddp,
  129. DWORD dwTransColor, bool bTransparent,
  130. IDirectDrawSurface **ppdds)
  131. {
  132. if (!pDD || !ppdds)
  133. return E_INVALIDARG;
  134. HRESULT hr;
  135. DDSURFACEDESC ddsd;
  136. INIT_DXSTRUCT(ddsd);
  137. ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS | DDSD_PIXELFORMAT;
  138. ddsd.dwWidth = nWidth;
  139. ddsd.dwHeight = nHeight;
  140. ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
  141. ddsd.ddpfPixelFormat = ddpf;
  142. LPDIRECTDRAWSURFACE pdds;
  143. if (FAILED(hr = pDD->CreateSurface(&ddsd, &pdds, NULL)))
  144. return hr;
  145. // attach palette if it exists
  146. if (pddp && FAILED(hr = pdds->SetPalette(pddp))) {
  147. pdds->Release();
  148. return hr;
  149. }
  150. // set the source color key
  151. if (bTransparent) {
  152. DDCOLORKEY ddck = {dwTransColor, dwTransColor};
  153. if (FAILED(hr = pdds->SetColorKey(DDCKEY_SRCBLT, &ddck))) {
  154. pdds->Release();
  155. return hr;
  156. }
  157. }
  158. *ppdds = pdds;
  159. return hr;
  160. }
  161. HRESULT
  162. CreatePalette(IDirectDraw *pDD, const BYTE *pPalette, DWORD cEntries,
  163. BYTE nBPPTarget, const CPixelInfo &pixiPalFmt,
  164. IDirectDrawPalette **ppddp)
  165. {
  166. if (!ppddp)
  167. return E_POINTER;
  168. if (!pDD || !pPalette || (cEntries > 256) || (nBPPTarget == 0) || (nBPPTarget > 8))
  169. return E_INVALIDARG;
  170. HRESULT hr;
  171. PALETTEENTRY rgpe[256];
  172. if ((pixiPalFmt != g_rgPIXI[iPF_PALETTEENTRY]) || (cEntries < (DWORD(1) << nBPPTarget))) {
  173. // copy info to palette
  174. if (FAILED(hr = BltFastRGBToRGB(pPalette, 0, (LPBYTE) rgpe, 0, cEntries,
  175. 1, pixiPalFmt, g_rgPIXI[iPF_PALETTEENTRY])))
  176. return hr;
  177. // zero out extra palette entries
  178. ZeroDWORDAligned((LPDWORD) rgpe + cEntries, 256 - cEntries);
  179. pPalette = (const BYTE *) rgpe;
  180. }
  181. DWORD dwPalFlags = BPPToPaletteFlags(nBPPTarget) | DDPCAPS_ALLOW256;
  182. return pDD->CreatePalette(dwPalFlags, (LPPALETTEENTRY) pPalette, ppddp, NULL);
  183. }
  184. HRESULT
  185. ClearToColor(LPRECT prDst, LPDIRECTDRAWSURFACE pdds, DWORD dwColor)
  186. {
  187. HRESULT hr;
  188. MMASSERT(pdds);
  189. DDBLTFX ddbfx;
  190. INIT_DXSTRUCT(ddbfx);
  191. ddbfx.dwFillColor = dwColor;
  192. RECT rDst;
  193. if (prDst == NULL) {
  194. ::GetSurfaceDimensions(pdds, &rDst);
  195. prDst = &rDst;
  196. }
  197. hr = pdds->Blt(prDst, NULL, NULL, DDBLT_COLORFILL | DDBLT_ASYNC, &ddbfx);
  198. if (hr == E_NOTIMPL) {
  199. // fill by hand
  200. DDSURFACEDESC(ddsd);
  201. INIT_DXSTRUCT(ddsd);
  202. CHECK_HR(hr = pdds->Lock(&rDst, &ddsd, DDLOCK_WAIT, NULL));
  203. CHECK_HR(hr = DrawFilledBox(ddsd, rDst, dwColor));
  204. e_Exit:
  205. pdds->Unlock(ddsd.lpSurface);
  206. return hr;
  207. } else {
  208. return hr;
  209. }
  210. }
  211. // blue is assumed to have a weight of 1.f
  212. #define fSimpleRedWeight 2.1f
  213. #define fSimpleGreenWeight 2.4f
  214. #define fMaxColorDistance ((1.f + fSimpleRedWeight + fSimpleGreenWeight) * float(257 * 256))
  215. static inline float
  216. _ColorDistance(const PALETTEENTRY &pe1, const PALETTEENTRY &pe2)
  217. {
  218. float fTotal, fTmpR, fTmpG, fTmpB;
  219. fTmpR = (float) (pe1.peRed - pe2.peRed);
  220. fTotal = fSimpleRedWeight * fTmpR * fTmpR;
  221. fTmpG = (float) (pe1.peGreen - pe2.peRed);
  222. fTotal += fSimpleGreenWeight * fTmpG * fTmpG;
  223. fTmpB = (float) (pe1.peBlue - pe2.peRed);
  224. // blue is assumed to have a weight of 1.f
  225. fTotal += fTmpB * fTmpB;
  226. return fTotal;
  227. }
  228. DWORD
  229. SimpleFindClosestIndex(const PALETTEENTRY *rgpePalette, DWORD cEntries,
  230. const PALETTEENTRY &peQuery)
  231. {
  232. MMASSERT(rgpePalette);
  233. float fTmp, fMinDistance = fMaxColorDistance;
  234. DWORD nMinIndex = cEntries;
  235. for (DWORD i = 0; i < cEntries; i++) {
  236. const PALETTEENTRY &peTmp = rgpePalette[i];
  237. if (!(peTmp.peFlags & (PC_RESERVED | PC_EXPLICIT))) {
  238. if ((fTmp = _ColorDistance(peTmp, peQuery)) < fMinDistance) {
  239. // check for exact match
  240. if (fTmp == 0.f)
  241. return i;
  242. nMinIndex = i;
  243. fMinDistance = fTmp;
  244. }
  245. }
  246. }
  247. MMASSERT(nMinIndex < cEntries);
  248. return nMinIndex;
  249. }
  250. // Function: GetColors
  251. // Compute packed/indexed color values for the given surface that most closely
  252. // matches the given color values. Alpha can be expressed by using the peFlags
  253. // field.
  254. HRESULT
  255. GetColors(LPDIRECTDRAWSURFACE pdds, const PALETTEENTRY *rgpeQuery,
  256. DWORD cEntries, LPDWORD pdwColors)
  257. {
  258. HRESULT hr;
  259. if (!pdwColors)
  260. return E_POINTER;
  261. if (!pdds || !rgpeQuery || (cEntries == 0))
  262. return E_INVALIDARG;
  263. DDSURFACEDESC ddsd;
  264. ddsd.dwSize = sizeof(DDSURFACEDESC);
  265. if (FAILED(hr = pdds->GetSurfaceDesc(&ddsd)))
  266. return hr;
  267. CPixelInfo pixi(ddsd.ddpfPixelFormat);
  268. if (pixi.IsRGB()) {
  269. for (DWORD i = 0; i < cEntries; i++)
  270. pdwColors[i] = pixi.Pack(rgpeQuery[i]);
  271. } else {
  272. LPDIRECTDRAWPALETTE pddp = NULL;
  273. PALETTEENTRY rgpe[256];
  274. if (FAILED(hr = pdds->GetPalette(&pddp)) ||
  275. FAILED(hr = pddp->GetEntries(0, 0, 256, rgpe)))
  276. return hr;
  277. for (DWORD i = 0; i < cEntries; i++) {
  278. // what if the palette is not 8 bit?
  279. pdwColors[i] = SimpleFindClosestIndex(rgpe, 256, rgpeQuery[i]);
  280. }
  281. }
  282. return S_OK;
  283. }
  284. HRESULT
  285. GetSurfaceDimensions(LPDIRECTDRAWSURFACE pdds, LPRECT prDim)
  286. {
  287. MMASSERT(pdds && prDim);
  288. HRESULT hr;
  289. DDSURFACEDESC ddsd;
  290. ddsd.dwSize = sizeof(DDSURFACEDESC);
  291. if (FAILED(hr = pdds->GetSurfaceDesc(&ddsd))) {
  292. return hr;
  293. }
  294. prDim->left = prDim->top = 0;
  295. prDim->right = (long) ddsd.dwWidth;
  296. prDim->bottom = (long) ddsd.dwHeight;
  297. return S_OK;
  298. }
  299. HRESULT
  300. CopyPixels8ToDDS(const BYTE *pSrcPixels, RECT rSrc, long nSrcPitch,
  301. LPDIRECTDRAWSURFACE pddsDst, DWORD nXPos, DWORD nYPos)
  302. {
  303. if (!pddsDst || !pSrcPixels)
  304. return E_INVALIDARG;
  305. HRESULT hr;
  306. bool bLocked = FALSE;
  307. DDSURFACEDESC ddsd;
  308. INIT_DXSTRUCT(ddsd);
  309. DWORD nSrcWidth = rSrc.right - rSrc.left;
  310. DWORD nSrcHeight = rSrc.bottom - rSrc.top;
  311. LPBYTE pDstPixels = NULL;
  312. RECT rDst = {nXPos, nYPos, nXPos + nSrcWidth, nYPos + nSrcHeight};
  313. // lock the surface for writing
  314. if (FAILED(hr = pddsDst->Lock(&rDst, &ddsd, DDLOCK_WAIT, NULL)))
  315. return hr;
  316. bLocked = TRUE;
  317. // check that the surface is the right size for the copy
  318. if (((ddsd.dwWidth - nXPos) < nSrcWidth) ||
  319. ((ddsd.dwHeight - nYPos) < nSrcHeight) ||
  320. (ddsd.ddpfPixelFormat.dwRGBBitCount != 8))
  321. {
  322. hr = E_INVALIDARG;
  323. goto e_CopyPixelsToDDS;
  324. }
  325. //
  326. // copy the pixels
  327. //
  328. pDstPixels = (LPBYTE) ddsd.lpSurface;
  329. // position the source pixel pointer
  330. pSrcPixels += rSrc.top * nSrcPitch + rSrc.left;
  331. hr = BltFast(pSrcPixels, nSrcPitch, pDstPixels, ddsd.lPitch,
  332. nSrcWidth, nSrcHeight);
  333. e_CopyPixelsToDDS:
  334. if (bLocked)
  335. pddsDst->Unlock(ddsd.lpSurface);
  336. return hr;
  337. }
  338. HRESULT
  339. CreateSurfaceWithText(LPDIRECTDRAW pDD, LPDIRECTDRAWPALETTE pddp,
  340. bool bTransparent, DWORD iTrans,
  341. const char *szText, HFONT hFont,
  342. bool bShadowed, SIZE *psiz,
  343. LPDIRECTDRAWSURFACE *ppdds)
  344. {
  345. MMASSERT(ppdds && psiz);
  346. // check arguments
  347. if ((szText == NULL) || (szText[0] == '\0') || (hFont == NULL) || (pDD == NULL) ||
  348. (iTrans >= 256))
  349. return E_INVALIDARG;
  350. HRESULT hr;
  351. HDC hDC = NULL;
  352. HGDIOBJ hOldFont = NULL, hOldDIB = NULL;
  353. LPDIRECTDRAWSURFACE pdds = NULL;
  354. BOOL b = FALSE;
  355. SIZE sizText;
  356. RECT rText;
  357. DDCOLORKEY ddck;
  358. ddck.dwColorSpaceLowValue = ddck.dwColorSpaceHighValue = iTrans;
  359. if (bTransparent == FALSE)
  360. iTrans = 0;
  361. int cTextLength = strlen(szText);
  362. //
  363. // compute the size and create the DDS
  364. //
  365. hr = E_FAIL;
  366. // open the DC
  367. b =(((hDC = GetDC(NULL)) == NULL) ||
  368. // select the font into the DC
  369. ((hOldFont = SelectObject(hDC, hFont)) == NULL) ||
  370. // compute the size of the fontified string in pixels
  371. (GetTextExtentPoint32(hDC, szText, cTextLength, &sizText) == 0)) ||
  372. // set the size of the rect
  373. ((SetRect(&rText, 0, 0, GetClosestMultipleOf4(sizText.cx, TRUE),
  374. GetClosestMultipleOf4(sizText.cy, TRUE)) == 0) ||
  375. // create the DDS based on the extent
  376. FAILED(hr = CreatePlainSurface(pDD, rText.right, rText.bottom,
  377. g_rgDDPF[iPF_Palette8], pddp, iTrans, bTransparent, &pdds)) ||
  378. // clear the surface to the transparency color
  379. FAILED(hr = ClearToColor(&rText, pdds, iTrans)));
  380. int nXOffset = (rText.right - sizText.cx) >> 1;
  381. int nYOffset = (rText.bottom - sizText.cy) >> 1;
  382. // update the size
  383. sizText.cx = rText.right;
  384. sizText.cy = rText.bottom;
  385. // clean up the DC
  386. if (hDC) {
  387. if (hOldFont) {
  388. // select the old object back into the DC
  389. SelectObject(hDC, hOldFont);
  390. hOldFont = NULL;
  391. }
  392. ReleaseDC(NULL, hDC);
  393. hDC = NULL;
  394. }
  395. if (b)
  396. return hr;
  397. //
  398. // output the font to the DDS
  399. //
  400. #ifdef __GetDCWorksOnOffscreenSurfaces
  401. // open the DC on the surface
  402. b =(FAILED(hr = pdds->GetDC(&hDC)) ||
  403. // select in the font
  404. ((hOldFont = SelectObject(hDC, hFont)) == NULL) ||
  405. // set the color of the text (the background is transparent)
  406. (SetTextColor(hDC, RGB(255,255,255)) == CLR_INVALID) ||
  407. (SetBkMode(hDC, TRANSPARENT) == 0) ||
  408. // output the text to the surface
  409. (ExtTextOut(hDC, 0, 0, 0, &rText, szText, cTextLength, NULL) == 0));
  410. // clean up the DC again
  411. if (hDC) {
  412. pdds->ReleaseDC(hDC);
  413. hDC = NULL;
  414. }
  415. if (b) {
  416. MMRELEASE(pdds);
  417. return (hr == S_OK ? E_FAIL : hr);
  418. }
  419. #else
  420. HBITMAP hDIB = NULL;
  421. LPBYTE pDIBPixels = NULL;
  422. PALETTEENTRY rgpe[256];
  423. HDC hdcMem = NULL;
  424. PALETTEENTRY &peTrans = rgpe[iTrans];
  425. MMASSERT((hOldDIB == NULL) && (hOldFont == NULL));
  426. // get the DC again
  427. hDC = GetDC(NULL);
  428. MMASSERT(hDC != NULL);
  429. // get the palette entries for the DIB section
  430. b =(FAILED(hr = pddp->GetEntries(0, 0, 256, rgpe)) ||
  431. // create an empty DIB section
  432. FAILED(hr = CreatePlainDIBSection(hDC, rText.right, rText.bottom, 8,
  433. rgpe, &hDIB, &pDIBPixels)) ||
  434. // create a memory DC
  435. ((hdcMem = CreateCompatibleDC(hDC)) == NULL) ||
  436. // select DIB section and font into DC
  437. ((hOldDIB = SelectObject(hdcMem, hDIB)) == NULL) ||
  438. ((hOldFont = SelectObject(hdcMem, hFont)) == NULL) ||
  439. (SetBkColor(hdcMem, RGB(peTrans.peRed, peTrans.peGreen, peTrans.peBlue)) == CLR_INVALID) ||
  440. (SetBkMode(hdcMem, OPAQUE) == 0));
  441. UINT fuOptions = ETO_OPAQUE;
  442. if (!b && bShadowed) {
  443. // set the color of the shadow text
  444. b =((SetTextColor(hdcMem, RGB(0,0,0)) == CLR_INVALID) || // black
  445. // output the shadow text
  446. (ExtTextOut(hdcMem, nXOffset + 2, nYOffset + 2, fuOptions, &rText, szText,
  447. cTextLength, NULL) == 0) ||
  448. (SetBkMode(hdcMem, TRANSPARENT) == 0));
  449. fuOptions = 0; // transparent
  450. }
  451. if (!b) {
  452. // set the color of the foreground text
  453. b =((SetTextColor(hdcMem, RGB(255,255,255)) == CLR_INVALID) || // white
  454. // output the foreground text to the surface
  455. (ExtTextOut(hdcMem, nXOffset, nYOffset, fuOptions, &rText, szText,
  456. cTextLength, NULL) == 0));
  457. }
  458. if (hdcMem) {
  459. if (hOldDIB)
  460. SelectObject(hdcMem, hOldDIB);
  461. if (hOldFont)
  462. SelectObject(hdcMem, hOldFont);
  463. ReleaseDC(NULL, hdcMem);
  464. hdcMem = NULL;
  465. }
  466. ReleaseDC(NULL, hDC);
  467. if (!b) {
  468. // copy the DIB pixels into the DDS
  469. hr = CopyPixels8ToDDS(pDIBPixels, rText, rText.right, pdds, 0, 0);
  470. }
  471. // clean up the DIB that we created
  472. if (hDIB) {
  473. DeleteObject(hDIB);
  474. pDIBPixels = NULL;
  475. }
  476. if (b || FAILED(hr))
  477. return (FAILED(hr) ? hr : E_FAIL);
  478. #endif
  479. *psiz = sizText;
  480. *ppdds = pdds;
  481. return S_OK;
  482. }
  483. HRESULT
  484. CreatePlainDIBSection(HDC hDC, DWORD nWidth, DWORD nHeight, DWORD nBPP,
  485. const PALETTEENTRY *rgpePalette, HBITMAP *phbm, LPBYTE *ppPixels)
  486. {
  487. MMASSERT(rgpePalette && ppPixels && phbm);
  488. HRESULT hr = S_OK;
  489. if (nBPP != 8) {
  490. return E_INVALIDARG;
  491. }
  492. DWORD i, cPalEntries = (1 << nBPP);
  493. HBITMAP hbm = NULL;
  494. // allocate bitmap info structure
  495. BITMAPINFO *pbmi = NULL;
  496. pbmi = (BITMAPINFO *) new BYTE[sizeof(BITMAPINFOHEADER) + cPalEntries * sizeof(RGBQUAD)];
  497. if (pbmi == NULL)
  498. return E_OUTOFMEMORY;
  499. // specify bitmip info
  500. pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  501. pbmi->bmiHeader.biPlanes = 1;
  502. pbmi->bmiHeader.biSizeImage = 0;
  503. pbmi->bmiHeader.biClrUsed = 0;
  504. pbmi->bmiHeader.biClrImportant = 0;
  505. pbmi->bmiHeader.biBitCount = (WORD) nBPP;
  506. pbmi->bmiHeader.biCompression = BI_RGB;
  507. pbmi->bmiHeader.biWidth = (LONG) nWidth;
  508. pbmi->bmiHeader.biHeight = -(LONG) nHeight;
  509. // copy palette into bmi
  510. for(i = 0; i < cPalEntries; i++) {
  511. pbmi->bmiColors[i].rgbRed = rgpePalette[i].peRed;
  512. pbmi->bmiColors[i].rgbGreen= rgpePalette[i].peGreen;
  513. pbmi->bmiColors[i].rgbBlue = rgpePalette[i].peBlue;
  514. pbmi->bmiColors[i].rgbReserved = 0;
  515. }
  516. // create bitmap
  517. LPVOID pvBits = NULL;
  518. hbm = ::CreateDIBSection(hDC, pbmi, DIB_RGB_COLORS, &pvBits, NULL, 0);
  519. if (hbm == NULL) {
  520. hr = E_FAIL;
  521. goto e_CreatePlainDIBSection;
  522. }
  523. *phbm = hbm;
  524. *ppPixels = (LPBYTE) pvBits;
  525. e_CreatePlainDIBSection:
  526. MMDELETE(pbmi);
  527. return hr;
  528. }
  529. bool
  530. ClipRect(const RECT &rTarget, RECT &rSrc)
  531. {
  532. MMASSERT((rTarget.left <= rTarget.right) && (rTarget.top <= rTarget.bottom) &&
  533. (rSrc.left <= rSrc.right) && (rSrc.top <= rSrc.bottom));
  534. CLAMPMIN(rSrc.left, rTarget.left);
  535. CLAMPMIN(rSrc.top, rTarget.top);
  536. CLAMPMAX(rSrc.right, rTarget.right);
  537. CLAMPMAX(rSrc.bottom, rTarget.bottom);
  538. // make sure we still have a valid rectangle
  539. CLAMPMIN(rSrc.right, rSrc.left);
  540. CLAMPMIN(rSrc.bottom, rSrc.top);
  541. return ((rSrc.left != rSrc.right) && (rSrc.top != rSrc.bottom));
  542. }
  543. bool
  544. ClipRect(long nWidth, long nHeight, RECT &rSrc)
  545. {
  546. MMASSERT((rSrc.left <= rSrc.right) && (rSrc.top <= rSrc.bottom));
  547. CLAMPMIN(rSrc.left, 0);
  548. CLAMPMIN(rSrc.top, 0);
  549. CLAMPMAX(rSrc.right, nWidth);
  550. CLAMPMAX(rSrc.bottom, nHeight);
  551. // make sure we still have a valid rectangle
  552. CLAMPMIN(rSrc.right, rSrc.left);
  553. CLAMPMIN(rSrc.bottom, rSrc.top);
  554. return ((rSrc.left != rSrc.right) && (rSrc.top != rSrc.bottom));
  555. }
  556. // Function: CreatePaletteFromSystem
  557. // This function creates a DDPalette from the current system palette
  558. HRESULT
  559. CreatePaletteFromSystem(HDC hDC, IDirectDraw *pDD, IDirectDrawPalette **ppddp)
  560. {
  561. HRESULT hr = E_INVALIDARG;
  562. if (ppddp == NULL)
  563. return E_POINTER;
  564. if ((hDC == NULL) || (pDD == NULL))
  565. return E_INVALIDARG;
  566. PALETTEENTRY rgPE[256];
  567. DWORD cEntries = 0, i;
  568. if ((cEntries = ::GetSystemPaletteEntries(hDC, 0, 256, rgPE)) == 0)
  569. return E_INVALIDARG;
  570. // fill palette entries
  571. for (i = 0; i < cEntries; i++)
  572. rgPE[i].peFlags = PC_NOCOLLAPSE;
  573. for (; i < 256; i++) {
  574. rgPE[i].peRed = rgPE[i].peGreen = rgPE[i].peBlue = 0;
  575. rgPE[i].peFlags = PC_NOCOLLAPSE;
  576. }
  577. if (FAILED(hr = pDD->CreatePalette(DDPCAPS_8BIT | DDPCAPS_INITIALIZE, rgPE, ppddp, NULL)))
  578. return hr;
  579. return S_OK;
  580. }
  581. HRESULT
  582. DrawPoints(LPBYTE pPixels, DWORD nWidth, DWORD nHeight, DWORD nPitch,
  583. DWORD nBytesPerPixel, const Point2 *rgpnt, DWORD cPoints,
  584. DWORD dwColor, DWORD nRadius)
  585. {
  586. MMASSERT(pPixels && rgpnt && cPoints && nWidth && nHeight &&
  587. (nPitch >= nWidth) && INRANGE(nBytesPerPixel, 1, 4));
  588. RECT rSafe = {nRadius, nRadius, nWidth - nRadius, nHeight - nRadius};
  589. for (DWORD i = 0; i < cPoints; i++) {
  590. const Point2 &pnt = rgpnt[i];
  591. // REVIEW: HACK! for now
  592. POINT pt;
  593. pt.x = long(pnt.x);
  594. pt.y = long(pnt.y);
  595. if (IsInside(pt.x, pt.y, rSafe)) {
  596. DWORD nX = pt.x - nRadius, nY = pt.y - nRadius;
  597. DWORD nSize = nRadius * 2 + 1;
  598. g_rgColorFillFn[nBytesPerPixel](
  599. pPixels + PixelOffset(nX, nY, nPitch, nBytesPerPixel),
  600. nPitch, nSize, nSize, dwColor);
  601. } else {
  602. // REVIEW: clip the point for now
  603. }
  604. }
  605. return S_OK;
  606. }
  607. HRESULT
  608. DrawBox(LPBYTE pPixels, DWORD nWidth, DWORD nHeight, DWORD nPitch,
  609. DWORD nBytesPerPixel, const RECT &rSrc, DWORD dwColor, DWORD nThickness)
  610. {
  611. MMASSERT(pPixels && nWidth && nHeight && (nPitch >= nWidth) &&
  612. nThickness && INRANGE(nBytesPerPixel, 1, 4));
  613. RECT r = rSrc;
  614. if (ClipRect(long(nWidth), long(nHeight), r)) {
  615. // compute pixel offset
  616. pPixels += PixelOffset(r.left, r.top, nPitch, nBytesPerPixel);
  617. DWORD nBoxWidth = r.right - r.left;
  618. DWORD nBoxHeight = r.bottom - r.top;
  619. // top
  620. g_rgColorFillFn[nBytesPerPixel](pPixels, nPitch, nBoxWidth, 1, dwColor);
  621. // left
  622. g_rgColorFillFn[nBytesPerPixel](pPixels, nPitch, 1, nBoxHeight, dwColor);
  623. // right
  624. g_rgColorFillFn[nBytesPerPixel](pPixels + nBoxWidth * nBytesPerPixel, nPitch, 1, nBoxHeight, dwColor);
  625. // bottom
  626. g_rgColorFillFn[nBytesPerPixel](pPixels + nBoxHeight * nPitch, nPitch, nBoxWidth, 1, dwColor);
  627. }
  628. return S_OK;
  629. }
  630. HRESULT
  631. DrawFilledBox(LPBYTE pPixels, DWORD nWidth, DWORD nHeight, DWORD nPitch,
  632. DWORD nBytesPerPixel, const RECT &rSrc, DWORD dwColor)
  633. {
  634. HRESULT hr;
  635. MMASSERT(pPixels && nWidth && nHeight && (nPitch >= nWidth) && INRANGE(nBytesPerPixel, 1, 4));
  636. RECT r = rSrc;
  637. if (ClipRect(long(nWidth), long(nHeight), r)) {
  638. pPixels += PixelOffset(r.left, r.top, nPitch, nBytesPerPixel);
  639. DWORD nBoxWidth = r.right - r.left;
  640. DWORD nBoxHeight = r.bottom - r.top;
  641. hr = g_rgColorFillFn[nBytesPerPixel](pPixels, nPitch, nBoxWidth, nBoxHeight, dwColor);
  642. }
  643. return hr;
  644. }