///////////////////////////////////////////////////////////
//                                                       //
//  (w)(c) 2002 - Carsten Dachsbacher                    //
//                carsten@dachsbacher.de                 //
//                                                       //
//  OpenGL Extension Handling                            //
//                                                       //
//  Changed: 12-17-2002                                  //
//                                                       //
///////////////////////////////////////////////////////////
#include <windows.h>
#include <stdio.h>

#include "oglextension.h"

#define MAX_EXTENSION_SPACE		10240
#define MAX_EXTENSION_LENGTH	256

bool	supportTextureCompressionS3		= false;
bool	supportVAR						= false;
bool	supportVertexProgram			= false;
bool	supportPointParameters			= false;
bool	supportCompiledVertexArray		= false;
bool	supportMultiDrawArray			= false;
bool	supportOcclusionQuery			= false;
bool    supportATI_vao					= false;
bool    supportATI_element_array		= false;
bool	supportWGL_ARB_pbuffer			= false;
bool	supportWGL_ARB_pixel_format		= false;
bool	supportWGL_ARB_render_texture	= false;
bool	supportGL_SGIS_generate_mipmap  = false;

int		maxTexelUnits				= 0;

// Compiled Vertex Arrays
PFNGLLOCKARRAYSEXTPROC				pfLockArrays				= NULL;
PFNGLUNLOCKARRAYSEXTPROC			pfUnlockArrays				= NULL;


// hier die definitionen für den import der multitexturing extensions
PFNGLMULTITEXCOORD1FARBPROC			glMultiTexCoord1fARB		= NULL;
PFNGLMULTITEXCOORD2FARBPROC			glMultiTexCoord2fARB		= NULL;
PFNGLMULTITEXCOORD3FARBPROC			glMultiTexCoord3fARB		= NULL;
PFNGLMULTITEXCOORD4FARBPROC			glMultiTexCoord4fARB		= NULL;
PFNGLACTIVETEXTUREARBPROC			glActiveTextureARB			= NULL;
PFNGLCLIENTACTIVETEXTUREARBPROC		glClientActiveTextureARB	= NULL;	
PFNGLCOMPRESSEDTEXIMAGE2DARBPROC	glCompressedTexImage2DARB	= NULL;

// EXT_point_parameters
PFNGLPOINTPARAMETERFEXTPROC			glPointParameterfEXT		= NULL;
PFNGLPOINTPARAMETERFVEXTPROC		glPointParameterfvEXT		= NULL;

// GL_EXT_multi_draw_arrays
PFNGLMULTIDRAWARRAYSEXTPROC			glMultiDrawArraysEXT		= NULL;
PFNGLMULTIDRAWELEMENTSEXTPROC		glMultiDrawElementsEXT		= NULL;

// Vertex Array Range EXT
PFNGLFLUSHVERTEXARRAYRANGENVPROC	glFlushVertexArrayRangeNV	= NULL;
PFNGLVERTEXARRAYRANGENVPROC			glVertexArrayRangeNV		= NULL;

#ifdef _WIN32
typedef void* (APIENTRY * PFNWGLALLOCATEMEMORYNVPROC) (GLsizei size, 
               GLfloat readFrequency, GLfloat writeFrequency, GLfloat priority);
typedef void (APIENTRY * PFNWGLFREEMEMORYNVPROC) (void *pointer);
PFNWGLALLOCATEMEMORYNVPROC			wglAllocateMemoryNV			= NULL;
PFNWGLFREEMEMORYNVPROC				wglFreeMemoryNV				= NULL;
#else
typedef void* ( * PFNGLXALLOCATEMEMORYNVPROC) (GLsizei size, 
               GLfloat readFrequency, GLfloat writeFrequency, GLfloat priority);
typedef void ( * PFNGLXFREEMEMORYNVPROC) (void *pointer);
PFNGLXALLOCATEMEMORYNVPROC			glXAllocateMemoryNV			= NULL;
PFNGLXFREEMEMORYNVPROC				glXFreeMemoryNV				= NULL;
#endif 


