//----------------------------------------------------------------------------
//
// d3dif.hpp
//
// D3D front-end/rasterizer interface header.
//
// Copyright (C) Microsoft Corporation, 1997.
//
//----------------------------------------------------------------------------

#ifndef _D3DIF_HPP_
#define _D3DIF_HPP_

#include <setup.hpp>

// For Primitive function prototypes.
#include <pmfns_mh.h>

// Vertex data is aligned on 32-byte boundaries.
#define DP_VTX_ALIGN 32

// Flags for uflags of D3DContex
#define D3DCONTEXT_IN_BEGIN             0x0001
#define D3DCONTEXT_TEXTURE_LOCKED       0x0002
#define D3DCONTEXT_APPHACK_MSGOLF       0x0004

// Flags for D3DDEVICEDESC dwDeviceZBufferBitDepth
// Note: This must be replicated in ddraw\ddd3dapi.h so DDHEL can pick them up
//       It only affect what legacy apps see when using GetCaps or EnumDevices,
//       internally ZBufferFormats() is checked when on ZBuffer creation.
//       Note stencil formats should have no representation in this flag word
//       becase legacy apps will be fooled into trying to create a Z-only surface
//       at the DDBD bitdepth and fail.   New apps should ignore dwDeviceZBufferBitDepth
//       and use EnumZBufferFormats

#define D3DSWRASTERIZER_ZBUFFERBITDEPTHFLAGS (DDBD_16)

// Macros used to access DDRAW surface info.
#define DDSurf_Width(lpLcl) ( (lpLcl)->lpGbl->wWidth )
#define DDSurf_Pitch(lpLcl) ( (lpLcl)->lpGbl->lPitch )
#define DDSurf_Height(lpLcl) ( (lpLcl)->lpGbl->wHeight )
#define DDSurf_BitDepth(lpLcl) \
    ( (lpLcl->dwFlags & DDRAWISURF_HASPIXELFORMAT) ? \
      (lpLcl->lpGbl->ddpfSurface.dwRGBBitCount) : \
      (lpLcl->lpGbl->lpDD->vmiData.ddpfDisplay.dwRGBBitCount) \
    )
#define DDSurf_PixFmt(lpLcl) \
    ( ((lpLcl)->dwFlags & DDRAWISURF_HASPIXELFORMAT) ? \
      ((lpLcl)->lpGbl->ddpfSurface) : \
      ((lpLcl)->lpGbl->lpDD->vmiData.ddpfDisplay) \
    )
#define VIDEO_MEMORY(pDDS) \
    (!(((LPDDRAWI_DDRAWSURFACE_INT) (pDDS))->lpLcl->lpGbl->dwGlobalFlags & \
    DDRAWISURFGBL_SYSMEMREQUESTED))
#define SURFACE_LOCKED(pDDS) \
    (((LPDDRAWI_DDRAWSURFACE_INT)(pDDS))->lpLcl->lpGbl->dwUsageCount > 0)

// Macro to retrieve SPANTEX pointer
#define HANDLE_TO_SPANTEX(hTex) \
    (*(PD3DI_SPANTEX *)ULongToPtr(hTex))

// Check the return value and return if something wrong.
// Assume hr has been declared
#define HR_RET(exp)                                                           \
{                                                                             \
    hr = (exp);                                                               \
    if (hr != D3D_OK)                                                           \
    {                                                                         \
        return hr;                                                            \
    }                                                                         \
}

// Triangle/Line/Point function
typedef HRESULT (*PFN_TRIANGLE)(LPVOID pCtx, PUINT8 pV0, PUINT8 pV1,
                                PUINT8 pV2,
                                WORD wFlags =
                                  D3DTRIFLAG_EDGEENABLE1 |
                                  D3DTRIFLAG_EDGEENABLE2 |
                                  D3DTRIFLAG_EDGEENABLE3 );
typedef HRESULT (*PFN_POINT)(LPVOID pCtx, PUINT8 pV0);
typedef HRESULT (*PFN_LINE)(LPVOID pCtx, PUINT8 pV0, PUINT8 pV1);
typedef void (*PFN_STORELASTPIXELSTATE)(LPVOID pCtx, BOOL bStore);
typedef HRESULT (*PFN_DP2SETRENDERSTATES)(LPVOID pCtx,
                                        DWORD dwFvf,
                                        LPD3DHAL_DP2COMMAND pCmd,
                                        LPDWORD lpdwRuntimeRStates);
