// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.

#include <sstream>
#include <unordered_map>

#include "Common/Logging/Log.h"
#include "VideoBackends/OGL/GLInterfaceBase.h"
#include "VideoBackends/OGL/GLExtensions/GLExtensions.h"

#if defined(__linux__) || defined(__APPLE__)
#include <dlfcn.h>
#endif

// gl_1_1
PFNGLCLEARINDEXPROC glClearIndex;
PFNGLCLEARCOLORPROC glClearColor;
PFNGLCLEARPROC glClear;
PFNGLINDEXMASKPROC glIndexMask;
PFNGLCOLORMASKPROC glColorMask;
PFNGLALPHAFUNCPROC glAlphaFunc;
PFNGLBLENDFUNCPROC glBlendFunc;
PFNGLLOGICOPPROC glLogicOp;
PFNGLCULLFACEPROC glCullFace;
PFNGLFRONTFACEPROC glFrontFace;
PFNGLPOINTSIZEPROC glPointSize;
PFNGLLINEWIDTHPROC glLineWidth;
PFNGLLINESTIPPLEPROC glLineStipple;
PFNGLPOLYGONMODEPROC glPolygonMode;
PFNGLPOLYGONOFFSETPROC glPolygonOffset;
PFNGLPOLYGONSTIPPLEPROC glPolygonStipple;
PFNGLGETPOLYGONSTIPPLEPROC glGetPolygonStipple;
PFNGLEDGEFLAGPROC glEdgeFlag;
PFNGLEDGEFLAGVPROC glEdgeFlagv;
PFNGLSCISSORPROC glScissor;
PFNGLCLIPPLANEPROC glClipPlane;
PFNGLGETCLIPPLANEPROC glGetClipPlane;
PFNGLDRAWBUFFERPROC glDrawBuffer;
PFNGLREADBUFFERPROC glReadBuffer;
PFNGLENABLEPROC glEnable;
PFNGLDISABLEPROC glDisable;
PFNGLISENABLEDPROC glIsEnabled;
PFNGLENABLECLIENTSTATEPROC glEnableClientState;
PFNGLDISABLECLIENTSTATEPROC glDisableClientState;
PFNGLGETBOOLEANVPROC glGetBooleanv;
PFNGLGETDOUBLEVPROC glGetDoublev;
PFNGLGETFLOATVPROC glGetFloatv;
PFNGLGETINTEGERVPROC glGetIntegerv;
PFNGLPUSHATTRIBPROC glPushAttrib;
PFNGLPOPATTRIBPROC glPopAttrib;
PFNGLPUSHCLIENTATTRIBPROC glPushClientAttrib;
PFNGLPOPCLIENTATTRIBPROC glPopClientAttrib;
PFNGLRENDERMODEPROC glRenderMode;
PFNGLGETERRORPROC glGetError;
PFNGLGETSTRINGPROC glGetString;
PFNGLFINISHPROC glFinish;
PFNGLFLUSHPROC glFlush;
PFNGLHINTPROC glHint;
PFNGLCLEARDEPTHPROC glClearDepth;
PFNGLDEPTHFUNCPROC glDepthFunc;
PFNGLDEPTHMASKPROC glDepthMask;
PFNGLDEPTHRANGEPROC glDepthRange;
PFNGLCLEARACCUMPROC glClearAccum;
PFNGLACCUMPROC glAccum;
PFNGLMATRIXMODEPROC glMatrixMode;
PFNGLORTHOPROC glOrtho;
PFNGLFRUSTUMPROC glFrustum;
PFNGLVIEWPORTPROC glViewport;
PFNGLPUSHMATRIXPROC glPushMatrix;
PFNGLPOPMATRIXPROC glPopMatrix;
PFNGLLOADIDENTITYPROC glLoadIdentity;
PFNGLLOADMATRIXDPROC glLoadMatrixd;
PFNGLLOADMATRIXFPROC glLoadMatrixf;
PFNGLMULTMATRIXDPROC glMultMatrixd;
PFNGLMULTMATRIXFPROC glMultMatrixf;
PFNGLROTATEDPROC glRotated;
PFNGLROTATEFPROC glRotatef;
PFNGLSCALEDPROC glScaled;
PFNGLSCALEFPROC glScalef;
PFNGLTRANSLATEDPROC glTranslated;
PFNGLTRANSLATEFPROC glTranslatef;
PFNGLISLISTPROC glIsList;
PFNGLDELETELISTSPROC glDeleteLists;
PFNGLGENLISTSPROC glGenLists;
PFNGLNEWLISTPROC glNewList;
PFNGLENDLISTPROC glEndList;
PFNGLCALLLISTPROC glCallList;
PFNGLCALLLISTSPROC glCallLists;
PFNGLLISTBASEPROC glListBase;
PFNGLBEGINPROC glBegin;
PFNGLENDPROC glEnd;
PFNGLVERTEX2DPROC glVertex2d;
PFNGLVERTEX2FPROC glVertex2f;
PFNGLVERTEX2IPROC glVertex2i;
PFNGLVERTEX2SPROC glVertex2s;
PFNGLVERTEX3DPROC glVertex3d;
PFNGLVERTEX3FPROC glVertex3f;
PFNGLVERTEX3IPROC glVertex3i;
PFNGLVERTEX3SPROC glVertex3s;
PFNGLVERTEX4DPROC glVertex4d;
PFNGLVERTEX4FPROC glVertex4f;
PFNGLVERTEX4IPROC glVertex4i;
PFNGLVERTEX4SPROC glVertex4s;
PFNGLVERTEX2DVPROC glVertex2dv;
PFNGLVERTEX2FVPROC glVertex2fv;
PFNGLVERTEX2IVPROC glVertex2iv;
PFNGLVERTEX2SVPROC glVertex2sv;
PFNGLVERTEX3DVPROC glVertex3dv;
PFNGLVERTEX3FVPROC glVertex3fv;
PFNGLVERTEX3IVPROC glVertex3iv;
PFNGLVERTEX3SVPROC glVertex3sv;
PFNGLVERTEX4DVPROC glVertex4dv;
PFNGLVERTEX4FVPROC glVertex4fv;
PFNGLVERTEX4IVPROC glVertex4iv;
PFNGLVERTEX4SVPROC glVertex4sv;
PFNGLNORMAL3BPROC glNormal3b;
PFNGLNORMAL3DPROC glNormal3d;
PFNGLNORMAL3FPROC glNormal3f;
PFNGLNORMAL3IPROC glNormal3i;
PFNGLNORMAL3SPROC glNormal3s;
PFNGLNORMAL3BVPROC glNormal3bv;
PFNGLNORMAL3DVPROC glNormal3dv;
PFNGLNORMAL3FVPROC glNormal3fv;
PFNGLNORMAL3IVPROC glNormal3iv;
PFNGLNORMAL3SVPROC glNormal3sv;
PFNGLINDEXDPROC glIndexd;
PFNGLINDEXFPROC glIndexf;
PFNGLINDEXIPROC glIndexi;
PFNGLINDEXSPROC glIndexs;
PFNGLINDEXUBPROC glIndexub;
PFNGLINDEXDVPROC glIndexdv;
PFNGLINDEXFVPROC glIndexfv;
PFNGLINDEXIVPROC glIndexiv;
PFNGLINDEXSVPROC glIndexsv;
PFNGLINDEXUBVPROC glIndexubv;
PFNGLCOLOR3BPROC glColor3b;
PFNGLCOLOR3DPROC glColor3d;
PFNGLCOLOR3FPROC glColor3f;
PFNGLCOLOR3IPROC glColor3i;
PFNGLCOLOR3SPROC glColor3s;
PFNGLCOLOR3UBPROC glColor3ub;
PFNGLCOLOR3UIPROC glColor3ui;
PFNGLCOLOR3USPROC glColor3us;
PFNGLCOLOR4BPROC glColor4b;
PFNGLCOLOR4DPROC glColor4d;
PFNGLCOLOR4FPROC glColor4f;
PFNGLCOLOR4IPROC glColor4i;
PFNGLCOLOR4SPROC glColor4s;
PFNGLCOLOR4UBPROC glColor4ub;
PFNGLCOLOR4UIPROC glColor4ui;
PFNGLCOLOR4USPROC glColor4us;
PFNGLCOLOR3BVPROC glColor3bv;
PFNGLCOLOR3DVPROC glColor3dv;
PFNGLCOLOR3FVPROC glColor3fv;
PFNGLCOLOR3IVPROC glColor3iv;
PFNGLCOLOR3SVPROC glColor3sv;
PFNGLCOLOR3UBVPROC glColor3ubv;
PFNGLCOLOR3UIVPROC glColor3uiv;
PFNGLCOLOR3USVPROC glColor3usv;
PFNGLCOLOR4BVPROC glColor4bv;
PFNGLCOLOR4DVPROC glColor4dv;
PFNGLCOLOR4FVPROC glColor4fv;
PFNGLCOLOR4IVPROC glColor4iv;
PFNGLCOLOR4SVPROC glColor4sv;
PFNGLCOLOR4UBVPROC glColor4ubv;
PFNGLCOLOR4UIVPROC glColor4uiv;
PFNGLCOLOR4USVPROC glColor4usv;
PFNGLTEXCOORD1DPROC glTexCoord1d;
PFNGLTEXCOORD1FPROC glTexCoord1f;
PFNGLTEXCOORD1IPROC glTexCoord1i;
PFNGLTEXCOORD1SPROC glTexCoord1s;
PFNGLTEXCOORD2DPROC glTexCoord2d;
PFNGLTEXCOORD2FPROC glTexCoord2f;
PFNGLTEXCOORD2IPROC glTexCoord2i;
PFNGLTEXCOORD2SPROC glTexCoord2s;
PFNGLTEXCOORD3DPROC glTexCoord3d;
PFNGLTEXCOORD3FPROC glTexCoord3f;
PFNGLTEXCOORD3IPROC glTexCoord3i;
PFNGLTEXCOORD3SPROC glTexCoord3s;
PFNGLTEXCOORD4DPROC glTexCoord4d;
PFNGLTEXCOORD4FPROC glTexCoord4f;
PFNGLTEXCOORD4IPROC glTexCoord4i;
PFNGLTEXCOORD4SPROC glTexCoord4s;
PFNGLTEXCOORD1DVPROC glTexCoord1dv;
PFNGLTEXCOORD1FVPROC glTexCoord1fv;
PFNGLTEXCOORD1IVPROC glTexCoord1iv;
PFNGLTEXCOORD1SVPROC glTexCoord1sv;
PFNGLTEXCOORD2DVPROC glTexCoord2dv;
PFNGLTEXCOORD2FVPROC glTexCoord2fv;
PFNGLTEXCOORD2IVPROC glTexCoord2iv;
PFNGLTEXCOORD2SVPROC glTexCoord2sv;
PFNGLTEXCOORD3DVPROC glTexCoord3dv;
PFNGLTEXCOORD3FVPROC glTexCoord3fv;
PFNGLTEXCOORD3IVPROC glTexCoord3iv;
PFNGLTEXCOORD3SVPROC glTexCoord3sv;
PFNGLTEXCOORD4DVPROC glTexCoord4dv;
PFNGLTEXCOORD4FVPROC glTexCoord4fv;
PFNGLTEXCOORD4IVPROC glTexCoord4iv;
PFNGLTEXCOORD4SVPROC glTexCoord4sv;
PFNGLRASTERPOS2DPROC glRasterPos2d;
PFNGLRASTERPOS2FPROC glRasterPos2f;
PFNGLRASTERPOS2IPROC glRasterPos2i;
PFNGLRASTERPOS2SPROC glRasterPos2s;
PFNGLRASTERPOS3DPROC glRasterPos3d;
PFNGLRASTERPOS3FPROC glRasterPos3f;
PFNGLRASTERPOS3IPROC glRasterPos3i;
PFNGLRASTERPOS3SPROC glRasterPos3s;
PFNGLRASTERPOS4DPROC glRasterPos4d;
PFNGLRASTERPOS4FPROC glRasterPos4f;
PFNGLRASTERPOS4IPROC glRasterPos4i;
PFNGLRASTERPOS4SPROC glRasterPos4s;
PFNGLRASTERPOS2DVPROC glRasterPos2dv;
PFNGLRASTERPOS2FVPROC glRasterPos2fv;
PFNGLRASTERPOS2IVPROC glRasterPos2iv;
PFNGLRASTERPOS2SVPROC glRasterPos2sv;
PFNGLRASTERPOS3DVPROC glRasterPos3dv;
PFNGLRASTERPOS3FVPROC glRasterPos3fv;
PFNGLRASTERPOS3IVPROC glRasterPos3iv;
PFNGLRASTERPOS3SVPROC glRasterPos3sv;
PFNGLRASTERPOS4DVPROC glRasterPos4dv;
PFNGLRASTERPOS4FVPROC glRasterPos4fv;
PFNGLRASTERPOS4IVPROC glRasterPos4iv;
PFNGLRASTERPOS4SVPROC glRasterPos4sv;
PFNGLRECTDPROC glRectd;
PFNGLRECTFPROC glRectf;
PFNGLRECTIPROC glRecti;
PFNGLRECTSPROC glRects;
PFNGLRECTDVPROC glRectdv;
PFNGLRECTFVPROC glRectfv;
PFNGLRECTIVPROC glRectiv;
PFNGLRECTSVPROC glRectsv;
PFNGLVERTEXPOINTERPROC glVertexPointer;
PFNGLNORMALPOINTERPROC glNormalPointer;
PFNGLCOLORPOINTERPROC glColorPointer;
PFNGLINDEXPOINTERPROC glIndexPointer;
PFNGLTEXCOORDPOINTERPROC glTexCoordPointer;
PFNGLEDGEFLAGPOINTERPROC glEdgeFlagPointer;
PFNGLGETPOINTERVPROC glGetPointerv;
PFNGLARRAYELEMENTPROC glArrayElement;
PFNGLDRAWARRAYSPROC glDrawArrays;
PFNGLDRAWELEMENTSPROC glDrawElements;
PFNGLINTERLEAVEDARRAYSPROC glInterleavedArrays;
PFNGLSHADEMODELPROC glShadeModel;
PFNGLLIGHTFPROC glLightf;
PFNGLLIGHTIPROC glLighti;
PFNGLLIGHTFVPROC glLightfv;
PFNGLLIGHTIVPROC glLightiv;
PFNGLGETLIGHTFVPROC glGetLightfv;
PFNGLGETLIGHTIVPROC glGetLightiv;
PFNGLLIGHTMODELFPROC glLightModelf;
PFNGLLIGHTMODELIPROC glLightModeli;
PFNGLLIGHTMODELFVPROC glLightModelfv;
PFNGLLIGHTMODELIVPROC glLightModeliv;
PFNGLMATERIALFPROC glMaterialf;
PFNGLMATERIALIPROC glMateriali;
PFNGLMATERIALFVPROC glMaterialfv;
PFNGLMATERIALIVPROC glMaterialiv;
PFNGLGETMATERIALFVPROC glGetMaterialfv;
PFNGLGETMATERIALIVPROC glGetMaterialiv;
PFNGLCOLORMATERIALPROC glColorMaterial;
PFNGLPIXELZOOMPROC glPixelZoom;
PFNGLPIXELSTOREFPROC glPixelStoref;
PFNGLPIXELSTOREIPROC glPixelStorei;
PFNGLPIXELTRANSFERFPROC glPixelTransferf;
PFNGLPIXELTRANSFERIPROC glPixelTransferi;
PFNGLPIXELMAPFVPROC glPixelMapfv;
PFNGLPIXELMAPUIVPROC glPixelMapuiv;
PFNGLPIXELMAPUSVPROC glPixelMapusv;
PFNGLGETPIXELMAPFVPROC glGetPixelMapfv;
PFNGLGETPIXELMAPUIVPROC glGetPixelMapuiv;
PFNGLGETPIXELMAPUSVPROC glGetPixelMapusv;
PFNGLBITMAPPROC glBitmap;
PFNGLREADPIXELSPROC glReadPixels;
PFNGLDRAWPIXELSPROC glDrawPixels;
PFNGLCOPYPIXELSPROC glCopyPixels;
PFNGLSTENCILFUNCPROC glStencilFunc;
PFNGLSTENCILMASKPROC glStencilMask;
PFNGLSTENCILOPPROC glStencilOp;
PFNGLCLEARSTENCILPROC glClearStencil;
PFNGLTEXGENDPROC glTexGend;
PFNGLTEXGENFPROC glTexGenf;
PFNGLTEXGENIPROC glTexGeni;
PFNGLTEXGENDVPROC glTexGendv;
PFNGLTEXGENFVPROC glTexGenfv;
PFNGLTEXGENIVPROC glTexGeniv;
PFNGLGETTEXGENDVPROC glGetTexGendv;
PFNGLGETTEXGENFVPROC glGetTexGenfv;
PFNGLGETTEXGENIVPROC glGetTexGeniv;
PFNGLTEXENVFPROC glTexEnvf;
PFNGLTEXENVIPROC glTexEnvi;
PFNGLTEXENVFVPROC glTexEnvfv;
PFNGLTEXENVIVPROC glTexEnviv;
PFNGLGETTEXENVFVPROC glGetTexEnvfv;
PFNGLGETTEXENVIVPROC glGetTexEnviv;
PFNGLTEXPARAMETERFPROC glTexParameterf;
PFNGLTEXPARAMETERIPROC glTexParameteri;
PFNGLTEXPARAMETERFVPROC glTexParameterfv;
PFNGLTEXPARAMETERIVPROC glTexParameteriv;
PFNGLGETTEXPARAMETERFVPROC glGetTexParameterfv;
PFNGLGETTEXPARAMETERIVPROC glGetTexParameteriv;
PFNGLGETTEXLEVELPARAMETERFVPROC glGetTexLevelParameterfv;
PFNGLGETTEXLEVELPARAMETERIVPROC glGetTexLevelParameteriv;
PFNGLTEXIMAGE1DPROC glTexImage1D;
PFNGLTEXIMAGE2DPROC glTexImage2D;
PFNGLGETTEXIMAGEPROC glGetTexImage;
PFNGLGENTEXTURESPROC glGenTextures;
PFNGLDELETETEXTURESPROC glDeleteTextures;
PFNGLBINDTEXTUREPROC glBindTexture;
PFNGLPRIORITIZETEXTURESPROC glPrioritizeTextures;
PFNGLARETEXTURESRESIDENTPROC glAreTexturesResident;
PFNGLISTEXTUREPROC glIsTexture;
PFNGLTEXSUBIMAGE1DPROC glTexSubImage1D;
PFNGLTEXSUBIMAGE2DPROC glTexSubImage2D;
PFNGLCOPYTEXIMAGE1DPROC glCopyTexImage1D;
PFNGLCOPYTEXIMAGE2DPROC glCopyTexImage2D;
PFNGLCOPYTEXSUBIMAGE1DPROC glCopyTexSubImage1D;
PFNGLCOPYTEXSUBIMAGE2DPROC glCopyTexSubImage2D;
PFNGLMAP1DPROC glMap1d;
PFNGLMAP1FPROC glMap1f;
PFNGLMAP2DPROC glMap2d;
PFNGLMAP2FPROC glMap2f;
PFNGLGETMAPDVPROC glGetMapdv;
PFNGLGETMAPFVPROC glGetMapfv;
PFNGLGETMAPIVPROC glGetMapiv;
PFNGLEVALCOORD1DPROC glEvalCoord1d;
PFNGLEVALCOORD1FPROC glEvalCoord1f;
PFNGLEVALCOORD1DVPROC glEvalCoord1dv;
PFNGLEVALCOORD1FVPROC glEvalCoord1fv;
PFNGLEVALCOORD2DPROC glEvalCoord2d;
PFNGLEVALCOORD2FPROC glEvalCoord2f;
PFNGLEVALCOORD2DVPROC glEvalCoord2dv;
PFNGLEVALCOORD2FVPROC glEvalCoord2fv;
PFNGLMAPGRID1DPROC glMapGrid1d;
PFNGLMAPGRID1FPROC glMapGrid1f;
PFNGLMAPGRID2DPROC glMapGrid2d;
PFNGLMAPGRID2FPROC glMapGrid2f;
PFNGLEVALPOINT1PROC glEvalPoint1;
PFNGLEVALPOINT2PROC glEvalPoint2;
PFNGLEVALMESH1PROC glEvalMesh1;
PFNGLEVALMESH2PROC glEvalMesh2;
PFNGLFOGFPROC glFogf;
PFNGLFOGIPROC glFogi;
PFNGLFOGFVPROC glFogfv;
PFNGLFOGIVPROC glFogiv;
PFNGLFEEDBACKBUFFERPROC glFeedbackBuffer;
PFNGLPASSTHROUGHPROC glPassThrough;
PFNGLSELECTBUFFERPROC glSelectBuffer;
PFNGLINITNAMESPROC glInitNames;
PFNGLLOADNAMEPROC glLoadName;
PFNGLPUSHNAMEPROC glPushName;
PFNGLPOPNAMEPROC glPopName;

