/*
 =======================================================================================
  Name        : Init_Glide2.c
  Author      : GliGlou     
  Description :
 =======================================================================================
 */

/*
 =======================================================================================
    Include 
 =======================================================================================
 */
#define INITGUID
#include <ddraw.h>

#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 "tmr.h"
#include "prf.h" 
#include "Glide2To3.h"

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#ifdef __cplusplus
extern "C" 
{
#endif
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

/*
 =======================================================================================
    Protos
 =======================================================================================
 */
void GLI_DRV_xClearViewingList ( void );
long GLI_fn_lGetTotalTextureMemorySize();
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 }
};


/*
 =======================================================================================
    Constants 
 =======================================================================================
 */
long			GLI_gl_MaxTmuAvailable; 

long            GLI_g_lNumberOfFogTableEntries;
GrContext_t     GLI_g_xGlideContext;
long            GLI_g_lWDepthMinMaxValue[2];
/*
 * for windowed mode
 */
#ifndef RETAIL

static BOOL                    gs_bIsWindowed = FALSE;
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;

#endif



/*
 =======================================================================================
    function use for windowed mode
 =======================================================================================
 */
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;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : release directX object created for windowed mode
 ----------------------------------------------------------------------------------------
 */
void GLI_fn_vReleaseDDObject( void )
{
    if (gs_lpDDClipper)
    {
        gs_lpDDClipper->lpVtbl->Release( gs_lpDDClipper );
        gs_lpDDClipper = NULL;
    }
    
    if (gs_lpDDSFront)
    {
        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;  
    }
}

/*
 ----------------------------------------------------------------------------------------
  Description   : prepare display for windowed mode
 ----------------------------------------------------------------------------------------
 */
BOOL __declspec(dllexport) GLI_DRV_bPrepareForGliWindowed( HWND _hWnd )
{
    HRESULT             hr;
    DDSURFACEDESC       ddsd;
    RECT                rcWindow;

    gs_bIsWindowed  = TRUE;
    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 )
    {
        GLI_fn_vReleaseDDObject();
        return FALSE;
    }

    // Set cooperative level to normal
    hr = gs_lpDD2->lpVtbl->SetCooperativeLevel( gs_lpDD2, _hWnd, DDSCL_NORMAL );
    if ( hr != DD_OK )
    {
        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;
    hr = gs_lpDD2->lpVtbl->CreateSurface(gs_lpDD2, &ddsd, &gs_lpDDSFront, NULL );
    if ( hr != DD_OK )
    {
        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 )
    {
        GLI_fn_vReleaseDDObject();
        return FALSE;
    }
    
    // Associate clipper with Window
    hr = gs_lpDDClipper->lpVtbl->SetHWnd(gs_lpDDClipper, 0, _hWnd );
    if( hr != DD_OK )
    {
        GLI_fn_vReleaseDDObject();
        return FALSE; //Can't create clipper
    }

    hr = gs_lpDDSFront->lpVtbl->SetClipper(gs_lpDDSFront, gs_lpDDClipper );
    if ( hr != DD_OK )
    {
        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;
    /*pstDevAttrib->dwHeight = */
    ddsd.dwHeight = rcWindow.bottom;
    //pstDevAttrib->dwWidth =
    ddsd.dwWidth = rcWindow.right;

    // Back buffer
    hr = gs_lpDD2->lpVtbl->CreateSurface(gs_lpDD2, &ddsd, &gs_lpDDSBack, NULL );
    if ( hr != DD_OK )
    {
        GLI_fn_vReleaseDDObject();
        return FALSE; //Can't create clipper
    } 

    grDisable ( GR_PASSTHRU );
    //GLI3grSstControl( GR_CONTROL_DEACTIVATE);

	return TRUE; // BART
}

/*
 ----------------------------------------------------------------------------------------
  Description   : prepare display for full screen mode
 ----------------------------------------------------------------------------------------
 */
void __declspec(dllexport) GLI_DRV_vPrepareForGliFullScreen( HWND _hWnd )
{
    GLI_fn_vReleaseDDObject();
    gs_bIsWindowed = FALSE;
    //GLI3grSstControl( GR_CONTROL_ACTIVATE);
    grEnable( GR_PASSTHRU );
}

/*
 ----------------------------------------------------------------------------------------
  Description   : copy 3DFX back buffer into D3D back bufer
 ----------------------------------------------------------------------------------------
 */
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 );

    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_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);

    GetClientRect( gs_hWnd, &rcDest );
    rcSrc.top = 0;
    rcSrc.left = 0;
    rcSrc.right = 640;
    rcSrc.bottom = 480;
    pt.x = pt.y = 0;
    ClientToScreen( gs_hWnd, &pt );
    OffsetRect( &rcDest, pt.x, pt.y );
    ddrval = IDirectDrawSurface_Blt(gs_lpDDSFront, &rcDest, gs_lpDDSBack, &rcSrc, 0, NULL );
}

