在 GLUT 中切换显示回调

Switching Display Callback in GLUT

本文关键字:显示 回调 GLUT      更新时间:2023-10-16

对于最终项目,我和我的朋友们正在制作一个游戏。我们正在使用GLUT(我知道,不是最好的选择)。我们要做的是针对游戏的不同模式(例如初始屏幕、菜单屏幕、游戏屏幕等)具有多个显示回调函数,因此当游戏模式发生变化时,我们会更改回调。所以实际上,这有点像能够在 GLUT 运行时调用glutDisplayFunc。这可能吗?我们不愿意在整个显示函数中使用巨大的 if/switch 语句,因为我们认为这可能会妨碍性能。如果这种担心是没有根据的,请说出来!

glutDisplayFunc 将指向显示场景的指针作为参数。使用多个显示函数的最简单方法是使用要切换到的显示场景函数指针调用 glutDisplayFunc。

void render1() {
    //.. display something
}
void render2() {
    //.. display something else
}
//...
void someEvent() {
    if(iWantToRender1) {
        glutDisplayFunc(render1);
        glutIdleFunc(render1);
    } else {
        glutDisplayFunc(render2);
        glutIdleFunc(render2);
    }
}

这与在 render1/render2 中使用 if/else 不同,因为它会更改要调用的函数。如果您查看 GLUT 的文档,http://www.opengl.org/resources/libraries/glut/spec3/node46.htmlglutDisplayFunc 更改当前窗口的显示函数,而不是执行像 glutTimerFunc 这样调度要运行的内容的操作。

这个问题有点老了,但我在寻找完全相同问题的解决方案时偶然发现了这个答案。

我认为,更优雅的方法是使用函数指针。首先,创建一个函数指针(可能是全局的):

void (*foo)(void);

之后,您可以创建不同的绘图功能,例如:

void draw_1()    
{    
  /* Draw fancy stuff */
}
void draw_2()
{
  /* Draw other fancy stuff */
}

现在你需要一个"mainloop-mainloop"函数,它由glutMainLoop调用,它指的是你的指针:

void mainloop_mainloop()
{    
  (*foo)();
}

正如我所说,这个函数必须是你的glutMainLoop,所以你设置它:

glutDisplayFunc(mainloop_mainloop);
glutIdleFunc(mainloop_mainloop);

当然,您必须在某处设置函数指针:

foo = &draw_1;

如果您现在希望切换到另一个绘图上下文,则只需更改指针即可。例如,您可以在菜单中实现这一点:

if (menuentry==1) foo = &draw_1;
if (menuentry==2) foo = &draw_2;

等等...

这使您能够保持在 glut 主循环内而不会弄乱显示功能,并且性能也不会受到损害,因为您只设置 if/switch 一次。你只有一个额外的函数调用,考虑到用于绘制每一帧内容的函数调用的数量,这应该可以忽略不计......

我们不愿意在整个显示函数中使用巨大的 if/switch 语句,因为我们认为这可能会妨碍性能。

它当然不是最好的编码风格,但性能不是争论。

您可以创建自己的模拟glutDisplayFunc的系统,例如更改指向所传递函数的函数指针的epicGameDisplayFunc

这段代码对我来说工作正常。首先在int main()中,您必须首先调用显示,然后添加glutTimerFenc,您可以在一定时间后调用另一个显示器。

void MyTimerFunc(int value);
int main(int argc, char **argv)
{
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA|GLUT_DEPTH);
    glutInitWindowSize(700,500);
    glutInitWindowPosition(0,0);
    glutCreateWindow("Animated Road Crossing Alert System");
    initOpenGl();
    glutDisplayFunc(display);
    glutIdleFunc(display);
    glutTimerFunc(20000, MyTimerFunc, 0);
    glutMainLoop();
    return 0;
}
void MyTimerFunc(int value)
{
   if (value == 0) // passed in in main
   {
      glutDisplayFunc(display1);
      glutIdleFunc(display1);
      // Change to a new display function in 2 seconds
      glutTimerFunc(40000, MyTimerFunc, 1);
   }
   else if(value==1)
   {
     glutDisplayFunc(display2);
     glutIdleFunc(display2);
   }
}