/*
 =======================================================================================
  Name        : DX5_Init.c
  Author      : vincent lhullier            Date :02/09/98
  Description : Init and device function for D3D
 =======================================================================================
 */
 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#include "d3d.h"
 
#include "TMR.h"
#include "PRF.h"
 
#include "init_gli.h"
#include "PvObj_st.h"
#include "DX6_Choose.h"
#include "DLLCom.h"
#include "DX6_Caps.h"
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
 
/*
 =======================================================================================
    External globals and functions
 =======================================================================================
 */
extern GLI_tdstInternalGlobalValuesFor3dEngine  *GLI_BIG_GLOBALS;
extern GLI_tdst_DllInfos  *GLI_gpst_DllInfo; 
/*
 =======================================================================================
    Globals 
 =======================================================================================
 */
 
/*
 * D3D var
 */
LPDIRECT3DVIEWPORT3		g_pvViewport        = NULL;
LPDIRECT3DDEVICE3		g_pd3dDevice        = NULL;
LPDIRECT3D3				g_pD3D              = NULL;
LPDIRECTDRAWSURFACE4	g_pddsZBuffer       = NULL;
LPDIRECTDRAWSURFACE4	g_pddsBackBuffer    = NULL;
LPDIRECTDRAWSURFACE4	g_pddsPrimary       = NULL;
LPDIRECTDRAW4			g_pDD4              = NULL;
LPDIRECTDRAW			g_pDD1              = NULL;
RECT					g_rcScreenRect      ;
RECT					g_rcViewportRect    ;
HWND					g_hWnd              = NULL;
 
GUID                    GLIDX6_gx_DDDriverGuid;
GUID                    GLIDX6_gx_D3DDeviceGuid;
 
DDCAPS                  g_stDDCaps;
 
BOOL                    g_bFullScreen = TRUE;
long                    g_lFullScreenWidth = 0;
long                    g_lFullScreenHeight = 0;
long                    g_lFullScreenBpp = 0;
 
BOOL                    g_bIsActive = TRUE;
int                     g_iModeDisplay = 1;  //0 = fit window;   1=Respect Ratio and maximize;  2 =Respect Ration and sizemax  fix(640*480)
/*
 * function prototypes
 */
static HRESULT GLI_fn_hRelease3DEnvironment( char _cEvenDirectDraw );
static HRESULT GLI_fn_hCreateDirectDraw( void );
static HRESULT GLI_fn_hInitialize3DEnvironment( HWND hWnd, BOOL _bFullScreen, long _lWidth, long _lHeight, long _lBpp );

       /* Domat.c */
       HRESULT GLI_fn_hRestoreSurfaces( void );
       void GLI_fn_vSetRenderParametersBeforeOpaqueFace( void );
       void GLI_vSendBlackPolygon();

       /* HdwTx.c */
       void GLI_DRV_vUnLoadTextures();
 
 
/*
 =======================================================================================
 =======================================================================================
    Functions 
 =======================================================================================
 =======================================================================================
 */
 
