/*
 =======================================================================================
  Name        : DX6_Choose.c
  Author      : vincent lhullier            Date :21/08/98
  Description : choose DirectX modes
 =======================================================================================
 */
 
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#include <stdio.h>
 
#define INITGUID
#include "d3d.h"
#include "ddraw.h"
 
#include "GLI_util.h"
#include "DispMode.h"
#include "DLLCom.h"
#include "DX6_Caps.h"
#include "DX6_Choose.h"
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
 
/*
 =======================================================================================
    Extern (globals and function prototypes) 
 =======================================================================================
 */
extern GUID             GLIDX6_gx_DDDriverGuid;
extern GUID             GLIDX6_gx_D3DDeviceGuid;

       long             GLIDX6_gl_DeviceFlags;
       D3DDEVICEDESC    GLIDX6_gst_DeviceDesc;

static char             GLIDX6_gc_Found;

/*
 =======================================================================================
    Direct draw Display mode
 =======================================================================================
 */
 
/*
 ----------------------------------------------------------------------------------------
  Description   : enumeration call back to get all display mode
 ----------------------------------------------------------------------------------------
 */
HRESULT CALLBACK GLIDX6_fnh_GetAllDisplayModesCallback(LPDDSURFACEDESC2 pddsd, LPVOID lpContext)
{
   //chbani  if ( ( pddsd->ddpfPixelFormat.dwRGBBitCount == 16 ) /* || ( pddsd->ddpfPixelFormat.dwRGBBitCount == 32 )*/ )
    {
        GLI_MDRV_lAddDisplayMode( 0, pddsd->dwWidth, pddsd->dwHeight, pddsd->ddpfPixelFormat.dwRGBBitCount ); //chbani 1-->0
    }
    return TRUE;
}
 
/*
 ----------------------------------------------------------------------------------------
  Description   : enumeration call back to get all drivers
 ----------------------------------------------------------------------------------------
 */
BOOL WINAPI GLIDX6_fnb_GetDriverCallback( GUID FAR *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, LPVOID lpContext )
{
    if ( strcmp( (char*) lpContext, lpDriverName ) == 0 )
    {
        if (lpGUID != NULL)
            memcpy( &GLIDX6_gx_DDDriverGuid, lpGUID, sizeof( GUID ) );
        else
            memset( &GLIDX6_gx_DDDriverGuid, 0, sizeof( GUID ) );
        GLIDX6_gc_Found = 1;
        return 0;
    }
 
    /* continue enumeration*/
    return TRUE;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : enumeration call back to get device
 ----------------------------------------------------------------------------------------
 */
static HRESULT CALLBACK GLIDX6_fnh_GetDeviceCallback( GUID *_pGuid, LPSTR _szDesc, LPSTR _szName, LPD3DDEVICEDESC _lpHWDesc, LPD3DDEVICEDESC _lpHELDesc, LPVOID _lpContext )
{
    if ( strcmp( _szName, (char*) _lpContext ) == 0 )
    {
        GLIDX6_gc_Found = 1;
        memcpy( &GLIDX6_gx_D3DDeviceGuid, _pGuid, sizeof( GUID ) );

        if ( _lpHWDesc->dcmColorModel )
        {
            GLIDX6_gl_DeviceFlags = DX6_C_Dev_Hardware;
            memcpy( &GLIDX6_gst_DeviceDesc, _lpHWDesc, sizeof( D3DDEVICEDESC ) );
        }
        else
        {
            GLIDX6_gl_DeviceFlags = 0;
            memcpy( &GLIDX6_gst_DeviceDesc, _lpHELDesc, sizeof( D3DDEVICEDESC ) );
        }

        return 0;
    }
    
    return D3DENUMRET_OK;
}


/*
 ----------------------------------------------------------------------------------------
  Description   : Main mode enumeration function called by engine initialization
 ----------------------------------------------------------------------------------------
 */
long __declspec(dllexport) GLI_DRV_fnl_EnumModes( char *_sz_DriverName, char *_sz_DeviceName )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    LPDIRECT3D3				pD3D = NULL;
    LPDIRECTDRAW4			pDD4 = NULL;
    LPDIRECTDRAW			pDD;
 
    HRESULT                 hr;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    /*
     * get driver
     */
    GLIDX6_gc_Found = 0;
    hr = DirectDrawEnumerate( GLIDX6_fnb_GetDriverCallback, (void *) _sz_DriverName );
    if ( (hr != DD_OK) || (GLIDX6_gc_Found == 0) )
        return 0;

    /*
     * get device
     */
    hr = DirectDrawCreate( &GLIDX6_gx_DDDriverGuid, &pDD, NULL );
    if (hr != DD_OK)
        return 0;

    /* Get a ptr to an IDirectDraw4 interface. This interface to DirectDraw represents the DX6 version of the API.*/
    hr = pDD->lpVtbl->QueryInterface( pDD, &IID_IDirectDraw4, (LPVOID *) &pDD4 );
    pDD->lpVtbl->Release(pDD);
    if (hr != DD_OK)
        return 0;

    /* Query DirectDraw for access to Direct3D*/
	hr = pDD4->lpVtbl->QueryInterface( pDD4, &IID_IDirect3D3, (VOID**)&pD3D );
    if (hr == DD_OK)
    {
        GLIDX6_gc_Found = 0;
        hr = pD3D->lpVtbl->EnumDevices( pD3D, GLIDX6_fnh_GetDeviceCallback, (void *) _sz_DeviceName );
        if ( (hr == DD_OK) && (GLIDX6_gc_Found != 0) )
        {
            hr = pDD4->lpVtbl->EnumDisplayModes( pDD4, 0, NULL, 0, GLIDX6_fnh_GetAllDisplayModesCallback );
        }
    }
                
    if (pD3D) pD3D->lpVtbl->Release(pD3D);
    if (pDD4) pDD4->lpVtbl->Release(pDD4);
    return ( (hr == DD_OK) && (GLIDX6_gc_Found != 0) ) ? 1 : 0;
}
 
