/******************************************************************************************
FILE : DoMat DirectX6
 
  Do render parameters settings for texture/material/fog
  Dispay black triangles for window smaller than screen
      
*******************************************************************************************/
 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#include <d3d.h>
 
#include "Gli_st.h"
#include "GLI_Defn.h"
#include "polygon.h"
#include "mater_st.h"
#include "light_st.h"
#include "PvObj_st.h"
#include "Liste.h"
#include "watrplan.h"
#include "proj.h"
#include "vpt3D.h"
#include "camera.h"
#include "material.h"
#include "texture.h"
#include "TEX.h"
#include "light.h"
#include "GliBench.h"
 
#include "TextuD3D.h"
#include "MacroD3D.h"
#include "DLLCom.h"
 
#include "PRF.h"
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
#ifdef __cplusplus
extern "C" 
{
#endif
#ifdef ZARMA
}
#endif
 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
/*
 =======================================================================================
    Globals, Externals
 =======================================================================================
 */
 
D3DCOLOR    xFogColor, xFogColorStart, xFogColorEnd, xFogcolorInfinite;
 
void GLI_vSetFogParams( tdstFogParams *_p_stFogParams );
HRESULT GLI_fn_hRestoreSurfaces( void );
 
extern LPDIRECT3DDEVICE3    g_pd3dDevice;
extern LPDIRECTDRAWSURFACE4 g_pddsBackBuffer;
 
/*
 * for Black triangles
 */
D3DTLVERTEX                 g_stBlackTriangle[24];
long                        g_lNumberOfBlackTriangles = 0;
 
/*
 * For fog
 */
static float                xZDepthConstant;
/* Begin G.CLEMENT 23/08/1999 : unused vars, now local to GLI_vSetFogParams */
/*static float                xFogIntensityEnd;*/
/*static float                xFogIntensityStart;*/
/* End G.CLEMENT 23/08/1999 */
static float                xZDepthStart, xZDepthStart2;
static float                xZDepthEnd;
D3DCOLOR                    xFogColor, xFogColorStart, xFogColorEnd, xFogcolorInfinite;
 
/*
 * For ZBuffer
 */
static long                 bIsWriteEnable = 1;
 
/*
 * for render
 */
static ACP_tdxIndex         xSaveFogIsOn = 0;
static unsigned char        ucSaveCyclingMode = -1;
static unsigned char        ucSaveFunction = -1;
static unsigned long        gs_ulDepthBufferTestEnabled = 0;
 
/*
 * for 32 bit back buffer
 */
extern long                 g_lFullScreenBpp;
 
/*
 =======================================================================================
    Special function for displaying black polygon
        it's for cinematic scene to hide non black background color
 =======================================================================================
 */
 
/*
 ----------------------------------------------------------------------------------------
  Description   : reinit list of black triangles
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vNoBlackPolygon()
{
    g_lNumberOfBlackTriangles = 0;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Add a black triangles to list
  Assume that list is large enough (no test)
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vAddBlackPolygon( long _lLeft, long _lTop, long _lRight, long _lBottom )
{
    D3DTLVERTEX             *p_stVertex;
    static float            fOoDepth = 0.8f/*4.0f*/;
 
    if (g_lNumberOfBlackTriangles + 6 > 24 )
        return;
 
    p_stVertex = g_stBlackTriangle + g_lNumberOfBlackTriangles;
    memset( p_stVertex, 0, 6 * sizeof( D3DTLVERTEX ) );
    g_lNumberOfBlackTriangles += 6;
 
    p_stVertex->sx   = (D3DVALUE) _lLeft;
    p_stVertex->sy   = (D3DVALUE) _lBottom;
    p_stVertex->rhw  = (D3DVALUE) fOoDepth;
 
    p_stVertex++;
    p_stVertex->sx   = (D3DVALUE) _lLeft;
    p_stVertex->sy   = (D3DVALUE) _lTop;
    p_stVertex->rhw  = (D3DVALUE) fOoDepth;

    p_stVertex++;
    p_stVertex->sx   = (D3DVALUE) _lRight;
    p_stVertex->sy   = (D3DVALUE) _lTop;
    p_stVertex->rhw  = (D3DVALUE) fOoDepth;
 
    p_stVertex++;
    p_stVertex->sx   = (D3DVALUE) _lRight;
    p_stVertex->sy   = (D3DVALUE) _lTop;
    p_stVertex->rhw  = (D3DVALUE) fOoDepth;

    p_stVertex++;
    p_stVertex->sx   = (D3DVALUE) _lRight;
    p_stVertex->sy   = (D3DVALUE) _lBottom;
    p_stVertex->rhw = (D3DVALUE) fOoDepth;
 
    p_stVertex++;
    p_stVertex->sx   = (D3DVALUE) _lLeft;
    p_stVertex->sy   = (D3DVALUE) _lBottom;
    p_stVertex->rhw  = (D3DVALUE) fOoDepth;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Draw black triangles
 ----------------------------------------------------------------------------------------
 */
