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.

1087 lines
36 KiB

  1. /*******************************************************************************
  2. * DXHelper.h *
  3. *------------*
  4. * Description:
  5. * This is the header file for core helper functions implementation.
  6. *-------------------------------------------------------------------------------
  7. * Created By: Edward W. Connell Date: 07/11/95
  8. * Copyright (C) 1995 Microsoft Corporation
  9. * All Rights Reserved
  10. *
  11. *-------------------------------------------------------------------------------
  12. * Revisions:
  13. *
  14. *******************************************************************************/
  15. #ifndef DXHelper_h
  16. #define DXHelper_h
  17. #include <DXTError.h>
  18. #include <DXBounds.h>
  19. #include <DXTrans.h>
  20. #include <limits.h>
  21. #include <crtdbg.h>
  22. #include <malloc.h>
  23. #include <math.h>
  24. //=== Constants ==============================================================
  25. #define DX_MMX_COUNT_CUTOFF 16
  26. //=== Class, Enum, Struct and Union Declarations =============================
  27. /*** DXLIMAPINFO
  28. * This structure is used by the array linear interpolation and image
  29. * filtering routines.
  30. */
  31. typedef struct DXLIMAPINFO
  32. {
  33. float IndexFrac;
  34. USHORT Index;
  35. BYTE Weight;
  36. } DXLIMAPINFO;
  37. //
  38. // Declare this class as a global to use for determining when to call MMX optimized
  39. // code. You can use MinMMXOverCount to determine if MMX instructions are present.
  40. // Typically, you would only want to use MMX instructions when you have a reasonably
  41. // large number of pixels to work on. In this case your code can always be coded like
  42. // this:
  43. //
  44. // if (CountOfPixelsToDo >= g_MMXInfo.MinMMXOverCount())
  45. // {
  46. // Do MMX Stuff
  47. // } else {
  48. // Do integer / float based stuff
  49. // }
  50. //
  51. // If you code your MMX sequences like this, you will not have to use a special test
  52. // for the presence of MMX since the MinMMXOverCount will be set to 0xFFFFFFFF if there
  53. // is no MMX present on the processor.
  54. //
  55. // You do not need to use this unless your module needs to conditionally execute MMX vs
  56. // non-MMX code. If you only call the helper functions provided by DXTrans.Dll, such as
  57. // DXOverArrayMMX, you do NOT need this test. You can always call these functions and they
  58. // will use the MMX code path only when MMX instructions are present.
  59. //
  60. class CDXMMXInfo
  61. {
  62. ULONG m_MinMMXOver;
  63. public:
  64. CDXMMXInfo()
  65. {
  66. #ifndef _X86_
  67. m_MinMMXOver = 0xFFFFFFFF;
  68. #else
  69. m_MinMMXOver = DX_MMX_COUNT_CUTOFF;
  70. __try
  71. {
  72. __asm
  73. {
  74. //--- Try the MMX exit multi-media state instruction
  75. EMMS;
  76. }
  77. }
  78. __except( GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION )
  79. {
  80. //--- MMX instructions not available
  81. m_MinMMXOver = 0xFFFFFFFF;
  82. }
  83. #endif
  84. }
  85. inline ULONG MinMMXOverCount() { return m_MinMMXOver; }
  86. };
  87. //=== Function Prototypes ==========================================
  88. _DXTRANS_IMPL_EXT void WINAPI
  89. DXLinearInterpolateArray( const DXBASESAMPLE* pSamps, DXLIMAPINFO* pMapInfo,
  90. DXBASESAMPLE* pResults, DWORD dwResultCount );
  91. _DXTRANS_IMPL_EXT void WINAPI
  92. DXLinearInterpolateArray( const DXBASESAMPLE* pSamps, PUSHORT pIndexes,
  93. PBYTE pWeights, DXBASESAMPLE* pResults,
  94. DWORD dwResultCount );
  95. //
  96. // DXOverArray
  97. //
  98. // Composits an array of source samples over the samples in the pDest buffer.
  99. //
  100. // pDest - Pointer to the samples that will be modified by compositing the pSrc
  101. // samples over the pDest samples.
  102. // pSrc - The samples to composit over the pDest samples
  103. // nCount - The number of samples to process
  104. //
  105. _DXTRANS_IMPL_EXT void WINAPI
  106. DXOverArray(DXPMSAMPLE* pDest, const DXPMSAMPLE* pSrc, ULONG nCount);
  107. //
  108. // DXOverArrayMMX
  109. //
  110. // Identical to DXOverArray except that the MMX instruction set will be used for
  111. // large arrays of samples. If the CPU does not support MMX, you may still call
  112. // this function, which will perform the same operation without the use of the MMX
  113. // unit.
  114. //
  115. // Note that it is LESS EFFICIENT to use this function if the majority of the pixels
  116. // in the pSrc buffer are either clear (alpha 0) or opaque (alpha 0xFF). This is
  117. // because the MMX code must process every pixel and can not special case clear or
  118. // opaque pixels. If there are a large number of translucent pixels then this function
  119. // is much more efficent than DXOverArray.
  120. //
  121. // pDest - Pointer to the samples that will be modified by compositing the pSrc
  122. // samples over the pDest samples.
  123. // pSrc - The samples to composit over the pDest samples
  124. // nCount - The number of samples to process
  125. //
  126. _DXTRANS_IMPL_EXT void WINAPI
  127. DXOverArrayMMX(DXPMSAMPLE* pDest, const DXPMSAMPLE* pSrc, ULONG nCount);
  128. //
  129. // DXConstOverArray
  130. //
  131. // Composits a single color over an array of samples.
  132. //
  133. // pDest - Pointer to the samples that will be modified by compositing the color (val)
  134. // over the pDest samples.
  135. // val - The premultiplied color value to composit over the pDest array.
  136. // nCount - The number of samples to process
  137. //
  138. _DXTRANS_IMPL_EXT void WINAPI
  139. DXConstOverArray(DXPMSAMPLE* pDest, const DXPMSAMPLE & val, ULONG nCount);
  140. //
  141. // DXConstOverArray
  142. //
  143. // Composits a single color over an array of samples.
  144. //
  145. // pDest - Pointer to the samples that will be modified by compositing the samples
  146. // in the buffer over the color (val).
  147. // val - The premultiplied color value to composit under the pDest array.
  148. // nCount - The number of samples to process
  149. //
  150. _DXTRANS_IMPL_EXT void WINAPI
  151. DXConstUnderArray(DXPMSAMPLE* pDest, const DXPMSAMPLE & val, ULONG nCount);
  152. //===================================================================================
  153. //
  154. // Dithering Helpers
  155. //
  156. // Image transforms are sometimes asked to dither their output. This helper function
  157. // should be used by all image transforms to enusure a consistant dither pattern.
  158. //
  159. // DXDitherArray is used to dither pixels prior to writing them to a DXSurface.
  160. // The caller must fill in the DXDITHERDESC structure, setting X and Y to the
  161. // output surface X,Y coordinates that the pixels will be placed in. The samples
  162. // will be modified in place.
  163. //
  164. // Once the samples have been dithered, they should be written to or composited with
  165. // the destination surface.
  166. //
  167. #define DX_DITHER_HEIGHT 4 // The dither pattern is 4x4 pixels
  168. #define DX_DITHER_WIDTH 4
  169. typedef struct DXDITHERDESC
  170. {
  171. DXBASESAMPLE * pSamples; // Pointer to the 32-bit samples to dither
  172. ULONG cSamples; // Count of number of samples in pSamples buffer
  173. ULONG x; // X coordinate of the output surface
  174. ULONG y; // Y coordinate of the output surface
  175. DXSAMPLEFORMATENUM DestSurfaceFmt; // Pixel format of the output surface
  176. } DXDITHERDESC;
  177. _DXTRANS_IMPL_EXT void WINAPI
  178. DXDitherArray(const DXDITHERDESC *pDitherDesc);
  179. //=== Enumerated Set Definitions =============================================
  180. //=== Function Type Definitions ==============================================
  181. //=== Class, Struct and Union Definitions ====================================
  182. //=== Inline Functions =======================================================
  183. //===================================================================================
  184. //
  185. // Memory allocation helpers.
  186. //
  187. // These macros are used to allocate arrays of samples from the stack (using _alloca)
  188. // and cast them to the appropriate type. The ulNumSamples parameter is the count
  189. // of samples required.
  190. //
  191. #define DXBASESAMPLE_Alloca( ulNumSamples ) \
  192. (DXBASESAMPLE *)_alloca( (ulNumSamples) * sizeof( DXBASESAMPLE ) )
  193. #define DXSAMPLE_Alloca( ulNumSamples ) \
  194. (DXSAMPLE *)_alloca( (ulNumSamples) * sizeof( DXSAMPLE ) )
  195. #define DXPMSAMPLE_Alloca( ulNumSamples ) \
  196. (DXPMSAMPLE *)_alloca( (ulNumSamples) * sizeof( DXPMSAMPLE ) )
  197. //===================================================================================
  198. //
  199. // Critical section helpers.
  200. //
  201. // These C++ classes, CDXAutoObjectLock and CDXAutoCritSecLock are used within functions
  202. // to automatically claim critical sections upon constuction, and the critical section
  203. // will be released when the object is destroyed (goes out of scope).
  204. //
  205. // The macros DXAUTO_OBJ_LOCK and DX_AUTO_SEC_LOCK(s) are normally used at the beginning
  206. // of a function that requires a critical section. Any exit from the scope in which the
  207. // auto-lock was taken will automatically release the lock.
  208. //
  209. #ifdef __ATLCOM_H__ //--- Only enable these if ATL is being used
  210. class CDXAutoObjectLock
  211. {
  212. protected:
  213. CComObjectRootEx<CComMultiThreadModel>* m_pObject;
  214. public:
  215. CDXAutoObjectLock(CComObjectRootEx<CComMultiThreadModel> * const pobject)
  216. {
  217. m_pObject = pobject;
  218. m_pObject->Lock();
  219. };
  220. ~CDXAutoObjectLock() {
  221. m_pObject->Unlock();
  222. };
  223. };
  224. #define DXAUTO_OBJ_LOCK CDXAutoObjectLock lck(this);
  225. #define DXAUTO_OBJ_LOCK_( t ) CDXAutoObjectLock lck(t);
  226. class CDXAutoCritSecLock
  227. {
  228. protected:
  229. CComAutoCriticalSection* m_pSec;
  230. public:
  231. CDXAutoCritSecLock(CComAutoCriticalSection* pSec)
  232. {
  233. m_pSec = pSec;
  234. m_pSec->Lock();
  235. };
  236. ~CDXAutoCritSecLock()
  237. {
  238. m_pSec->Unlock();
  239. };
  240. };
  241. #define DXAUTO_SEC_LOCK( s ) CDXAutoCritSecLock lck(s);
  242. #endif // __ATLCOM_H__
  243. //--- This function is used to compute the coefficient for a gaussian filter coordinate
  244. inline float DXGaussCoeff( double x, double y, double Sigma )
  245. {
  246. double TwoSigmaSq = 2 * ( Sigma * Sigma );
  247. return (float)(exp( ( -(x*x + y*y) / TwoSigmaSq ) ) /
  248. ( 3.1415927 * TwoSigmaSq ));
  249. }
  250. //--- This function is used to initialize a gaussian convolution filter
  251. inline void DXInitGaussianFilter( float* pFilter, ULONG Width, ULONG Height, double Sigma )
  252. {
  253. int i, NumCoeff = Width * Height;
  254. float val, CoeffAdjust, FilterSum = 0.;
  255. double x, y;
  256. double LeftX = -(double)(Width / 2);
  257. double RightX = Width - LeftX;
  258. double TopY = -(double)(Height / 2);
  259. double BottomY = Height - TopY;
  260. for( y = -TopY; y <= BottomY; y += 1. )
  261. {
  262. for( x = -LeftX; x <= RightX; x += 1. )
  263. {
  264. val = DXGaussCoeff( x, y, Sigma );
  265. pFilter[i++] = val;
  266. }
  267. }
  268. //--- Normalize filter (make it sum to 1.0)
  269. for( i = 0; i < NumCoeff; ++i ) FilterSum += pFilter[i];
  270. if( FilterSum < 1. )
  271. {
  272. CoeffAdjust = 1.f / FilterSum;
  273. for( i = 0; i < NumCoeff; ++i )
  274. {
  275. pFilter[i] *= CoeffAdjust;
  276. }
  277. }
  278. } /* DXInitGaussianFilter*/
  279. //
  280. // DXConvertToGray
  281. //
  282. // Translates a color sample to a gray scale sample
  283. //
  284. // Sample - The sample to convert to gray scale.
  285. // Return value is the gray scale sample.
  286. //
  287. inline DXBASESAMPLE DXConvertToGray( DXBASESAMPLE Sample )
  288. {
  289. DWORD v = Sample;
  290. DWORD r = (BYTE)(v >> 16);
  291. DWORD g = (BYTE)(v >> 8);
  292. DWORD b = (BYTE)(v);
  293. DWORD sat = (r*306 + g*601 + b*117) / 1024;
  294. v &= 0xFF000000;
  295. v |= (sat << 16) | (sat << 8) | sat;
  296. return v;
  297. } /* DXConvertToGray */
  298. //--- This returns into the destination the value of the source
  299. // sample scaled by its own alpha (producing a premultiplied alpha sample)
  300. //
  301. inline DXPMSAMPLE DXPreMultSample(const DXSAMPLE & Src)
  302. {
  303. if(Src.Alpha == 255 )
  304. {
  305. return (DWORD)Src;
  306. }
  307. else if(Src.Alpha == 0 )
  308. {
  309. return 0;
  310. }
  311. else
  312. {
  313. unsigned t1, t2;
  314. t1 = (Src & 0x00ff00ff) * Src.Alpha + 0x00800080;
  315. t1 = ((t1 + ((t1 >> 8) & 0x00ff00ff)) >> 8) & 0x00ff00ff;
  316. t2 = (((Src >> 8) & 0x000000ff) | 0x01000000) * Src.Alpha + 0x00800080;
  317. t2 = (t2 + ((t2 >> 8) & 0x00ff00ff)) & 0xff00ff00;
  318. return (t1 | t2);
  319. }
  320. } /* DXPreMultSample */
  321. inline DXPMSAMPLE * DXPreMultArray(DXSAMPLE *pBuffer, ULONG cSamples)
  322. {
  323. for (ULONG i = 0; i < cSamples; i++)
  324. {
  325. BYTE SrcAlpha = pBuffer[i].Alpha;
  326. if (SrcAlpha != 0xFF)
  327. {
  328. if (SrcAlpha == 0)
  329. {
  330. pBuffer[i] = 0;
  331. }
  332. else
  333. {
  334. DWORD S = pBuffer[i];
  335. DWORD t1 = (S & 0x00ff00ff) * SrcAlpha + 0x00800080;
  336. t1 = ((t1 + ((t1 >> 8) & 0x00ff00ff)) >> 8) & 0x00ff00ff;
  337. DWORD t2 = (((S >> 8) & 0x000000ff) | 0x01000000) * SrcAlpha + 0x00800080;
  338. t2 = (t2 + ((t2 >> 8) & 0x00ff00ff)) & 0xff00ff00;
  339. pBuffer[i] = (t1 | t2);
  340. }
  341. }
  342. }
  343. return (DXPMSAMPLE *)pBuffer;
  344. }
  345. inline DXSAMPLE DXUnPreMultSample(const DXPMSAMPLE & Src)
  346. {
  347. if(Src.Alpha == 255 || Src.Alpha == 0)
  348. {
  349. return (DWORD)Src;
  350. }
  351. else
  352. {
  353. DXSAMPLE Dst;
  354. Dst.Blue = (BYTE)((Src.Blue * 255) / Src.Alpha);
  355. Dst.Green = (BYTE)((Src.Green * 255) / Src.Alpha);
  356. Dst.Red = (BYTE)((Src.Red * 255) / Src.Alpha);
  357. Dst.Alpha = Src.Alpha;
  358. return Dst;
  359. }
  360. } /* DXUnPreMultSample */
  361. inline DXSAMPLE * DXUnPreMultArray(DXPMSAMPLE *pBuffer, ULONG cSamples)
  362. {
  363. for (ULONG i = 0; i < cSamples; i++)
  364. {
  365. BYTE SrcAlpha = pBuffer[i].Alpha;
  366. if (SrcAlpha != 0xFF && SrcAlpha != 0)
  367. {
  368. pBuffer[i].Blue = (BYTE)((pBuffer[i].Blue * 255) / SrcAlpha);
  369. pBuffer[i].Green = (BYTE)((pBuffer[i].Green * 255) / SrcAlpha);
  370. pBuffer[i].Red = (BYTE)((pBuffer[i].Red * 255) / SrcAlpha);
  371. }
  372. }
  373. return (DXSAMPLE *)pBuffer;
  374. }
  375. //
  376. // This returns the result of 255-Alpha which is computed by doing a NOT
  377. //
  378. inline BYTE DXInvertAlpha( BYTE Alpha ) { return (BYTE)~Alpha; }
  379. inline DWORD DXScaleSample( DWORD Src, ULONG beta )
  380. {
  381. ULONG t1, t2;
  382. t1 = (Src & 0x00ff00ff) * beta + 0x00800080;
  383. t1 = ((t1 + ((t1 >> 8) & 0x00ff00ff)) >> 8) & 0x00ff00ff;
  384. t2 = ((Src >> 8) & 0x00ff00ff) * beta + 0x00800080;
  385. t2 = (t2 + ((t2 >> 8) & 0x00ff00ff)) & 0xff00ff00;
  386. return (DWORD)(t1 | t2);
  387. }
  388. inline DWORD DXScaleSamplePercent( DWORD Src, float Percent )
  389. {
  390. if (Percent > (254.0f / 255.0f)) {
  391. return Src;
  392. }
  393. else
  394. {
  395. return DXScaleSample(Src, (BYTE)(Percent * 255));
  396. }
  397. }
  398. inline void DXCompositeOver(DXPMSAMPLE & Dst, const DXPMSAMPLE & Src)
  399. {
  400. if (Src.Alpha)
  401. {
  402. ULONG Beta = DXInvertAlpha(Src.Alpha);
  403. if (Beta)
  404. {
  405. Dst = Src + DXScaleSample(Dst, Beta);
  406. }
  407. else
  408. {
  409. Dst = Src;
  410. }
  411. }
  412. }
  413. inline DXPMSAMPLE DXCompositeUnder(DXPMSAMPLE Dst, DXPMSAMPLE Src )
  414. {
  415. return Dst + DXScaleSample(Src, DXInvertAlpha(Dst.Alpha));
  416. }
  417. inline DXBASESAMPLE DXApplyLookupTable(const DXBASESAMPLE Src, const BYTE * pTable)
  418. {
  419. DXBASESAMPLE Dest;
  420. Dest.Blue = pTable[Src.Blue];
  421. Dest.Green = pTable[Src.Green];
  422. Dest.Red = pTable[Src.Red];
  423. Dest.Alpha = pTable[Src.Alpha];
  424. return Dest;
  425. }
  426. inline DXBASESAMPLE * DXApplyLookupTableArray(DXBASESAMPLE *pBuffer, ULONG cSamples, const BYTE * pTable)
  427. {
  428. for (ULONG i = 0; i < cSamples; i++)
  429. {
  430. DWORD v = pBuffer[i];
  431. DWORD a = pTable[v >> 24];
  432. DWORD r = pTable[(BYTE)(v >> 16)];
  433. DWORD g = pTable[(BYTE)(v >> 8)];
  434. DWORD b = pTable[(BYTE)v];
  435. pBuffer[i] = (a << 24) | (r << 16) | (g << 8) | b;
  436. }
  437. return pBuffer;
  438. }
  439. inline DXBASESAMPLE * DXApplyColorChannelLookupArray(DXBASESAMPLE *pBuffer,
  440. ULONG cSamples,
  441. const BYTE * pAlphaTable,
  442. const BYTE * pRedTable,
  443. const BYTE * pGreenTable,
  444. const BYTE * pBlueTable)
  445. {
  446. for (ULONG i = 0; i < cSamples; i++)
  447. {
  448. pBuffer[i].Blue = pBlueTable[pBuffer[i].Blue];
  449. pBuffer[i].Green = pGreenTable[pBuffer[i].Green];
  450. pBuffer[i].Red = pRedTable[pBuffer[i].Red];
  451. pBuffer[i].Alpha = pAlphaTable[pBuffer[i].Alpha];
  452. }
  453. return pBuffer;
  454. }
  455. //
  456. // CDXScale helper class
  457. //
  458. // This class uses a pre-computed lookup table to scale samples. For scaling large
  459. // arrays of samples to a constant scale, this is much faster than using even MMX
  460. // instructions. This class is usually declared as a member of another class and
  461. // is most often used to apply a global opacity to a set of samples.
  462. //
  463. // When using this class, you must always check for the two special cases of clear
  464. // and opaque before calling any of the scaling member functions. Do this by using
  465. // the ScaleType() inline function. Your code should look somthing like this:
  466. //
  467. // if (ScaleType() == DXRUNTYPE_CLEAR)
  468. // Do whatever you do for a 0 alpha set of samples -- usually just ignore them
  469. // else if (ScaleType() == DXRUNTYPE_OPAQUE)
  470. // Do whatever you would do for a non-scaled set of samples
  471. // else
  472. // Scale the samples by using ScaleSample or one of the ScaleArray members
  473. //
  474. // If you call any of the scaling members when the ScaleType() is either clear or
  475. // opaque, you will GP fault becuase the lookup table will not be allocated.
  476. //
  477. // The scale can be set using either a floating point number between 0 and 1 using:
  478. // CDXScale::SetScale / CDXScale::GetScale
  479. // or you can use a byte integer value by using:
  480. // CDXScale::SetScaleAlphaValue / CDXScale::GetScaleAlphaValue
  481. //
  482. class CDXScale
  483. {
  484. private:
  485. float m_Scale;
  486. BYTE m_AlphaScale;
  487. BYTE *m_pTable;
  488. HRESULT InternalSetScale(BYTE Scale)
  489. {
  490. if (m_AlphaScale == Scale) return S_OK;
  491. if (Scale == 0 || Scale == 255)
  492. {
  493. delete m_pTable;
  494. m_pTable = NULL;
  495. }
  496. else
  497. {
  498. if(!m_pTable)
  499. {
  500. m_pTable = new BYTE[256];
  501. if(!m_pTable )
  502. {
  503. return E_OUTOFMEMORY;
  504. }
  505. }
  506. for (int i = 0; i < 256; ++i )
  507. {
  508. m_pTable[i] = (BYTE)((i * Scale) / 255);
  509. }
  510. }
  511. m_AlphaScale = Scale;
  512. return S_OK;
  513. }
  514. public:
  515. CDXScale() :
  516. m_Scale(1.0f),
  517. m_AlphaScale(0xFF),
  518. m_pTable(NULL)
  519. {}
  520. ~CDXScale()
  521. {
  522. delete m_pTable;
  523. }
  524. DXRUNTYPE ScaleType()
  525. {
  526. if (m_AlphaScale == 0) return DXRUNTYPE_CLEAR;
  527. if (m_AlphaScale == 0xFF) return DXRUNTYPE_OPAQUE;
  528. return DXRUNTYPE_TRANS;
  529. }
  530. HRESULT SetScaleAlphaValue(BYTE Alpha)
  531. {
  532. HRESULT hr = InternalSetScale(Alpha);
  533. if (SUCCEEDED(hr))
  534. {
  535. m_Scale = ((float)Alpha) / 255.0f;
  536. }
  537. return hr;
  538. }
  539. BYTE GetScaleAlphaValue(void)
  540. {
  541. return m_AlphaScale;
  542. }
  543. HRESULT SetScale(float Scale)
  544. {
  545. HRESULT hr = S_OK;
  546. if(( Scale < 0.0f ) || ( Scale > 1.0f ) )
  547. {
  548. hr = E_INVALIDARG;
  549. }
  550. else
  551. {
  552. ULONG IntScale = (ULONG)(Scale * 256.0f); // Round up alpha (.9999 = 255 = Solid)
  553. if (IntScale > 255)
  554. {
  555. IntScale = 255;
  556. }
  557. hr = SetScaleAlphaValue((BYTE)IntScale);
  558. if (SUCCEEDED(hr))
  559. {
  560. m_Scale = Scale;
  561. }
  562. }
  563. return hr;
  564. }
  565. float GetScale() const
  566. {
  567. return m_Scale;
  568. }
  569. DXRUNTYPE ScaleType() const
  570. {
  571. return (m_pTable ? DXRUNTYPE_TRANS : (m_AlphaScale ? DXRUNTYPE_OPAQUE : DXRUNTYPE_CLEAR));
  572. }
  573. DWORD ScaleSample(const DWORD s) const
  574. {
  575. return DXApplyLookupTable((DXBASESAMPLE)s, m_pTable);
  576. }
  577. DXBASESAMPLE * ScaleBaseArray(DXBASESAMPLE * pBuffer, ULONG cSamples) const
  578. {
  579. return DXApplyLookupTableArray(pBuffer, cSamples, m_pTable);
  580. }
  581. DXPMSAMPLE * ScalePremultArray(DXPMSAMPLE * pBuffer, ULONG cSamples) const
  582. {
  583. return (DXPMSAMPLE *)DXApplyLookupTableArray(pBuffer, cSamples, m_pTable);
  584. }
  585. DXSAMPLE * ScaleArray(DXSAMPLE * pBuffer, ULONG cSamples) const
  586. {
  587. return (DXSAMPLE *)DXApplyLookupTableArray(pBuffer, cSamples, m_pTable);
  588. }
  589. DXSAMPLE * ScaleArrayAlphaOnly(DXSAMPLE *pBuffer, ULONG cSamples) const
  590. {
  591. const BYTE *pTable = m_pTable;
  592. for (ULONG i = 0; i < cSamples; i++)
  593. {
  594. pBuffer[i].Alpha = pTable[pBuffer[i].Alpha];
  595. }
  596. return pBuffer;
  597. }
  598. };
  599. inline DWORD DXWeightedAverage( DXBASESAMPLE S1, DXBASESAMPLE S2, ULONG Wgt )
  600. {
  601. _ASSERT( Wgt < 256 );
  602. ULONG t1, t2;
  603. ULONG InvWgt = Wgt ^ 0xFF;
  604. t1 = (((S1 & 0x00ff00ff) * Wgt) + ((S2 & 0x00ff00ff) * InvWgt )) + 0x00800080;
  605. t1 = ((t1 + ((t1 >> 8) & 0x00ff00ff)) >> 8) & 0x00ff00ff;
  606. t2 = ((((S1 >> 8) & 0x00ff00ff) * Wgt) + (((S2 >> 8) & 0x00ff00ff) * InvWgt )) + 0x00800080;
  607. t2 = (t2 + ((t2 >> 8) & 0x00ff00ff)) & 0xff00ff00;
  608. return (t1 | t2);
  609. } /* DXWeightedAverage */
  610. inline void DXWeightedAverageArray( DXBASESAMPLE* pS1, DXBASESAMPLE* pS2, ULONG Wgt,
  611. DXBASESAMPLE* pResults, DWORD dwCount )
  612. {
  613. _ASSERT( pS1 && pS2 && pResults && dwCount );
  614. for( DWORD i = 0; i < dwCount; ++i )
  615. {
  616. pResults[i] = DXWeightedAverage( pS1[i], pS2[i], Wgt );
  617. }
  618. } /* DXWeightedAverageArray */
  619. inline void DXWeightedAverageArrayOver( DXPMSAMPLE* pS1, DXPMSAMPLE* pS2, ULONG Wgt,
  620. DXPMSAMPLE* pResults, DWORD dwCount )
  621. {
  622. _ASSERT( pS1 && pS2 && pResults && dwCount );
  623. DWORD i;
  624. if( Wgt == 255 )
  625. {
  626. for( i = 0; i < dwCount; ++i )
  627. {
  628. DXCompositeOver( pResults[i], pS1[i] );
  629. }
  630. }
  631. else
  632. {
  633. for( i = 0; i < dwCount; ++i )
  634. {
  635. DXPMSAMPLE Avg = DXWeightedAverage( (DXBASESAMPLE)pS1[i],
  636. (DXBASESAMPLE)pS2[i], Wgt );
  637. DXCompositeOver( pResults[i], Avg );
  638. }
  639. }
  640. } /* DXWeightedAverageArrayOver */
  641. inline void DXScalePremultArray(DXPMSAMPLE *pBuffer, ULONG cSamples, BYTE Weight)
  642. {
  643. for (DXPMSAMPLE *pBuffLimit = pBuffer + cSamples; pBuffer < pBuffLimit; pBuffer++)
  644. {
  645. *pBuffer = DXScaleSample(*pBuffer, Weight);
  646. }
  647. }
  648. //
  649. //
  650. inline HRESULT DXClipToOutputWithPlacement(CDXDBnds & LogicalOutBnds, const CDXDBnds * pClipBnds, CDXDBnds & PhysicalOutBnds, const CDXDVec *pPlacement)
  651. {
  652. if(pClipBnds && (!LogicalOutBnds.IntersectBounds(*pClipBnds)))
  653. {
  654. return S_FALSE; // no intersect, we're done
  655. }
  656. else
  657. {
  658. CDXDVec vClipPos(false);
  659. LogicalOutBnds.GetMinVector( vClipPos );
  660. if (pPlacement)
  661. {
  662. vClipPos -= *pPlacement;
  663. }
  664. PhysicalOutBnds += vClipPos;
  665. if (!LogicalOutBnds.IntersectBounds(PhysicalOutBnds))
  666. {
  667. return S_FALSE;
  668. }
  669. PhysicalOutBnds = LogicalOutBnds;
  670. PhysicalOutBnds -= vClipPos;
  671. }
  672. return S_OK;
  673. }
  674. //
  675. // Helper for converting a color ref to a DXSAMPLE
  676. //
  677. inline DWORD DXSampleFromColorRef(COLORREF cr)
  678. {
  679. DXSAMPLE Samp(0xFF, GetRValue(cr), GetGValue(cr), GetBValue(cr));
  680. return Samp;
  681. }
  682. //
  683. // Fill an entire surface with a color
  684. //
  685. inline HRESULT DXFillSurface( IDXSurface *pSurface, DXPMSAMPLE Color,
  686. BOOL bDoOver = FALSE, ULONG ulTimeOut = 10000 )
  687. {
  688. IDXARGBReadWritePtr * pPtr;
  689. HRESULT hr = pSurface->LockSurface( NULL, ulTimeOut, DXLOCKF_READWRITE,
  690. IID_IDXARGBReadWritePtr, (void **)&pPtr, NULL);
  691. if( SUCCEEDED(hr) )
  692. {
  693. pPtr->FillRect(NULL, Color, bDoOver);
  694. pPtr->Release();
  695. }
  696. return hr;
  697. } /* DXFillSurface */
  698. //
  699. // Fill a specified sub-rectangle of a surface with a color.
  700. //
  701. inline HRESULT DXFillSurfaceRect( IDXSurface *pSurface, RECT & rect, DXPMSAMPLE Color,
  702. BOOL bDoOver = FALSE, ULONG ulTimeOut = 10000 )
  703. {
  704. CDXDBnds bnds(rect);
  705. IDXARGBReadWritePtr * pPtr;
  706. HRESULT hr = pSurface->LockSurface( &bnds, ulTimeOut, DXLOCKF_READWRITE,
  707. IID_IDXARGBReadWritePtr, (void **)&pPtr, NULL);
  708. if( SUCCEEDED(hr) )
  709. {
  710. pPtr->FillRect(NULL, Color, bDoOver);
  711. pPtr->Release();
  712. }
  713. return hr;
  714. } /* DXFillSurfaceRect */
  715. //
  716. // The DestBnds height and width must be greater than or equal to the source bounds.
  717. //
  718. // The dwFlags parameter uses the flags defined by IDXSurfaceFactory::BitBlt:
  719. //
  720. // DXBOF_DO_OVER
  721. // DXBOF_DITHER
  722. //
  723. inline HRESULT DXBitBlt(IDXSurface * pDest, const CDXDBnds & DestBnds,
  724. IDXSurface * pSrc, const CDXDBnds & SrcBnds,
  725. DWORD dwFlags, ULONG ulTimeout)
  726. {
  727. IDXARGBReadPtr * pIn;
  728. HRESULT hr;
  729. hr = pSrc->LockSurface( &SrcBnds, INFINITE,
  730. (dwFlags & DXBOF_DO_OVER) ? (DXLOCKF_READ | DXLOCKF_WANTRUNINFO) : DXLOCKF_READ,
  731. IID_IDXARGBReadPtr, (void**)&pIn, NULL);
  732. if(SUCCEEDED(hr))
  733. {
  734. IDXARGBReadWritePtr * pOut;
  735. hr = pDest->LockSurface( &DestBnds, INFINITE, DXLOCKF_READWRITE,
  736. IID_IDXARGBReadWritePtr, (void**)&pOut, NULL );
  737. if (SUCCEEDED(hr))
  738. {
  739. DXSAMPLEFORMATENUM InNativeType = pIn->GetNativeType(NULL);
  740. DXSAMPLEFORMATENUM OutNativeType = pOut->GetNativeType(NULL);
  741. BOOL bSrcIsOpaque = !(InNativeType & (DXPF_TRANSLUCENCY | DXPF_TRANSPARENCY));
  742. const ULONG Width = SrcBnds.Width();
  743. DXPMSAMPLE *pSrcBuff = NULL;
  744. if( InNativeType != DXPF_PMARGB32 )
  745. {
  746. pSrcBuff = DXPMSAMPLE_Alloca(Width);
  747. }
  748. //
  749. // Don't dither unless the dest has a greater error term than the source.
  750. //
  751. if ((dwFlags & DXBOF_DITHER) &&
  752. ((OutNativeType & DXPF_ERRORMASK) <= (InNativeType & DXPF_ERRORMASK)))
  753. {
  754. dwFlags &= (~DXBOF_DITHER);
  755. }
  756. if ((dwFlags & DXBOF_DITHER) || ((dwFlags & DXBOF_DO_OVER) && bSrcIsOpaque== 0))
  757. {
  758. //--- Allocate a working output buffer if necessary
  759. DXPMSAMPLE *pDestBuff = NULL;
  760. if( OutNativeType != DXPF_PMARGB32 )
  761. {
  762. pDestBuff = DXPMSAMPLE_Alloca(Width);
  763. }
  764. //--- Process each output row
  765. // Note: Output coordinates are relative to the lock region
  766. const ULONG Height = SrcBnds.Height();
  767. if (dwFlags & DXBOF_DITHER)
  768. {
  769. DXPMSAMPLE * pSrcDitherBuff = pSrcBuff;
  770. if (pSrcDitherBuff == NULL)
  771. {
  772. pSrcDitherBuff = DXPMSAMPLE_Alloca(Width);
  773. }
  774. const BOOL bCopy = ((dwFlags & DXBOF_DO_OVER) == 0);
  775. //
  776. // Set up the dither descriptor (some things are constant)
  777. //
  778. DXDITHERDESC dd;
  779. dd.pSamples = pSrcDitherBuff;
  780. dd.DestSurfaceFmt = OutNativeType;
  781. for(ULONG Y = 0; Y < Height; ++Y )
  782. {
  783. dd.x = DestBnds.Left();
  784. dd.y = DestBnds.Top() + Y;
  785. const DXRUNINFO *pRunInfo;
  786. ULONG cRuns = pIn->MoveAndGetRunInfo(Y, &pRunInfo);
  787. pOut->MoveToRow( Y );
  788. do
  789. {
  790. ULONG ulRunLen = pRunInfo->Count;
  791. if (pRunInfo->Type == DXRUNTYPE_CLEAR)
  792. {
  793. pIn->Move(ulRunLen);
  794. if (bCopy)
  795. {
  796. //
  797. // The only way to avoid calling a constructor function to create
  798. // a pmsample from 0 is to declare a variable and then assign it!
  799. //
  800. DXPMSAMPLE NullColor;
  801. NullColor = 0;
  802. pOut->FillAndMove(pSrcDitherBuff, NullColor, ulRunLen, FALSE);
  803. }
  804. else
  805. {
  806. pOut->Move(ulRunLen);
  807. }
  808. dd.x += ulRunLen;
  809. }
  810. else
  811. {
  812. pIn->UnpackPremult(pSrcDitherBuff, ulRunLen, TRUE);
  813. dd.cSamples = ulRunLen;
  814. DXDitherArray(&dd);
  815. dd.x += ulRunLen;
  816. if (bCopy || pRunInfo->Type == DXRUNTYPE_OPAQUE)
  817. {
  818. pOut->PackPremultAndMove(pSrcDitherBuff, ulRunLen);
  819. }
  820. else
  821. {
  822. pOut->OverArrayAndMove(pDestBuff, pSrcDitherBuff, ulRunLen);
  823. }
  824. }
  825. pRunInfo++;
  826. cRuns--;
  827. } while (cRuns);
  828. }
  829. }
  830. else
  831. {
  832. for(ULONG Y = 0; Y < Height; ++Y )
  833. {
  834. const DXRUNINFO *pRunInfo;
  835. ULONG cRuns = pIn->MoveAndGetRunInfo(Y, &pRunInfo);
  836. pOut->MoveToRow( Y );
  837. do
  838. {
  839. ULONG ulRunLen = pRunInfo->Count;
  840. switch (pRunInfo->Type)
  841. {
  842. case DXRUNTYPE_CLEAR:
  843. pIn->Move(ulRunLen);
  844. pOut->Move(ulRunLen);
  845. break;
  846. case DXRUNTYPE_OPAQUE:
  847. pOut->CopyAndMoveBoth(pDestBuff, pIn, ulRunLen, TRUE);
  848. break;
  849. case DXRUNTYPE_TRANS:
  850. {
  851. DXPMSAMPLE *pSrc = pIn->UnpackPremult(pSrcBuff, ulRunLen, TRUE);
  852. DXPMSAMPLE *pDest = pOut->UnpackPremult(pDestBuff, ulRunLen, FALSE);
  853. DXOverArrayMMX(pDest, pSrc, ulRunLen);
  854. pOut->PackPremultAndMove(pDestBuff, ulRunLen);
  855. break;
  856. }
  857. case DXRUNTYPE_UNKNOWN:
  858. {
  859. pOut->OverArrayAndMove(pDestBuff,
  860. pIn->UnpackPremult(pSrcBuff, ulRunLen, TRUE),
  861. ulRunLen);
  862. break;
  863. }
  864. }
  865. pRunInfo++;
  866. cRuns--;
  867. } while (cRuns);
  868. }
  869. }
  870. }
  871. else // if ((dwFlags & DXBOF_DITHER) || ((dwFlags & DXBOF_DO_OVER) && bSrcIsOpaque== 0))
  872. {
  873. // This code is run if:
  874. //
  875. // !(dwFlags & DXBOF_DITHER)
  876. // && !((dwFlags & DXBOF_DO_OVER) && bSrcIsOpaque == 0)
  877. //
  878. // In English:
  879. //
  880. // This code is run if 1) dithering is not required
  881. // and 2) blending with output is not required because it was
  882. // not requested or because it's not needed because the source
  883. // pixels are all opaque.
  884. // hrDD is initialized to failure so that in the event that the
  885. // pixel formats don't match or the pixel format supports
  886. // transparency, the CopyRect will still run.
  887. HRESULT hrDD = E_FAIL;
  888. DXSAMPLEFORMATENUM formatIn = pIn->GetNativeType(NULL);
  889. // If the pixel formats match and do not support transparency
  890. // (because it's not supported by ddraw yet) try to use a
  891. // ddraw blit instead of CopyRect.
  892. if ((formatIn == pOut->GetNativeType(NULL))
  893. && !(formatIn & DXPF_TRANSPARENCY))
  894. {
  895. CComPtr<IDirectDrawSurface> cpDDSrc;
  896. // Get source ddraw surface pointer.
  897. hrDD = pSrc->QueryInterface(IID_IDirectDrawSurface,
  898. (void **)&cpDDSrc);
  899. if (SUCCEEDED(hrDD))
  900. {
  901. CComPtr<IDirectDrawSurface> cpDDDest;
  902. // Get destination ddraw surface pointer.
  903. hrDD = pDest->QueryInterface(IID_IDirectDrawSurface,
  904. (void **)&cpDDDest);
  905. if (SUCCEEDED(hrDD))
  906. {
  907. RECT rcSrc;
  908. RECT rcDest;
  909. SrcBnds.GetXYRect(rcSrc);
  910. DestBnds.GetXYRect(rcDest);
  911. // Attempt the ddraw blit.
  912. hrDD = cpDDDest->Blt(&rcDest, cpDDSrc, &rcSrc,
  913. 0, NULL);
  914. }
  915. }
  916. }
  917. // If hrDD has failed at this point, it means a direct draw blit
  918. // was not possible and a CopyRect is needed to perform the
  919. // copy.
  920. if (FAILED(hrDD))
  921. {
  922. pOut->CopyRect(pSrcBuff, NULL, pIn, NULL, bSrcIsOpaque);
  923. }
  924. }
  925. pOut->Release();
  926. }
  927. pIn->Release();
  928. }
  929. return hr;
  930. }
  931. inline HRESULT DXSrcCopy(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight,
  932. IDXSurface *pSrcSurface, int nXSrc, int nYSrc)
  933. {
  934. IDXDCLock *pDCLock;
  935. HRESULT hr = pSrcSurface->LockSurfaceDC(NULL, INFINITE, DXLOCKF_READ, &pDCLock);
  936. if (SUCCEEDED(hr))
  937. {
  938. ::BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, pDCLock->GetDC(), nXSrc, nYSrc, SRCCOPY);
  939. pDCLock->Release();
  940. }
  941. return hr;
  942. }
  943. //
  944. //=== Pointer validation functions
  945. //
  946. inline BOOL DXIsBadReadPtr( const void* pMem, UINT Size )
  947. {
  948. #if !defined( _DEBUG ) && defined( DXTRANS_NOROBUST )
  949. return false;
  950. #else
  951. return ::IsBadReadPtr( pMem, Size );
  952. #endif
  953. }
  954. inline BOOL DXIsBadWritePtr( void* pMem, UINT Size )
  955. {
  956. #if !defined( _DEBUG ) && defined( DXTRANS_NOROBUST )
  957. return false;
  958. #else
  959. return ::IsBadWritePtr( pMem, Size );
  960. #endif
  961. }
  962. inline BOOL DXIsBadInterfacePtr( const IUnknown* pUnknown )
  963. {
  964. #if !defined( _DEBUG ) && defined( DXTRANS_NOROBUST )
  965. return false;
  966. #else
  967. return ( ::IsBadReadPtr( pUnknown, sizeof( *pUnknown ) ) ||
  968. ::IsBadCodePtr( (FARPROC)((void **)pUnknown)[0] ))?
  969. (true):(false);
  970. #endif
  971. }
  972. #define DX_IS_BAD_OPTIONAL_WRITE_PTR(p) ((p) && DXIsBadWritePtr(p, sizeof(p)))
  973. #define DX_IS_BAD_OPTIONAL_READ_PTR(p) ((p) && DXIsBadReadPtr(p, sizeof(p)))
  974. #define DX_IS_BAD_OPTIONAL_INTERFACE_PTR(p) ((p) && DXIsBadInterfacePtr(p))
  975. #endif /* This must be the last line in the file */