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

/*
 =======================================================================================
    Include 
 =======================================================================================
 */
#define INITGUID

#include "OGL_Options.h"


#ifdef USE_DDRAW
	#include <ddraw.h>
#else
	#include <windows.h>            // Window defines
#endif //USE_DDRAW

#include <d3d.h>
#include <gl/gl.h>
//#include <gl/glu.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 "OGL_Errors.h"
#include "OGL_Thread.h"

BOOL g_bReinitDevice = TRUE;



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


/*
 =======================================================================================
    Constants 
 =======================================================================================
 */

/*
 * for gamma correction
 */
static float    gs_fGammaMin = 0.0f;
static float    gs_fGammaMax = 4.0f;

/*
 =======================================================================================
    Protos
 =======================================================================================
 */
void GLI_DRV_xClearViewingList ( void );

//#define  DEST_WIDTH  320
//#define  DEST_HEIGHT 200

long                            g_lDestWidth, g_lDestHeight;
long                            g_lDestWidthInit, g_lDestHeightInit;

static BOOL                    gs_bIsWindowed = TRUE;

HWND                     gs_hWnd = NULL;

#ifdef USE_DDRAW
	static LPDIRECTDRAW             gs_lpDD = NULL;
#endif //USE_DDRAW

//HGLRC                    gs_hRC;                // Permenant Rendering context
HDC                      gs_hDC;                // Private GDI Device context

static BOOL                    gs_bCanReleaseDDObject = TRUE;

RECT					g_rcScreenRect      ;
RECT					g_rcViewportRect    ;

/*
 * function prototypes
 */
static void GLI_fn_vRelease3DEnvironment( char _cDirectDraw );
static HRESULT GLI_fn_hCreateDirectDraw( void );
static BOOL GLI_fn_bInitialize3DEnvironment( BOOL _bFullScreen, long _lWidth, long _lHeight, long _lBpp );
       HRESULT GLI_fn_hRestoreSurfaces( void );




/*
 =======================================================================================
    function use for windowed mode
 =======================================================================================
 */

BOOL __declspec(dllexport) GLI_DRV_bWindowedModeIsOptimized(void)
{
	return FALSE;
}

void __declspec(dllexport) GLI_DRV_vOptimizedWindowedMode(void)
{
}

void __declspec(dllexport) GLI_DRV_vNonOptimizedWindowedMode(void)
{
}


/*
 ----------------------------------------------------------------------------------------
  Description   : release directX object created for windowed mode
 ----------------------------------------------------------------------------------------
 */
void GLI_fn_vReleaseDDObject( void )
{
}


/*
 ----------------------------------------------------------------------------------------
  Description   : prepare display for windowed mode
 ----------------------------------------------------------------------------------------
 */
BOOL __declspec(dllexport) GLI_DRV_bPrepareForGliWindowed( HWND _hWnd )
{
    g_lDestWidth = g_lDestWidthInit;
    g_lDestHeight = g_lDestHeightInit;
    gs_bIsWindowed = FALSE;
    gs_hWnd = _hWnd; //bart990217
	return TRUE;
//    return FALSE;
}

/*
 ----------------------------------------------------------------------------------------
  Description   : something to do when app is activate/deactivate
 ----------------------------------------------------------------------------------------
 */
void __declspec(dllexport) GLI_DRV_vActivateGli( HWND _hWnd, BOOL _bActivate )
{
}


/*
 ----------------------------------------------------------------------------------------
  Description   : prepare display for full screen mode
 ----------------------------------------------------------------------------------------
 */
void __declspec(dllexport) GLI_DRV_vPrepareForGliFullScreen( HWND _hWnd )
{
    g_lDestWidth = g_lDestWidthInit;
    g_lDestHeight = g_lDestHeightInit;
    gs_bIsWindowed = FALSE;
    gs_hWnd = _hWnd; //bart990217
}

/* bart990217
 ----------------------------------------------------------------------------------------
  Description   : readapt window (called when window move or is resized)
 ----------------------------------------------------------------------------------------
 */

