/*
Copyright (C) 2003 Rice1964

This program 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.

This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "stdafx.h"
#define GLH_EXT_SINGLE_FILE
//#define WGL_WGLEXT_PROTOTYPES
#include "glh_genext.h"

const char * ( WINAPI *wglGetExtensionsStringARB)(HDC)		= NULL;
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT				= NULL;
PFNWGLCREATEBUFFERREGIONARBPROC wglCreateBufferRegionARB	= NULL;
PFNWGLDELETEBUFFERREGIONARBPROC wglDeleteBufferRegionARB	= NULL;
PFNWGLSAVEBUFFERREGIONARBPROC wglSaveBufferRegionARB		= NULL;
PFNWGLRESTOREBUFFERREGIONARBPROC wglRestoreBufferRegionARB	= NULL;

PFNWGLCREATEPBUFFERARBPROC wglCreatePbufferARB				= NULL;
PFNWGLGETPBUFFERDCARBPROC wglGetPbufferDCARB				= NULL;
PFNWGLRELEASEPBUFFERDCARBPROC wglReleasePbufferDCARB		= NULL;
PFNWGLDESTROYPBUFFERARBPROC	wglDestroyPbufferARB			= NULL;
PFNWGLQUERYPBUFFERARBPROC wglQueryPbufferARB				= NULL;

PFNWGLBINDTEXIMAGEARBPROC wglBindTexImageARB				= NULL;
PFNWGLRELEASETEXIMAGEARBPROC wglReleaseTexImageARB			= NULL;
PFNWGLSETPBUFFERATTRIBARBPROC wglSetPbufferAttribARB		= NULL;

PFNWGLGETPIXELFORMATATTRIBIVARBPROC wglGetPixelFormatAttribivARB = NULL;
PFNWGLGETPIXELFORMATATTRIBFVARBPROC wglGetPixelFormatAttribfvARB = NULL;
PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB = NULL;

COGLGraphicsContext::COGLGraphicsContext() :
	m_hDC(0),
	m_hGLRC(0),
	m_pVendorStr(NULL),
	m_pRenderStr(NULL),
	m_pExtensionStr(NULL),
	m_pVersionStr(NULL),
	m_bSupportMultiTexture(false),
	m_bSupportTextureEnvCombine(false),
	m_bSupportSeparateSpecularColor(false),
	m_bSupportSecondColor(false),
	m_bSupportFogCoord(false),
	m_bSupportTextureObject(false),
	m_bSupportRescaleNormal(false),
	m_bSupportLODBias(false),
	m_bSupportTextureMirrorRepeat(false),
	m_bSupportTextureLOD(false),
	m_bSupportNVRegisterCombiner(false),
	m_bSupportBlendColor(false),
	m_bSupportBlendSubtract(false),
	m_bSupportNVTextureEnvCombine4(false)
{
}


COGLGraphicsContext::~COGLGraphicsContext()
{
}

bool COGLGraphicsContext::Initialize(HWND hWnd, HWND hWndStatus, uint32 dwWidth, uint32 dwHeight, BOOL bWindowed )
{
	if( g_GraphicsInfo.hStatusBar )
	{
		SetWindowText(g_GraphicsInfo.hStatusBar,"Initializing OpenGL Device Context");
	}
	Lock();

	CGraphicsContext::Get()->m_supportTextureMirror = false;
	CGraphicsContext::Initialize(hWnd, hWndStatus, dwWidth, dwHeight, bWindowed );

	if( bWindowed )
	{
		windowSetting.statusBarHeightToUse = windowSetting.statusBarHeight;
		windowSetting.toolbarHeightToUse = windowSetting.toolbarHeight;
	}
	else
	{
		windowSetting.statusBarHeightToUse = 0;
		windowSetting.toolbarHeightToUse = 0;
	}

	int  pfm;
	int	 depthBufferDepth = options.OpenglDepthBufferSetting;
	int	 colorBufferDepth = 32;
	if( options.colorQuality == TEXTURE_FMT_A4R4G4B4 ) colorBufferDepth = 16;

	PIXELFORMATDESCRIPTOR pfd = {
		sizeof(PIXELFORMATDESCRIPTOR),  // size of this pfd
		1,                       // version number
		PFD_DRAW_TO_WINDOW |     // support window
		PFD_SUPPORT_OPENGL |     // support OpenGL
		//PFD_GENERIC_ACCELERATED | PFD_SWAP_COPY | PFD_SWAP_EXCHANGE |
		PFD_DOUBLEBUFFER,        // double buffered
		PFD_TYPE_RGBA,           // RGBA type
		colorBufferDepth,
		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
		depthBufferDepth,        // z-buffer      
		0,                       // no stencil buffer
		0,						 // no auxiliary buffer
		PFD_MAIN_PLANE,          // main layer
		0,                       // reserved
		0, 0, 0};                // layer masks ignored

	if ((m_hDC = GetDC(hWnd)) == NULL)
	{
		ErrorMsg("GetDC on main window failed");
		return false;
	}

	if ((pfm = ChoosePixelFormat(m_hDC, &pfd)) == 0)
	{
		ErrorMsg("ChoosePixelFormat failed");
		return false;
	}
	if (SetPixelFormat(m_hDC, pfm, &pfd) == FALSE)
	{
		ErrorMsg("SetPixelFormat failed");
		return false;
	}

	DescribePixelFormat(m_hDC, pfm, sizeof(pfd), &pfd);
	
	if ((m_hGLRC = wglCreateContext(m_hDC)) == 0)
	{
		ErrorMsg("wglCreateContext failed!");
		CleanUp();
		return false;
	}

	if (!wglMakeCurrent(m_hDC, m_hGLRC))
	{
		ErrorMsg("wglMakeCurrent failed!");
		CleanUp();
		return false;
	}

	InitState();
	InitOGLExtension();
	sprintf(m_strDeviceStats, "%s - %s : %s", m_pVendorStr, m_pRenderStr, m_pVersionStr);
	TRACE0(m_strDeviceStats);
	SetWindowText(m_hWndStatus, m_strDeviceStats);

	Unlock();

	Clear(CLEAR_COLOR_AND_DEPTH_BUFFER);	// Clear buffers
	UpdateFrame();
	Clear(CLEAR_COLOR_AND_DEPTH_BUFFER);
	UpdateFrame();
	
	m_bReady = true;
	status.isVertexShaderEnabled = false;

	return true;
}

void COGLGraphicsContext::InitState(void)
{
	m_pRenderStr = glGetString(GL_RENDERER);;
	m_pExtensionStr = glGetString(GL_EXTENSIONS);;
	m_pVersionStr = glGetString(GL_VERSION);;
	m_pVendorStr = glGetString(GL_VENDOR);
	wglGetExtensionsStringARB = (const char *(WINAPI *)(HDC))wglGetProcAddress( "wglGetExtensionsStringARB" );
	if( wglGetExtensionsStringARB )
	{
		m_pWglExtensionStr = wglGetExtensionsStringARB(m_hDC);
	}
	else
	{
		m_pWglExtensionStr = NULL;
	}

	if( IsWglExtensionSupported("WGL_EXT_swap_control") )
	{
		wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress( "wglSwapIntervalEXT" );
		wglSwapIntervalEXT(0);	// Disable buffer swapping sync to increase speed
	}

	if( IsWglExtensionSupported("WGL_ARB_buffer_region") )
	{
		wglCreateBufferRegionARB = (PFNWGLCREATEBUFFERREGIONARBPROC)wglGetProcAddress( "wglCreateBufferRegionARB" );
		wglDeleteBufferRegionARB = (PFNWGLDELETEBUFFERREGIONARBPROC)wglGetProcAddress( "wglDeleteBufferRegionARB" );
		wglSaveBufferRegionARB = (PFNWGLSAVEBUFFERREGIONARBPROC)wglGetProcAddress( "wglSaveBufferRegionARB" );
		wglRestoreBufferRegionARB = (PFNWGLRESTOREBUFFERREGIONARBPROC)wglGetProcAddress( "wglRestoreBufferRegionARB" );
	}

	if( IsWglExtensionSupported("WGL_ARB_pbuffer") )
	{
		wglCreatePbufferARB			= (PFNWGLCREATEPBUFFERARBPROC)		wglGetProcAddress( "wglCreatePbufferARB" );
		wglGetPbufferDCARB			= (PFNWGLGETPBUFFERDCARBPROC)		wglGetProcAddress( "wglGetPbufferDCARB" );
		wglReleasePbufferDCARB		= (PFNWGLRELEASEPBUFFERDCARBPROC)	wglGetProcAddress( "wglReleasePbufferDCARB" );
		wglDestroyPbufferARB		= (PFNWGLDESTROYPBUFFERARBPROC)		wglGetProcAddress( "wglDestroyPbufferARB" );
		wglQueryPbufferARB			= (PFNWGLQUERYPBUFFERARBPROC)		wglGetProcAddress( "wglQueryPbufferARB" );
	}

	if( IsWglExtensionSupported("WGL_ARB_render_texture") )
	{
		wglBindTexImageARB = (PFNWGLBINDTEXIMAGEARBPROC)wglGetProcAddress( "wglBindTexImageARB" );
		wglReleaseTexImageARB = (PFNWGLRELEASETEXIMAGEARBPROC)wglGetProcAddress( "wglReleaseTexImageARB" );
		wglSetPbufferAttribARB = (PFNWGLSETPBUFFERATTRIBARBPROC)wglGetProcAddress( "wglSetPbufferAttribARB" );
	}

	if( IsWglExtensionSupported("WGL_ARB_render_texture") )
	{
		wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC)wglGetProcAddress( "wglGetPixelFormatAttribivARB" );
		wglGetPixelFormatAttribfvARB = (PFNWGLGETPIXELFORMATATTRIBFVARBPROC)wglGetProcAddress( "wglGetPixelFormatAttribfvARB" );
		wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress( "wglChoosePixelFormatARB" );
	}

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
	glClearDepth(1.0f);

	glShadeModel(GL_SMOOTH);

    //position viewer 
	//glMatrixMode(GL_MODELVIEW);
	//glLoadIdentity();

	glDisable(GL_ALPHA_TEST);

	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glDisable(GL_BLEND);

	glFrontFace(GL_CCW);
	glDisable(GL_CULL_FACE);
	glDisable(GL_NORMALIZE);

	glDepthFunc(GL_LEQUAL);
	glEnable(GL_DEPTH_TEST);

	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

	glEnable(GL_BLEND);
	glEnable(GL_ALPHA_TEST);

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	
	glDepthRange(-1, 1);
}

PFNGLGENFRAGMENTSHADERSATIPROC        glGenFragmentShadersATI;
PFNGLBINDFRAGMENTSHADERATIPROC        glBindFragmentShaderATI;
PFNGLDELETEFRAGMENTSHADERATIPROC      glDeleteFragmentShaderATI;
PFNGLBEGINFRAGMENTSHADERATIPROC       glBeginFragmentShaderATI;
PFNGLENDFRAGMENTSHADERATIPROC         glEndFragmentShaderATI;
PFNGLPASSTEXCOORDATIPROC              glPassTexCoordATI;
PFNGLSAMPLEMAPATIPROC                 glSampleMapATI;
PFNGLCOLORFRAGMENTOP1ATIPROC          glColorFragmentOp1ATI;
PFNGLCOLORFRAGMENTOP2ATIPROC          glColorFragmentOp2ATI;
PFNGLCOLORFRAGMENTOP3ATIPROC          glColorFragmentOp3ATI;
PFNGLALPHAFRAGMENTOP1ATIPROC          glAlphaFragmentOp1ATI;
PFNGLALPHAFRAGMENTOP2ATIPROC          glAlphaFragmentOp2ATI;
PFNGLALPHAFRAGMENTOP3ATIPROC          glAlphaFragmentOp3ATI;
PFNGLSETFRAGMENTSHADERCONSTANTATIPROC glSetFragmentShaderConstantATI;

PFNGLNEWOBJECTBUFFERATIPROC         glNewObjectBufferATI;
PFNGLISOBJECTBUFFERATIPROC          glIsObjectBufferATI;
PFNGLUPDATEOBJECTBUFFERATIPROC      glUpdateObjectBufferATI;
PFNGLGETOBJECTBUFFERFVATIPROC       glGetObjectBufferfvATI;
PFNGLGETOBJECTBUFFERIVATIPROC       glGetObjectBufferivATI;
PFNGLFREEOBJECTBUFFERATIPROC        glFreeObjectBufferATI;
PFNGLARRAYOBJECTATIPROC             glArrayObjectATI;
PFNGLGETARRAYOBJECTFVATIPROC        glGetArrayObjectfvATI;
PFNGLGETARRAYOBJECTIVATIPROC        glGetArrayObjectivATI;
PFNGLVARIANTARRAYOBJECTATIPROC      glVariantArrayObjectATI;
PFNGLGETVARIANTARRAYOBJECTFVATIPROC glGetVariantArrayObjectfvATI;
PFNGLGETVARIANTARRAYOBJECTIVATIPROC glGetVariantArrayObjectivATI;

PFNGLPROGRAMSTRINGARBPROC glProgramStringARB = NULL;
PFNGLBINDPROGRAMARBPROC glBindProgramARB = NULL;
PFNGLDELETEPROGRAMSARBPROC glDeleteProgramsARB = NULL;
PFNGLGENPROGRAMSARBPROC glGenProgramsARB = NULL;
PFNGLPROGRAMENVPARAMETER4DARBPROC glProgramEnvParameter4dARB = NULL;
PFNGLPROGRAMENVPARAMETER4DVARBPROC glProgramEnvParameter4dvARB = NULL;
PFNGLPROGRAMENVPARAMETER4FARBPROC glProgramEnvParameter4fARB = NULL;
PFNGLPROGRAMENVPARAMETER4FVARBPROC glProgramEnvParameter4fvARB = NULL;
PFNGLPROGRAMLOCALPARAMETER4DARBPROC glProgramLocalParameter4dARB = NULL;
PFNGLPROGRAMLOCALPARAMETER4DVARBPROC glProgramLocalParameter4dvARB = NULL;
PFNGLPROGRAMLOCALPARAMETER4FARBPROC glProgramLocalParameter4fARB = NULL;
PFNGLPROGRAMLOCALPARAMETER4FVARBPROC glProgramLocalParameter4fvARB = NULL;
PFNGLGETPROGRAMENVPARAMETERDVARBPROC glGetProgramEnvParameterdvARB = NULL;
PFNGLGETPROGRAMENVPARAMETERFVARBPROC glGetProgramEnvParameterfvARB = NULL;
PFNGLGETPROGRAMENVPARAMETERFVARBPROC glGetssProgramEnvParameterfvARB = NULL;
PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC glGetProgramLocalParameterdvARB = NULL;;
PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC glGetProgramLocalParameterfvARB = NULL;;
PFNGLGETPROGRAMIVARBPROC glGetProgramivARB = NULL;;
PFNGLGETPROGRAMSTRINGARBPROC glGetProgramStringARB = NULL;;
PFNGLISPROGRAMARBPROC glIsProgramARB = NULL;

void COGLGraphicsContext::InitOGLExtension_ATI(void)
{
	#define SAFE_GET_PROC( func, type, fail)   func = (type) wglGetProcAddress( #func);   fail &= (func != NULL);

	if (IsExtensionSupported("GL_ATI_fragment_shader"))
	{
		glGenFragmentShadersATI        = (PFNGLGENFRAGMENTSHADERSATIPROC) wglGetProcAddress("glGenFragmentShadersATI");
		glBindFragmentShaderATI        = (PFNGLBINDFRAGMENTSHADERATIPROC) wglGetProcAddress("glBindFragmentShaderATI");
		glDeleteFragmentShaderATI      = (PFNGLDELETEFRAGMENTSHADERATIPROC) wglGetProcAddress("glDeleteFragmentShaderATI");
		glBeginFragmentShaderATI       = (PFNGLBEGINFRAGMENTSHADERATIPROC) wglGetProcAddress("glBeginFragmentShaderATI");
		glEndFragmentShaderATI         = (PFNGLENDFRAGMENTSHADERATIPROC) wglGetProcAddress("glEndFragmentShaderATI");
		glPassTexCoordATI              = (PFNGLPASSTEXCOORDATIPROC) wglGetProcAddress("glPassTexCoordATI");
		glSampleMapATI                 = (PFNGLSAMPLEMAPATIPROC) wglGetProcAddress("glSampleMapATI");
		glColorFragmentOp1ATI          = (PFNGLCOLORFRAGMENTOP1ATIPROC) wglGetProcAddress("glColorFragmentOp1ATI");
		glColorFragmentOp2ATI          = (PFNGLCOLORFRAGMENTOP2ATIPROC) wglGetProcAddress("glColorFragmentOp2ATI");
		glColorFragmentOp3ATI          = (PFNGLCOLORFRAGMENTOP3ATIPROC) wglGetProcAddress("glColorFragmentOp3ATI");
		glAlphaFragmentOp1ATI          = (PFNGLALPHAFRAGMENTOP1ATIPROC) wglGetProcAddress("glAlphaFragmentOp1ATI");
		glAlphaFragmentOp2ATI          = (PFNGLALPHAFRAGMENTOP2ATIPROC) wglGetProcAddress("glAlphaFragmentOp2ATI");
		glAlphaFragmentOp3ATI          = (PFNGLALPHAFRAGMENTOP3ATIPROC) wglGetProcAddress("glAlphaFragmentOp3ATI");
		glSetFragmentShaderConstantATI = (PFNGLSETFRAGMENTSHADERCONSTANTATIPROC) wglGetProcAddress("glSetFragmentShaderConstantATI");

		if (glGenFragmentShadersATI == NULL)
		{
			ErrorMsg("Can't init glGenFragmentShadersATI");
		}

		if (glBindFragmentShaderATI == NULL)
		{
			ErrorMsg ("Can't init glBindFragmentShaderATI");
		}

		if (glDeleteFragmentShaderATI == NULL)
		{
			ErrorMsg ("Can't init glDeleteFragmentShaderATI");
		}

		if (glBeginFragmentShaderATI == NULL)
		{
			ErrorMsg ("Can't init glBeginFragmentShaderATI");
		}

		if (glEndFragmentShaderATI == NULL)
		{
			ErrorMsg ("Can't init glEndFragmentShaderATI");
		}

		if (glPassTexCoordATI == NULL)
		{
			ErrorMsg ("Can't init glPassTexCoordATI");
		}

		if (glColorFragmentOp1ATI == NULL)
		{
			ErrorMsg ("Can't init glColorFragmentOp1ATI");
		}

		if (glColorFragmentOp2ATI == NULL)
		{
			ErrorMsg ("Can't init glColorFragmentOp2ATI");
		}

		if (glColorFragmentOp3ATI == NULL)
		{
			ErrorMsg ("Can't init glColorFragmentOp3ATI");
		}

		if (glAlphaFragmentOp1ATI == NULL)
		{
			ErrorMsg ("Can't init glAlphaFragmentOp1ATI");
		}

		if (glAlphaFragmentOp2ATI == NULL)
		{
			ErrorMsg ("Can't init glAlphaFragmentOp2ATI");
		}

		if (glAlphaFragmentOp2ATI == NULL)
		{
			ErrorMsg ("Can't init glAlphaFragmentOp2ATI");
		}

		if (glAlphaFragmentOp3ATI == NULL)
		{
			ErrorMsg ("Can't init glAlphaFragmentOp3ATI");
		}

		if (glSetFragmentShaderConstantATI == NULL)
		{
			ErrorMsg ("Can't init glSetFragmentShaderConstantATI");
		}
	}
	
	if (IsExtensionSupported("GL_ARB_fragment_program"))
	{
		int ret = TRUE;

		SAFE_GET_PROC( glProgramStringARB, PFNGLPROGRAMSTRINGARBPROC, ret);
		SAFE_GET_PROC( glBindProgramARB, PFNGLBINDPROGRAMARBPROC, ret);
		SAFE_GET_PROC( glDeleteProgramsARB, PFNGLDELETEPROGRAMSARBPROC, ret);
		SAFE_GET_PROC( glGenProgramsARB, PFNGLGENPROGRAMSARBPROC, ret);
		SAFE_GET_PROC( glProgramEnvParameter4dARB, PFNGLPROGRAMENVPARAMETER4DARBPROC, ret);
		SAFE_GET_PROC( glProgramEnvParameter4dvARB, PFNGLPROGRAMENVPARAMETER4DVARBPROC, ret);
		SAFE_GET_PROC( glProgramEnvParameter4fARB, PFNGLPROGRAMENVPARAMETER4FARBPROC, ret);
		SAFE_GET_PROC( glProgramEnvParameter4fvARB, PFNGLPROGRAMENVPARAMETER4FVARBPROC, ret);
		SAFE_GET_PROC( glProgramLocalParameter4dARB, PFNGLPROGRAMLOCALPARAMETER4DARBPROC, ret);
		SAFE_GET_PROC( glProgramLocalParameter4dvARB, PFNGLPROGRAMLOCALPARAMETER4DVARBPROC, ret);
		SAFE_GET_PROC( glProgramLocalParameter4fARB, PFNGLPROGRAMLOCALPARAMETER4FARBPROC, ret);
		SAFE_GET_PROC( glProgramLocalParameter4fvARB, PFNGLPROGRAMLOCALPARAMETER4FVARBPROC, ret);
		SAFE_GET_PROC( glGetProgramEnvParameterdvARB, PFNGLGETPROGRAMENVPARAMETERDVARBPROC, ret);
		SAFE_GET_PROC( glGetProgramEnvParameterfvARB, PFNGLGETPROGRAMENVPARAMETERFVARBPROC, ret);
		SAFE_GET_PROC( glGetProgramLocalParameterdvARB, PFNGLGETPROGRAMLOCALPARAMETERDVARBPROC, ret);
		SAFE_GET_PROC( glGetProgramLocalParameterfvARB, PFNGLGETPROGRAMLOCALPARAMETERFVARBPROC, ret);
		SAFE_GET_PROC( glGetProgramivARB, PFNGLGETPROGRAMIVARBPROC, ret);
		SAFE_GET_PROC( glGetProgramStringARB, PFNGLGETPROGRAMSTRINGARBPROC, ret);
		SAFE_GET_PROC( glIsProgramARB, PFNGLISPROGRAMARBPROC, ret);
	}
	else
	{
		//ErrorMsg("No fragment shader support!");
	}
}


void COGLGraphicsContext::InitOGLExtension(void)
{
	// important extension features, it is very bad not to have these feature
	m_bSupportMultiTexture = IsExtensionSupported("GL_ARB_multitexture");
	m_bSupportTextureEnvCombine = IsExtensionSupported("GL_EXT_texture_env_combine");
	
	m_bSupportSeparateSpecularColor = IsExtensionSupported("GL_EXT_separate_specular_color");
	m_bSupportSecondColor = IsExtensionSupported("GL_EXT_secondary_color");
	m_bSupportFogCoord = IsExtensionSupported("GL_EXT_fog_coord");
	m_bSupportTextureObject = IsExtensionSupported("GL_EXT_texture_object");

	// Optional extension features
	m_bSupportRescaleNormal = IsExtensionSupported("GL_EXT_rescale_normal");
	m_bSupportLODBias = IsExtensionSupported("GL_EXT_texture_lod_bias");

	// Nvidia only extension features (optional)
	m_bSupportNVRegisterCombiner = IsExtensionSupported("GL_NV_register_combiners");
	m_bSupportTextureMirrorRepeat = IsExtensionSupported("GL_IBM_texture_mirrored_repeat") || IsExtensionSupported("ARB_texture_mirrored_repeat");
	m_supportTextureMirror = m_bSupportTextureMirrorRepeat;
	m_bSupportTextureLOD = IsExtensionSupported("GL_EXT_texture_lod");
	m_bSupportBlendColor = IsExtensionSupported("GL_EXT_blend_color");
	m_bSupportBlendSubtract = IsExtensionSupported("GL_EXT_blend_subtract");
	m_bSupportNVTextureEnvCombine4 = IsExtensionSupported("GL_NV_texture_env_combine4");

	glh_init_extension("GL_ARB_multitexture");
	glh_init_extension("GL_EXT_texture_env_combine");
	glh_init_extension("GL_EXT_separate_specular_color");
	glh_init_extension("GL_EXT_secondary_color");
	glh_init_extension("GL_EXT_fog_coord");
	glh_init_extension("GL_EXT_texture_object");
	glh_init_extension("GL_EXT_rescale_normal");
	glh_init_extension("GL_EXT_texture_lod_bias");
	glh_init_extension("GL_NV_register_combiners");
	glh_init_extension("GL_IBM_texture_mirrored_repeat");
	glh_init_extension("GL_EXT_texture_lod");
	glh_init_extension("GL_EXT_blend_color");
	glh_init_extension("GL_EXT_blend_subtract");
	glh_init_extension("GL_NV_texture_env_combine4");
	glh_init_extension("GL_EXT_copy_texture");

	InitOGLExtension_ATI();
}

bool COGLGraphicsContext::IsExtensionSupported(const char* pExtName)
{
	if( strstr((const char*)m_pExtensionStr, pExtName) != NULL )
		return true;
	else
		return false;
}

bool COGLGraphicsContext::IsWglExtensionSupported(const char* pExtName)
{
	if( m_pWglExtensionStr == NULL )
		return false;

	if( strstr((const char*)m_pWglExtensionStr, pExtName) != NULL )
		return true;
	else
		return false;
}


void COGLGraphicsContext::CleanUp()
{
	if (m_hGLRC)
	{
		//UpdateFrame();

		if (!wglMakeCurrent(m_hDC, m_hGLRC))
		//if (!wglMakeCurrent(NULL, NULL))
		{
			uint32 error = GetLastError();
			TRACE1("wglMakeCurrent failed, error code=%d!", error);
		}

		//DelTexture();

		if (!wglDeleteContext(m_hGLRC))
		{
			uint32 error = GetLastError();
			TRACE1("wglDeleteContext failed, error code=%08X!", error);
		}
		m_hGLRC = NULL;
	}

	if (m_hDC)
	{
		if (!ReleaseDC(m_hWnd, m_hDC))
		{
			uint32 error = GetLastError();
			TRACE1("ReleaseDC failed, error code=%d!", error);
		}
		m_hDC = NULL;
	}

	m_bReady = false;
}


void COGLGraphicsContext::Clear(ClearFlag dwFlags, uint32 color, float depth)
{
	uint32 flag=0;
	if( dwFlags&CLEAR_COLOR_BUFFER )	flag |= GL_COLOR_BUFFER_BIT;
	if( dwFlags&CLEAR_DEPTH_BUFFER )	flag |= GL_DEPTH_BUFFER_BIT;

	float r = ((color>>16)&0xFF)/255.0f;
	float g = ((color>> 8)&0xFF)/255.0f;
	float b = ((color    )&0xFF)/255.0f;
	float a = ((color>>24)&0xFF)/255.0f;
	glClearColor(r, g, b, a);
	glClearDepth(depth);
	glClear(flag);	//Clear color buffer and depth buffer
}


void COGLGraphicsContext::UpdateFrame(bool swaponly)
{
	status.gFrameCount++;

	glFlush();
	//glFinish();
	//wglSwapIntervalEXT(0);
	SwapBuffers(m_hDC);
	glDepthMask(GL_TRUE);
	glClearDepth(1.0);
	if( !g_curRomInfo.bForceScreenClear ) 
		glClear(GL_DEPTH_BUFFER_BIT);
	else
		needCleanScene = true;

	status.bScreenIsDrawn = false;
}

bool COGLGraphicsContext::SetFullscreenMode()
{
	DEVMODEA devMode;

	ZeroMemory(&devMode, sizeof(DEVMODE));
	devMode.dmSize       = sizeof(DEVMODE);
	devMode.dmPelsWidth	 = windowSetting.uFullScreenDisplayWidth;
	devMode.dmPelsHeight = windowSetting.uFullScreenDisplayHeight;
	devMode.dmBitsPerPel = options.colorQuality==TEXTURE_FMT_A8R8G8B8?32:16;
	if( windowSetting.uFullScreenRefreshRate == 0 )
		devMode.dmFields     = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL ;//| DM_DISPLAYFREQUENCY;
	else
	{
		devMode.dmDisplayFrequency = windowSetting.uFullScreenRefreshRate;
		devMode.dmFields     = DM_PELSWIDTH | DM_PELSHEIGHT | DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
	}
	
	if (ChangeDisplaySettings(&devMode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
	{
		return false;
	}

	ShowCursor(0);

	m_WindowPlacement.length = sizeof(WINDOWPLACEMENT);
	GetWindowPlacement(m_hWnd, &m_WindowPlacement);
	if (m_hWndStatus)
	{
		ShowWindow(m_hWndStatus,SW_HIDE); 
	}
	if (m_hMenu) SetMenu(m_hWnd,NULL); 

	SetWindowLong(m_hWnd, GWL_EXSTYLE, WS_EX_APPWINDOW | WS_EX_TOPMOST);
	SetWindowLong(m_hWnd, GWL_STYLE, WS_VISIBLE|WS_POPUP);
	
	SetWindowPos(m_hWnd, HWND_TOPMOST, 0, 0, windowSetting.uFullScreenDisplayWidth,windowSetting.uFullScreenDisplayHeight, SWP_SHOWWINDOW);

	windowSetting.uDisplayWidth = windowSetting.uFullScreenDisplayWidth;
	windowSetting.uDisplayHeight = windowSetting.uFullScreenDisplayHeight;
	windowSetting.statusBarHeightToUse = 0;
	windowSetting.toolbarHeightToUse = 0;

	return true;
}

bool COGLGraphicsContext::SetWindowMode()
{
	SetWindowLong(m_hWnd, GWL_STYLE, 0);
	ShowWindow(m_hWnd, SW_SHOWNORMAL);

	if (!ChangeDisplaySettings(NULL,CDS_TEST)) 
	{
		// If The Shortcut Doesn't Work
		ChangeDisplaySettings(NULL,CDS_RESET);		// Do It Anyway (To Get The Values Out Of The Registry)
		ChangeDisplaySettings(&m_DMsaved,CDS_RESET);	// Change It To The Saved Settings
	} 
	else 
	{
		ChangeDisplaySettings(NULL,CDS_RESET);		// If It Works, Go Right Ahead
	}

	if (m_hWndStatus)	ShowWindow(m_hWndStatus,SW_SHOW);
	if (m_hMenu)		SetMenu(m_hWnd,m_hMenu); 
	SetWindowLong(m_hWnd, GWL_STYLE, m_dwWindowStyle);
	SetWindowPos(m_hWnd, HWND_NOTOPMOST, m_WindowPlacement.rcNormalPosition.left, 
		m_WindowPlacement.rcNormalPosition.top, 640, 480, SWP_NOSIZE|SWP_SHOWWINDOW);
	ShowCursor(TRUE);

	SetWindowPos(m_hWnd, HWND_TOP, m_rcWindowBounds.left, m_rcWindowBounds.top, 
		m_rcWindowBounds.right - m_rcWindowBounds.left,
		m_rcWindowBounds.bottom - m_rcWindowBounds.top,
		SWP_SHOWWINDOW);

	GetWindowRect(m_hWnd, &m_rcWindowBounds);

	windowSetting.uDisplayWidth = windowSetting.uWindowDisplayWidth;
	windowSetting.uDisplayHeight = windowSetting.uWindowDisplayHeight;
	windowSetting.statusBarHeightToUse = windowSetting.statusBarHeight;
	windowSetting.toolbarHeightToUse = windowSetting.toolbarHeight;

	return true;
}
int COGLGraphicsContext::ToggleFullscreen()
{
    if( m_bWindowed ) 
    {
    	EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &m_DMsaved);
        m_bWindowed = !SetFullscreenMode();
    }
    else
    {
        m_bWindowed = SetWindowMode();
    }

	if( !m_bWindowed )
	{
		ShowCursor( FALSE );
	}
	else
	{
		ShowCursor( TRUE );
	}

	return m_bWindowed?0:1;
}

// This is a static function, will be called when the plugin DLL is initialized
void COGLGraphicsContext::InitDeviceParameters()
{
	status.isVertexShaderEnabled = false;	// Disable it for now
}

