OpenGL/GLUT, Classes (OOP), and Problems

Update: 8/22/10 Checkout the updated framework and post: http://paulsolt.com/2010/08/glut-object-oriented-framework-on-github/

I created a C style driver program that used OpenGL/GLUT for my computer animation course projects. It worked fine for the first project. However, there were multiple projects and they all started to use the same boiler plate code. In order to reuse code, I decided to refactor and make an extensible class to setup GLUT. My goal was to make it easy to extend the core behavior of the GLUT/OpenGL application.

As I refactored the code I decided to make a base class to perform all the GLUT setup. There’s a first time for everything and I didn’t realize the scope of this change until I was committed to it. I will summarize the problems and how to solve them. The code and explanations should provide the basic understanding of what is happening, but it will not compile as it is provided.

Problem 1: My initial attempt was to pass member functions to the GLUT callback functions. However, you can’t pass member functions from a class directly to C callback functions. The GLUT callback functions expect a function signature exactly as function(BLAH) and I was giving it something that was function(this, BLAH). Where the “this” portion was the object passed under the hood.

class AnimationFramework {
public:
	void display();
	void run();
	void keyboard(unsigned char key, int x, int y);
	void keyboardUp(unsigned char key, int x, int y);
	void specialKeyboard(int key, int x, int y);
	void specialKeyboard(int key, int x, int y);
	void startFramework(int argc, char *argv[]);
};

… in the setup function for GLUT

void AnimationFramework::startFramework(int argc, char *argv[]) {
	// Initialize GLUT
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
	glutInitWindowPosition(300, 100);
	glutInitWindowSize(600, 480);
	glutCreateWindow("Animation Framework"); 
 
	// Function callbacks
	glutDisplayFunc(display); 		// ERROR
	glutKeyboardFunc(keyboard); 		// ERROR
	glutKeyboardUpFunc(keyboardUp); 	// ERROR
	glutSpecialFunc(specialKeyboard); 	// ERROR
	glutSpecialUpFunc(specialKeyboardUp); // ERROR
 
	init();			// Initialize
	glutIdleFunc(run); 	// The program run loop  // ERROR
	glutMainLoop();		// Start the main GLUT thread
}

Solution 1: Create static methods, and pass these static methods to the call back functions. All the logic for the AnimationFramework will go into these static methods. I’ve fixed the compiler errors, but it feels like a step backwards from what I set out to do.

class AnimationFramework {
public:
	static void displayWrapper();
	static void runWrapper();
	static void keyboardWrapper(unsigned char key, int x, int y);
	static void keyboardUpWrapper(unsigned char key, int x, int y);
	static void specialKeyboardWrapper(int key, int x, int y);
	static void specialKeyboardUpWrapper(int key, int x, int y);
	void startFramework(int argc, char *argv[]);
};

… in a setup function for GLUT

void AnimationFramework::startFramework(int argc, char *argv[]) {
	// Initialize GLUT
	glutInit(&argc, argv);
	glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
	glutInitWindowPosition(300, 100);
	glutInitWindowSize(600, 480);
	glutCreateWindow("Animation Framework"); 
 
	// Function callbacks
	glutDisplayFunc(displayWrapper);		// NO ERRORS!
	glutKeyboardFunc(keyboardWrapper);
	glutKeyboardUpFunc(keyboardUpWrapper);
	glutSpecialFunc(specialKeyboardWrapper);
	glutSpecialUpFunc(specialKeyboardUpWrapper);
 
	init();					// Initialize
	glutIdleFunc(runWrapper); 	// The program run loop
	glutMainLoop();				// Start the main GLUT thread
}

I’ve made a bit of progress, but when you think about it, static methods aren’t much different from the plain C functions.

Problem 2: I want to have the functionality in the instance methods, yet I’m stuck with static methods. I’m not encapsulating the behavior inside instance methods, and I have no option for inheritance. I’ve still failed to hit the initial goal of creating an easy to use object oriented GLUT wrapper that’s extensible.

Solution 2: I need to make virtual instance methods in the class and call them from the static callback functions. But I can’t make the function calls directly, I need a static instance of the class to make the instance function calls. (Re-read, as it’s a little complex) All I need to do is pass an instance of the class or subclass and I’ll be able to extend the functionality. It’s a little tricky/ugly, but it’s the best method I’ve found for encapsulating C style GLUT into a C++ application.

class AnimationFramework {
protected:
	static AnimationFramework *instance;
public:
	static void displayWrapper();
	static void runWrapper();
	static void keyboardWrapper(unsigned char key, int x, int y);
	static void keyboardUpWrapper(unsigned char key, int x, int y);
	static void specialKeyboardWrapper(int key, int x, int y);
	static void specialKeyboardUpWrapper(int key, int x, int y);
	void startFramework(int argc, char *argv[]);
 
	void run();
	virtual void display(float dTime);
	virtual void keyboard(unsigned char key, int x, int y);
	virtual void keyboardUp(unsigned char key, int x, int y);
	virtual void specialKeyboard(int key, int x, int y);
	virtual void specialKeyboardUp(int key, int x, int y);
};

