/*======================================================================================

	Program:		Range Imaging Toolkit (RITK)
	Module:			ritkOpenGLExtensions.h
	Version:		$Revision: 1761 $
	Date:			$Date: 2011-09-23 17:25:41 +0200 (Fri, 23 Sep 2011) $

	Copyright (c) 2010-2011
	Pattern Recognition Lab, 
    University Erlangen-Nuremberg, Germany
    All rights reserved.

	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 RITKCopyright.txt for more information.

	http://www5.informatik.uni-erlangen.de/research/software/ritk

========================================================================================*/

#ifndef OPENGLEXTENSIONS_H__
#define OPENGLEXTENSIONS_H__


#if defined (WIN32)

#include <iostream>
#include <GL/gl.h>

namespace ritk
{



// Multi texturing
#define GL_TEXTURE0 0x84C0
#define GL_TEXTURE1 0x84C1
#define GL_TEXTURE2 0x84C2
#define GL_TEXTURE3 0x84C3
#define GL_TEXTURE4 0x84C4
#define GL_TEXTURE5 0x84C5

// Shader
#define GL_FRAGMENT_SHADER 0x8B30
#define GL_VERTEX_SHADER 0x8B31
#define GL_INFO_LOG_LENGTH 0x8B84

// Floating point textures
#define GL_LUMINANCE32F_ARB 0x8818
#define GL_R32F 0x822E
#define GL_RGB32F 0x8815
#define GL_BGR 0x80E0

// VBO Extension Definitions, From glext.h
#define GL_ARRAY_BUFFER 0x8892
#define GL_ELEMENT_ARRAY_BUFFER 0x8893
#define GL_READ_ONLY 0x88B8
#define GL_WRITE_ONLY 0x88B9
#define GL_READ_WRITE 0x88BA
#define GL_BUFFER_ACCESS 0x88BB
#define GL_BUFFER_MAPPED 0x88BC
#define GL_BUFFER_MAP_POINTER 0x88BD
#define GL_STREAM_DRAW 0x88E0
#define GL_STREAM_READ 0x88E1
#define GL_STREAM_COPY 0x88E2
#define GL_STATIC_DRAW 0x88E4
#define GL_STATIC_READ 0x88E5
#define GL_STATIC_COPY 0x88E6
#define GL_DYNAMIC_DRAW 0x88E8
#define GL_DYNAMIC_READ 0x88E9
#define GL_DYNAMIC_COPY 0x88EA
#define GL_PIXEL_PACK_BUFFER 0x88EB
#define GL_PIXEL_UNPACK_BUFFER 0x88EC

/// GLchar
typedef char GLchar;

//typedef void (APIENTRY *PFNGLBUFFERDATAARBPROC) (GLenum target, int size, const GLvoid *data, GLenum usage);


/**	@name	Multitexturing */
//@{
typedef void (_stdcall *GL_ActiveTextureARB_Func)(unsigned int);
GL_ActiveTextureARB_Func glActiveTexture = NULL;

typedef void (_stdcall *GL_MultiTexCoord2fARB_Func)(unsigned int, float, float);
GL_MultiTexCoord2fARB_Func glMultiTexCoord2f = NULL;
//@}


/**	@name	Shader */
//@{
typedef GLuint (_stdcall *GL_CreateShader_Func)(GLenum);
GL_CreateShader_Func glCreateShader = NULL;

typedef void (_stdcall *GL_ShaderSource_Func)(GLuint, GLsizei, const GLchar**, const GLint*);
GL_ShaderSource_Func glShaderSource = NULL;

typedef void (_stdcall *GL_CompileShader_Func)(GLuint);
GL_CompileShader_Func glCompileShader = NULL;

typedef GLuint (_stdcall *GL_CreateProgram_Func)(void);
GL_CreateProgram_Func glCreateProgram = NULL;

typedef void (_stdcall *GL_AttachShader_Func)(GLuint,GLuint);
GL_AttachShader_Func glAttachShader = NULL;

typedef void (_stdcall *GL_GetShaderiv_Func)(GLuint,GLenum,GLint*);
GL_GetShaderiv_Func glGetShaderiv = NULL;

typedef void (_stdcall *GL_GetShaderInfoLog_Func)(GLuint,GLsizei,GLsizei*,GLchar*);
GL_GetShaderInfoLog_Func glGetShaderInfoLog = NULL;

typedef void (_stdcall *GL_LinkProgram_Func)(GLuint);
GL_LinkProgram_Func glLinkProgram = NULL;

typedef void (_stdcall *GL_UseProgram_Func)(GLuint);
GL_UseProgram_Func glUseProgram = NULL;

typedef GLint (_stdcall *GL_GetUniformLocation_Func)(GLuint,const GLchar*);
GL_GetUniformLocation_Func glGetUniformLocation = NULL;

typedef void (_stdcall *GL_Uniform1i_Func)(GLint,GLint);
GL_Uniform1i_Func glUniform1i = NULL;

typedef void (_stdcall *GL_Uniform1f_Func)(GLint,GLfloat);
GL_Uniform1f_Func glUniform1f = NULL;

typedef void (_stdcall *GL_Uniform3f_Func)(GLint,GLfloat,GLfloat,GLfloat);
GL_Uniform3f_Func glUniform3f = NULL;

typedef void (_stdcall *GL_DetachShader_Func)(GLuint,GLuint);
GL_DetachShader_Func glDetachShader = NULL;

typedef void (_stdcall *GL_DeleteShader_Func)(GLuint);
GL_DeleteShader_Func glDeleteShader = NULL;

typedef void (_stdcall *GL_DeleteProgram_Func)(GLuint);
GL_DeleteProgram_Func glDeleteProgram = NULL;

//@}


/**	@name	VBOs */
//@{
typedef void (_stdcall *GL_GenBuffers_Func)(GLsizei n, GLuint *buffers);
GL_GenBuffers_Func glGenBuffers = NULL;

typedef void (_stdcall *GL_BindBuffer_Func)(GLenum target, GLuint buffer);
GL_BindBuffer_Func glBindBuffer = NULL;

typedef void (_stdcall *GL_BufferData_Func)(GLenum target, int size, const GLvoid *data, GLenum usage);
GL_BufferData_Func glBufferData = NULL;

typedef void (_stdcall *GL_DeleteBuffers_Func)(GLsizei n, const GLuint *buffers);
GL_DeleteBuffers_Func glDeleteBuffers = NULL;

//@}


/// Initialize all OpenGL extensions
bool
InitOpenGLExtensions()
{
	glActiveTexture = (GL_ActiveTextureARB_Func) wglGetProcAddress("glActiveTextureARB");
	if ( !glActiveTexture )
	{
		std::cerr << "Could not find extension glActiveTexture()!" << std::endl;
		return false;
	}
	
	glMultiTexCoord2f = (GL_MultiTexCoord2fARB_Func) wglGetProcAddress("glMultiTexCoord2fARB");
	if ( !glMultiTexCoord2f )
	{
		std::cerr << "Could not find extension glMultiTexCoord2d()!" << std::endl;
		return false;
	}

	glCreateShader = (GL_CreateShader_Func) wglGetProcAddress("glCreateShader");
	if ( !glCreateShader )
	{
		std::cerr << "Could not obtain extension function glCreateShader()!" << std::endl;
		return false;
	}

	glShaderSource = (GL_ShaderSource_Func) wglGetProcAddress("glShaderSource");
	if ( !glShaderSource )
	{
		std::cerr << "Could not obtain extension function glShaderSource()!" << std::endl;
		return false;
	}

	glCompileShader = (GL_CompileShader_Func) wglGetProcAddress("glCompileShader");
	if ( !glCompileShader )
	{
		std::cerr << "Could not obtain extension function glCompileShader()!" << std::endl;
		return false;
	}

	glCreateProgram = (GL_CreateProgram_Func) wglGetProcAddress("glCreateProgram");
	if ( !glCreateProgram )
	{
		std::cerr << "Could not obtain extension function glCreateProgram()!" << std::endl;
		return false;
	}

	glAttachShader = (GL_AttachShader_Func) wglGetProcAddress("glAttachShader");
	if ( !glAttachShader )
	{
		std::cerr << "Could not obtain extension function glAttachShader()!" << std::endl;
		return false;
	}

	glGetShaderiv = (GL_GetShaderiv_Func) wglGetProcAddress("glGetShaderiv");
	if ( !glGetShaderiv )
	{
		std::cerr << "Could not obtain extension function glGetShaderiv()!" << std::endl;
		return false;
	}

	glGetShaderInfoLog = (GL_GetShaderInfoLog_Func) wglGetProcAddress("glGetShaderInfoLog");
	if ( !glGetShaderInfoLog )
	{
		std::cerr << "Could not obtain extension function glGetShaderInfoLog()!" << std::endl;
		return false;
	}

	glUseProgram = (GL_UseProgram_Func) wglGetProcAddress("glUseProgram");
	if ( !glUseProgram )
	{
		std::cerr << "Could not find extension glUseProgram()!" << std::endl;
		return false;
	}

	glLinkProgram = (GL_LinkProgram_Func) wglGetProcAddress("glLinkProgram");
	if ( !glLinkProgram )
	{
		std::cerr << "Could not find extension glLinkProgram()!" << std::endl;
		return false;
	}

	glGetUniformLocation = (GL_GetUniformLocation_Func) wglGetProcAddress("glGetUniformLocation");
	if ( !glGetUniformLocation )
	{
		std::cerr << "Could not find extension glGetUniformLocation()!" << std::endl;
		return false;
	}

	glUniform1i = (GL_Uniform1i_Func) wglGetProcAddress("glUniform1i");
	if ( !glUniform1i )
	{
		std::cerr << "Could not find extension glUniform1i" << std::endl;
		return false;
	}

	glUniform1f = (GL_Uniform1f_Func) wglGetProcAddress("glUniform1f");
	if ( !glUniform1i )
	{
		std::cerr << "Could not find extension glUniform1f" << std::endl;
		return false;
	}

	glUniform3f = (GL_Uniform3f_Func) wglGetProcAddress("glUniform3f");
	if ( !glUniform3f )
	{
		std::cerr << "Could not find extension glUniform3f" << std::endl;
		return false;
	}

	glDetachShader = (GL_DetachShader_Func) wglGetProcAddress("glDetachShader");
	if ( !glDetachShader )
	{
		std::cerr << "Could not find extension glDetachShader" << std::endl;
		return false;
	}

	glDeleteShader = (GL_DeleteShader_Func) wglGetProcAddress("glDeleteShader");
	if ( !glDeleteShader )
	{
		std::cerr << "Could not find extension glDeleteShader" << std::endl;
		return false;
	}

	glDeleteProgram = (GL_DeleteProgram_Func) wglGetProcAddress("glDeleteProgram");
	if ( !glDeleteProgram )
	{
		std::cerr << "Could not find extension glDeleteProgram" << std::endl;
		return false;
	}

	glGenBuffers = (GL_GenBuffers_Func) wglGetProcAddress("glGenBuffers");
	if ( !glGenBuffers )
	{
		std::cerr << "Could not find extension glGenBuffers" << std::endl;
		return false;
	}

	glBindBuffer = (GL_BindBuffer_Func) wglGetProcAddress("glBindBuffer");
	if ( !glBindBuffer )
	{
		std::cerr << "Could not find extension glBindBuffer" << std::endl;
		return false;
	}

	glBufferData = (GL_BufferData_Func) wglGetProcAddress("glBufferData");
	if ( !glBufferData )
	{
		std::cerr << "Could not find extension glBufferData" << std::endl;
		return false;
	}

	glDeleteBuffers = (GL_DeleteBuffers_Func) wglGetProcAddress("glDeleteBuffers");
	if ( !glDeleteBuffers )
	{
		std::cerr << "Could not find extension glDeleteBuffers" << std::endl;
		return false;
	}

	return true;
}

} // end namespace ritk
#else
#include <GLee.h>
#endif

#endif // OPENGELEXTENSIONS_H__