void GLI_vSendBlackPolygon()
{
    if (g_lNumberOfBlackTriangles == 0)
        return;
 
    g_pd3dDevice->lpVtbl->SetTexture(g_pd3dDevice,0, NULL );
    g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_FOGENABLE,FALSE);
    xSaveFogIsOn = 0;
/* 
    g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
    if( FAILED( g_pd3dDevice->lpVtbl->BeginScene(g_pd3dDevice) ) )
            return;
*/
       
    /* Draw the triangles*/
    g_pd3dDevice->lpVtbl->DrawPrimitive( g_pd3dDevice, D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX, g_stBlackTriangle, g_lNumberOfBlackTriangles, D3DDP_DONOTCLIP | D3DDP_DONOTLIGHT );
 
/*
    /* End the scene./
    g_pd3dDevice->lpVtbl->EndScene(g_pd3dDevice);
*/
}
 
/*
 =======================================================================================
    FOG 
 =======================================================================================
 */
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : set render for fog parameters
 ----------------------------------------------------------------------------------------
 */
/* Begin G.CLEMENT 23/08/1999 : modified computation of xZDepthStart2,
								turned global vars xFogIntensityStart/End into local ones */
void GLI_vSetFogParams( tdstFogParams *_p_stFogParams )
{
/*
    xZDepthStart        = _p_stFogParams->xDepthStart;
    xZDepthEnd          = _p_stFogParams->xDepthEnd;
 
    xFogIntensityStart  = _p_stFogParams->xBlendStart / 255.0f;
    xFogIntensityEnd    = _p_stFogParams->xBlendEnd / 255.0f;
  
    xZDepthConstant = _p_stFogParams->xDepthEnd - _p_stFogParams->xDepthStart;
    if ( xZDepthConstant )
        xZDepthConstant = ( xFogIntensityEnd - xFogIntensityStart) / xZDepthConstant;
 
    xZDepthStart2 = 1.0f / (256.0f * xZDepthConstant) + xZDepthStart;

    if (_p_stFogParams->stColor.xR < 0.0f)
        _p_stFogParams->stColor.xR = 0.0f;
    else if (_p_stFogParams->stColor.xR > 1.0f)
        _p_stFogParams->stColor.xR = 1.0f;
 
    if (_p_stFogParams->stColor.xG < 0.0f)
        _p_stFogParams->stColor.xG = 0.0f;
    else if (_p_stFogParams->stColor.xG > 1.0f)
        _p_stFogParams->stColor.xG = 1.0f;
 
    if (_p_stFogParams->stColor.xB < 0.0f)
        _p_stFogParams->stColor.xB = 0.0f;
    else if (_p_stFogParams->stColor.xB > 1.0f)
        _p_stFogParams->stColor.xB = 1.0f;
 
    xFogColor = D3DRGBA( _p_stFogParams->stColor.xR, _p_stFogParams->stColor.xG, _p_stFogParams->stColor.xB, 0 );
    xFogColorStart = D3DRGBA( 0, 0, 0, 1.f - xFogIntensityStart );
    xFogColorEnd = D3DRGBA( 0, 0, 0, 1.f - xFogIntensityEnd );
*/

    float xFogIntensityStart  = _p_stFogParams->xBlendStart / 255.0f;
    float xFogIntensityEnd    = _p_stFogParams->xBlendEnd / 255.0f;

	xZDepthStart        = _p_stFogParams->xDepthStart;
    xZDepthEnd          = _p_stFogParams->xDepthEnd;
 
    xZDepthConstant = xZDepthEnd - xZDepthStart;
    if ( xZDepthConstant )
	{
        xZDepthConstant = ( xFogIntensityEnd - xFogIntensityStart) / xZDepthConstant;
		if (xFogIntensityStart == 0)
			xZDepthStart2 = xZDepthStart; /* More accurate than actual computation */
		else
			xZDepthStart2 = (xFogIntensityEnd * xZDepthStart - xFogIntensityStart * xZDepthEnd) / (xFogIntensityEnd - xFogIntensityStart);
	} else {
		xZDepthStart2 = xZDepthConstant = 0;
	}
 
    /* xZDepthStart2 = 1.0f / (256.0f * xZDepthConstant) + xZDepthStart; /* was wrong */

    if (_p_stFogParams->stColor.xR < 0.0f)
        _p_stFogParams->stColor.xR = 0.0f;
    else if (_p_stFogParams->stColor.xR > 1.0f)
        _p_stFogParams->stColor.xR = 1.0f;
 
    if (_p_stFogParams->stColor.xG < 0.0f)
        _p_stFogParams->stColor.xG = 0.0f;
    else if (_p_stFogParams->stColor.xG > 1.0f)
        _p_stFogParams->stColor.xG = 1.0f;
 
    if (_p_stFogParams->stColor.xB < 0.0f)
        _p_stFogParams->stColor.xB = 0.0f;
    else if (_p_stFogParams->stColor.xB > 1.0f)
        _p_stFogParams->stColor.xB = 1.0f;
 
    xFogColor = D3DRGBA( _p_stFogParams->stColor.xR, _p_stFogParams->stColor.xG, _p_stFogParams->stColor.xB, 0 );
    xFogColorStart = D3DRGBA( 0, 0, 0, 1.0f - xFogIntensityStart);
    xFogColorEnd = D3DRGBA( 0, 0, 0, 1.0f - xFogIntensityEnd);
/* End G.CLEMENT 23/08/1999 */
    
 
    g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice, D3DRENDERSTATE_FOGCOLOR, xFogColor);
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : compute vertex color to render fog
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vComputeFogEffect(GLI_tdstInternalGlobalValuesFor3dEngine *p_stBG )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    GLI_tdstAligned3DVector *p_stVertex, *p_stLastVertex;
    D3DCOLOR                *p_xColor;
    unsigned long           ulAlpha;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    if ( !GLI_BIG_GLOBALS->xFogIsOn )
        return;
 
    if ( GLI_BIG_GLOBALS->p_stLastComputedFog != GLI_BIG_GLOBALS->p_stActiveFog )
    {
        GLI_vSetFogParams( GLI_BIG_GLOBALS->p_stActiveFog );
        GLI_BIG_GLOBALS->p_stLastComputedFog = GLI_BIG_GLOBALS->p_stActiveFog;
    }
    
    p_stVertex = p_stBG->GLI_TurnedScaledDisplecedPoint;
    p_stLastVertex = p_stVertex + p_stBG->p_stObj->xNbPoints;
    p_xColor = (D3DCOLOR *) p_stBG->GLI_aDEF_stColorsRLIS;
 
    for ( ; p_stVertex < p_stLastVertex;p_stVertex++, p_xColor++)
    {
        if (p_stVertex->xZ >= xZDepthEnd)
            *p_xColor = xFogColorEnd;
        else if ( p_stVertex->xZ <= xZDepthStart2)
            *p_xColor = 0xff000000; /* and not xFogColorStart; /* G.CLEMENT 24/08/1999 */
        else
        {
			/* Begin G.CLEMENT 24/08/1999 : added post-computation test */
            *(float *) &ulAlpha = (1.f - (p_stVertex->xZ - xZDepthStart2) * xZDepthConstant) + 32768.0f + 16384.0f; /* G.CLEMENT 23/08/1999 : changed xZDepthStart to xZDepthStart2 */
			/* Blending factor as a float is between 0 and 1, so we don't have to test the negative case.
			   We just test if it is too near 1, which would cause *p_xColor to be 0x00 */
			if (ulAlpha & 0x0000ff00)
				*p_xColor = 0xff000000;
			else
	            *p_xColor = ulAlpha << 24;
			/* End G.CLEMENT 24/08/1999 */
        }
    } 
}
 