The static methods are implemented here:

// Static functions which are passed to Glut function callbacks
 
void AnimationFramework::displayWrapper() {
	instance->displayFramework(); // calls display(float) with time delta
}
void AnimationFramework::runWrapper() {
	instance->run();
}
void AnimationFramework::keyboardWrapper(unsigned char key, int x, int y) {
	instance->keyboard(key,x,y);
}
void AnimationFramework::keyboardUpWrapper(unsigned char key, int x, int y) {
	instance->keyboardUp(key,x,y);
}
void AnimationFramework::specialKeyboardWrapper(int key, int x, int y) {
	instance->specialKeyboard(key,x,y);
}
void AnimationFramework::specialKeyboardUpWrapper(int key, int x, int y) {
	instance->specialKeyboardUp(key,x,y);
}

The startFramework() method is the same as provided in the Solution 1.

EDIT:
I left out details on how the instance was set. In my program, I subclassed AnimationFramework and created classes for each program I needed overriding the appropriate methods. As an example, KeyFrameFramework was a subclass in my project.

I have a function in my AnimationFramework.h

static void setInstance(AnimationFramework * framework);

AnimationFramework.cpp

AnimationFramework *AnimationFramework::instance = 0;
void AnimationFramework::setInstance(AnimationFramework *framework) {
	instance = framework;
}

The main.cpp looks something like this:

int main(int argc, char *argv[]) {
 
	AnimationFramework *f = new KeyFrameFramework(); // Subclass of AnimationFramework
	f->setInstance(f);
	f->setTitle("Key Framing:");
	f->setLookAt(0.0, 2.0, 10.0, 0.0, 2.0, 0.0, 0.0, 1.0, 0.0);
	f->startFramework(argc, argv);
	return 0;
}

I set the instance variable of the AnimationFramework class to an AnimationFramework subclass called KeyFrameFramework. Doing so allows me to use polymorphism and call the appropriate functionality that is specific to each animation project. Note: Don’t set the instance within a constructor, since the object is not fully initialized until the constructor is finished. You need to set the instance after your subclass object has been created.

Let me know if you have any questions. Below are the references I used.

References:

