/*
 =======================================================================================
  Name        : DX6_Caps.c
  Author      : vincent lhullier            Date :30/10/98
  Description : capabilities of driver (depend on hardware)
 =======================================================================================
 */
#include "DLLCom.h"
#include "DX6_Choose.h"
#include "DX6_Caps.h"
 
extern LPDIRECTDRAW4			g_pDD4;
extern LPDIRECT3DDEVICE3		g_pd3dDevice;
extern LPDIRECTDRAWSURFACE4	    g_pddsPrimary;
 
/*
 =======================================================================================
    Globals 
 =======================================================================================
 */
static long             gs_lNumberOfPixelFormats;
static DDPIXELFORMAT	gs_a_stD3DPixelFormat[20];
static char             gs_a_cPixelFormatIndex[ GLI_DX6_TexNbFormats ];
 
static long             gs_a_lPrecalculatedTextureSize[GLI_DX6_TexNbFormats][2][9][9];
 
/*
 =======================================================================================
    private Functions prototypes
 =======================================================================================
 */
 
unsigned char GLI_DX6_fn_ucGetPrimarySurfacePixelFormat( LPDDPIXELFORMAT _p_stDDPF );
 
 
/*
 =======================================================================================
    public Functions 
 =======================================================================================
 */
 
/*
 ----------------------------------------------------------------------------------------
  Description   : compute video memory
 ----------------------------------------------------------------------------------------
 */
HRESULT GLI_DX6_hGetVideoMemory( LPDIRECTDRAW4 _pDD4, long _lDDSCaps, unsigned long *_ulTotal, unsigned long *_ulLeft )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    DDSCAPS2				stLocalVideoCaps;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    memset(&stLocalVideoCaps,0,sizeof(stLocalVideoCaps));
    stLocalVideoCaps.dwCaps = _lDDSCaps;
    return _pDD4->lpVtbl->GetAvailableVidMem( _pDD4 ,&stLocalVideoCaps,_ulTotal, _ulLeft );
}
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Get driver caps
 ----------------------------------------------------------------------------------------
 */
