/*
===========================================================================
Copyright (C) 1997-2001 Id Software, Inc.

This file is part of Quake 2 source code.

Quake 2 source code is free software; you can redistribute it
and/or modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the License,
or (at your option) any later version.

Quake 2 source code is distributed in the hope that it will be
useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Quake 2 source code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
===========================================================================
*/

/*
** GLW_IMP.C
**
** This file contains ALL Win32 specific stuff having to do with the
** OpenGL refresh.  When a port is being made the following functions
** must be implemented by the port:
**
** GLimp_EndFrame
** GLimp_Init
** GLimp_Shutdown
** GLimp_SwitchFullscreen
**
*/
#include <assert.h>
#include <windows.h>
#include "../renderer/r_local.h"
#include "resource.h"
#include "glw_win.h"
#include "winquake.h"

static qboolean GLimp_SwitchFullscreen( int width, int height );
qboolean GLimp_InitGL (void);

glwstate_t glw_state;

extern cvar_t *vid_fullscreen;
extern cvar_t *vid_ref;

// Knightmare- added Vic's hardware gammaramp
WORD original_ramp[3][256];
WORD gamma_ramp[3][256];

void InitGammaRamp (void)
{
	if (!r_ignorehwgamma->value)
	{
		if (qwglGetDeviceGammaRamp3DFX)
	/*	{
			WORD newramp[3*256];
			int j;

			glState.gammaRamp = qwglGetDeviceGammaRamp3DFX ( glw_state.hDC, newramp );

			for (j = 0; j < 256; j++)
			{
				original_ramp[0][j] = newramp[j+0];
				original_ramp[1][j] = newramp[j+256];
				original_ramp[2][j] = newramp[j+512];
			}
		}*/
			glState.gammaRamp = qwglGetDeviceGammaRamp3DFX ( glw_state.hDC, original_ramp );
		else
			glState.gammaRamp = GetDeviceGammaRamp ( glw_state.hDC, original_ramp );
	}
	else
		glState.gammaRamp = false;

	if (glState.gammaRamp)
		vid_gamma->modified = true;
}

void ShutdownGammaRamp (void)
{
//	if (r_ignorehwgamma->value)
	if (!glState.gammaRamp)
		return;

	if (qwglSetDeviceGammaRamp3DFX)
/*	{
		WORD newramp[3*256];
		int j;

		for (j = 0; j < 256; j++)
		{
			newramp[j+0] = original_ramp[0][j];
			newramp[j+256] = original_ramp[1][j];
			newramp[j+512] = original_ramp[2][j];
		}
		qwglSetDeviceGammaRamp3DFX ( glw_state.hDC, newramp );
	}*/
		qwglSetDeviceGammaRamp3DFX ( glw_state.hDC, original_ramp );
	else
		SetDeviceGammaRamp (glw_state.hDC, original_ramp);
}

void UpdateGammaRamp (void)
{
	int	i, o;

	if (!glState.gammaRamp)
		return;
	
	memcpy (gamma_ramp, original_ramp, sizeof(original_ramp));

	for (o = 0; o < 3; o++) 
	{
		for (i = 0; i < 256; i++) 
		{
			signed int v;

			v = 255 * pow ((i+0.5)/255.5, vid_gamma->value ) + 0.5;
			if (v > 255) v = 255;
			if (v < 0) v = 0;
			gamma_ramp[o][i] = ((WORD)v) << 8;
		}
	}
	if (qwglSetDeviceGammaRamp3DFX)
/*	{
		WORD newramp[3*256];
		int		j;

		for (j = 0; j < 256; j++) {
			newramp[j+0] = gamma_ramp[0][j];
			newramp[j+256] = gamma_ramp[1][j];
			newramp[j+512] = gamma_ramp[2][j];
		}
		qwglSetDeviceGammaRamp3DFX (glw_state.hDC, newramp);
	}*/
		qwglSetDeviceGammaRamp3DFX (glw_state.hDC, gamma_ramp);
	else
		SetDeviceGammaRamp (glw_state.hDC, gamma_ramp);
}