// Occlusion Query
PFNGLBEGINOCCLUSIONQUERYNVPROC		glBeginOcclusionQueryNV		= NULL;
PFNGLENDOCCLUSIONQUERYNVPROC		glEndOcclusionQueryNV		= NULL;
PFNGLGETOCCLUSIONQUERYUIVNVPROC		glGetOcclusionQueryuivNV	= NULL;
PFNGLGENOCCLUSIONQUERIESNVPROC		glGenOcclusionQueriesNV		= NULL;

// Vertex Programs
PFNGLBINDPROGRAMNVPROC				glBindProgramNV				= NULL;
PFNGLDELETEPROGRAMSNVPROC			glDeleteProgramsNV			= NULL;
PFNGLEXECUTEPROGRAMNVPROC			glExecuteProgramNV			= NULL;
PFNGLGENPROGRAMSNVPROC				glGenProgramsNV				= NULL;
PFNGLAREPROGRAMSRESIDENTNVPROC		glAreProgramsResidentNV;
PFNGLREQUESTRESIDENTPROGRAMSNVPROC	glRequestResidentProgramsNV;
PFNGLGETPROGRAMPARAMETERFVNVPROC	glGetProgramParameterfvNV;
PFNGLGETPROGRAMPARAMETERDVNVPROC	glGetProgramParameterdvNV;
PFNGLGETPROGRAMIVNVPROC				glGetProgramivNV;
PFNGLGETPROGRAMSTRINGNVPROC			glGetProgramStringNV;
PFNGLGETTRACKMATRIXIVNVPROC			glGetTrackMatrixivNV;
PFNGLGETVERTEXATTRIBDVNVPROC		glGetVertexAttribdvNV;
PFNGLGETVERTEXATTRIBFVNVPROC		glGetVertexAttribfvNV;
PFNGLGETVERTEXATTRIBIVNVPROC		glGetVertexAttribivNV;
PFNGLGETVERTEXATTRIBPOINTERVNVPROC	glGetVertexAttribPointervNV;
PFNGLISPROGRAMNVPROC				glIsProgramNV;
PFNGLLOADPROGRAMNVPROC				glLoadProgramNV;
PFNGLPROGRAMPARAMETER4FNVPROC		glProgramParameter4fNV;
PFNGLPROGRAMPARAMETER4DNVPROC		glProgramParameter4dNV;
PFNGLPROGRAMPARAMETER4DVNVPROC		glProgramParameter4dvNV;
PFNGLPROGRAMPARAMETER4FVNVPROC		glProgramParameter4fvNV;
PFNGLPROGRAMPARAMETERS4DVNVPROC		glProgramParameters4dvNV;
PFNGLPROGRAMPARAMETERS4FVNVPROC		glProgramParameters4fvNV;
PFNGLTRACKMATRIXNVPROC				glTrackMatrixNV;

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

// ATI element arrays
PFNGLELEMENTPOINTERATIPROC             glElementPointerATI = NULL;
PFNGLDRAWELEMENTARRAYATIPROC           glDrawElementArrayATI = NULL;
PFNGLDRAWRANGEELEMENTARRAYATIPROC      glDrawRangeElementArrayATI = NULL;

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

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

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

// WGL_ARB_extensions_string
PFNWGLGETEXTENSIONSSTRINGARBPROC		wglGetExtensionsStringARB = NULL;


#ifdef _WIN32
#define GETEXT( function, name ) \
	*(void**)&function = (void *)wglGetProcAddress( name );
#else
#define GETEXT( function, name ) \
	*(void**)&function = (void *)glXGetProcAddressARB( (byte*)name );
#endif