#ifdef __cplusplus
extern "C" 
{
#endif
 
 



void fn_vRecomputeViewportToMaximizeDisplay( void )
{
	if(g_iModeDisplay==0) 
	{
		RECT    rcNewWindowRect;
		GetClientRect( g_hWnd, &rcNewWindowRect );
		ClientToScreen( g_hWnd, (POINT*)&rcNewWindowRect.left );
		ClientToScreen( g_hWnd, (POINT*)&rcNewWindowRect.right );
		g_rcScreenRect = rcNewWindowRect;
	
		GLI_gpst_DllInfo->f_WidthRatio=1.0f;
		GLI_gpst_DllInfo->f_HeightRatio=1.0f;

	}else 
	{
		RECT stDestRect;
		RECT stSrcRect;
		DWORD dwDestWidth;
		DWORD dwDestHeight;
		DWORD dwDestWidth0;
		DWORD dwDestHeight0;
		float fRatio;
	
		GetWindowRect( g_hWnd, &stDestRect );
		
		dwDestWidth0 = dwDestWidth = stDestRect.right - stDestRect.left;
		dwDestHeight0= dwDestHeight = stDestRect.bottom - stDestRect.top;

		if( dwDestWidth > 0 && dwDestHeight > 0 )
		{
			fRatio = (float)dwDestWidth/(float)dwDestHeight;
			if( fRatio > 1.333f )
			{
				// Ok, maximise height, and keep ratio
				if(g_iModeDisplay==2)
					if( dwDestHeight > (DWORD)GLI_gpst_DllInfo->l_InitHeight )
					{
						dwDestHeight = GLI_gpst_DllInfo->l_InitHeight;
					}
				stDestRect.bottom = stDestRect.top + dwDestHeight;
				dwDestWidth = dwDestHeight*1.333f;
				stDestRect.right = stDestRect.left + dwDestWidth;
			}
			else
			{
				// Ok, maximise Width, and keep ratio
				if(g_iModeDisplay==2)
					if( dwDestWidth > (DWORD)GLI_gpst_DllInfo->l_InitWidth)
					{
						dwDestWidth = GLI_gpst_DllInfo->l_InitWidth;
					}
				stDestRect.right = stDestRect.left + dwDestWidth;
				dwDestHeight = dwDestWidth*0.75f;
				stDestRect.bottom = stDestRect.top + dwDestHeight;
			}
			g_rcScreenRect = stDestRect;

			GLI_gpst_DllInfo->f_WidthRatio= (float)dwDestWidth0/(float)dwDestWidth;
			GLI_gpst_DllInfo->f_HeightRatio= (float)dwDestHeight0/(float)dwDestHeight;
		}
	}
}


void GLI_fn_vReplaceDisplayForWindowedEditorMode( void )
	{
		RECT    rcNewWindowRect;
		
		GetClientRect( g_hWnd, &rcNewWindowRect );
		ClientToScreen( g_hWnd, (POINT*)&rcNewWindowRect.left );
		ClientToScreen( g_hWnd, (POINT*)&rcNewWindowRect.right );
		g_rcScreenRect = rcNewWindowRect;
	//	fn_vRecomputeViewportToMaximizeDisplay();
	}
void __declspec(dllexport)    GLI_DRV_vRecomputeViewportToMaximizeDisplay(int _arg)
{
	fn_vRecomputeViewportToMaximizeDisplay();
}

void __declspec(dllexport)    GLI_DRV_vSetMainWindowForRender(HWND _hWnd)
{
	RECT    rcNewWindowRect;
	LPDIRECTDRAWCLIPPER		hClipper;

	g_pddsPrimary->lpVtbl->GetClipper( g_pddsPrimary, &hClipper );
	hClipper->lpVtbl->SetHWnd( hClipper, 0, _hWnd );
	g_hWnd = _hWnd;
	GetClientRect( g_hWnd, &rcNewWindowRect );
	ClientToScreen( g_hWnd, (POINT*)&rcNewWindowRect.left );
	ClientToScreen( g_hWnd, (POINT*)&rcNewWindowRect.right );
	g_rcScreenRect = rcNewWindowRect;
	//fn_vRecomputeViewportToMaximizeDisplay();

}



 
/*Bart990108:*/
BOOL __declspec(dllexport) GLI_DRV_bWindowedModeIsOptimized(void)
{
	return FALSE;
}
 
void __declspec(dllexport) GLI_DRV_vOptimizedWindowedMode(void)
{
	return;
}
 
void __declspec(dllexport) GLI_DRV_vNonOptimizedWindowedMode(void)
{
	return;
}
 
/*
 =======================================================================================
    Debug only Functions 
 =======================================================================================
 */
 
/*
 ----------------------------------------------------------------------------------------
  Description   : lock device
 ----------------------------------------------------------------------------------------
 */
BOOL GLI_DRV_bLockDevice( void **_pp_vVirtualScreen, long *_p_lPitch )
{
    DDSURFACEDESC2	ddsd;
    HRESULT         hr;
 
    memset( &ddsd, 0,  sizeof(DDSURFACEDESC2) );
    ddsd.dwSize = sizeof(DDSURFACEDESC2);
    hr = g_pddsBackBuffer->lpVtbl->Lock( g_pddsBackBuffer ,NULL,&ddsd,DDLOCK_WAIT | DDLOCK_SURFACEMEMORYPTR | DDLOCK_NOSYSLOCK,NULL);
    if (hr != DD_OK)
        return FALSE;
 
    *_pp_vVirtualScreen = ddsd.lpSurface;
    *_p_lPitch = ddsd.lPitch;
 
    return TRUE;
}
    
/*
 ----------------------------------------------------------------------------------------
  Description   : prepare display for full screen mode
 ----------------------------------------------------------------------------------------
 */
void __declspec(dllexport) GLI_DRV_vPrepareForGliFullScreen( HWND _hWnd )
{
    if (!GLI_MDRV_xIsGliInit())
        return;
    
    GLI_fn_hRelease3DEnvironment( FALSE );
    g_hWnd = _hWnd;
    GLI_fn_hInitialize3DEnvironment( g_hWnd, TRUE, g_lFullScreenWidth, g_lFullScreenHeight, g_lFullScreenBpp );
    //bart990210 : GLI_fn_hRestoreSurfaces();
}
/*
 ----------------------------------------------------------------------------------------
  Description   : Unlock device
 ----------------------------------------------------------------------------------------
 */
BOOL GLI_DRV_bUnlockDevice( void )
{
    return ( g_pddsBackBuffer->lpVtbl->Unlock(g_pddsBackBuffer, NULL) == DD_OK);
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : something to do when app is activate/deactivate
 ----------------------------------------------------------------------------------------
 */
void __declspec(dllexport) GLI_DRV_vActivateGli( HWND _hWnd, BOOL _bActivate )
{
    g_bIsActive = _bActivate;
	if (_bActivate)
		GLI_DRV_vPrepareForGliFullScreen( _hWnd );
}
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : prepare display for full screen mode
 ----------------------------------------------------------------------------------------
 */
BOOL __declspec(dllexport) GLI_DRV_bPrepareForGliWindowed( HWND _hWnd )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    HRESULT hr;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    if (!GLI_MDRV_xIsGliInit())
        return FALSE;
    
    GLI_fn_hRelease3DEnvironment( FALSE );
    
    g_hWnd = _hWnd;
#ifndef  USE_DX //chbani
    hr = GLI_fn_hInitialize3DEnvironment( g_hWnd, FALSE, 0, 0, 0 );
#else
     hr = GLI_fn_hInitialize3DEnvironment( g_hWnd, FALSE, GLI_gpst_DllInfo->l_InitWidth, GLI_gpst_DllInfo->l_InitHeight, GLI_gpst_DllInfo->l_InitBpp );
#endif
    if (hr != DD_OK)
        return FALSE;

    /*bart990210 : GLI_fn_hRestoreSurfaces();*/
    return TRUE;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : readapt window (called when window move or is resized)
 ----------------------------------------------------------------------------------------
 */
void __declspec(dllexport) GLI_DRV_vReadaptDisplay( void )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    HRESULT hr;
    RECT    rcNewWindowRect;
    DWORD   dwWidth, dwHeight, dwNewWidth, dwNewHeight;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    GetClientRect( g_hWnd, &rcNewWindowRect );
    dwWidth     = g_rcScreenRect.right - g_rcScreenRect.left;
    dwNewWidth  = rcNewWindowRect.right - rcNewWindowRect.left;
    dwHeight    = g_rcScreenRect.bottom - g_rcScreenRect.top;
    dwNewHeight = rcNewWindowRect.bottom - rcNewWindowRect.top;
 //#ifndef USE_DX
    if ( (dwWidth != dwNewWidth) || (dwHeight != dwNewHeight ) )
    {
        GLI_fn_hRelease3DEnvironment( FALSE );
        hr = GLI_fn_hInitialize3DEnvironment( g_hWnd, FALSE, 0, 0, 0 );
        if (hr == DD_OK)
            GLI_fn_hRestoreSurfaces();
    }
    else
//#endif
    {
        ClientToScreen( g_hWnd, (POINT*)&rcNewWindowRect.left );
        ClientToScreen( g_hWnd, (POINT*)&rcNewWindowRect.right );
        g_rcScreenRect = rcNewWindowRect;
    }
}
 
 
 
/*
 =======================================================================================
    Functions 
 =======================================================================================
 */
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Initialize DirectDraw, Direct3D objects
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_xClearViewingList(void);
 
void GLI_DRV_xInitDriver( HWND _hWnd, BOOL _bFullScreen, long _lWidth, long _lHeight, long _lBpp )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    HRESULT hr;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#ifdef USE_DX0 //attention
    if( !_bFullScreen )
	{
		HDC hDc;

		hDc = GetDC( NULL );
		_lBpp = GLI_gpst_DllInfo->l_InitBpp = g_lFullScreenBpp = GetDeviceCaps( hDc, BITSPIXEL );
		ReleaseDC( NULL, hDc );
	}

#endif   
        
    GLI_BIG_GLOBALS -> p_TheZListe = malloc(sizeof(GLI_tdstZListe));
    memset (GLI_BIG_GLOBALS -> p_TheZListe , 0 , sizeof(GLI_tdstZListe));
    GLI_BIG_GLOBALS -> p_TheZListe -> p_TableOfPoints = malloc((3L * sizeof (D3DTLVERTEX))<<GLI_MaxZListeTrianglesPO2);
    GLI_BIG_GLOBALS -> ulCurrentZTable = 0;
    GLI_DRV_xClearViewingList();
 
    /* retrieve window application */
    g_hWnd = _hWnd;
 
	ShowWindow( g_hWnd, SW_SHOWNORMAL );
    UpdateWindow( g_hWnd );
    SetFocus(g_hWnd);
 
    /* Create a DirectDraw object.*/
    hr = GLI_fn_hCreateDirectDraw();
    if( hr != DD_OK )
        return;
 
 
    hr = GLI_fn_hInitialize3DEnvironment( g_hWnd, _bFullScreen, _lWidth, _lHeight, _lBpp );
 #ifdef USE_DX
      SetFocus(g_hWnd); // Portage Windows 2000
	{
		int iRunning;
		iRunning = 0;
		SystemParametersInfo( SPI_SETSCREENSAVERRUNNING, TRUE, &iRunning, 0 );
	}
#endif
 
    /*
     * Set driver capabilities
     */
    memset( g_p_stGliCaps, 0, sizeof( tdstGliCaps ) );
    GLI_DX6_fn_hGetDriverCaps( g_p_stGliCaps, GLIDX6_fnl_GetDeviceFlag(), g_pDD4 );
    GLI_DX6_fn_hGetDeviceCaps( g_p_stGliCaps, g_pDD4, GLIDX6_fnpst_GetDeviceDesc() );
    GLI_DX6_fn_hGetPixelFormats();
    GLI_DX6_fn_vPrecalculateTextureSize();
    
    return;
}
    
