import dlibincludes;

// TODO: fix on js side

PFNGLDELETERENDERBUFFERSPROC      glDeleteRenderbuffers;
PFNGLGENRENDERBUFFERSPROC         glGenRenderbuffers;
PFNGLGENVERTEXARRAYSPROC          glGenVertexArrays;
PFNGLDELETEVERTEXARRAYSPROC       glDeleteVertexArrays;
PFNGLGENBUFFERSPROC               glGenBuffers;
PFNGLCOMPILESHADERPROC            glCompileShader;
PFNGLUSEPROGRAMPROC               glUseProgram;
PFNGLVALIDATEPROGRAMPROC          glValidateProgram;
PFNGLBINDBUFFERBASEPROC           glBindBufferBase;
PFNGLGETUNIFORMBLOCKINDEXPROC     glGetUniformBlockIndex;
PFNGLENABLEVERTEXATTRIBARRAYPROC  glEnableVertexAttribArray;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
PFNGLBLENDFUNCSEPARATEPROC        glBlendFuncSeparate;
PFNGLBINDVERTEXARRAYPROC          glBindVertexArray;
PFNGLBINDBUFFERPROC               glBindBuffer;
PFNGLBUFFERDATAPROC               glBufferData;
PFNGLBUFFERSUBDATAPROC            glBufferSubData;
PFNGLVERTEXATTRIBDIVISORPROC      glVertexAttribDivisor;
PFNGLVERTEXATTRIBPOINTERPROC      glVertexAttribPointer;
PFNGLDRAWARRAYSINSTANCEDPROC      glDrawArraysInstanced;
PFNGLDRAWELEMENTSINSTANCEDPROC    glDrawElementsInstanced;
PFNGLGETUNIFORMLOCATIONPROC       glGetUniformLocation;
PFNGLUNIFORM1FPROC                glUniform1f;
PFNGLUNIFORM2FPROC                glUniform2f;
PFNGLUNIFORM3FPROC                glUniform3f;
PFNGLUNIFORM4FPROC                glUniform4f;
PFNGLUNIFORM1IPROC                glUniform1i;
PFNGLUNIFORM2IPROC                glUniform2i;
PFNGLUNIFORM3IPROC                glUniform3i;
PFNGLUNIFORM4IPROC                glUniform4i;
PFNGLCREATEPROGRAMPROC            glCreateProgram;
PFNGLCREATESHADERPROC             glCreateShader;
PFNGLDELETEFRAMEBUFFERSPROC       glDeleteFramebuffers;
PFNGLDELETEPROGRAMPROC            glDeleteProgram;
PFNGLDELETESHADERPROC             glDeleteShader;
PFNGLSHADERSOURCEPROC             glShaderSource;
PFNGLGETPROGRAMIVPROC             glGetProgramiv;
PFNGLGETPROGRAMINFOLOGPROC        glGetProgramInfoLog;
PFNGLGETSHADERIVPROC              glGetShaderiv;
PFNGLGETSHADERINFOLOGPROC         glGetShaderInfoLog;
PFNGLATTACHSHADERPROC             glAttachShader;
PFNGLLINKPROGRAMPROC              glLinkProgram;

static if(!__traits(compiles, { glActiveTexture(0x84C0); }))
{
	PFNGLACTIVETEXTUREPROC            glActiveTexture;
}

alias GLLoadProcAddr = SDL_GL_GetProcAddress;

