6
votes

From the code I have of a program that draws and moves a square around an application window, I'm having trouble when resizing the application window. When I handle a resize and alter states accordingly, everything on the screen that should be drawn and was before the resize vanishes. I have no idea why because none of the objects internal coordinates are changed during the window resizing.

My question is can anyone point me in the right direction to solve my problem.(The code compiles fine)

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

Main loop:

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

}

It all runs perfectly until the window is resized.

2
I saw your earlier question, but couldn't get around to pointing out all the problems at that time. I trust that you don't have solved your earlier problems. You should probably post the changes you made to get it working as your own answer and close the question.batbrat
Did my suggestions fix the problem?batbrat
I've been asleep since I posted this question, your answer makes sense, especially the bit about SDL_SetVideoMode, looking back at it, it seems like a silly mistake on my part. The earlier question I posted really had one problem which was another big mistake by me; I was working from memory and didn't look up the glOrtho parameters. I had it as going left to right as 0-0. I'll try your suggestions nowuser969416
The resize event is called SDL_WINDOWEVENT_RESIZED in sdl 2.0lubosz

2 Answers

14
votes

I've copy pasted your code and I'll explain what is going on line by line. It should help you see not only why the screen is going blank after a resize, but also help you remove stuff that you don't really need.

void ResizeWindow()
{

These next lines are good! You've obtained the new screen width and height from the resize event. I'm assuming that the event is accessible at this point in your code.

    screen_width = event.resize.w;
    screen_height = event.resize.h;

I doubt you need this call to SDL_SetViedoMode. I'd expect it to be used only while setting up the OpenGL window. I have no experience with using SDL currently, so I can't be certain. I did do a quick look up of the documentation and that seems to support using it the way I expected.

SDL_SetVideoMode(screen_width, screen_height, bpp, SDL_OPENGL | SDL_RESIZABLE | SDL_DOUBLEBUF);

Now we get to the interesting GL stuff. You've resized the viewport, which is necessary.

    glViewport(0, 0, screen_width, screen_height);

Now, you're making a new projection matrix to maintain the aspect ration (unless I'm mistaken). You've switched the matrix mode and set up an Orthographic projection matrix, which is sensible.

    glMatrixMode(GL_PROJECTION);
    glOrtho(0, screen_width, 0, screen_height, -1, 1);

Now, you set the projection matrix to identity, overwriting the old OpenGL projection matrix and undoing all the good work you did. This is the reason the screen went blank.

    glLoadIdentity();

Now, you switch to the model-view matrix and set it to identity, which isn't really necessary, so long as you are setting it correctly elsewhere.

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

I doubt you really need this next line. Why would you want to clear the screen after a resize, anyway? You do want to redraw it, but I'm sure your draw function will clear the screen and draw the object that will be called automatically after the refresh is done.

    glClear(GL_COLOR_BUFFER_BIT);

And you definitely don't need to re-set the current model-view matrix to identity for a second time. OpenGL is still in model-view mode and that matrix was already set to identity! Remember that OpenGL is a state machine!

    glLoadIdentity();
}
1
votes

One problem you probably have is, that resizing a window with SDL a new OpenGL context is created, which means that all the things you uploaded before (textures, vertex buffer objects) and state you set (like vertex array pointers) are lost. You need to reinitialize them if using SDL. If you want to keep them, don't use SDL for window management. I recommend GLFW.

This

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

}

is the most common anti pattern found in beginners OpenGL code. Drawing commands and state management that influences drawing belongs in the drawing function. That is the following:

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

If you want a robust OpenGL program never put them (only) into the resize handler. They belong with the other drawing commands.