/*
 =======================================================================================
    ZBuffer function
 =======================================================================================
 */
 
/*
 ----------------------------------------------------------------------------------------
  Description   : To enable write to ZBuffer
 ----------------------------------------------------------------------------------------
 */
static void GLI_fn_vEnableWriteToZBuffer()
{
    if (bIsWriteEnable) return;
    g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ZWRITEENABLE, TRUE );
    bIsWriteEnable = 1;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : To disable write to ZBuffer
 ----------------------------------------------------------------------------------------
 */
static void GLI_fn_vDisableWriteToZBuffer()
{
    if (!bIsWriteEnable) return;
    g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ZWRITEENABLE, FALSE );
    bIsWriteEnable = 0;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : To manage use of ZBuffer
 ----------------------------------------------------------------------------------------
 */

void GLI_DRV_vEnableDepthTest()
{
    if( gs_ulDepthBufferTestEnabled )
        return;

    g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ZFUNC, D3DCMP_GREATEREQUAL );
    gs_ulDepthBufferTestEnabled = 1;
}

void GLI_DRV_vDisableDepthTest()
{
    if( ! gs_ulDepthBufferTestEnabled )
        return;

    g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ZFUNC, D3DCMP_ALWAYS );
    gs_ulDepthBufferTestEnabled = 0;
}

