/******************************Module*Header**********************************\
*
*                           *******************
*                           * D3D SAMPLE CODE *
*                           *******************
*
* Module Name: d3dhw.h
*
* Content:  D3D Global definitions and macros.
*
* Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
* Copyright (c) 1995-1999 Microsoft Corporation.  All rights Reserved.
\*****************************************************************************/

#ifdef __D3DHW
#pragma message ("FILE : "__FILE__" : Multiple inclusion")
#endif

#define __D3DHW


#ifndef __DIRECTX
#include "directx.h"
#endif

//-----------------------------------------------------------------------------
//               Known Issues in current version of the D3D driver
//-----------------------------------------------------------------------------
//
// Stencil support is not yet completed
//
// Some games may have some issues when running under a Permedia 2 since this
// hw has some limitations, namely:
//   1) Alpha blending modes available
//   2) Alpha channel interpolation is not possible
//   3) There is no mip mapping support
//   4) Texture filtering is applied only to textures being magnified
//
//  Also, the fill rules of the Delta setup unit don't follow exactly the D3D
//  fill rules, though in practice this shouldn't be a much of a problem for
//  most apps.


//-----------------------------------------------------------------------------
//                      Global enabling/disabling definitions
//-----------------------------------------------------------------------------
// Set to 1 to enable stencil buffer support in the driver
#define D3D_STENCIL         1

// Code stubs to implement a T&L driver. Since the P2 does not support this
// in hw, this symbol should always be set to zero.
#define D3DDX7_TL           0

// Code stubs to implement mip mapping, Since the P2 does not support this 
// natively in hw, this symbols should always be set to zero. Only shows
// how/where to grab DDI info to implement it.
#define D3D_MIPMAPPING      0

// This code shows how to add stateblock support into your DX7 driver. It is
// functional code, so this symbols should be set to one.
#define D3D_STATEBLOCKS     1


//-----------------------------------------------------------------------------
//                         DX6 FVF Support declarations
//-----------------------------------------------------------------------------
typedef struct _P2TEXCOORDS{
    D3DVALUE tu;
    D3DVALUE tv;
} P2TEXCOORDS, *LPP2TEXCOORDS;

typedef struct _P2COLOR {
    D3DCOLOR color;
} P2COLOR, *LPP2COLOR;

typedef struct _P2SPECULAR {
    D3DCOLOR specular;
} P2SPECULAR, *LPP2SPECULAR;

typedef struct _P2PSIZE{
    D3DVALUE psize;
} P2PSIZE, *LPP2PSIZE;

typedef struct _P2FVFOFFSETS{ 
        DWORD dwColOffset;
        DWORD dwSpcOffset;
        DWORD dwTexOffset;
        DWORD dwTexBaseOffset;
        DWORD dwStride;
} P2FVFOFFSETS , *LPP2FVFOFFSETS;

    // track appropriate pointers to fvf vertex components
__inline void __SetFVFOffsets (DWORD  *lpdwColorOffs, 
                               DWORD  *lpdwSpecularOffs, 
                               DWORD  *lpdwTexOffs, 
                               LPP2FVFOFFSETS lpP2FVFOff)
{
    if (lpP2FVFOff == NULL) {
        // Default non-FVF case , we just set up everything as for a D3DTLVERTEX
        *lpdwColorOffs    = offsetof( D3DTLVERTEX, color);
        *lpdwSpecularOffs = offsetof( D3DTLVERTEX, specular);
        *lpdwTexOffs      = offsetof( D3DTLVERTEX, tu);
    } else {
        // Use the offsets info to setup the corresponding fields
        *lpdwColorOffs    = lpP2FVFOff->dwColOffset;
        *lpdwSpecularOffs = lpP2FVFOff->dwSpcOffset;
        *lpdwTexOffs      = lpP2FVFOff->dwTexOffset;
    }
}

//Size of maximum FVF that we can get. Used for temporary storage
typedef BYTE P2FVFMAXVERTEX[ 3 * sizeof( D3DVALUE ) +    // Position coordinates
                             5 * 4                  +    // D3DFVF_XYZB5
                                 sizeof( D3DVALUE ) +    // FVF_TRANSFORMED
                             3 * sizeof( D3DVALUE ) +    // Normals
                                 sizeof( DWORD )    +    // RESERVED1
                                 sizeof( DWORD )    +    // Diffuse color
                                 sizeof( D3DCOLOR ) +    // Specular color
                                 sizeof( D3DVALUE ) +    // Point sprite size
                             4 * 8 * sizeof( D3DVALUE )  // 8 sets of 4D texture coordinates
                           ];

#define FVFTEX( lpVtx , dwOffs )     ((LPP2TEXCOORDS)((LPBYTE)(lpVtx) + dwOffs))
#define FVFCOLOR( lpVtx, dwOffs )    ((LPP2COLOR)((LPBYTE)(lpVtx) + dwOffs))
#define FVFSPEC( lpVtx, dwOffs)      ((LPP2SPECULAR)((LPBYTE)(lpVtx) + dwOffs))
#define FVFPSIZE( lpVtx, dwOffs)     ((LPP2PSIZE)((LPBYTE)(lpVtx) + dwOffs))

