Home COM GDI+ WebBrowser Data Access 

Filters Functions

 

Functions

 

DXAPCPROC

DXApplyColorChannelLookupArray

DXApplyLookupTable

DXApplyLookupTableArray

DXBASESAMPLE_Alloca

DXBitBlt

DXClipToOutputWithPlacement

DXColorFromBSTR

DXCompositeOver

DXCompositeUnder

DXConstOverArray

DXConstUnderArray

DXConvertToGray

DXDitherArray

DXFillSurface

DXFillSurfaceRect

DXInvertAlpha

DXIsBAdInterfacePtr

DXIsBadReadPtr

DXIsBadWriterPtr

DXLinearInterpolateArray

DXOverArray

DXOverArrayMMX

DXPMSAMPLE_Alloca

DXPreMultArray

DXPreMultSample

DXSAMPLE_Alloca

DXSampleFromColorRef

DXScalePemultArray

DXSampleFromColorRef

DXScalePremultArray

DXScaleSample

DXScaleSamplePercent

DXSrcCopy

DXTASKPROC

DXUnPreMultArray

DXUnPreMultSample

DXWeightedAverage

 

 

DXWeightedAverageArray

DXWeightedAverageArrayOver

DXWeightedAverage

DXWeightedAverageArray

DXWeightedAverageArrayOver

DXSrcCopy

DXTASKPROC

DXUnPreMultArray

DXUnPreMultSample

DXWeightedAverage

DXWeightedAverageArray

DXWeightedAverageArrayOver

DXTASKPROC

DXUnPreMultArray

DXUnPreMultSample

DXWeightedAverage

DXWeightedAverageArray

DXWeightedAverageArrayOver

DXOverArray

DXOverArrayMMX

DXPMSAMPLE_Alloca

DXPreMultArray

DXPreMultSample

DXSAMPLE_Alloca

DXSampleFromColorRef

DXScalePemultArray

DXSampleFromColorRef

DXScalePremultArray

DXScaleSample

DXScaleSamplePercent

DXSrcCopy

DXTASKPROC

DXUnPreMultArray

DXUnPreMultSample

DXWeightedAverage

DXWeightedAverageArray

DXWeightedAverageArrayOver

 

 

 

 

/*******************************************************************************
* DXHelper.h *
*------------*
*   Description:
*       This is the header file for core helper functions implementation.
*-------------------------------------------------------------------------------
*  Created By: Edward W. Connell                            Date: 07/11/95
*  Copyright (C) 1995 Microsoft Corporation
*  All Rights Reserved
*
*-------------------------------------------------------------------------------
*  Revisions:
*
*******************************************************************************/
#ifndef DXHelper_h
#pragma option push -b -a8 -pc -A- /*P_O_Push*/
#define DXHelper_h

#ifndef DXTError_h
#include <DXTError.h>
#endif

#ifndef DXBounds_h
#include <DXBounds.h>
#endif

#ifndef __DXTrans_h__
#include <DXTrans.h>
#endif

#ifndef _INC_LIMITS
#include <limits.h>
#endif

#ifndef _INC_CRTDBG
#include <crtdbg.h>
#endif

#ifndef _INC_MALLOC
#include <malloc.h>
#endif


//=== Constants ==============================================================

#define DX_MMX_COUNT_CUTOFF 16

//=== Class, Enum, Struct and Union Declarations =============================

/*** DXLIMAPINFO
*   This structure is used by the array linear interpolation and image
*   filtering routines.
*/
typedef struct DXLIMAPINFO
{
    float   IndexFrac;
    USHORT  Index;
    BYTE    Weight;
} DXLIMAPINFO;

//
//  Declare this class as a global to use for determining when to call MMX optimized
//  code.  You can use MinMMXOverCount to determine if MMX instructions are present.
//  Typically, you would only want to use MMX instructions when you have a reasonably
//  large number of pixels to work on.  In this case your code can always be coded like
//  this:
//
//  if (CountOfPixelsToDo >= g_MMXInfo.MinMMXOverCount())
//  {
//      Do MMX Stuff
//  } else {
//      Do integer / float based stuff
//  }    
//  
//  If you code your MMX sequences like this, you will not have to use a special test
//  for the presence of MMX since the MinMMXOverCount will be set to 0xFFFFFFFF if there
//  is no MMX present on the processor.
//
//  You do not need to use this unless your module needs to conditionally execute MMX vs
//  non-MMX code.  If you only call the helper functions provided by DXTrans.Dll, such as
//  DXOverArrayMMX, you do NOT need this test.  You can always call these functions and they
//  will use the MMX code path only when MMX instructions are present.
//
class CDXMMXInfo
{
    ULONG m_MinMMXOver;
public:
    CDXMMXInfo()
    {
#ifndef _X86_
        m_MinMMXOver = 0xFFFFFFFF;
#else
        m_MinMMXOver = DX_MMX_COUNT_CUTOFF;
        __try
        {
            __asm
            {
                //--- Try the MMX exit multi-media state instruction
                EMMS;
            }
        }
        __except( GetExceptionCode() == EXCEPTION_ILLEGAL_INSTRUCTION )
        {
            //--- MMX instructions not available
            m_MinMMXOver = 0xFFFFFFFF;
        }
#endif
    }
    inline ULONG MinMMXOverCount() { return m_MinMMXOver; }
};