// gl_1_2
PFNGLCOPYTEXSUBIMAGE3DPROC glCopyTexSubImage3D;
PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements;
PFNGLTEXIMAGE3DPROC glTexImage3D;
PFNGLTEXSUBIMAGE3DPROC glTexSubImage3D;

// gl_1_3
PFNGLACTIVETEXTUREARBPROC glActiveTexture;
PFNGLCLIENTACTIVETEXTUREARBPROC glClientActiveTexture;
PFNGLCOMPRESSEDTEXIMAGE1DPROC glCompressedTexImage1D;
PFNGLCOMPRESSEDTEXIMAGE2DPROC glCompressedTexImage2D;
PFNGLCOMPRESSEDTEXIMAGE3DPROC glCompressedTexImage3D;
PFNGLCOMPRESSEDTEXSUBIMAGE1DPROC glCompressedTexSubImage1D;
PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC glCompressedTexSubImage2D;
PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC glCompressedTexSubImage3D;
PFNGLGETCOMPRESSEDTEXIMAGEPROC glGetCompressedTexImage;
PFNGLLOADTRANSPOSEMATRIXDARBPROC glLoadTransposeMatrixd;
PFNGLLOADTRANSPOSEMATRIXFARBPROC glLoadTransposeMatrixf;
PFNGLMULTTRANSPOSEMATRIXDARBPROC glMultTransposeMatrixd;
PFNGLMULTTRANSPOSEMATRIXFARBPROC glMultTransposeMatrixf;
PFNGLMULTITEXCOORD1DARBPROC glMultiTexCoord1d;
PFNGLMULTITEXCOORD1DVARBPROC glMultiTexCoord1dv;
PFNGLMULTITEXCOORD1FARBPROC glMultiTexCoord1f;
PFNGLMULTITEXCOORD1FVARBPROC glMultiTexCoord1fv;
PFNGLMULTITEXCOORD1IARBPROC glMultiTexCoord1i;
PFNGLMULTITEXCOORD1IVARBPROC glMultiTexCoord1iv;
PFNGLMULTITEXCOORD1SARBPROC glMultiTexCoord1s;
PFNGLMULTITEXCOORD1SVARBPROC glMultiTexCoord1sv;
PFNGLMULTITEXCOORD2DARBPROC glMultiTexCoord2d;
PFNGLMULTITEXCOORD2DVARBPROC glMultiTexCoord2dv;
PFNGLMULTITEXCOORD2FARBPROC glMultiTexCoord2f;
PFNGLMULTITEXCOORD2FVARBPROC glMultiTexCoord2fv;
PFNGLMULTITEXCOORD2IARBPROC glMultiTexCoord2i;
PFNGLMULTITEXCOORD2IVARBPROC glMultiTexCoord2iv;
PFNGLMULTITEXCOORD2SARBPROC glMultiTexCoord2s;
PFNGLMULTITEXCOORD2SVARBPROC glMultiTexCoord2sv;
PFNGLMULTITEXCOORD3DARBPROC glMultiTexCoord3d;
PFNGLMULTITEXCOORD3DVARBPROC glMultiTexCoord3dv;
PFNGLMULTITEXCOORD3FARBPROC glMultiTexCoord3f;
PFNGLMULTITEXCOORD3FVARBPROC glMultiTexCoord3fv;
PFNGLMULTITEXCOORD3IARBPROC glMultiTexCoord3i;
PFNGLMULTITEXCOORD3IVARBPROC glMultiTexCoord3iv;
PFNGLMULTITEXCOORD3SARBPROC glMultiTexCoord3s;
PFNGLMULTITEXCOORD3SVARBPROC glMultiTexCoord3sv;
PFNGLMULTITEXCOORD4DARBPROC glMultiTexCoord4d;
PFNGLMULTITEXCOORD4DVARBPROC glMultiTexCoord4dv;
PFNGLMULTITEXCOORD4FARBPROC glMultiTexCoord4f;
PFNGLMULTITEXCOORD4FVARBPROC glMultiTexCoord4fv;
PFNGLMULTITEXCOORD4IARBPROC glMultiTexCoord4i;
PFNGLMULTITEXCOORD4IVARBPROC glMultiTexCoord4iv;
PFNGLMULTITEXCOORD4SARBPROC glMultiTexCoord4s;
PFNGLMULTITEXCOORD4SVARBPROC glMultiTexCoord4sv;
PFNGLSAMPLECOVERAGEARBPROC glSampleCoverage;

// gl_1_4
PFNGLBLENDCOLORPROC glBlendColor;
PFNGLBLENDEQUATIONPROC glBlendEquation;
PFNGLBLENDFUNCSEPARATEPROC glBlendFuncSeparate;
PFNGLFOGCOORDPOINTERPROC glFogCoordPointer;
PFNGLFOGCOORDDPROC glFogCoordd;
PFNGLFOGCOORDDVPROC glFogCoorddv;
PFNGLFOGCOORDFPROC glFogCoordf;
PFNGLFOGCOORDFVPROC glFogCoordfv;
PFNGLMULTIDRAWARRAYSPROC glMultiDrawArrays;
PFNGLMULTIDRAWELEMENTSPROC glMultiDrawElements;
PFNGLPOINTPARAMETERFPROC glPointParameterf;
PFNGLPOINTPARAMETERFVPROC glPointParameterfv;
PFNGLPOINTPARAMETERIPROC glPointParameteri;
PFNGLPOINTPARAMETERIVPROC glPointParameteriv;
PFNGLSECONDARYCOLOR3BPROC glSecondaryColor3b;
PFNGLSECONDARYCOLOR3BVPROC glSecondaryColor3bv;
PFNGLSECONDARYCOLOR3DPROC glSecondaryColor3d;
PFNGLSECONDARYCOLOR3DVPROC glSecondaryColor3dv;
PFNGLSECONDARYCOLOR3FPROC glSecondaryColor3f;
PFNGLSECONDARYCOLOR3FVPROC glSecondaryColor3fv;
PFNGLSECONDARYCOLOR3IPROC glSecondaryColor3i;
PFNGLSECONDARYCOLOR3IVPROC glSecondaryColor3iv;
PFNGLSECONDARYCOLOR3SPROC glSecondaryColor3s;
PFNGLSECONDARYCOLOR3SVPROC glSecondaryColor3sv;
PFNGLSECONDARYCOLOR3UBPROC glSecondaryColor3ub;
PFNGLSECONDARYCOLOR3UBVPROC glSecondaryColor3ubv;
PFNGLSECONDARYCOLOR3UIPROC glSecondaryColor3ui;
PFNGLSECONDARYCOLOR3UIVPROC glSecondaryColor3uiv;
PFNGLSECONDARYCOLOR3USPROC glSecondaryColor3us;
PFNGLSECONDARYCOLOR3USVPROC glSecondaryColor3usv;
PFNGLSECONDARYCOLORPOINTERPROC glSecondaryColorPointer;
PFNGLWINDOWPOS2DPROC glWindowPos2d;
PFNGLWINDOWPOS2DVPROC glWindowPos2dv;
PFNGLWINDOWPOS2FPROC glWindowPos2f;
PFNGLWINDOWPOS2FVPROC glWindowPos2fv;
PFNGLWINDOWPOS2IPROC glWindowPos2i;
PFNGLWINDOWPOS2IVPROC glWindowPos2iv;
PFNGLWINDOWPOS2SPROC glWindowPos2s;
PFNGLWINDOWPOS2SVPROC glWindowPos2sv;
PFNGLWINDOWPOS3DPROC glWindowPos3d;
PFNGLWINDOWPOS3DVPROC glWindowPos3dv;
PFNGLWINDOWPOS3FPROC glWindowPos3f;
PFNGLWINDOWPOS3FVPROC glWindowPos3fv;
PFNGLWINDOWPOS3IPROC glWindowPos3i;
PFNGLWINDOWPOS3IVPROC glWindowPos3iv;
PFNGLWINDOWPOS3SPROC glWindowPos3s;
PFNGLWINDOWPOS3SVPROC glWindowPos3sv;