HRESULT GLI_DX6_fn_hGetDriverCaps( tdstGliCaps *_pst_Caps, long _lFlags, LPDIRECTDRAW4 _pDD4 )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    DDCAPS                  stHDDCaps;
    DDCAPS                  stSDDCaps;
    DDCAPS                  *p_stCaps;
    HRESULT                 hr;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    memset( &stHDDCaps, 0, sizeof( DDCAPS ) );
    memset( &stSDDCaps, 0, sizeof( DDCAPS ) );
    stHDDCaps.dwSize = stSDDCaps.dwSize = sizeof( DDCAPS );
 
    hr = _pDD4->lpVtbl->GetCaps( _pDD4, &stHDDCaps, &stSDDCaps );
    if (hr != DD_OK)
    {
        char szText[512];
        FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0, szText, 512,    NULL );
        return hr;
    }
 
    
    p_stCaps = (_lFlags & DX6_C_Dev_Hardware) ? &stHDDCaps : &stSDDCaps;
    
    if( p_stCaps->dwCaps & DDCAPS_3D) 
        _pst_Caps->ulDriverCaps |= GLICAPS_DRV_C_ulIsHardware;
 
	if ( ( p_stCaps->dwCaps & DDCAPS_PALETTE ) && (p_stCaps->dwPalCaps & DDPCAPS_8BIT ) && (p_stCaps->dwPalCaps & DDPCAPS_ALLOW256 ) )
		_pst_Caps->ulTextureCaps |= GLICAPS_TEX_C_ulSupport8P;
    
    if( p_stCaps->dwCaps2 & DDCAPS2_NONLOCALVIDMEM)
        _pst_Caps->ulDriverCaps |= GLICAPS_DRV_C_ulCanUseAGP;
 
    if( p_stCaps->dwCaps2 & DDCAPS2_CANRENDERWINDOWED )
        _pst_Caps->ulDriverCaps |= GLICAPS_DRV_C_ulCanBeWindowed | GLICAPS_DRV_C_ulReadjustViewport;
 
    /*if( (stHDDCaps.ddsCaps.dwCaps & (DDSCAPS_COMPLEX | DDSCAPS_MIPMAP)) == (DDSCAPS_COMPLEX | DDSCAPS_MIPMAP) )*/
    if( p_stCaps->ddsCaps.dwCaps & DDSCAPS_MIPMAP )
        _pst_Caps->ulTextureCaps |= GLICAPS_TEX_C_ulSupportMipmap;

    /* Compute monitor's refresh rate */
    if( TMR_MDRV_vTimerGetCounter && TMR_MDRV_ulTimerTickPerSecond )
    {
        hr = _pDD4->lpVtbl->WaitForVerticalBlank( _pDD4, DDWAITVB_BLOCKBEGIN, NULL );
        if( FAILED( hr ) ) 
            _pst_Caps->fRefreshRate = 60.0f;
        else
        {
            stTimerCount stTimerBefore, stTimerAfter;
            int i;

            TMR_MDRV_vTimerGetCounter( C_wTimerFrequencyMedium, &stTimerBefore );
            /* it's a 10 frame sample */
            for( i=0; i<10; i++ )
            {
                hr = _pDD4->lpVtbl->WaitForVerticalBlank( _pDD4, DDWAITVB_BLOCKBEGIN, NULL );
                if( FAILED( hr ) ) 
                    break;
            }
            TMR_MDRV_vTimerGetCounter( C_wTimerFrequencyMedium, &stTimerAfter );

            if( i<10 )
                /* If an error occured we set the refresh rate to 60Hz */
                _pst_Caps->fRefreshRate = 60.0f;
            else
                /* Else, we compute it normally. The result is rounded to the nearest integer value. */
                _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;


    return hr;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Get device caps
 ----------------------------------------------------------------------------------------
 */
HRESULT GLI_DX6_fn_hGetDeviceCaps( tdstGliCaps *_pst_Caps, LPDIRECTDRAW4 _pDD4, D3DDEVICEDESC *_pst_DevDesc )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    HRESULT         hr;
    unsigned long   ulTotal, ulLeft;
    DDPIXELFORMAT   stPixelFormat;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    
    /*
     * Alpha test
     */ 
	if ( _pst_DevDesc->dpcTriCaps.dwAlphaCmpCaps & D3DPCMPCAPS_GREATEREQUAL )
		_pst_Caps->ulDriverCaps |= GLICAPS_DRV_C_ulSupportAlphaTest;
 
    /*
     * non squared texture
     */
    if (!(_pst_DevDesc->dpcTriCaps.dwTextureCaps & D3DPTEXTURECAPS_SQUAREONLY))
        _pst_Caps->ulTextureCaps |= GLICAPS_TEX_C_ulSupportNonSquare;
 
    /*
     * non local texture
     */
    if ( _pst_DevDesc->dwDevCaps & D3DDEVCAPS_TEXTURENONLOCALVIDMEM )
        _pst_Caps->ulDriverCaps |= GLICAPS_DRV_C_ulCanUseAGP;
    else if (_pst_Caps->ulDriverCaps & GLICAPS_DRV_C_ulCanUseAGP )
        _pst_Caps->ulDriverCaps -= GLICAPS_DRV_C_ulCanUseAGP;
        
    /*
     * max texture size
     */
    _pst_Caps->ulTextureMaxSize = __min(_pst_DevDesc->dwMaxTextureWidth, _pst_DevDesc->dwMaxTextureHeight);
    if ( _pst_Caps->ulTextureMaxSize == 0)
        _pst_Caps->ulTextureMaxSize = 256;
 
    /*
     * total video mem (local and non local)
     */
    hr = GLI_DX6_hGetVideoMemory( _pDD4, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_MIPMAP, &ulTotal, &ulLeft );
    if (hr == DD_OK)
    {
        _pst_Caps->ulTotalVideoMemory = ulTotal;
        _pst_Caps->ulTotalTextureMemory = ulLeft;
    }
 
    if ( _pst_Caps->ulDriverCaps & GLICAPS_DRV_C_ulCanUseAGP)
    {
        hr = GLI_DX6_hGetVideoMemory( _pDD4, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM | DDSCAPS_MIPMAP, &ulTotal, &ulLeft );
        if (hr == DD_OK)
        {
            _pst_Caps->ulTotalAGPMemory = ulTotal;
            /*_pst_Caps->ulTotalTextureMemory += ulLeft;*/
        }
        else
            _pst_Caps->ulDriverCaps -= GLICAPS_DRV_C_ulCanUseAGP;
    }
 
    /*
     * pixel format of primary surface
     */
    if ( g_pddsPrimary )
    {
        memset( &stPixelFormat, 0, sizeof(DDPIXELFORMAT) );
        stPixelFormat.dwSize = sizeof( DDPIXELFORMAT );
        g_pddsPrimary->lpVtbl->GetPixelFormat(g_pddsPrimary, &stPixelFormat );
        _pst_Caps->ucPrimarySurfacePixelFormat = GLI_DX6_fn_ucGetPrimarySurfacePixelFormat(&stPixelFormat);
    }
    return DD_OK;
}
 
/*
 =======================================================================================
 =======================================================================================
    Private Function
 =======================================================================================
 =======================================================================================
 */
 
 
/*
 =======================================================================================
    conversion D3D Pixel format to Defined Pixel Format
 =======================================================================================
 */
 
long GLI_DX6_fn_lConvertMaskToShift ( unsigned long _ulMask )
{
    if ( _ulMask & 0x00000001 ) return 0;
    if ( _ulMask & 0x00000002 ) return 1;
    if ( _ulMask & 0x00000004 ) return 2;
    if ( _ulMask & 0x00000008 ) return 3;
    if ( _ulMask & 0x00000010 ) return 4;
    if ( _ulMask & 0x00000020 ) return 5;
    if ( _ulMask & 0x00000040 ) return 6;
    if ( _ulMask & 0x00000080 ) return 7;
    if ( _ulMask & 0x00000100 ) return 8;
    if ( _ulMask & 0x00000200 ) return 9;
    if ( _ulMask & 0x00000400 ) return 10;
    if ( _ulMask & 0x00000800 ) return 11;
    if ( _ulMask & 0x00001000 ) return 12;
    if ( _ulMask & 0x00002000 ) return 13;
    if ( _ulMask & 0x00004000 ) return 14;
    if ( _ulMask & 0x00008000 ) return 15;
    if ( _ulMask & 0x00010000 ) return 16;
    if ( _ulMask & 0x00020000 ) return 17;
    if ( _ulMask & 0x00040000 ) return 18;
    if ( _ulMask & 0x00080000 ) return 19;
    if ( _ulMask & 0x00100000 ) return 20;
    if ( _ulMask & 0x00200000 ) return 21;
    if ( _ulMask & 0x00400000 ) return 22;
    if ( _ulMask & 0x00800000 ) return 23;
    if ( _ulMask & 0x01000000 ) return 24;
    if ( _ulMask & 0x02000000 ) return 25;
    if ( _ulMask & 0x04000000 ) return 26;
    if ( _ulMask & 0x08000000 ) return 27;
    if ( _ulMask & 0x10000000 ) return 28;
    if ( _ulMask & 0x20000000 ) return 29;
    if ( _ulMask & 0x40000000 ) return 30;
    if ( _ulMask & 0x80000000 ) return 31;
    return 0;
}
 
unsigned long GLI_DX6_fn_ulConvertNbBitsToMask ( long _lNbBits )
{
    if ( _lNbBits == 0  ) return 0x00000000;
    if ( _lNbBits == 1  ) return 0x00000001;
    if ( _lNbBits == 2  ) return 0x00000003;
    if ( _lNbBits == 3  ) return 0x00000007;
    if ( _lNbBits == 4  ) return 0x0000000F;
    if ( _lNbBits == 5  ) return 0x0000001F;
    if ( _lNbBits == 6  ) return 0x0000003F;
    if ( _lNbBits == 7  ) return 0x0000007F;
    if ( _lNbBits == 8  ) return 0x000000FF;
    if ( _lNbBits == 9  ) return 0x000001FF;
    if ( _lNbBits == 10 ) return 0x000003FF;
    if ( _lNbBits == 11 ) return 0x000007FF;
    if ( _lNbBits == 12 ) return 0x00000FFF;
    if ( _lNbBits == 13 ) return 0x00001FFF;
    if ( _lNbBits == 14 ) return 0x00003FFF;
    if ( _lNbBits == 15 ) return 0x00007FFF;
    if ( _lNbBits == 16 ) return 0x0000FFFF;
    if ( _lNbBits == 17 ) return 0x0001FFFF;
    if ( _lNbBits == 18 ) return 0x0003FFFF;
    if ( _lNbBits == 19 ) return 0x0007FFFF;
    if ( _lNbBits == 20 ) return 0x000FFFFF;
    if ( _lNbBits == 21 ) return 0x001FFFFF;
    if ( _lNbBits == 22 ) return 0x003FFFFF;
    if ( _lNbBits == 23 ) return 0x007FFFFF;
    if ( _lNbBits == 24 ) return 0x00FFFFFF;
    if ( _lNbBits == 25 ) return 0x01FFFFFF;
    if ( _lNbBits == 26 ) return 0x03FFFFFF;
    if ( _lNbBits == 27 ) return 0x07FFFFFF;
    if ( _lNbBits == 28 ) return 0x0FFFFFFF;
    if ( _lNbBits == 29 ) return 0x1FFFFFFF;
    if ( _lNbBits == 30 ) return 0x3FFFFFFF;
    if ( _lNbBits == 31 ) return 0x7FFFFFFF;
    if ( _lNbBits == 32 ) return 0xFFFFFFFF;
    return 0x00000000;
}
 
long GLI_DX6_fn_lConvertMaskToNbBits( unsigned long _ulMask )
{
    if ( _ulMask == 0x00000000 ) return 0;
    if ( _ulMask == 0x00000001 ) return 1;
    if ( _ulMask == 0x00000003 ) return 2;
    if ( _ulMask == 0x00000007 ) return 3;
    if ( _ulMask == 0x0000000F ) return 4;
    if ( _ulMask == 0x0000001F ) return 5;
    if ( _ulMask == 0x0000003F ) return 6;
    if ( _ulMask == 0x0000007F ) return 7;
    if ( _ulMask == 0x000000FF ) return 8;
    if ( _ulMask == 0x000001FF ) return 9;
    if ( _ulMask == 0x000003FF ) return 10;
    if ( _ulMask == 0x000007FF ) return 11;
    if ( _ulMask == 0x00000FFF ) return 12;
    if ( _ulMask == 0x00001FFF ) return 13;
    if ( _ulMask == 0x00003FFF ) return 14;
    if ( _ulMask == 0x00007FFF ) return 15;
    if ( _ulMask == 0x0000FFFF ) return 16;
    if ( _ulMask == 0x0001FFFF ) return 17;
    if ( _ulMask == 0x0003FFFF ) return 18;
    if ( _ulMask == 0x0007FFFF ) return 19;
    if ( _ulMask == 0x000FFFFF ) return 20;
    if ( _ulMask == 0x001FFFFF ) return 21;
    if ( _ulMask == 0x003FFFFF ) return 22;
    if ( _ulMask == 0x007FFFFF ) return 23;
    if ( _ulMask == 0x00FFFFFF ) return 24;
    if ( _ulMask == 0x01FFFFFF ) return 25;
    if ( _ulMask == 0x03FFFFFF ) return 26;
    if ( _ulMask == 0x07FFFFFF ) return 27;
    if ( _ulMask == 0x0FFFFFFF ) return 28;
    if ( _ulMask == 0x1FFFFFFF ) return 29;
    if ( _ulMask == 0x3FFFFFFF ) return 30;
    if ( _ulMask == 0x7FFFFFFF ) return 31;
    if ( _ulMask == 0xFFFFFFFF ) return 32;
    return 0;
}
 
 
ACP_tdxBool GLI_DX6_fn_bEqualRGBMask( GLD_tdpstPixelFormat _p_stPF, DDPIXELFORMAT *_p_stDDPF )
{
    return ( _p_stPF->ulRedMask == _p_stDDPF->dwRBitMask ) && ( _p_stPF->ulGreenMask == _p_stDDPF->dwGBitMask ) && ( _p_stPF->ulBlueMask == _p_stDDPF->dwBBitMask );
}
 
ACP_tdxBool GLI_DX6_fn_bEqualRGBAMask( GLD_tdpstPixelFormat _p_stPF, DDPIXELFORMAT *_p_stDDPF )
{
    return ( _p_stPF->ulRedMask == _p_stDDPF->dwRBitMask ) && ( _p_stPF->ulGreenMask == _p_stDDPF->dwGBitMask ) && ( _p_stPF->ulBlueMask == _p_stDDPF->dwBBitMask ) && ( _p_stPF->ulAlphaMask == _p_stDDPF->dwRGBAlphaBitMask );
}
 
void GLI_DX6_fn_vConvertDDPixelFormatToPixelFormat( GLD_tdpstPixelFormat _p_stPF, LPDDPIXELFORMAT _p_stDDPF )
{
    _p_stPF->xFormatNumber   = 0;
    _p_stPF->bAlpha          = (unsigned char) (_p_stDDPF->dwFlags & DDPF_ALPHAPIXELS);
 
    _p_stPF->lPixelNbBits    = _p_stDDPF->dwRGBBitCount;
    _p_stPF->ulPixelMask     = GLI_DX6_fn_ulConvertNbBitsToMask( _p_stPF->lPixelNbBits );
    _p_stPF->lPixelNbBytes   = _p_stPF->lPixelNbBits/8;
 
    _p_stPF->ulRedMask       = _p_stDDPF->dwRBitMask;
    _p_stPF->lRedShift       = GLI_DX6_fn_lConvertMaskToShift( _p_stPF->ulRedMask );
    _p_stPF->lRedNbBits      = GLI_DX6_fn_lConvertMaskToNbBits( _p_stPF->ulRedMask >> _p_stPF->lRedShift );
 
    _p_stPF->ulGreenMask     = _p_stDDPF->dwGBitMask;
    _p_stPF->lGreenShift     = GLI_DX6_fn_lConvertMaskToShift( _p_stPF->ulGreenMask );
    _p_stPF->lGreenNbBits    = GLI_DX6_fn_lConvertMaskToNbBits( _p_stPF->ulGreenMask >> _p_stPF->lGreenShift );
 
    _p_stPF->ulBlueMask      = _p_stDDPF->dwBBitMask;
    _p_stPF->lBlueShift      = GLI_DX6_fn_lConvertMaskToShift( _p_stPF->ulBlueMask );
    _p_stPF->lBlueNbBits     = GLI_DX6_fn_lConvertMaskToNbBits( _p_stPF->ulBlueMask >> _p_stPF->lBlueShift );
 
    if ( _p_stPF->bAlpha )
    {
        _p_stPF->ulAlphaMask = _p_stDDPF->dwRGBAlphaBitMask;
        _p_stPF->lAlphaShift = GLI_DX6_fn_lConvertMaskToShift( _p_stPF->ulAlphaMask );
        _p_stPF->lAlphaNbBits= GLI_DX6_fn_lConvertMaskToNbBits( _p_stPF->ulAlphaMask >> _p_stPF->lAlphaShift );
    }
    else
    {
        _p_stPF->ulAlphaMask = 0x00000000;
        _p_stPF->lAlphaShift = 0;
        _p_stPF->lAlphaNbBits= 0;
    }
}
 
 
long GLI_DX6_fn_lGetEquivalentPixelFormat( LPDDPIXELFORMAT _p_stDDPixelFormat )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    long                    lFormatIndex;
    GLD_tdstPixelFormat    *_p_stDefinedPF;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    if ( !(_p_stDDPixelFormat->dwFlags & DDPF_RGB) )
        return -1;
 
    lFormatIndex = 0;
    while(1)
    {
        _p_stDefinedPF = GLD_MDRV_fn_p_stGetDefinedPixelFormat( lFormatIndex );
        if (_p_stDefinedPF == NULL)
            return -1;
 
        if ( _p_stDefinedPF->lPixelNbBits == (long) _p_stDDPixelFormat->dwRGBBitCount )
        {
            if ( _p_stDDPixelFormat->dwFlags & DDPF_ALPHAPIXELS )
            {
                if ( ( _p_stDefinedPF->bAlpha ) && ( GLI_DX6_fn_bEqualRGBAMask( _p_stDefinedPF, _p_stDDPixelFormat ) ) )
                    return lFormatIndex;
            }
            else
            {
                if ( ( !_p_stDefinedPF->bAlpha ) && ( GLI_DX6_fn_bEqualRGBMask( _p_stDefinedPF, _p_stDDPixelFormat ) ) )
                    return lFormatIndex;
            }
            
        }
        lFormatIndex++;
    }
    return -1;
}
 