/*
 =======================================================================================
    Access function
 =======================================================================================
 */
 
char GLIDX6_fnc_IsHardware( void )
{
    return (GLIDX6_gl_DeviceFlags & DX6_C_Dev_Hardware) ? 1 : 0;
}

long GLIDX6_fnl_GetDeviceFlag( void )
{
    return GLIDX6_gl_DeviceFlags;
}
 
 
D3DDEVICEDESC *GLIDX6_fnpst_GetDeviceDesc( void )
{
    return &GLIDX6_gst_DeviceDesc;
}

/*
 =======================================================================================
    Function used only by GliDetect not in engine used.
 =======================================================================================
 */

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

/*
 ----------------------------------------------------------------------------------------
  Description   : enumeration call back to get all display mode
 ----------------------------------------------------------------------------------------
 */
static HRESULT CALLBACK DX6_fnh_ModeCallback(LPDDSURFACEDESC2 pddsd, LPVOID lpContext)
{
    long l_Mode;
    if ( ( pddsd->ddpfPixelFormat.dwRGBBitCount == 16 ) || ( pddsd->ddpfPixelFormat.dwRGBBitCount == 32 ) )
    {
        l_Mode = gpfnl_AddDisplayInfo( gl_Driver, 0, 0, "modeadd", 0);
        gpfnl_AddDisplayInfo( gl_Driver, 0, l_Mode, "modefs", 1 );
        gpfnl_AddDisplayInfo( gl_Driver, 0, l_Mode, "modebpp", pddsd->ddpfPixelFormat.dwRGBBitCount );
        gpfnl_AddDisplayInfo( gl_Driver, 0, l_Mode, "modew", pddsd->dwWidth );
        gpfnl_AddDisplayInfo( gl_Driver, 0, l_Mode, "modeh", pddsd->dwHeight );
    }
    return TRUE;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : enumeration call back to get all device
 ----------------------------------------------------------------------------------------
 */
static HRESULT CALLBACK DX6_fnh_DevicesCallback( GUID *_pGuid, LPSTR _szDesc, LPSTR _szName, LPD3DDEVICEDESC _lpHWDesc, LPD3DDEVICEDESC _lpHELDesc, LPVOID _lpContext )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    tdstGliCaps             st_Caps;
    D3DDEVICEDESC           *_pst_DevDesc;
    long                    lFlags;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

    gl_Device = gpfnl_AddDisplayInfo( gl_Driver, 0, 0, "dev_add", 0);
    gpfnl_AddDisplayInfo( gl_Driver, gl_Device, 0, "dev_name", (unsigned long) _szName );
    gpfnl_AddDisplayInfo( gl_Driver, gl_Device, 0, "dev_desc", (unsigned long) _szDesc );
    gpfnl_AddDisplayInfo( gl_Driver, gl_Device, 0, "dev_param", (unsigned long) _pGuid );

    if ( _lpHWDesc->dcmColorModel )
    {
        _pst_DevDesc = _lpHWDesc;
        lFlags = DX6_C_Dev_Hardware;
    }
    else
    {
        _pst_DevDesc = _lpHELDesc;
        lFlags = 0;
    }

    memset( &st_Caps, 0, sizeof( tdstGliCaps ) );
    GLI_DX6_fn_hGetDriverCaps( &st_Caps, lFlags, (LPDIRECTDRAW4) _lpContext );
    GLI_DX6_fn_hGetDeviceCaps( &st_Caps, (LPDIRECTDRAW4) _lpContext, _pst_DevDesc );
    //GLI_DX6_fn_hGetPixelFormats();
    //GLI_DX6_fn_vPrecalculateTextureSize();

    gpfnl_AddDisplayInfo( gl_Driver, gl_Device, 0, "dev_caps", (unsigned long) &st_Caps );

    return D3DENUMRET_OK;
}