typedef HRESULT (*PFN_DP2TEXTURESTAGESTATE)(LPVOID pCtx,
                                            DWORD dwFvf,
                                            LPD3DHAL_DP2COMMAND pCmd);

typedef HRESULT (*PFN_DP2SETVIEWPORT)(LPVOID pCtx, LPD3DHAL_DP2COMMAND pCmd);
typedef HRESULT (*PFN_DP2SETWRANGE)(LPVOID pCtx, LPD3DHAL_DP2COMMAND pCmd);

typedef struct _PRIMITIVE_FUNTIONS
{
    PFN_TRIANGLE pfnTri;
    PFN_POINT pfnPoint;
    PFN_LINE pfnLine;
    PFN_STORELASTPIXELSTATE pfnStoreLastPixelState;
    PFN_DP2SETRENDERSTATES pfnDp2SetRenderStates;
    PFN_DP2TEXTURESTAGESTATE pfnDp2TextureStageState;
    PFN_DP2SETVIEWPORT pfnDp2SetViewport;
    PFN_DP2SETWRANGE pfnDp2SetWRange;
}PRIMITIVE_FUNTIONS;

typedef enum _SW_RAST_TYPE
{
    SW_RAST_REFNULL = 1,
    SW_RAST_RGB = 2,
    SW_RAST_MMX = 3,
    SW_RAST_MMXASRGB = 4,
}SW_RAST_TYPE;

// Records the stride and the member offsets of the current FVF vertex type
// Used to pack a FVF vertex into one known by the rasterizer, such as
// RAST_GENERIC_VERTEX
typedef struct _FVFDATA
{
    // 0 means no according field
    INT16 offsetRHW;
    INT16 offsetDiff;
    INT16 offsetSpec;
    INT16 offsetTex[D3DHAL_TSS_MAXSTAGES];

    UINT16 stride;

    RAST_VERTEX_TYPE vtxType;

    DWORD preFVF;
    INT TexIdx[D3DHAL_TSS_MAXSTAGES];
    UINT cActTex;
}FVFDATA;

// Class used for the context returned to D3DIM.
class D3DContext
{
public:
    D3DI_RASTCTX m_RastCtx;

    // InBegin and TextureLockd flags
    // TextureLockd bit is set/cleared by texture Lock/Unlock functions.
    // It is used by texture Lock/Unlock and Begin functions.
    // InBegin bit is set by Begin and cleared by End
    unsigned short m_uFlags;

    // This is init'ed according to the fill mode.
    // It is init'ed after state change and before rendering
    PRIMITIVE_FUNTIONS m_fnPrims;

    // Used to store the old last pixel setting when drawing line strips.
    UINT uOldFlags;

    inline BOOL IsTextureOff(void);

    inline void UpdatePrimFunctionTbl(void);    // Init m_pfnTri
    inline BOOL IsAnyStatesChanged(void);
    inline BOOL IsStateChanged(UINT32 uState);
    inline void StateChanged(UINT32 uState);
    inline void SetAllStatesDirtyBits(void);
    inline void ClearAllStatesDirtyBits(void);
    inline void ClearStateDirtyBit(UINT32 uState);

    // FVF stuff
    FVFDATA m_fvfData;


#if DBG
    inline HRESULT ValidatePrimType(D3DPRIMITIVETYPE PrimitiveType);
#endif

    PrimProcessor m_PrimProc;

    UINT32 dwSize;

    D3DContext(void){};
    ~D3DContext(void){};

    HRESULT Initialize(LPDIRECTDRAWSURFACE pDDS,
        LPDIRECTDRAWSURFACE pDDSZ, DWORD BeadSet, DWORD devVer);
    HRESULT FillContext(LPDIRECTDRAWSURFACE pDDS, LPDIRECTDRAWSURFACE pDDSZ);
    HRESULT SetViewport(LPD3DHAL_DP2VIEWPORTINFO pVpt);
    HRESULT TextureSetState(PD3DI_SPANTEX pSpanTex, DWORD dwState, DWORD dwValue);
    HRESULT ValidateTextureStageState(void);
    HRESULT UpdateActiveTexStageCount(void);

    inline PD3DI_RASTCTX GetRastCtx(void){return &m_RastCtx;};