unsigned char GLI_DX6_fn_ucGetPrimarySurfacePixelFormat( LPDDPIXELFORMAT _p_stDDPF )
{
    long                    lPixelFormat;
    GLD_tdstPixelFormat     stPF;
 
    lPixelFormat = GLI_DX6_fn_lGetEquivalentPixelFormat( _p_stDDPF );
    if (lPixelFormat != -1)
        return (unsigned char) lPixelFormat;
 
    GLI_DX6_fn_vConvertDDPixelFormatToPixelFormat( &stPF, _p_stDDPF );
    lPixelFormat = GLD_MDRV_fn_lAddDefinedPixelFormat( &stPF );
    if (lPixelFormat != -1 )
        return (unsigned char ) lPixelFormat;
 
    return (unsigned char) GLD_C_xUndefinedPixelFormat;
}
 
 
/*
 =======================================================================================
    D3D texture format
 =======================================================================================
 */
 
/*
 ----------------------------------------------------------------------------------------
  Description   : callback (use by D3DDevice3 method "EnumTextureFormats")
 ----------------------------------------------------------------------------------------
 */
static HRESULT CALLBACK fn_D3DCallbackGetPixelFormats (LPDDPIXELFORMAT _pddPF,LPVOID lpContext)
{
    /*
     * Record the DDSURFACEDESC of this texture format
     */
	/* Skip any funky modes*/
    if( _pddPF->dwFlags & (DDPF_LUMINANCE|DDPF_BUMPLUMINANCE|DDPF_BUMPDUDV) )
        return DDENUMRET_OK;
 
    memset(&gs_a_stD3DPixelFormat[ gs_lNumberOfPixelFormats ], 0,sizeof(DDPIXELFORMAT));
    memcpy(&gs_a_stD3DPixelFormat[ gs_lNumberOfPixelFormats ], _pddPF,sizeof(DDPIXELFORMAT));
    gs_lNumberOfPixelFormats++;
    return DDENUMRET_OK;
};
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : This function update stD3DTextureFormat from the device
 ----------------------------------------------------------------------------------------
 */