/*
 =======================================================================================
    Main render parameter setting functions
 =======================================================================================
 */
 
/*
 * Write to ZBuffer
 */
#define M_vZBuffer()\
    if (p_stGlobaleMT -> lCurrentDrawMask & GLI_C_lIsWriteZBuffer)  \
        GLI_fn_vEnableWriteToZBuffer();                             \
    else                                                            \
        GLI_fn_vDisableWriteToZBuffer();                            
 
/*
 * fog
 */
#define M_vFog()\
    if (GLI_BIG_GLOBALS->xFogIsOn)                                                              \
    {                                                                                           \
        if ( GLI_BIG_GLOBALS->p_stLastComputedFog != GLI_BIG_GLOBALS->p_stActiveFog )           \
        {                                                                                       \
            GLI_vSetFogParams( GLI_BIG_GLOBALS->p_stActiveFog );                                \
            GLI_BIG_GLOBALS->p_stLastComputedFog = GLI_BIG_GLOBALS->p_stActiveFog;              \
        }                                                                                       \
        if (!xSaveFogIsOn)                                                                      \
        {                                                                                       \
            g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_FOGENABLE,TRUE); \
            xSaveFogIsOn = 1;                                                                   \
        }                                                                                       \
    }                                                                                           \
    else if (xSaveFogIsOn)                                                                      \
    {                                                                                           \
        g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_FOGENABLE,FALSE);    \
        xSaveFogIsOn = 0;                                                                       \
    }                                                                                  
 
/*
 * back face testing
 */
/*
#define M_vBackFace()\
    if (p_stGlobaleMT->lCurrentDrawMask & GLI_C_lIsTestingBackface)                                     \
        if ((p_stGlobaleMT -> lHierachDrawMask  & GLI_C_lIsNotDrawingInMirror) ?					\
			(p_stGlobaleMT -> lCurrentDrawMask & GLI_C_lNotInvertBackfaces) :						\
			!(p_stGlobaleMT -> lCurrentDrawMask & GLI_C_lNotInvertBackfaces) )						\
				g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_CULLMODE, D3DCULL_CW);   \
        else                                                                                            \
            g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_CULLMODE, D3DCULL_CCW);  \
    else                                                                                                \
        g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
*/
 
 
/*
 * Chromakey
 */
#define M_vChromakey()\
    if (p_stGlobaleMT -> p_stCurrentTexture -> lTextureCaps & GLI_C_lNZTexture)                     \
        g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_COLORKEYENABLE,TRUE);    \
    else                                                                                            \
        g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_COLORKEYENABLE,FALSE);
 
/*
 * uv cycling mode
 */