void __declspec(dllexport) GLI_DRV_vReadaptDisplay( void )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    RECT    rcNewWindowRect;
    DWORD   dwNewWidth, dwNewHeight;
	DWORD   dwWidth, dwHeight;
	DWORD   dwViewportWidth, dwViewportHeight;
    BOOL bOK;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

 
    GetClientRect( gs_hWnd, &rcNewWindowRect ); // gs_hWnd = M_h_MFCWinCm_GetMainWndHandle() ?
    dwWidth     = g_rcScreenRect.right - g_rcScreenRect.left;
    dwNewWidth  = rcNewWindowRect.right - rcNewWindowRect.left;
    dwHeight    = g_rcScreenRect.bottom - g_rcScreenRect.top;
    dwNewHeight = rcNewWindowRect.bottom - rcNewWindowRect.top;
 
    dwViewportWidth     = g_rcViewportRect.right - g_rcViewportRect.left;
    dwViewportHeight    = g_rcViewportRect.bottom - g_rcViewportRect.top;
    if ( (dwWidth != dwNewWidth) || (dwHeight != dwNewHeight ) || (dwWidth != dwViewportWidth) || (dwHeight != dwViewportHeight ) )
    {
#if defined (REINIT_DEVICE_ONSIZE)
		g_bReinitDevice = TRUE;
#else
		g_bReinitDevice = FALSE;
#endif //defined (REINIT_DEVICE_ONSIZE)

		GLI_fn_vRelease3DEnvironment( FALSE );
		bOK = GLI_fn_bInitialize3DEnvironment( FALSE, dwNewWidth, dwNewHeight, 16 ); //( gs_hWnd, FALSE, 0, 0, 0 );
		if (bOK)
			GLI_MDRV_vReloadTextures();
		g_bReinitDevice = TRUE;
    }/*
    else
    {
        //ClientToScreen( gs_hWnd, (POINT*)&rcNewWindowRect.left );
        //ClientToScreen( gs_hWnd, (POINT*)&rcNewWindowRect.right );
        g_rcScreenRect = rcNewWindowRect;
    }*/

}

/*
 ----------------------------------------------------------------------------------------
  Description   : copy 3DFX back buffer into D3D back bufer
 ----------------------------------------------------------------------------------------
 */
void GLI_fn_vCopyBackBufferToD3DBackBuffer()
{
}



/*
 =======================================================================================
    Lock / unlock backbuffer 
 =======================================================================================
 */

//#include "OGL_Lock.c"
//#define W_BUFFER 640
//#define H_BUFFER 480

//#define W_TEXTURE 1024
//#define H_TEXTURE 1024


//unsigned short g_auwBuffer[W_TEXTURE*H_TEXTURE];
//unsigned long g_aulTmpBuffer[W_TEXTURE*H_TEXTURE];

extern void* g_p_vVirtualScreen;
extern long g_lPitch;

char g_cSkipRead, g_cSkipDraw;

BOOL GLI_DRV_bLockDevice( void **_pp_vVirtualScreen, long *_p_lPitch )
{

	if (g_cSkipRead == 0) {
		g_cSkipRead = 1;
		OGLThread_fn_vWaitForSynchro();
		OGLThread_fn_vPostCmd(OGLT0_LOCKDEVICE); //fn_OGLThread_vLockDevice
		OGLThread_fn_vWaitForSynchro();
	}

	*_pp_vVirtualScreen = g_p_vVirtualScreen;
	*_p_lPitch = g_lPitch; //W_TEXTURE*2;
	return TRUE;
}

BOOL GLI_DRV_bUnlockDevice( void )
{
	if (g_cSkipDraw == 0) {
		g_cSkipDraw = 1;
	}

	if (g_cSkipDraw == 2) {
		OGLThread_fn_vWaitForSynchro();
		OGLThread_fn_vPostCmd(OGLT0_UNLOCKDEVICE); //fn_OGLThread_vUnlockDevice
	}

	return TRUE;
}

/*
 =======================================================================================
    Init / close
 =======================================================================================
 */

/*
 ----------------------------------------------------------------------------------------
  Description   : open Glide with good resolution
 ----------------------------------------------------------------------------------------
 */

#define HAS_ACCELERATION(f) \
  ((((f) & PFD_GENERIC_FORMAT) != 0) == (((f) & PFD_GENERIC_ACCELERATED) != 0))


#define COMPARE_PDF_KEY(varLeft, varRight) \
{\
	difference = varRight - varLeft;/*increasing order*/\
	if (difference)\
		return difference;\
}


