Обработка изменения размера окна с помощью OpenGL и SDL
Из кода программы, которая рисует и перемещает квадрат вокруг окна приложения, у меня возникли проблемы при изменении размера окна приложения. Когда я обрабатываю изменение размера и соответственно изменяю состояния, все на экране, что должно быть нарисовано и было до изменения размера, исчезает. Я понятия не имею, почему, потому что ни один из внутренних координат объектов не изменяется во время изменения размера окна.
Мой вопрос заключается в том, может ли кто-нибудь указать мне правильное направление для решения моей проблемы.(Этот код компилируется отлично)
void ResizeWindow()
{
screen_width = event.resize.w;
screen_height = event.resize.h;
SDL_SetVideoMode(screen_width, screen_height, bpp, SDL_OPENGL | SDL_RESIZABLE | SDL_DOUBLEBUF);
glViewport(0, 0, screen_width, screen_height);
glMatrixMode(GL_PROJECTION);
glOrtho(0, screen_width, 0, screen_height, -1, 1);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glClear(GL_COLOR_BUFFER_BIT);
glLoadIdentity();
}
Основной цикл:
while (running == true)
{
while(SDL_PollEvent(&event))
{
switch(event.type)
{
case SDL_VIDEORESIZE: ResizeWindow(); break; // resizing called here
case SDL_QUIT: running = false; break;
case SDL_KEYDOWN: square.Handle_Input(down); break;
case SDL_KEYUP: square.Handle_Input(up); break;
}
}
square.Move();
square.Check_Collision();
glClear(GL_COLOR_BUFFER_BIT);
square.Draw();
SDL_GL_SwapBuffers();
}
Все это работает идеально, пока размер окна не будет изменен.
2 ответов:
Я скопировал ваш код и объясню, что происходит строка за строкой. Это должно помочь вам увидеть не только то, почему экран становится пустым после изменения размера, но и помочь вам удалить вещи, которые вам на самом деле не нужны.
void ResizeWindow() {Эти следующие строки хороши! Вы получили новую ширину и высоту экрана из события resize. Я предполагаю, что событие доступно в данный момент в вашем коде.
Я сомневаюсь, что вам нужен этот звонок вscreen_width = event.resize.w; screen_height = event.resize.h;SDL_SetViedoMode. Я бы ожидал, что он будет использоваться только при настройке окна OpenGL. В настоящее время у меня нет опыта использования SDL, поэтому я не могу быть уверен. Я сделал быстрый просмотр документации, и это, кажется, поддерживает использование его так, как я ожидал.SDL_SetVideoMode(screen_width, screen_height, bpp, SDL_OPENGL | SDL_RESIZABLE | SDL_DOUBLEBUF);Теперь мы переходим к интересному материалу GL. Вы изменили размер окна просмотра, что необходимо.
Теперь вы создаете новую проекционную матрицу для поддержания соотношения сторон (если я не ошибаюсь). Вы переключили режим матрицы и настроили орфографический режим. проекционная матрица, что вполне разумно.glViewport(0, 0, screen_width, screen_height);Теперь вы устанавливаете проекционную матрицу на идентичность, перезаписывая старую проекционную матрицу OpenGL и отменяя все хорошие работы, которые вы сделали. Вот почему экран погас.glMatrixMode(GL_PROJECTION); glOrtho(0, screen_width, 0, screen_height, -1, 1);Теперь вы переключаетесь на матрицу представления модели и устанавливаете ее на identity, что на самом деле не обязательно, если вы устанавливаете ее правильно в другом месте.glLoadIdentity();Я сомневаюсь, что вам действительно нужна эта следующая строка. Почему вы хотите очистить экран во всяком случае, после изменения размера? Вы хотите перерисовать его, но я уверен, что ваша функция рисования очистит экран и нарисует объект, который будет вызван автоматически после обновления.glMatrixMode(GL_MODELVIEW); glLoadIdentity();И вам определенно не нужно повторно устанавливать текущую матрицу представления модели на идентичность во второй раз. OpenGL все еще находится в режиме просмотра модели, и эта матрица уже настроена на идентификацию! Помните, что OpenGL-это государственная машина!glClear(GL_COLOR_BUFFER_BIT);glLoadIdentity(); }
Одна из проблем, с которой вы, вероятно, сталкиваетесь, заключается в том, что при изменении размера окна с SDL создается новый контекст OpenGL, что означает, что все вещи, загруженные ранее (текстуры, объекты буфера вершин) и состояние, которое вы установили (например, указатели массива вершин), теряются. Вам нужно повторно инициализировать их, если вы используете SDL. Если вы хотите сохранить их, не используйте SDL для управления окнами. Я рекомендую GLFW.
Это
void ResizeWindow() { screen_width = event.resize.w; screen_height = event.resize.h; SDL_SetVideoMode(screen_width, screen_height, bpp, SDL_OPENGL | SDL_RESIZABLE | SDL_DOUBLEBUF); glViewport(0, 0, screen_width, screen_height); glMatrixMode(GL_PROJECTION); glOrtho(0, screen_width, 0, screen_height, -1, 1); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity(); }Является наиболее распространенным анти-паттерном, найденным в коде OpenGL для начинающих. Команды рисования и управление состоянием, влияющее на рисование, относится к функции рисования. Это означает следующее:
glViewport(0, 0, screen_width, screen_height); glMatrixMode(GL_PROJECTION); glOrtho(0, screen_width, 0, screen_height, -1, 1); glLoadIdentity(); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClear(GL_COLOR_BUFFER_BIT); glLoadIdentity();Если вам нужна надежная программа OpenGL, никогда не помещайте их (только) в обработчик изменения размера. Они принадлежат другим командам рисования.
Comments