Обработка изменения размера окна с использованием OpenGL и SDL - PullRequest
6 голосов
/ 04 февраля 2012

Из кода программы, которая рисует и перемещает квадрат вокруг окна приложения, у меня возникают проблемы при изменении размера окна приложения. Когда я обрабатываю соответственно изменение размера и состояния, все на экране, которое должно быть нарисовано и было до изменения размера, исчезает. Я понятия не имею, почему, поскольку ни один из внутренних координат объектов не изменяется во время изменения размера окна.

Мой вопрос: может ли кто-нибудь направить меня в правильном направлении, чтобы решить мою проблему. (Код прекрасно компилируется)

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 ]

14 голосов
/ 04 февраля 2012

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

void ResizeWindow()
{

Эти следующие строки хороши!Вы получили новые ширину и высоту экрана из события изменения размера.Я предполагаю, что событие доступно в этот момент в вашем коде.

    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();

Теперь вы переключаетесь на матрицу вида модели и устанавливаете ее на идентичность, которая на самом деле не нужна, если вы правильно ее устанавливаете в другом месте..

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

Я сомневаюсь, что вам действительно нужна эта следующая строка.Почему вы хотите очистить экран после изменения размера?Вы действительно хотите перерисовать его, но я уверен, что ваша функция рисования очистит экран и нарисует объект, который будет вызываться автоматически после завершения обновления.

    glClear(GL_COLOR_BUFFER_BIT);

И вам определенно не нужночтобы повторно установить текущую матрицу вида модели на идентичность во второй раз.OpenGL все еще находится в режиме просмотра модели, и эта матрица уже установлена ​​на идентичность!Помните, что OpenGL - это конечный автомат!

    glLoadIdentity();
}
1 голос
/ 04 февраля 2012

Одна из проблем, с которой вы, вероятно, сталкиваетесь, заключается в том, что при изменении размера окна с помощью 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, никогда не помещайте их (только) в обработчик изменения размера. Они принадлежат другим командам рисования.

...