static int __cdecl ComparePFD(const void* p_xLeft, const void* p_xRight) 
{
	int difference;
    PIXELFORMATDESCRIPTOR pfdLeft, pfdRight;
	DWORD dwFlagsLeft, dwFlagsRight;

	DescribePixelFormat(gs_hDC, *(int*)p_xLeft, sizeof(PIXELFORMATDESCRIPTOR), &pfdLeft);
	DescribePixelFormat(gs_hDC, *(int*)p_xRight, sizeof(PIXELFORMATDESCRIPTOR), &pfdRight);
	dwFlagsLeft = pfdLeft.dwFlags;
	dwFlagsRight = pfdRight.dwFlags;

	COMPARE_PDF_KEY( HAS_ACCELERATION(dwFlagsLeft), HAS_ACCELERATION(dwFlagsRight) )

	// biggest cDepthBits :
	COMPARE_PDF_KEY(pfdLeft.cDepthBits, pfdRight.cDepthBits)

	 // smallest cColorBits : ( ? - constant when DRAW_TO_WINDOW)
	COMPARE_PDF_KEY(-pfdLeft.cColorBits, -pfdRight.cColorBits)

	// biggest sum of color bitplanes : (constant ?)
	COMPARE_PDF_KEY((pfdLeft.cRedBits + pfdLeft.cGreenBits + pfdLeft.cBlueBits), (pfdRight.cRedBits + pfdRight.cGreenBits + pfdRight.cBlueBits))

	return 0;
}