//-----------------------------------------------------------------------------
//                           Miscelaneous definitions
//-----------------------------------------------------------------------------

//AZN9
#ifdef SUPPORTING_MONOFLAG
#define RENDER_MONO (Flags & CTXT_HAS_MONO_ENABLED)
#else
#define RENDER_MONO 0
#endif

// Defines used in the FakeBlendNum field of the P2 D3D context in order to
// make up for missing features in the hw that can be easily simulated
#define FAKE_ALPHABLEND_ONE_ONE     1
#define FAKE_ALPHABLEND_MODULATE    2

#define NOT_HANDLED DBG_D3D((4, "    **Not Currently Handled**"));

// This is defined in the the d3dcntxt.h header, we use it to declare functions
struct _permedia_d3dcontext;
typedef struct _permedia_d3dcontext PERMEDIA_D3DCONTEXT;

//-----------------------------------------------------------------------------
//                       D3D global functions and callbacks
//-----------------------------------------------------------------------------


// Render state processing
DWORD 
__ProcessPermediaStates(PERMEDIA_D3DCONTEXT* pContext, 
                      DWORD Count,
                      LPD3DSTATE lpState, 
                      LPDWORD lpStateMirror);

void 
__HandleDirtyPermediaState(PPDev ppdev, 
                         PERMEDIA_D3DCONTEXT* pContext, 
                         LPP2FVFOFFSETS lpP2FVFOff);

void __HWPreProcessTSS(PERMEDIA_D3DCONTEXT *pContext, 
                      DWORD dwStage, 
                      DWORD dwState, 
                      DWORD dwValue);

// Texture functions
void 
EnableTexturePermedia(PERMEDIA_D3DCONTEXT* pContext);

void 
DisableTexturePermedia(PERMEDIA_D3DCONTEXT* pContext);

void 
P2LUTDownload(PPDev ppdev, 
              PermediaSurfaceData* pPrivateDest, 
              PERMEDIA_D3DCONTEXT* pContext, 
              LPDDRAWI_DDRAWSURFACE_LCL pTexture);

// Chip specific
BOOL 
SetupDefaultsPermediaContext(PERMEDIA_D3DCONTEXT* pContext);

void 
CleanDirect3DContext(PERMEDIA_D3DCONTEXT* pContext, ULONG_PTR dwhContext);

HRESULT 
InitPermediaContext(PERMEDIA_D3DCONTEXT* Context);

void 
SetupCommonContext(PERMEDIA_D3DCONTEXT* pContext);

void 
__PermediaDisableUnits(PERMEDIA_D3DCONTEXT* pContext);

void 
DisableAllUnits(PPDev ppdev);

void __DeleteAllStateSets(PERMEDIA_D3DCONTEXT* pContext);

// Hardware primitive setup functions
void 
P2_Draw_FVF_Line(PERMEDIA_D3DCONTEXT *pContext, 
                 LPD3DTLVERTEX lpV0, 
                 LPD3DTLVERTEX lpV1,
                 LPD3DTLVERTEX lpVFlat, 
                 LPP2FVFOFFSETS lpFVFOff);

void 
P2_Draw_FVF_Point(PERMEDIA_D3DCONTEXT *pContext, 
                  LPD3DTLVERTEX lpV0, 
                  LPP2FVFOFFSETS lpFVFOff);

void 
P2_Draw_FVF_Point_Sprite(PERMEDIA_D3DCONTEXT *pContext, 
                         LPD3DTLVERTEX lpV0, 
                         LPP2FVFOFFSETS lpFVFOff);

typedef void (D3DFVFDRAWTRIFUNC)(PERMEDIA_D3DCONTEXT *, 
                                 LPD3DTLVERTEX, 
                                 LPD3DTLVERTEX,
                                 LPD3DTLVERTEX, 
                                 LPP2FVFOFFSETS);

typedef D3DFVFDRAWTRIFUNC *D3DFVFDRAWTRIFUNCPTR;

typedef void (D3DFVFDRAWPNTFUNC)(PERMEDIA_D3DCONTEXT *, 
                                 LPD3DTLVERTEX, 
                                 LPP2FVFOFFSETS);

typedef D3DFVFDRAWPNTFUNC *D3DFVFDRAWPNTFUNCPTR;

D3DFVFDRAWPNTFUNCPTR __HWSetPointFunc(PERMEDIA_D3DCONTEXT *pContext,
                                       LPP2FVFOFFSETS lpP2FVFOff);

D3DFVFDRAWTRIFUNC P2_Draw_FVF_Solid_Tri;
D3DFVFDRAWTRIFUNC P2_Draw_FVF_Wire_Tri;
D3DFVFDRAWTRIFUNC P2_Draw_FVF_Point_Tri;

// Driver callbacks
void CALLBACK 
D3DHALCreateDriver(PPDev ppdev, 
                   LPD3DHAL_GLOBALDRIVERDATA* lpD3DGlobalDriverData,
                   LPD3DHAL_CALLBACKS* lpD3DHALCallbacks,
                   LPDDHAL_D3DBUFCALLBACKS* lpDDExeBufCallbacks);

