做图形学作业终于到的问题。打算将每一个场景抽象为一个Scene类,然后调用类的run接口来显示场景。
其中遇到了关于glutDisplayFunc函数调用的问题,函数原型为:
extern void APIENTRY glutDisplayFunc(void (*func)(void));
即要求func参数为一个void (*func)(void)类型,对于如下定义的类:
class Scene { public: Scene(std::string title, int width=1024, int height=768); virtual ~Scene(); /*初始化场景*/ virtual void init(int argc, char *argv[]) = 0; /*运行场景*/ virtual int run() = 0; protected: /*绘制场景*/ virtual void display() = 0; /*键盘回调函数*/ virtual void key(unsigned char key, int x, int y) = 0; virtual void reshape(int width, int height) = 0; virtual void idle() = 0; };
那么我需要传入的是Scene::display函数,此时将会出现函数类型不匹配的问题。因为Scene::display为Scene类的成员函数,类成员函数的实现方式是传入了一个默认的Scene *this参数,所以如果要使用成员函数,必须同时传入this指针,这与func类型冲突。
参考stackoverflow上的解决方法1:http://stackoverflow.com/questions/3589422/using-opengl-glutdisplayfunc-within-class
将Scene设计为一个单例类,定义static void displayCallback()函数,内部通过单例指针调用display函数,通过这种添加中间层的方式将带有默认this指针的函数转变为全局可访问的 void (*func)(void)函数。但其付出的代价就是不能创建多个场景实例,不过目前所做的是一个单场景,并不需要考虑此问题。
修改后代码如下:
/* file:Scene.h brief:创建一个opengl场景 */ #ifndef SCENE_H #define SCENE_H #include <string> #include "opengl.h" class Scene { public: Scene(std::string title, int width=1024, int height=768); virtual ~Scene(); /*初始化场景*/ virtual void init(int argc, char *argv[]) = 0; /*运行场景*/ virtual int run() = 0; void setupDisplayCallback() { currentInstance = this; ::glutDisplayFunc(Scene::displayCallback); } void setupKeyCallback() { currentInstance = this; ::glutKeyboardFunc(Scene::keyCallback); } void setupReshapeCallback() { currentInstance = this; ::glutReshapeFunc(Scene::reshapeCallback); } void setupIdleCallBack() { currentInstance = this; ::glutIdleFunc(Scene::idleCallback); } static void displayCallback() { currentInstance->display(); } static void keyCallback(unsigned char key, int x, int y) { currentInstance->key(key, x, y); } static void reshapeCallback(int width, int height) { currentInstance->reshape(width, height); } static void idleCallback() { currentInstance->idle(); } protected: std::string _title; int _height; int _width; /*绘制场景*/ virtual void display() = 0; /*键盘回调函数*/ virtual void key(unsigned char key, int x, int y) = 0; virtual void reshape(int width, int height) = 0; virtual void idle() = 0; private: static Scene * currentInstance; }; #endif // SCENE_H