SDL GL Wrapper Code Generator

Home --> Useful Scripts --> SDL GL Wrapper Code Generator

Why You Are Here

You are using SDL and you want a C++ singleton class that has member functions with the same signatures as a small number of OpenGL extension functions you want to call. If this is not what you want, then stop reading now. Normally you would use the library glew to get OpenGL extensions, but you are so sick and tired of having to link with it every single time you or others compile your game on a new and strange platform, and you start thinking about whether all the time spent by you or others doing this is not better spent by yourself to get the darn function pointers yourself so that other people do not have to deal with this garbage. If your game is written in C++ and you are linking with SDL, why the heck do you also have to link with glew? However, people yell at you when you suggest getting the function pointers yourself.

Luckily, SDL does the non-trivial part with the function SDL_GL_GetProcAddress. If you do not know what this is, read about it right now.

Now all you have to do is the "trivial" part of writing code to call SDL_GL_GetProcAddress. You could do this yourself, but let's face it, you probably think that 1) it is beeneth you, 2) someone has already done it, 3) you are not going to solve the problem in any sort of generality. Well, generality and simplicity are at odds with one another, and if you really wanted generality, maybe you would just use glew in the first place. Also, if you want to world's most pointlessly general code generation system which takes hours to learn and configure, then create it yourself and try to convince others it saves time.

Thus, you want simplicity. What is the simplest possible way to generate a .h and a .cpp file with the declaration and definition of a singleton class to wrap the handful of OpenGL extension functions which you want to call? Just type the .h and .cpp files into existence using your fingers, eyes, brain, a good text editor, and an internet connection. What is the second most simple way? The python script below:

How To Use It

Download and install python. Put SDLGLWrapperGen.py.txt in some folder and remove the .txt extension. Open the file with a text editor and scrool down to where it says "HEY YOU HUMAN". Add lines of python code in the obvious way (which you can figure out from context). For each function you want to add, go online and look at its signature and type the obvious thing. Whatever you do, don't make a typo. Check what you wrote once, twice, and then check it again. Run the python script. It will generate OpenGLWrapper.h and OpenGLWrapper.cpp. Read the files to see what is going on. You are done!

If you don't like the fact that the class is called OpenGLWrapper, then go to town on the python script with a good text editor. Or, better yet, write it all yourself. If you wish the names of the members to the class were mangled for some technical reason, then you know what to do.

Was the python script itself generated through some strange meconism? You better believe it.

Code Dump

Here is the python script, in all its disguesting beauty:
#File: sdlglwrappergen.py

#This list gets appended by AddFunc.
funcs = []

#The name should be a string (the function name, e.g. "glColor3f").
#The params should be a list of pairs.
#The first element of each pair should be the string for the type (e.g. "GLfloat").
#The second element of each pair should be the string for the arg name (e.g. "r").
def AddFunc(name, params):
    funcs.append((name,params))

def Helper_PrintTypedef(hf, name, params):
    hf.write('    typedef void (APIENTRY * ' + name + '_Func)(')
    i = 0
    for (type_name, arg) in params:
        i += 1
        hf.write(type_name)
        if i != len(params):
            hf.write(', ')
    hf.write(');\n')

def Helper_PrintPtrDef(hf, name):
    hf.write('    ' + name + '_Func ' + name + '_ptr;\n')

def Helper_PrintWrapperFuncDec(hf, name, params):
    hf.write('    void ' + name + '(')
    i = 0
    for (type_name, arg) in params:
        i += 1
        hf.write(type_name)
        hf.write(' ')
        hf.write(arg)
        if i != len(params):
            hf.write(', ')
    hf.write(');\n')

def Helper_PrintSetPtrToNull(cf, name):
    cf.write('    ' + name + '_ptr = 0;\n')

def Helper_PrintFuncPtrGetter(cf, name):
    cf.write('    ' + name + '_ptr = (' + name + '_Func) ')
    cf.write('GetProcAddrHelper(\"' + name + '\");\n')

def Helper_PrintWrapperFuncDef(cf, name, params):
    cf.write('\n')
    cf.write('void OpenGLWrapper::' + name + '(')
    i = 0
    for (type_name, arg) in params:
        i += 1
        cf.write(type_name)
        cf.write(' ')
        cf.write(arg)
        if i != len(params):
            cf.write(', ')
    cf.write(') {\n')
    cf.write('    ' + name + '_ptr(')
    i = 0
    for (type_name, arg) in params:
        i += 1
        cf.write(arg)
        if i != len(params):
            cf.write(', ')
    cf.write(');\n')
    cf.write('}\n')

