Переключение обратного вызова дисплея в GLUT
Для финального проекта мы с друзьями делаем игру. Мы используем GLUT (я знаю, не лучший выбор). Мы хотели бы иметь несколько функций обратного вызова дисплея для разных режимов игры (например, заставки, экрана меню, экрана игрового процесса и т. Д.), Поэтому при изменении режима игры мы меняем обратный вызов. По сути, это похоже на возможность звонить glutDisplayFunc
пока GLUT работает. Это возможно? Мы неохотно имеем гигантский оператор if/switch в общей функции отображения, поскольку считаем, что это может снизить производительность. Если это беспокойство необоснованно, скажите, пожалуйста!
4 ответа
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, которая планирует что-то для запуска.
Этот вопрос довольно старый, но я наткнулся на этот ответ, ища решение точно такой же проблемы.
Я думаю, более элегантным подходом было бы использование указателей на функции. Сначала вы создаете указатель на функцию (может быть глобальным):
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;
и так далее...
Это позволяет вам оставаться внутри перенасыщенного основного цикла, не нарушая функций дисплея, и производительность также не пострадает, так как вы устанавливаете переключатель if/ только один раз. У вас есть только один дополнительный вызов функции, который должен пренебречь, учитывая количество вызовов функций, используемых для рисования ваших вещей в каждом отдельном кадре...
Этот код работает нормально для меня. Сначала в int main() вам нужно сначала вызвать display, а затем, добавив glutTimerFunc, через некоторое время вы можете вызвать другой display.
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);
}
}
Мы неохотно имеем гигантский оператор if/switch в общей функции отображения, поскольку считаем, что это может снизить производительность.
Конечно, это не лучший стиль кодирования, но производительность не является аргументом.
Вы можете сделать свою собственную систему, которая имитирует glutDisplayFunc
, лайк epicGameDisplayFunc
это изменяет указатель функции на переданную функцию.