/**
 * Glad - OpenGL ES 3.0 Loader Implementation
 */
#include <glad/gl.h>

PFNGLCLEARCOLORPROC glad_glClearColor = NULL;
PFNGLCLEARPROC glad_glClear = NULL;
PFNGLENABLEPROC glad_glEnable = NULL;
PFNGLDISABLEPROC glad_glDisable = NULL;
PFNGLVIEWPORTPROC glad_glViewport = NULL;
PFNGLGETSTRINGPROC glad_glGetString = NULL;
PFNGLBLENDFUNCPROC glad_glBlendFunc = NULL;

PFNGLCREATESHADERPROC glad_glCreateShader = NULL;
PFNGLDELETESHADERPROC glad_glDeleteShader = NULL;
PFNGLSHADERSOURCEPROC glad_glShaderSource = NULL;
PFNGLCOMPILESHADERPROC glad_glCompileShader = NULL;
PFNGLGETSHADERIVPROC glad_glGetShaderiv = NULL;
PFNGLGETSHADERINFOLOGPROC glad_glGetShaderInfoLog = NULL;

PFNGLCREATEPROGRAMPROC glad_glCreateProgram = NULL;
PFNGLDELETEPROGRAMPROC glad_glDeleteProgram = NULL;
PFNGLATTACHSHADERPROC glad_glAttachShader = NULL;
PFNGLLINKPROGRAMPROC glad_glLinkProgram = NULL;
PFNGLUSEPROGRAMPROC glad_glUseProgram = NULL;
PFNGLGETPROGRAMIVPROC glad_glGetProgramiv = NULL;
PFNGLGETPROGRAMINFOLOGPROC glad_glGetProgramInfoLog = NULL;

PFNGLGETUNIFORMLOCATIONPROC glad_glGetUniformLocation = NULL;
PFNGLUNIFORM1IPROC glad_glUniform1i = NULL;
PFNGLUNIFORM1FPROC glad_glUniform1f = NULL;
PFNGLUNIFORM2FPROC glad_glUniform2f = NULL;
PFNGLUNIFORM3FPROC glad_glUniform3f = NULL;
PFNGLUNIFORM4FPROC glad_glUniform4f = NULL;
PFNGLUNIFORMMATRIX4FVPROC glad_glUniformMatrix4fv = NULL;

PFNGLGENVERTEXARRAYSPROC glad_glGenVertexArrays = NULL;
PFNGLDELETEVERTEXARRAYSPROC glad_glDeleteVertexArrays = NULL;
PFNGLBINDVERTEXARRAYPROC glad_glBindVertexArray = NULL;

PFNGLGENBUFFERSPROC glad_glGenBuffers = NULL;
PFNGLDELETEBUFFERSPROC glad_glDeleteBuffers = NULL;
PFNGLBINDBUFFERPROC glad_glBindBuffer = NULL;
PFNGLBUFFERDATAPROC glad_glBufferData = NULL;

PFNGLVERTEXATTRIBPOINTERPROC glad_glVertexAttribPointer = NULL;
PFNGLENABLEVERTEXATTRIBARRAYPROC glad_glEnableVertexAttribArray = NULL;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glad_glDisableVertexAttribArray = NULL;

PFNGLDRAWARRAYSPROC glad_glDrawArrays = NULL;
PFNGLDRAWELEMENTSPROC glad_glDrawElements = NULL;

PFNGLGENTEXTURESPROC glad_glGenTextures = NULL;
PFNGLDELETETEXTURESPROC glad_glDeleteTextures = NULL;
PFNGLBINDTEXTUREPROC glad_glBindTexture = NULL;
PFNGLTEXIMAGE2DPROC glad_glTexImage2D = NULL;
PFNGLTEXPARAMETERIPROC glad_glTexParameteri = NULL;
PFNGLACTIVETEXTUREPROC glad_glActiveTexture = NULL;

PFNGLGETINTEGERVPROC glad_glGetIntegerv = NULL;
PFNGLGETERRORPROC glad_glGetError = NULL;