void ToggleGammaRamp (qboolean enable)
{
//	WORD	newramp[3*256];
//	int		j;

	if (!glState.gammaRamp)
		return;

	if (enable)
	{
		if (qwglSetDeviceGammaRamp3DFX)
	/*	{
			for (j = 0; j < 256; j++) {
				newramp[j+0] = gamma_ramp[0][j];
				newramp[j+256] = gamma_ramp[1][j];
				newramp[j+512] = gamma_ramp[2][j];
			}
			qwglSetDeviceGammaRamp3DFX (glw_state.hDC, newramp);
		}*/
			qwglSetDeviceGammaRamp3DFX (glw_state.hDC, gamma_ramp);
		else
			SetDeviceGammaRamp (glw_state.hDC, gamma_ramp);
	}
	else
	{
		if (qwglSetDeviceGammaRamp3DFX)
	/*	{
			for (j = 0; j < 256; j++)
			{
				newramp[j+0] = original_ramp[0][j];
				newramp[j+256] = original_ramp[1][j];
				newramp[j+512] = original_ramp[2][j];
			}
			qwglSetDeviceGammaRamp3DFX ( glw_state.hDC, newramp );
		}*/
			qwglSetDeviceGammaRamp3DFX ( glw_state.hDC, original_ramp );
		else
			SetDeviceGammaRamp (glw_state.hDC, original_ramp);
	}
}
// end Vic's hardware gammaramp

static qboolean VerifyDriver( void )
{
	char buffer[1024];

//	strncpy( buffer, qglGetString( GL_RENDERER ) );
	Q_strncpyz( buffer, qglGetString( GL_RENDERER ), sizeof(buffer) );
	strlwr( buffer );
	if ( strcmp( buffer, "gdi generic" ) == 0 )
		if ( !glw_state.mcd_accelerated )
			return false;
	return true;
}


/*
** VID_CreateWindow
*/
#define	WINDOW_CLASS_NAME	"KMQuake2" // changed
#define	WINDOW_CLASS_NAME2	"KMQuake2 - The Reckoning" // changed
#define	WINDOW_CLASS_NAME3	"KMQuake2 - Ground Zero" // changed

qboolean VID_CreateWindow( int width, int height, qboolean fullscreen )
{
	WNDCLASS		wc;
	RECT			r;
	cvar_t			*vid_xpos, *vid_ypos;
	int				stylebits;
	int				x, y, w, h;
	int				exstyle;

	/* Register the frame class */
    wc.style         = 0;
    wc.lpfnWndProc   = (WNDPROC)glw_state.wndproc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = glw_state.hInstance;

	if (FS_ModType("xatrix")) { // q2mp1
		wc.hIcon         = LoadIcon(glw_state.hInstance, MAKEINTRESOURCE(IDI_ICON2));
		//wc.lpszClassName = WINDOW_CLASS_NAME2;
	}
	else if (FS_ModType("rogue"))  { // q2mp2
		wc.hIcon         = LoadIcon(glw_state.hInstance, MAKEINTRESOURCE(IDI_ICON3));
		//wc.lpszClassName = WINDOW_CLASS_NAME3;
	}
	else {
		wc.hIcon         = LoadIcon(glw_state.hInstance, MAKEINTRESOURCE(IDI_ICON1));
	}

    wc.hCursor       = LoadCursor (NULL,IDC_ARROW);
	wc.hbrBackground = (void *)COLOR_GRAYTEXT;
    wc.lpszMenuName  = 0;
	wc.lpszClassName = WINDOW_CLASS_NAME;

    if (!RegisterClass (&wc) )
		VID_Error (ERR_FATAL, "Couldn't register window class");

	if (fullscreen)
	{
		exstyle = WS_EX_TOPMOST;
		//stylebits = WS_POPUP|WS_VISIBLE;
		stylebits = WS_POPUP|WS_SYSMENU|WS_VISIBLE;
	}
	else
	{
		exstyle = 0;
		//stylebits = WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_VISIBLE;
		stylebits = WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_SYSMENU|WS_VISIBLE;
	}

	r.left = 0;
	r.top = 0;
	r.right  = width;
	r.bottom = height;

	AdjustWindowRect (&r, stylebits, FALSE);

	w = r.right - r.left;
	h = r.bottom - r.top;

	if (fullscreen)
	{
		x = 0;
		y = 0;
	}
	else
	{
		vid_xpos = Cvar_Get ("vid_xpos", "0", 0);
		vid_ypos = Cvar_Get ("vid_ypos", "0", 0);
		x = vid_xpos->value;
		y = vid_ypos->value;
	}

	glw_state.hWnd = CreateWindowEx (
		 exstyle, 
		 WINDOW_CLASS_NAME,
		 "KMQuake2",		//Knightmare changed
		 stylebits,
		 x, y, w, h,
		 NULL,
		 NULL,
		 glw_state.hInstance,
		 NULL);

	if (!glw_state.hWnd)
		VID_Error (ERR_FATAL, "Couldn't create window");
	
	ShowWindow( glw_state.hWnd, SW_SHOW );
	UpdateWindow( glw_state.hWnd );

	// init all the gl stuff for the window
	if (!GLimp_InitGL ())
	{
		VID_Printf( PRINT_ALL, "VID_CreateWindow() - GLimp_InitGL failed\n");
		return false;
	}

	SetForegroundWindow( glw_state.hWnd );
	SetFocus( glw_state.hWnd );

	// let the sound and input subsystems know about the new window
	VID_NewWindow (width, height);

	return true;
}