DWORD CALLBACK 
D3DValidateTextureStageState( LPD3DHAL_VALIDATETEXTURESTAGESTATEDATA lpvtssd );

DWORD CALLBACK 
D3DDrawPrimitives2( LPD3DNTHAL_DRAWPRIMITIVES2DATA pd );

DWORD CALLBACK 
D3DGetDriverState( LPDDHAL_GETDRIVERSTATEDATA);

DWORD CALLBACK 
D3DCreateSurfaceEx( LPDDHAL_CREATESURFACEEXDATA);

DWORD CALLBACK 
D3DDestroyDDLocal( LPDDHAL_DESTROYDDLOCALDATA);

DWORD CALLBACK 
DdSetColorKey(LPDDHAL_SETCOLORKEYDATA psckd);

//-----------------------------------------------------------------------------
//                    Conversion, math and culling macros
//-----------------------------------------------------------------------------
/*
 * This loses one bit of accuracy, but adds and clamps without ifs.
 * We first mask all channels with 0xfe.  This leaves the lsb of
 * each channel clear, so when the terms are added, any carry goes
 * into the new highest bit.  Now all we have to do is generate a
 * mask for any channels that have overflowed.  So we shift right
 * and eliminate everything but the overflow bits, so each channel
 * contains either 0x00 or 0x01.  Subtracting each channel from 0x80
 * produces 0x7f or 0x80.  We just shift this left once and mask to
 * give 0xfe or 0x00.  (We could eliminate the final mask here, but
 * it would introduce noise into the low-bit of every channel..)
 */
#define CLAMP8888(result, color, specular) \
     result = (color & 0xfefefefe) + (specular & 0xfefefe); \
     result |= ((0x808080 - ((result >> 8) & 0x010101)) & 0x7f7f7f) << 1;

#define RGB256_TO_LUMA(r,g,b) (float)(((float)r * 0.001172549019608) + \
                                      ((float)g * 0.002301960784314) + \
                                      ((float)b * 0.000447058823529));

#define LONG_AT(flt) (*(long *)(&flt))
#define ULONG_AT(flt) (*(unsigned long *)(&flt))

//Triangle culling macro
#define CULL_TRI(pCtxt,p0,p1,p2)                                         \
    ((pCtxt->CullMode != D3DCULL_NONE) &&                                \
     (((p1->sx - p0->sx)*(p2->sy - p0->sy) <=                            \
       (p2->sx - p0->sx)*(p1->sy - p0->sy)) ?                            \
      (pCtxt->CullMode == D3DCULL_CCW)     :                             \
      (pCtxt->CullMode == D3DCULL_CW) ) )

ULONG inline RGB888ToHWFmt(ULONG dwRGB888Color, ULONG ColorMask, ULONG RGB888Mask)
{
    unsigned long m;
    int s = 0;

    if (ColorMask)
        for (s = 0, m = ColorMask; !(m & RGB888Mask);  s++)
            m <<= 1;

    return ((dwRGB888Color >> s) & ColorMask);
}

//-----------------------------------------------------------------------------
//                              State Set overrides
//-----------------------------------------------------------------------------

#define IS_OVERRIDE(type)       ((DWORD)(type) > D3DSTATE_OVERRIDE_BIAS)
#define GET_OVERRIDE(type)      ((DWORD)(type) - D3DSTATE_OVERRIDE_BIAS)

#define MAX_STATE       D3DSTATE_OVERRIDE_BIAS
#define DWORD_BITS      32
#define DWORD_SHIFT     5

#define VALID_STATE(type)       ((DWORD)(type) < 2*D3DSTATE_OVERRIDE_BIAS)

typedef struct _D3DStateSet {
    DWORD               bits[MAX_STATE >> DWORD_SHIFT];
} D3DStateSet;

#define STATESET_MASK(set, state)       \
        (set).bits[((state) - 1) >> DWORD_SHIFT]

#define STATESET_BIT(state)     (1 << (((state) - 1) & (DWORD_BITS - 1)))

#define STATESET_ISSET(set, state) \
        STATESET_MASK(set, state) & STATESET_BIT(state)

#define STATESET_SET(set, state) \
        STATESET_MASK(set, state) |= STATESET_BIT(state)

#define STATESET_CLEAR(set, state) \
        STATESET_MASK(set, state) &= ~STATESET_BIT(state)

#define STATESET_INIT(set)      memset(&(set), 0, sizeof(set))


//-----------------------------------------------------------------------------
//  One special legacy texture op we can;t easily map into the new texture ops
//-----------------------------------------------------------------------------
#define D3DTOP_LEGACY_ALPHAOVR (0x7fffffff)

// Temporary data structure we are using here until d3dnthal.h gets updated AZN
typedef struct {
    DWORD       dwOperation;
    DWORD       dwParam; 
    DWORD       dwReserved;
} P2D3DHAL_DP2STATESET;