int gladLoadGL(GLADloadfunc load) {
    if (load == NULL) return 0;

    typedef void* (*LoadFunc)(const char*);
    LoadFunc loader = (LoadFunc)load;

    #define LOAD(type, name) glad_##name = (type)loader(#name)

    LOAD(PFNGLCLEARCOLORPROC, glClearColor);
    LOAD(PFNGLCLEARPROC, glClear);
    LOAD(PFNGLENABLEPROC, glEnable);
    LOAD(PFNGLDISABLEPROC, glDisable);
    LOAD(PFNGLVIEWPORTPROC, glViewport);
    LOAD(PFNGLGETSTRINGPROC, glGetString);
    LOAD(PFNGLBLENDFUNCPROC, glBlendFunc);

    LOAD(PFNGLCREATESHADERPROC, glCreateShader);
    LOAD(PFNGLDELETESHADERPROC, glDeleteShader);
    LOAD(PFNGLSHADERSOURCEPROC, glShaderSource);
    LOAD(PFNGLCOMPILESHADERPROC, glCompileShader);
    LOAD(PFNGLGETSHADERIVPROC, glGetShaderiv);
    LOAD(PFNGLGETSHADERINFOLOGPROC, glGetShaderInfoLog);

    LOAD(PFNGLCREATEPROGRAMPROC, glCreateProgram);
    LOAD(PFNGLDELETEPROGRAMPROC, glDeleteProgram);
    LOAD(PFNGLATTACHSHADERPROC, glAttachShader);
    LOAD(PFNGLLINKPROGRAMPROC, glLinkProgram);
    LOAD(PFNGLUSEPROGRAMPROC, glUseProgram);
    LOAD(PFNGLGETPROGRAMIVPROC, glGetProgramiv);
    LOAD(PFNGLGETPROGRAMINFOLOGPROC, glGetProgramInfoLog);

    LOAD(PFNGLGETUNIFORMLOCATIONPROC, glGetUniformLocation);
    LOAD(PFNGLUNIFORM1IPROC, glUniform1i);
    LOAD(PFNGLUNIFORM1FPROC, glUniform1f);
    LOAD(PFNGLUNIFORM2FPROC, glUniform2f);
    LOAD(PFNGLUNIFORM3FPROC, glUniform3f);
    LOAD(PFNGLUNIFORM4FPROC, glUniform4f);
    LOAD(PFNGLUNIFORMMATRIX4FVPROC, glUniformMatrix4fv);

    LOAD(PFNGLGENVERTEXARRAYSPROC, glGenVertexArrays);
    LOAD(PFNGLDELETEVERTEXARRAYSPROC, glDeleteVertexArrays);
    LOAD(PFNGLBINDVERTEXARRAYPROC, glBindVertexArray);

    LOAD(PFNGLGENBUFFERSPROC, glGenBuffers);
    LOAD(PFNGLDELETEBUFFERSPROC, glDeleteBuffers);
    LOAD(PFNGLBINDBUFFERPROC, glBindBuffer);
    LOAD(PFNGLBUFFERDATAPROC, glBufferData);

    LOAD(PFNGLVERTEXATTRIBPOINTERPROC, glVertexAttribPointer);
    LOAD(PFNGLENABLEVERTEXATTRIBARRAYPROC, glEnableVertexAttribArray);
    LOAD(PFNGLDISABLEVERTEXATTRIBARRAYPROC, glDisableVertexAttribArray);

    LOAD(PFNGLDRAWARRAYSPROC, glDrawArrays);
    LOAD(PFNGLDRAWELEMENTSPROC, glDrawElements);

    LOAD(PFNGLGENTEXTURESPROC, glGenTextures);
    LOAD(PFNGLDELETETEXTURESPROC, glDeleteTextures);
    LOAD(PFNGLBINDTEXTUREPROC, glBindTexture);
    LOAD(PFNGLTEXIMAGE2DPROC, glTexImage2D);
    LOAD(PFNGLTEXPARAMETERIPROC, glTexParameteri);
    LOAD(PFNGLACTIVETEXTUREPROC, glActiveTexture);

    LOAD(PFNGLGETINTEGERVPROC, glGetIntegerv);
    LOAD(PFNGLGETERRORPROC, glGetError);

    #undef LOAD

    return glad_glGetString != NULL ? 1 : 0;
}