int GLI_fn_nChooseTheBestPixelFormat()
{
  #if defined (ERROR_TEST)
	char szPixelFormatChoosen[255];
  #endif //defined (ERROR_TEST)

    int i, maxpf, nbpf;
    PIXELFORMATDESCRIPTOR pfd;
	DWORD dwFlags;
	int* anPFIndex;
	int nPixelFormat = 0;

  #if defined (WORKAROUNDBUG) //Work around bug in mini drivers
	M_ASSERT( (maxpf = DescribePixelFormat(gs_hDC, 1, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) )
  #else //defined (WORKAROUNDBUG)
	M_ASSERT( (maxpf = DescribePixelFormat(gs_hDC, 0, 0, NULL)) )
  #endif //defined (WORKAROUNDBUG)

    nbpf = 0;
	anPFIndex = (int *) GLI_MDRV_p_vTmpMalloc(maxpf * sizeof(int));

	/* loop through all the pixel formats */
    for(i = 1; i <= maxpf; i++) {

		M_ASSERT( DescribePixelFormat(gs_hDC, i, sizeof(PIXELFORMATDESCRIPTOR), &pfd) )
		dwFlags = pfd.dwFlags;

		/* skip formats that don't support OpenGL + draw to window + db buff + RGBA	+ color + depth */
		if(
		     !(dwFlags & PFD_SUPPORT_OPENGL)
		  || !(dwFlags & PFD_DRAW_TO_WINDOW)
		  || !(dwFlags & PFD_DOUBLEBUFFER)
		  || (pfd.iPixelType != PFD_TYPE_RGBA)
	      || (pfd.cColorBits < 16)
		  || (pfd.cDepthBits < 16)
		  || (pfd.iLayerType != PFD_MAIN_PLANE) // ?
		  )
			continue;
		anPFIndex[nbpf] = i;
		nbpf++;
	}

	if (nbpf != 0) {
	    qsort(anPFIndex, nbpf, sizeof(int), ComparePFD);
		nPixelFormat = anPFIndex[0];

	  #if defined (ERROR_TEST)
		M_OUTPUT("Ordered Formats : g a dp cl sz\n");
		M_OUTPUT("--------------------------------\n");
		for (i = 0; i<nbpf ; i++) {
			M_ASSERT( DescribePixelFormat(gs_hDC, anPFIndex[i], sizeof(PIXELFORMATDESCRIPTOR), &pfd) )
			dwFlags = pfd.dwFlags;
			sprintf(szPixelFormatChoosen, "%2d  Format 0x%02x : %c %c %2d %2d %2d\n",
				i+1, anPFIndex[i], 
				(dwFlags & PFD_GENERIC_FORMAT ? 'y' : '.'),
				(dwFlags & PFD_GENERIC_ACCELERATED ? 'y' : '.'),
				pfd.cDepthBits,
				pfd.cColorBits,
				pfd.cRedBits + pfd.cGreenBits + pfd.cBlueBits);
			M_OUTPUT(szPixelFormatChoosen);
		}
		M_OUTPUT("------------------------------\n");
	  #endif //defined (ERROR_TEST)

	}

	GLI_MDRV_vTmpFree(anPFIndex);

	return nPixelFormat;
}

BOOL GLI_fn_bSetDCPixelFormat()
{
	int nPixelFormat;
	BOOL bFormatAvailable = FALSE;
	
	char szPixelFormatChoosen[255];

	PIXELFORMATDESCRIPTOR pfd;
	DWORD dwFlags;

		
	nPixelFormat = GLI_fn_nChooseTheBestPixelFormat();
	
	if (nPixelFormat != 0)
		M_ASSERT( (bFormatAvailable = DescribePixelFormat( gs_hDC, nPixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd)) )

	if (bFormatAvailable) {

		dwFlags = pfd.dwFlags;
		if  (
				   !(dwFlags & PFD_SUPPORT_OPENGL) 
				|| !(dwFlags & PFD_DRAW_TO_WINDOW) 
				|| !(dwFlags & PFD_DOUBLEBUFFER)
				|| (pfd.iPixelType != PFD_TYPE_RGBA)
				|| (pfd.cColorBits < 16)
				|| (pfd.cDepthBits < 16)
				|| (pfd.iLayerType != PFD_MAIN_PLANE) // ?
			)
			bFormatAvailable = FALSE;
	}

	// Set the pixel format for the device context
	if (bFormatAvailable)
		M_ASSERT( (bFormatAvailable = SetPixelFormat(gs_hDC, nPixelFormat, &pfd)) )

	// ERREUR
	if (!bFormatAvailable)
	{
		MessageBox( NULL, "No pixel format available !\n\nARE REQUIRED :\nsupport OpenGL,\ndraw to window,\ndouble buffer,\ntype RGBA,\ncolorbits >= 16\ndepthbits >= 16", "ERROR : ChoosePixelFormat", MB_OK|MB_ICONSTOP );
		M_OUTPUT("No pixel format available !\n");
		return FALSE;
	}

	sprintf(szPixelFormatChoosen, "Pixel Format Choosen : 0x%02x\n", nPixelFormat);
	M_OUTPUT(szPixelFormatChoosen);
		
	// WARNING IF NO ACCELERATION
	if ( !HAS_ACCELERATION(dwFlags) )
	{
		MessageBox( NULL, "No hardware acceleration => Software only !", "WARNING : SetPixelFormat", MB_OK|MB_ICONINFORMATION );
		M_OUTPUT("No hardware acceleration => Software only !\n");
	}

	return TRUE;
}


#if defined (USE_DEVMODE)

void Log(BYTE* buf)
{
	M_OUTPUT(buf);
}

void ListDisplaySettings(void) {
  DEVMODE devMode;
  int   i;
  int   modeExist;
  BYTE    buf[1024];

  /* enumerate all modes to log */
  modeExist = EnumDisplaySettings(NULL, 0, &devMode);
  sprintf(buf, "Available screen modes for %s:\n", devMode.dmDeviceName);
  Log(buf);
  for (i=0; modeExist;i++) {
    sprintf(buf, "%ldx%ldx%ld-bit color (%ld hertz)\n", devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmBitsPerPel, devMode.dmDisplayFrequency);
    Log(buf);

    modeExist = EnumDisplaySettings(NULL, i, &devMode);
  }
}

/* Change the resolution & bitdepth:
 * -Change back by calling ChangeDisplaySettings(0,0);
 * -Note the use of the undocumented CDS_FULLSCREEN to leave their icons alone
 * -Note the funny fallback to handle both Win95 and WinNT
 */
BOOL ChangeResolution(DWORD w, DWORD h, USHORT bitdepth) {
  DEVMODE devMode;
  int   modeExist;
  int   modeSwitch;
  int   closeMode = 0;
  int   i;
  BYTE    buf[256];

  for (i=0; ;i++) {
    modeExist = EnumDisplaySettings(NULL, i, &devMode);

    /* Check if we ran out of modes */
    if (!modeExist) {
      ListDisplaySettings();

      /* Pony up an error message */
      sprintf(buf, "No matching mode to %ldx%ldx%ld-bit color available\n", w, h, bitdepth);
      Log(buf);
      break;
    }

    /* Check for a matching mode */
    if ( (devMode.dmBitsPerPel == bitdepth) 
       &&(devMode.dmPelsWidth == w) 
       &&(devMode.dmPelsHeight == h) )
    {
      sprintf(buf, "Trying %ldx%ldx%ld-bit color (%ld hertz)\n", devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmBitsPerPel, devMode.dmDisplayFrequency);
      Log(buf);
      modeSwitch = ChangeDisplaySettings(&devMode, CDS_FULLSCREEN); 
      if (modeSwitch==DISP_CHANGE_SUCCESSFUL) return TRUE;
      Log("Nope, didnt work\n");
      if (!closeMode) closeMode = i;
    }
  }

  //Might be running in Windows95, let's try without the hertz change 
  EnumDisplaySettings(NULL, closeMode, &devMode);
  devMode.dmBitsPerPel = bitdepth; 
  devMode.dmPelsWidth  = w; 
  devMode.dmPelsHeight = h; 
  devMode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; 
  sprintf(buf, "Trying %ldx%ldx%ld-bit color (Win95 Hack)\n", devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmBitsPerPel);
  Log(buf);
  modeSwitch = ChangeDisplaySettings(&devMode, CDS_FULLSCREEN); 
  if(modeSwitch == DISP_CHANGE_SUCCESSFUL) return TRUE;
  Log("Nope, didnt work\n");

  /* try with separate changes to bitdepth and resolution */
  devMode.dmFields = DM_BITSPERPEL; 
  sprintf(buf, "Trying %ldx%ldx%ld-bit color (Separate BPP switch)\n", devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmBitsPerPel);
  Log(buf);
  modeSwitch = ChangeDisplaySettings(&devMode, CDS_FULLSCREEN);
  if(modeSwitch == DISP_CHANGE_SUCCESSFUL) {
    devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT; 
    sprintf(buf, "Trying %ldx%ldx%ld-bit color (Separate resolution switch)\n", devMode.dmPelsWidth, devMode.dmPelsHeight, devMode.dmBitsPerPel);
    Log(buf);
    modeSwitch = ChangeDisplaySettings(&devMode, CDS_FULLSCREEN); 
    if(modeSwitch == DISP_CHANGE_SUCCESSFUL) return TRUE;
    ChangeDisplaySettings(NULL, 0);
  }
  Log("Nope, didnt work\n");

  /* Well nothing works now does it */
  if(modeSwitch == DISP_CHANGE_RESTART) { 
    sprintf(buf, "You must change your video mode to %ldx%ldx%ld-bit color and then restart\n", w, h, bitdepth);
    Log(buf);
  } else if(modeSwitch == DISP_CHANGE_BADMODE) {
    sprintf(buf, "The video mode %ldx%ldx%ld-bit color is not supported\n", w, h, bitdepth);
    Log(buf);
  } else if(modeSwitch == DISP_CHANGE_FAILED) {
    sprintf(buf, "Hardware failed to change to %ldx%ldx%ld-bit color\n", w, h, bitdepth);
    Log(buf);
  } else {
    sprintf(buf, "Failed to change to %ldx%ldx%ld-bit color - unknown reason\n", w, h, bitdepth);
    Log(buf);
  }
  return FALSE; 
}

#endif //USE_DEVMODE


/*
 ----------------------------------------------------------------------------------------
  Description   : init driver
 ----------------------------------------------------------------------------------------
 */



extern long GLI_fn_lGetTotalTextureMemorySize( void );
extern void GLI_fn_vInitRenderParameters( void );

BOOL GLI_fn_bSetDisplayResolution(BOOL _bFullScreen, long _lWidth, long _lHeight, long _lBpp)
{
/*
    dwCoopFlag = ( (_bFullScreen ) ? (DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN) : DDSCL_NORMAL) | DDSCL_FPUSETUP;
    
    hr = g_pDD4->lpVtbl->SetCooperativeLevel( g_pDD4, (_bFullScreen ) ? hWnd : NULL, dwCoopFlag );
    if( FAILED( hr ) )
        return hr;
 
    // change display mode
    if (_bFullScreen)
    {
        hr = g_pDD4->lpVtbl->SetDisplayMode(g_pDD4, _lWidth, _lHeight, _lBpp, 0, 0);
        if( FAILED( hr ) )
            return hr;
    }
 
*/

	long lWindowStyles;

	if (_bFullScreen)
	//only WS_POPUP
	{
		M_ASSERT( (lWindowStyles = GetWindowLong(gs_hWnd, GWL_STYLE)) )
		lWindowStyles &= ~(WS_CAPTION | WS_SIZEBOX /*| WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX*/);
		M_ASSERT( SetWindowLong(gs_hWnd, GWL_STYLE, lWindowStyles) )
	}
	else
	//windowed sizable : WS_POPUP | WS_CAPTION | WS_SIZEBOX | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
	//windowed non sizable : WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX
	{
		M_ASSERT( (lWindowStyles = GetWindowLong(gs_hWnd, GWL_STYLE)) )
	  #if defined(SIZABLE)
		lWindowStyles |= WS_CAPTION | WS_SIZEBOX /*| WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX*/;
	  #else //defined(SIZABLE)
		lWindowStyles |= WS_CAPTION /*| WS_SYSMENU | WS_MINIMIZEBOX*/;
	  #endif //defined(SIZABLE)
		M_ASSERT( SetWindowLong(gs_hWnd, GWL_STYLE, lWindowStyles) )
	}


  #if defined (USE_DDRAW)
	// Create the direct draw interface
	if(FAILED(DirectDrawCreate(NULL,&gs_lpDD,NULL)))
    {
		gs_lpDD->lpVtbl->Release( gs_lpDD );
	    gs_lpDD = NULL;
    }

    // Set exclusive mode so we can change the color depth
   #if defined(FULL_SCREEN)
	if(gs_lpDD && FAILED(gs_lpDD->lpVtbl->SetCooperativeLevel( gs_lpDD, gs_hWnd, DDSCL_EXCLUSIVE |  DDSCL_FULLSCREEN )))
   #else
	if(gs_lpDD && FAILED(gs_lpDD->lpVtbl->SetCooperativeLevel( gs_lpDD, gs_hWnd, DDSCL_EXCLUSIVE )))
   #endif //FULL_SCREEN
    {
	    gs_lpDD->lpVtbl->Release( gs_lpDD );
		gs_lpDD = NULL;
    }


	// Change the display mode to 640 X 480 X 16bpp
	//if(gs_lpDD && FAILED(gs_lpDD->lpVtbl->SetDisplayMode( gs_lpDD, 640, 480, 16 )))
	if(gs_lpDD && FAILED(gs_lpDD->lpVtbl->SetDisplayMode( gs_lpDD, _lWidth, _lHeight, _lBpp )))
	{
	    gs_lpDD->lpVtbl->Release( gs_lpDD );
		gs_lpDD= NULL;
    }

	// Get out of exclusive mode - most OpenGL drivers will not work correctly when set
	if(gs_lpDD && FAILED(gs_lpDD->lpVtbl->SetCooperativeLevel( gs_lpDD, gs_hWnd, DDSCL_NORMAL)))
	{
	    gs_lpDD->lpVtbl->Release( gs_lpDD );
		gs_lpDD = NULL;
    }
  #elif defined (USE_DEVMODE)
	ChangeResolution(_lWidth, _lHeight, _lBpp); //ChangeResolution(640, 480, 16);
  #endif //USE_DDRAW or USE_DEVMODE
	
	return TRUE;
}

void GLI_DRV_xInitDriver( HWND _hWnd, BOOL _bFullScreen, long _lWidth, long _lHeight, long _lBpp )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    BOOL bOK;
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

	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 (D3DTLVERTEX))<<GLI_MaxZListeTrianglesPO2);
    GLI_BIG_GLOBALS -> ulCurrentZTable = 0;
    GLI_DRV_xClearViewingList();
  
	
	
	/* retrieve window application */
    gs_hWnd = _hWnd;

	ShowWindow( gs_hWnd, SW_SHOWNORMAL );
    UpdateWindow( gs_hWnd );
    SetFocus(gs_hWnd);

	OGLThread_fn_vCreateThread();
	bOK = GLI_fn_bInitialize3DEnvironment( _bFullScreen, _lWidth, _lHeight, _lBpp );
	if (!bOK)
		exit(-1);

    /*
     * Set driver capabilities
     */
    memset( g_p_stGliCaps, 0, sizeof( tdstGliCaps ) );
    g_p_stGliCaps->ulDriverCaps                 = GLICAPS_DRV_C_ulIsHardware | GLICAPS_DRV_C_ulCanBeWindowed | GLICAPS_DRV_C_ulSupportAlphaTest | GLICAPS_DRV_C_ulReadjustViewport; //bart
    g_p_stGliCaps->ulTextureCaps                = GLICAPS_TEX_C_ulSupport8P | GLICAPS_TEX_C_ulSupportNonSquare | GLICAPS_TEX_C_ulSupportMipmap;
    g_p_stGliCaps->ulTextureMaxSize             = 256;
    g_p_stGliCaps->ulTotalTextureMemory         = GLI_fn_lGetTotalTextureMemorySize();
    g_p_stGliCaps->ulTotalAGPMemory             = 0;
    g_p_stGliCaps->ucPrimarySurfacePixelFormat  = GLD_C_xR5G6B5PixelFormat;
}
    