    HRESULT Begin(void);
    inline HRESULT End(BOOL bNotFlush = TRUE);
    inline void BeginPrimSet(D3DPRIMITIVETYPE PrimType, RAST_VERTEX_TYPE VertType)
        {m_PrimProc.BeginPrimSet(PrimType, VertType);};
    inline void StoreLastPixelState(BOOL bStore);
    inline PRIMITIVE_FUNTIONS *GetFunsTbl(void){return &m_fnPrims;};

    void RastUnlockSpanTexture(void);
    HRESULT RastLockSpanTexture(void);
    void UpdateColorKeyAndPalette(void);
    void RemoveTexture(PD3DI_SPANTEX pSpanTex);
    HRESULT InitSpanTexture(PD3DI_SPANTEX pSpanTex, LPDIRECTDRAWSURFACE pDDS);
    HRESULT SetSizesSpanTexture(PD3DI_SPANTEX pSpanTex);

    HRESULT SetRenderState(UINT32 uState, UINT32 uStateVal);
    HRESULT UpdateRenderStates(LPDWORD puStateChange, UINT cStateChanges);
    HRESULT UpdateAllRenderStates(LPDWORD puStates);
    HRESULT SetTextureStageState(DWORD dwStage, DWORD dwState, DWORD uStateVal);
    HRESULT Dp2SetRenderStates(LPD3DHAL_DP2COMMAND pCmd, LPDWORD lpdwRuntimeRStates);
    HRESULT Dp2TextureStageState(LPD3DHAL_DP2COMMAND pCmd, DWORD dwFvf);
    void MapTextureStageState( DWORD dwStage );
    void MapLegacyTextureBlend( void );
    void MapLegacyTextureFilter( void );

    inline HRESULT CheckDrawOnePrimitive(
        LPD3DHAL_DRAWONEPRIMITIVEDATA pOnePrimData);
    inline HRESULT CheckDrawOneIndexedPrimitive(
        LPD3DHAL_DRAWONEINDEXEDPRIMITIVEDATA pOneIdxPrimData);
    inline HRESULT DrawOnePrimitive(PUINT8 pVtx,
                 D3DPRIMITIVETYPE PrimType,
                 UINT cVertices);
    inline HRESULT DrawOneIndexedPrimitive(PUINT8 pVtx,
                 LPWORD puIndices,
                 D3DPRIMITIVETYPE PrimType,
                 UINT cIndices);

    // Check if a triangle is culled or not. It's only used for wireframe and
    // point mode. It's done in PrimProc.Tri for solid mode.
    inline BOOL NotCulled(LPD3DTLVERTEX pV0, LPD3DTLVERTEX pV1,
                                             LPD3DTLVERTEX pV2);

    // FVF stuff
    HRESULT FASTCALL CheckFVF(DWORD dwFVF);
    void FASTCALL PackGenVertex(PUINT8 pFvfVtx, RAST_GENERIC_VERTEX *pGenVtx);
    inline UINT16 GetFvfStride(void){return m_fvfData.stride;};
    inline RAST_VERTEX_TYPE GetFvfVertexType(void){return m_fvfData.vtxType;};

    inline void BeginSceneHook(void);
    inline void EndSceneHook(void);
};

inline void D3DContext::StoreLastPixelState(BOOL bStore)
{
    if (bStore)
    {
        uOldFlags = m_PrimProc.GetFlags();
        m_PrimProc.ClrFlags(PPF_DRAW_LAST_LINE_PIXEL);
    }
    else
    {
        m_PrimProc.SetFlags(uOldFlags & PPF_DRAW_LAST_LINE_PIXEL);
    }
}