/*
** GLimp_SetMode
*/
rserr_t GLimp_SetMode ( int *pwidth, int *pheight, int mode, qboolean fullscreen )
{
	int width, height;
	const char *win_fs[] = { "W", "FS" };

	VID_Printf( PRINT_ALL, "Initializing OpenGL display\n");

	VID_Printf (PRINT_ALL, "...setting mode %d:", mode );

	if ( !VID_GetModeInfo( &width, &height, mode ) )
	{
		VID_Printf( PRINT_ALL, " invalid mode\n" );
		return rserr_invalid_mode;
	}

	VID_Printf( PRINT_ALL, " %dx%d %s\n", width, height, win_fs[fullscreen] );

	// destroy the existing window
	if (glw_state.hWnd)
	{
		GLimp_Shutdown ();
	}

	// do a CDS if needed
	if ( fullscreen )
	{
		DEVMODE dm;

		VID_Printf( PRINT_ALL, "...attempting fullscreen\n" );

		memset( &dm, 0, sizeof( dm ) );

		dm.dmSize = sizeof( dm );

		dm.dmPelsWidth  = width;
		dm.dmPelsHeight = height;
		dm.dmFields     = DM_PELSWIDTH | DM_PELSHEIGHT;

		// Added refresh rate control
		if ( r_displayrefresh->value != 0 )
		{
			dm.dmDisplayFrequency = r_displayrefresh->integer;
			dm.dmFields |= DM_DISPLAYFREQUENCY;
			VID_Printf( PRINT_ALL, "...using r_displayrefresh of %d\n", (int)r_displayrefresh->value );
		}

		if ( r_bitdepth->value != 0 )
		{
			dm.dmBitsPerPel = r_bitdepth->value;
			dm.dmFields |= DM_BITSPERPEL;
			VID_Printf( PRINT_ALL, "...using r_bitdepth of %d\n", ( int ) r_bitdepth->value );
		}
		else
		{
			HDC hdc = GetDC( NULL );
			int bitspixel = GetDeviceCaps( hdc, BITSPIXEL );

			VID_Printf( PRINT_ALL, "...using desktop display depth of %d\n", bitspixel );

			ReleaseDC( 0, hdc );
		}

		VID_Printf( PRINT_ALL, "...calling CDS: " );
		if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) == DISP_CHANGE_SUCCESSFUL )
		{
			*pwidth = width;
			*pheight = height;

			glState.fullscreen = true;

			VID_Printf( PRINT_ALL, "ok\n" );

			if ( !VID_CreateWindow (width, height, true) )
				return rserr_invalid_mode;

			return rserr_ok;
		}
		else
		{
			*pwidth = width;
			*pheight = height;

			VID_Printf( PRINT_ALL, "failed\n" );

			VID_Printf( PRINT_ALL, "...calling CDS assuming dual monitors:" );

			dm.dmPelsWidth = width * 2;
			dm.dmPelsHeight = height;
			dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;

			if ( r_bitdepth->value != 0 )
			{
				dm.dmBitsPerPel = r_bitdepth->value;
				dm.dmFields |= DM_BITSPERPEL;
			}

			/*
			** our first CDS failed, so maybe we're running on some weird dual monitor
			** system 
			*/
			if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) != DISP_CHANGE_SUCCESSFUL )
			{
				VID_Printf( PRINT_ALL, " failed\n" );

				VID_Printf( PRINT_ALL, "...setting windowed mode\n" );

				ChangeDisplaySettings( 0, 0 );

				*pwidth = width;
				*pheight = height;
				glState.fullscreen = false;
				if ( !VID_CreateWindow (width, height, false) )
					return rserr_invalid_mode;
				return rserr_invalid_fullscreen;
			}
			else
			{
				VID_Printf( PRINT_ALL, " ok\n" );
				if ( !VID_CreateWindow (width, height, true) )
					return rserr_invalid_mode;

				glState.fullscreen = true;
				return rserr_ok;
			}
		}
	}
	else
	{
		VID_Printf( PRINT_ALL, "...setting windowed mode\n" );

		ChangeDisplaySettings( 0, 0 );

		*pwidth = width;
		*pheight = height;
		glState.fullscreen = false;
		if ( !VID_CreateWindow (width, height, false) )
			return rserr_invalid_mode;
	}

	return rserr_ok;
}