/*
 ----------------------------------------------------------------------------------------
  Description   : close driver
 ----------------------------------------------------------------------------------------
 */
void GLI_DRV_vCloseDriver()
{
    GLI_fn_vRelease3DEnvironment( TRUE );
	OGLThread_fn_vTerminateThread();

	if (GLI_BIG_GLOBALS->p_TheZListe) {
		if (GLI_BIG_GLOBALS->p_TheZListe->p_TableOfPoints) {
			GLI_MDRV_vTmpFree( GLI_BIG_GLOBALS->p_TheZListe->p_TableOfPoints );
			GLI_BIG_GLOBALS->p_TheZListe->p_TableOfPoints = NULL;
		}
		GLI_MDRV_vTmpFree( GLI_BIG_GLOBALS->p_TheZListe );
		GLI_BIG_GLOBALS->p_TheZListe = NULL;
	}
}

/*
 =======================================================================================
    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_vClearDevice(BOOL ZBuffer, BOOL ColorBuffer, unsigned long Color);

void GLI_DRV_vClearZBufferRegion(long lXStart,long lXEnd,long lYStart,long lYEnd)
{
	GLI_DRV_vClearDevice(TRUE, FALSE, 0L); // glDepthMask( GL_TRUE ); glClear(GL_DEPTH_BUFFER_BIT);
	
    /*
    grDepthMask( FXTRUE );
	grColorMask( FXFALSE, FXFALSE );
	grBufferClear( 0, 0, GR_WDEPTHVALUE_FARTHEST  );
	grColorMask( FXTRUE, FXFALSE );
    */
	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()) 
        return;

	OGLThread_fn_vPostCmd_2Long(OGLT2_CLEARDEVICE, (ZBuffer? 2L:0L) + (ColorBuffer? 1L:0L) /*ZBuffer + ColorBuffer*/, (long)Color );
}