/*
 ----------------------------------------------------------------------------------------
  Description   : close driver
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vCloseDriver ()
{
    /*g_pDD4->lpVtbl->SetDisplayMode(g_pDD4, 1280, 1024, 16/*8  , 0, 0);*/
    //GLI_DRV_vUnLoadTextures();
    GLI_fn_hRelease3DEnvironment( TRUE );
}
    
 
/*
 ----------------------------------------------------------------------------------------
  Description   : 
 ----------------------------------------------------------------------------------------
 */
void GLI_vBeginDrawingTexturedMirrors(void)
{
    GLI_BIG_GLOBALS->bDrawMirrorSymetric = 1;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : 
 ----------------------------------------------------------------------------------------
 */
void GLI_vBeginDrawingTexturedMirrorsSurfaces()
{
    GLI_BIG_GLOBALS->lAMirrorIsDetected = 3;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : 
 ----------------------------------------------------------------------------------------
 */
void GLI_vEndDrawingTexturedMirrors()
{
    GLI_BIG_GLOBALS->lAMirrorIsDetected &= 1;
    GLI_BIG_GLOBALS->bDrawMirrorSymetric = 0;
}
    
/*
 ----------------------------------------------------------------------------------------
  Description   : Flip
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vFlipDevice(long lNbFrames)
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    HRESULT                 hDDResult;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    if (!GLI_MDRV_xIsGliInit() || !g_bIsActive) 
	    return;
 
    GLI_BIG_GLOBALS->lDisplayMenuIsDetected = GLI_BIG_GLOBALS->lAMirrorIsDetected = 0;
 
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

#if !defined(PRESS_DEMO)
    PRF_MDRV_vStartChrono( PRF_C_ulWaitFor3dFx , NULL);
#endif /* PRESS_DEMO */
    while( g_pddsBackBuffer->lpVtbl->GetFlipStatus( g_pddsBackBuffer, DDGFS_CANFLIP ) == DDERR_WASSTILLDRAWING )
        ;

#if !defined(PRESS_DEMO)
    PRF_MDRV_vStopChrono( PRF_C_ulWaitFor3dFx , NULL);

	PRF_MDRV_vStopChrono( PRF_C_ulFctMainLoop , NULL);
	PRF_MDRV_lIncIndependantVariable( PRF_C_ulIdpRasterTime, -(long)TMR_fn_ulFastGetInternalCounter() );
#endif /* PRESS_DEMO */
 
	GAM_MDRV_vShowRasters();
 
#if !defined(PRESS_DEMO)
	PRF_MDRV_lIncIndependantVariable( PRF_C_ulIdpRasterTime, TMR_fn_ulFastGetInternalCounter() );
	PRF_MDRV_vStartChrono (PRF_C_ulFctFlip , NULL);
#endif /* PRESS_DEMO */
 
	if( NULL == g_pddsPrimary )
	    return;
 
    do 
    { 
        if (g_bFullScreen)
            hDDResult = g_pddsPrimary->lpVtbl->Flip( g_pddsPrimary, NULL, DDFLIP_WAIT );
        else
            hDDResult = g_pddsPrimary->lpVtbl->Blt( g_pddsPrimary, &g_rcScreenRect, g_pddsBackBuffer, &g_rcViewportRect, DDBLT_WAIT, NULL );
        
        if (hDDResult == DDERR_SURFACELOST)
        {
            /*
            if (WaitForSingleObject( g_p_vDrawSemaphore, 100) == WAIT_TIMEOUT)
                hDDResult = DD_OK;
            else
            */
                GLI_fn_hRestoreSurfaces();
        }
    } while (hDDResult != DD_OK );
 
    /* g_pDD4->lpVtbl->WaitForVerticalBlank( g_pDD4, DDWAITVB_BLOCKBEGIN, NULL ); */
#if !defined(PRESS_DEMO)
    PRF_MDRV_vStopChrono  (PRF_C_ulFctFlip , NULL);
	PRF_MDRV_vStartChrono (PRF_C_ulFctMainLoop, NULL);
#endif /* PRESS_DEMO */
 
    /* GLI_fn_vSetRenderParametersBeforeOpaqueFace(); */
    //GLI_vSendBlackPolygon();
}


/*
 ----------------------------------------------------------------------------------------
  Description   : Special flip with automatic syncro
 ----------------------------------------------------------------------------------------
 */
 
void GLI_DRV_vFlipDeviceWithSyncro()
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    HRESULT                 hDDResult;
    long lNbFrames;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    if (!GLI_MDRV_xIsGliInit() || !g_bIsActive) 
        return;
 
    GLI_BIG_GLOBALS->lDisplayMenuIsDetected = GLI_BIG_GLOBALS->lAMirrorIsDetected = 0;
 
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
#if !defined(PRESS_DEMO)
    PRF_MDRV_vStartChrono( PRF_C_ulWaitFor3dFx , NULL);
#endif /* PRESS_DEMO */

    while( g_pddsBackBuffer->lpVtbl->GetFlipStatus( g_pddsBackBuffer, DDGFS_CANFLIP ) == DDERR_WASSTILLDRAWING )
        ;

#if !defined(PRESS_DEMO)
    PRF_MDRV_vStopChrono( PRF_C_ulWaitFor3dFx , NULL);
    PRF_MDRV_vStopChrono( PRF_C_ulFctMainLoop , NULL);

    PRF_MDRV_lIncIndependantVariable( PRF_C_ulIdpRasterTime, -(long)TMR_fn_ulFastGetInternalCounter() );
 
    GAM_MDRV_vShowRasters();
 
    PRF_MDRV_lIncIndependantVariable( PRF_C_ulIdpRasterTime, TMR_fn_ulFastGetInternalCounter() );
    PRF_MDRV_vStartChrono (PRF_C_ulFctFlip , NULL);
#endif /* PRESS_DEMO */
 
    if( NULL == g_pddsPrimary )
        return;
 
    lNbFrames = GLD_MDRV_fn_lComputeWaitFrameForSmoothSynchro();
	//GetClientRect( g_hWnd, &g_rcViewportRect );
	SetRect(&g_rcViewportRect, 0, 0, GLI_gpst_DllInfo->l_InitWidth , GLI_gpst_DllInfo->l_InitHeight );

	fn_vRecomputeViewportToMaximizeDisplay();
	
	
    do 
    { 
        if (g_bFullScreen)
            hDDResult = g_pddsPrimary->lpVtbl->Flip( g_pddsPrimary, NULL, DDFLIP_WAIT );
        else
            hDDResult = g_pddsPrimary->lpVtbl->Blt( g_pddsPrimary, &g_rcScreenRect, g_pddsBackBuffer, &g_rcViewportRect, DDBLT_WAIT, NULL );
        
        if (hDDResult == DDERR_SURFACELOST)
        {
            /*
            if (WaitForSingleObject( g_p_vDrawSemaphore, 100) == WAIT_TIMEOUT)
                hDDResult = DD_OK;
            else
            */
                GLI_fn_hRestoreSurfaces();
        }
    } while (hDDResult != DD_OK );
 
    while( --lNbFrames )
    {
        g_pDD4->lpVtbl->WaitForVerticalBlank( g_pDD4, DDWAITVB_BLOCKBEGIN, NULL );

    }

#if !defined(PRESS_DEMO)
    PRF_MDRV_vStopChrono  (PRF_C_ulFctFlip , NULL);
	PRF_MDRV_vStartChrono (PRF_C_ulFctMainLoop, NULL);
#endif /* PRESS_DEMO */
 
    /* GLI_fn_vSetRenderParametersBeforeOpaqueFace(); */
    //GLI_vSendBlackPolygon();
}

 
/*
 ----------------------------------------------------------------------------------------
  Description   : Clear
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vClearDevice(BOOL ZBuffer, BOOL ColorBuffer, unsigned long Color)
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    HRESULT                 hres;
    long                    lFlag;
    long                    lColor;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
 
    if (GLI_MDRV_xIsGliInit())
    {
        lColor = ((Color & 0xFF0000) >> 16) | (Color & 0xFF00) | ((Color & 0xFF) << 16);
        lFlag = (ZBuffer ? D3DCLEAR_ZBUFFER : 0 ) | (ColorBuffer ? D3DCLEAR_TARGET : 0);
		hres = g_pvViewport->lpVtbl->Clear2( g_pvViewport, 1UL, (D3DRECT *) &g_rcViewportRect, lFlag, lColor,0L, 0L );

/*        GLI_vSendBlackPolygon(); */
    }
}