/* Begin G.CLEMENT 20/07/1999 : replacing superseded SetRenderState's with SetTextureStageState */
#define M_vUVCyclingMode()\
    if ( p_stGlobaleMT -> p_stCurrentTexture -> ucCylingMode != ucSaveCyclingMode )                                     \
    {                                                                                                                   \
        switch ( ucSaveCyclingMode = p_stGlobaleMT -> p_stCurrentTexture -> ucCylingMode )                              \
        {                                                                                                               \
            case 0:                                                                                                     \
				/* g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice ,D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_CLAMP); */ \
                /* g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_TEXTUREADDRESSU,D3DTADDRESS_CLAMP); */ \
                /* g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_TEXTUREADDRESSV,D3DTADDRESS_CLAMP); */ \
				/*g_pd3dDevice->lpVtbl->SetTextureStageState(g_pd3dDevice, 0, D3DTSS_ADDRESS, D3DTADDRESS_CLAMP); */ \
				g_pd3dDevice->lpVtbl->SetTextureStageState(g_pd3dDevice, 0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); \
				g_pd3dDevice->lpVtbl->SetTextureStageState(g_pd3dDevice, 0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP); \
                break;                                                                                                  \
            case GLI_C_lCylingU: /* Cycling V */                                                                        \
                /* g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); */   \
                /* g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_TEXTUREADDRESSU,D3DTADDRESS_CLAMP); */ \
                /* g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_TEXTUREADDRESSV,D3DTADDRESS_WRAP); */ \
				/* g_pd3dDevice->lpVtbl->SetTextureStageState(g_pd3dDevice, 0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); */ \
				g_pd3dDevice->lpVtbl->SetTextureStageState(g_pd3dDevice, 0, D3DTSS_ADDRESSU, D3DTADDRESS_CLAMP); \
				g_pd3dDevice->lpVtbl->SetTextureStageState(g_pd3dDevice, 0, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); \
                break;                                                                                                  \
           case GLI_C_lCylingV: /* Cycling U */                                                                         \
                /* g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); */   \
                /* g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_TEXTUREADDRESSU,D3DTADDRESS_WRAP); */  \
                /* g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_TEXTUREADDRESSV,D3DTADDRESS_CLAMP); */ \
				/*g_pd3dDevice->lpVtbl->SetTextureStageState(g_pd3dDevice, 0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); */\
				g_pd3dDevice->lpVtbl->SetTextureStageState(g_pd3dDevice, 0, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP);  \
				g_pd3dDevice->lpVtbl->SetTextureStageState(g_pd3dDevice, 0, D3DTSS_ADDRESSV, D3DTADDRESS_CLAMP); \
                break;                                                                                                  \
           case GLI_C_lCylingUV:                                                                                        \
                /* g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_TEXTUREADDRESS,D3DTADDRESS_WRAP); */   \
                /* g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_TEXTUREADDRESSU,D3DTADDRESS_WRAP); */  \
                /* g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_TEXTUREADDRESSV,D3DTADDRESS_WRAP); */  \
				/*g_pd3dDevice->lpVtbl->SetTextureStageState(g_pd3dDevice, 0, D3DTSS_ADDRESS, D3DTADDRESS_WRAP); */ \
				g_pd3dDevice->lpVtbl->SetTextureStageState(g_pd3dDevice, 0, D3DTSS_ADDRESSU, D3DTADDRESS_WRAP); \
				g_pd3dDevice->lpVtbl->SetTextureStageState(g_pd3dDevice, 0, D3DTSS_ADDRESSV, D3DTADDRESS_WRAP); \
                break;                                                                                                  \
        }                                                                                                               \
    }
/* End G.CLEMENT 20/07/1999 */
 
/* Begin G.CLEMENT 20/07/1999 : some macros for Texture Stage Settings */
#define GLI_M_SetTextureColorStage(dev, i, arg1, op, arg2) { \
   dev->lpVtbl->SetTextureStageState(dev, i, D3DTSS_COLOROP, op); \
   dev->lpVtbl->SetTextureStageState(dev, i, D3DTSS_COLORARG1, arg1); \
   dev->lpVtbl->SetTextureStageState(dev, i, D3DTSS_COLORARG2, arg2); \
}

#define GLI_M_SetTextureAlphaStage(dev, i, arg1, op, arg2) {\
   dev->lpVtbl->SetTextureStageState(dev, i, D3DTSS_ALPHAOP, op); \
   dev->lpVtbl->SetTextureStageState(dev, i, D3DTSS_ALPHAARG1, arg1); \
   dev->lpVtbl->SetTextureStageState(dev, i, D3DTSS_ALPHAARG2, arg2); \
}
/* End G.CLEMENT 20/07/1999 */

/*
 ----------------------------------------------------------------------------------------
  Description   : set render parameters that will work for all Opaque faces
 ----------------------------------------------------------------------------------------
 */
void GLI_fn_vSetRenderParametersBeforeOpaqueFace( void )
{
    GLI_fn_vEnableWriteToZBuffer();
 
    g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ALPHABLENDENABLE, FALSE);
	/* Begin G.CLEMENT 19/07/1999 */
	/* g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA); replaced with */
	GLI_M_SetTextureColorStage(g_pd3dDevice, 0, D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
	GLI_M_SetTextureAlphaStage(g_pd3dDevice, 0, D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE); /* For NZ-textures */
	/* End G.CLEMENT 19/07/1999 */
    g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ALPHATESTENABLE, FALSE );
    ucSaveFunction = 4;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : called before the rendering of any triangle
 ----------------------------------------------------------------------------------------
 */
