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.

516 lines
16 KiB

  1. // File: PalMap.cpp
  2. // Author: Michael Marr (mikemarr)
  3. //
  4. // History:
  5. // -@- 09/23/97 (mikemarr) copied to DXCConv from d2d\mmimage
  6. #include "stdafx.h"
  7. #include "PalMap.h"
  8. #include "Blt.h"
  9. #include "ddhelper.h"
  10. char gs_szPMPrefix[] = "palette map error";
  11. CPaletteMap::CPaletteMap()
  12. {
  13. m_rgIndexMap = NULL;
  14. m_nConvertCode = cvcInvalid;
  15. m_cSrcBPP = m_cDstBPP = 0;
  16. m_bIdentity = FALSE;
  17. }
  18. CPaletteMap::~CPaletteMap()
  19. {
  20. MMDELETE(m_rgIndexMap);
  21. }
  22. // Function: CreateMap
  23. // This function creates a new mapping from a src palette to a destination color model.
  24. HRESULT
  25. CPaletteMap::CreateMap(BYTE nBPPSrcPixels, BYTE nBPPSrcPalette, LPPALETTEENTRY rgpeSrc,
  26. const CPixelInfo &pixiDst, LPDIRECTDRAWPALETTE pddpDst)
  27. {
  28. MMTRACE("CPaletteMap::CreateMap\n");
  29. HRESULT hr;
  30. PALETTEENTRY rgpeDst[256];
  31. DWORD dwDstCaps;
  32. // verify arguments
  33. if (rgpeSrc == NULL)
  34. return E_INVALIDARG;
  35. // delete the old index map, if it exists
  36. MMDELETE(m_rgIndexMap);
  37. // store the bit depths for mapping verification
  38. // REVIEW: perhaps the maps should be created with at least 256 entries always
  39. m_cSrcBPP = nBPPSrcPixels;
  40. m_cDstBPP = pixiDst.nBPP;
  41. // figure out what kind of conversion we are doing
  42. if ((m_nConvertCode = static_cast<BYTE>(GetConvertCode(m_cSrcBPP, m_cDstBPP))) == cvcInvalid) {
  43. MMTRACE("%s: can't convert from %d bit to %d bit\n",
  44. gs_szPMPrefix, (int) m_cSrcBPP, (int) m_cDstBPP);
  45. return E_INVALIDARG;
  46. }
  47. if (pddpDst == NULL) {
  48. // destination is RGB
  49. switch (m_cDstBPP) {
  50. case 16: return DoPalTo16BitMap(nBPPSrcPalette, pixiDst, rgpeSrc); break;
  51. case 24: return DoPalTo24BitMap(nBPPSrcPalette, pixiDst, rgpeSrc); break;
  52. case 32: return DoPalTo32BitMap(nBPPSrcPalette, pixiDst, rgpeSrc); break;
  53. default:
  54. return E_INVALIDARG;
  55. break;
  56. }
  57. } else {
  58. // destination is 8 bit palettized
  59. hr = E_INVALIDARG;
  60. if ((m_cDstBPP != 8) ||
  61. // get the caps
  62. FAILED(pddpDst->GetCaps(&dwDstCaps)) ||
  63. // verify we have True Color entries
  64. (dwDstCaps & DDPCAPS_8BITENTRIES) ||
  65. // make sure the number of palette entries from the caps is 8 bits
  66. (!(dwDstCaps & DDPCAPS_8BIT)) ||
  67. // get the palette entries
  68. FAILED(hr = pddpDst->GetEntries(0, 0, 1 << m_cDstBPP, rgpeDst)))
  69. {
  70. MMTRACE("%s: invalid dst palette for map\n", gs_szPMPrefix);
  71. return hr;
  72. }
  73. // create map for palette to palette
  74. return DoPalToPalMap(nBPPSrcPalette, m_cDstBPP, rgpeSrc, rgpeDst);
  75. }
  76. }
  77. HRESULT
  78. CPaletteMap::CreateMap(LPDIRECTDRAWPALETTE pddpSrc, const CPixelInfo &pixiDst,
  79. LPDIRECTDRAWPALETTE pddpDst)
  80. {
  81. // MMTRACE("CPaletteMap::CreateMap\n");
  82. PALETTEENTRY rgpeSrc[256];
  83. BYTE nBPPSrc;
  84. DWORD dwSrcCaps;
  85. // sanitize the src palette and get the srcBPP
  86. HRESULT hr = E_INVALIDARG;
  87. if ((pddpSrc == NULL) ||
  88. // get the caps
  89. FAILED(pddpSrc->GetCaps(&dwSrcCaps)) ||
  90. // verify we have True Color entries
  91. (dwSrcCaps & DDPCAPS_8BITENTRIES) ||
  92. // get the number of palette entries from the caps
  93. ((nBPPSrc = BYTE(PaletteFlagsToBPP(dwSrcCaps))) == 0) ||
  94. // get the palette entries
  95. FAILED(hr = pddpSrc->GetEntries(0, 0, (1 << nBPPSrc), rgpeSrc)))
  96. {
  97. MMTRACE("%s: invalid src palette for map\n", gs_szPMPrefix);
  98. return hr;
  99. }
  100. return CreateMap(nBPPSrc, nBPPSrc, rgpeSrc, pixiDst, pddpDst);
  101. }
  102. /*
  103. HRESULT
  104. CPaletteMap::CreateSortedMap(BYTE nBPP, const RGB *rgrgbSrc, BYTE nBPPUsed, DWORD iTransColor,
  105. DWORD dwFlags, LPPALETTEENTRY rgpeDst)
  106. {
  107. MMTRACE("CPaletteMap::CreateSortedMap\n");
  108. MMASSERT(nBPP <= nBPPUsed);
  109. DWORD i, j, imin;
  110. if ((rgrgbSrc == NULL) || (nBPPUsed > 8))
  111. return E_INVALIDARG;
  112. struct {
  113. DWORD nPos;
  114. int nLuminance;
  115. } rgSortMap[nMAXPALETTEENTRIES], minLuminance;
  116. // allocate the index map
  117. MMDELETE(m_rgIndexMap);
  118. m_rgIndexMap = (BYTE *) new BYTE[1 << nBPPUsed];
  119. if (m_rgIndexMap == NULL)
  120. return E_OUTOFMEMORY;
  121. m_nConvertCode = GetConvertCode(nBPPUsed, nBPPUsed);
  122. MMASSERT(m_nConvertCode == cvc8To8);
  123. m_cSrcBPP = nBPPUsed;
  124. m_cDstBPP = nBPPUsed;
  125. // m_pixiDst.Init(nBPPUsed);
  126. // initialize the sort map (compute luminance values)
  127. DWORD cMapLength = (1 << nBPP), cTotalEntries = (1 << nBPPUsed);
  128. for (i = 0; i < cMapLength; i++) {
  129. const RGB &rgbTmp = rgrgbSrc[i];
  130. rgSortMap[i].nPos = i;
  131. rgSortMap[i].nLuminance = nREDWEIGHT * rgbTmp.r + nGREENWEIGHT * rgbTmp.g +
  132. nBLUEWEIGHT * rgbTmp.b;
  133. }
  134. // if transparency exists, change its luminance to -1 so it will
  135. // become the zeroth index
  136. if (dwFlags & flagTRANSPARENT) {
  137. if (iTransColor > cMapLength)
  138. return E_INVALIDARG;
  139. rgSortMap[iTransColor].nLuminance = -1;
  140. }
  141. // sort the entries by luminance
  142. // REVIEW: use naive insertion sort for now
  143. for (i = 0; i < cMapLength; i++) {
  144. imin = i;
  145. minLuminance = rgSortMap[imin];
  146. for (j = i + 1; j < cMapLength; j++) {
  147. if (minLuminance.nLuminance > rgSortMap[j].nLuminance) {
  148. imin = j;
  149. minLuminance = rgSortMap[imin];
  150. }
  151. }
  152. rgSortMap[imin] = rgSortMap[i];
  153. rgSortMap[i] = minLuminance;
  154. }
  155. // fill in the index map (sorting generates an "inverse" map)
  156. for (i = 0; i < cMapLength; i++) {
  157. m_rgIndexMap[rgSortMap[i].nPos] = (BYTE) i;
  158. }
  159. for (; i < cTotalEntries; i++)
  160. m_rgIndexMap[i] = (BYTE) i;
  161. // sort to a palette entry array based on this mapping
  162. if (rgpeDst) {
  163. for (i = 0; i < cMapLength; i++) {
  164. PALETTEENTRY &pe = rgpeDst[i];
  165. const RGB &rgb = rgrgbSrc[rgSortMap[i].nPos];
  166. pe.peRed = rgb.r; pe.peGreen = rgb.g; pe.peBlue = rgb.b; pe.peFlags = 0;
  167. }
  168. PALETTEENTRY peZero = {0, 0, 0, 0};
  169. for (; i < cTotalEntries; i++)
  170. rgpeDst[i] = peZero;
  171. }
  172. return S_OK;
  173. }
  174. */
  175. HRESULT
  176. CPaletteMap::DoPalTo16BitMap(BYTE cSrcBPP, const CPixelInfo &pixiDst, const PALETTEENTRY *ppeSrc)
  177. {
  178. MMASSERT(ppeSrc);
  179. DWORD cEntries = (1 << cSrcBPP);
  180. MapEntry16 *pIndexMap = new MapEntry16[cEntries];
  181. if (pIndexMap == NULL)
  182. return E_OUTOFMEMORY;
  183. for (DWORD i = 0; i < cEntries; i++) {
  184. pIndexMap[i] = pixiDst.Pack16(ppeSrc[i]);
  185. }
  186. m_rgIndexMap = (BYTE *) pIndexMap;
  187. return S_OK;
  188. }
  189. HRESULT
  190. CPaletteMap::DoPalTo24BitMap(BYTE cSrcBPP, const CPixelInfo &pixiDst, const PALETTEENTRY *ppeSrc)
  191. {
  192. MMASSERT(ppeSrc);
  193. if ((pixiDst.nRedResidual | pixiDst.nGreenResidual | pixiDst.nBlueResidual) != 0)
  194. return DDERR_INVALIDPIXELFORMAT;
  195. DWORD cEntries = (1 << cSrcBPP);
  196. MapEntry24 *pIndexMap = new MapEntry24[cEntries];
  197. if (pIndexMap == NULL)
  198. return E_OUTOFMEMORY;
  199. for (DWORD i = 0; i < cEntries; i++) {
  200. pIndexMap[i] = pixiDst.Pack(ppeSrc[i]);
  201. }
  202. m_rgIndexMap = (BYTE *) pIndexMap;
  203. return S_OK;
  204. }
  205. HRESULT
  206. CPaletteMap::DoPalTo32BitMap(BYTE cSrcBPP, const CPixelInfo &pixiDst, const PALETTEENTRY *ppeSrc)
  207. {
  208. // REVIEW: since PALETTEENTRY does not have an alpha field,
  209. // this should be the same as 24 bit
  210. return DoPalTo24BitMap(cSrcBPP, pixiDst, ppeSrc);
  211. }
  212. // blue is assumed to have a weight of 1.f
  213. #define fSimpleRedWeight 2.1f
  214. #define fSimpleGreenWeight 2.4f
  215. #define fMaxColorDistance ((1.f + fSimpleRedWeight + fSimpleGreenWeight) * float(257 * 256))
  216. static inline float
  217. _ColorDistance(const PALETTEENTRY &pe, BYTE r, BYTE g, BYTE b)
  218. {
  219. float fTotal, fTmpR, fTmpG, fTmpB;
  220. fTmpR = (float) (pe.peRed - r);
  221. fTotal = fSimpleRedWeight * fTmpR * fTmpR;
  222. fTmpG = (float) (pe.peGreen - g);
  223. fTotal += fSimpleGreenWeight * fTmpG * fTmpG;
  224. fTmpB = (float) (pe.peBlue - b);
  225. // blue is assumed to have a weight of 1.f
  226. fTotal += fTmpB * fTmpB;
  227. return fTotal;
  228. }
  229. DWORD
  230. _SimpleFindClosestIndex(const PALETTEENTRY *rgpePalette, DWORD cEntries, BYTE r, BYTE g, BYTE b)
  231. {
  232. MMASSERT(rgpePalette);
  233. MMASSERT(cEntries <= nMAXPALETTEENTRIES);
  234. float fTmp, fMinDistance = fMaxColorDistance;
  235. DWORD nMinIndex = cEntries;
  236. for (DWORD i = 0; i < cEntries; i++) {
  237. const PALETTEENTRY &peTmp = rgpePalette[i];
  238. if (!(peTmp.peFlags & (PC_RESERVED | PC_EXPLICIT))) {
  239. if ((fTmp = _ColorDistance(peTmp, r, g, b)) < fMinDistance) {
  240. // check for exact match
  241. if (fTmp == 0.f)
  242. return i;
  243. nMinIndex = i;
  244. fMinDistance = fTmp;
  245. }
  246. }
  247. }
  248. MMASSERT(nMinIndex < cEntries);
  249. return nMinIndex;
  250. }
  251. // Function: DoPalToPalMap
  252. // Compute a mapping from one palette to another and store in the palette map.
  253. HRESULT
  254. CPaletteMap::DoPalToPalMap(BYTE cSrcBPP, BYTE cDstBPP, const PALETTEENTRY *ppeSrc,
  255. const PALETTEENTRY *ppeDst)
  256. {
  257. MMASSERT(ppeSrc && ppeDst);
  258. DWORD cSrcEntries = (1 << cSrcBPP), cDstEntries = (1 << cDstBPP);
  259. m_rgIndexMap = new BYTE[cSrcEntries];
  260. if (m_rgIndexMap == NULL)
  261. return E_OUTOFMEMORY;
  262. for (DWORD i = 0; i < cSrcEntries; i++) {
  263. const PALETTEENTRY &pe = ppeSrc[i];
  264. m_rgIndexMap[i] = (BYTE) _SimpleFindClosestIndex(ppeDst, cDstEntries,
  265. pe.peRed, pe.peGreen, pe.peBlue);
  266. }
  267. return S_OK;
  268. }
  269. // Function: GetConvertCode
  270. // This function computes the index into the function arrays for
  271. // mapping and color conversion.
  272. int
  273. CPaletteMap::GetConvertCode(DWORD nSrcBPP, DWORD nDstBPP)
  274. {
  275. int nCode;
  276. if ((nDstBPP < 8) || (nSrcBPP > 8) || (nSrcBPP < 4)) {
  277. nCode = cvcInvalid;
  278. } else {
  279. nCode = (((nSrcBPP >> 2) - 1) << 2) | ((nDstBPP >> 3) - 1);
  280. }
  281. return nCode;
  282. }
  283. static DWORD
  284. GetColor8To8(DWORD dwSrcColor, const BYTE *pIndexMap)
  285. {
  286. MMASSERT(dwSrcColor < 256);
  287. return (DWORD) pIndexMap[dwSrcColor];
  288. }
  289. static DWORD
  290. GetColor8To16(DWORD dwSrcColor, const BYTE *pIndexMap)
  291. {
  292. MMASSERT(dwSrcColor < 256);
  293. MapEntry16 *pIndexMap16 = (MapEntry16 *) pIndexMap;
  294. return (DWORD) pIndexMap16[dwSrcColor];
  295. }
  296. static DWORD
  297. GetColor8To24(DWORD dwSrcColor, const BYTE *pIndexMap)
  298. {
  299. MMASSERT(dwSrcColor < 256);
  300. MapEntry24 *pIndexMap24 = (MapEntry24 *) pIndexMap;
  301. return (DWORD) pIndexMap24[dwSrcColor];
  302. }
  303. static DWORD
  304. GetColor8To32(DWORD dwSrcColor, const BYTE *pIndexMap)
  305. {
  306. MMASSERT(dwSrcColor < 256);
  307. MapEntry32 *pIndexMap32 = (MapEntry32 *) pIndexMap;
  308. return (DWORD) pIndexMap32[dwSrcColor];
  309. }
  310. static GetColorFunction gs_rgGetColorFunctions[cvcNumCodes] = {
  311. NULL, NULL, NULL, NULL,
  312. GetColor8To8, GetColor8To16,
  313. GetColor8To24, GetColor8To32
  314. };
  315. DWORD
  316. CPaletteMap::GetIndexMapping(DWORD iSrcColor) const
  317. {
  318. MMASSERT((m_nConvertCode < cvcInvalid) && (gs_rgGetColorFunctions[m_nConvertCode] != NULL));
  319. return gs_rgGetColorFunctions[m_nConvertCode](iSrcColor, m_rgIndexMap);
  320. }
  321. // Notes:
  322. // The convert functions also fix the transparency on the destination objects.
  323. // A better way to do this stuff might be to have Blt functions and then separate
  324. // convert functions that cleanup the rest of the image after the Blt.
  325. ConvertFunction g_rgConvertFunctions[cvcNumCodes] = {
  326. NULL, NULL, NULL, NULL,
  327. BltFast8To8T, BltFast8To16T,
  328. BltFast8To24T, BltFast8To32T
  329. };
  330. // Function: BltFast
  331. // This function takes a src dds and writes a dst dds using the
  332. // mapping defined by the PaletteMap. The src and dst can be the
  333. // same surface.
  334. HRESULT
  335. CPaletteMap::BltFast(LPDIRECTDRAWSURFACE pddsSrc, LPRECT prSrc, LPDIRECTDRAWSURFACE pddsDst,
  336. DWORD nXPos, DWORD nYPos, DWORD dwFlags) const
  337. {
  338. if (m_rgIndexMap == NULL)
  339. return E_NOTINITIALIZED;
  340. // make sure the surfaces are valid
  341. if (!pddsSrc || !pddsDst) {
  342. return E_INVALIDARG;
  343. }
  344. ConvertFunction pfnConvertFunction;
  345. HRESULT hr = E_INVALIDARG;
  346. BOOL bSrcLocked = FALSE, bDstLocked = FALSE;
  347. DDSURFACEDESC ddsdSrc, ddsdDst;
  348. INIT_DXSTRUCT(ddsdSrc);
  349. INIT_DXSTRUCT(ddsdDst);
  350. long nWidth, nHeight;
  351. //
  352. // Lock the surfaces
  353. //
  354. if (pddsSrc == pddsDst) {
  355. // REVIEW: this lock could just lock the minimum rectangle...
  356. if (FAILED(hr = pddsDst->Lock(NULL, &ddsdDst, DDLOCK_WAIT, NULL))) {
  357. goto e_Convert;
  358. }
  359. bSrcLocked = bDstLocked = TRUE;
  360. // copy the dst info into the src info
  361. ddsdSrc = ddsdDst;
  362. } else {
  363. // REVIEW: this lock could just lock the minimum rectangle...
  364. if (FAILED(hr = pddsSrc->Lock(NULL, &ddsdSrc, DDLOCK_WAIT, NULL)))
  365. goto e_Convert;
  366. bSrcLocked = TRUE;
  367. if (FAILED(hr = pddsDst->Lock(NULL, &ddsdDst, DDLOCK_WAIT, NULL)))
  368. goto e_Convert;
  369. bDstLocked = TRUE;
  370. }
  371. // verify the image information
  372. if ((ddsdSrc.ddpfPixelFormat.dwRGBBitCount != m_cSrcBPP) ||
  373. (ddsdDst.ddpfPixelFormat.dwRGBBitCount != m_cDstBPP)) {
  374. hr = E_INVALIDARG;
  375. goto e_Convert;
  376. }
  377. //
  378. // clip
  379. //
  380. long nClipWidth, nClipHeight, nLeft, nTop;
  381. if (prSrc == NULL) {
  382. nWidth = ddsdSrc.dwWidth;
  383. nHeight = ddsdSrc.dwHeight;
  384. nLeft = 0;
  385. nTop = 0;
  386. } else {
  387. nWidth = prSrc->right - prSrc->left;
  388. nHeight = prSrc->bottom - prSrc->top;
  389. nLeft = prSrc->left;
  390. nTop = prSrc->top;
  391. }
  392. nClipWidth = long(ddsdDst.dwWidth - nXPos);
  393. nClipHeight = long(ddsdDst.dwHeight - nYPos);
  394. UPDATEMAX(nClipWidth, 0);
  395. UPDATEMAX(nClipHeight, 0);
  396. UPDATEMAX(nWidth, 0);
  397. UPDATEMAX(nHeight, 0);
  398. UPDATEMAX(nLeft, 0);
  399. UPDATEMAX(nTop, 0);
  400. UPDATEMIN(nClipWidth, nWidth);
  401. UPDATEMIN(nClipHeight, nHeight);
  402. if (((nLeft + nClipWidth) > long(ddsdSrc.dwWidth)) ||
  403. ((nTop + nClipHeight) > long(ddsdSrc.dwHeight))) {
  404. hr = E_INVALIDARG;
  405. goto e_Convert;
  406. }
  407. // REVIEW: for now, fail if we are not dealing with at least 8BPP
  408. if ((ddsdSrc.ddpfPixelFormat.dwRGBBitCount < 8) || (ddsdDst.ddpfPixelFormat.dwRGBBitCount < 8)) {
  409. hr = E_FAIL;
  410. goto e_Convert;
  411. }
  412. nLeft *= (ddsdSrc.ddpfPixelFormat.dwRGBBitCount >> 3);
  413. nXPos *= (ddsdDst.ddpfPixelFormat.dwRGBBitCount >> 3);
  414. pfnConvertFunction = g_rgConvertFunctions[m_nConvertCode];
  415. if (pfnConvertFunction) {
  416. hr = pfnConvertFunction(
  417. LPBYTE(ddsdSrc.lpSurface) + nLeft + (nTop * ddsdSrc.lPitch),
  418. ddsdSrc.lPitch,
  419. LPBYTE(ddsdDst.lpSurface) + nXPos + (nYPos * ddsdDst.lPitch),
  420. ddsdDst.lPitch,
  421. nClipWidth,
  422. nClipHeight,
  423. m_rgIndexMap);
  424. } else {
  425. hr = E_NOTIMPL;
  426. goto e_Convert;
  427. }
  428. e_Convert:
  429. // unlock the surfaces
  430. if (pddsSrc == pddsDst) {
  431. if (bSrcLocked)
  432. pddsDst->Unlock(ddsdDst.lpSurface);
  433. } else {
  434. if (bDstLocked)
  435. pddsDst->Unlock(ddsdDst.lpSurface);
  436. if (bSrcLocked)
  437. pddsSrc->Unlock(ddsdSrc.lpSurface);
  438. }
  439. MMASSERT(SUCCEEDED(hr));
  440. return hr;
  441. }