/*
 ----------------------------------------------------------------------------------------
  Description   : Clear ZBuffer
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vClearZBufferRegion(long lXStart,long lXEnd,long lYStart,long lYEnd)
{
    if (!GLI_BIG_GLOBALS->bDrawMirrorSymetric)
    {
        GLI_DRV_vClearDevice( TRUE, FALSE, 0);
        //GLI_BIG_GLOBALS->lDisplayMenuIsDetected = 1;
        GLI_fn_vSetRenderParametersBeforeOpaqueFace();
    }
}

 
/*
 ----------------------------------------------------------------------------------------
  Description   : Get display statistics
  _p_ulPixelSent        -> return % of pixel sent / screen size
  _p_ulPixelDisplayed   -> return % of display pixel / screen size
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vGetStats(unsigned long *_p_ulPixelsSent, unsigned long *_p_ulPixelsDisplayed )
{
    *_p_ulPixelsSent        = 0;
    *_p_ulPixelsDisplayed   = 0;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : WaitRetrace
 ----------------------------------------------------------------------------------------
 */


void GLI_DRV_vWaitRetrace(void )
{
} 

 
/*
 =======================================================================================
	Internal functions 
 =======================================================================================
 */
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Restore surface
 ----------------------------------------------------------------------------------------
 */