bool
GLLoadFuncs()
{
	glDeleteRenderbuffers      = cast(typeof(glDeleteRenderbuffers))GLLoadProcAddr(cast(const(char)*)"glDeleteRenderbuffers".ptr);
	glGenRenderbuffers         = cast(typeof(glGenRenderbuffers))GLLoadProcAddr(cast(const(char)*)"glGenRenderbuffers".ptr);
	glGenVertexArrays          = cast(typeof(glGenVertexArrays))GLLoadProcAddr(cast(const(char)*)"glGenVertexArrays".ptr);
	glDeleteVertexArrays       = cast(typeof(glDeleteVertexArrays))GLLoadProcAddr(cast(const(char)*)"glDeleteVertexArrays".ptr);
	glGenBuffers               = cast(typeof(glGenBuffers))GLLoadProcAddr(cast(const(char)*)"glGenBuffers".ptr);
	glCompileShader            = cast(typeof(glCompileShader))GLLoadProcAddr(cast(const(char)*)"glCompileShader".ptr);
	glUseProgram               = cast(typeof(glUseProgram))GLLoadProcAddr(cast(const(char)*)"glUseProgram".ptr);
	glValidateProgram          = cast(typeof(glValidateProgram))GLLoadProcAddr(cast(const(char)*)"glValidateProgram".ptr);
	glBindBufferBase           = cast(typeof(glBindBufferBase))GLLoadProcAddr(cast(const(char)*)"glBindBufferBase".ptr);
	glGetUniformBlockIndex     = cast(typeof(glGetUniformBlockIndex))GLLoadProcAddr(cast(const(char)*)"glGetUniformBlockIndex".ptr);
	glEnableVertexAttribArray  = cast(typeof(glEnableVertexAttribArray))GLLoadProcAddr(cast(const(char)*)"glEnableVertexAttribArray".ptr);
	glDisableVertexAttribArray = cast(typeof(glDisableVertexAttribArray))GLLoadProcAddr(cast(const(char)*)"glDisableVertexAttribArray".ptr);
	glBlendFuncSeparate        = cast(typeof(glBlendFuncSeparate))GLLoadProcAddr(cast(const(char)*)"glBlendFuncSeparate".ptr);
	glBindVertexArray          = cast(typeof(glBindVertexArray))GLLoadProcAddr(cast(const(char)*)"glBindVertexArray".ptr);
	glBindBuffer               = cast(typeof(glBindBuffer))GLLoadProcAddr(cast(const(char)*)"glBindBuffer".ptr);
	glBufferData               = cast(typeof(glBufferData))GLLoadProcAddr(cast(const(char)*)"glBufferData".ptr);
	glBufferSubData            = cast(typeof(glBufferSubData))GLLoadProcAddr(cast(const(char)*)"glBufferSubData".ptr);
	glVertexAttribDivisor      = cast(typeof(glVertexAttribDivisor))GLLoadProcAddr(cast(const(char)*)"glVertexAttribDivisor".ptr);
	glVertexAttribPointer      = cast(typeof(glVertexAttribPointer))GLLoadProcAddr(cast(const(char)*)"glVertexAttribPointer".ptr);
	glDrawArraysInstanced      = cast(typeof(glDrawArraysInstanced))GLLoadProcAddr(cast(const(char)*)"glDrawArraysInstanced".ptr);
	glDrawElementsInstanced    = cast(typeof(glDrawElementsInstanced))GLLoadProcAddr(cast(const(char)*)"glDrawElementsInstanced".ptr);
	glGetUniformLocation       = cast(typeof(glGetUniformLocation))GLLoadProcAddr(cast(const(char)*)"glGetUniformLocation".ptr);
	glUniform1f                = cast(typeof(glUniform1f))GLLoadProcAddr(cast(const(char)*)"glUniform1f".ptr);
	glUniform2f                = cast(typeof(glUniform2f))GLLoadProcAddr(cast(const(char)*)"glUniform2f".ptr);
	glUniform3f                = cast(typeof(glUniform3f))GLLoadProcAddr(cast(const(char)*)"glUniform3f".ptr);
	glUniform4f                = cast(typeof(glUniform4f))GLLoadProcAddr(cast(const(char)*)"glUniform4f".ptr);
	glUniform1i                = cast(typeof(glUniform1i))GLLoadProcAddr(cast(const(char)*)"glUniform1i".ptr);
	glUniform2i                = cast(typeof(glUniform2i))GLLoadProcAddr(cast(const(char)*)"glUniform2i".ptr);
	glUniform3i                = cast(typeof(glUniform3i))GLLoadProcAddr(cast(const(char)*)"glUniform3i".ptr);
	glUniform4i                = cast(typeof(glUniform4i))GLLoadProcAddr(cast(const(char)*)"glUniform4i".ptr);
	glCreateProgram            = cast(typeof(glCreateProgram))GLLoadProcAddr(cast(const(char)*)"glCreateProgram".ptr);
	glCreateShader             = cast(typeof(glCreateShader))GLLoadProcAddr(cast(const(char)*)"glCreateShader".ptr);
	glDeleteFramebuffers       = cast(typeof(glDeleteFramebuffers))GLLoadProcAddr(cast(const(char)*)"glDeleteFramebuffers".ptr);
	glDeleteProgram            = cast(typeof(glDeleteProgram))GLLoadProcAddr(cast(const(char)*)"glDeleteProgram".ptr);
	glDeleteShader             = cast(typeof(glDeleteShader))GLLoadProcAddr(cast(const(char)*)"glDeleteShader".ptr);
	glShaderSource             = cast(typeof(glShaderSource))GLLoadProcAddr(cast(const(char)*)"glShaderSource".ptr);
	glGetProgramiv             = cast(typeof(glGetProgramiv))GLLoadProcAddr(cast(const(char)*)"glGetProgramiv".ptr);
	glGetProgramInfoLog        = cast(typeof(glGetProgramInfoLog))GLLoadProcAddr(cast(const(char)*)"glGetProgramInfoLog".ptr);
	glGetShaderiv              = cast(typeof(glGetShaderiv))GLLoadProcAddr(cast(const(char)*)"glGetShaderiv".ptr);
	glGetShaderInfoLog         = cast(typeof(glGetShaderInfoLog))GLLoadProcAddr(cast(const(char)*)"glGetShaderInfoLog".ptr);
	glAttachShader             = cast(typeof(glAttachShader))GLLoadProcAddr(cast(const(char)*)"glAttachShader".ptr);
	glLinkProgram              = cast(typeof(glLinkProgram))GLLoadProcAddr(cast(const(char)*)"glLinkProgram".ptr);

	static if(!__traits(compiles, { glActiveTexture(0x84C0); }))
	{
		glActiveTexture            = cast(typeof(glActiveTexture))GLLoadProcAddr(cast(const(char)*)"glActiveTexture".ptr);
	}

	return glDeleteRenderbuffers != null;
}