HRESULT GLI_DX6_fn_hGetPixelFormats( void )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    HRESULT     hr;
    long        lIndex;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
 
    /*
     * Set the default format to -1 to let the callback know it's being 
     * called for the first time.
     */
	gs_lNumberOfPixelFormats = 0;
	hr = g_pd3dDevice->lpVtbl->EnumTextureFormats( g_pd3dDevice, &fn_D3DCallbackGetPixelFormats,NULL);
    if (hr != DD_OK)
        return hr;
 
    memset( gs_a_cPixelFormatIndex, -1, GLI_DX6_TexNbFormats );
    for ( lIndex = 0; lIndex < gs_lNumberOfPixelFormats; lIndex++)
    {
        if (gs_a_stD3DPixelFormat[lIndex].dwFlags & DDPF_RGB) 
        {
            /*
             * 32 bits format
             */
            if (gs_a_stD3DPixelFormat[lIndex].dwRGBBitCount == 32) 
            {
                if (gs_a_stD3DPixelFormat[lIndex].dwFlags & DDPF_ALPHAPIXELS)
                {
                    gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat8888 ] = (char) lIndex;
                }
                else
                {
                    gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat888 ] = (char) lIndex;
                }
            }
            /*
             * 16 bit format
             */
            else if (gs_a_stD3DPixelFormat[lIndex].dwRGBBitCount == 16) 
            {
                /* alpha format*/
                if (gs_a_stD3DPixelFormat[lIndex].dwFlags & DDPF_ALPHAPIXELS)
                {
                    if( (gs_a_stD3DPixelFormat[lIndex].dwRGBAlphaBitMask == 0xF000) || (gs_a_stD3DPixelFormat[lIndex].dwRGBAlphaBitMask == 0xF) )
                    {
                        gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat4444 ] = (char) lIndex;
                    }
                    else if ( (gs_a_stD3DPixelFormat[lIndex].dwRGBAlphaBitMask != 0x1) && (gs_a_stD3DPixelFormat[lIndex].dwRGBAlphaBitMask != 0x8000) )
                    {
                        if ( gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat4444 ] == -1)
                            gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat4444 ] = (char) lIndex;
                    }
                    else if ( (gs_a_stD3DPixelFormat[lIndex].dwRGBAlphaBitMask == 0x1) || (gs_a_stD3DPixelFormat[lIndex].dwRGBAlphaBitMask == 0x8000) )
                    {
                        gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat1555 ] = (char) lIndex;
                    }
                    else
                    {
                        if ( gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat4444 ] == -1)
                            gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat4444 ] = (char) lIndex;
                        if ( gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat1555 ] == -1)
                            gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat1555 ] = (char) lIndex;
                    }
                }
                else
                {
                    if(gs_a_stD3DPixelFormat[lIndex].dwGBitMask == 0x07E0)
                    {
                        gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat565 ] = (char) lIndex;
                        if ( gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat4444 ] == -1)
                            gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat4444 ] = (char) lIndex;
                        if ( gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat1555 ] == -1)
                            gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat1555 ] = (char) lIndex;
 
                    }
                    else if(gs_a_stD3DPixelFormat[lIndex].dwGBitMask == 0x03E0)
                    {
                        if ( gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat565 ] != -1 )
                            gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat565 ] = (char) lIndex;
                        if ( gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat4444 ] == -1)
                            gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat4444 ] = (char) lIndex;
                        if ( gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat1555 ] == -1)
                            gs_a_cPixelFormatIndex[ GLI_DX6_TexFormat1555 ] = (char) lIndex;
 
                    }
                }
            }
			/* 
             * 8 bit format 
             */
			else if (gs_a_stD3DPixelFormat[lIndex].dwRGBBitCount == 8) 
			{
				if( gs_a_stD3DPixelFormat[lIndex].dwFlags & DDPF_PALETTEINDEXED8 )
					gs_a_cPixelFormatIndex[ GLI_DX6_TexFormatPalette8 ] = (char) lIndex; 
			}
        }
    }
 
	/*
	 * some more check
	 */
	if ( ( gs_a_cPixelFormatIndex[ GLI_DX6_TexFormatPalette8 ] == -1) && (g_p_stGliCaps->ulTextureCaps & GLICAPS_TEX_C_ulSupport8P) )
		g_p_stGliCaps->ulTextureCaps -= GLICAPS_TEX_C_ulSupport8P;
 
    return DD_OK;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Get pixel format that correspond to a constant
 ----------------------------------------------------------------------------------------
 */