/*
 =======================================================================================
    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 VD2_fnv_SetCaps( tdstGliCaps *_pst_Caps )
{
    memset( _pst_Caps, 0, sizeof( tdstGliCaps ) );

    _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;
}

/*
 ----------------------------------------------------------------------------------------
  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 < 16; 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_60Hz, GR_COLORFORMAT_ABGR, 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   : open Glide with good resolution
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_xInitDriver( HWND _hWnd, BOOL _bFullScreen, long _lWidth, long _lHeight, long _lBpp )
{
    grGlideInit();

    grGet( GR_NUM_TMU, 4, &GLI_gl_MaxTmuAvailable );
    grGet( GR_FOG_TABLE_ENTRIES, 4, &GLI_g_lNumberOfFogTableEntries );
    grGet( GR_WDEPTH_MIN_MAX, 8, (long *) &GLI_g_lWDepthMinMaxValue );

    grSstSelect( 0 );
    grVertexLayout(GR_PARAM_XY,  GR_VERTEX_X_OFFSET << 2, GR_PARAM_ENABLE);
    grVertexLayout(GR_PARAM_Z,   GR_VERTEX_OOZ_OFFSET << 2, GR_PARAM_ENABLE);
    //grVertexLayout(GR_PARAM_PARGB, GR_VERTEX_R_OFFSET << 2, GR_PARAM_ENABLE);
    grVertexLayout(GR_PARAM_RGB, GR_VERTEX_R_OFFSET << 2, GR_PARAM_ENABLE);
    grVertexLayout(GR_PARAM_A,   GR_VERTEX_A_OFFSET << 2, GR_PARAM_ENABLE);
    grVertexLayout(GR_PARAM_Q,   GR_VERTEX_OOW_OFFSET << 2, GR_PARAM_ENABLE);
    grVertexLayout(GR_PARAM_ST0, GR_VERTEX_SOW_TMU0_OFFSET << 2, GR_PARAM_ENABLE);
    grVertexLayout(GR_PARAM_Q0,  GR_VERTEX_OOW_TMU0_OFFSET << 2, GR_PARAM_DISABLE);
    grVertexLayout(GR_PARAM_ST1, GR_VERTEX_SOW_TMU1_OFFSET << 2, GR_PARAM_ENABLE);
    grVertexLayout(GR_PARAM_Q1,  GR_VERTEX_OOW_TMU1_OFFSET << 2, GR_PARAM_DISABLE);

    //grSstWinOpen( 0, GR_RESOLUTION_640x480, GR_REFRESH_60Hz, GR_COLORFORMAT_ABGR, GR_ORIGIN_UPPER_LEFT, 2, 1 ) ;
    //GLI_g_xGlideContext = grSstWinOpen( (FxU32) _hWnd, GR_RESOLUTION_640x480, GR_REFRESH_60Hz, GR_COLORFORMAT_ABGR, GR_ORIGIN_UPPER_LEFT, 2, 1 ) ;
    GLI_g_xGlideContext = 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 (GLI_tdScreenVertx))<<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[ 64 ];

        for (lIndex = 0; lIndex < GLI_g_lNumberOfFogTableEntries; lIndex++)
            GLI_ga_fFogDist[lIndex] = guFogTableIndexToW(lIndex) * GLI_C_xZClippingNear;
    }

    /* set format of vertices */
    grCoordinateSpace(GR_WINDOW_COORDS); 
    grViewport((FxU32)0, (FxU32)0, (FxU32)_lWidth, (FxU32)_lHeight);
    grDepthRange(0,1);
    grRenderBuffer( GR_BUFFER_BACKBUFFER );

    /*
     * Init render parameters
     */
    GLI_fn_vInitRenderParameters();
 
    /*
     * Set driver capabilities
     */
    VD2_fnv_SetCaps( g_p_stGliCaps );
}

    