// gl_1_5
PFNGLBEGINQUERYPROC glBeginQuery;
PFNGLBINDBUFFERPROC glBindBuffer;
PFNGLBUFFERDATAPROC glBufferData;
PFNGLBUFFERSUBDATAPROC glBufferSubData;
PFNGLDELETEBUFFERSPROC glDeleteBuffers;
PFNGLDELETEQUERIESPROC glDeleteQueries;
PFNGLENDQUERYPROC glEndQuery;
PFNGLGENBUFFERSPROC glGenBuffers;
PFNGLGENQUERIESPROC glGenQueries;
PFNGLGETBUFFERPARAMETERIVPROC glGetBufferParameteriv;
PFNGLGETBUFFERPOINTERVPROC glGetBufferPointerv;
PFNGLGETBUFFERSUBDATAPROC glGetBufferSubData;
PFNGLGETQUERYOBJECTIVPROC glGetQueryObjectiv;
PFNGLGETQUERYOBJECTUIVPROC glGetQueryObjectuiv;
PFNGLGETQUERYIVPROC glGetQueryiv;
PFNGLISBUFFERPROC glIsBuffer;
PFNGLISQUERYPROC glIsQuery;
PFNGLMAPBUFFERPROC glMapBuffer;
PFNGLUNMAPBUFFERPROC glUnmapBuffer;

// gl_2_0
PFNGLATTACHSHADERPROC glAttachShader;
PFNGLBINDATTRIBLOCATIONPROC glBindAttribLocation;
PFNGLBLENDEQUATIONSEPARATEPROC glBlendEquationSeparate;
PFNGLCOMPILESHADERPROC glCompileShader;
PFNGLCREATEPROGRAMPROC glCreateProgram;
PFNGLCREATESHADERPROC glCreateShader;
PFNGLDELETEPROGRAMPROC glDeleteProgram;
PFNGLDELETESHADERPROC glDeleteShader;
PFNGLDETACHSHADERPROC glDetachShader;
PFNGLDISABLEVERTEXATTRIBARRAYPROC glDisableVertexAttribArray;
PFNGLDRAWBUFFERSPROC glDrawBuffers;
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray;
PFNGLGETACTIVEATTRIBPROC glGetActiveAttrib;
PFNGLGETACTIVEUNIFORMPROC glGetActiveUniform;
PFNGLGETATTACHEDSHADERSPROC glGetAttachedShaders;
PFNGLGETATTRIBLOCATIONPROC glGetAttribLocation;
PFNGLGETPROGRAMINFOLOGPROC glGetProgramInfoLog;
PFNGLGETPROGRAMIVPROC glGetProgramiv;
PFNGLGETSHADERINFOLOGPROC glGetShaderInfoLog;
PFNGLGETSHADERSOURCEPROC glGetShaderSource;
PFNGLGETSHADERIVPROC glGetShaderiv;
PFNGLGETUNIFORMLOCATIONPROC glGetUniformLocation;
PFNGLGETUNIFORMFVPROC glGetUniformfv;
PFNGLGETUNIFORMIVPROC glGetUniformiv;
PFNGLGETVERTEXATTRIBPOINTERVPROC glGetVertexAttribPointerv;
PFNGLGETVERTEXATTRIBDVPROC glGetVertexAttribdv;
PFNGLGETVERTEXATTRIBFVPROC glGetVertexAttribfv;
PFNGLGETVERTEXATTRIBIVPROC glGetVertexAttribiv;
PFNGLISPROGRAMPROC glIsProgram;
PFNGLISSHADERPROC glIsShader;
PFNGLLINKPROGRAMPROC glLinkProgram;
PFNGLSHADERSOURCEPROC glShaderSource;
PFNGLSTENCILFUNCSEPARATEPROC glStencilFuncSeparate;
PFNGLSTENCILMASKSEPARATEPROC glStencilMaskSeparate;
PFNGLSTENCILOPSEPARATEPROC glStencilOpSeparate;
PFNGLUNIFORM1FPROC glUniform1f;
PFNGLUNIFORM1FVPROC glUniform1fv;
PFNGLUNIFORM1IPROC glUniform1i;
PFNGLUNIFORM1IVPROC glUniform1iv;
PFNGLUNIFORM2FPROC glUniform2f;
PFNGLUNIFORM2FVPROC glUniform2fv;
PFNGLUNIFORM2IPROC glUniform2i;
PFNGLUNIFORM2IVPROC glUniform2iv;
PFNGLUNIFORM3FPROC glUniform3f;
PFNGLUNIFORM3FVPROC glUniform3fv;
PFNGLUNIFORM3IPROC glUniform3i;
PFNGLUNIFORM3IVPROC glUniform3iv;
PFNGLUNIFORM4FPROC glUniform4f;
PFNGLUNIFORM4FVPROC glUniform4fv;
PFNGLUNIFORM4IPROC glUniform4i;
PFNGLUNIFORM4IVPROC glUniform4iv;
PFNGLUNIFORMMATRIX2FVPROC glUniformMatrix2fv;
PFNGLUNIFORMMATRIX3FVPROC glUniformMatrix3fv;
PFNGLUNIFORMMATRIX4FVPROC glUniformMatrix4fv;
PFNGLUSEPROGRAMPROC glUseProgram;
PFNGLVALIDATEPROGRAMPROC glValidateProgram;
PFNGLVERTEXATTRIB1DPROC glVertexAttrib1d;
PFNGLVERTEXATTRIB1DVPROC glVertexAttrib1dv;
PFNGLVERTEXATTRIB1FPROC glVertexAttrib1f;
PFNGLVERTEXATTRIB1FVPROC glVertexAttrib1fv;
PFNGLVERTEXATTRIB1SPROC glVertexAttrib1s;
PFNGLVERTEXATTRIB1SVPROC glVertexAttrib1sv;
PFNGLVERTEXATTRIB2DPROC glVertexAttrib2d;
PFNGLVERTEXATTRIB2DVPROC glVertexAttrib2dv;
PFNGLVERTEXATTRIB2FPROC glVertexAttrib2f;
PFNGLVERTEXATTRIB2FVPROC glVertexAttrib2fv;
PFNGLVERTEXATTRIB2SPROC glVertexAttrib2s;
PFNGLVERTEXATTRIB2SVPROC glVertexAttrib2sv;
PFNGLVERTEXATTRIB3DPROC glVertexAttrib3d;
PFNGLVERTEXATTRIB3DVPROC glVertexAttrib3dv;
PFNGLVERTEXATTRIB3FPROC glVertexAttrib3f;
PFNGLVERTEXATTRIB3FVPROC glVertexAttrib3fv;
PFNGLVERTEXATTRIB3SPROC glVertexAttrib3s;
PFNGLVERTEXATTRIB3SVPROC glVertexAttrib3sv;
PFNGLVERTEXATTRIB4NBVPROC glVertexAttrib4Nbv;
PFNGLVERTEXATTRIB4NIVPROC glVertexAttrib4Niv;
PFNGLVERTEXATTRIB4NSVPROC glVertexAttrib4Nsv;
PFNGLVERTEXATTRIB4NUBPROC glVertexAttrib4Nub;
PFNGLVERTEXATTRIB4NUBVPROC glVertexAttrib4Nubv;
PFNGLVERTEXATTRIB4NUIVPROC glVertexAttrib4Nuiv;
PFNGLVERTEXATTRIB4NUSVPROC glVertexAttrib4Nusv;
PFNGLVERTEXATTRIB4BVPROC glVertexAttrib4bv;
PFNGLVERTEXATTRIB4DPROC glVertexAttrib4d;
PFNGLVERTEXATTRIB4DVPROC glVertexAttrib4dv;
PFNGLVERTEXATTRIB4FPROC glVertexAttrib4f;
PFNGLVERTEXATTRIB4FVPROC glVertexAttrib4fv;
PFNGLVERTEXATTRIB4IVPROC glVertexAttrib4iv;
PFNGLVERTEXATTRIB4SPROC glVertexAttrib4s;
PFNGLVERTEXATTRIB4SVPROC glVertexAttrib4sv;
PFNGLVERTEXATTRIB4UBVPROC glVertexAttrib4ubv;
PFNGLVERTEXATTRIB4UIVPROC glVertexAttrib4uiv;
PFNGLVERTEXATTRIB4USVPROC glVertexAttrib4usv;
PFNGLVERTEXATTRIBPOINTERPROC glVertexAttribPointer;

// gl_3_0
PFNGLBEGINCONDITIONALRENDERPROC glBeginConditionalRender;
PFNGLBEGINTRANSFORMFEEDBACKPROC glBeginTransformFeedback;
PFNGLBINDFRAGDATALOCATIONPROC glBindFragDataLocation;
PFNGLCLAMPCOLORPROC glClampColor;
PFNGLCLEARBUFFERFIPROC glClearBufferfi;
PFNGLCLEARBUFFERFVPROC glClearBufferfv;
PFNGLCLEARBUFFERIVPROC glClearBufferiv;
PFNGLCLEARBUFFERUIVPROC glClearBufferuiv;
PFNGLCOLORMASKIPROC glColorMaski;
PFNGLDISABLEIPROC glDisablei;
PFNGLENABLEIPROC glEnablei;
PFNGLENDCONDITIONALRENDERPROC glEndConditionalRender;
PFNGLENDTRANSFORMFEEDBACKPROC glEndTransformFeedback;
PFNGLGETBOOLEANI_VPROC glGetBooleani_v;
PFNGLGETFRAGDATALOCATIONPROC glGetFragDataLocation;
PFNGLGETSTRINGIPROC glGetStringi;
PFNGLGETTEXPARAMETERIIVPROC glGetTexParameterIiv;
PFNGLGETTEXPARAMETERIUIVPROC glGetTexParameterIuiv;
PFNGLGETTRANSFORMFEEDBACKVARYINGPROC glGetTransformFeedbackVarying;
PFNGLGETUNIFORMUIVPROC glGetUniformuiv;
PFNGLGETVERTEXATTRIBIIVPROC glGetVertexAttribIiv;
PFNGLGETVERTEXATTRIBIUIVPROC glGetVertexAttribIuiv;
PFNGLISENABLEDIPROC glIsEnabledi;
PFNGLTEXPARAMETERIIVPROC glTexParameterIiv;
PFNGLTEXPARAMETERIUIVPROC glTexParameterIuiv;
PFNGLTRANSFORMFEEDBACKVARYINGSPROC glTransformFeedbackVaryings;
PFNGLUNIFORM1UIPROC glUniform1ui;
PFNGLUNIFORM1UIVPROC glUniform1uiv;
PFNGLUNIFORM2UIPROC glUniform2ui;
PFNGLUNIFORM2UIVPROC glUniform2uiv;
PFNGLUNIFORM3UIPROC glUniform3ui;
PFNGLUNIFORM3UIVPROC glUniform3uiv;
PFNGLUNIFORM4UIPROC glUniform4ui;
PFNGLUNIFORM4UIVPROC glUniform4uiv;
PFNGLVERTEXATTRIBI1IPROC glVertexAttribI1i;
PFNGLVERTEXATTRIBI1IVPROC glVertexAttribI1iv;
PFNGLVERTEXATTRIBI1UIPROC glVertexAttribI1ui;
PFNGLVERTEXATTRIBI1UIVPROC glVertexAttribI1uiv;
PFNGLVERTEXATTRIBI2IPROC glVertexAttribI2i;
PFNGLVERTEXATTRIBI2IVPROC glVertexAttribI2iv;
PFNGLVERTEXATTRIBI2UIPROC glVertexAttribI2ui;
PFNGLVERTEXATTRIBI2UIVPROC glVertexAttribI2uiv;
PFNGLVERTEXATTRIBI3IPROC glVertexAttribI3i;
PFNGLVERTEXATTRIBI3IVPROC glVertexAttribI3iv;
PFNGLVERTEXATTRIBI3UIPROC glVertexAttribI3ui;
PFNGLVERTEXATTRIBI3UIVPROC glVertexAttribI3uiv;
PFNGLVERTEXATTRIBI4BVPROC glVertexAttribI4bv;
PFNGLVERTEXATTRIBI4IPROC glVertexAttribI4i;
PFNGLVERTEXATTRIBI4IVPROC glVertexAttribI4iv;
PFNGLVERTEXATTRIBI4SVPROC glVertexAttribI4sv;
PFNGLVERTEXATTRIBI4UBVPROC glVertexAttribI4ubv;
PFNGLVERTEXATTRIBI4UIPROC glVertexAttribI4ui;
PFNGLVERTEXATTRIBI4UIVPROC glVertexAttribI4uiv;
PFNGLVERTEXATTRIBI4USVPROC glVertexAttribI4usv;
PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer;

// gl_3_1
PFNGLDRAWARRAYSINSTANCEDPROC glDrawArraysInstanced;
PFNGLDRAWELEMENTSINSTANCEDPROC glDrawElementsInstanced;
PFNGLPRIMITIVERESTARTINDEXPROC glPrimitiveRestartIndex;
PFNGLTEXBUFFERPROC glTexBuffer;

// gl_3_2
PFNGLFRAMEBUFFERTEXTUREPROC glFramebufferTexture;
PFNGLGETBUFFERPARAMETERI64VPROC glGetBufferParameteri64v;
PFNGLGETINTEGER64I_VPROC glGetInteger64i_v;

// ARB_uniform_buffer_object
PFNGLBINDBUFFERBASEPROC glBindBufferBase;
PFNGLBINDBUFFERRANGEPROC glBindBufferRange;
PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC glGetActiveUniformBlockName;
PFNGLGETACTIVEUNIFORMBLOCKIVPROC glGetActiveUniformBlockiv;
PFNGLGETACTIVEUNIFORMNAMEPROC glGetActiveUniformName;
PFNGLGETACTIVEUNIFORMSIVPROC glGetActiveUniformsiv;
PFNGLGETINTEGERI_VPROC glGetIntegeri_v;
PFNGLGETUNIFORMBLOCKINDEXPROC glGetUniformBlockIndex;
PFNGLGETUNIFORMINDICESPROC glGetUniformIndices;
PFNGLUNIFORMBLOCKBINDINGPROC glUniformBlockBinding;

// ARB_sampler_objects
PFNGLBINDSAMPLERPROC glBindSampler;
PFNGLDELETESAMPLERSPROC glDeleteSamplers;
PFNGLGENSAMPLERSPROC glGenSamplers;
PFNGLGETSAMPLERPARAMETERIIVPROC glGetSamplerParameterIiv;
PFNGLGETSAMPLERPARAMETERIUIVPROC glGetSamplerParameterIuiv;
PFNGLGETSAMPLERPARAMETERFVPROC glGetSamplerParameterfv;
PFNGLGETSAMPLERPARAMETERIVPROC glGetSamplerParameteriv;
PFNGLISSAMPLERPROC glIsSampler;
PFNGLSAMPLERPARAMETERIIVPROC glSamplerParameterIiv;
PFNGLSAMPLERPARAMETERIUIVPROC glSamplerParameterIuiv;
PFNGLSAMPLERPARAMETERFPROC glSamplerParameterf;
PFNGLSAMPLERPARAMETERFVPROC glSamplerParameterfv;
PFNGLSAMPLERPARAMETERIPROC glSamplerParameteri;
PFNGLSAMPLERPARAMETERIVPROC glSamplerParameteriv;