//=== Function Prototypes ==========================================
_DXTRANS_IMPL_EXT void WINAPI
    DXLinearInterpolateArray( const DXBASESAMPLE* pSamps, DXLIMAPINFO* pMapInfo,
                              DXBASESAMPLE* pResults, DWORD dwResultCount );
_DXTRANS_IMPL_EXT void WINAPI
    DXLinearInterpolateArray( const DXBASESAMPLE* pSamps, PUSHORT pIndexes,
                              PBYTE pWeights, DXBASESAMPLE* pResults,
                              DWORD dwResultCount );

//
//  DXOverArray
//
//  Composits an array of source samples over the samples in the pDest buffer.
//
//  pDest   - Pointer to the samples that will be modified by compositing the pSrc
//            samples over the pDest samples.
//  pSrc    - The samples to composit over the pDest samples
//  nCount  - The number of samples to process
//
_DXTRANS_IMPL_EXT void WINAPI
    DXOverArray(DXPMSAMPLE* pDest, const DXPMSAMPLE* pSrc, ULONG nCount);

//
//  DXOverArrayMMX
//
//  Identical to DXOverArray except that the MMX instruction set will be used for
//  large arrays of samples.  If the CPU does not support MMX, you may still call
//  this function, which will perform the same operation without the use of the MMX
//  unit.
//
//  Note that it is LESS EFFICIENT to use this function if the majority of the pixels
//  in the pSrc buffer are either clear (alpha 0) or opaque (alpha 0xFF).  This is 
//  because the MMX code must process every pixel and can not special case clear or
//  opaque pixels.  If there are a large number of translucent pixels then this function
//  is much more efficent than DXOverArray.
//
//  pDest   - Pointer to the samples that will be modified by compositing the pSrc
//            samples over the pDest samples.
//  pSrc    - The samples to composit over the pDest samples
//  nCount  - The number of samples to process
//
_DXTRANS_IMPL_EXT void WINAPI
    DXOverArrayMMX(DXPMSAMPLE* pDest, const DXPMSAMPLE* pSrc, ULONG nCount);

//
//  DXConstOverArray
//
//  Composits a single color over an array of samples.
//
//  pDest   - Pointer to the samples that will be modified by compositing the color (val)
//            over the pDest samples.
//  val     - The premultiplied color value to composit over the pDest array.
//  nCount  - The number of samples to process
//
_DXTRANS_IMPL_EXT void WINAPI
    DXConstOverArray(DXPMSAMPLE* pDest, const DXPMSAMPLE & val, ULONG nCount);

//
//  DXConstOverArray
//
//  Composits a single color over an array of samples.
//
//  pDest   - Pointer to the samples that will be modified by compositing the samples
//            in the buffer over the color (val).
//  val     - The premultiplied color value to composit under the pDest array.
//  nCount  - The number of samples to process
//
_DXTRANS_IMPL_EXT void WINAPI
    DXConstUnderArray(DXPMSAMPLE* pDest, const DXPMSAMPLE & val, ULONG nCount);

//===================================================================================
//
//  Dithering Helpers
//
//  Image transforms are sometimes asked to dither their output.  This helper function
//  should be used by all image transforms to enusure a consistant dither pattern.
//
//  DXDitherArray is used to dither pixels prior to writing them to a DXSurface.
//  The caller must fill in the DXDITHERDESC structure, setting X and Y to the
//  output surface X,Y coordinates that the pixels will be placed in.  The samples
//  will be modified in place.
//
//  Once the samples have been dithered, they should be written to or composited with
//  the destination surface.
//
#define DX_DITHER_HEIGHT    4       // The dither pattern is 4x4 pixels
#define DX_DITHER_WIDTH     4

typedef struct DXDITHERDESC
{
    DXBASESAMPLE *      pSamples;       // Pointer to the 32-bit samples to dither
    ULONG               cSamples;       // Count of number of samples in pSamples buffer
    ULONG               x;              // X coordinate of the output surface
    ULONG               y;              // Y coordinate of the output surface
    DXSAMPLEFORMATENUM  DestSurfaceFmt; // Pixel format of the output surface
} DXDITHERDESC;

_DXTRANS_IMPL_EXT void WINAPI
    DXDitherArray(const DXDITHERDESC *pDitherDesc);

//=== Enumerated Set Definitions =============================================


//=== Function Type Definitions ==============================================


//=== Class, Struct and Union Definitions ====================================


//=== Inline Functions =======================================================

//===================================================================================
//
//  Memory allocation helpers.
//
//  These macros are used to allocate arrays of samples from the stack (using _alloca)
//  and cast them to the appropriate type.  The ulNumSamples parameter is the count
//  of samples required.
//
#define DXBASESAMPLE_Alloca( ulNumSamples ) \
    (DXBASESAMPLE *)_alloca( (ulNumSamples) * sizeof( DXBASESAMPLE ) )