19 Comments

  1. Thanks for this, very helpful. One thing I don’t get, however, is where the instance variable in the last example is actually assigned to be the instance?

    after putting all of my GLUT stuff into classes it can’t resolve any of it, I get errors for each OpenGL function like “undefined reference to `_imp__glMatrixMode’” etc. Did you encounter this problem?

  2. Sorry, I left out details on how that was set. I subclassed AnimationFramework and created classes for each program I needed overriding the appropriate methods. KeyFrameFramework was a subclass in my project.

    I have a function in my AnimationFramework.h

    static void setInstance(AnimationFramework * framework);

    AnimationFramework.cpp

    void AnimationFramework::setInstance(AnimationFramework *framework) {
    	instance = framework;
    }

    The main.cpp looks something like this:

    int main(int argc, char *argv[]) {
     
    	AnimationFramework *f = new KeyFrameFramework(); // Subclass of AnimationFramework
    	f->setInstance(f);
    	f->setTitle("Key Framing:");
    	f->setLookAt(0.0, 2.0, 10.0, 0.0, 2.0, 0.0, 0.0, 1.0, 0.0);
    	f->startFramework(argc, argv);
    	return 0;
    }
  3. The errors you get may be from a bad order of include files. Make sure you include GLUT files after you include STL (Standard library) files. It should look something like this:

    #include <stdlib.h>
    #include <stdio.h>
    #include <iostream>
    #include <vector>
    #include <math.h>
    #include <windows.h>  
     
    // Mac and PC compatible
    #if defined(__APPLE__) && defined(__MACH__)
    #   include <GLUT/glut.h>
    #else
    #   include <GL/glut.h>
    #endif
  4. Hi.

    I tried something similar but my program crashes on startup. When running the debugger, I find that when I set my instance, the vfptr is set correctly, but when I’m inside the delegating function (the one actually called by glut) the vfptr is 0×0. So, basically, mine works with non-virtual methods, but not with virtual methods.

    I’m using Visual Studio 2008. Any suggestions?
    – Seth

  5. Might be related to this issue, but I’m not 100%

    http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2
    “Note: static member functions do not require an actual object to be invoked, so pointers-to-static-member-functions are usually type-compatible with regular pointers-to-functions. However, although it probably works on most compilers, it actually would have to be an extern “C” non-member function to be correct, since “C linkage” doesn’t only cover things like name mangling, but also calling conventions, which might be different between C and C++.”

    Do you have any snippets of code?

  6. Hi Paul

    Looking at your code and it is a really good idea.

    I am having a few problems however in getting it to work.. It may be a general C++ error but for some reason it keeps complaining that the instance variable isn’t defined..

    class cgvDrawWrap
    {
    	protected:
    		static cgvDrawWrap *instance;
     
    	public:
    		static void drawSceneWrap()
    		{
    			instance->drawScene();
    		}
     
    		static void setInstance(cgvDrawWrap *in)
    		{
    			//printf("\nBefore %ld\t%ld", in, cgvDrawinstance);
    			instance = in;
    			//printf("\nAfter %ld\t%ld", in, instance);
    		}
    };
     
    class cgvDraw : public cgvDrawWrap
    {
    	public:
     
    		// Class constructor
    		cgvDraw()
    		{
    			// Set the instance of the class
    			this->setInstance(this);
                            ..........................
                    }
    };

    this is only a cut down version of the offending code – but it seems the same as what you have and I don’t know why it isn’t working.

    Any ideas would be amazing.

    “undefined reference to `cgvDrawWrap::instance’”

    Regards,
    Richard

  7. @Richard Simpson
    It looks like your trying to set the instance in your constructor. That instance will not be complete until after the constructor is finished running. I think that is your issue.

    Following one of my previous comments you need to do the following in a “main program” where you create the cgvDraw object.

    1. Create the object
    2. Pass in the object’s instance to it’s static instance variable.

    cgvDraw cgObject = new cgvDraw();
    cgObject->setInstance(cgObject);
  8. Awesome tutorial. I followed what you said above, but I am getting one really annoying linker error and can’t seem to figure out what’s up with it.

    Error	1	error LNK2001: unresolved external symbol "protected: static class Graphics * Graphics::instance" (?instance@Graphics@@1PAV1@A)	Graphics.obj

    I am doing the following in main:

    Graphics *rhGraphics = new Graphics();
     
    rhGraphics->setInstance(rhGraphics);

    Not sure where else it could be causing problems. My codes has gotten quite large, as I wasn’t doing oop when I first started the project. If you need more than just this, please let me know. This problem’s been bugging me for too long…

  9. Have you tried creating a sample project with very basic functionality? I need to see more code.

  10. Meant to post this awhile ago, but actually fixed the problem. Had spoken to my professor and he mentioned to add:

    Graphics *Graphics::instance;

    to the top of my Graphics.cpp file. This did the trick and thankfully got rid of the linker error.

  11. @Steven
    Glad to hear. I’ve updated my post implementation file to include the line:

     AnimationFramework *AnimationFramework::instance = NULL;
  12. Could you post the code for a full example I can compile and run?
    Thanks.

  13. @adrian I just refactored out the code from my animation project. I’m hosting it on github at: http://github.com/PaulSolt/GLUT-Object-Oriented-Framework

    I’ve included an Xcode 3.1 and a Visual Studio 2010 project along with the source files. I’ll update the site with more information on using it.

    The sample will create a simple teapot animation at 60fps.

  14. @Paul Solt
    Great, many thanks! For programmers it is trivially simple to understand your explanations from this post. I needed to see a full working example; I have to follow trough your code and bring bits and pieces into Code::Blocks, but it is so much easier now! For beginners like me I have a tiny little example following your tutorial with just a very basic opengl instance here: http://ubuntuforums.org/showthread.php?t=1557360
    I am not sure why this subject it is not a lot more discussed. Other than your example it is not too much more out there one can learn from. Keep up the good work!
    Adi

  15. You’re welcome. I’ve also been frustrated a lot by the shear complexity of getting started in OpenGL. Hopefully this is a good starting point and I’ll follow up with more documentation.

    I didn’t post the code before, since it was all mangled in my class project and I had to spend a good deal of time cleaning it up for release. There’s still things that could be changed, and I plan on updating them in the near future.

    The code on github is a lot more friendly than the steps that I discussed regarding the static instance. The instance is set from within the framework, instead of requiring the user to set it in their code.

  16. @Paul Solt
    I was able to download your example and get it running using code::block in Ubuntu. All I had to do was to download freeglut_std.h from here: http://www.koders.com/c/fid9C884D79DFF686DE5685DF424FC66761EADD7313.aspx?s=freeglut_std.h#L5 and to replace in 3 places “NULL” with “0″ in PerformanceTimer.cpp file.
    Many thanks again! I will check from time to time to see what other goodies you will share :)

  17. Good job, thanks.

    If I want to draw a colorful triangle:

    glBegin(GL_TRIANGLES);
    glColor3f(0.0f,0.0f,1.0f);
    glVertex3f( 0.0f, 1.0f, 0.0f);
    glColor3f(0.0f,1.0f,0.0f);
    glVertex3f(-1.0f,-1.0f, 0.0f);
    glColor3f(1.0f,0.0f,0.0f);
    glVertex3f( 1.0f,-1.0f, 0.0f);
    glEnd();

    I have to disable light0:

    glDisable(GL_LIGHTING);
    glDisable(GL_LIGHT0);

    otherwise, the color of the object is almost white.Could you let us know the solution.Thanks.

  18. I’d look at one of the tutorials on OpenGL. My code is just a starting point.

Leave a Reply

Your email address will not be published.

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

© 2014 Paul Solt

Theme by Anders NorenUp ↑