/*
** GLimp_Shutdown
**
** This routine does all OS specific shutdown procedures for the OpenGL
** subsystem.  Under OpenGL this means NULLing out the current DC and
** HGLRC, deleting the rendering context, and releasing the DC acquired
** for the window.  The state structure is also nulled out.
**
*/
void GLimp_Shutdown( void )
{
	// Knightmare- added Vic's hardware gamma ramp
	ShutdownGammaRamp ();

	if ( qwglMakeCurrent && !qwglMakeCurrent( NULL, NULL ) )
		VID_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - wglMakeCurrent failed\n");
	if ( glw_state.hGLRC )
	{
		if (  qwglDeleteContext && !qwglDeleteContext( glw_state.hGLRC ) )
			VID_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - wglDeleteContext failed\n");
		glw_state.hGLRC = NULL;
	}
	if (glw_state.hDC)
	{
		if ( !ReleaseDC( glw_state.hWnd, glw_state.hDC ) )
			VID_Printf( PRINT_ALL, "ref_gl::R_Shutdown() - ReleaseDC failed\n" );
		glw_state.hDC   = NULL;
	}
	if (glw_state.hWnd)
	{	//Knightmare- remove leftover button on taskbar
		ShowWindow (glw_state.hWnd, SW_HIDE);
		//end Knightmare
		DestroyWindow (	glw_state.hWnd );
		glw_state.hWnd = NULL;
	}

	if ( glw_state.log_fp )
	{
		fclose( glw_state.log_fp );
		glw_state.log_fp = 0;
	}

	UnregisterClass (WINDOW_CLASS_NAME, glw_state.hInstance);

	if ( glState.fullscreen )
	{
		ChangeDisplaySettings( 0, 0 );
		glState.fullscreen = false;
	}
}


/*
** GLimp_Init
**
** This routine is responsible for initializing the OS specific portions
** of OpenGL.  Under Win32 this means dealing with the pixelformats and
** doing the wgl interface stuff.
*/
qboolean GLimp_Init( void *hinstance, void *wndproc )
{
#define OSR2_BUILD_NUMBER 1111

	OSVERSIONINFO	vinfo;

	vinfo.dwOSVersionInfoSize = sizeof(vinfo);

	glw_state.allowdisplaydepthchange = false;

	if ( GetVersionEx( &vinfo) )
	{
		if ( vinfo.dwMajorVersion > 4 )
		{
			glw_state.allowdisplaydepthchange = true;
		}
		else if ( vinfo.dwMajorVersion == 4 )
		{
			if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_NT )
			{
				glw_state.allowdisplaydepthchange = true;
			}
			else if ( vinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS )
			{
				if ( LOWORD( vinfo.dwBuildNumber ) >= OSR2_BUILD_NUMBER )
				{
					glw_state.allowdisplaydepthchange = true;
				}
			}
		}
	}
	else
	{
		VID_Printf( PRINT_ALL, "GLimp_Init() - GetVersionEx failed\n" );
		return false;
	}

	glw_state.hInstance = ( HINSTANCE ) hinstance;
	glw_state.wndproc = wndproc;

	return true;
}