// ARB_map_buffer_range
PFNGLFLUSHMAPPEDBUFFERRANGEPROC glFlushMappedBufferRange;
PFNGLMAPBUFFERRANGEPROC glMapBufferRange;

// ARB_vertex_array_object
PFNGLBINDVERTEXARRAYPROC glBindVertexArray;
PFNGLDELETEVERTEXARRAYSPROC glDeleteVertexArrays;
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays;
PFNGLISVERTEXARRAYPROC glIsVertexArray;

// ARB_framebuffer_object
PFNGLBINDFRAMEBUFFERPROC glBindFramebuffer;
PFNGLBINDRENDERBUFFERPROC glBindRenderbuffer;
PFNGLBLITFRAMEBUFFERPROC glBlitFramebuffer;
PFNGLCHECKFRAMEBUFFERSTATUSPROC glCheckFramebufferStatus;
PFNGLDELETEFRAMEBUFFERSPROC glDeleteFramebuffers;
PFNGLDELETERENDERBUFFERSPROC glDeleteRenderbuffers;
PFNGLFRAMEBUFFERRENDERBUFFERPROC glFramebufferRenderbuffer;
PFNGLFRAMEBUFFERTEXTURE1DPROC glFramebufferTexture1D;
PFNGLFRAMEBUFFERTEXTURE2DPROC glFramebufferTexture2D;
PFNGLFRAMEBUFFERTEXTURE3DPROC glFramebufferTexture3D;
PFNGLFRAMEBUFFERTEXTURELAYERPROC glFramebufferTextureLayer;
PFNGLGENFRAMEBUFFERSPROC glGenFramebuffers;
PFNGLGENRENDERBUFFERSPROC glGenRenderbuffers;
PFNGLGENERATEMIPMAPPROC glGenerateMipmap;
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC glGetFramebufferAttachmentParameteriv;
PFNGLGETRENDERBUFFERPARAMETERIVPROC glGetRenderbufferParameteriv;
PFNGLISFRAMEBUFFERPROC glIsFramebuffer;
PFNGLISRENDERBUFFERPROC glIsRenderbuffer;
PFNGLRENDERBUFFERSTORAGEPROC glRenderbufferStorage;
PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC glRenderbufferStorageMultisample;

// ARB_get_program_binary
PFNGLGETPROGRAMBINARYPROC glGetProgramBinary;
PFNGLPROGRAMBINARYPROC glProgramBinary;
PFNGLPROGRAMPARAMETERIPROC glProgramParameteri;

// ARB_sync
PFNGLCLIENTWAITSYNCPROC glClientWaitSync;
PFNGLDELETESYNCPROC glDeleteSync;
PFNGLFENCESYNCPROC glFenceSync;
PFNGLGETINTEGER64VPROC glGetInteger64v;
PFNGLGETSYNCIVPROC glGetSynciv;
PFNGLISSYNCPROC glIsSync;
PFNGLWAITSYNCPROC glWaitSync;

// ARB_texture_multisample
PFNGLTEXIMAGE2DMULTISAMPLEPROC glTexImage2DMultisample;
PFNGLTEXIMAGE3DMULTISAMPLEPROC glTexImage3DMultisample;
PFNGLGETMULTISAMPLEFVPROC glGetMultisamplefv;
PFNGLSAMPLEMASKIPROC glSampleMaski;

// ARB_ES2_compatibility
PFNGLCLEARDEPTHFPROC glClearDepthf;
PFNGLDEPTHRANGEFPROC glDepthRangef;
PFNGLGETSHADERPRECISIONFORMATPROC glGetShaderPrecisionFormat;
PFNGLRELEASESHADERCOMPILERPROC glReleaseShaderCompiler;
PFNGLSHADERBINARYPROC glShaderBinary;

// NV_primitive_restart
PFNGLPRIMITIVERESTARTINDEXNVPROC glPrimitiveRestartIndexNV;
PFNGLPRIMITIVERESTARTNVPROC glPrimitiveRestartNV;

// ARB_blend_func_extended
PFNGLBINDFRAGDATALOCATIONINDEXEDPROC glBindFragDataLocationIndexed;
PFNGLGETFRAGDATAINDEXPROC glGetFragDataIndex;

// ARB_viewport_array
PFNGLDEPTHRANGEARRAYVPROC glDepthRangeArrayv;
PFNGLDEPTHRANGEINDEXEDPROC glDepthRangeIndexed;
PFNGLGETDOUBLEI_VPROC glGetDoublei_v;
PFNGLGETFLOATI_VPROC glGetFloati_v;
PFNGLSCISSORARRAYVPROC glScissorArrayv;
PFNGLSCISSORINDEXEDPROC glScissorIndexed;
PFNGLSCISSORINDEXEDVPROC glScissorIndexedv;
PFNGLVIEWPORTARRAYVPROC glViewportArrayv;
PFNGLVIEWPORTINDEXEDFPROC glViewportIndexedf;
PFNGLVIEWPORTINDEXEDFVPROC glViewportIndexedfv;

// ARB_draw_elements_base_vertex
PFNGLDRAWELEMENTSBASEVERTEXPROC glDrawElementsBaseVertex;
PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC glDrawElementsInstancedBaseVertex;
PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC glDrawRangeElementsBaseVertex;
PFNGLMULTIDRAWELEMENTSBASEVERTEXPROC glMultiDrawElementsBaseVertex;

// ARB_sample_shading
PFNGLMINSAMPLESHADINGARBPROC glMinSampleShadingARB;

// ARB_debug_output
PFNGLDEBUGMESSAGECALLBACKARBPROC glDebugMessageCallbackARB;
PFNGLDEBUGMESSAGECONTROLARBPROC glDebugMessageControlARB;
PFNGLDEBUGMESSAGEINSERTARBPROC glDebugMessageInsertARB;
PFNGLGETDEBUGMESSAGELOGARBPROC glGetDebugMessageLogARB;

// KHR_debug
PFNGLDEBUGMESSAGECALLBACKPROC glDebugMessageCallback;
PFNGLDEBUGMESSAGECONTROLPROC glDebugMessageControl;
PFNGLDEBUGMESSAGEINSERTPROC glDebugMessageInsert;
PFNGLGETDEBUGMESSAGELOGPROC glGetDebugMessageLog;
PFNGLGETOBJECTLABELPROC glGetObjectLabel;
PFNGLGETOBJECTPTRLABELPROC glGetObjectPtrLabel;
PFNGLOBJECTLABELPROC glObjectLabel;
PFNGLOBJECTPTRLABELPROC glObjectPtrLabel;
PFNGLPOPDEBUGGROUPPROC glPopDebugGroup;
PFNGLPUSHDEBUGGROUPPROC glPushDebugGroup;

// ARB_buffer_storage
PFNGLBUFFERSTORAGEPROC glBufferStorage;
PFNGLNAMEDBUFFERSTORAGEEXTPROC glNamedBufferStorageEXT;

// GL_NV_occlusion_query_samples
PFNGLGENOCCLUSIONQUERIESNVPROC glGenOcclusionQueriesNV;
PFNGLDELETEOCCLUSIONQUERIESNVPROC glDeleteOcclusionQueriesNV;
PFNGLISOCCLUSIONQUERYNVPROC glIsOcclusionQueryNV;
PFNGLBEGINOCCLUSIONQUERYNVPROC glBeginOcclusionQueryNV;
PFNGLENDOCCLUSIONQUERYNVPROC glEndOcclusionQueryNV;
PFNGLGETOCCLUSIONQUERYIVNVPROC glGetOcclusionQueryivNV;
PFNGLGETOCCLUSIONQUERYUIVNVPROC glGetOcclusionQueryuivNV;

// Creates a GLFunc object that requires a feature
#define GLFUNC_REQUIRES(x, y) { (void**)&x, #x, y }
// Creates a GLFunc object with a different function suffix
// For when we want to use the same function pointer, but different function name
#define GLFUNC_SUFFIX(x, y, z) { (void**)&x, #x #y, z }
// Creates a GLFunc object that should always be able to get grabbed
// Used for OpenGL functions that should /always/ be provided.
// aka GL 1.1/1.2/1.3/1.4
#define GLFUNC_ALWAYS_REQUIRED(x) { (void**)&x, #x, "" }

struct GLFunc
{
	void** function_ptr;
	const std::string function_name;
	const std::string requirements;
};