void GLI_DRV_vCloseDriver()
{
    grSstWinClose( GLI_g_xGlideContext );
    grGlideShutdown();
    GLI_MDRV_vTmpFree( GLI_BIG_GLOBALS->p_TheZListe->p_TableOfPoints );
    GLI_MDRV_vTmpFree( GLI_BIG_GLOBALS->p_TheZListe );
}
    
/*
 =======================================================================================
    Clear 
 =======================================================================================
 */
void GLI_DRV_vClearZBufferRegion(long lXStart,long lXEnd,long lYStart,long lYEnd)
{
    if (!GLI_BIG_GLOBALS->bDrawMirrorSymetric)
        GLI_BIG_GLOBALS->lDisplayMenuIsDetected = 1;
}

void GLI_vBeginDrawingTexturedMirrors(void)
{
    GLI_BIG_GLOBALS->bDrawMirrorSymetric = 1;
}

void GLI_vBeginDrawingTexturedMirrorsSurfaces()
{
    GLI_BIG_GLOBALS->lAMirrorIsDetected = 3;
}

void GLI_vEndDrawingTexturedMirrors()
{
    GLI_BIG_GLOBALS->lAMirrorIsDetected &= 1;
    GLI_BIG_GLOBALS->bDrawMirrorSymetric = 0;
}

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 );
        //GLI3grBufferClear( Color, 0, GR_WDEPTHVALUE_FARTHEST  );
        grBufferClear( Color, 0, GLI_g_lWDepthMinMaxValue[1] );
        grColorMask( FXTRUE, FXFALSE );
        grDepthMask( FXTRUE );
    }
}

/*
 =======================================================================================
    Flip
 =======================================================================================
 */
void GLI_DRV_vFlipDevice(long lNbFrames)
{
    PRF_MDRV_vStartChrono( PRF_C_ulWaitFor3dFx , NULL);

    if (!GLI_MDRV_xIsGliInit()) 
        return;

    GLI_BIG_GLOBALS->lDisplayMenuIsDetected = 0;
    GLI_BIG_GLOBALS->lAMirrorIsDetected = 0;
    //grSstIdle();
    grFinish();

	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);

	grBufferSwap( lNbFrames );

	do 
	{
	    //lNbFrames = grBufferNumPending();
        grGet( GR_PENDING_BUFFERSWAPS, 4, &lNbFrames );
    }
	while (lNbFrames != 0 );

#ifdef _DEBUG
    if ( gs_bIsWindowed )
    {
        GLI_fn_vCopyBackBufferToD3DBackBuffer();
    }
#endif
		
	PRF_MDRV_vStopChrono  (PRF_C_ulFctFlip , NULL);
	PRF_MDRV_vStartChrono (PRF_C_ulFctMainLoop, NULL);
}


void GLI_DRV_vFlipDeviceWithSyncro( void )
{
	GLI_DRV_vFlipDevice( 1 );
}