BOOL GLI_DRV_bBeginScene()
{
    if( SUCCEEDED( g_pd3dDevice->lpVtbl->BeginScene(g_pd3dDevice) ) )
    {
        GLI_fn_vSetRenderParametersBeforeOpaqueFace();
        GLI_vSendBlackPolygon();
        return TRUE;
    }

    return FALSE;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : called after the rendering of all triangles
 ----------------------------------------------------------------------------------------
 */
BOOL GLI_DRV_bEndScene()
{
    return SUCCEEDED( g_pd3dDevice->lpVtbl->EndScene(g_pd3dDevice) );
}
/*
 =======================================================================================
    Special function for displaying black polygon
        it's for cinematic scene to hide non black background color
 =======================================================================================
 */
 
 /*
 ----------------------------------------------------------------------------------------
  Description   : Called for all object before drawn. 
                Set some general parameters and set render parameter for opaque texture only
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vDoOpaqueTextureSelection(GLI_tdstInternalGlobalValuesFor3dEngine *p_stGlobaleMT)
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    BOOL                    bTexture;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

    bTexture = (p_stGlobaleMT->p_stCurrentTexture != NULL) && (p_stGlobaleMT->p_stCurrentTexture->bIsAvailable);
    /*p_stGlobaleMT->xTextureDontAcceptFog = TRUE;*/
    p_stGlobaleMT->xTextureDontAcceptFog = FALSE;

  
    /*
     * test if triangle will be transparent if so do not set render parameters
     */
	if (GLI_BIG_GLOBALS->lAMirrorIsDetected)
		GLI_BIG_GLOBALS->lAMirrorIsDetected = 3;
 
    if ( 
        (!(GLI_BIG_GLOBALS->lAMirrorIsDetected) && bTexture && (p_stGlobaleMT -> p_stCurrentTexture -> lTextureCaps & (GLI_C_lAlphaTexture | GLI_C_lNZFilteredTexture | GLI_C_lAddTransparencyTexture) ) )
        || (!(p_stGlobaleMT -> lCurrentDrawMask & GLI_C_lIsNotGrided) && (p_stGlobaleMT->xGlobalAlpha < 0.98f))
        )
    {
        p_stGlobaleMT -> lClippingModeMask |= GLI_C_TrianglesMustBeSorted;
        if (bTexture && !(p_stGlobaleMT -> p_stCurrentTexture -> lTextureCaps & GLI_C_lAlphaTexture  ))
            p_stGlobaleMT->xTextureDontAcceptFog = TRUE;
        return;
    }
    
    
    p_stGlobaleMT->lClippingModeMask &= 0xffffffff - GLI_C_TrianglesMustBeSorted;
    
/* 
    if ( p_stGlobaleMT->lCurrentDrawMask & GLI_C_lIsEnableZSorting )
        g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ZFUNC, D3DCMP_GREATEREQUAL );
    else
        g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ZFUNC, D3DCMP_ALWAYS );
*/
    if ( p_stGlobaleMT->lCurrentDrawMask & GLI_C_lIsEnableZSorting )
        GLI_DRV_vEnableDepthTest();
    else
        GLI_DRV_vDisableDepthTest();
 
    M_vFog();
 
    /* GuS :  Backfaces are removed by the engine itself. */
    /*
    M_vBackFace();
    */
 
    M_vZBuffer();
    
    /*
    * mirror
    */
    if ( bTexture )
    {
        if (p_stGlobaleMT -> p_stCurrentTexture -> lTextureCaps & GLI_C_lAlphaTest)
        {
            if (ucSaveFunction != 5)
            {
				if ( ucSaveFunction == 2 )
					GLI_fn_vSetRenderParametersBeforeOpaqueFace() ;
				/* Begin Guidom */
    /*g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ALPHABLENDENABLE, FALSE ); /*
    g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ALPHAFUNC, D3DCMP_GREATEREQUAL );
	g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ALPHAREF, 0xC0 );
				/* End Guidom */
                g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ALPHATESTENABLE, TRUE );
                /*g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_ALPHABLENDENABLE,FALSE);*/
                /*g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA);*/
                ucSaveFunction = 5;
            }
		}
        else if (GLI_BIG_GLOBALS->lAMirrorIsDetected & 2)
		{
			g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ALPHATESTENABLE, FALSE );
			g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_ALPHABLENDENABLE,TRUE);
			g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA);
 
            g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA);
			/* Begin G.CLEMENT 19/07/1999 */
			/* g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA); replaced with */
			GLI_M_SetTextureColorStage(g_pd3dDevice, 0, D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
			GLI_M_SetTextureAlphaStage(g_pd3dDevice, 0, D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
			/* End G.CLEMENT 19/07/1999 */
			ucSaveFunction = 2;
		}
        else
        {
            if (ucSaveFunction != 4)
            {       
				if ( ucSaveFunction == 2 )
					GLI_fn_vSetRenderParametersBeforeOpaqueFace() ;
                g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ALPHATESTENABLE, FALSE );
                /*g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_ALPHABLENDENABLE,FALSE);*/
                /*g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA);*/
                ucSaveFunction = 4;
            }
        }
        
        M_vChromakey();
        M_vUVCyclingMode();
        
        g_pd3dDevice->lpVtbl->SetTexture(g_pd3dDevice,0, (LPDIRECT3DTEXTURE2) p_stGlobaleMT->p_stCurrentTexture->p_stSpecParam );
    } 
    else /* gouraud */
    {
        if (ucSaveFunction != 4)
        {
			if ( ucSaveFunction == 2 )
				GLI_fn_vSetRenderParametersBeforeOpaqueFace() ;				
            g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ALPHATESTENABLE, FALSE );
            /*g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_ALPHABLENDENABLE,FALSE);*/
            /*g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_MODULATEALPHA);*/
            ucSaveFunction = 4;
        }
        
        g_pd3dDevice->lpVtbl->SetTexture(g_pd3dDevice,0, NULL );
    }
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : set render parameters that will work for all transparency faces
 ----------------------------------------------------------------------------------------
 */