inline BOOL D3DContext::NotCulled(LPD3DTLVERTEX pV0,
              LPD3DTLVERTEX pV1, LPD3DTLVERTEX pV2)
{
    if (m_RastCtx.pdwRenderState[D3DRENDERSTATE_CULLMODE] == D3DCULL_NONE)
    {
        return TRUE;
    }

    FLOAT x1, y1, x2x1, x3x1, y2y1, y3y1, fDet;

    x1 = pV0->sx;
    y1 = pV0->sy;
    x2x1 = pV1->sx - x1;
    y2y1 = pV1->sy - y1;
    x3x1 = pV2->sx - x1;
    y3y1 = pV2->sy - y1;

    fDet = x2x1 * y3y1 - x3x1 * y2y1;

    if (0. == fDet)
    {
        return FALSE;
    }
    switch ( m_RastCtx.pdwRenderState[D3DRENDERSTATE_CULLMODE] )
    {
    case D3DCULL_CW:
        if ( fDet > 0.f )
        {
            return FALSE;
        }
        break;
    case D3DCULL_CCW:
        if ( fDet < 0.f )
        {
            return FALSE;
        }
        break;
    }
    return TRUE;
}
// Update m_pfnPrims according to the current fill mode, device type
// and vertextype. It's called when fill mode or FVF type chang.
inline void D3DContext::UpdatePrimFunctionTbl(void)
{
    if (m_fvfData.vtxType == RAST_GENVERTEX)
    {
        m_fnPrims.pfnPoint = RGB_PointPack;
        m_fnPrims.pfnLine = RGB_LinePack;
    }
    else
    {
        m_fnPrims.pfnPoint = RGB_PointNoPack;
        m_fnPrims.pfnLine = RGB_LineNoPack;
    }
    switch (m_RastCtx.pdwRenderState[D3DRENDERSTATE_FILLMODE])
    {
    case D3DFILL_POINT:
        if (m_fvfData.vtxType == RAST_GENVERTEX)
        {
            m_fnPrims.pfnTri = RGB_TriPackPoint;
        }
        else
        {
            m_fnPrims.pfnTri = RGB_TriNoPackPoint;
        }
        break;
    case D3DFILL_WIREFRAME:
        if (m_fvfData.vtxType == RAST_GENVERTEX)
        {
            m_fnPrims.pfnTri = RGB_TriPackWireframe;
        }
        else
        {
            m_fnPrims.pfnTri = RGB_TriNoPackWireframe;
        }
        break;
        break;
    case D3DFILL_SOLID:
    default:
        if (m_fvfData.vtxType == RAST_GENVERTEX)
        {
            m_fnPrims.pfnTri = RGB_TriPackSolid;
        }
        else
        {
            m_fnPrims.pfnTri = RGB_TriNoPackSolid;
        }
        break;
    }
}

// The following inline functions are provided to manipulate StatesDirtyBits.
// StatesDirtyBits is used to store one dirty bit for each render state. It
// contains (D3DHAL_MAX_RSTATES_AND_STAGES>>3+1) bytes.
// For a particular state, say uState,
// it is represented by i'th bit of j'th byte, where i=(uState & 7) and
// j=uState>>3. So,
// StatesDirtyBits[uState>>3]&(1<<(uState&7)) gives the bit info. for uState
// StatesDirtyBits[uState>>3] |= (1<<(uState&7)) sets the bit to 1
// StatesDirtyBits[uState>>3] &= ~(1 <<(uState&7)) clears the bit to 0

// Check if any render states have changed. The info. is stored in the bit
// corresponding to D3DHAL_MAX_RSTATES_AND_STAGES.
inline BOOL D3DContext::IsAnyStatesChanged()
{
    return (m_RastCtx.StatesDirtyBits[D3DHAL_MAX_RSTATES_AND_STAGES>>3] &
        (1<<(D3DHAL_MAX_RSTATES_AND_STAGES & 7)));
}
// Check if uState has changed.
inline BOOL D3DContext::IsStateChanged(UINT32 uState)
{
    return (m_RastCtx.StatesDirtyBits[uState>>3] & (1<<(uState & 7)));
};

// uState has changed so set the according dirty bit and the AnyStates bit.
inline void D3DContext::StateChanged(UINT32 uState)
{
    m_RastCtx.StatesDirtyBits[uState>>3] |= (1<<(uState & 7));
    m_RastCtx.StatesDirtyBits[D3DHAL_MAX_RSTATES_AND_STAGES>>3] |=
        (1<<(D3DHAL_MAX_RSTATES_AND_STAGES & 7));
};

// Called after bead chooser to clear all the dirty bits.
inline void D3DContext::ClearAllStatesDirtyBits(void)
{
    memset(m_RastCtx.StatesDirtyBits, 0, sizeof(UINT8) * RAST_DIRTYBITS_SIZE);
};

// Called at context creation time to set all the dirty bits.
inline void D3DContext::SetAllStatesDirtyBits(void)
{
    memset(m_RastCtx.StatesDirtyBits, 7, sizeof(UINT8) * RAST_DIRTYBITS_SIZE);
};