const GLFunc gl_function_array[] =
{
	// gl_1_2
	GLFUNC_ALWAYS_REQUIRED(glCopyTexSubImage3D),
	GLFUNC_ALWAYS_REQUIRED(glDrawRangeElements),
	GLFUNC_ALWAYS_REQUIRED(glTexImage3D),
	GLFUNC_ALWAYS_REQUIRED(glTexSubImage3D),

	// gl_1_3
	GLFUNC_ALWAYS_REQUIRED(glActiveTexture),
	GLFUNC_ALWAYS_REQUIRED(glClientActiveTexture),
	GLFUNC_ALWAYS_REQUIRED(glCompressedTexImage1D),
	GLFUNC_ALWAYS_REQUIRED(glCompressedTexImage2D),
	GLFUNC_ALWAYS_REQUIRED(glCompressedTexImage3D),
	GLFUNC_ALWAYS_REQUIRED(glCompressedTexSubImage1D),
	GLFUNC_ALWAYS_REQUIRED(glCompressedTexSubImage2D),
	GLFUNC_ALWAYS_REQUIRED(glCompressedTexSubImage3D),
	GLFUNC_ALWAYS_REQUIRED(glGetCompressedTexImage),
	GLFUNC_ALWAYS_REQUIRED(glLoadTransposeMatrixd),
	GLFUNC_ALWAYS_REQUIRED(glLoadTransposeMatrixf),
	GLFUNC_ALWAYS_REQUIRED(glMultTransposeMatrixd),
	GLFUNC_ALWAYS_REQUIRED(glMultTransposeMatrixf),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1d),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1dv),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1f),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1fv),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1i),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1iv),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1s),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord1sv),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2d),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2dv),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2f),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2fv),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2i),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2iv),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2s),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord2sv),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3d),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3dv),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3f),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3fv),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3i),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3iv),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3s),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord3sv),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4d),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4dv),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4f),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4fv),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4i),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4iv),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4s),
	GLFUNC_ALWAYS_REQUIRED(glMultiTexCoord4sv),
	GLFUNC_ALWAYS_REQUIRED(glSampleCoverage),

	// gl_1_4
	GLFUNC_ALWAYS_REQUIRED(glBlendColor),
	GLFUNC_ALWAYS_REQUIRED(glBlendEquation),
	GLFUNC_ALWAYS_REQUIRED(glBlendFuncSeparate),
	GLFUNC_ALWAYS_REQUIRED(glFogCoordPointer),
	GLFUNC_ALWAYS_REQUIRED(glFogCoordd),
	GLFUNC_ALWAYS_REQUIRED(glFogCoorddv),
	GLFUNC_ALWAYS_REQUIRED(glFogCoordf),
	GLFUNC_ALWAYS_REQUIRED(glFogCoordfv),
	GLFUNC_ALWAYS_REQUIRED(glMultiDrawArrays),
	GLFUNC_ALWAYS_REQUIRED(glMultiDrawElements),
	GLFUNC_ALWAYS_REQUIRED(glPointParameterf),
	GLFUNC_ALWAYS_REQUIRED(glPointParameterfv),
	GLFUNC_ALWAYS_REQUIRED(glPointParameteri),
	GLFUNC_ALWAYS_REQUIRED(glPointParameteriv),
	GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3b),
	GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3bv),
	GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3d),
	GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3dv),
	GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3f),
	GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3fv),
	GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3i),
	GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3iv),
	GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3s),
	GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3sv),
	GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3ub),
	GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3ubv),
	GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3ui),
	GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3uiv),
	GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3us),
	GLFUNC_ALWAYS_REQUIRED(glSecondaryColor3usv),
	GLFUNC_ALWAYS_REQUIRED(glSecondaryColorPointer),
	GLFUNC_ALWAYS_REQUIRED(glWindowPos2d),
	GLFUNC_ALWAYS_REQUIRED(glWindowPos2dv),
	GLFUNC_ALWAYS_REQUIRED(glWindowPos2f),
	GLFUNC_ALWAYS_REQUIRED(glWindowPos2fv),
	GLFUNC_ALWAYS_REQUIRED(glWindowPos2i),
	GLFUNC_ALWAYS_REQUIRED(glWindowPos2iv),
	GLFUNC_ALWAYS_REQUIRED(glWindowPos2s),
	GLFUNC_ALWAYS_REQUIRED(glWindowPos2sv),
	GLFUNC_ALWAYS_REQUIRED(glWindowPos3d),
	GLFUNC_ALWAYS_REQUIRED(glWindowPos3dv),
	GLFUNC_ALWAYS_REQUIRED(glWindowPos3f),
	GLFUNC_ALWAYS_REQUIRED(glWindowPos3fv),
	GLFUNC_ALWAYS_REQUIRED(glWindowPos3i),
	GLFUNC_ALWAYS_REQUIRED(glWindowPos3iv),
	GLFUNC_ALWAYS_REQUIRED(glWindowPos3s),
	GLFUNC_ALWAYS_REQUIRED(glWindowPos3sv),

	// gl_1_5
	GLFUNC_ALWAYS_REQUIRED(glBeginQuery),
	GLFUNC_ALWAYS_REQUIRED(glBindBuffer),
	GLFUNC_ALWAYS_REQUIRED(glBufferData),
	GLFUNC_ALWAYS_REQUIRED(glBufferSubData),
	GLFUNC_ALWAYS_REQUIRED(glDeleteBuffers),
	GLFUNC_ALWAYS_REQUIRED(glDeleteQueries),
	GLFUNC_ALWAYS_REQUIRED(glEndQuery),
	GLFUNC_ALWAYS_REQUIRED(glGenBuffers),
	GLFUNC_ALWAYS_REQUIRED(glGenQueries),
	GLFUNC_ALWAYS_REQUIRED(glGetBufferParameteriv),
	GLFUNC_ALWAYS_REQUIRED(glGetBufferPointerv),
	GLFUNC_ALWAYS_REQUIRED(glGetBufferSubData),
	GLFUNC_ALWAYS_REQUIRED(glGetQueryObjectiv),
	GLFUNC_ALWAYS_REQUIRED(glGetQueryObjectuiv),
	GLFUNC_ALWAYS_REQUIRED(glGetQueryiv),
	GLFUNC_ALWAYS_REQUIRED(glIsBuffer),
	GLFUNC_ALWAYS_REQUIRED(glIsQuery),
	GLFUNC_ALWAYS_REQUIRED(glMapBuffer),
	GLFUNC_ALWAYS_REQUIRED(glUnmapBuffer),

	// gl_2_0
	GLFUNC_ALWAYS_REQUIRED(glAttachShader),
	GLFUNC_ALWAYS_REQUIRED(glBindAttribLocation),
	GLFUNC_ALWAYS_REQUIRED(glBlendEquationSeparate),
	GLFUNC_ALWAYS_REQUIRED(glCompileShader),
	GLFUNC_ALWAYS_REQUIRED(glCreateProgram),
	GLFUNC_ALWAYS_REQUIRED(glCreateShader),
	GLFUNC_ALWAYS_REQUIRED(glDeleteProgram),
	GLFUNC_ALWAYS_REQUIRED(glDeleteShader),
	GLFUNC_ALWAYS_REQUIRED(glDetachShader),
	GLFUNC_ALWAYS_REQUIRED(glDisableVertexAttribArray),
	GLFUNC_ALWAYS_REQUIRED(glDrawBuffers),
	GLFUNC_ALWAYS_REQUIRED(glEnableVertexAttribArray),
	GLFUNC_ALWAYS_REQUIRED(glGetActiveAttrib),
	GLFUNC_ALWAYS_REQUIRED(glGetActiveUniform),
	GLFUNC_ALWAYS_REQUIRED(glGetAttachedShaders),
	GLFUNC_ALWAYS_REQUIRED(glGetAttribLocation),
	GLFUNC_ALWAYS_REQUIRED(glGetProgramInfoLog),
	GLFUNC_ALWAYS_REQUIRED(glGetProgramiv),
	GLFUNC_ALWAYS_REQUIRED(glGetShaderInfoLog),
	GLFUNC_ALWAYS_REQUIRED(glGetShaderSource),
	GLFUNC_ALWAYS_REQUIRED(glGetShaderiv),
	GLFUNC_ALWAYS_REQUIRED(glGetUniformLocation),
	GLFUNC_ALWAYS_REQUIRED(glGetUniformfv),
	GLFUNC_ALWAYS_REQUIRED(glGetUniformiv),
	GLFUNC_ALWAYS_REQUIRED(glGetVertexAttribPointerv),
	GLFUNC_ALWAYS_REQUIRED(glGetVertexAttribdv),
	GLFUNC_ALWAYS_REQUIRED(glGetVertexAttribfv),
	GLFUNC_ALWAYS_REQUIRED(glGetVertexAttribiv),
	GLFUNC_ALWAYS_REQUIRED(glIsProgram),
	GLFUNC_ALWAYS_REQUIRED(glIsShader),
	GLFUNC_ALWAYS_REQUIRED(glLinkProgram),
	GLFUNC_ALWAYS_REQUIRED(glShaderSource),
	GLFUNC_ALWAYS_REQUIRED(glStencilFuncSeparate),
	GLFUNC_ALWAYS_REQUIRED(glStencilMaskSeparate),
	GLFUNC_ALWAYS_REQUIRED(glStencilOpSeparate),
	GLFUNC_ALWAYS_REQUIRED(glUniform1f),
	GLFUNC_ALWAYS_REQUIRED(glUniform1fv),
	GLFUNC_ALWAYS_REQUIRED(glUniform1i),
	GLFUNC_ALWAYS_REQUIRED(glUniform1iv),
	GLFUNC_ALWAYS_REQUIRED(glUniform2f),
	GLFUNC_ALWAYS_REQUIRED(glUniform2fv),
	GLFUNC_ALWAYS_REQUIRED(glUniform2i),
	GLFUNC_ALWAYS_REQUIRED(glUniform2iv),
	GLFUNC_ALWAYS_REQUIRED(glUniform3f),
	GLFUNC_ALWAYS_REQUIRED(glUniform3fv),
	GLFUNC_ALWAYS_REQUIRED(glUniform3i),
	GLFUNC_ALWAYS_REQUIRED(glUniform3iv),
	GLFUNC_ALWAYS_REQUIRED(glUniform4f),
	GLFUNC_ALWAYS_REQUIRED(glUniform4fv),
	GLFUNC_ALWAYS_REQUIRED(glUniform4i),
	GLFUNC_ALWAYS_REQUIRED(glUniform4iv),
	GLFUNC_ALWAYS_REQUIRED(glUniformMatrix2fv),
	GLFUNC_ALWAYS_REQUIRED(glUniformMatrix3fv),
	GLFUNC_ALWAYS_REQUIRED(glUniformMatrix4fv),
	GLFUNC_ALWAYS_REQUIRED(glUseProgram),
	GLFUNC_ALWAYS_REQUIRED(glValidateProgram),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib1d),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib1dv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib1f),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib1fv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib1s),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib1sv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib2d),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib2dv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib2f),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib2fv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib2s),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib2sv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib3d),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib3dv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib3f),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib3fv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib3s),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib3sv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nbv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Niv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nsv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nub),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nubv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nuiv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4Nusv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4bv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4d),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4dv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4f),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4fv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4iv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4s),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4sv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4ubv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4uiv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttrib4usv),
	GLFUNC_ALWAYS_REQUIRED(glVertexAttribPointer),

	// gl_3_0
	GLFUNC_REQUIRES(glBeginConditionalRender,      "VERSION_3_0"),
	GLFUNC_REQUIRES(glBeginTransformFeedback,      "VERSION_3_0"),
	GLFUNC_REQUIRES(glBindFragDataLocation,        "VERSION_3_0"),
	GLFUNC_REQUIRES(glClampColor,                  "VERSION_3_0"),
	GLFUNC_REQUIRES(glClearBufferfi,               "VERSION_3_0"),
	GLFUNC_REQUIRES(glClearBufferfv,               "VERSION_3_0"),
	GLFUNC_REQUIRES(glClearBufferiv,               "VERSION_3_0"),
	GLFUNC_REQUIRES(glClearBufferuiv,              "VERSION_3_0"),
	GLFUNC_REQUIRES(glColorMaski,                  "VERSION_3_0"),
	GLFUNC_REQUIRES(glDisablei,                    "VERSION_3_0"),
	GLFUNC_REQUIRES(glEnablei,                     "VERSION_3_0"),
	GLFUNC_REQUIRES(glEndConditionalRender,        "VERSION_3_0"),
	GLFUNC_REQUIRES(glEndTransformFeedback,        "VERSION_3_0"),
	GLFUNC_REQUIRES(glGetBooleani_v,               "VERSION_3_0"),
	GLFUNC_REQUIRES(glGetFragDataLocation,         "VERSION_3_0"),
	GLFUNC_REQUIRES(glGetStringi,                  "VERSION_3_0"),
	GLFUNC_REQUIRES(glGetTexParameterIiv,          "VERSION_3_0"),
	GLFUNC_REQUIRES(glGetTexParameterIuiv,         "VERSION_3_0"),
	GLFUNC_REQUIRES(glGetTransformFeedbackVarying, "VERSION_3_0"),
	GLFUNC_REQUIRES(glGetUniformuiv,               "VERSION_3_0"),
	GLFUNC_REQUIRES(glGetVertexAttribIiv,          "VERSION_3_0"),
	GLFUNC_REQUIRES(glGetVertexAttribIuiv,         "VERSION_3_0"),
	GLFUNC_REQUIRES(glIsEnabledi,                  "VERSION_3_0"),
	GLFUNC_REQUIRES(glTexParameterIiv,             "VERSION_3_0"),
	GLFUNC_REQUIRES(glTexParameterIuiv,            "VERSION_3_0"),
	GLFUNC_REQUIRES(glTransformFeedbackVaryings,   "VERSION_3_0"),
	GLFUNC_REQUIRES(glUniform1ui,                  "VERSION_3_0"),
	GLFUNC_REQUIRES(glUniform1uiv,                 "VERSION_3_0"),
	GLFUNC_REQUIRES(glUniform2ui,                  "VERSION_3_0"),
	GLFUNC_REQUIRES(glUniform2uiv,                 "VERSION_3_0"),
	GLFUNC_REQUIRES(glUniform3ui,                  "VERSION_3_0"),
	GLFUNC_REQUIRES(glUniform3uiv,                 "VERSION_3_0"),
	GLFUNC_REQUIRES(glUniform4ui,                  "VERSION_3_0"),
	GLFUNC_REQUIRES(glUniform4uiv,                 "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI1i,             "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI1iv,            "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI1ui,            "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI1uiv,           "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI2i,             "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI2iv,            "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI2ui,            "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI2uiv,           "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI3i,             "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI3iv,            "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI3ui,            "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI3uiv,           "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI4bv,            "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI4i,             "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI4iv,            "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI4sv,            "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI4ubv,           "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI4ui,            "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI4uiv,           "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribI4usv,           "VERSION_3_0"),
	GLFUNC_REQUIRES(glVertexAttribIPointer,        "VERSION_3_0"),

	// gl_3_1
	GLFUNC_REQUIRES(glDrawArraysInstanced,   "VERSION_3_1"),
	GLFUNC_REQUIRES(glDrawElementsInstanced, "VERSION_3_1"),
	GLFUNC_REQUIRES(glPrimitiveRestartIndex, "VERSION_3_1"),
	GLFUNC_REQUIRES(glTexBuffer,             "VERSION_3_1"),

	// gl_3_2
	GLFUNC_REQUIRES(glFramebufferTexture,     "VERSION_3_2"),
	GLFUNC_REQUIRES(glGetBufferParameteri64v, "VERSION_3_2"),
	GLFUNC_REQUIRES(glGetInteger64i_v,        "VERSION_3_2"),

	// ARB_uniform_buffer_object
	GLFUNC_REQUIRES(glBindBufferBase,            "GL_ARB_uniform_buffer_object"),
	GLFUNC_REQUIRES(glBindBufferRange,           "GL_ARB_uniform_buffer_object"),
	GLFUNC_REQUIRES(glGetActiveUniformBlockName, "GL_ARB_uniform_buffer_object"),
	GLFUNC_REQUIRES(glGetActiveUniformBlockiv,   "GL_ARB_uniform_buffer_object"),
	GLFUNC_REQUIRES(glGetActiveUniformName,      "GL_ARB_uniform_buffer_object"),
	GLFUNC_REQUIRES(glGetActiveUniformsiv,       "GL_ARB_uniform_buffer_object"),
	GLFUNC_REQUIRES(glGetIntegeri_v,             "GL_ARB_uniform_buffer_object"),
	GLFUNC_REQUIRES(glGetUniformBlockIndex,      "GL_ARB_uniform_buffer_object"),
	GLFUNC_REQUIRES(glGetUniformIndices,         "GL_ARB_uniform_buffer_object"),
	GLFUNC_REQUIRES(glUniformBlockBinding,       "GL_ARB_uniform_buffer_object"),

	// ARB_sampler_objects
	GLFUNC_REQUIRES(glBindSampler,             "GL_ARB_sampler_objects"),
	GLFUNC_REQUIRES(glDeleteSamplers,          "GL_ARB_sampler_objects"),
	GLFUNC_REQUIRES(glGenSamplers,             "GL_ARB_sampler_objects"),
	GLFUNC_REQUIRES(glGetSamplerParameterIiv,  "GL_ARB_sampler_objects"),
	GLFUNC_REQUIRES(glGetSamplerParameterIuiv, "GL_ARB_sampler_objects"),
	GLFUNC_REQUIRES(glGetSamplerParameterfv,   "GL_ARB_sampler_objects"),
	GLFUNC_REQUIRES(glGetSamplerParameteriv,   "GL_ARB_sampler_objects"),
	GLFUNC_REQUIRES(glIsSampler,               "GL_ARB_sampler_objects"),
	GLFUNC_REQUIRES(glSamplerParameterIiv,     "GL_ARB_sampler_objects"),
	GLFUNC_REQUIRES(glSamplerParameterIuiv,    "GL_ARB_sampler_objects"),
	GLFUNC_REQUIRES(glSamplerParameterf,       "GL_ARB_sampler_objects"),
	GLFUNC_REQUIRES(glSamplerParameterfv,      "GL_ARB_sampler_objects"),
	GLFUNC_REQUIRES(glSamplerParameteri,       "GL_ARB_sampler_objects"),
	GLFUNC_REQUIRES(glSamplerParameteriv,      "GL_ARB_sampler_objects"),

	// ARB_map_buffer_range
	GLFUNC_REQUIRES(glFlushMappedBufferRange, "GL_ARB_map_buffer_range"),
	GLFUNC_REQUIRES(glMapBufferRange,         "GL_ARB_map_buffer_range"),

	// ARB_vertex_array_object
	GLFUNC_REQUIRES(glBindVertexArray,    "GL_ARB_vertex_array_object"),
	GLFUNC_REQUIRES(glDeleteVertexArrays, "GL_ARB_vertex_array_object"),
	GLFUNC_REQUIRES(glGenVertexArrays,    "GL_ARB_vertex_array_object"),
	GLFUNC_REQUIRES(glIsVertexArray,      "GL_ARB_vertex_array_object"),

	// APPLE_vertex_array_object
	GLFUNC_SUFFIX(glBindVertexArray,    APPLE, "GL_APPLE_vertex_array_object !GL_ARB_vertex_array_object"),
	GLFUNC_SUFFIX(glDeleteVertexArrays, APPLE, "GL_APPLE_vertex_array_object !GL_ARB_vertex_array_object"),
	GLFUNC_SUFFIX(glGenVertexArrays,    APPLE, "GL_APPLE_vertex_array_object !GL_ARB_vertex_array_object"),
	GLFUNC_SUFFIX(glIsVertexArray,      APPLE, "GL_APPLE_vertex_array_object !GL_ARB_vertex_array_object"),

	// ARB_framebuffer_object
	GLFUNC_REQUIRES(glBindFramebuffer,                     "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glBindRenderbuffer,                    "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glBlitFramebuffer,                     "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glCheckFramebufferStatus,              "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glDeleteFramebuffers,                  "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glDeleteRenderbuffers,                 "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glFramebufferRenderbuffer,             "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glFramebufferTexture1D,                "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glFramebufferTexture2D,                "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glFramebufferTexture3D,                "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glFramebufferTextureLayer,             "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glGenFramebuffers,                     "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glGenRenderbuffers,                    "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glGenerateMipmap,                      "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glGetFramebufferAttachmentParameteriv, "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glGetRenderbufferParameteriv,          "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glIsFramebuffer,                       "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glIsRenderbuffer,                      "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glRenderbufferStorage,                 "GL_ARB_framebuffer_object"),
	GLFUNC_REQUIRES(glRenderbufferStorageMultisample,      "GL_ARB_framebuffer_object"),

	// ARB_get_program_binary
	GLFUNC_REQUIRES(glGetProgramBinary,  "GL_ARB_get_program_binary"),
	GLFUNC_REQUIRES(glProgramBinary,     "GL_ARB_get_program_binary"),
	GLFUNC_REQUIRES(glProgramParameteri, "GL_ARB_get_program_binary"),

	// ARB_sync
	GLFUNC_REQUIRES(glClientWaitSync, "GL_ARB_sync"),
	GLFUNC_REQUIRES(glDeleteSync,     "GL_ARB_sync"),
	GLFUNC_REQUIRES(glFenceSync,      "GL_ARB_sync"),
	GLFUNC_REQUIRES(glGetInteger64v,  "GL_ARB_sync"),
	GLFUNC_REQUIRES(glGetSynciv,      "GL_ARB_sync"),
	GLFUNC_REQUIRES(glIsSync,         "GL_ARB_sync"),
	GLFUNC_REQUIRES(glWaitSync,       "GL_ARB_sync"),

	// ARB_texture_multisample
	GLFUNC_REQUIRES(glTexImage2DMultisample, "GL_ARB_texture_multisample"),
	GLFUNC_REQUIRES(glTexImage3DMultisample, "GL_ARB_texture_multisample"),
	GLFUNC_REQUIRES(glGetMultisamplefv,      "GL_ARB_texture_multisample"),
	GLFUNC_REQUIRES(glSampleMaski,           "GL_ARB_texture_multisample"),

	// ARB_ES2_compatibility
	GLFUNC_REQUIRES(glClearDepthf,              "GL_ARB_ES2_compatibility"),
	GLFUNC_REQUIRES(glDepthRangef,              "GL_ARB_ES2_compatibility"),
	GLFUNC_REQUIRES(glGetShaderPrecisionFormat, "GL_ARB_ES2_compatibility"),
	GLFUNC_REQUIRES(glReleaseShaderCompiler,    "GL_ARB_ES2_compatibility"),
	GLFUNC_REQUIRES(glShaderBinary,             "GL_ARB_ES2_compatibility"),

	// NV_primitive_restart
	GLFUNC_REQUIRES(glPrimitiveRestartIndexNV, "GL_NV_primitive_restart"),
	GLFUNC_REQUIRES(glPrimitiveRestartNV,      "GL_NV_primitive_restart"),

	// ARB_blend_func_extended
	GLFUNC_REQUIRES(glBindFragDataLocationIndexed, "GL_ARB_blend_func_extended"),
	GLFUNC_REQUIRES(glGetFragDataIndex,            "GL_ARB_blend_func_extended"),

	// ARB_viewport_array
	GLFUNC_REQUIRES(glDepthRangeArrayv,  "GL_ARB_viewport_array"),
	GLFUNC_REQUIRES(glDepthRangeIndexed, "GL_ARB_viewport_array"),
	GLFUNC_REQUIRES(glGetDoublei_v,      "GL_ARB_viewport_array"),
	GLFUNC_REQUIRES(glGetFloati_v,       "GL_ARB_viewport_array"),
	GLFUNC_REQUIRES(glScissorArrayv,     "GL_ARB_viewport_array"),
	GLFUNC_REQUIRES(glScissorIndexed,    "GL_ARB_viewport_array"),
	GLFUNC_REQUIRES(glScissorIndexedv,   "GL_ARB_viewport_array"),
	GLFUNC_REQUIRES(glViewportArrayv,    "GL_ARB_viewport_array"),
	GLFUNC_REQUIRES(glViewportIndexedf,  "GL_ARB_viewport_array"),
	GLFUNC_REQUIRES(glViewportIndexedfv, "GL_ARB_viewport_array"),

	// ARB_draw_elements_base_vertex
	GLFUNC_REQUIRES(glDrawElementsBaseVertex,          "GL_ARB_draw_elements_base_vertex"),
	GLFUNC_REQUIRES(glDrawElementsInstancedBaseVertex, "GL_ARB_draw_elements_base_vertex"),
	GLFUNC_REQUIRES(glDrawRangeElementsBaseVertex,     "GL_ARB_draw_elements_base_vertex"),
	GLFUNC_REQUIRES(glMultiDrawElementsBaseVertex,     "GL_ARB_draw_elements_base_vertex"),

	// OES_draw_elements_base_vertex
	GLFUNC_SUFFIX(glDrawElementsBaseVertex,          OES, "GL_OES_draw_elements_base_vertex !GL_ARB_draw_elements_base_vertex"),
	GLFUNC_SUFFIX(glDrawElementsInstancedBaseVertex, OES, "GL_OES_draw_elements_base_vertex VERSION_GLES3 !GL_ARB_draw_elements_base_vertex"),
	GLFUNC_SUFFIX(glDrawRangeElementsBaseVertex,     OES, "GL_OES_draw_elements_base_vertex VERSION_GLES3 !GL_ARB_draw_elements_base_vertex"),
	GLFUNC_SUFFIX(glMultiDrawElementsBaseVertex,     OES, "GL_OES_draw_elements_base_vertex GL_EXT_multi_draw_arrays !GL_ARB_draw_elements_base_vertex"),

	// EXT_draw_elements_base_vertex
	GLFUNC_SUFFIX(glDrawElementsBaseVertex,          EXT, "GL_EXT_draw_elements_base_vertex !GL_OES_draw_elements_base_vertex !GL_ARB_draw_elements_base_vertex"),
	GLFUNC_SUFFIX(glDrawElementsInstancedBaseVertex, EXT, "GL_EXT_draw_elements_base_vertex VERSION_GLES3 !GL_OES_draw_elements_base_vertex !GL_ARB_draw_elements_base_vertex"),
	GLFUNC_SUFFIX(glDrawRangeElementsBaseVertex,     EXT, "GL_EXT_draw_elements_base_vertex VERSION_GLES3 !GL_OES_draw_elements_base_vertex !GL_ARB_draw_elements_base_vertex"),
	GLFUNC_SUFFIX(glMultiDrawElementsBaseVertex,     EXT, "GL_EXT_draw_elements_base_vertex GL_EXT_multi_draw_arrays !GL_OES_draw_elements_base_vertex !GL_ARB_draw_elements_base_vertex"),

	// ARB_sample_shading
	GLFUNC_REQUIRES(glMinSampleShadingARB, "GL_ARB_sample_shading"),

	// ARB_debug_output
	GLFUNC_REQUIRES(glDebugMessageCallbackARB, "GL_ARB_debug_output"),
	GLFUNC_REQUIRES(glDebugMessageControlARB,  "GL_ARB_debug_output"),
	GLFUNC_REQUIRES(glDebugMessageInsertARB,   "GL_ARB_debug_output"),
	GLFUNC_REQUIRES(glGetDebugMessageLogARB,   "GL_ARB_debug_output"),

	// KHR_debug
	GLFUNC_SUFFIX(glDebugMessageCallback, KHR, "GL_KHR_debug VERSION_GLES3"),
	GLFUNC_SUFFIX(glDebugMessageControl,  KHR, "GL_KHR_debug VERSION_GLES3"),
	GLFUNC_SUFFIX(glDebugMessageInsert,   KHR, "GL_KHR_debug VERSION_GLES3"),
	GLFUNC_SUFFIX(glGetDebugMessageLog,   KHR, "GL_KHR_debug VERSION_GLES3"),
	GLFUNC_SUFFIX(glGetObjectLabel,       KHR, "GL_KHR_debug VERSION_GLES3"),
	GLFUNC_SUFFIX(glGetObjectPtrLabel,    KHR, "GL_KHR_debug VERSION_GLES3"),
	GLFUNC_SUFFIX(glObjectLabel,          KHR, "GL_KHR_debug VERSION_GLES3"),
	GLFUNC_SUFFIX(glObjectPtrLabel,       KHR, "GL_KHR_debug VERSION_GLES3"),
	GLFUNC_SUFFIX(glPopDebugGroup,        KHR, "GL_KHR_debug VERSION_GLES3"),
	GLFUNC_SUFFIX(glPushDebugGroup,       KHR, "GL_KHR_debug VERSION_GLES3"),
	GLFUNC_REQUIRES(glDebugMessageCallback, "GL_KHR_debug !VERSION_GLES3"),
	GLFUNC_REQUIRES(glDebugMessageControl,  "GL_KHR_debug !VERSION_GLES3"),
	GLFUNC_REQUIRES(glDebugMessageInsert,   "GL_KHR_debug !VERSION_GLES3"),
	GLFUNC_REQUIRES(glGetDebugMessageLog,   "GL_KHR_debug !VERSION_GLES3"),
	GLFUNC_REQUIRES(glGetObjectLabel,       "GL_KHR_debug !VERSION_GLES3"),
	GLFUNC_REQUIRES(glGetObjectPtrLabel,    "GL_KHR_debug !VERSION_GLES3"),
	GLFUNC_REQUIRES(glObjectLabel,          "GL_KHR_debug !VERSION_GLES3"),
	GLFUNC_REQUIRES(glObjectPtrLabel,       "GL_KHR_debug !VERSION_GLES3"),
	GLFUNC_REQUIRES(glPopDebugGroup,        "GL_KHR_debug !VERSION_GLES3"),
	GLFUNC_REQUIRES(glPushDebugGroup,       "GL_KHR_debug !VERSION_GLES3"),

	// ARB_buffer_storage
	GLFUNC_REQUIRES(glBufferStorage,         "GL_ARB_buffer_storage"),
	GLFUNC_REQUIRES(glNamedBufferStorageEXT, "GL_ARB_buffer_storage GL_EXT_direct_state_access"),

	// EXT_buffer_storage
	GLFUNC_SUFFIX(glBufferStorage, EXT, "GL_EXT_buffer_storage !GL_ARB_buffer_storage"),

	// EXT_geometry_shader
	GLFUNC_SUFFIX(glFramebufferTexture, EXT, "GL_EXT_geometry_shader !VERSION_3_2"),

	// NV_occlusion_query_samples
	GLFUNC_REQUIRES(glGenOcclusionQueriesNV,    "GL_NV_occlusion_query_samples"),
	GLFUNC_REQUIRES(glDeleteOcclusionQueriesNV, "GL_NV_occlusion_query_samples"),
	GLFUNC_REQUIRES(glIsOcclusionQueryNV,       "GL_NV_occlusion_query_samples"),
	GLFUNC_REQUIRES(glBeginOcclusionQueryNV,    "GL_NV_occlusion_query_samples"),
	GLFUNC_REQUIRES(glEndOcclusionQueryNV,      "GL_NV_occlusion_query_samples"),
	GLFUNC_REQUIRES(glGetOcclusionQueryivNV,    "GL_NV_occlusion_query_samples"),
	GLFUNC_REQUIRES(glGetOcclusionQueryuivNV,   "GL_NV_occlusion_query_samples"),

	// gl_1_1
	// OpenGL 1.1 is at the end due to a bug in Android's EGL stack.
	// eglGetProcAddress can only return a finite amount of function pointers
	// To work around the issue put GL 1.1 function pointers at the end of the list
	// We don't use many from GL 1.1, so we don't have the chance of hitting a null pointer
	// For more information about Android's failing EGL stack, look at the Android issue report
	// https://code.google.com/p/android/issues/detail?id=80882
	GLFUNC_ALWAYS_REQUIRED(glClearIndex),
	GLFUNC_ALWAYS_REQUIRED(glClearColor),
	GLFUNC_ALWAYS_REQUIRED(glClear),
	GLFUNC_ALWAYS_REQUIRED(glIndexMask),
	GLFUNC_ALWAYS_REQUIRED(glColorMask),
	GLFUNC_ALWAYS_REQUIRED(glAlphaFunc),
	GLFUNC_ALWAYS_REQUIRED(glBlendFunc),
	GLFUNC_ALWAYS_REQUIRED(glLogicOp),
	GLFUNC_ALWAYS_REQUIRED(glCullFace),
	GLFUNC_ALWAYS_REQUIRED(glFrontFace),
	GLFUNC_ALWAYS_REQUIRED(glPointSize),
	GLFUNC_ALWAYS_REQUIRED(glLineWidth),
	GLFUNC_ALWAYS_REQUIRED(glLineStipple),
	GLFUNC_ALWAYS_REQUIRED(glPolygonMode),
	GLFUNC_ALWAYS_REQUIRED(glPolygonOffset),
	GLFUNC_ALWAYS_REQUIRED(glPolygonStipple),
	GLFUNC_ALWAYS_REQUIRED(glGetPolygonStipple),
	GLFUNC_ALWAYS_REQUIRED(glEdgeFlag),
	GLFUNC_ALWAYS_REQUIRED(glEdgeFlagv),
	GLFUNC_ALWAYS_REQUIRED(glScissor),
	GLFUNC_ALWAYS_REQUIRED(glClipPlane),
	GLFUNC_ALWAYS_REQUIRED(glGetClipPlane),
	GLFUNC_ALWAYS_REQUIRED(glDrawBuffer),
	GLFUNC_ALWAYS_REQUIRED(glReadBuffer),
	GLFUNC_ALWAYS_REQUIRED(glEnable),
	GLFUNC_ALWAYS_REQUIRED(glDisable),
	GLFUNC_ALWAYS_REQUIRED(glIsEnabled),
	GLFUNC_ALWAYS_REQUIRED(glEnableClientState),
	GLFUNC_ALWAYS_REQUIRED(glDisableClientState),
	GLFUNC_ALWAYS_REQUIRED(glGetBooleanv),
	GLFUNC_ALWAYS_REQUIRED(glGetDoublev),
	GLFUNC_ALWAYS_REQUIRED(glGetFloatv),
	GLFUNC_ALWAYS_REQUIRED(glPushAttrib),
	GLFUNC_ALWAYS_REQUIRED(glPopAttrib),
	GLFUNC_ALWAYS_REQUIRED(glPushClientAttrib),
	GLFUNC_ALWAYS_REQUIRED(glPopClientAttrib),
	GLFUNC_ALWAYS_REQUIRED(glRenderMode),
	GLFUNC_ALWAYS_REQUIRED(glFinish),
	GLFUNC_ALWAYS_REQUIRED(glFlush),
	GLFUNC_ALWAYS_REQUIRED(glHint),
	GLFUNC_ALWAYS_REQUIRED(glClearDepth),
	GLFUNC_ALWAYS_REQUIRED(glDepthFunc),
	GLFUNC_ALWAYS_REQUIRED(glDepthMask),
	GLFUNC_ALWAYS_REQUIRED(glDepthRange),
	GLFUNC_ALWAYS_REQUIRED(glClearAccum),
	GLFUNC_ALWAYS_REQUIRED(glAccum),
	GLFUNC_ALWAYS_REQUIRED(glMatrixMode),
	GLFUNC_ALWAYS_REQUIRED(glOrtho),
	GLFUNC_ALWAYS_REQUIRED(glFrustum),
	GLFUNC_ALWAYS_REQUIRED(glViewport),
	GLFUNC_ALWAYS_REQUIRED(glPushMatrix),
	GLFUNC_ALWAYS_REQUIRED(glPopMatrix),
	GLFUNC_ALWAYS_REQUIRED(glLoadIdentity),
	GLFUNC_ALWAYS_REQUIRED(glLoadMatrixd),
	GLFUNC_ALWAYS_REQUIRED(glLoadMatrixf),
	GLFUNC_ALWAYS_REQUIRED(glMultMatrixd),
	GLFUNC_ALWAYS_REQUIRED(glMultMatrixf),
	GLFUNC_ALWAYS_REQUIRED(glRotated),
	GLFUNC_ALWAYS_REQUIRED(glRotatef),
	GLFUNC_ALWAYS_REQUIRED(glScaled),
	GLFUNC_ALWAYS_REQUIRED(glScalef),
	GLFUNC_ALWAYS_REQUIRED(glTranslated),
	GLFUNC_ALWAYS_REQUIRED(glTranslatef),
	GLFUNC_ALWAYS_REQUIRED(glIsList),
	GLFUNC_ALWAYS_REQUIRED(glDeleteLists),
	GLFUNC_ALWAYS_REQUIRED(glGenLists),
	GLFUNC_ALWAYS_REQUIRED(glNewList),
	GLFUNC_ALWAYS_REQUIRED(glEndList),
	GLFUNC_ALWAYS_REQUIRED(glCallList),
	GLFUNC_ALWAYS_REQUIRED(glCallLists),
	GLFUNC_ALWAYS_REQUIRED(glListBase),
	GLFUNC_ALWAYS_REQUIRED(glBegin),
	GLFUNC_ALWAYS_REQUIRED(glEnd),
	GLFUNC_ALWAYS_REQUIRED(glVertex2d),
	GLFUNC_ALWAYS_REQUIRED(glVertex2f),
	GLFUNC_ALWAYS_REQUIRED(glVertex2i),
	GLFUNC_ALWAYS_REQUIRED(glVertex2s),
	GLFUNC_ALWAYS_REQUIRED(glVertex3d),
	GLFUNC_ALWAYS_REQUIRED(glVertex3f),
	GLFUNC_ALWAYS_REQUIRED(glVertex3i),
	GLFUNC_ALWAYS_REQUIRED(glVertex3s),
	GLFUNC_ALWAYS_REQUIRED(glVertex4d),
	GLFUNC_ALWAYS_REQUIRED(glVertex4f),
	GLFUNC_ALWAYS_REQUIRED(glVertex4i),
	GLFUNC_ALWAYS_REQUIRED(glVertex4s),
	GLFUNC_ALWAYS_REQUIRED(glVertex2dv),
	GLFUNC_ALWAYS_REQUIRED(glVertex2fv),
	GLFUNC_ALWAYS_REQUIRED(glVertex2iv),
	GLFUNC_ALWAYS_REQUIRED(glVertex2sv),
	GLFUNC_ALWAYS_REQUIRED(glVertex3dv),
	GLFUNC_ALWAYS_REQUIRED(glVertex3fv),
	GLFUNC_ALWAYS_REQUIRED(glVertex3iv),
	GLFUNC_ALWAYS_REQUIRED(glVertex3sv),
	GLFUNC_ALWAYS_REQUIRED(glVertex4dv),
	GLFUNC_ALWAYS_REQUIRED(glVertex4fv),
	GLFUNC_ALWAYS_REQUIRED(glVertex4iv),
	GLFUNC_ALWAYS_REQUIRED(glVertex4sv),
	GLFUNC_ALWAYS_REQUIRED(glNormal3b),
	GLFUNC_ALWAYS_REQUIRED(glNormal3d),
	GLFUNC_ALWAYS_REQUIRED(glNormal3f),
	GLFUNC_ALWAYS_REQUIRED(glNormal3i),
	GLFUNC_ALWAYS_REQUIRED(glNormal3s),
	GLFUNC_ALWAYS_REQUIRED(glNormal3bv),
	GLFUNC_ALWAYS_REQUIRED(glNormal3dv),
	GLFUNC_ALWAYS_REQUIRED(glNormal3fv),
	GLFUNC_ALWAYS_REQUIRED(glNormal3iv),
	GLFUNC_ALWAYS_REQUIRED(glNormal3sv),
	GLFUNC_ALWAYS_REQUIRED(glIndexd),
	GLFUNC_ALWAYS_REQUIRED(glIndexf),
	GLFUNC_ALWAYS_REQUIRED(glIndexi),
	GLFUNC_ALWAYS_REQUIRED(glIndexs),
	GLFUNC_ALWAYS_REQUIRED(glIndexub),
	GLFUNC_ALWAYS_REQUIRED(glIndexdv),
	GLFUNC_ALWAYS_REQUIRED(glIndexfv),
	GLFUNC_ALWAYS_REQUIRED(glIndexiv),
	GLFUNC_ALWAYS_REQUIRED(glIndexsv),
	GLFUNC_ALWAYS_REQUIRED(glIndexubv),
	GLFUNC_ALWAYS_REQUIRED(glColor3b),
	GLFUNC_ALWAYS_REQUIRED(glColor3d),
	GLFUNC_ALWAYS_REQUIRED(glColor3f),
	GLFUNC_ALWAYS_REQUIRED(glColor3i),
	GLFUNC_ALWAYS_REQUIRED(glColor3s),
	GLFUNC_ALWAYS_REQUIRED(glColor3ub),
	GLFUNC_ALWAYS_REQUIRED(glColor3ui),
	GLFUNC_ALWAYS_REQUIRED(glColor3us),
	GLFUNC_ALWAYS_REQUIRED(glColor4b),
	GLFUNC_ALWAYS_REQUIRED(glColor4d),
	GLFUNC_ALWAYS_REQUIRED(glColor4f),
	GLFUNC_ALWAYS_REQUIRED(glColor4i),
	GLFUNC_ALWAYS_REQUIRED(glColor4s),
	GLFUNC_ALWAYS_REQUIRED(glColor4ub),
	GLFUNC_ALWAYS_REQUIRED(glColor4ui),
	GLFUNC_ALWAYS_REQUIRED(glColor4us),
	GLFUNC_ALWAYS_REQUIRED(glColor3bv),
	GLFUNC_ALWAYS_REQUIRED(glColor3dv),
	GLFUNC_ALWAYS_REQUIRED(glColor3fv),
	GLFUNC_ALWAYS_REQUIRED(glColor3iv),
	GLFUNC_ALWAYS_REQUIRED(glColor3sv),
	GLFUNC_ALWAYS_REQUIRED(glColor3ubv),
	GLFUNC_ALWAYS_REQUIRED(glColor3uiv),
	GLFUNC_ALWAYS_REQUIRED(glColor3usv),
	GLFUNC_ALWAYS_REQUIRED(glColor4bv),
	GLFUNC_ALWAYS_REQUIRED(glColor4dv),
	GLFUNC_ALWAYS_REQUIRED(glColor4fv),
	GLFUNC_ALWAYS_REQUIRED(glColor4iv),
	GLFUNC_ALWAYS_REQUIRED(glColor4sv),
	GLFUNC_ALWAYS_REQUIRED(glColor4ubv),
	GLFUNC_ALWAYS_REQUIRED(glColor4uiv),
	GLFUNC_ALWAYS_REQUIRED(glColor4usv),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord1d),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord1f),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord1i),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord1s),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord2d),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord2f),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord2i),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord2s),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord3d),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord3f),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord3i),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord3s),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord4d),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord4f),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord4i),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord4s),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord1dv),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord1fv),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord1iv),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord1sv),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord2dv),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord2fv),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord2iv),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord2sv),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord3dv),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord3fv),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord3iv),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord3sv),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord4dv),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord4fv),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord4iv),
	GLFUNC_ALWAYS_REQUIRED(glTexCoord4sv),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos2d),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos2f),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos2i),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos2s),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos3d),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos3f),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos3i),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos3s),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos4d),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos4f),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos4i),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos4s),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos2dv),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos2fv),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos2iv),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos2sv),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos3dv),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos3fv),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos3iv),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos3sv),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos4dv),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos4fv),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos4iv),
	GLFUNC_ALWAYS_REQUIRED(glRasterPos4sv),
	GLFUNC_ALWAYS_REQUIRED(glRectd),
	GLFUNC_ALWAYS_REQUIRED(glRectf),
	GLFUNC_ALWAYS_REQUIRED(glRecti),
	GLFUNC_ALWAYS_REQUIRED(glRects),
	GLFUNC_ALWAYS_REQUIRED(glRectdv),
	GLFUNC_ALWAYS_REQUIRED(glRectfv),
	GLFUNC_ALWAYS_REQUIRED(glRectiv),
	GLFUNC_ALWAYS_REQUIRED(glRectsv),
	GLFUNC_ALWAYS_REQUIRED(glVertexPointer),
	GLFUNC_ALWAYS_REQUIRED(glNormalPointer),
	GLFUNC_ALWAYS_REQUIRED(glColorPointer),
	GLFUNC_ALWAYS_REQUIRED(glIndexPointer),
	GLFUNC_ALWAYS_REQUIRED(glTexCoordPointer),
	GLFUNC_ALWAYS_REQUIRED(glEdgeFlagPointer),
	GLFUNC_ALWAYS_REQUIRED(glGetPointerv),
	GLFUNC_ALWAYS_REQUIRED(glArrayElement),
	GLFUNC_ALWAYS_REQUIRED(glDrawArrays),
	GLFUNC_ALWAYS_REQUIRED(glDrawElements),
	GLFUNC_ALWAYS_REQUIRED(glInterleavedArrays),
	GLFUNC_ALWAYS_REQUIRED(glShadeModel),
	GLFUNC_ALWAYS_REQUIRED(glLightf),
	GLFUNC_ALWAYS_REQUIRED(glLighti),
	GLFUNC_ALWAYS_REQUIRED(glLightfv),
	GLFUNC_ALWAYS_REQUIRED(glLightiv),
	GLFUNC_ALWAYS_REQUIRED(glGetLightfv),
	GLFUNC_ALWAYS_REQUIRED(glGetLightiv),
	GLFUNC_ALWAYS_REQUIRED(glLightModelf),
	GLFUNC_ALWAYS_REQUIRED(glLightModeli),
	GLFUNC_ALWAYS_REQUIRED(glLightModelfv),
	GLFUNC_ALWAYS_REQUIRED(glLightModeliv),
	GLFUNC_ALWAYS_REQUIRED(glMaterialf),
	GLFUNC_ALWAYS_REQUIRED(glMateriali),
	GLFUNC_ALWAYS_REQUIRED(glMaterialfv),
	GLFUNC_ALWAYS_REQUIRED(glMaterialiv),
	GLFUNC_ALWAYS_REQUIRED(glGetMaterialfv),
	GLFUNC_ALWAYS_REQUIRED(glGetMaterialiv),
	GLFUNC_ALWAYS_REQUIRED(glColorMaterial),
	GLFUNC_ALWAYS_REQUIRED(glPixelZoom),
	GLFUNC_ALWAYS_REQUIRED(glPixelStoref),
	GLFUNC_ALWAYS_REQUIRED(glPixelStorei),
	GLFUNC_ALWAYS_REQUIRED(glPixelTransferf),
	GLFUNC_ALWAYS_REQUIRED(glPixelTransferi),
	GLFUNC_ALWAYS_REQUIRED(glPixelMapfv),
	GLFUNC_ALWAYS_REQUIRED(glPixelMapuiv),
	GLFUNC_ALWAYS_REQUIRED(glPixelMapusv),
	GLFUNC_ALWAYS_REQUIRED(glGetPixelMapfv),
	GLFUNC_ALWAYS_REQUIRED(glGetPixelMapuiv),
	GLFUNC_ALWAYS_REQUIRED(glGetPixelMapusv),
	GLFUNC_ALWAYS_REQUIRED(glBitmap),
	GLFUNC_ALWAYS_REQUIRED(glReadPixels),
	GLFUNC_ALWAYS_REQUIRED(glDrawPixels),
	GLFUNC_ALWAYS_REQUIRED(glCopyPixels),
	GLFUNC_ALWAYS_REQUIRED(glStencilFunc),
	GLFUNC_ALWAYS_REQUIRED(glStencilMask),
	GLFUNC_ALWAYS_REQUIRED(glStencilOp),
	GLFUNC_ALWAYS_REQUIRED(glClearStencil),
	GLFUNC_ALWAYS_REQUIRED(glTexGend),
	GLFUNC_ALWAYS_REQUIRED(glTexGenf),
	GLFUNC_ALWAYS_REQUIRED(glTexGeni),
	GLFUNC_ALWAYS_REQUIRED(glTexGendv),
	GLFUNC_ALWAYS_REQUIRED(glTexGenfv),
	GLFUNC_ALWAYS_REQUIRED(glTexGeniv),
	GLFUNC_ALWAYS_REQUIRED(glGetTexGendv),
	GLFUNC_ALWAYS_REQUIRED(glGetTexGenfv),
	GLFUNC_ALWAYS_REQUIRED(glGetTexGeniv),
	GLFUNC_ALWAYS_REQUIRED(glTexEnvf),
	GLFUNC_ALWAYS_REQUIRED(glTexEnvi),
	GLFUNC_ALWAYS_REQUIRED(glTexEnvfv),
	GLFUNC_ALWAYS_REQUIRED(glTexEnviv),
	GLFUNC_ALWAYS_REQUIRED(glGetTexEnvfv),
	GLFUNC_ALWAYS_REQUIRED(glGetTexEnviv),
	GLFUNC_ALWAYS_REQUIRED(glTexParameterf),
	GLFUNC_ALWAYS_REQUIRED(glTexParameteri),
	GLFUNC_ALWAYS_REQUIRED(glTexParameterfv),
	GLFUNC_ALWAYS_REQUIRED(glTexParameteriv),
	GLFUNC_ALWAYS_REQUIRED(glGetTexParameterfv),
	GLFUNC_ALWAYS_REQUIRED(glGetTexParameteriv),
	GLFUNC_ALWAYS_REQUIRED(glGetTexLevelParameterfv),
	GLFUNC_ALWAYS_REQUIRED(glGetTexLevelParameteriv),
	GLFUNC_ALWAYS_REQUIRED(glTexImage1D),
	GLFUNC_ALWAYS_REQUIRED(glTexImage2D),
	GLFUNC_ALWAYS_REQUIRED(glGetTexImage),
	GLFUNC_ALWAYS_REQUIRED(glGenTextures),
	GLFUNC_ALWAYS_REQUIRED(glDeleteTextures),
	GLFUNC_ALWAYS_REQUIRED(glBindTexture),
	GLFUNC_ALWAYS_REQUIRED(glPrioritizeTextures),
	GLFUNC_ALWAYS_REQUIRED(glAreTexturesResident),
	GLFUNC_ALWAYS_REQUIRED(glIsTexture),
	GLFUNC_ALWAYS_REQUIRED(glTexSubImage1D),
	GLFUNC_ALWAYS_REQUIRED(glTexSubImage2D),
	GLFUNC_ALWAYS_REQUIRED(glCopyTexImage1D),
	GLFUNC_ALWAYS_REQUIRED(glCopyTexImage2D),
	GLFUNC_ALWAYS_REQUIRED(glCopyTexSubImage1D),
	GLFUNC_ALWAYS_REQUIRED(glCopyTexSubImage2D),
	GLFUNC_ALWAYS_REQUIRED(glMap1d),
	GLFUNC_ALWAYS_REQUIRED(glMap1f),
	GLFUNC_ALWAYS_REQUIRED(glMap2d),
	GLFUNC_ALWAYS_REQUIRED(glMap2f),
	GLFUNC_ALWAYS_REQUIRED(glGetMapdv),
	GLFUNC_ALWAYS_REQUIRED(glGetMapfv),
	GLFUNC_ALWAYS_REQUIRED(glGetMapiv),
	GLFUNC_ALWAYS_REQUIRED(glEvalCoord1d),
	GLFUNC_ALWAYS_REQUIRED(glEvalCoord1f),
	GLFUNC_ALWAYS_REQUIRED(glEvalCoord1dv),
	GLFUNC_ALWAYS_REQUIRED(glEvalCoord1fv),
	GLFUNC_ALWAYS_REQUIRED(glEvalCoord2d),
	GLFUNC_ALWAYS_REQUIRED(glEvalCoord2f),
	GLFUNC_ALWAYS_REQUIRED(glEvalCoord2dv),
	GLFUNC_ALWAYS_REQUIRED(glEvalCoord2fv),
	GLFUNC_ALWAYS_REQUIRED(glMapGrid1d),
	GLFUNC_ALWAYS_REQUIRED(glMapGrid1f),
	GLFUNC_ALWAYS_REQUIRED(glMapGrid2d),
	GLFUNC_ALWAYS_REQUIRED(glMapGrid2f),
	GLFUNC_ALWAYS_REQUIRED(glEvalPoint1),
	GLFUNC_ALWAYS_REQUIRED(glEvalPoint2),
	GLFUNC_ALWAYS_REQUIRED(glEvalMesh1),
	GLFUNC_ALWAYS_REQUIRED(glEvalMesh2),
	GLFUNC_ALWAYS_REQUIRED(glFogf),
	GLFUNC_ALWAYS_REQUIRED(glFogi),
	GLFUNC_ALWAYS_REQUIRED(glFogfv),
	GLFUNC_ALWAYS_REQUIRED(glFogiv),
	GLFUNC_ALWAYS_REQUIRED(glFeedbackBuffer),
	GLFUNC_ALWAYS_REQUIRED(glPassThrough),
	GLFUNC_ALWAYS_REQUIRED(glSelectBuffer),
	GLFUNC_ALWAYS_REQUIRED(glInitNames),
	GLFUNC_ALWAYS_REQUIRED(glLoadName),
	GLFUNC_ALWAYS_REQUIRED(glPushName),
	GLFUNC_ALWAYS_REQUIRED(glPopName),
};