void GLI_DX6_fn_vGetPixelFormat( char _ucFormatAsked, DDPIXELFORMAT *_p_stPixelFormat )
{
    if ( (_ucFormatAsked >= GLI_DX6_TexNbFormats) || (gs_a_cPixelFormatIndex[ _ucFormatAsked ] == -1 ) )
        *_p_stPixelFormat = gs_a_stD3DPixelFormat[0];
    else
        *_p_stPixelFormat = gs_a_stD3DPixelFormat[ gs_a_cPixelFormatIndex[ _ucFormatAsked ] ];
}
 
 
/*
 =======================================================================================
    Precalculate different texture size
 =======================================================================================
 */
 
/*
 ----------------------------------------------------------------------------------------
  Description   : precalculate texture size
 ----------------------------------------------------------------------------------------
 */
void GLI_DX6_fn_vPrecalculateTextureSize( void )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    char                    cTexFormat;
    char                    cMipmap;
    char                    cWidth, cHeight;
    long                    lWidth, lHeight;
    DDSURFACEDESC2          ddsd;
    unsigned long	        ulMemoryBefore, ulMemoryAfter, ulTotal, ulLeft;
    HRESULT                 hr;
    LPDIRECTDRAWSURFACE4     p_stDDS4;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    memset(&ddsd, 0, sizeof(ddsd));
    ddsd.dwSize = sizeof(ddsd);
 
    for (cTexFormat = 0; cTexFormat < GLI_DX6_TexNbFormats; cTexFormat++)
    {
        ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT | DDSD_PIXELFORMAT ;
        ddsd.ddsCaps.dwCaps = DDSCAPS_TEXTURE | DDSCAPS_ALLOCONLOAD | DDSCAPS_LOCALVIDMEM | DDSCAPS_VIDEOMEMORY;
        GLI_DX6_fn_vGetPixelFormat( cTexFormat, &ddsd.ddpfPixelFormat );
 
        for (cMipmap = 0; cMipmap < 2; cMipmap++)
        {
            if (cMipmap)
            {
                if ( !( g_p_stGliCaps->ulTextureCaps & GLICAPS_TEX_C_ulSupportMipmap ) )
                {
                    for (cWidth = 0, lWidth = 1; cWidth < 9 ; cWidth++, lWidth <<= 1 )
                        for (cHeight = 0, lHeight = 1; cHeight < 9; cHeight++, lHeight <<= 1)
                            gs_a_lPrecalculatedTextureSize[ cTexFormat ][ 1 ][ cWidth ][ cHeight ] = gs_a_lPrecalculatedTextureSize[ cTexFormat ][ 0 ][ cWidth ][ cHeight ];
                    continue;
                }
 
                ddsd.ddsCaps.dwCaps |= DDSCAPS_MIPMAP | DDSCAPS_COMPLEX;
                ddsd.dwFlags |= DDSD_MIPMAPCOUNT;
            }
 
            for (cWidth = 0, lWidth = 1; cWidth < 9 ; cWidth++, lWidth <<= 1 )
            {
                for (cHeight = 0, lHeight = 1; cHeight < 9; cHeight++, lHeight <<= 1)
                {
                    ddsd.dwWidth = lWidth;
                    ddsd.dwHeight = lHeight;
 
                    if (cMipmap)
                        ddsd.dwMipMapCount = ((cWidth > cHeight) ? cHeight : cWidth) + 1;
 
                    GLI_DX6_hGetVideoMemory( g_pDD4, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_MIPMAP, &ulTotal, &ulMemoryBefore );
                    if (g_p_stGliCaps->ulDriverCaps & GLICAPS_DRV_C_ulCanUseAGP )
                    {
                        GLI_DX6_hGetVideoMemory( g_pDD4, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM | DDSCAPS_MIPMAP, &ulTotal, &ulLeft);
                        ulMemoryBefore += ulLeft;
                    }
                    
                    /*
                     *  create texture surface
                     */
                    hr = g_pDD4->lpVtbl->CreateSurface( g_pDD4, &ddsd, &p_stDDS4, NULL );
                    if ( (hr != DD_OK) || !(p_stDDS4) )
                    {
                        gs_a_lPrecalculatedTextureSize[ cTexFormat ][ cMipmap ][ cWidth ][ cHeight ] = 0;
                        continue;
                    }
 
                    GLI_DX6_hGetVideoMemory( g_pDD4, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_LOCALVIDMEM | DDSCAPS_MIPMAP, &ulTotal, &ulMemoryAfter );
                    if (g_p_stGliCaps->ulDriverCaps & GLICAPS_DRV_C_ulCanUseAGP )
                    {
                        GLI_DX6_hGetVideoMemory( g_pDD4, DDSCAPS_TEXTURE | DDSCAPS_VIDEOMEMORY | DDSCAPS_NONLOCALVIDMEM | DDSCAPS_MIPMAP, &ulTotal, &ulLeft);
                        ulMemoryAfter += ulLeft;
                    }
 
                                        
                    gs_a_lPrecalculatedTextureSize[ cTexFormat ][ cMipmap ][ cWidth ][ cHeight ] = ulMemoryBefore - ulMemoryAfter;
 
                    do
                    {
                        hr = p_stDDS4->lpVtbl->Release( p_stDDS4 );
                    } while( hr );
                }
            }
        }
    }
 
    /*
    {
        FILE *hpFile;
        hpFile = fopen( "PreCalcTextureSize.log", "wt" );
        if (hpFile == NULL)
            return;
 
        fprintf( hpFile, "Precalculated texture size\r\n\r\n[PixelFormat][mipmap count][Width][height][size]\r\n\r\n" );
 
        for (cTexFormat = 0; cTexFormat < GLI_DX6_TexNbFormats; cTexFormat++)
            for (cMipmap = 0; cMipmap < 2; cMipmap++)
                for (cWidth = 0, lWidth = 1; cWidth < 9 ; cWidth++, lWidth <<= 1 )
                    for (cHeight = 0, lHeight = 1; cHeight < 9; cHeight++, lHeight <<= 1)
                    {
                        if (cMipmap)
                            ddsd.dwMipMapCount = ((cWidth > cHeight) ? cHeight : cWidth) + 1;
                        else 
                            ddsd.dwMipMapCount = 0;
 
                        fprintf( hpFile, "%d %d %3d %3d %8d %8X\r\n", cTexFormat, ddsd.dwMipMapCount, lWidth, lHeight, 
                                gs_a_lPrecalculatedTextureSize[ cTexFormat ][ cMipmap ][ cWidth ][ cHeight ], 
                                gs_a_lPrecalculatedTextureSize[ cTexFormat ][ cMipmap ][ cWidth ][ cHeight ] );
                    }
        fclose( hpFile );
    }
    */
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Get precalculated size
 ----------------------------------------------------------------------------------------
 */
long GLI_DX6_fn_lGetPrecalculatedTextureSize( char _cTexFormat, char _cMipmap, long _lWidth, long _lHeight )
{
    char cWidth, cHeight;
    
    cWidth  = (char) GLI_DX6_fn_lConvertMaskToShift( _lWidth  );
    cHeight = (char) GLI_DX6_fn_lConvertMaskToShift( _lHeight );
 
    return gs_a_lPrecalculatedTextureSize[ _cTexFormat ][ _cMipmap ][ cWidth ][ cHeight ];
}