qboolean GLimp_InitGL (void)
{
    PIXELFORMATDESCRIPTOR pfd = 
	{
		sizeof(PIXELFORMATDESCRIPTOR),	// size of this pfd
		1,								// version number
		PFD_DRAW_TO_WINDOW |			// support window
		PFD_SUPPORT_OPENGL |			// support OpenGL
		PFD_DOUBLEBUFFER,				// double buffered
		PFD_TYPE_RGBA,					// RGBA type
		32,								// 32-bit color depth // was 24
		0, 0, 0, 0, 0, 0,				// color bits ignored
		0,								// no alpha buffer
		0,								// shift bit ignored
		0,								// no accumulation buffer
		0, 0, 0, 0, 					// accum bits ignored
		//Knightmare 12/24/2001- stencil buffer
		24,								// 24-bit z-buffer, was 32	
		8,								// 8-bit stencil buffer
		//end Knightmare
		0,								// no auxiliary buffer
		PFD_MAIN_PLANE,					// main layer
		0,								// reserved
		0, 0, 0							// layer masks ignored
    };
    int  pixelformat;
	cvar_t *stereo;
	
	stereo = Cvar_Get( "cl_stereo", "0", 0 );

	/*
	** set PFD_STEREO if necessary
	*/
	if ( stereo->value != 0 )
	{
		VID_Printf( PRINT_ALL, "...attempting to use stereo\n" );
		pfd.dwFlags |= PFD_STEREO;
		glState.stereo_enabled = true;
	}
	else
	{
		glState.stereo_enabled = false;
	}

	/*
	** figure out if we're running on a minidriver or not
	*/
	if ( strstr( gl_driver->string, "opengl32" ) != 0 )
		glw_state.minidriver = false;
	else
		glw_state.minidriver = true;

	/*
	** Get a DC for the specified window
	*/
	if ( glw_state.hDC != NULL )
		VID_Printf( PRINT_ALL, "GLimp_Init() - non-NULL DC exists\n" );

    if ( ( glw_state.hDC = GetDC( glw_state.hWnd ) ) == NULL )
	{
		VID_Printf( PRINT_ALL, "GLimp_Init() - GetDC failed\n" );
		return false;
	}

	if ( glw_state.minidriver )
	{
		if ( (pixelformat = qwglChoosePixelFormat( glw_state.hDC, &pfd)) == 0 )
		{
			VID_Printf (PRINT_ALL, "GLimp_Init() - qwglChoosePixelFormat failed\n");
			return false;
		}
		if ( qwglSetPixelFormat( glw_state.hDC, pixelformat, &pfd) == FALSE )
		{
			VID_Printf (PRINT_ALL, "GLimp_Init() - qwglSetPixelFormat failed\n");
			return false;
		}
		qwglDescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd );
	}
	else
	{
		if ( ( pixelformat = ChoosePixelFormat( glw_state.hDC, &pfd)) == 0 )
		{
			VID_Printf (PRINT_ALL, "GLimp_Init() - ChoosePixelFormat failed\n");
			return false;
		}
		if ( SetPixelFormat( glw_state.hDC, pixelformat, &pfd) == FALSE )
		{
			VID_Printf (PRINT_ALL, "GLimp_Init() - SetPixelFormat failed\n");
			return false;
		}
		DescribePixelFormat( glw_state.hDC, pixelformat, sizeof( pfd ), &pfd );

		if ( !( pfd.dwFlags & PFD_GENERIC_ACCELERATED ) )
		{
			extern cvar_t *gl_allow_software;

			if ( gl_allow_software->value )
				glw_state.mcd_accelerated = true;
			else
				glw_state.mcd_accelerated = false;
		}
		else
		{
			glw_state.mcd_accelerated = true;
		}
	}

	/*
	** report if stereo is desired but unavailable
	*/
	if ( !( pfd.dwFlags & PFD_STEREO ) && ( stereo->value != 0 ) ) 
	{
		VID_Printf( PRINT_ALL, "...failed to select stereo pixel format\n" );
		Cvar_SetValue( "cl_stereo", 0 );
		glState.stereo_enabled = false;
	}

	/*
	** startup the OpenGL subsystem by creating a context and making
	** it current
	*/
	if ( ( glw_state.hGLRC = qwglCreateContext( glw_state.hDC ) ) == 0 )
	{
		VID_Printf (PRINT_ALL, "GLimp_Init() - qwglCreateContext failed\n");

		goto fail;
	}

    if ( !qwglMakeCurrent( glw_state.hDC, glw_state.hGLRC ) )
	{
		VID_Printf (PRINT_ALL, "GLimp_Init() - qwglMakeCurrent failed\n");

		goto fail;
	}

	if ( !VerifyDriver() )
	{
		VID_Printf( PRINT_ALL, "GLimp_Init() - no hardware acceleration detected.\nPlease install drivers provided by your video card/GPU vendor.\n" );
		goto fail;
	}

	/*
	** print out PFD specifics 
	*/
	VID_Printf( PRINT_ALL, "PIXELFORMAT: color(%d-bits) Z(%d-bit)\n", ( int ) pfd.cColorBits, ( int ) pfd.cDepthBits );

	// Knightmare- Vic's hardware gamma stuff
	InitGammaRamp ();

	// moved these to GL_SetDefaultState
	//glState.blend = false;
	//glState.alphaTest = false;
	//end Knightmare

	//Knightmare- 12/24/2001- stecil buffer
	{
		char buffer[1024];

	//	strncpy( buffer, qglGetString( GL_RENDERER ) );
		Q_strncpyz( buffer, qglGetString( GL_RENDERER ), sizeof(buffer) );
		strlwr( buffer );
		if (strstr(buffer, "Voodoo3")) {
			VID_Printf( PRINT_ALL, "... Voodoo3 has no stencil buffer\n" );
			glConfig.have_stencil = false;
		} else {
			if (pfd.cStencilBits) {
				VID_Printf( PRINT_ALL, "... Using stencil buffer\n" );
				glConfig.have_stencil = true; // Stencil shadows - MrG
			}
		}
	}
	//if (pfd.cStencilBits)
	//	glConfig.have_stencil = true;
	//end Knightmare