namespace GLExtensions
{
	// Private members and functions
	static bool _isES3;
	static bool _isES;
	static u32 _GLVersion;
	static std::unordered_map<std::string, bool> m_extension_list;

	// Private initialization functions
	bool InitFunctionPointers();

	// Initializes the extension list the old way
	static void InitExtensionList21()
	{
		const char* extensions = (const char*)glGetString(GL_EXTENSIONS);
		std::string tmp(extensions);
		std::istringstream buffer(tmp);

		while (buffer >> tmp)
			m_extension_list[tmp] = true;
	}

	static void InitExtensionList()
	{
		m_extension_list.clear();
		if (_isES3)
		{
			// XXX: Add all extensions that a base ES3 implementation supports
			std::string gles3exts[] = {
				"GL_ARB_uniform_buffer_object",
				"GL_ARB_sampler_objects",
				"GL_ARB_map_buffer_range",
				"GL_ARB_vertex_array_object",
				"GL_ARB_framebuffer_object",
				"GL_ARB_occlusion_query",
				"GL_ARB_get_program_binary",
				"GL_ARB_sync",
				"GL_ARB_ES2_compatibility",
				"VERSION_GLES3",
				"VERSION_3_0",
				};
			for (auto it : gles3exts)
				m_extension_list[it] = true;
		}
		else if (!_isES)
		{
			// Some OpenGL implementations chose to not expose core extensions as extensions
			// Let's add them to the list manually depending on which version of OpenGL we have
			// We need to be slightly careful here
			// When an extension got merged in to core, the naming may have changed

			// This has intentional fall through
			switch (_GLVersion)
			{
				default:
				case 450:
				{
					std::string gl450exts[] = {
						"GL_ARB_ES3_1_compatibility",
						"GL_ARB_clip_control",
						"GL_ARB_conditional_render_inverted",
						"GL_ARB_cull_distance",
						"GL_ARB_derivative_control",
						"GL_ARB_direct_state_access",
						"GL_ARB_get_texture_sub_image",
						"GL_ARB_robustness",
						"GL_ARB_shader_texture_image_samples",
						"GL_ARB_texture_barrier",
						"VERSION_4_5",
					};
					for (auto it : gl450exts)
						m_extension_list[it] = true;
				}
				case 440:
				{
					std::string gl440exts[] = {
						"GL_ARB_buffer_storage",
						"GL_ARB_clear_texture",
						"GL_ARB_enhanced_layouts",
						"GL_ARB_multi_bind",
						"GL_ARB_query_buffer_object",
						"GL_ARB_texture_mirror_clamp_to_edge",
						"GL_ARB_texture_stencil8",
						"GL_ARB_vertex_type_10f_11f_11f_rev",
						"VERSION_4_4",
					};
					for (auto it : gl440exts)
						m_extension_list[it] = true;
				}
				case 430:
				{
					std::string gl430exts[] = {
						"GL_ARB_ES3_compatibility",
						"GL_ARB_arrays_of_arrays",
						"GL_ARB_clear_buffer_object",
						"GL_ARB_compute_shader",
						"GL_ARB_copy_image",
						"GL_ARB_explicit_uniform_location",
						"GL_ARB_fragment_layer_viewport",
						"GL_ARB_framebuffer_no_attachments",
						"GL_ARB_internalformat_query2",
						"GL_ARB_invalidate_subdata",
						"GL_ARB_multi_draw_indirect",
						"GL_ARB_program_interface_query",
						"GL_ARB_shader_image_size",
						"GL_ARB_shader_storage_buffer_object",
						"GL_ARB_stencil_texturing",
						"GL_ARB_texture_buffer_range",
						"GL_ARB_texture_query_levels",
						"GL_ARB_texture_storage_multisample",
						"GL_ARB_texture_view",
						"GL_ARB_vertex_attrib_binding",
						"VERSION_4_3",
					};
					for (auto it : gl430exts)
						m_extension_list[it] = true;
				}
				case 420:
				{
					std::string gl420exts[] = {
						"GL_ARB_base_instance",
						"GL_ARB_compressed_texture_pixel_storage",
						"GL_ARB_conservative_depth",
						"GL_ARB_internalformat_query",
						"GL_ARB_map_buffer_alignment",
						"GL_ARB_shader_atomic_counters",
						"GL_ARB_shader_image_load_store",
						"GL_ARB_shading_language_420pack",
						"GL_ARB_shading_language_packing",
						"GL_ARB_texture_compression_BPTC",
						"GL_ARB_texture_storage",
						"GL_ARB_transform_feedback_instanced",
						"VERSION_4_2",
					};
					for (auto it : gl420exts)
						m_extension_list[it] = true;
				}
				case 410:
				{
					std::string gl410exts[] = {
						"GL_ARB_ES2_compatibility",
						"GL_ARB_get_program_binary",
						"GL_ARB_separate_shader_objects",
						"GL_ARB_shader_precision",
						"GL_ARB_vertex_attrib_64_bit",
						"GL_ARB_viewport_array",
						"VERSION_4_1",
					};
					for (auto it : gl410exts)
						m_extension_list[it] = true;
				}
				case 400:
				{
					std::string gl400exts[] = {
						"GL_ARB_draw_indirect",
						"GL_ARB_gpu_shader5",
						"GL_ARB_gpu_shader_fp64",
						"GL_ARB_sample_shading",
						"GL_ARB_shader_subroutine",
						"GL_ARB_tessellation_shader",
						"GL_ARB_texture_buffer_object_rgb32",
						"GL_ARB_texture_cube_map_array",
						"GL_ARB_texture_gather",
						"GL_ARB_texture_query_lod",
						"GL_ARB_transform_feedback2",
						"GL_ARB_transform_feedback3",
						"VERSION_4_0",
					};
					for (auto it : gl400exts)
						m_extension_list[it] = true;
				}
				case 330:
				{
					std::string gl330exts[] = {
						"GL_ARB_shader_bit_encoding",
						"GL_ARB_blend_func_extended",
						"GL_ARB_explicit_attrib_location",
						"GL_ARB_occlusion_query2",
						"GL_ARB_sampler_objects",
						"GL_ARB_texture_swizzle",
						"GL_ARB_timer_query",
						"GL_ARB_instanced_arrays",
						"GL_ARB_texture_rgb10_a2ui",
						"GL_ARB_vertex_type_2_10_10_10_rev",
						"VERSION_3_3",
					};
					for (auto it : gl330exts)
						m_extension_list[it] = true;
				}
				case 320:
				{
					std::string gl320exts[] = {
						"GL_ARB_geometry_shader4",
						"GL_ARB_sync",
						"GL_ARB_vertex_array_bgra",
						"GL_ARB_draw_elements_base_vertex",
						"GL_ARB_seamless_cube_map",
						"GL_ARB_texture_multisample",
						"GL_ARB_fragment_coord_conventions",
						"GL_ARB_provoking_vertex",
						"GL_ARB_depth_clamp",
						"VERSION_3_2",
					};
					for (auto it : gl320exts)
						m_extension_list[it] = true;
				}
				case 310:
				{
					// Can't add NV_primitive_restart since function name changed
					std::string gl310exts[] = {
						"GL_ARB_draw_instanced",
						"GL_ARB_copy_buffer",
						"GL_ARB_texture_buffer_object",
						"GL_ARB_texture_rectangle",
						"GL_ARB_uniform_buffer_object",
						//"GL_NV_primitive_restart",
						"VERSION_3_1",
					};
					for (auto it : gl310exts)
						m_extension_list[it] = true;
				}
				case 300:
				{
					// Quite a lot of these had their names changed when merged in to core
					// Disable the ones that have
					std::string gl300exts[] = {
						"GL_ARB_map_buffer_range",
						//"GL_EXT_gpu_shader4",
						//"GL_APPLE_flush_buffer_range",
						"GL_ARB_color_buffer_float",
						//"GL_NV_depth_buffer_float",
						"GL_ARB_texture_float",
						//"GL_EXT_packed_float",
						//"GL_EXT_texture_shared_exponent",
						"GL_ARB_half_float_pixel",
						//"GL_NV_half_float",
						"GL_ARB_framebuffer_object",
						//"GL_EXT_framebuffer_sRGB",
						"GL_ARB_texture_float",
						//"GL_EXT_texture_integer",
						//"GL_EXT_draw_buffers2",
						//"GL_EXT_texture_integer",
						//"GL_EXT_texture_array",
						//"GL_EXT_texture_compression_rgtc",
						//"GL_EXT_transform_feedback",
						"GL_ARB_vertex_array_object",
						//"GL_NV_conditional_render",
						"VERSION_3_0",
					};
					for (auto it : gl300exts)
						m_extension_list[it] = true;
				}
				case 210:
				case 200:
				case 150:
				case 140:
				case 130:
				case 121:
				case 120:
				case 110:
				case 100:
				break;
			}
		}

		if (_GLVersion < 300)
		{
			InitExtensionList21();
			return;
		}
		GLint NumExtension = 0;
		glGetIntegerv(GL_NUM_EXTENSIONS, &NumExtension);
		for (GLint i = 0; i < NumExtension; ++i)
			m_extension_list[std::string((const char*)glGetStringi(GL_EXTENSIONS, i))] = true;
	}
	static void InitVersion()
	{
		GLint major, minor;
		glGetIntegerv(GL_MAJOR_VERSION, &major);
		glGetIntegerv(GL_MINOR_VERSION, &minor);
		if (glGetError() == GL_NO_ERROR)
			_GLVersion = major * 100 + minor * 10;
		else
			_GLVersion = 210;
		if (_isES3)
			_GLVersion = 330; // Get all the fun things
	}