#define DXSAMPLE_Alloca( ulNumSamples ) \
    (DXSAMPLE *)_alloca( (ulNumSamples) * sizeof( DXSAMPLE ) )

#define DXPMSAMPLE_Alloca( ulNumSamples ) \
    (DXPMSAMPLE *)_alloca( (ulNumSamples) * sizeof( DXPMSAMPLE ) )

//===================================================================================
//
//  Critical section helpers.
//
//  These C++ classes, CDXAutoObjectLock and CDXAutoCritSecLock are used within functions
//  to automatically claim critical sections upon constuction, and the critical section
//  will be released when the object is destroyed (goes out of scope).
//
//  The macros DXAUTO_OBJ_LOCK and DX_AUTO_SEC_LOCK(s) are normally used at the beginning
//  of a function that requires a critical section.  Any exit from the scope in which the
//  auto-lock was taken will automatically release the lock.
//

#ifdef __ATLCOM_H__     //--- Only enable these if ATL is being used
class CDXAutoObjectLock
{
  protected:
    CComObjectRootEx<CComMultiThreadModel>* m_pObject;

  public:
    CDXAutoObjectLock(CComObjectRootEx<CComMultiThreadModel> * const pobject)
    {
        m_pObject = pobject;
        m_pObject->Lock();
    };

    ~CDXAutoObjectLock() {
        m_pObject->Unlock();
    };
};

#define DXAUTO_OBJ_LOCK CDXAutoObjectLock lck(this);
#define DXAUTO_OBJ_LOCK_( t ) CDXAutoObjectLock lck(t);

class CDXAutoCritSecLock
{
  protected:
    CComAutoCriticalSection* m_pSec;

  public:
    CDXAutoCritSecLock(CComAutoCriticalSection* pSec)
    {
        m_pSec = pSec;
        m_pSec->Lock();
    };

    ~CDXAutoCritSecLock()
    {
        m_pSec->Unlock();
    };
};

#define DXAUTO_SEC_LOCK( s ) CDXAutoCritSecLock lck(s);
#endif  // __ATLCOM_H__

//--- This function is used to compute the coefficient for a gaussian filter coordinate
inline float DXGaussCoeff( double x, double y, double Sigma )
{
    double TwoSigmaSq = 2 * ( Sigma * Sigma );
    return (float)(exp( ( -(x*x + y*y) / TwoSigmaSq  ) ) /
                        ( 3.1415927 * TwoSigmaSq ));
}

//--- This function is used to initialize a gaussian convolution filter
inline void DXInitGaussianFilter( float* pFilter, ULONG Width, ULONG Height, double Sigma )
{
    int i, NumCoeff = Width * Height;
    float  val, CoeffAdjust, FilterSum = 0.;
    double x, y;
    double LeftX   = -(double)(Width / 2);
    double RightX  =   Width - LeftX;
    double TopY    = -(double)(Height / 2);
    double BottomY =   Height - TopY;

    for( y = -TopY; y <= BottomY; y += 1. )
    {
        for( x = -LeftX; x <= RightX; x += 1. )
        {
            val = DXGaussCoeff( x, y, Sigma );
            pFilter[i++] = val;
        }
    }

    //--- Normalize filter (make it sum to 1.0)
    for( i = 0; i < NumCoeff; ++i ) FilterSum += pFilter[i];

    if( FilterSum < 1. )
    {
        CoeffAdjust = 1.f / FilterSum;
        for( i = 0; i < NumCoeff; ++i )
        {
            pFilter[i] *= CoeffAdjust;
        }
    }

} /* DXInitGaussianFilter*/

//
//  DXConvertToGray
//
//  Translates a color sample to a gray scale sample
//
//  Sample  - The sample to convert to gray scale.
//  Return value is the gray scale sample.
//
inline DXBASESAMPLE DXConvertToGray( DXBASESAMPLE Sample )
{
    DWORD v = Sample;
    DWORD r = (BYTE)(v >> 16);
    DWORD g = (BYTE)(v >> 8);
    DWORD b = (BYTE)(v);
    DWORD sat = (r*306 + g*601 + b*117) / 1024;
    v &= 0xFF000000;
    v |= (sat << 16) | (sat << 8) | sat;
    return v;
} /* DXConvertToGray */

//--- This returns into the destination the value of the source
//  sample scaled by its own alpha (producing a premultiplied alpha sample)
//
inline DXPMSAMPLE DXPreMultSample(const DXSAMPLE & Src)
{
    if(Src.Alpha == 255 )
    {
        return (DWORD)Src;
    }
    else if(Src.Alpha == 0 )
    {
        return 0;
    }
    else
    {
        unsigned t1, t2;
        t1 = (Src & 0x00ff00ff) * Src.Alpha + 0x00800080;
        t1 = ((t1 + ((t1 >> 8) & 0x00ff00ff)) >> 8) & 0x00ff00ff;

        t2 = (((Src >> 8) & 0x000000ff) | 0x01000000) * Src.Alpha + 0x00800080;
        t2 = (t2 + ((t2 >> 8) & 0x00ff00ff)) & 0xff00ff00;
        return (t1 | t2);
    }
} /* DXPreMultSample */