/*	Moved to GL_SetDefaultState in r_glstate.c
	// Vertex arrays
	qglEnableClientState (GL_TEXTURE_COORD_ARRAY);
	qglEnableClientState (GL_VERTEX_ARRAY);
	qglEnableClientState (GL_COLOR_ARRAY);

	qglTexCoordPointer (2, GL_FLOAT, sizeof(texCoordArray[0][0]), texCoordArray[0][0]);
	qglVertexPointer (3, GL_FLOAT, sizeof(vertexArray[0]), vertexArray[0]);
	qglColorPointer (4, GL_FLOAT, sizeof(colorArray[0]), colorArray[0]);
	//glState.activetmu[0] = true;
	// end vertex arrays
*/

	return true;

fail:
	if ( glw_state.hGLRC )
	{
		qwglDeleteContext( glw_state.hGLRC );
		glw_state.hGLRC = NULL;
	}

	if ( glw_state.hDC )
	{
		ReleaseDC( glw_state.hWnd, glw_state.hDC );
		glw_state.hDC = NULL;
	}
	return false;
}


/*
** GLimp_BeginFrame
*/
void GLimp_BeginFrame( float camera_separation )
{
	if ( r_bitdepth->modified )
	{
		if ( r_bitdepth->value != 0 && !glw_state.allowdisplaydepthchange )
		{
			Cvar_SetValue( "r_bitdepth", 0 );
			VID_Printf( PRINT_ALL, "r_bitdepth requires Win95 OSR2.x or WinNT 4.x\n" );
		}
		r_bitdepth->modified = false;
	}

	if ( camera_separation < 0 && glState.stereo_enabled )
	{
		qglDrawBuffer( GL_BACK_LEFT );
	}
	else if ( camera_separation > 0 && glState.stereo_enabled )
	{
		qglDrawBuffer( GL_BACK_RIGHT );
	}
	else
	{
		qglDrawBuffer( GL_BACK );
	}
}