	static void* GetFuncAddress(std::string name, void **func)
	{
		*func = GLInterface->GetFuncAddress(name);
		if (*func == nullptr)
		{
#if defined(__linux__) || defined(__APPLE__)
			// Give it a second try with dlsym
			*func = dlsym(RTLD_NEXT, name.c_str());
#endif
			if (*func == nullptr && _isES)
				*func = (void*)(uintptr_t)0xFFFFFFFF; // Easy to determine invalid function, just so we continue on
			if (*func == nullptr)
				ERROR_LOG(VIDEO, "Couldn't load function %s", name.c_str());
		}
		return *func;
	}

	// Public members
	u32 Version() { return _GLVersion; }
	bool Supports(const std::string& name)
	{
		return m_extension_list[name];
	}

	bool Init()
	{
		_isES3 = GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3;
		_isES = GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES3 || GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGLES2;

		// Grab a few functions for initial checking
		// We need them to grab the extension list
		// Also to check if there is an error grabbing the version
		if (GetFuncAddress("glGetIntegerv", (void**)&glGetIntegerv) == nullptr)
			return false;
		if (GetFuncAddress("glGetString", (void**)&glGetString) == nullptr)
			return false;
		if (GetFuncAddress("glGetError", (void**)&glGetError) == nullptr)
			return false;

		InitVersion();

		// We need to use glGetStringi to get the extension list
		// if we are using GLES3 or a GL version greater than 2.1
		if (_GLVersion > 210 && GetFuncAddress("glGetStringi", (void**)&glGetStringi) == nullptr)
			return false;

		InitExtensionList();

		return InitFunctionPointers();
	}

	// Private initialization functions
	static bool HasFeatures(const std::string& extensions)
	{
		bool result = true;
		std::string tmp;
		std::istringstream buffer(extensions);

		while (buffer >> tmp)
		{
			if (tmp[0] == '!')
				result &= !m_extension_list[tmp.erase(0)];
			else
				result &= m_extension_list[tmp];
		}
		return result;
	}
	bool InitFunctionPointers()
	{
		bool result = true;
		for (const auto &it : gl_function_array)
			if (HasFeatures(it.requirements))
				result &= !!GetFuncAddress(it.function_name, it.function_ptr);
		return result;
	}
}