void GLI_fn_vSetRenderParametersBeforeTransparencyFace( void )
{
    GLI_fn_vDisableWriteToZBuffer();
    g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ALPHATESTENABLE, FALSE );
    g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_ALPHABLENDENABLE,TRUE);
    g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA);
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : set render parameters for transparent triangles
 ----------------------------------------------------------------------------------------
 */
void GLI_vDoTransparentTextureSelection(GLI_tdstInternalGlobalValuesFor3dEngine *p_stGlobaleMT)
{
/* 
    if ( p_stGlobaleMT->lCurrentDrawMask & GLI_C_lIsEnableZSorting )
        g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ZFUNC, D3DCMP_GREATEREQUAL );
    else
        g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ZFUNC, D3DCMP_ALWAYS );
*/
    if ( p_stGlobaleMT->lCurrentDrawMask & GLI_C_lIsEnableZSorting )
        GLI_DRV_vEnableDepthTest();
    else
        GLI_DRV_vDisableDepthTest();

    M_vFog();

    /* GuS :  Backfaces are removed by the engine itself. */
    /*
    M_vBackFace();
    */
    
    if ((p_stGlobaleMT -> p_stCurrentTexture != NULL) && (p_stGlobaleMT -> p_stCurrentTexture ->  bIsAvailable))
    {
        if (p_stGlobaleMT -> p_stCurrentTexture -> lTextureCaps & GLI_C_lAddTransparencyTexture)
        {
			/* Begin G.CLEMENT 02/08/1999 : Take the fog-disabling outside the 'if' statement */
			/*                              Otherwise several addtransp. textures won't work well together */
            if (ucSaveFunction != 1)
            {
                /*g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_ALPHABLENDENABLE,TRUE);*/
                /*g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA);*/
                g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE);
				/* Begin G.CLEMENT 19/07/1999 */
                /* g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_TEXTUREMAPBLEND,D3DTBLEND_COPY); replaced with */
				g_pd3dDevice->lpVtbl->SetTextureStageState(g_pd3dDevice, 0, D3DTSS_COLOROP, D3DTOP_SELECTARG1);
				g_pd3dDevice->lpVtbl->SetTextureStageState(g_pd3dDevice, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE); 
				g_pd3dDevice->lpVtbl->SetTextureStageState(g_pd3dDevice, 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG1);
				g_pd3dDevice->lpVtbl->SetTextureStageState(g_pd3dDevice, 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE);
				/* End G.CLEMENT 19/07/1999 */
	            ucSaveFunction = 1;
            }
            if (xSaveFogIsOn)
            {
                g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_FOGENABLE,FALSE);
                xSaveFogIsOn = 0;
            }
			/* End G.CLEMENT 02/08/1999 */
        } 
        else if (ucSaveFunction != 2)
        {
            /*g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_ALPHABLENDENABLE, TRUE);*/
            /*g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_SRCBLEND,D3DBLEND_SRCALPHA);*/
            g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA);
			/* Begin G.CLEMENT 19/07/1999 */
			/* g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_TEXTUREMAPBLEND, D3DTBLEND_MODULATEALPHA); replaced with */
			GLI_M_SetTextureColorStage(g_pd3dDevice, 0, D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
			GLI_M_SetTextureAlphaStage(g_pd3dDevice, 0, D3DTA_TEXTURE, D3DTOP_MODULATE, D3DTA_DIFFUSE);
			/* End G.CLEMENT 19/07/1999 */
            ucSaveFunction = 2;
        } 
        
        
        M_vChromakey();
        M_vUVCyclingMode();
        
        g_pd3dDevice->lpVtbl->SetTexture(g_pd3dDevice,0, (LPDIRECT3DTEXTURE2) p_stGlobaleMT->p_stCurrentTexture->p_stSpecParam );
    } 
    else
    {
        /* GOURAUD*/
		/* Begin G.CLEMENT 02/08/1999 : Don't forget to reset destination alpha */
		if (ucSaveFunction == 1)
			g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_DESTBLEND,D3DBLEND_INVSRCALPHA);
		/* End G.CLEMENT 02/08/1999 */
        g_pd3dDevice->lpVtbl->SetTexture(g_pd3dDevice, 0, NULL );
        ucSaveFunction = 0;
    }
}
 
