Read me About Demoscene? Links Contact

Use the compiler to keep track of OpenGL

In a world of rapid development and an emphasis on lowering bugs and perhaps not specifically speed - I have found it usefull to take advantage of the C++ stack for keeping track of my OpenGL states.

Sounds weird? Well, yes. Reviewing 10 years of OpenGL code has boiled down to heaps of enable/disable and begin/end statements covered with late night debugging figuring out why stuff doesn’t work.

Here is my suggestion which has some overhead in terms of performance but should lower the number of hourse spend on debugging to figure out why the OpenGL state is wrong.

Try comparing the following two pieces of code. First is a reference snippet using plain old OpenGL function calls:

    void Draw3D()
    {
      glBegin(GL_TRIANGLE_STRIP);
      …
      glEnd();
    }

    void Frame()
    {
      glEnable(GL_TEXTURE_2D);
      glEnable(GL_DEPTH_TEST);
      glEnable(GL_BLEND);
       
      Draw3D();

      glDisable(GL_BLEND);
      glDisable(GL_DEPTH_TEST);
      glDisable(GL_BLEND);
    }

Now, here is a modified version which uses the compiler stack to keep track of the states:

    void Draw3D()
    {
        GL::Begin t(GL_TRIANGLE_STRIP);
        …
    }

    void Frame()
    {
        GL::Enable t(GL_TEXTURE_2D);
        GL::Enable d(GL_DEPTH_TEST);
        GL::Enable b(GL_BLEND);
       
        Draw3D();
    }

I don’t know which version you prefer - however, I do know which one is most readable.

So, how does it all work? Basicly I am just using the fact that local instances are allocated on the stack and thus releases when it runs out of scope. The constructor of Enable and Begin are wrapping the glEnable and glBegin calls while the deconstructors are wrapping glDisable and glEnd. Neat, eh?

In addition, wrapping stuff allows for further debug facilities. Below is a basic implementation you can use if you like …

namespace GL
{
    class Enable
    {
    private:
        GLenum cap;
    public:
        Enable(GLenum cap) : cap(cap)
        {
            glEnable(cap);
#ifdef _DEBUG
            assert(glGetError()==GL_NO_ERROR);
#endif
        }
        ~Enable()
        {
            glDisable(cap);
#ifdef _DEBUG
            assert(glGetError()==GL_NO_ERROR);
#endif
        }
    };


    class Begin
    {
    public:
        Begin(GLenum cap)
        {
            glBegin(cap);
        }
        ~Begin()
        {
            glEnd();
#ifdef _DEBUG
            int v = glGetError();
            assert(v==GL_NO_ERROR);
#endif
        }
    };
}

If you dislike the local variables - you might find these macros handy:

#define ENABLE(x) GL::Enable(x) __##x##__;
#define BEGIN(x) GL::Begin(x) __##x##__;

Which might be used as follows:

    void Draw3D()
    {
        BEGIN(GL_TRIANGLE_STRIP);
        …
    }

    void Frame()
    {
        ENABLE(GL_TEXTURE_2D);
        ENABLE(GL_DEPTH_TEST);
        ENABLE(GL_BLEND);
       
        Draw3D();
    }