// Clear the dirty bit corresponding to uState.
inline void D3DContext::ClearStateDirtyBit(UINT32 uState)
{
    m_RastCtx.StatesDirtyBits[uState>>3] &= ~(1 << (uState & 7));
}
inline BOOL D3DContext::IsTextureOff(void)
{
    return
        (m_RastCtx.cActTex == 0 ||
        (m_RastCtx.cActTex == 1 && m_RastCtx.pTexture[0] == NULL) ||
        (m_RastCtx.cActTex == 2 &&
         (m_RastCtx.pTexture[0] == NULL ||
          m_RastCtx.pTexture[1] == NULL)));
}
extern "C" HRESULT WINAPI
DDInternalLock( LPDDRAWI_DDRAWSURFACE_LCL this_lcl, LPVOID* lpBits );
extern "C" HRESULT WINAPI
DDInternalUnlock( LPDDRAWI_DDRAWSURFACE_LCL this_lcl );

// Lock surfaces before rendering
inline HRESULT LockSurface(LPDIRECTDRAWSURFACE pDDS, LPVOID *ppData)
{
    if (pDDS)
    {
        if (!VIDEO_MEMORY(pDDS))
        {
            if (SURFACE_LOCKED(pDDS))
            return DDERR_SURFACEBUSY;
            *ppData = (LPVOID)SURFACE_MEMORY(pDDS);
            return DD_OK;
        }
        else
        {
            HRESULT ddrval;
            do
            {
                LPDDRAWI_DDRAWSURFACE_INT lpInt;

                lpInt = (LPDDRAWI_DDRAWSURFACE_INT) pDDS;
                ddrval = DDInternalLock(lpInt->lpLcl, ppData);
            } while (ddrval == DDERR_WASSTILLDRAWING);
            return ddrval;
        }
    }
    return DD_OK;
}
// Unlock surfaces after rendering
inline void UnlockSurface(LPDIRECTDRAWSURFACE pDDS)
{
    if (pDDS && VIDEO_MEMORY(pDDS))
    {
        LPDDRAWI_DDRAWSURFACE_INT lpInt;

        lpInt = (LPDDRAWI_DDRAWSURFACE_INT) pDDS;
        DDInternalUnlock(lpInt->lpLcl);
    }
}
// After rendering cleanup: flush primitive processor, unlock textures
inline HRESULT
D3DContext::End(BOOL bNotFlush)
{
    if (m_uFlags & D3DCONTEXT_IN_BEGIN)
    {
        HRESULT hr = m_PrimProc.End();

        // Unlock texture if this is not called in the middle of drawPrims to
        // flush for possible state changes. In the 2nd case, let
        // SetRenderState to handle it.
        if (bNotFlush)
        {
            RastUnlockSpanTexture();
        }

        // Unlock surfaces
        UnlockSurface(m_RastCtx.pDDS);
        if (m_RastCtx.pDDSZ != NULL)
        {
            UnlockSurface(m_RastCtx.pDDSZ);
        }

        m_uFlags &= ~D3DCONTEXT_IN_BEGIN;
        return (hr);
    }
    else
    {
        // In the case of DrawPrims being called just to set render states,
        // Begin is actually not called.
        return D3D_OK;
    }
}

// Following primitive functions are shared by RGB/REF rasterizers
HRESULT FASTCALL
DoDrawOneIndexedPrimitive(LPVOID pCtx,
                 PRIMITIVE_FUNTIONS *pfnPrims,
                 UINT16 FvfStride,
                 PUINT8 pVtx,
                 LPWORD puIndices,
                 D3DPRIMITIVETYPE PrimType,
                 UINT cIndices);
HRESULT FASTCALL
DoDrawOnePrimitive(LPVOID pCtx,
                 PRIMITIVE_FUNTIONS *pfnPrims,
                 UINT16 FvfStride,
                 PUINT8 pVtx,
                 D3DPRIMITIVETYPE PrimType,
                 UINT cVertices);
HRESULT FASTCALL
DoDrawOneEdgeFlagTriangleFan(LPVOID pCtx,
                 PRIMITIVE_FUNTIONS *pfnPrims,
                 UINT16 FvfStride,
                 PUINT8 pVtx,
                 UINT cVertices,
                 UINT32 dwEdgeFlags);
HRESULT FASTCALL
DoRendPoints(LPVOID pCtx,
                 PRIMITIVE_FUNTIONS *pfnPrims,
                 LPD3DINSTRUCTION pIns,
                 LPD3DTLVERTEX pVtx,
                 LPD3DPOINT pPt);