/*
 ----------------------------------------------------------------------------------------
  Description   : enumeration call back to get all drivers
 ----------------------------------------------------------------------------------------
 */
BOOL WINAPI DX6_fnb_DriverCallback( GUID FAR *lpGUID, LPSTR lpDriverDescription, LPSTR lpDriverName, LPVOID lpContext )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    LPDIRECT3D3				pD3D = NULL;
    LPDIRECTDRAW4			pDD4 = NULL;
    LPDIRECTDRAW			pDD  = NULL;
    HRESULT                 hr;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
    gl_Driver = gpfnl_AddDisplayInfo( 0, 0, 0, "dispadd", 0);
    gpfnl_AddDisplayInfo( gl_Driver, 0, 0, "dispname", (unsigned long) lpDriverName );
    gpfnl_AddDisplayInfo( gl_Driver, 0, 0, "dispdesc", (unsigned long) lpDriverDescription );
    gpfnl_AddDisplayInfo( gl_Driver, 0, 0, "dispparam", (unsigned long) lpGUID );

    hr = DirectDrawCreate( lpGUID, &pDD, NULL );
    if (hr == DD_OK)
    {
        /* Get a ptr to an IDirectDraw4 interface. This interface to DirectDraw represents the DX6 version of the API.*/
        hr = pDD->lpVtbl->QueryInterface( pDD, &IID_IDirectDraw4, (LPVOID *) &pDD4 );
        if (hr == DD_OK)
        {
            /* Query DirectDraw for access to Direct3D*/
	        hr = pDD4->lpVtbl->QueryInterface( pDD4, &IID_IDirect3D3, (VOID**)&pD3D );
            if ( hr == DD_OK )
            {
                hr = pD3D->lpVtbl->EnumDevices( pD3D, DX6_fnh_DevicesCallback, pDD4 );
                pDD4->lpVtbl->EnumDisplayModes( pDD4, 0, NULL, 0, DX6_fnh_ModeCallback );
            }
        }
    }

    if (pDD)    pDD->lpVtbl->Release(pDD);
    if (pD3D)   pD3D->lpVtbl->Release(pD3D);
    if (pDD4)   pDD4->lpVtbl->Release(pDD4);

    /* continue enumeration*/
    return TRUE;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : Function to Get All display information
 ----------------------------------------------------------------------------------------
 */
long __declspec(dllexport) GLI_DRV_fn_lGetAllDisplayConfig( FARPROC _x_Fct )
{
    HRESULT hr;
    long    lVersion;

    gpfnl_AddDisplayInfo = (long (__cdecl *)( long, long, long, char *, unsigned long ) ) _x_Fct;

    gpfnl_AddDisplayInfo( 0, 0, 0, "dll_bmp", 2);

    lVersion = gpfnl_AddDisplayInfo(0,0,0,"miscdxversiondetect", 0);
    if (lVersion < 0x600)
        return 0;
    
    hr = DirectDrawEnumerate( DX6_fnb_DriverCallback, NULL );
    if (hr != DD_OK )
        return 0;

    return 1;
}