//void getOpenGLExtensions( char *extensions ) 
void getOpenGLExtensions() 
{
	GETEXT( wglGetExtensionsStringARB, "wglGetExtensionsStringARB" );

	char *vendor        = (char*)glGetString( GL_VENDOR );
	char *version       = (char*)glGetString( GL_VERSION );
	char *renderer	    = (char*)glGetString( GL_RENDERER );
	char *extensions    = (char*)glGetString( GL_EXTENSIONS );
	char *wglextensions = NULL;

	if ( wglGetExtensionsStringARB )
		wglextensions = (char*)wglGetExtensionsStringARB( wglGetCurrentDC() );

	FILE *f = fopen( "extension.txt", "wb" );
	fwrite( vendor, 1, strlen( vendor ), f );
	fwrite( version, 1, strlen( version ), f );
	fwrite( renderer, 1, strlen( renderer ), f );
	fwrite( extensions, 1, strlen( extensions ), f );
	if ( wglextensions )
		fwrite( wglextensions, 1, strlen( wglextensions ), f );
	fclose( f );

	if ( strstr( extensions, "GL_NV_vertex_array_range" ) )
	{
		supportVAR = true;

		GETEXT(	glFlushVertexArrayRangeNV,	"glFlushVertexArrayRangeNV" );
		GETEXT(	glVertexArrayRangeNV,		"glVertexArrayRangeNV" );

		#ifdef _WIN32
		GETEXT(	wglAllocateMemoryNV, "wglAllocateMemoryNV" );
		GETEXT(	wglFreeMemoryNV,	 "wglFreeMemoryNV" );
		#else
		GETEXT(	glXAllocateMemoryNV, "glXAllocateMemoryNV" );
		GETEXT(	glXFreeMemoryNV,	 "glXFreeMemoryNV" );
		#endif
	}

	if ( strstr( extensions, "GL_ARB_texture_compression" ) && 
		 strstr( extensions, "GL_EXT_texture_compression_s3tc" ) )
	{
		supportTextureCompressionS3 = true;
		GETEXT( glCompressedTexImage2DARB, "glCompressedTexImage2DARB" );
	}

	if ( strstr( extensions, "GL_EXT_compiled_vertex_array" ) )
	{
		supportCompiledVertexArray = true;

		GETEXT( pfLockArrays, "glLockArraysEXT" );
		GETEXT( pfUnlockArrays, "glUnlockArraysEXT" );
	}

	if ( strstr( extensions, "GL_EXT_multi_draw_arrays" ) )
	{
		supportMultiDrawArray = true;
		GETEXT( glMultiDrawArraysEXT, "glMultiDrawArraysEXT" );
		GETEXT( glMultiDrawElementsEXT, "glMultiDrawElementsEXT" );
	}

	if ( strstr( extensions, "GL_EXT_point_parameters" ) )
	{
		supportPointParameters = true;

		GETEXT( glPointParameterfEXT,  "glPointParameterfEXT" );
		GETEXT( glPointParameterfvEXT, "glPointParameterfvEXT" );
	}

	if ( strstr( extensions, "GL_NV_occlusion_query" ) )
	{
		supportOcclusionQuery = true;

		GETEXT( glBeginOcclusionQueryNV,  "glBeginOcclusionQueryNV" );
		GETEXT( glEndOcclusionQueryNV,    "glEndOcclusionQueryNV" );
		GETEXT( glGetOcclusionQueryuivNV, "glGetOcclusionQueryuivNV" );
		GETEXT( glGenOcclusionQueriesNV,  "glGenOcclusionQueriesNV" );
	}

	if ( strstr( extensions, "GL_ARB_multitexture" ) && 
		 strstr( extensions, "GL_EXT_texture_env_combine" ) )
	{	
		glGetIntegerv( GL_MAX_TEXTURE_UNITS_ARB, &maxTexelUnits );

		GETEXT( glMultiTexCoord1fARB,     "glMultiTexCoord1fARB" );
		GETEXT( glMultiTexCoord2fARB,     "glMultiTexCoord2fARB" );
		GETEXT( glMultiTexCoord3fARB,     "glMultiTexCoord3fARB" );
		GETEXT( glMultiTexCoord4fARB,     "glMultiTexCoord4fARB" );
		GETEXT( glActiveTextureARB,       "glActiveTextureARB" );
		GETEXT( glClientActiveTextureARB, "glClientActiveTextureARB" );		
	}

	if ( strstr( extensions, "GL_NV_vertex_program" ) )
	{
		supportVertexProgram = true;

		GETEXT( glBindProgramNV,			"glBindProgramNV" );
		GETEXT( glDeleteProgramsNV,			"glDeleteProgramsNV" );
		GETEXT( glExecuteProgramNV,			"glExecuteProgramNV" );
		GETEXT( glGenProgramsNV,			"glGenProgramsNV" );
		GETEXT( glAreProgramsResidentNV,	"glAreProgramsResidentNV" );
		GETEXT( glRequestResidentProgramsNV,"glRequestResidentProgramsNV" );
		GETEXT( glGetProgramParameterfvNV,	"glGetProgramParameterfvNV" );
		GETEXT( glGetProgramParameterdvNV,	"glGetProgramParameterdvNV" );
		GETEXT( glGetProgramivNV,			"glGetProgramivNV" );
		GETEXT( glGetProgramStringNV,		"glGetProgramStringNV" );
		GETEXT( glGetTrackMatrixivNV,		"glGetTrackMatrixivNV" );
		GETEXT( glGetVertexAttribdvNV,		"glGetVertexAttribdvNV" );
		GETEXT( glGetVertexAttribfvNV,		"glGetVertexAttribfvNV" );
		GETEXT( glGetVertexAttribivNV,		"glGetVertexAttribivNV" );
		GETEXT( glGetVertexAttribPointervNV,"glGetVertexAttribPointervNV" );
		GETEXT( glIsProgramNV,				"glIsProgramNV" );
		GETEXT( glLoadProgramNV,			"glLoadProgramNV" );
		GETEXT( glProgramParameter4fNV,		"glProgramParameter4fNV" );
		GETEXT( glProgramParameter4dNV,		"glProgramParameter4dNV" );
		GETEXT( glProgramParameter4dvNV,	"glProgramParameter4dvNV" );
		GETEXT( glProgramParameter4fvNV,	"glProgramParameter4fvNV" );
		GETEXT( glProgramParameters4dvNV,	"glProgramParameters4dvNV" );
		GETEXT( glProgramParameters4fvNV,	"glProgramParameters4fvNV" );
		GETEXT( glTrackMatrixNV,			"glTrackMatrixNV" );
	}

	if ( strstr( extensions, "GL_ATI_vertex_array_object" ) )
	{
		supportATI_vao = true;
		glNewObjectBufferATI = (PFNGLNEWOBJECTBUFFERATIPROC)wglGetProcAddress("glNewObjectBufferATI");
		glIsObjectBufferATI = (PFNGLISOBJECTBUFFERATIPROC)wglGetProcAddress("glIsObjectBufferATI");
		glUpdateObjectBufferATI = (PFNGLUPDATEOBJECTBUFFERATIPROC)wglGetProcAddress("glUpdateObjectBufferATI");
		glGetObjectBufferfvATI = (PFNGLGETOBJECTBUFFERFVATIPROC)wglGetProcAddress("glGetObjectBufferfvATI");
		glGetObjectBufferivATI = (PFNGLGETOBJECTBUFFERIVATIPROC)wglGetProcAddress("glGetObjectBufferivATI");
		glFreeObjectBufferATI = (PFNGLFREEOBJECTBUFFERATIPROC)wglGetProcAddress("glFreeObjectBufferATI");
		glArrayObjectATI = (PFNGLARRAYOBJECTATIPROC)wglGetProcAddress("glArrayObjectATI");
		glGetArrayObjectfvATI = (PFNGLGETARRAYOBJECTFVATIPROC)wglGetProcAddress("glGetArrayObjectfvATI");
		glGetArrayObjectivATI = (PFNGLGETARRAYOBJECTIVATIPROC)wglGetProcAddress("glGetArrayObjectivATI");
		glVariantArrayObjectATI = (PFNGLVARIANTARRAYOBJECTATIPROC)wglGetProcAddress("glVariantArrayObjectATI");
		glGetVariantArrayObjectfvATI = (PFNGLGETVARIANTARRAYOBJECTFVATIPROC)wglGetProcAddress("glGetVariantArrayObjectfvATI");
		glGetVariantArrayObjectivATI = (PFNGLGETVARIANTARRAYOBJECTIVATIPROC)wglGetProcAddress("glGetVariantArrayObjectivATI");
	}

	if ( strstr( extensions, "GL_ATI_element_array" ) )
	{
		supportATI_element_array = true;
		glElementPointerATI = (PFNGLELEMENTPOINTERATIPROC)wglGetProcAddress("glElementPointerATI");
		glDrawElementArrayATI = (PFNGLDRAWELEMENTARRAYATIPROC)wglGetProcAddress("glDrawElementArrayATI");
		glDrawRangeElementArrayATI = (PFNGLDRAWRANGEELEMENTARRAYATIPROC)wglGetProcAddress("glDrawRangeElementArrayATI");
	}

	if ( strstr( wglextensions, "WGL_ARB_pbuffer" ) )
	{
		supportWGL_ARB_pbuffer = true;
		GETEXT( wglCreatePbufferARB,		"wglCreatePbufferARB" );
		GETEXT( wglGetPbufferDCARB,			"wglGetPbufferDCARB" );
		GETEXT( wglReleasePbufferDCARB,		"wglReleasePbufferDCARB" );
		GETEXT( wglDestroyPbufferARB,		"wglDestroyPbufferARB" );
		GETEXT( wglQueryPbufferARB,			"wglQueryPbufferARB" );
	}
	if ( strstr( wglextensions, "WGL_ARB_pixel_format" ) )
	{
		supportWGL_ARB_pixel_format = true;
		GETEXT( wglGetPixelFormatAttribivARB,	"wglGetPixelFormatAttribivARB" );
		GETEXT( wglGetPixelFormatAttribfvARB,	"wglGetPixelFormatAttribfvARB" );
		GETEXT( wglChoosePixelFormatARB,		"wglChoosePixelFormatARB" );
	}
	if ( strstr( wglextensions, "WGL_ARB_render_texture" ) )
	{
		supportWGL_ARB_render_texture = true;
		GETEXT( wglBindTexImageARB,			"wglBindTexImageARB" );
		GETEXT( wglReleaseTexImageARB,		"wglReleaseTexImageARB" );
		GETEXT( wglSetPbufferAttribARB,		"wglSetPbufferAttribARB" );
	}

	if ( strstr( extensions, "GL_SGIS_generate_mipmap" ) )
	{
		supportGL_SGIS_generate_mipmap = true;
	}
}


const float materialBorder_ambient[] = { 0.1f, 0.1f, 0.1f, 1.0f };
const float materialBorder_diffuse[] = { 0.7f, 0.7f, 0.7f, 1.0f };
const float materialBorder_specular[] = { 0.8f, 0.8f, 0.8f, 1.0f };
const float materialBorder_shininess = 40.0f;
const float materialBorder_emission[] = { 0.0f, 0.0f, 0.0f, 1.0f };

void setMaterial()
{
	glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT, materialBorder_ambient );
	glMaterialfv( GL_FRONT_AND_BACK, GL_DIFFUSE, materialBorder_diffuse );
	glMaterialfv( GL_FRONT_AND_BACK, GL_SPECULAR, materialBorder_specular );
	glMaterialfv( GL_FRONT_AND_BACK, GL_SHININESS, &materialBorder_shininess );
	glMaterialfv( GL_FRONT_AND_BACK, GL_EMISSION, materialBorder_emission );
}

