使用OpenGL和SDL处理窗口大小调整

时间:2012-02-04 05:03:21

标签: 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 个答案:

答案 0 :(得分:14)

我已经复制粘贴了你的代码,我将解释一行一行的内容。它不仅可以帮助您了解调整大小后屏幕为何空白,还可以帮助您删除不需要的内容。

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

现在,您将投影矩阵设置为identity,覆盖旧的OpenGL投影矩阵并撤消您所做的所有好工作。这就是屏​​幕空白的原因。

    glLoadIdentity();

现在,您切换到模型视图矩阵并将其设置为identity,这不是必需的,只要您在其他地方正确设置它。

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

我怀疑你真的需要下一行。无论如何,为什么要在调整大小后清除屏幕?你确实想要重绘它,但我确定你的绘图功能会清除屏幕并绘制在刷新完成后自动调用的对象。

    glClear(GL_COLOR_BUFFER_BIT);

您绝对不需要重新设置当前模型视图矩阵以进行第二次识别。 OpenGL仍然处于模型视图模式,并且该矩阵已经设置为标识!请记住,OpenGL是状态机!

    glLoadIdentity();
}

答案 1 :(得分:1)

您可能遇到的一个问题是,使用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程序,永远不要把它们(仅)放入resize处理程序。它们属于其他绘图命令。