inline DXPMSAMPLE * DXPreMultArray(DXSAMPLE *pBuffer, ULONG cSamples)
{
    for (ULONG i = 0; i < cSamples; i++)
    {
        BYTE SrcAlpha = pBuffer[i].Alpha;
        if (SrcAlpha != 0xFF)
        {
            if (SrcAlpha == 0)
            {
                pBuffer[i] = 0;
            }
            else
            {
                DWORD S = pBuffer[i];
                DWORD t1 = (S & 0x00ff00ff) * SrcAlpha + 0x00800080;
                t1 = ((t1 + ((t1 >> 8) & 0x00ff00ff)) >> 8) & 0x00ff00ff;

                DWORD t2 = (((S >> 8) & 0x000000ff) | 0x01000000) * SrcAlpha + 0x00800080;
                t2 = (t2 + ((t2 >> 8) & 0x00ff00ff)) & 0xff00ff00;

                pBuffer[i] = (t1 | t2);
            }
        }
    }
    return (DXPMSAMPLE *)pBuffer;
}


inline DXSAMPLE DXUnPreMultSample(const DXPMSAMPLE & Src)
{
    if(Src.Alpha == 255 || Src.Alpha == 0)
    {
        return (DWORD)Src;
    }
    else
    {
        DXSAMPLE Dst;
        Dst.Blue  = (BYTE)((Src.Blue  * 255) / Src.Alpha);
        Dst.Green = (BYTE)((Src.Green * 255) / Src.Alpha);
        Dst.Red   = (BYTE)((Src.Red   * 255) / Src.Alpha);
        Dst.Alpha = Src.Alpha;
        return Dst;
    }
} /* DXUnPreMultSample */

inline DXSAMPLE * DXUnPreMultArray(DXPMSAMPLE *pBuffer, ULONG cSamples)
{
    for (ULONG i = 0; i < cSamples; i++)
    {
        BYTE SrcAlpha = pBuffer[i].Alpha;
        if (SrcAlpha != 0xFF && SrcAlpha != 0)
        {
            pBuffer[i].Blue  = (BYTE)((pBuffer[i].Blue  * 255) / SrcAlpha);
            pBuffer[i].Green = (BYTE)((pBuffer[i].Green * 255) / SrcAlpha);
            pBuffer[i].Red   = (BYTE)((pBuffer[i].Red   * 255) / SrcAlpha);
        }
    }
    return (DXSAMPLE *)pBuffer;
}


//
//  This returns the result of 255-Alpha which is computed by doing a NOT
//
inline BYTE DXInvertAlpha( BYTE Alpha ) { return (BYTE)~Alpha; }

inline DWORD DXScaleSample( DWORD Src, ULONG beta )
{
    ULONG t1, t2;

    t1 = (Src & 0x00ff00ff) * beta + 0x00800080;
    t1 = ((t1 + ((t1 >> 8) & 0x00ff00ff)) >> 8) & 0x00ff00ff;

    t2 = ((Src >> 8) & 0x00ff00ff) * beta + 0x00800080;
    t2 = (t2 + ((t2 >> 8) & 0x00ff00ff)) & 0xff00ff00;

    return (DWORD)(t1 | t2);
}


inline DWORD DXScaleSamplePercent( DWORD Src, float Percent )
{
    if (Percent > (254.0f / 255.0f)) {
        return Src;
    }
    else
    {
        return DXScaleSample(Src, (BYTE)(Percent * 255));
    }
}

inline void DXCompositeOver(DXPMSAMPLE & Dst, const DXPMSAMPLE & Src)
{
    if (Src.Alpha)
    {
        ULONG Beta = DXInvertAlpha(Src.Alpha);
        if (Beta)
        {
            Dst = Src + DXScaleSample(Dst, Beta);
        }
        else
        {
            Dst = Src;
        }
    }
}


inline DXPMSAMPLE DXCompositeUnder(DXPMSAMPLE Dst, DXPMSAMPLE Src )
{
    return Dst + DXScaleSample(Src, DXInvertAlpha(Dst.Alpha));
}


inline DXBASESAMPLE DXApplyLookupTable(const DXBASESAMPLE Src, const BYTE * pTable)
{
    DXBASESAMPLE Dest;
    Dest.Blue   = pTable[Src.Blue];
    Dest.Green  = pTable[Src.Green];
    Dest.Red    = pTable[Src.Red];
    Dest.Alpha  = pTable[Src.Alpha];
    return Dest;
}

inline DXBASESAMPLE * DXApplyLookupTableArray(DXBASESAMPLE *pBuffer, ULONG cSamples, const BYTE * pTable)
{
    for (ULONG i = 0; i < cSamples; i++)
    {
        DWORD v = pBuffer[i];
        DWORD a = pTable[v >> 24];
        DWORD r = pTable[(BYTE)(v >> 16)];
        DWORD g = pTable[(BYTE)(v >> 8)];
        DWORD b = pTable[(BYTE)v];
        pBuffer[i] = (a << 24) | (r << 16) | (g << 8) | b;
    }
    return pBuffer;
}