/*
 =======================================================================================
    Write bitmap in backbuffer
 =======================================================================================
 */
 
/*
 ----------------------------------------------------------------------------------------
  Description   : write region of a bitmap into a region of the backbuffer
 ----------------------------------------------------------------------------------------
 */
void GLI_WriteRegionD3D(long X, long Y, long l, long h, unsigned char *p_ucSrc, long SrcPitch , LPDDSURFACEDESC2 p_ddsd )
{
    long            lXDst, lYDst;
    unsigned short  *p_uwSrc, *p_uwTgt;
    long            TgtPitch;
    
    p_uwSrc = (unsigned short *) p_ucSrc;
    p_uwTgt = (unsigned short *) ( (unsigned char *) p_ddsd->lpSurface + Y * p_ddsd->lPitch + X * 2 );
    SrcPitch = (SrcPitch >> 1) - l;
    TgtPitch = (p_ddsd->lPitch >> 1) - l;
    
    for ( lYDst = 0 ; lYDst < h ; lYDst ++ )
    {
        for ( lXDst = 0 ; lXDst < l; lXDst ++ )
            *p_uwTgt++ = *p_uwSrc++;
        
        p_uwTgt += TgtPitch;
        p_uwSrc += SrcPitch;
    }
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Write a 16 bit bitmap in the back buffer
  _p_vSourceBuffer    -> bitmap
  _lWidth, _lHeight   -> dimension of bitmap
  _lDestX, _lDestY    -> where the bitmap have to be copied in the backbuffer
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vWrite16bBitmapToBackBuffer( void *_p_vSourceBuffer, long _lWidth, long _lHeight, long _lDestLeft, long _lDestTop, long _lDestRight, long _lDestBottom )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    long            lXDst, lYDst;
    DDSURFACEDESC2  ddsd;
    unsigned short  *p_uwSrc, *p_uwTgt;
    HRESULT         hr;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    memset(&ddsd,0,sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
    hr = g_pddsBackBuffer->lpVtbl->Lock(g_pddsBackBuffer, NULL, &ddsd, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR | DDLOCK_NOSYSLOCK, NULL);
 
    if ( hr != DD_OK )
    {
        GLI_fn_hRestoreSurfaces();
        memset(&ddsd,0,sizeof(ddsd));
        ddsd.dwSize = sizeof(ddsd);
        hr = g_pddsBackBuffer->lpVtbl->Lock(g_pddsBackBuffer, NULL, &ddsd, DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR | DDLOCK_NOSYSLOCK, NULL);
 
        if ( hr != DD_OK )
            return;
    }

    if ( g_lFullScreenBpp == 32 )
    {
        unsigned char *p_ucSrc, *p_ucTgt;
        
        p_ucSrc = (unsigned char *) _p_vSourceBuffer;
        p_ucTgt = (unsigned char *) ddsd.lpSurface;
        ddsd.lPitch = ddsd.lPitch - (_lWidth * 4);
 
        for ( lYDst = 0 ; lYDst < _lHeight ; lYDst ++ )
        {
            for ( lXDst = 0 ; lXDst <  _lWidth; lXDst ++ )
            {
                *p_ucTgt++ = *p_ucSrc++;
                *p_ucTgt++ = *p_ucSrc++;
                *p_ucTgt++ = *p_ucSrc++;
                p_ucTgt++;
            }
        }
    }
    else
    {
        p_uwSrc = (unsigned short *) _p_vSourceBuffer;
        p_uwTgt = (unsigned short *) ddsd.lpSurface;
        p_uwTgt += (ddsd.lPitch >> 1) * _lDestTop + _lDestLeft;
        GLD_MDRV_vBlitStretched16b( _lDestRight - _lDestLeft + 1, _lDestBottom - _lDestTop + 1, p_uwTgt, ddsd.lPitch >> 1, _lWidth, _lHeight, p_uwSrc );
    }
 
    hr = g_pddsBackBuffer->lpVtbl->Unlock(g_pddsBackBuffer, NULL);
}
 
 
#ifdef __cplusplus
} /*extern "C"*/
#endif
