/*
 =======================================================================================
  Name        : Init_Glide2.c
  Author      : GliGlou     
  Description :
 =======================================================================================
 */
 
/*
 =======================================================================================
    Include 
 =======================================================================================
 */
/*#ifdef _DEBUG*/
 
#define INITGUID
#include <ddraw.h>
 
/*#endif*/
 
#define __MSC__
#include <glide.h>
 
#include "init_gli.h"
#include "gli_st.h"
#include "GLI_Defn.h"
#include "light_st.h"
#include "PvObj_st.h"
#include "DLLCom.h"
#include "GLIBench.h"
 
#include "tmr.h"
#include "prf.h" 
 
 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#ifdef __cplusplus
extern "C" 
{
#endif
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
/*
 =======================================================================================
    Protos
 =======================================================================================
 */
void GLI_DRV_xClearViewingList ( void );
long GLI_fn_lGetTotalTextureMemorySize( void );
void GLI_fn_vInitRenderParameters( void );
 
/*
 =======================================================================================
    Structure
 =======================================================================================
 */
typedef struct tdstGlideResolution_
{
    long            lCode;
    unsigned long   ulWidth;
    unsigned long   ulHeight;
    long            lAlreadyAdded;
} tdstGlideResolution;
 
/*
 =======================================================================================
    Globals
 =======================================================================================
 */
tdstGlideResolution g_a_stGlideRes[16] =
{
    {GR_RESOLUTION_320x200  , 320, 200, 0 },   
    {GR_RESOLUTION_320x240  , 320, 240, 0 },   
    {GR_RESOLUTION_400x256  , 400, 256, 0 },   
    {GR_RESOLUTION_512x384  , 512, 384, 0 },   
    {GR_RESOLUTION_640x200  , 640, 200, 0 },   
    {GR_RESOLUTION_640x350  , 640, 350, 0 },   
    {GR_RESOLUTION_640x400  , 640, 400, 0 },   
    {GR_RESOLUTION_640x480  , 640, 480, 0 },   
    {GR_RESOLUTION_800x600  , 800, 600, 0 },   
    {GR_RESOLUTION_960x720  , 960, 720, 0 },   
    {GR_RESOLUTION_856x480  , 856, 480, 0 },   
    {GR_RESOLUTION_512x256  , 512, 256, 0 }
//    {GR_RESOLUTION_1024x768 ,1024, 768, 0 },  
//    {GR_RESOLUTION_1280x1024,1280,1024, 0 }, 
//    {GR_RESOLUTION_1600x1200,1600,1200, 0 }, 
//    {GR_RESOLUTION_400x300  , 400, 300, 0 }
};
 
#define  DEST_WIDTH  320
#define  DEST_HEIGHT 200
 
long                            g_lDestWidth, g_lDestHeight;
long                            g_lDestWidthInit, g_lDestHeightInit;
 
GrHwConfiguration               hwconfig;
long                            GLI_gl_MaxTmuAvailable; 
/*
 * for windowed mode
 */
 
static BOOL                    gs_bIsWindowed = TRUE;
static HWND                    gs_hWnd = NULL;
static LPDIRECTDRAW            gs_lpDD = NULL;
static LPDIRECTDRAW2           gs_lpDD2 = NULL;
static LPDIRECTDRAWSURFACE     gs_lpDDSFront = NULL;
static LPDIRECTDRAWSURFACE     gs_lpDDSBack = NULL;
static LPDIRECTDRAWCLIPPER     gs_lpDDClipper = NULL;
static BOOL                    gs_bCanReleaseDDObject = TRUE;
 
#ifndef RETAIL
	#if defined (BART_TEST)
		BOOL g_b_IWantToKeepFullScreenDrawingWhileDebugging = TRUE;
	#else
		BOOL g_b_IWantToKeepFullScreenDrawingWhileDebugging = FALSE;
	#endif /*BART_TEST*/
#endif /* RETAIL */
 
BOOL g_bOptimizedWindowedMode = FALSE;

/*
 =======================================================================================
    Bench function
 =======================================================================================
 */
#ifdef GLI_BENCH
void BENCH_M_DumpTriangleSurface()
{
    static char cDump = 0;
    float           a_fTriangle[ 1024 ];
    unsigned long   ulSurface;
    float           fCumul;
    float           fTotal;
    float           fTriangle;
    float           fPercent;
    float           fCumulPercent;
    float           fCote;
    float           fOccSurf;
    FILE            *hpFile;

    if (GetAsyncKeyState( VK_HOME) & 0x8000 )
        cDump = 1;

    if (!cDump)
        return;

    cDump = 0;

    hpFile = fopen( "TriangleSurface.txt", "wt" );
    if (hpFile == NULL)
        return;

    fprintf( hpFile, "répartition des triangles en fonction de la surface\nmoyenne sur %d render\n\nSurface\t~ Côté\tTriangles\tCumul\t\%\t\% cumulés\t~ Surface occupée\n\n", GLI_BIG_GLOBALS->GLD_RenderingCounter);

    fTotal = 0;
    for (ulSurface = 0; ulSurface < 1024; ulSurface++ )
    {
        a_fTriangle[ ulSurface ] = (float) ceil(((float) GLI_MDRV_g_p_stBench->lTrianglePerSurface[ ulSurface ])/ ((float) GLI_BIG_GLOBALS->GLD_RenderingCounter));
        fTotal += a_fTriangle[ ulSurface ];
    }

    fCumul = 0;
    for (ulSurface = 0; ulSurface < 1024; ulSurface++ )
    {
        fTriangle = a_fTriangle[ ulSurface ];
        fCumul += fTriangle;
        fCote = (float) sqrt( 2 * ulSurface );
        fPercent = (float) (fTriangle / fTotal );
        fCumulPercent = (float)(fCumul / fTotal );
        fOccSurf = (fTriangle * ulSurface) / 1000;

        fprintf( hpFile,"%d\t%f\t%.0f\t%.0f\t%.2f\t%.2f\t%.3f\n", 
                    ulSurface, fCote, fTriangle, fCumul, fPercent, fCumulPercent, fOccSurf );
    }

    fclose( hpFile );
}

#else
#define BENCH_M_DumpTriangleSurface()
#endif
 
/*
 =======================================================================================
    function use for windowed mode
 =======================================================================================
 */
void GLI_fn_vActualizeModeDevice() /*GLI_fn_vChangeModeDevice()*/
{
	if (g_bOptimizedWindowedMode)
	{
		g_lDestWidth = (gs_bIsWindowed) ? DEST_WIDTH : g_lDestWidthInit;
		g_lDestHeight = (gs_bIsWindowed) ? DEST_HEIGHT : g_lDestHeightInit;
	}
	else
	{
		g_lDestWidth = g_lDestWidthInit;
		g_lDestHeight = g_lDestHeightInit;
	}
}
 
 
BOOL __declspec(dllexport) GLI_DRV_bWindowedModeIsOptimized(void)
{
	return g_bOptimizedWindowedMode;
}
 
void __declspec(dllexport) GLI_DRV_vOptimizedWindowedMode(void)
{
	g_bOptimizedWindowedMode = TRUE;
	GLI_fn_vActualizeModeDevice();
}
 
void __declspec(dllexport) GLI_DRV_vNonOptimizedWindowedMode(void)
{
	g_bOptimizedWindowedMode = FALSE;
	GLI_fn_vActualizeModeDevice();
}
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : release directX object created for windowed mode
 ----------------------------------------------------------------------------------------
 */
void GLI_fn_vReleaseDDObject( void )
{
	int i = 0;
 
	while (!gs_bCanReleaseDDObject)
	{
		i++;
	}
    if (gs_lpDDClipper)
    {
        gs_lpDDClipper->lpVtbl->Release( gs_lpDDClipper );
        gs_lpDDClipper = NULL;
    }
    
    if (gs_lpDDSBack)
    {
        gs_lpDDSBack->lpVtbl->Release( gs_lpDDSBack );
        gs_lpDDSBack = NULL;
    }
 
    if (gs_lpDDSFront)
    {
        gs_lpDDSFront->lpVtbl->Release( gs_lpDDSFront );
        gs_lpDDSFront = NULL;
    }
 
    if (gs_lpDD2)
    {
        gs_lpDD2->lpVtbl->Release(gs_lpDD2);
        gs_lpDD2 = NULL;
    }
 
    if (gs_lpDD)
    {
        gs_lpDD->lpVtbl->Release(gs_lpDD);
        gs_lpDD = NULL;  
    }
 
	gs_bCanReleaseDDObject = TRUE; /* just in case !*/
}
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : prepare display for windowed mode
 ----------------------------------------------------------------------------------------
 */
BOOL __declspec(dllexport) GLI_DRV_bPrepareForGliWindowed( HWND _hWnd )
{
    HRESULT             hr;
    DDSURFACEDESC       ddsd;
    RECT                rcWindow;
 
	gs_bIsWindowed  = FALSE;
    gs_hWnd         = _hWnd;
 
    /* Create Direct draw object*/
    hr = DirectDrawCreate( NULL, &gs_lpDD, NULL );
    if( hr != DD_OK )
    {
        gs_lpDD = NULL;
        return FALSE;
    }
 
    /* Get the DirectDraw2 object*/
    hr = gs_lpDD->lpVtbl->QueryInterface(gs_lpDD, &IID_IDirectDraw2, (LPVOID *)&gs_lpDD2 );
    if( hr != DD_OK )
    {
		gs_bCanReleaseDDObject = TRUE;
        GLI_fn_vReleaseDDObject();
        return FALSE;
    }
 
    /* Set cooperative level to normal*/
    hr = gs_lpDD2->lpVtbl->SetCooperativeLevel( gs_lpDD2, _hWnd, DDSCL_NORMAL );
    if ( hr != DD_OK )
    {
		gs_bCanReleaseDDObject = TRUE;
        GLI_fn_vReleaseDDObject();        
        return FALSE; /*Can't get normal mode*/
    }
 
    /* Creation of primary surface*/
    memset( &ddsd, 0, sizeof( DDSURFACEDESC ) );
    ddsd.dwSize = sizeof( DDSURFACEDESC );
	ddsd.dwFlags = DDSD_CAPS;
    ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;
 
	gs_bCanReleaseDDObject = FALSE;
	hr = gs_lpDD2->lpVtbl->CreateSurface(gs_lpDD2, &ddsd, &gs_lpDDSFront, NULL );
    if ( hr != DD_OK )
    {
		gs_bCanReleaseDDObject = TRUE;
        GLI_fn_vReleaseDDObject();
        return FALSE; /*Can't create primary surface*/
    }
 
    /* Creation of DirectDraw Clipper*/
    hr = gs_lpDD2->lpVtbl->CreateClipper(gs_lpDD2, 0, &gs_lpDDClipper, NULL );
    if ( hr != DD_OK )
    {
		gs_bCanReleaseDDObject = TRUE;
        GLI_fn_vReleaseDDObject();
        return FALSE;
    }
    
    /* Associate clipper with Window*/
    hr = gs_lpDDClipper->lpVtbl->SetHWnd(gs_lpDDClipper, 0, _hWnd );
    if( hr != DD_OK )
    {
		gs_bCanReleaseDDObject = TRUE;
        GLI_fn_vReleaseDDObject();
        return FALSE; /*Can't create clipper*/
    }
 
    hr = gs_lpDDSFront->lpVtbl->SetClipper(gs_lpDDSFront, gs_lpDDClipper );
    if ( hr != DD_OK )
    {
		gs_bCanReleaseDDObject = TRUE;
        GLI_fn_vReleaseDDObject();
        return FALSE; /*Can't create clipper*/
    } 
 
    GetClientRect( _hWnd, &rcWindow );
 
    memset( &ddsd, 0, sizeof( DDSURFACEDESC ) );
    ddsd.dwSize = sizeof( DDSURFACEDESC );
    ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH;
    ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
 
	gs_bIsWindowed  = TRUE; /*Bart990105*/
	GLI_fn_vActualizeModeDevice();
 
	ddsd.dwHeight = g_lDestHeight;
	ddsd.dwWidth = g_lDestWidth;
 
    /* Back buffer*/
    hr = gs_lpDD2->lpVtbl->CreateSurface(gs_lpDD2, &ddsd, &gs_lpDDSBack, NULL );
    if ( hr != DD_OK )
    {
		gs_bCanReleaseDDObject = TRUE;
	    gs_bIsWindowed = FALSE; /* bart990126*/
        GLI_fn_vReleaseDDObject();
        return FALSE; /*Can't create clipper*/
    } 
	
#ifndef RETAIL
	if (!g_b_IWantToKeepFullScreenDrawingWhileDebugging)
#endif /*RETAIL*/
		grSstControl( GR_CONTROL_DEACTIVATE);
 
	gs_bCanReleaseDDObject = TRUE;
 
	return TRUE; /* BART*/
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : something to do when app is activate/deactivate
 ----------------------------------------------------------------------------------------
 */
void __declspec(dllexport) GLI_DRV_vActivateGli( HWND _hWnd, BOOL _bActivate )
{
	gs_bIsWindowed = !_bActivate;
    if (_bActivate)
        grSstControl( GR_CONTROL_ACTIVATE);
    else
        grSstControl( GR_CONTROL_DEACTIVATE);
}
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : prepare display for full screen mode
 ----------------------------------------------------------------------------------------
 */
void __declspec(dllexport) GLI_DRV_vPrepareForGliFullScreen( HWND _hWnd )
{
	int i = 0;
 
	while (!gs_bCanReleaseDDObject)
	{
		i++;
	}
    g_lDestWidth = g_lDestWidthInit;
    g_lDestHeight = g_lDestHeightInit;
    gs_bIsWindowed = FALSE; /* bart990126*/
    GLI_fn_vReleaseDDObject();
    /*gs_bIsWindowed = FALSE;*/
    grSstControl( GR_CONTROL_ACTIVATE);
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : copy 3DFX back buffer into D3D back buffer
 ----------------------------------------------------------------------------------------
 */
void GLI_fn_vCopyBackBufferToD3DBackBuffer()
{
    GrLfbInfo_t     info;
    DDSURFACEDESC   ddsd;
    unsigned long   *p_sourceptr , *p_sourceptrLast , *p_destptr ,lYCounterLocal, lSizeX,lSizeY,lPitch;
    HRESULT         ddrval;     
    POINT           pt;
    RECT            rcDest, rcSrc;
 
    memset( &ddsd, 0, sizeof( DDSURFACEDESC ) );
    ddsd.dwSize = sizeof( DDSURFACEDESC );
 
	gs_bCanReleaseDDObject = FALSE;
 
	if ( (gs_lpDDSBack == NULL) || (gs_lpDDSFront == NULL) )
	{
		gs_bCanReleaseDDObject = TRUE;
        return; /*tu t'es fais avoir !*/
	}
 
	grLfbLock( GR_LFB_READ_ONLY, 	GR_BUFFER_BACKBUFFER,GR_LFBWRITEMODE_565, GR_ORIGIN_UPPER_LEFT, FXFALSE, &info);
    ddrval = IDirectDrawSurface_Lock(gs_lpDDSBack, NULL, &ddsd, DDLOCK_WAIT, NULL );
    if (ddrval == DD_OK)
    {
        lSizeX = ddsd.dwWidth;
        lSizeY =ddsd.dwHeight;
        lPitch =ddsd.lPitch;
        for (lYCounterLocal = 0; lYCounterLocal < lSizeY ; lYCounterLocal++)
        {
//            p_sourceptr  = ((unsigned long *)info.lfbPtr) + 512L /*pitch 3dfx */  * lYCounterLocal ;
			p_sourceptr  = ((unsigned long *)info.lfbPtr) + (info.strideInBytes >> 2) /*pitch 3dfx */  * lYCounterLocal ;
            p_destptr = ((unsigned long *)ddsd.lpSurface) + (lPitch >>2) * lYCounterLocal ;
            p_sourceptrLast = p_sourceptr  + (lSizeX  >>1);
            for (;p_sourceptr < p_sourceptrLast ;p_sourceptr ++,p_destptr ++)
                *p_destptr = *p_sourceptr ;
        }
        IDirectDrawSurface_Unlock(gs_lpDDSBack, ddsd.lpSurface );
    }
    grLfbUnlock( GR_LFB_READ_ONLY, GR_BUFFER_BACKBUFFER);
 
    rcSrc.top = 0;
    rcSrc.left = 0;
 
#ifdef _DEBUG
	if (g_bOptimizedWindowedMode) {
		assert (g_lDestWidth == DEST_WIDTH);
		assert (g_lDestHeight == DEST_HEIGHT); }
#endif /* _DEBUG*/
	
    rcSrc.right = g_lDestWidth;
    rcSrc.bottom = g_lDestHeight;
 
    GetClientRect( gs_hWnd, &rcDest );
    pt.x = pt.y = 0;
    ClientToScreen( gs_hWnd, &pt );
    OffsetRect( &rcDest, pt.x, pt.y );
 
    do
    {
        ddrval = IDirectDrawSurface_Blt(gs_lpDDSFront, &rcDest, gs_lpDDSBack, &rcSrc, 0, NULL );
        if (ddrval == DDERR_SURFACELOST)
        {
            if( ( gs_lpDDSFront ) && ( gs_lpDDSFront->lpVtbl->IsLost(gs_lpDDSFront) ) )
                gs_lpDDSFront->lpVtbl->Restore(gs_lpDDSFront);
    
            /* Check/restore the back buffer*/
            if( ( gs_lpDDSBack ) && ( gs_lpDDSBack->lpVtbl->IsLost(gs_lpDDSBack) ) )
                gs_lpDDSBack->lpVtbl->Restore(gs_lpDDSBack);
        }
		/*
		else if (ddrval == DDERR_INVALIDRECT)
		{
			GetClientRect( gs_hWnd, &rcDest ); // try again !
			pt.x = pt.y = 0;
			ClientToScreen( gs_hWnd, &pt );
			OffsetRect( &rcDest, pt.x, pt.y );
		}
		else if (ddrval != DD_OK )
		{
			gs_bCanReleaseDDObject = TRUE;
			return; //tu t'es fais avoir !
		}
		*/
    } while (ddrval == DDERR_SURFACELOST); /* (ddrval != DD_OK );*/
 
	gs_bCanReleaseDDObject = TRUE;
}

/*
 =======================================================================================
    Lock / unlock backbuffer 
 =======================================================================================
 */
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Lock (return pointer on virtual screen and pitch value)
 ----------------------------------------------------------------------------------------
 */
BOOL GLI_DRV_bLockDevice( void **_pp_vVirtualScreen, long *_p_lPitch )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    GrLfbInfo_t  info;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    grLfbLock(	GR_LFB_WRITE_ONLY, 	GR_BUFFER_BACKBUFFER,GR_LFBWRITEMODE_565, GR_ORIGIN_UPPER_LEFT, FXFALSE, &info);
    *_pp_vVirtualScreen = info.lfbPtr;
    *_p_lPitch = info.strideInBytes;
 
    return TRUE;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : UnLock
 ----------------------------------------------------------------------------------------
 */
BOOL GLI_DRV_bUnlockDevice( void )
{
    grLfbUnlock( GR_LFB_WRITE_ONLY, GR_BUFFER_BACKBUFFER);
    return TRUE;
}
 
/*
 =======================================================================================
    Init / close
 =======================================================================================
 */

/*
 ----------------------------------------------------------------------------------------
  Description   : Set capabilities
 ----------------------------------------------------------------------------------------
 */
void VD1_fnv_SetCaps( tdstGliCaps *_pst_Caps, GrHwConfiguration *_pst_HwConfig )
{
    memset( _pst_Caps, 0, sizeof( tdstGliCaps ) );

    switch (_pst_HwConfig->SSTs[0].type)
    {
        case GR_SSTTYPE_VOODOO:
            GLI_gl_MaxTmuAvailable = hwconfig.SSTs[0].sstBoard.VoodooConfig.nTexelfx;
            _pst_Caps->ulTotalVideoMemory = hwconfig.SSTs[0].sstBoard.VoodooConfig.fbRam * (1024 * 1024);
            break;
        case GR_SSTTYPE_SST96:
            GLI_gl_MaxTmuAvailable = hwconfig.SSTs[0].sstBoard.SST96Config.nTexelfx;
            _pst_Caps->ulTotalVideoMemory = hwconfig.SSTs[0].sstBoard.SST96Config.fbRam * (1024 * 1024);
            break;
        case GR_SSTTYPE_AT3D:
            GLI_gl_MaxTmuAvailable = 1;
            break;
    }

    _pst_Caps->ulDriverCaps                 = GLICAPS_DRV_C_ulIsHardware | GLICAPS_DRV_C_ulCanBeWindowed /*| GLICAPS_DRV_C_ulSupportAlphaTest*/;
    _pst_Caps->ulTextureCaps                = GLICAPS_TEX_C_ulSupport8P | GLICAPS_TEX_C_ulSupportNonSquare | GLICAPS_TEX_C_ulSupportMipmap;
    _pst_Caps->ulTextureMaxSize             = 256;
    _pst_Caps->ulTotalTextureMemory         = GLI_fn_lGetTotalTextureMemorySize();
    _pst_Caps->ulTotalAGPMemory             = 0;
    _pst_Caps->ucPrimarySurfacePixelFormat  = GLD_C_xR5G6B5PixelFormat;

    /* Compute refresh rate */
    if( TMR_MDRV_vTimerGetCounter && TMR_MDRV_ulTimerTickPerSecond )
    {
        stTimerCount stTimerBefore, stTimerAfter;
        int i;

        while( grSstVRetraceOn() == FXTRUE )
            ;
        while( grSstVRetraceOn() != FXTRUE )
            ;

        TMR_MDRV_vTimerGetCounter( C_wTimerFrequencyMedium, &stTimerBefore );
        for( i=0; i<10; i++ )
        {
            while( grSstVRetraceOn() == FXTRUE )
                ;
            while( grSstVRetraceOn() != FXTRUE )
                ;
        }
        TMR_MDRV_vTimerGetCounter( C_wTimerFrequencyMedium, &stTimerAfter );
 
        _pst_Caps->fRefreshRate = 
            (float)floor( 
                0.5f + 
                ((float) i * TMR_MDRV_ulTimerTickPerSecond(C_wTimerFrequencyMedium))
                    / ((float)abs( stTimerAfter.m_ulLowPart - stTimerBefore.m_ulLowPart) ) );
    }
    else
        _pst_Caps->fRefreshRate                 = 60.0f;
}

 
/*
 ----------------------------------------------------------------------------------------
  Description   : open Glide with good resolution
 ----------------------------------------------------------------------------------------
 */
long fn_lChooseResolution( HWND _hWnd, BOOL _bFullScreen, long _lWidth, long _lHeight, long _lBpp )
{
    int iResIndex;
    long lContext;
    GrScreenResolution_t GrResolutionChoosen;
  
    GrResolutionChoosen = GR_RESOLUTION_NONE;
    for (iResIndex = 0; iResIndex < 12; iResIndex++)
    {
        if ( (g_a_stGlideRes[iResIndex].ulWidth == (unsigned long) _lWidth) && (g_a_stGlideRes[iResIndex].ulHeight == (unsigned long) _lHeight) )
        {
            GrResolutionChoosen = g_a_stGlideRes[iResIndex].lCode;
            break;
        }
    }
 
    if ( GrResolutionChoosen!= GR_RESOLUTION_NONE)
        lContext = grSstWinOpen( (FxU32) _hWnd, GrResolutionChoosen, GR_REFRESH_85Hz, GR_COLORFORMAT_ARGB, GR_ORIGIN_UPPER_LEFT, 2, 1 ) ;
  
    if (lContext) 
    {
	    gs_bIsWindowed = (_bFullScreen) ? 0 : 1;
 
        g_lDestWidthInit = _lWidth;
        g_lDestHeightInit = _lHeight;
 
		GLI_fn_vActualizeModeDevice();
    }
 
    return lContext;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : init driver
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_xInitDriver( HWND _hWnd, BOOL _bFullScreen, long _lWidth, long _lHeight, long _lBpp )
{
    grGlideInit();
    grSstQueryHardware( &hwconfig );
    grSstSelect( 0 );
 
    fn_lChooseResolution(_hWnd, _bFullScreen, _lWidth, _lHeight, _lBpp);
 
    grDepthBufferMode( GR_DEPTHBUFFER_WBUFFER );
    grDepthBufferFunction( GR_CMP_LESS );
    grDepthMask( FXTRUE );
    MMG_MDRV_vAddMemoryInfo (MMG_C_lTypeGLI , MMG_C_lSubTypeZList , NULL);
    GLI_BIG_GLOBALS -> p_TheZListe = (GLI_tdstZListe *) GLI_MDRV_p_vTmpMalloc(sizeof(GLI_tdstZListe));
    memset (GLI_BIG_GLOBALS -> p_TheZListe , 0 , sizeof(GLI_tdstZListe));
    MMG_MDRV_vAddMemoryInfo(MMG_C_lTypeGLI , MMG_C_lSubTypeZList , NULL);
    GLI_BIG_GLOBALS -> p_TheZListe -> p_TableOfPoints = GLI_MDRV_p_vTmpMalloc((3L * sizeof (GrVertex))<<GLI_MaxZListeTrianglesPO2);
    GLI_BIG_GLOBALS -> ulCurrentZTable = 0;
    GLI_DRV_xClearViewingList();
 
    grTexFilterMode(0,GR_TEXTUREFILTER_BILINEAR,GR_TEXTUREFILTER_BILINEAR );
    grTexFilterMode(1,GR_TEXTUREFILTER_BILINEAR,GR_TEXTUREFILTER_BILINEAR );
    grTexLodBiasValue(0, -1.0f );
    grTexLodBiasValue(1, -1.0f );
    GLI_BIG_GLOBALS -> ulCurrentZTable = 0;
 
    /* get fog distance value */
    {
        long lIndex;
        extern float GLI_ga_fFogDist[ GR_FOG_TABLE_SIZE ];
 
        for (lIndex = 0; lIndex < GR_FOG_TABLE_SIZE; lIndex++)
            GLI_ga_fFogDist[lIndex] = guFogTableIndexToW(lIndex) * GLI_C_xZClippingNear;
    }
 
    /*
     * Init render parameters
     */
    GLI_fn_vInitRenderParameters();
 
    /*
     * Set driver capabilities
     */
    VD1_fnv_SetCaps( g_p_stGliCaps, &hwconfig );
    
}
    
/*
 ----------------------------------------------------------------------------------------
  Description   : close driver
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vCloseDriver()
{
    /*grSstWinClose();*/
    grGlideShutdown();
    GLI_MDRV_vTmpFree( GLI_BIG_GLOBALS->p_TheZListe->p_TableOfPoints );
    GLI_MDRV_vTmpFree( GLI_BIG_GLOBALS->p_TheZListe );
}
    
/*
 =======================================================================================
    Clear 
 =======================================================================================
 */
 
/*
 ----------------------------------------------------------------------------------------
  Description   : clear Z buffer 
  use only to display second viewport
  to accelerate we do not do clear but we set a variable.
  When this var is set all z coordinates are multiplicated by a factor to be sure that
  triangle will be in front all already drawn
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vClearZBufferRegion(long lXStart,long lXEnd,long lYStart,long lYEnd)
{
	/*
    grDepthMask( FXTRUE );
	grColorMask( FXFALSE, FXFALSE );
	grBufferClear( 0, 0, GR_WDEPTHVALUE_FARTHEST  );
	grColorMask( FXTRUE, FXFALSE );
    */
	/*if (!GLI_BIG_GLOBALS->bDrawMirrorSymetric)*/
		GLI_BIG_GLOBALS->lDisplayMenuIsDetected = 1;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : set a var to say we are drawing mirror texture
 ----------------------------------------------------------------------------------------
 */
void GLI_vBeginDrawingTexturedMirrors(void)
{
    GLI_BIG_GLOBALS->bDrawMirrorSymetric = 1;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : set a var to say we are drawing in mirror surface
 ----------------------------------------------------------------------------------------
 */
void GLI_vBeginDrawingTexturedMirrorsSurfaces()
{
    GLI_BIG_GLOBALS->lAMirrorIsDetected = 3;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : end draw mirror
 ----------------------------------------------------------------------------------------
 */
void GLI_vEndDrawingTexturedMirrors()
{
    GLI_BIG_GLOBALS->lAMirrorIsDetected &= 1;
    GLI_BIG_GLOBALS->bDrawMirrorSymetric = 0;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : clear device
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vClearDevice(BOOL ZBuffer, BOOL ColorBuffer, unsigned long Color)
{
    if (GLI_MDRV_xIsGliInit())
    {
        if (ColorBuffer)  
            grColorMask( FXTRUE, FXFALSE );
        else
            grColorMask( FXFALSE, FXFALSE );
        if (ZBuffer)  
            grDepthMask( FXTRUE );
        else 
            grDepthMask( FXFALSE );
        grBufferClear( Color, 0, GR_WDEPTHVALUE_FARTHEST  );
        grColorMask( FXTRUE, FXFALSE );
        grDepthMask( FXTRUE );
    }
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : flip front and back buffer
 ----------------------------------------------------------------------------------------
 */
 
void GLI_DRV_vFlipDevice(long lNbFrames)
{
 
    if (!GLI_MDRV_xIsGliInit()) 
        return;
 
#if !defined(PRESS_DEMO)
    PRF_MDRV_vStartChrono( PRF_C_ulWaitFor3dFx , NULL);
#endif /* PRESS_DEMO */

    GLI_BIG_GLOBALS->lDisplayMenuIsDetected = 0;
    GLI_BIG_GLOBALS->lAMirrorIsDetected = 0;
    grSstIdle();
 
#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 ( gs_bIsWindowed )
    {
        GLI_fn_vCopyBackBufferToD3DBackBuffer();
#ifndef RETAIL
		if (g_b_IWantToKeepFullScreenDrawingWhileDebugging)
		    grBufferSwap( lNbFrames );
#endif /*RETAIL*/
    }
	else
	{
	
	    grBufferSwap( lNbFrames );
 
/*
	    do 
		   {
			   lNbFrames = grBufferNumPending();
		} while (lNbFrames != 0 );
*/
		grSstIdle();
 
	}
 
#if !defined(PRESS_DEMO)
    PRF_MDRV_vStopChrono  (PRF_C_ulFctFlip , NULL);
    PRF_MDRV_vStartChrono (PRF_C_ulFctMainLoop, NULL);

    BENCH_M_DumpTriangleSurface();
#endif /* PRESS_DEMO */
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Special flip with automatic syncro
 ----------------------------------------------------------------------------------------
 */
 
void GLI_DRV_vFlipDeviceWithSyncro()
{
    long lNbFrames;
 
    if (!GLI_MDRV_xIsGliInit()) 
        return;
 
#if !defined(PRESS_DEMO)
    PRF_MDRV_vStartChrono( PRF_C_ulWaitFor3dFx , NULL);
#endif /* PRESS_DEMO */

    GLI_BIG_GLOBALS->lDisplayMenuIsDetected = 0;
    GLI_BIG_GLOBALS->lAMirrorIsDetected = 0;
    grSstIdle();
 
#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 */
 
    lNbFrames = GLD_MDRV_fn_lComputeWaitFrameForSmoothSynchro();
 
    if ( gs_bIsWindowed )
    {
        GLI_fn_vCopyBackBufferToD3DBackBuffer();
#ifndef RETAIL
		if (g_b_IWantToKeepFullScreenDrawingWhileDebugging)
		    grBufferSwap( lNbFrames );
#endif /*RETAIL*/
    }
	else
	{
	
	    grBufferSwap( lNbFrames );
 
/*
	    do 
		   {
			   lNbFrames = grBufferNumPending();
		} while (lNbFrames != 0 );
*/
		grSstIdle();
 
	}
 
#if !defined(PRESS_DEMO)
    PRF_MDRV_vStopChrono  (PRF_C_ulFctFlip , NULL);
    PRF_MDRV_vStartChrono (PRF_C_ulFctMainLoop, NULL);

    BENCH_M_DumpTriangleSurface();
#endif /* PRESS_DEMO */
}

 
/*
 ----------------------------------------------------------------------------------------
 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 )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    GrSstPerfStats_t    stStats;
    unsigned long       ulScreenSize;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    if (!GLI_MDRV_xIsGliInit())
        return;
 
    grSstPerfStats( &stStats );
 
    ulScreenSize            = 480 * 640 / 100;
    *_p_ulPixelsSent        = stStats.pixelsIn / ulScreenSize;
    *_p_ulPixelsDisplayed   = (stStats.pixelsIn - stStats.chromaFail - stStats.zFuncFail - stStats.aFuncFail)  / ulScreenSize;
 
    grSstResetPerfStats();
}
 
/*
----------------------------------------------------------------------------------------
Description   : WaitRetrace(
----------------------------------------------------------------------------------------
*/

void GLI_DRV_vWaitRetrace(void)
{
	while (!grSstVRetraceOn());
	while (grSstVRetraceOn());
}

 
/*
 ----------------------------------------------------------------------------------------
  Description   : test a display mode
 ----------------------------------------------------------------------------------------
 */
BOOL fn_bIsAValidResolution(GrScreenResolution_t _ScreenResolution) 
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    GrHwConfiguration hwconfig;
    BOOL bResult;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    bResult = FALSE;
 
    grGlideInit();
    if (grSstQueryHardware(&hwconfig)) 
    {
	    grSstSelect(0);
        bResult = grSstWinOpen( 0, _ScreenResolution, GR_REFRESH_85Hz, GR_COLORFORMAT_ARGB, GR_ORIGIN_UPPER_LEFT, 2, 1 ) ;
        if (bResult)
            grSstWinClose();
    }
    return bResult;
}
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : enumerate display mode
 ----------------------------------------------------------------------------------------
 */
long __declspec(dllexport) GLI_DRV_fnl_EnumModes( char *_sz_DriverName, char *_sz_DeviceName )
{
    int iResIndex;
 
    for (iResIndex = 0; iResIndex < 12; iResIndex++)
    {
        if (fn_bIsAValidResolution(g_a_stGlideRes[iResIndex].lCode))
        {
            g_a_stGlideRes[iResIndex].lAlreadyAdded = 1;
            GLI_MDRV_lAddDisplayMode( 1, g_a_stGlideRes[iResIndex].ulWidth, g_a_stGlideRes[iResIndex].ulHeight, 16 );
        }
    }
    return 1;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : change mode
 ----------------------------------------------------------------------------------------
 */
HRESULT GLI_DRV_hChangeMode( BOOL _bFullScreen, long _lWidth, long _lHeight, long _lBpp )
{
/*
    HRESULT hr;
 
    if (!GLI_MDRV_xIsGliInit())
        return 0;
  
    hr = fn_lChooseResolution(0, _bFullScreen, _lWidth, _lHeight, _lBpp);
 
    return (hr == 0) ? 1 : 0;
    */
	return 0;
} 

long (*gpfnl_AddDisplayInfo) (long, long, long , char*, unsigned long );

long __declspec(dllexport) GLI_DRV_fn_lGetAllDisplayConfig( FARPROC _x_Fct )
{
    int                 iResIndex;
    long                l_Disp, l_Dev, l_Mode;
    tdstGliCaps         stCaps;
    BOOL                bResult;
    
    gpfnl_AddDisplayInfo = (long (__cdecl *)( long, long, long, char *, unsigned long ) ) _x_Fct;

    if ( gpfnl_AddDisplayInfo(0, 0, 0, "miscvoodoodetect", 3) == 0)
        return 0;

    gpfnl_AddDisplayInfo( 0, 0, 0, "dll_bmp", 1);
    
    l_Disp = gpfnl_AddDisplayInfo( 0, 0, 0, "dispadd", 0 );
    gpfnl_AddDisplayInfo( l_Disp, 0, 0, "dispname", (long) "" );
    gpfnl_AddDisplayInfo( l_Disp, 0, 0, "dispdesc", (long) "---" );

    l_Dev = gpfnl_AddDisplayInfo( l_Disp, 0, 0, "dev_add", 0 );
    gpfnl_AddDisplayInfo( l_Disp, l_Dev, 0, "dev_name", (long) "" );
    gpfnl_AddDisplayInfo( l_Disp, l_Dev, 0, "dev_desc", (long) "---" );

    grGlideInit();

    if (grSstQueryHardware(&hwconfig)) 
    {
	    grSstSelect(0);

        for (iResIndex = 0; iResIndex < 12; iResIndex++)
        {
            bResult = grSstWinOpen( 0, g_a_stGlideRes[iResIndex].lCode, GR_REFRESH_85Hz, GR_COLORFORMAT_ARGB, GR_ORIGIN_UPPER_LEFT, 2, 1 ) ;
            if (bResult)
            {
                grSstWinClose();
                l_Mode = gpfnl_AddDisplayInfo( l_Disp, l_Dev, 0, "modeadd", 0 );
                gpfnl_AddDisplayInfo( l_Disp, l_Dev, l_Mode, "modefs", 1 );
                gpfnl_AddDisplayInfo( l_Disp, l_Dev, l_Mode, "modebpp", 16 );
                gpfnl_AddDisplayInfo( l_Disp, l_Dev, l_Mode, "modew", g_a_stGlideRes[iResIndex].ulWidth );
                gpfnl_AddDisplayInfo( l_Disp, l_Dev, l_Mode, "modeh", g_a_stGlideRes[iResIndex].ulHeight );
            }
        }
    }

    VD1_fnv_SetCaps( &stCaps, &hwconfig );
    gpfnl_AddDisplayInfo( l_Disp, l_Dev, 0, "dev_caps", (long) &stCaps );

    grGlideShutdown();

    return 1;
}
 
 
 
#ifdef __cplusplus
} /*extern "C"*/
#endif