inline DXBASESAMPLE * DXApplyColorChannelLookupArray(DXBASESAMPLE *pBuffer,
                                                     ULONG cSamples,
                                                     const BYTE * pAlphaTable,
                                                     const BYTE * pRedTable,
                                                     const BYTE * pGreenTable,
                                                     const BYTE * pBlueTable)
{
    for (ULONG i = 0; i < cSamples; i++)
    {
        pBuffer[i].Blue   = pBlueTable[pBuffer[i].Blue];
        pBuffer[i].Green  = pGreenTable[pBuffer[i].Green];
        pBuffer[i].Red    = pRedTable[pBuffer[i].Red];
        pBuffer[i].Alpha  = pAlphaTable[pBuffer[i].Alpha];
    }
    return pBuffer;
}


//
//  CDXScale helper class
//
//  This class uses a pre-computed lookup table to scale samples.  For scaling large
//  arrays of samples to a constant scale, this is much faster than using even MMX
//  instructions.  This class is usually declared as a member of another class and
//  is most often used to apply a global opacity to a set of samples.
//
//  When using this class, you must always check for the two special cases of clear
//  and opaque before calling any of the scaling member functions.  Do this by using
//  the ScaleType() inline function.  Your code should look somthing like this:
//
//  if (ScaleType() == DXRUNTYPE_CLEAR)
//      Do whatever you do for a 0 alpha set of samples -- usually just ignore them
//  else if (ScaleType() == DXRUNTYPE_OPAQUE)
//      Do whatever you would do for a non-scaled set of samples
//  else
//      Scale the samples by using ScaleSample or one of the ScaleArray members
//
//  If you call any of the scaling members when the ScaleType() is either clear or
//  opaque, you will GP fault becuase the lookup table will not be allocated.
//
//  The scale can be set using either a floating point number between 0 and 1 using:
//      CDXScale::SetScale / CDXScale::GetScale
//  or you can use a byte integer value by using:
//      CDXScale::SetScaleAlphaValue / CDXScale::GetScaleAlphaValue
//
class CDXScale
{
private:
    float       m_Scale;
    BYTE        m_AlphaScale;
    BYTE        *m_pTable;

HRESULT InternalSetScale(BYTE Scale)
{
    if (m_AlphaScale == Scale) return S_OK;
    if (Scale == 0 || Scale == 255) 
    {
        delete m_pTable;
        m_pTable = NULL;
    }
    else
    {
        if(!m_pTable)
        {
            m_pTable = new BYTE[256];
            if(!m_pTable )
            {
                return E_OUTOFMEMORY;
            }
        }
        for (int i = 0; i < 256; ++i )
        {
            m_pTable[i] = (BYTE)((i * Scale) / 255);
        }
    }
    m_AlphaScale = Scale;
    return S_OK;
}
public:
    CDXScale() : 
      m_Scale(1.0f),
      m_AlphaScale(0xFF),
      m_pTable(NULL)
      {}
    ~CDXScale()
    {
        delete m_pTable;
    }
    DXRUNTYPE ScaleType() 
    {
        if (m_AlphaScale == 0) return DXRUNTYPE_CLEAR;
        if (m_AlphaScale == 0xFF) return DXRUNTYPE_OPAQUE;
        return DXRUNTYPE_TRANS;
    }
    HRESULT SetScaleAlphaValue(BYTE Alpha)
    {
        HRESULT hr = InternalSetScale(Alpha);
        if (SUCCEEDED(hr))
        {
            m_Scale = ((float)Alpha) / 255.0f;
        }
        return hr;
    }
    BYTE GetScaleAlphaValue(void)
    {
        return m_AlphaScale;
    }
    HRESULT SetScale(float Scale)
    {
        HRESULT hr = S_OK;
        if(( Scale < 0.0f ) || ( Scale > 1.0f ) )
        {
            hr = E_INVALIDARG;
        }
        else
        {
            ULONG IntScale = (ULONG)(Scale * 256.0f);     // Round up alpha (.9999 = 255 = Solid)
            if (IntScale > 255) 
            {
                IntScale = 255;
            }
            hr = SetScaleAlphaValue((BYTE)IntScale);
            if (SUCCEEDED(hr))
            {
                m_Scale = Scale;
            }
        }
        return hr;
    }
    float GetScale() const
    {
        return m_Scale;
    }
    DXRUNTYPE ScaleType() const
    {
        return (m_pTable ? DXRUNTYPE_TRANS : (m_AlphaScale ? DXRUNTYPE_OPAQUE : DXRUNTYPE_CLEAR));
    }
    DWORD ScaleSample(const DWORD s) const
    {
        return DXApplyLookupTable((DXBASESAMPLE)s, m_pTable);
    }
    DXBASESAMPLE * ScaleBaseArray(DXBASESAMPLE * pBuffer, ULONG cSamples) const
    {
        return DXApplyLookupTableArray(pBuffer, cSamples, m_pTable);
    }
    DXPMSAMPLE * ScalePremultArray(DXPMSAMPLE * pBuffer, ULONG cSamples) const
    {
        return (DXPMSAMPLE *)DXApplyLookupTableArray(pBuffer, cSamples, m_pTable);
    }
    DXSAMPLE * ScaleArray(DXSAMPLE * pBuffer, ULONG cSamples) const
    {
        return (DXSAMPLE *)DXApplyLookupTableArray(pBuffer, cSamples, m_pTable);
    }
    DXSAMPLE * ScaleArrayAlphaOnly(DXSAMPLE *pBuffer, ULONG cSamples) const
    {
        const BYTE *pTable = m_pTable;
        for (ULONG i = 0; i < cSamples; i++)
        {
            pBuffer[i].Alpha  = pTable[pBuffer[i].Alpha];
        }
        return pBuffer;
    }
};