HRESULT FASTCALL
DoRendLines(LPVOID pCtx,
                 PRIMITIVE_FUNTIONS *pfnPrims,
                 LPD3DINSTRUCTION pIns,
                 LPD3DTLVERTEX pVtx,
                 LPD3DLINE pLine);
HRESULT FASTCALL
DoRendTriangles(LPVOID pCtx,
                 PRIMITIVE_FUNTIONS *pfnPrims,
                 LPD3DINSTRUCTION pIns,
                 LPD3DTLVERTEX pVtx,
                 LPD3DTRIANGLE pTri);
HRESULT FASTCALL
DoDrawPrimitives2(LPVOID pCtx,
                  PRIMITIVE_FUNTIONS *pfnPrims,
                  UINT16 dwStride,
                  DWORD dwFvf,
                  PUINT8 pVtx,
                  LPD3DHAL_DP2COMMAND *ppCmd,
                  LPDWORD lpdwRStates,
                  BOOL bWireframe = FALSE
                  );


inline HRESULT
D3DContext::DrawOnePrimitive(PUINT8 pVtx,
                 D3DPRIMITIVETYPE PrimType,
                 UINT cVertices)
{
    m_PrimProc.BeginPrimSet(PrimType, m_fvfData.vtxType);
    return DoDrawOnePrimitive((LPVOID)this,
                                    &m_fnPrims,
                                    m_fvfData.stride,
                                    (PUINT8)pVtx,
                                    PrimType,
                                    cVertices);

}

inline HRESULT
D3DContext::DrawOneIndexedPrimitive(PUINT8 pVtx,
                 LPWORD puIndices,
                 D3DPRIMITIVETYPE PrimType,
                 UINT cIndices)
{
    m_PrimProc.BeginPrimSet(PrimType, m_fvfData.vtxType);
    return DoDrawOneIndexedPrimitive((LPVOID)this,
                                    &m_fnPrims,
                                    m_fvfData.stride,
                                    (PUINT8)pVtx,
                                    puIndices,
                                    PrimType,
                                    cIndices);
}

// Macros to check if a pointer is valid
#if DBG
#define VALID_D3DCONTEX_PTR(pDCtx)  ((pDCtx)->dwSize == sizeof(D3DContext))
#define VALID_D3DI_RASTCTX_PTR(pRastCtx) \
            ((pRastCtx)->dwSize == sizeof(D3DI_RASTCTX))
#define VALID_D3DI_SPANTEX_PTR(pSpanTex) \
            ((pSpanTex)->dwSize == sizeof(D3DI_SPANTEX))
#define VALID_D3DI_SPANTEX_PTR_PTR(ppSpanTex) \
            ((ppSpanTex) && VALID_D3DI_SPANTEX_PTR(*(ppSpanTex)))
// Validate context. pCtx should be declared before this macro
// Type can be D3DContext or RefRast
#define VALIDATE_CONTEXT(caller_name, data_ptr, pCtx, type)  \
{   \
    if ((data_ptr) == NULL)   \
    {   \
        D3D_INFO(0, "in %s, data pointer = NULL", (caller_name));  \
        return DDHAL_DRIVER_HANDLED;    \
    }   \
    pCtx = (type)((data_ptr)->dwhContext); \
    if (!pCtx) \
    {   \
        D3D_INFO(0, "in %s, dwhContext = NULL", (caller_name));    \
        (data_ptr)->ddrval = D3DHAL_CONTEXT_BAD;  \
        return DDHAL_DRIVER_HANDLED;    \
    }   \
}
#else // !DBG
#define VALID_D3DCONTEX_PTR(pDCtx)              1
#define VALID_D3DI_RASTCTX_PTR(pRastCtx)        1
#define VALID_D3DI_SPANTEX_PTR(pSpanTex)        1
#define VALID_D3DI_SPANTEX_PTR_PTR(ppSpanTex)   1
// Validate context. pCtx should be declared before this macro
// Type can be D3DContext or RefRast
#define VALIDATE_CONTEXT(caller_name, data_ptr, pCtx, type)  \
{   \
    pCtx = (type)((data_ptr)->dwhContext); \
}
#endif // !DBG