/*
 ----------------------------------------------------------------------------------------
  Description   : flip front and back buffer
 ----------------------------------------------------------------------------------------
 */

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;
    
	OGLThread_fn_vWaitForSynchro(); 
	OGLThread_fn_vPostCmd(OGLT0_FLUSH);
    
    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();

	g_cSkipRead = 0;
	if (g_cSkipDraw == 1) {
		g_cSkipDraw = 2;
		GLI_DRV_bUnlockDevice();
	}
	g_cSkipDraw = 0;

    PRF_MDRV_lIncIndependantVariable( PRF_C_ulIdpRasterTime, TMR_fn_ulFastGetInternalCounter() );

    PRF_MDRV_vStartChrono (PRF_C_ulFctFlip , NULL);


	OGLThread_fn_vPostCmd(OGLT0_SWAP);

    if ( gs_bIsWindowed )
    {
    }
	else
	{
	}

    PRF_MDRV_vStopChrono  (PRF_C_ulFctFlip , NULL);
    PRF_MDRV_vStartChrono (PRF_C_ulFctMainLoop, NULL);
}

void GLI_DRV_vFlipDeviceWithSyncro()
{
    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 )
{
}




/*******************************************************************************************************************/
/*
 =======================================================================================
	Internal functions 
 =======================================================================================
 */
 