/*
 ----------------------------------------------------------------------------------------
 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;
    unsigned long       ulPixelsIn, ulPixelsOut;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

    if (!GLI_MDRV_xIsGliInit())
        return;

    //grSstPerfStats( &stStats );
    grGet( GR_STATS_PIXELS_IN, 4, &ulPixelsIn );
    grGet( GR_STATS_PIXELS_OUT, 4, &ulPixelsOut );

	ulScreenSize            = 480 * 640 / 100;
	*_p_ulPixelsSent        = ulPixelsIn / ulScreenSize;
	*_p_ulPixelsDisplayed   = ulPixelsOut  / ulScreenSize;

	grReset( GR_STATS_PIXELS );
}



/*
 ----------------------------------------------------------------------------------------
  Description   : enumerate display mode
 ----------------------------------------------------------------------------------------
 */
long __declspec(dllexport) GLI_DRV_fnl_EnumModes( char *_sz_DriverName, char *_sz_DeviceName )
{
    GrResolution    stQuery;
    GrResolution    *p_stQueryResult;
    int             iListSize;
    int             iIndex;
    int             iResIndex;

    /* find all possible modes that include a z-buffer */
    grGlideInit();
    grSstSelect( 0 );
    stQuery.resolution = GR_QUERY_ANY;
    stQuery.refresh = GR_REFRESH_60Hz;
    stQuery.numColorBuffers = 2;
    stQuery.numAuxBuffers = 1;
    iListSize = grQueryResolutions( &stQuery, NULL );
    p_stQueryResult = malloc( iListSize );
    grQueryResolutions( &stQuery, p_stQueryResult );
    grGlideShutdown();
    
    iListSize /= sizeof(iListSize);
    for (iIndex = 0; iIndex < iListSize; iIndex++)
    {
        for (iResIndex = 0; iResIndex < 16; iResIndex++)
        {
            if (p_stQueryResult[iIndex].resolution == g_a_stGlideRes[iResIndex].lCode)
                break;
        }
        if (iResIndex < 16)
        {
            if ( !g_a_stGlideRes[iResIndex].lAlreadyAdded )
            {
                g_a_stGlideRes[iResIndex].lAlreadyAdded = 1;
                GLI_MDRV_lAddDisplayMode( 1, g_a_stGlideRes[iResIndex].ulWidth, g_a_stGlideRes[iResIndex].ulHeight, 16 );
            }
        }
    }
    
    free( p_stQueryResult );
    return 1;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : change mode
 ----------------------------------------------------------------------------------------
 */
HRESULT GLI_DRV_hChangeMode( BOOL _bFullScreen, long _lWidth, long _lHeight, long _lBpp )
{
    return 0;
}

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

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

    if ( gpfnl_AddDisplayInfo(0, 0, 0, "miscvoodoodetect", 2) == 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) "---" );

    {
        GrResolution    stQuery;
        GrResolution    *p_stQueryResult;
        int             iListSize;
        int             iIndex;
        int             iResIndex;

        /* find all possible modes that include a z-buffer */
        grGlideInit();
        grSstSelect( 0 );
        stQuery.resolution = GR_QUERY_ANY;
        stQuery.refresh = GR_REFRESH_60Hz;
        stQuery.numColorBuffers = 2;
        stQuery.numAuxBuffers = 1;
        iListSize = grQueryResolutions( &stQuery, NULL );
        p_stQueryResult = malloc( iListSize );
        grQueryResolutions( &stQuery, p_stQueryResult );
        grGlideShutdown();
    
        iListSize /= sizeof(iListSize);
        for (iIndex = 0; iIndex < iListSize; iIndex++)
        {
            for (iResIndex = 0; iResIndex < 16; iResIndex++)
            {
                if (p_stQueryResult[iIndex].resolution == g_a_stGlideRes[iResIndex].lCode)
                    break;
            }
            if (iResIndex < 16)
            {
                if ( !g_a_stGlideRes[iResIndex].lAlreadyAdded )
                {
                    g_a_stGlideRes[iResIndex].lAlreadyAdded = 1;
                    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 );
                }
            }
        }
    
        free( p_stQueryResult );

    }

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

    return 1;
}


#ifdef __cplusplus
} //extern "C"
#endif