inline DWORD DXWeightedAverage( DXBASESAMPLE S1, DXBASESAMPLE S2, ULONG Wgt )
{
    _ASSERT( Wgt < 256 );
    ULONG t1, t2;
    ULONG InvWgt = Wgt ^ 0xFF;

    t1  = (((S1 & 0x00ff00ff) * Wgt) + ((S2 & 0x00ff00ff) * InvWgt )) + 0x00800080;
    t1  = ((t1 + ((t1 >> 8) & 0x00ff00ff)) >> 8) & 0x00ff00ff;

    t2  = ((((S1 >> 8) & 0x00ff00ff) * Wgt) + (((S2 >> 8) & 0x00ff00ff) * InvWgt )) + 0x00800080;
    t2  = (t2 + ((t2 >> 8) & 0x00ff00ff)) & 0xff00ff00;

    return (t1 | t2);
} /* DXWeightedAverage */

inline void DXWeightedAverageArray( DXBASESAMPLE* pS1, DXBASESAMPLE* pS2, ULONG Wgt,
                                    DXBASESAMPLE* pResults, DWORD dwCount )
{
    _ASSERT( pS1 && pS2 && pResults && dwCount );
    for( DWORD i = 0; i < dwCount; ++i )
    {
        pResults[i] = DXWeightedAverage( pS1[i], pS2[i], Wgt );
    }
} /* DXWeightedAverageArray */

inline void DXWeightedAverageArrayOver( DXPMSAMPLE* pS1, DXPMSAMPLE* pS2, ULONG Wgt,
                                        DXPMSAMPLE* pResults, DWORD dwCount )
{
    _ASSERT( pS1 && pS2 && pResults && dwCount );
    DWORD i;

    if( Wgt == 255 )
    {
        for( i = 0; i < dwCount; ++i )
        {
            DXCompositeOver( pResults[i], pS1[i] );
        }
    }
    else
    {
        for( i = 0; i < dwCount; ++i )
        {
            DXPMSAMPLE Avg = DXWeightedAverage( (DXBASESAMPLE)pS1[i],
                                                (DXBASESAMPLE)pS2[i], Wgt );
            DXCompositeOver( pResults[i], Avg );
        }
    }

} /* DXWeightedAverageArrayOver */

inline void DXScalePremultArray(DXPMSAMPLE *pBuffer, ULONG cSamples, BYTE Weight)
{
    for (DXPMSAMPLE *pBuffLimit = pBuffer + cSamples; pBuffer < pBuffLimit; pBuffer++)
    {
        *pBuffer = DXScaleSample(*pBuffer, Weight);
    }
}



//
//
inline HRESULT DXClipToOutputWithPlacement(CDXDBnds & LogicalOutBnds, const CDXDBnds * pClipBnds, CDXDBnds & PhysicalOutBnds, const CDXDVec *pPlacement)
{
    if(pClipBnds && (!LogicalOutBnds.IntersectBounds(*pClipBnds)))
    {
        return S_FALSE;    // no intersect, we're done
    }
    else
    {
        CDXDVec vClipPos(false);
        LogicalOutBnds.GetMinVector( vClipPos );
        if (pPlacement)
        {
            vClipPos -= *pPlacement;
        }
        PhysicalOutBnds += vClipPos;
        if (!LogicalOutBnds.IntersectBounds(PhysicalOutBnds))
        {
            return S_FALSE;
        }
        PhysicalOutBnds = LogicalOutBnds;
        PhysicalOutBnds -= vClipPos;
    }
    return S_OK;
}



//
//  Helper for converting a color ref to a DXSAMPLE
//
inline DWORD DXSampleFromColorRef(COLORREF cr)
{
    DXSAMPLE Samp(0xFF, GetRValue(cr), GetGValue(cr), GetBValue(cr));
    return Samp;
}

//
//  Fill an entire surface with a color
//
inline HRESULT DXFillSurface( IDXSurface *pSurface, DXPMSAMPLE Color,
                              BOOL bDoOver = FALSE, ULONG ulTimeOut = 10000 )
{
    IDXARGBReadWritePtr * pPtr;
    HRESULT hr = pSurface->LockSurface( NULL, ulTimeOut, DXLOCKF_READWRITE, 
                                        IID_IDXARGBReadWritePtr, (void **)&pPtr, NULL);
    if( SUCCEEDED(hr) )
    {
        pPtr->FillRect(NULL, Color, bDoOver);
        pPtr->Release();
    }
    return hr;
} /* DXFillSurface */