HRESULT GLI_fn_hRestoreSurfaces( void )
{
    /* Check/restore the primary surface*/
    if( ( g_pddsPrimary ) && ( g_pddsPrimary->lpVtbl->IsLost(g_pddsPrimary) ) )
            g_pddsPrimary->lpVtbl->Restore(g_pddsPrimary);
    
    /* Check/restore the back buffer*/
    if( ( g_pddsBackBuffer ) && ( g_pddsBackBuffer->lpVtbl->IsLost(g_pddsBackBuffer) ) )
            g_pddsBackBuffer->lpVtbl->Restore(g_pddsBackBuffer);
 
    /* Check/restore the z-buffer surface*/
    if( ( g_pddsZBuffer ) && ( g_pddsZBuffer->lpVtbl->IsLost(g_pddsZBuffer) ) ) 
            g_pddsZBuffer->lpVtbl->Restore(g_pddsZBuffer);
 
    GLI_MDRV_vReloadTextures();
    
    return S_OK;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Release D3D objects
 ----------------------------------------------------------------------------------------
 */
#define M_ReleaseD3DObject(p) { if(p) { hr = (p)->lpVtbl->Release(p); (p)=NULL; } }

#define M_ReleaseAllD3DObject(p) {\
	if(p)\
	{\
		do\
		{\
			hr = (p)->lpVtbl->Release(p);\
		}while(hr);\
		(p)=NULL;\
	}\
}

static HRESULT GLI_fn_hRelease3DEnvironment( char _cDirectDraw )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    HRESULT hr; /* used by macro*/
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    M_ReleaseD3DObject(g_pvViewport)
    M_ReleaseD3DObject(g_pd3dDevice);
 
    /* In windowed mode, release the explicity created backbuffer.*/
    /*if( FALSE == m_bIsFullscreen )*/
    /*    SAFE_RELEASE( m_pddsBackBuffer );*/
    /*SAFE_RELEASE( m_pddsRenderTarget ); //Note: release before frontbuffer*/
    M_ReleaseD3DObject( g_pddsZBuffer );
    M_ReleaseD3DObject( g_pddsBackBuffer ); //bart990210
    M_ReleaseD3DObject( g_pddsPrimary );
    M_ReleaseD3DObject( g_pD3D );

    /*
     * Release texture
     */
    GLI_DRV_vUnLoadTextures();


 
    /* Do a safe check for releasing DDRAW. RefCount must be zero.*/
    if( _cDirectDraw )
	{
	    g_pDD4->lpVtbl->SetCooperativeLevel( g_pDD4, g_hWnd, DDSCL_NORMAL );
        M_ReleaseAllD3DObject( g_pDD4 );
	}
 
    /* Return successful, unless there are outstanding DD or D3DDevice refs.*/
    /*return ( nDD==0 && nD3D==0 ) ? S_OK : D3DFWERR_NONZEROREFCOUNT;*/
 
    return hr;
}
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : callback function for enumerating Z-Buffer
 ----------------------------------------------------------------------------------------
 */
