Bit Of A Hack

Home Archives
logo

Keep up to date with Bit Of A Hack...

The gotchas of OpenGL and freeGLUT [Permalink]

So, I've been writing lots of OpenGL things recently for an upcoming OpenGL workshop at York Hackspace. It's been a little while since I did proper OpenGL stuff and so I quickly tripped up on some things.

First off, the question that has been asked a million and one times. "Why is the depth buffer not working?"

Two cubes, one rendered with incorrect depth, one with correct depth.

On the left is what you have, on the right is what you want. What gives?

A quick google to make sure you haven't set things up wrong and you find that you have remembered everything you need. You initialise your OpenGL depth handling with these two lines:

glEnable(GL_DEPTH_TEST);

glDepthFunc(GL_LEQUAL);

So everything is fine there right?

Next you check you are clearing things properly. Not that this would cause quite what you are seeing but you're now grasping at straws so you see how everyone else does it and find that it is correct to clear the depth buffer by calling glClear like so...

glClear(GL_DEPTH_BUFFER_BIT);

You've checked that the near and far clipping planes are appropriate, they are both positive and the clear depth is set correctly. So what's wrong? Now you are frustrated. Then you remember that you are using freeGLUT to handle the initialisation of your OpenGL environment and that you haven't specified that you want a depth buffer. Argh! all that time wasted and all you needed was to change this line...

glutInitDisplayMode( GLUT_DOUBLE );

To this...

glutInitDisplayMode( GLUT_DOUBLE | GLUT_DEPTH );

It's a similar story with multisampling. You can enable polygon antialiasing all you like, set the hints to nicest as many times as pleases you, but if you didn't add it to the glutInitDisplayMode() call then you get nothing, try this...

glutInitDisplayMode( GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE );

Now for the killer. Lighting. There is something that the OpenGL docs won't tell you about the glLightfv() function. When you give it a pointer to your array of values, it doesn't copy them to it's own location in memory. It just lets you deal with it all. So when you have a function like this:

void initLights(){

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_COLOR_MATERIAL);

    glShadeModel(GL_SMOOTH);

    GLfloat difLight[] = {0.8f,0.8f,0.8f,1.0f};
    GLfloat difLightPos[] = {4.8f,0.0f,0.0f};
    glLightfv(GL_LIGHT0, GL_DIFFUSE, difLight);
    glLightfv(GL_LIGHT0, GL_POSITION, difLightPos);

}

When you call initLights(), some memory is reserved for your 'difLight' and 'difLightPos' arrays. That memory is filled with the data you want to pass to the glLightfv() function. You then pass a pointer to the start of this memory into the glLightfv() function and all is well. Or so you think. When this function returns, the variables 'difLight' and 'difLightPos' go out of scope. You'd think that this is fine because you are done with them. It is of course not fine, as mentioned before, OpenGL will not make a copy of these arrays, it just keeps a pointer to them. When the memory gets freed, sooner or later it's going to be overwritten and cause bad things to happen.

In my case, by fluke, whenever I moved the mouse over the window, it got overwritten. Up until that point, everything worked. The solution is simple. Make sure the arrays with the lighting parameters in don't go out of scope. Simple...

GLfloat difLight[] = {0.8f,0.8f,0.8f,1.0f};
GLfloat difLightPos[] = {4.8f,0.0f,0.0f};

void initLights(){

    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_COLOR_MATERIAL);

    glShadeModel(GL_SMOOTH);

    glLightfv(GL_LIGHT0, GL_DIFFUSE, difLight);
    glLightfv(GL_LIGHT0, GL_POSITION, difLightPos);

}

This is an argument for garbage collection. If this was done in a suitably clever garbage collected programming language then the GC would not free the memory used by the arrays as there would still be a pointer to it even after the function returns. If you want my opinion on garbage collection, I am mostly indifferent towards it. Yeah, memory leaks are not an issue if you have GC but my only problem with it is that you have less control over the memory. Personally I much rather want to malloc() and free() things. That said, I can quite happily live with it when using Java for example.

By .

comments powered by Disqus

This website uses cookies. If you don't like this, please stop using this site.