//
//  Fill a specified sub-rectangle of a surface with a color.
//
inline HRESULT DXFillSurfaceRect( IDXSurface *pSurface, RECT & rect, DXPMSAMPLE Color,
                                  BOOL bDoOver = FALSE, ULONG ulTimeOut = 10000 )
{
    CDXDBnds bnds(rect);
    IDXARGBReadWritePtr * pPtr;
    HRESULT hr = pSurface->LockSurface( &bnds, ulTimeOut, DXLOCKF_READWRITE, 
                                         IID_IDXARGBReadWritePtr, (void **)&pPtr, NULL);
    if( SUCCEEDED(hr) )
    {
        pPtr->FillRect(NULL, Color, bDoOver);
        pPtr->Release();
    }
    return hr;
} /* DXFillSurfaceRect */



//
//  The DestBnds height and width must be greater than or equal to the source bounds.
//
//  The dwFlags parameter uses the flags defined by IDXSurfaceFactory::BitBlt:
// 
//    DXBOF_DO_OVER
//    DXBOF_DITHER
//
inline HRESULT DXBitBlt(IDXSurface * pDest, const CDXDBnds & DestBnds, IDXSurface * pSrc, const CDXDBnds & SrcBnds, DWORD dwFlags, ULONG ulTimeout)
{
    IDXARGBReadPtr * pIn;
    HRESULT hr;
    hr = pSrc->LockSurface( &SrcBnds, INFINITE,
                            (dwFlags & DXBOF_DO_OVER) ? (DXLOCKF_READ | DXLOCKF_WANTRUNINFO) : DXLOCKF_READ,
                            IID_IDXARGBReadPtr, (void**)&pIn, NULL);
    if(SUCCEEDED(hr))
    {
        IDXARGBReadWritePtr * pOut;
        hr = pDest->LockSurface( &DestBnds, INFINITE, DXLOCKF_READWRITE,
                                 IID_IDXARGBReadWritePtr, (void**)&pOut, NULL );
        if (SUCCEEDED(hr))
        {
            DXSAMPLEFORMATENUM InNativeType = pIn->GetNativeType(NULL);
            DXSAMPLEFORMATENUM OutNativeType = pOut->GetNativeType(NULL);
            BOOL bSrcIsOpaque = !(InNativeType & (DXPF_TRANSLUCENCY | DXPF_TRANSPARENCY));
            const ULONG Width = SrcBnds.Width();
            DXPMSAMPLE *pSrcBuff = NULL;
            if( InNativeType != DXPF_PMARGB32 )
            {
                pSrcBuff = DXPMSAMPLE_Alloca(Width);
            }
            //
            //  Don't dither unless the dest has a greater error term than the source.
            //
            if ((dwFlags & DXBOF_DITHER) && 
                ((OutNativeType & DXPF_ERRORMASK) <= (InNativeType & DXPF_ERRORMASK)))
            {
                dwFlags &= (~DXBOF_DITHER);
            }
            if ((dwFlags & DXBOF_DITHER) || ((dwFlags & DXBOF_DO_OVER) && bSrcIsOpaque== 0))
            {
                //--- Allocate a working output buffer if necessary
                DXPMSAMPLE *pDestBuff = NULL;
                if( OutNativeType != DXPF_PMARGB32 )
                {
                    pDestBuff = DXPMSAMPLE_Alloca(Width);
                }
                //--- Process each output row
                //    Note: Output coordinates are relative to the lock region
                const ULONG Height = SrcBnds.Height();
                if (dwFlags & DXBOF_DITHER)
                {
                    DXPMSAMPLE * pSrcDitherBuff = pSrcBuff;
                    if (pSrcDitherBuff == NULL)
                    {
                        pSrcDitherBuff = DXPMSAMPLE_Alloca(Width);
                    }
                    const BOOL bCopy = ((dwFlags & DXBOF_DO_OVER) == 0);
                    //
                    //  Set up the dither descriptor (some things are constant)
                    //
                    DXDITHERDESC dd;
                    dd.pSamples = pSrcDitherBuff;
                    dd.DestSurfaceFmt = OutNativeType;
                    for(ULONG Y = 0; Y < Height; ++Y )
                    {
                        dd.x = DestBnds.Left();
                        dd.y = DestBnds.Top() + Y;
                        const DXRUNINFO *pRunInfo;
                        ULONG cRuns = pIn->MoveAndGetRunInfo(Y, &pRunInfo);
                        pOut->MoveToRow( Y );
                        do
                        {
                            ULONG ulRunLen = pRunInfo->Count;
                            if (pRunInfo->Type == DXRUNTYPE_CLEAR)
                            {
                                pIn->Move(ulRunLen);
                                if (bCopy)
                                {
                                    //
                                    //  The only way to avoid calling a constructor function to create
                                    //  a pmsample from 0 is to declare a variable and then assign it!
                                    //
                                    DXPMSAMPLE NullColor;
                                    NullColor = 0;
                                    pOut->FillAndMove(pSrcDitherBuff, NullColor, ulRunLen, FALSE);
                                }
                                else
                                {
                                    pOut->Move(ulRunLen);
                                }
                                dd.x += ulRunLen;
                            }
                            else
                            {
                                pIn->UnpackPremult(pSrcDitherBuff, ulRunLen, TRUE);
                                dd.cSamples = ulRunLen;
                                DXDitherArray(&dd);
                                dd.x += ulRunLen;
                                if (bCopy || pRunInfo->Type == DXRUNTYPE_OPAQUE)
                                {
                                    pOut->PackPremultAndMove(pSrcDitherBuff, ulRunLen);
                                }
                                else
                                {
                                    pOut->OverArrayAndMove(pDestBuff, pSrcDitherBuff, ulRunLen);
                                }
                            }
                            pRunInfo++;
                            cRuns--;
                        } while (cRuns);
                    }
                }
                else
                {
                    for(ULONG Y = 0; Y < Height; ++Y )
                    {
                        const DXRUNINFO *pRunInfo;
                        ULONG cRuns = pIn->MoveAndGetRunInfo(Y, &pRunInfo);
                        pOut->MoveToRow( Y );
                        do
                        {
                            ULONG ulRunLen = pRunInfo->Count;
                            switch (pRunInfo->Type)
                            {
                              case DXRUNTYPE_CLEAR:
                                pIn->Move(ulRunLen);
                                pOut->Move(ulRunLen);
                                break;
                              case DXRUNTYPE_OPAQUE:
                                pOut->CopyAndMoveBoth(pDestBuff, pIn, ulRunLen, TRUE);
                                break;
                              case DXRUNTYPE_TRANS:
                              {
                                DXPMSAMPLE *pSrc = pIn->UnpackPremult(pSrcBuff, ulRunLen, TRUE);
                                DXPMSAMPLE *pDest = pOut->UnpackPremult(pDestBuff, ulRunLen, FALSE);                 
                                DXOverArrayMMX(pDest, pSrc, ulRunLen);
                                pOut->PackPremultAndMove(pDestBuff, ulRunLen);
                                break;
                              }

                              case DXRUNTYPE_UNKNOWN:
                              {
                                pOut->OverArrayAndMove(pDestBuff,
                                                       pIn->UnpackPremult(pSrcBuff, ulRunLen, TRUE),
                                                       ulRunLen);
                                break;
                              }
                            }
                            pRunInfo++;
                            cRuns--;
                        } while (cRuns);
                    }
                }
            }
            else
            {
                pOut->CopyRect( pSrcBuff, NULL, pIn, NULL, bSrcIsOpaque );
            }
            pOut->Release();
        }
        pIn->Release();
    }
    return hr;
}