/*
** GLimp_EndFrame
** 
** Responsible for doing a swapbuffers and possibly for other stuff
** as yet to be determined.  Probably better not to make this a GLimp
** function and instead do a call to GLimp_SwapBuffers.
*/
void GLimp_EndFrame (void)
{
	int		err;

	err = qglGetError();
//	assert( err == GL_NO_ERROR );
	if (err != GL_NO_ERROR)	// Output error code instead
		VID_Printf (PRINT_DEVELOPER, "OpenGL Error %i\n", err);

	if ( stricmp( r_drawbuffer->string, "GL_BACK" ) == 0 )
	{
		if ( !qwglSwapBuffers( glw_state.hDC ) )
			VID_Error (ERR_FATAL, "GLimp_EndFrame() - SwapBuffers() failed!\n");
	}
}

/*
** GLimp_AppActivate
*/
void GLimp_AppActivate( qboolean active )
{
	static qboolean	desktop_restored;
	cvar_t			*restore_desktop = Cvar_Get( "win_alttab_restore_desktop", "1", CVAR_ARCHIVE );

	if ( active )
	{
		ToggleGammaRamp (true);
		SetForegroundWindow( glw_state.hWnd );
		ShowWindow( glw_state.hWnd, SW_RESTORE );

		// Knightmare- restore desktop settings on alt-tabbing from fullscreen
		if ( vid_fullscreen->value && desktop_restored && glw_state.hGLRC != NULL )
		{
			int		width, height;
			DEVMODE	dm;

			if ( !VID_GetModeInfo (&width, &height, (int)(r_mode->value)) )
			{
				VID_Printf( PRINT_ALL, "invalid mode\n" );
				return;
			}
			
			memset( &dm, 0, sizeof( dm ) );
			dm.dmSize = sizeof( dm );
			dm.dmPelsWidth  = width;
			dm.dmPelsHeight = height;
			dm.dmFields     = DM_PELSWIDTH | DM_PELSHEIGHT;

			if ( r_displayrefresh->value != 0 )
			{
				dm.dmDisplayFrequency = r_displayrefresh->integer;
				dm.dmFields |= DM_DISPLAYFREQUENCY;
			//	VID_Printf( PRINT_ALL, "...using r_displayrefresh of %d\n", (int)r_displayrefresh->value );
			}

			if ( r_bitdepth->value != 0 )
			{
				dm.dmBitsPerPel = r_bitdepth->value;
				dm.dmFields |= DM_BITSPERPEL;
			//	VID_Printf( PRINT_ALL, "...using r_bitdepth of %d\n", (int)r_bitdepth->value );
			}
			else
			{
				HDC hdc = GetDC( NULL );
				int bitspixel = GetDeviceCaps( hdc, BITSPIXEL );
			//	VID_Printf( PRINT_ALL, "...using desktop display depth of %d\n", bitspixel );
				ReleaseDC( 0, hdc );
			}

			VID_Printf( PRINT_ALL, "...calling CDS: " );
			if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) == DISP_CHANGE_SUCCESSFUL )
			{
				VID_Printf( PRINT_ALL, "ok\n" );
			}
			else
			{	// our first CDS failed, so maybe we're running on some weird dual monitor system 
				VID_Printf( PRINT_ALL, "failed\n" );
				VID_Printf( PRINT_ALL, "...calling CDS assuming dual monitors: " );

				dm.dmPelsWidth = width * 2;
				dm.dmPelsHeight = height;
				dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;

				if ( r_bitdepth->value != 0 )
				{
					dm.dmBitsPerPel = r_bitdepth->value;
					dm.dmFields |= DM_BITSPERPEL;
				}

				if ( ChangeDisplaySettings( &dm, CDS_FULLSCREEN ) == DISP_CHANGE_SUCCESSFUL )
				{
					VID_Printf( PRINT_ALL, "ok\n" );
				}
			}
			desktop_restored = false;
		}
	}
	else
	{
		ToggleGammaRamp (false);

		if ( vid_fullscreen->value )
		{
			ShowWindow( glw_state.hWnd, SW_MINIMIZE );

			// Knightmare- restore desktop settings on alt-tabbing from fullscreen
			if (restore_desktop->value) {
				ChangeDisplaySettings (0, 0);
				desktop_restored = true;
			}
			else
				desktop_restored = false;
		}
	}
}