home *** CD-ROM | disk | FTP | other *** search
/ PC Format (South-Africa) 2001 May / PCFMay2001.iso / Xenon / C++ / FreeCommandLineTools.exe / Include / dxhelper.h < prev    next >
Encoding:
C/C++ Source or Header  |  2000-01-31  |  33.8 KB  |  1,038 lines

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