inline HRESULT DXSrcCopy(HDC hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, 
                         IDXSurface *pSrcSurface, int nXSrc, int nYSrc)
{
    IDXDCLock *pDCLock;
    HRESULT hr = pSrcSurface->LockSurfaceDC(NULL, INFINITE, DXLOCKF_READ, &pDCLock);
    if (SUCCEEDED(hr))
    {
        ::BitBlt(hdcDest, nXDest, nYDest, nWidth, nHeight, pDCLock->GetDC(), nXSrc, nYSrc, SRCCOPY);
        pDCLock->Release();
    }
    return hr;
}
//
//=== Pointer validation functions
//
inline BOOL DXIsBadReadPtr( const void* pMem, UINT Size )
{
#if !defined( _DEBUG ) && defined( DXTRANS_NOROBUST )
    return false;
#else
    return ::IsBadReadPtr( pMem, Size );
#endif
}

inline BOOL DXIsBadWritePtr( void* pMem, UINT Size )
{
#if !defined( _DEBUG ) && defined( DXTRANS_NOROBUST )
    return false;
#else
    return ::IsBadWritePtr( pMem, Size );
#endif
}


inline BOOL DXIsBadInterfacePtr( const IUnknown* pUnknown )
{
#if !defined( _DEBUG ) && defined( DXTRANS_NOROBUST )
    return false;
#else
    return ( ::IsBadReadPtr( pUnknown, sizeof( *pUnknown ) ) ||
             ::IsBadCodePtr( (FARPROC)((PDWORD)pUnknown)[0] ))?
            (true):(false);
#endif
}

#define DX_IS_BAD_OPTIONAL_WRITE_PTR(p) ((p) && DXIsBadWritePtr(p, sizeof(p)))
#define DX_IS_BAD_OPTIONAL_READ_PTR(p) ((p) && DXIsBadReadPtr(p, sizeof(p)))
#define DX_IS_BAD_OPTIONAL_INTERFACE_PTR(p) ((p) && DXIsBadInterfacePtr(p))


#pragma option pop /*P_O_Pop*/
#endif /* This must be the last line in the file */

 

Page last updated on Saturday, 07 January 2006 18:14:31 +0100