// Validate D3DCxt. pDCtx should be declared before this macro
#define VALIDATE_D3DCONTEXT(caller_name, data_ptr)  \
{   \
    VALIDATE_CONTEXT(caller_name, data_ptr, pDCtx, D3DContext*); \
    if (!VALID_D3DCONTEX_PTR(pDCtx) ||  \
        !VALID_D3DI_RASTCTX_PTR((pDCtx)->GetRastCtx()))    \
    {   \
        D3D_INFO(0, "in %s, invalid dwhContext", (caller_name));    \
        (data_ptr)->ddrval = D3DHAL_CONTEXT_BAD;  \
        return DDHAL_DRIVER_HANDLED;    \
    }   \
}

// Validate ReferenceRasterizer. pRefRast should be declared before this macro
#define VALIDATE_REFRAST_CONTEXT(caller_name, data_ptr)  \
{   \
    VALIDATE_CONTEXT(caller_name, data_ptr, pRefRast, ReferenceRasterizer*);\
}

#define CHECK_FVF(ret, pDCtx, dwFlags)  \
{   \
    if ((ret = pDCtx->CheckFVF(dwFlags)) != DD_OK)  \
    {   \
        return DDHAL_DRIVER_HANDLED;    \
    }   \
}

HRESULT FASTCALL
FindOutSurfFormat(LPDDPIXELFORMAT pDdPixFmt,
                  D3DI_SPANTEX_FORMAT *pFmt);

extern int
TextureFormats(LPDDSURFACEDESC* lplpddsd, DWORD dwVersion, SW_RAST_TYPE RastType);

extern int
ZBufferFormats(DDPIXELFORMAT** ppDDPF);

BOOL FASTCALL
ValidTextureSize(INT16 iuSize, INT16 iuShift,
                             INT16 ivSize, INT16 ivShift);
BOOL FASTCALL
ValidMipmapSize(INT16 iPreSize, INT16 iSize);

DWORD __stdcall
RastContextCreate(LPD3DHAL_CONTEXTCREATEDATA pCtxData, DWORD BeadSet);

DWORD __stdcall
RastContextCreate(LPD3DHAL_CONTEXTCREATEDATA pCtxData, DWORD BeadSet);

DWORD __stdcall
RastContextCreateC(LPD3DHAL_CONTEXTCREATEDATA pCtxData);

DWORD __stdcall
RastContextCreateMMX(LPD3DHAL_CONTEXTCREATEDATA pCtxData);

DWORD __stdcall
RastContextCreateMMXAsRGB(LPD3DHAL_CONTEXTCREATEDATA pCtxData);

DWORD __stdcall
RastContextDestroy(LPD3DHAL_CONTEXTDESTROYDATA pCtxDestroyData);

DWORD __stdcall
RastSetRenderTarget(LPD3DHAL_SETRENDERTARGETDATA pTgtData);

DWORD __stdcall
RastTextureCreate(LPD3DHAL_TEXTURECREATEDATA pTexData);

DWORD __stdcall
RastTextureDestroy(LPD3DHAL_TEXTUREDESTROYDATA pTexDestroyData);

DWORD __stdcall
RastTextureGetSurf(LPD3DHAL_TEXTUREGETSURFDATA pTexGetSurf);

DWORD __stdcall
RastRenderState(LPD3DHAL_RENDERSTATEDATA pStateData);

DWORD __stdcall
RastRenderPrimitive(LPD3DHAL_RENDERPRIMITIVEDATA pRenderData);

DWORD __stdcall
RastDrawOnePrimitive(LPD3DHAL_DRAWONEPRIMITIVEDATA pOnePrimData);

DWORD __stdcall
RastDrawOneIndexedPrimitive(LPD3DHAL_DRAWONEINDEXEDPRIMITIVEDATA
                            pOneIdxPrimData);

DWORD __stdcall
RastDrawPrimitives(LPD3DHAL_DRAWPRIMITIVESDATA pDrawPrimData);

DWORD __stdcall
RastValidateTextureStageState(LPD3DHAL_VALIDATETEXTURESTAGESTATEDATA pData);

DWORD __stdcall
RastDrawPrimitives2(LPD3DHAL_DRAWPRIMITIVES2DATA pDPrim2Data);

DWORD __stdcall
RefRastDrawPrimitives2(LPD3DHAL_DRAWPRIMITIVES2DATA pDPrim2Data);

#endif // #ifndef _D3DIF_HPP_