static HRESULT WINAPI GLI_fn_hEnumZBufferCallback( DDPIXELFORMAT* pddpf, VOID* pddpfDesired )
{
    /* If this is ANY type of depth-buffer, stop.*/
    if( pddpf->dwFlags == DDPF_ZBUFFER )
    {
        memcpy( pddpfDesired, pddpf, sizeof(DDPIXELFORMAT) );
 
        /* Return with D3DENUMRET_CANCEL to end the search.*/
        return D3DENUMRET_CANCEL;
    }
 
    /* Return with D3DENUMRET_OK to continue the search.*/
    return D3DENUMRET_OK;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Init Direct draw object (device, surface and viewport )
 ----------------------------------------------------------------------------------------
 */
static HRESULT GLI_fn_hInitialize3DEnvironment( HWND hWnd, BOOL _bFullScreen, long _lWidth, long _lHeight, long _lBpp )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    HRESULT					hr;
	DDSURFACEDESC2			ddsd;
	LPDIRECTDRAWCLIPPER		pcClipper;
	D3DVIEWPORT2			vdData;
	DDPIXELFORMAT			ddpfZBuffer;  
    DDSCAPS2                ddscaps;
    DWORD                   dwCoopFlag;
 
    unsigned long           ulTotal, ulLeft;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    g_bFullScreen = _bFullScreen;
    if (g_bFullScreen)
    {
        g_lFullScreenWidth  = _lWidth;
        g_lFullScreenHeight = _lHeight;
        g_lFullScreenBpp    = _lBpp;
    }
 
#ifdef USE_DX
	{
		g_lFullScreenWidth = GLI_gpst_DllInfo->l_InitWidth;
		g_lFullScreenHeight = GLI_gpst_DllInfo->l_InitHeight;
		g_lFullScreenBpp = GLI_gpst_DllInfo->l_InitBpp;
		if (_lWidth == 0)
			_lWidth = g_lFullScreenWidth;
		if (_lHeight == 0)
			_lHeight = g_lFullScreenHeight;
		if (_lBpp == 0)
			_lBpp = g_lFullScreenBpp;
	}
 

#endif

 
    /* Query DirectDraw for access to Direct3D*/
    hr = g_pDD4->lpVtbl->QueryInterface( g_pDD4, &IID_IDirect3D3, (VOID**)&g_pD3D );
    if( FAILED( hr) )
        return hr;
 
    /* Z-Buffer*/
    memset( &ddpfZBuffer, 0, sizeof(DDPIXELFORMAT) );
    /*hr = g_pD3D->lpVtbl->EnumZBufferFormats( g_pD3D, &xDeviceGuid, GLI_fn_hEnumZBufferCallback, (VOID*)&ddpfZBuffer );*/
    hr = g_pD3D->lpVtbl->EnumZBufferFormats( g_pD3D, &GLIDX6_gx_D3DDeviceGuid, GLI_fn_hEnumZBufferCallback, (VOID*)&ddpfZBuffer );
    if( ddpfZBuffer.dwSize != sizeof(DDPIXELFORMAT) )
        return E_FAIL;
 
    dwCoopFlag = ( (_bFullScreen ) ? (DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN) : DDSCL_NORMAL) | DDSCL_FPUSETUP;
    /*hr = g_pDD4->lpVtbl->SetCooperativeLevel( g_pDD4, hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_FPUSETUP );*/
    hr = g_pDD4->lpVtbl->SetCooperativeLevel( g_pDD4, (_bFullScreen ) ? hWnd : NULL, dwCoopFlag );
    if( FAILED( hr ) )
        return hr;
 
    /* change display mode*/
    if (_bFullScreen)
    {
        hr = g_pDD4->lpVtbl->SetDisplayMode(g_pDD4, _lWidth, _lHeight, _lBpp, 0, 0);
        if( FAILED( hr ) )
            return hr;
    }
 
   	/* Get the dimensions of the viewport and screen bounds Store the rectangle which contains the renderer*/
    if (_bFullScreen)
    {
        SetRect(&g_rcViewportRect, 0, 0, _lWidth, _lHeight );
        memcpy(&g_rcScreenRect, &g_rcViewportRect, sizeof(RECT) );
    }
    else
    {
        GetClientRect( hWnd, &g_rcScreenRect );
        GetClientRect( hWnd, &g_rcViewportRect );
        ClientToScreen( hWnd, (POINT*)&g_rcScreenRect.left );
        ClientToScreen( hWnd, (POINT*)&g_rcScreenRect.right );
    }
 
    /*
     * Create primary and back buffer
     */
 
    /* Prepare a surface description for the primary surface.*/
    ZeroMemory( &ddsd, sizeof(DDSURFACEDESC2) );
    ddsd.dwSize         = sizeof(DDSURFACEDESC2);
    ddsd.dwFlags        = DDSD_CAPS;
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
 
    if (_bFullScreen)
    {
        ddsd.dwFlags        |= DDSD_BACKBUFFERCOUNT;
        ddsd.ddsCaps.dwCaps |= DDSCAPS_3DDEVICE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
        ddsd.dwBackBufferCount = 1;
    }
 
    /* select memory type */
    ddsd.ddsCaps.dwCaps |= GLIDX6_fnc_IsHardware() ? (DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM) : DDSCAPS_SYSTEMMEMORY;
 
    /* Create the primary surface with or without backbuffer (if in or not in full screen mode )*/
 
    GLI_DX6_hGetVideoMemory( g_pDD4, DDSCAPS_VIDEOMEMORY, &ulTotal, &ulLeft );
 
    hr = g_pDD4->lpVtbl->CreateSurface( g_pDD4, &ddsd, &g_pddsPrimary, NULL );
    if(  hr != DD_OK )
        return hr;
 
    /*
    memset( &ddpfPrimary, 0, sizeof(DDPIXELFORMAT) );
    ddpfPrimary.dwSize = sizeof( DDPIXELFORMAT );
    g_pddsPrimary->lpVtbl->GetPixelFormat(g_pddsPrimary, &ddpfPrimary );
    */
 
    GLI_DX6_hGetVideoMemory( g_pDD4, DDSCAPS_VIDEOMEMORY, &ulTotal, &ulLeft );
 
    if (_bFullScreen)
    {
        /* get the created backbuffer*/
	    ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
	    hr = g_pddsPrimary->lpVtbl->GetAttachedSurface( g_pddsPrimary, &ddscaps, &g_pddsBackBuffer );
        if (hr != DD_OK)
            return hr;
    }
    else
    {
        /* If in windowed-mode, create a clipper object*/
        hr = g_pDD4->lpVtbl->CreateClipper( g_pDD4, 0, &pcClipper, NULL );
		if( hr != DD_OK )
            return hr;
 
		/* Associate the clipper with the window*/
		pcClipper->lpVtbl->SetHWnd( pcClipper, 0, hWnd );
		g_pddsPrimary->lpVtbl->SetClipper( g_pddsPrimary, pcClipper );
		M_ReleaseD3DObject( pcClipper );
 
		/* Create the backbuffer*/
		ddsd.dwFlags        = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
#ifdef USE_DX0
               ddsd.dwWidth        = _lWidth;
               ddsd.dwHeight       = _lHeight;
#else
		ddsd.dwWidth        = g_rcViewportRect.right;
		ddsd.dwHeight       = g_rcViewportRect.bottom;
#endif
		ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_3DDEVICE;
        /* select memory type */
        ddsd.ddsCaps.dwCaps |= GLIDX6_fnc_IsHardware() ? (DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM): DDSCAPS_SYSTEMMEMORY;
 
        hr = g_pDD4->lpVtbl->CreateSurface( g_pDD4, &ddsd, &g_pddsBackBuffer, NULL );
        if (hr != DD_OK)
            return hr;
    }
 
	/*
     * Create the ZBuffer
     */
    /* Get z-buffer dimensions from the render target, Setup the surface desc for the z-buffer.*/
    ddsd.dwFlags        = DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT|DDSD_PIXELFORMAT;
    
    ddsd.ddsCaps.dwCaps = DDSCAPS_ZBUFFER;
    ddsd.ddsCaps.dwCaps |= GLIDX6_fnc_IsHardware() ? (DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM): DDSCAPS_SYSTEMMEMORY;
 #ifdef USE_DX0
   ddsd.dwWidth        = _lWidth;
    ddsd.dwHeight       = _lHeight;
#else
    ddsd.dwWidth        = g_rcScreenRect.right - g_rcScreenRect.left;
    ddsd.dwHeight       = g_rcScreenRect.bottom - g_rcScreenRect.top;
#endif  
    memcpy( &ddsd.ddpfPixelFormat, &ddpfZBuffer, sizeof(DDPIXELFORMAT) );
     
    hr = g_pDD4->lpVtbl->CreateSurface( g_pDD4, &ddsd, &g_pddsZBuffer, NULL );
    if( hr != DD_OK)
        return hr;
 
    GLI_DX6_hGetVideoMemory( g_pDD4, DDSCAPS_VIDEOMEMORY , &ulTotal, &ulLeft );
 
	/* Attach the z-buffer to the back buffer.*/
	hr = g_pddsBackBuffer->lpVtbl->AddAttachedSurface( g_pddsBackBuffer, g_pddsZBuffer );
    if (hr != DD_OK)
        return hr;
 
    /*
     * Create device and viewport
     */
    hr = g_pD3D->lpVtbl->CreateDevice( g_pD3D, &GLIDX6_gx_D3DDeviceGuid, g_pddsBackBuffer, &g_pd3dDevice, NULL );
    if( FAILED( hr ) )
        return hr;
 
	/* Set up the viewport data parameters*/
    ZeroMemory( &vdData, sizeof(D3DVIEWPORT2) );
 
    /* Always set the structure size!*/
    vdData.dwSize       = sizeof(D3DVIEWPORT2);  
#ifdef USE_DX0
     vdData.dwWidth      = _lWidth;
    vdData.dwHeight     = _lHeight;
#else
    vdData.dwWidth      = g_rcScreenRect.right - g_rcScreenRect.left;
    vdData.dwHeight     = g_rcScreenRect.bottom - g_rcScreenRect.top;
#endif
    vdData.dvClipX      = -1.0f;
    vdData.dvClipWidth  = 2.0f;
    vdData.dvClipY      = 1.0f;
    vdData.dvClipHeight = 2.0f;
    vdData.dvMaxZ       = 1.0f; 
 
	/* Create the viewport.*/
    hr = g_pD3D->lpVtbl->CreateViewport( g_pD3D, &g_pvViewport, NULL );
    if( FAILED( hr ) )
        return hr;
 
    /* Associate the viewport with the device.*/
    g_pd3dDevice->lpVtbl->AddViewport( g_pd3dDevice, g_pvViewport );
 
    /* Set the parameters for the new viewport.*/
    hr = g_pvViewport->lpVtbl->SetViewport2( g_pvViewport, &vdData );
	if (hr != DD_OK)
		return FALSE;
 
	/* Set the current viewport for the device*/
    g_pd3dDevice->lpVtbl->SetCurrentViewport( g_pd3dDevice, g_pvViewport );
 
    /* render initialization*/
    /* 
     * ZTest
     */
    g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ZENABLE, D3DZB_TRUE );
	g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ZFUNC, D3DCMP_GREATEREQUAL );
		
	g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_DITHERENABLE, TRUE );
	g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_SPECULARENABLE, FALSE );
        
    g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_TEXTUREPERSPECTIVE, TRUE);

	/* Begin G.CLEMENT 20/07/1999 : superseded SetRenderState's replaced */
    /* g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_TEXTUREMAG, D3DFILTER_LINEAR); */
	/* g_pd3dDevice->lpVtbl->SetTextureStageState( g_pd3dDevice, 0, D3DTSS_MAGFILTER, D3DTFG_LINEAR); See below */
    /* g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_TEXTUREMIN, D3DFILTER_LINEAR); */
	/* g_pd3dDevice->lpVtbl->SetTextureStageState( g_pd3dDevice, 0, D3DTSS_MINFILTER, D3DTFG_LINEAR); See below */
	/* End G.CLEMENT 20/07/1999 */
    g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ANTIALIAS,D3DANTIALIAS_NONE);
 
    g_pd3dDevice->lpVtbl->SetRenderState(g_pd3dDevice,D3DRENDERSTATE_CULLMODE, D3DCULL_NONE);
 
		
    g_pd3dDevice->lpVtbl->SetTextureStageState( g_pd3dDevice, 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
	g_pd3dDevice->lpVtbl->SetTextureStageState( g_pd3dDevice, 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
	g_pd3dDevice->lpVtbl->SetTextureStageState( g_pd3dDevice, 0, D3DTSS_COLOROP,   D3DTOP_MODULATE );
	g_pd3dDevice->lpVtbl->SetTextureStageState( g_pd3dDevice, 0, D3DTSS_MINFILTER, D3DTFN_LINEAR );
	g_pd3dDevice->lpVtbl->SetTextureStageState( g_pd3dDevice, 0, D3DTSS_MAGFILTER, D3DTFG_LINEAR );
    g_pd3dDevice->lpVtbl->SetTextureStageState( g_pd3dDevice, 0, D3DTSS_MIPFILTER, D3DTFP_LINEAR );
    /*
     * Alpha test
     */
    g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ALPHATESTENABLE, FALSE );
    g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ALPHAFUNC, D3DCMP_GREATEREQUAL );
	g_pd3dDevice->lpVtbl->SetRenderState( g_pd3dDevice, D3DRENDERSTATE_ALPHAREF, 0xC0 );

	//GLI_fn_vReplaceDisplayForWindowedEditorMode();
	
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : enumerate, choose and create direct draw driver
 ----------------------------------------------------------------------------------------
 */
