SDL GL Wrapper Code Generator

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

What This Is

This is a simple program that demonstrats how you can use SDL to get OpenGL function pointers by calling the SDL function SDL_GL_GetProcAddress.

Specifically, this is a python script that when run generates files OpenGLWrapper.h and OpenGLWrapper.cpp. These files define a C++ singleton class that has member functions associated to various OpenGL functions. Calling these member functions will call the associated OpenGL functions.

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 natural 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 relevant thing. Whatever you do, don't make a typo! Run the python script. It will generate OpenGLWrapper.h and OpenGLWrapper.cpp. You can put these files in your C++ program. Read the files to see what is going on. You are done!

The Python Script Code

Here is the python script:
#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();

Output (OpenGLWrapper.h and .cpp) of the Python Script

Here is the file OpenGLWrapper.h that the python script generates:
//File: OpenGLWrapper.h
//This C++ header was autogenerated
//using a python script (by Dan Hathaway).

#ifndef OpenGLWrapper_h_
#define OpenGLWrapper_h_

//Replace the next include with "gl.h" or whatever.
//This is only needed for the type definitions,
//so if you want you can just typedef them yourself.
#include "OpenGLInclude.h"

//-----------------------------------------------
//                                               
//                OPEN GL WRAPPER                
//                                               
//-----------------------------------------------

//The singleton instance of this class should
//be used to make OpenGL calls.  When the singleton
//is constructed, SDL_GL_GetProcAddress will be called,
//so SDL must be initialzied before this.

class OpenGLWrapper {
private:
    //Typedefs.
    typedef void (APIENTRY * glEnd_Func)();
    typedef void (APIENTRY * glTranslated_Func)(GLdouble, GLdouble, GLdouble);
    typedef void (APIENTRY * glColor3f_Func)(GLfloat, GLfloat, GLfloat);

    //The singleton.
    static class GLWrapper * singleton;

    //These should all be initially set to 0.
    glEnd_Func glEnd_ptr;
    glTranslated_Func glTranslated_ptr;
    glColor3f_Func glColor3f_ptr;

    void Initialize();
    void * GetProcAddrHelper(const char * name);

    //Can only construct by getting the singleton.
    OpenGLWrapper();
    ~OpenGLWrapper();

public:
    //The first call to this will
    //instantiate the singleton,
    //so SDL must already be initialized
    //when this happens.
    static OpenGLWrapper & Inst();

    //Some OpenGL functions.
    void glEnd();
    void glTranslated(GLdouble x, GLdouble y, GLdouble z);
    void glColor3f(GLfloat r, GLfloat g, GLfloat b);
};

#endif
Here is the file OpenGLWrapper.cpp that the python script generates:
//File: OpenGLWrapper.cpp

#include "OpenGLWrapper.h"

#include  //For SDL_GL_GetProcAddress.

#include  //For exit.
#include  //For cout.
using std::cout;

OpenGLWrapper * OpenGLWrapper::singleton = 0;

OpenGLWrapper & OpenGLWrapper::Inst() {
    if( singleton == 0 ) {
        singleton = new GLWrapper;
    }
    return *singleton;
}

OpenGLWrapper::OpenGLWrapper() {
    //Better safe than sorry.
    glEnd_ptr = 0;
    glTranslated_ptr = 0;
    glColor3f_ptr = 0;

    Initialize();
}

OpenGLWrapper::~OpenGLWrapper() {
    //Nothing to do.
}

void * OpenGLWrapper::GetProcAddrHelper(
    const char * name)
{
    //Uncomment the next line if you want.
    //cout << "Calling SDL_GL_GetProcAddress("" << name << "")\n";
    void * function_ptr = 0;
    function_ptr = SDL_GL_GetProcAddress(name);
    if( function_ptr == 0 ) {
        cout << "*** Error in GLWrapper::GetProcAddressHelper:\n"
            << "cannot get function pointer: " << name << "\n"
            << "from SDL_GL_GetProcAddress\n";
        PoliteExit();
    }
    return function_ptr;
}

void GLWrapper::Initialize() {
    glEnd_ptr = (glEnd_Func) GetProcAddrHelper("glEnd");
    glTranslated_ptr = (glTranslated_Func) GetProcAddrHelper("glTranslated");
    glColor3f_ptr = (glColor3f_Func) GetProcAddrHelper("glColor3f");
}

void OpenGLWrapper::glEnd() {
    glEnd_ptr();
}

void OpenGLWrapper::glTranslated(GLdouble x, GLdouble y, GLdouble z) {
    glTranslated_ptr(x, y, z);
}

void OpenGLWrapper::glColor3f(GLfloat r, GLfloat g, GLfloat b) {
    glColor3f_ptr(r, g, b);
}