Обработка изменения размера окна с помощью 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();

}


Все это работает идеально, пока размер окна не будет изменен.

567   2  

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);
Теперь вы создаете новую проекционную матрицу для поддержания соотношения сторон (если я не ошибаюсь). Вы переключили режим матрицы и настроили орфографический режим. проекционная матрица, что вполне разумно.
    glMatrixMode(GL_PROJECTION);
    glOrtho(0, screen_width, 0, screen_height, -1, 1);
Теперь вы устанавливаете проекционную матрицу на идентичность, перезаписывая старую проекционную матрицу OpenGL и отменяя все хорошие работы, которые вы сделали. Вот почему экран погас.
    glLoadIdentity();
Теперь вы переключаетесь на матрицу представления модели и устанавливаете ее на identity, что на самом деле не обязательно, если вы устанавливаете ее правильно в другом месте.
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
Я сомневаюсь, что вам действительно нужна эта следующая строка. Почему вы хотите очистить экран во всяком случае, после изменения размера? Вы хотите перерисовать его, но я уверен, что ваша функция рисования очистит экран и нарисует объект, который будет вызван автоматически после обновления.
    glClear(GL_COLOR_BUFFER_BIT);
И вам определенно не нужно повторно устанавливать текущую матрицу представления модели на идентичность во второй раз. OpenGL все еще находится в режиме просмотра модели, и эта матрица уже настроена на идентификацию! Помните, что OpenGL-это государственная машина!
    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

    Ничего не найдено.