static HRESULT GLI_fn_hCreateDirectDraw()
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    HRESULT hr;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    hr = DirectDrawCreate( &GLIDX6_gx_DDDriverGuid, &g_pDD1, NULL );
    if( hr != DD_OK )
        return hr;
 
    /* Get a ptr to an IDirectDraw4 interface. This interface to DirectDraw represents the DX6 version of the API.*/
    hr = g_pDD1->lpVtbl->QueryInterface( g_pDD1, &IID_IDirectDraw4, (LPVOID *) &g_pDD4 );
    if( FAILED( hr ) )
 		return hr;
 
    M_ReleaseD3DObject( g_pDD1 );
 
    /*
     * Get driver caps
     */
    g_stDDCaps.dwSize = sizeof( DDCAPS );
    g_pDD4->lpVtbl->GetCaps( g_pDD4, &g_stDDCaps, NULL );
    
 
    return DD_OK;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : change display mode
 ----------------------------------------------------------------------------------------
 */
HRESULT GLI_DRV_hChangeMode( BOOL _bFullScreen, long _lWidth, long _lHeight, long _lBpp )
{
    HRESULT hr;
 
    if (!GLI_MDRV_xIsGliInit())
        return 0;
    
    GLI_fn_hRelease3DEnvironment( FALSE );
    hr = GLI_fn_hInitialize3DEnvironment( g_hWnd, _bFullScreen, _lWidth, _lHeight, _lBpp );
	if (hr == DD_OK)
		GLI_fn_hRestoreSurfaces();
    return hr;
}
 
   
#ifdef __cplusplus
} /*extern "C"*/
#endif