#Prints to output the contents of "GLWrapper.h".
def GenWrapper():
    #hf stands for header file.
    #cf stands for source file.
    hf = open('OpenGLWrapper.h', 'w')
    cf = open('OpenGLWrapper.cpp', 'w')
    #Generating the header file.
    hf.write('//File: OpenGLWrapper.h\n')
    hf.write('//This C++ header was autogenerated\n')
    hf.write('//using a python script (by Dan Hathaway).\n')
    hf.write('\n')
    hf.write('#ifndef OpenGLWrapper_h_\n')
    hf.write('#define OpenGLWrapper_h_\n')
    hf.write('\n')
    hf.write('//Replace the next include with \"gl.h\" or whatever.\n')
    hf.write('//This is only needed for the type definitions,\n')
    hf.write('//so if you want you can just typedef them yourself.\n')
    hf.write('#include \"OpenGLInclude.h\"\n')
    hf.write('\n')
    hf.write('//-----------------------------------------------\n')
    hf.write('//                                               \n')
    hf.write('//                OPEN GL WRAPPER                \n')
    hf.write('//                                               \n')
    hf.write('//-----------------------------------------------\n')
    hf.write('\n')
    hf.write('//The singleton instance of this class should\n')
    hf.write('//be used to make OpenGL calls.  When the singleton\n')
    hf.write('//is constructed, SDL_GL_GetProcAddress will be called,\n')
    hf.write('//so SDL must be initialzied before this.\n')
    hf.write('\n')
    hf.write('class OpenGLWrapper {\n')
    hf.write('private:\n')
    hf.write('    //Typedefs.\n')
    for (name, params) in funcs:
        Helper_PrintTypedef(hf, name, params)
    hf.write('\n')
    hf.write('    //The singleton.\n')
    hf.write('    static class GLWrapper * singleton;\n')
    hf.write('\n')
    hf.write('    //These should all be initially set to 0.\n')
    for (name, params) in funcs:
        Helper_PrintPtrDef(hf, name)
    hf.write('\n')
    hf.write('    void Initialize();')
    hf.write('\n')
    hf.write('    void * GetProcAddrHelper(const char * name);\n')
    hf.write('\n')
    hf.write('    //Can only construct by getting the singleton.\n')
    hf.write('    OpenGLWrapper();\n')
    hf.write('    ~OpenGLWrapper();\n')
    hf.write('\n')
    hf.write('public:\n')
    hf.write('    //The first call to this will\n')
    hf.write('    //instantiate the singleton,\n')
    hf.write('    //so SDL must already be initialized\n')
    hf.write('    //when this happens.\n')
    hf.write('    static OpenGLWrapper & Inst();\n')
    hf.write('\n')
    hf.write('    //Some OpenGL functions.\n')
    hf.write('    //If you wish they were inlined,\n')
    hf.write('    //then cut and paste the function definitions\n')
    hf.write('    //from the .cpp file to here.\n')
    for (name, params) in funcs:
        Helper_PrintWrapperFuncDec(hf, name, params)
    hf.write('};\n')
    hf.write('\n')
    hf.write('#endif\n')
    #Generating the source file.
    cf.write('//File: OpenGLWrapper.cpp\n')
    cf.write('\n')
    cf.write('#include "OpenGLWrapper.h"\n')
    cf.write('\n')
    cf.write('#include  //For SDL_GL_GetProcAddress.\n')
    cf.write('\n')
    cf.write('#include  //For exit.\n')
    cf.write('#include  //For cout.\n')
    cf.write('using std::cout;\n')
    cf.write('\n')
    cf.write('OpenGLWrapper * OpenGLWrapper::singleton = 0;\n')
    cf.write('\n')
    cf.write('OpenGLWrapper & OpenGLWrapper::Inst() {\n')
    cf.write('    if( singleton == 0 ) {\n')
    cf.write('        singleton = new GLWrapper;\n')
    cf.write('    }\n')
    cf.write('    return *singleton;\n')
    cf.write('}\n')
    cf.write('\n')
    cf.write('OpenGLWrapper::OpenGLWrapper() {\n')
    cf.write('    //Better safe than sorry.\n')
    for (name, params) in funcs:
        Helper_PrintSetPtrToNull(cf, name)
    cf.write('\n')
    cf.write('    Initialize();\n')
    cf.write('}\n')
    cf.write('\n')
    cf.write('OpenGLWrapper::~OpenGLWrapper() {\n')
    cf.write('    //Nothing to do.\n')
    cf.write('}\n')
    cf.write('\n')
    cf.write('void * OpenGLWrapper::GetProcAddrHelper(\n')
    cf.write('    const char * name)\n')
    cf.write('{\n')
    cf.write('    //Uncomment the next line if you want.\n')
    cf.write('    //cout << "Calling SDL_GL_GetProcAddress(\"" << name << "\")\\n";\n')
    cf.write('    void * function_ptr = 0;\n')
    cf.write('    function_ptr = SDL_GL_GetProcAddress(name);\n')
    cf.write('    if( function_ptr == 0 ) {\n')
    cf.write('        cout << "*** Error in GLWrapper::GetProcAddressHelper:\\n"\n')
    cf.write('            << "cannot get function pointer: " << name << "\\n"\n')
    cf.write('            << "from SDL_GL_GetProcAddress\\n";\n')
    cf.write('        PoliteExit();\n')
    cf.write('    }\n')
    cf.write('    return function_ptr;\n')
    cf.write('}\n')
    cf.write('\n')
    cf.write('void GLWrapper::Initialize() {\n')
    for (name, params) in funcs:
        Helper_PrintFuncPtrGetter(cf, name)
    cf.write('}\n')
    for (name, params) in funcs:
        Helper_PrintWrapperFuncDef(cf, name, params)

#HEY YOU HUMAN.
#Modify these and/or add your own:
AddFunc('glEnd',        [])
AddFunc('glTranslated', [('GLdouble','x'),('GLdouble','y'),('GLdouble','z')])
AddFunc('glColor3f',    [('GLfloat','r'),('GLfloat','g'),('GLfloat','b')])

#Generating the .h and .cpp files.
GenWrapper();
Here is the .h file it generates: BLAH BLAH Here is the .cpp file it generates: BLAH BLAH