I went with the global gl variable approach in game code that gets passed in with the platform's memory struct (like hmh's debug code).
I have a small metaprogram that generates the GL functions and loader code (by parsing glcorearb.h)
GLFunctions.h
[Code]
#ifndef GL_FUNCTIONS_H
#define GL_FUNCTIONS_H
#include <GL/glcorearb.h>
typedef void (*glFunction)(void);
glFunction LoadFunction(char *);
struct gl_functions
{
PFNGLCULLFACEPROC CullFace;
PFNGLFRONTFACEPROC FrontFace;
PFNGLHINTPROC Hint;
PFNGLLINEWIDTHPROC LineWidth;
// etc...
};
[/Code]
GLLoader.h
[Code]
#ifndef GL_LOADER_H
#define GL_LOADER_H
#include "GLFunctions.h"
#include <Windows.h>
typedef void(*glFunction)(void);
gl_functions LoadFunctions();
HMODULE GLModule;
struct gl_version
{
int Major;
int Minor;
} GLVersion;
glFunction LoadFunction(char *FunctionName)
{
glFunction Function = (glFunction)wglGetProcAddress(FunctionName);
if (!Function)
Function = (glFunction)GetProcAddress(GLModule, FunctionName);
return Function;
}
bool glInit(gl_functions *Functions)
{
GLModule = LoadLibrary("opengl32.dll");
gl_functions GL = LoadFunctions();
FreeLibrary(GLModule);
GL.GetIntegerv(GL_MAJOR_VERSION, &GLVersion.Major);
GL.GetIntegerv(GL_MINOR_VERSION, &GLVersion.Minor);
*Functions = GL;
return GLVersion.Major >= 3;
}
bool glIsSupported(int Major, int Minor)
{
if (Major < 3 || Major > GLVersion.Major)
return false;
if (Major < GLVersion.Major)
return true;
return Minor <= GLVersion.Minor;
}
gl_functions LoadFunctions()
{
gl_functions Result;
Result.CullFace = (PFNGLCULLFACEPROC)LoadFunction("glCullFace");
Result.FrontFace = (PFNGLFRONTFACEPROC)LoadFunction("glFrontFace");
Result.Hint = (PFNGLHINTPROC)LoadFunction("glHint");
Result.LineWidth = (PFNGLLINEWIDTHPROC)LoadFunction("glLineWidth");
// etc...
return (Result);
}
#endif
[/Code]
Then in my platform layer, I initialize GL and keep a pointer to it in my game_memory:
[Code]
// Initialize GL (_must_ be done after creating GL Context)
gl_functions GLFunctions = {};
Assert(glInit(&GLFunctions));
char GLVersion[128] = {};
sprintf(GLVersion, "OpenGL %s, GLSL %s\n",
GLFunctions.GetString(GL_VERSION), GLFunctions.GetString(GL_SHADING_LANGUAGE_VERSION));
OutputDebugString(GLVersion);
game_memory Memory;
// Initialize persistent and transient memory...
Memory.GLFunctions = GLFunctions;
[/Code]
In the game:
[Code]
#include "GLFunctions.h"
gl_functions gl;
// more include stuff...
void UpdateAndRender(r32 DeltaTime, game_memory *Memory, platform_services *Platform)
{
// platform_services contains Input key values and a GetTime function pointer to get the current time for use in some shader code...
gl = Memory->GLFunctions;
}
[/Code]
Then any GL helper function should be included _after_ the global 'gl' variable, and instead of writing glXXX it writes
gl.XXX
Hope somebody else finds this useful. If anybody's interested in the parsing/metaprogram code let me know!