Переключение обратного вызова дисплея при перенасыщении

#c #opengl #callback #glut #switching

#c #opengl #обратный вызов #перенасыщение #переключение

Вопрос:

Для окончательного проекта мы с друзьями создаем игру. Мы используем GLUT (я знаю, не лучший выбор). Что мы хотели бы сделать, так это иметь несколько функций обратного вызова дисплея для разных режимов игры (например, экран-заставка, экран меню, экран игрового процесса и т.д.), Чтобы при изменении режима игры мы меняли обратный вызов. Таким образом, по сути, это похоже на возможность вызывать glutDisplayFunc во время выполнения GLUT. Возможно ли это? Мы неохотно используем гигантский оператор if / switch в общей функции отображения, потому что считаем, что это может снизить производительность. Если это беспокойство необоснованно, пожалуйста, скажите об этом!

Ответ №1:

glutDisplayFunc принимает указатель на сцену отображения в качестве аргумента. Самый простой способ использовать несколько функций отображения — это просто вызвать glutDisplayFunc с указателем функции отображения сцены, на которую вы хотите переключиться.

т. е.

 void render1() {
    //.. display something
}

void render2() {
    //.. display something else
}

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

Это отличается от использования if / else в render1 / render2, потому что это изменяет, какую функцию вызывать. Если вы посмотрите на документацию GLUT, http://www.opengl.org/resources/libraries/glut/spec3/node46.html
glutDisplayFunc изменяет функцию отображения текущего окна, вместо того, чтобы выполнять что-то вроде glutTimerFunc, который планирует запуск чего-либо.

Ответ №2:

Этот вопрос довольно старый, но я наткнулся на этот ответ, когда искал решение точно такой же проблемы.

Я думаю, более элегантным подходом было бы использование указателей на функции. Сначала вы создаете указатель на функцию (может быть глобальным):

 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 = amp;draw_1;
  

Если вы теперь хотите переключиться на другой контекст рисования, вам просто нужно изменить указатель. Вы могли бы реализовать это, например, в меню:

 if (menuentry==1) foo = amp;draw_1;

if (menuentry==2) foo = amp;draw_2;
  

и так далее…

Это позволяет вам оставаться внутри основного цикла glut, не нарушая функции отображения, и производительность также не пострадает, поскольку вы устанавливаете if / switch только один раз. У вас есть только один дополнительный вызов функции, которым следует пренебречь, учитывая количество вызовов функций, используемых для отрисовки вашего материала в каждом отдельном кадре…

Ответ №3:

Мы неохотно используем гигантский оператор if / switch в общей функции отображения, потому что считаем, что это может снизить производительность.

Это, конечно, не лучший стиль кодирования, но производительность не является аргументом.

Вы можете создать свою собственную систему, которая имитирует, glutDisplayFunc например epicGameDisplayFunc , которая изменяет указатель функции на переданную функцию.

Ответ №4:

У меня этот код работает нормально. Сначала в int main () вы должны вызвать первый display, а затем, добавив glutTimerFunc, вы можете вызвать другой display через определенное время.

 void MyTimerFunc(int value);

int main(int argc, char **argv)
{
    glutInit(amp;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);
   }

}