extern void GLI_DRV_vUnLoadTextures();

static void GLI_fn_vRelease3DEnvironment( char _cDirectDraw )
{
    /*
     * Release texture
     */
    GLI_DRV_vUnLoadTextures();

	OGLThread_fn_vResumeContext(g_bReinitDevice);

    /* Do a safe check for releasing DDRAW. RefCount must be zero.*/
    if( _cDirectDraw )
	{
	    //g_pDD4->lpVtbl->SetCooperativeLevel( g_pDD4, gs_hWnd, DDSCL_NORMAL );
        //M_ReleaseAllD3DObject( g_pDD4 );
  #ifdef USE_DDRAW
		if(gs_lpDD)
			gs_lpDD->lpVtbl->Release( gs_lpDD );
  #endif //USE_DDRAW
	}
 
}
 
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Init Direct draw object (device, surface and viewport )
 ----------------------------------------------------------------------------------------
 */
static BOOL GLI_fn_bInitialize3DEnvironment( BOOL _bFullScreen, long _lWidth, long _lHeight, long _lBpp )
{
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
	BOOL bOK;
  #if !defined (SIZABLE)
	long lWidth, lHeight;
  #endif //!defined (SIZABLE)
    /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

    /*
	g_bFullScreen = _bFullScreen;
    if (g_bFullScreen)
    {
        g_lFullScreenWidth  = _lWidth;
        g_lFullScreenHeight = _lHeight;
        g_lFullScreenBpp    = _lBpp;
    }
	*/
    
	if (_bFullScreen)
    {
        SetRect(&g_rcViewportRect, 0, 0, _lWidth, _lHeight );
        memcpy(&g_rcScreenRect, &g_rcViewportRect, sizeof(RECT) );
    }
    else
    {
  #if defined (SIZABLE)

        GetClientRect( gs_hWnd, &g_rcScreenRect );
        //GetClientRect( gs_hWnd, &g_rcViewportRect );
		SetRect(&g_rcViewportRect, 0, 0, _lWidth, _lHeight );

        //ClientToScreen( gs_hWnd, (POINT*)&g_rcScreenRect.left );
        //ClientToScreen( gs_hWnd, (POINT*)&g_rcScreenRect.right );
  
  #else //defined (SIZABLE)

		lWidth = _lWidth + GetSystemMetrics(SM_CXDLGFRAME)*2;
		lHeight = _lHeight + GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYDLGFRAME)*2;


		SetWindowPos( gs_hWnd, HWND_TOP , 0, 0, lWidth, lHeight, SWP_NOMOVE );
        GetClientRect( gs_hWnd, &g_rcScreenRect );
        GetClientRect( gs_hWnd, &g_rcViewportRect );
        ClientToScreen( gs_hWnd, (POINT*)&g_rcScreenRect.left );
        ClientToScreen( gs_hWnd, (POINT*)&g_rcScreenRect.right );
		assert (g_rcScreenRect.right - g_rcScreenRect.left == _lWidth) ;
		assert (g_rcScreenRect.bottom - g_rcScreenRect.top == _lHeight) ;

  #endif //defined (SIZABLE)
    }
 
	bOK = GLI_fn_bSetDisplayResolution(_bFullScreen, _lWidth, _lHeight, _lBpp);
    if( !bOK )
        return FALSE;

    // Store the device context
    gs_hDC = GetDC( gs_hWnd );

    // Select the pixel format
    bOK = GLI_fn_bSetDCPixelFormat();
    if( !bOK )
        return FALSE;

	OGLThread_fn_vCreateContext(g_bReinitDevice);

    /*
     * Init render parameters
     */
    GLI_fn_vInitRenderParameters();

	return TRUE;
}
/*******************************************************************************************************************/







/*
 ----------------------------------------------------------------------------------------
  Description   : enumerate display mode
 ----------------------------------------------------------------------------------------
 */
long __declspec(dllexport) GLI_DRV_fnl_EnumModes( char *_sz_DriverName, char *_sz_DeviceName )
{
    //GLI_MDRV_lAddDisplayMode( 1, 640, 480, 16 );
    GLI_MDRV_lAddDisplayMode( 0, 640, 480, 16 );
	GLI_MDRV_lAddDisplayMode( 0, 800, 600, 16 );
    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 )
{
//    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;

	gpfnl_AddDisplayInfo( 0, 0, 0, "dll_bmp", 3);
    
    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) "---" );

	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", 640 );
    gpfnl_AddDisplayInfo( l_Disp, l_Dev, l_Mode, "modeh", 480 );

	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", 800 );
    gpfnl_AddDisplayInfo( l_Disp, l_Dev, l_Mode, "modeh", 600 );

    return 1;
}




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