6

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.

Martin G
  • 17,357
  • 9
  • 82
  • 98
  • 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 Feb 04 '12 at 08:01
  • Did my suggestions fix the problem? – batbrat Feb 04 '12 at 12:36
  • 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 now –  Feb 04 '12 at 12:50
  • The resize event is called `SDL_WINDOWEVENT_RESIZED` in sdl 2.0 – lubosz Mar 08 '20 at 14:33

2 Answers2

14

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();
}
batbrat
  • 5,155
  • 3
  • 32
  • 38
2

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.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • I think I see what you are saying. Is there really no minimal-effort way to keep the program running normal when resizing in SDL? –  Feb 04 '12 at 13:05
  • So he does need the call to SDL_SetVideoMode? On a separate note, isn't it sensible to resize the viewport and set the projection both at the start and during resize? In fact, if I want to preserve aspect ratio, I think it's essential. As for the modelview matrix, I'd set it during drawing as needed. Of course, this isn't taking into account modern OpenGL practices and considers immediate mode alone. – batbrat Feb 04 '12 at 13:08
  • I do agree that state management and drawing commands should go in the draw function. However, I've found it convenient to have the projection matrix and the viewport set in the resize function (and the initialization function) when doing simple stuff. – batbrat Feb 04 '12 at 13:10
  • The call to SDL_SetVideoMode would have to be in the resizing code somewhere. What I'm now wondering is how to completely reset the matrix's if at all possible so i can start from scratch when the window is resized if at all possible –  Feb 04 '12 at 13:11
  • Although the more I think about it all, the more I seem to think it's just not possible to handle resizing in OpenGL and SDL (At least not the way I'm trying to go about it anyway) –  Feb 04 '12 at 13:13
  • @batbrat: Setting the projection and viewport in the resize handler will bite you, as soon as you want to draw a minimap, HUD overlay or just use framebuffer objects. As soon as you want to do any of those you need to put the viewport/projection setting into the drawing function. If you don't do this from the start you may introduce some structures relying on the setting in the resize handler, which you then have to rebuild from scratch. So just do it in the drawing function from the very beginning to save you a lot of trouble in the long term. – datenwolf Feb 04 '12 at 14:54
  • @Michael: Window resizing is not a problem for OpenGL, but it is for SDL. Because of that my suggestion to not use it. Use GLFW or SMFL. – datenwolf Feb 04 '12 at 14:55
  • 1
    Okay I understand that. My aim is to learn OpenGL. SDL was suggested by a relative because of its ease of use whilst I was beginning to program. I'll try out your suggestion of GLFW. Thank you for your help –  Feb 04 '12 at 14:58
  • @datenwolf Ah! As I suspected, you're dealing with something more complicated than really basic programs. Obviously, when I want to do any of the above, I would put the viewport/projection setting with the draw code. It depends on the use case, if you ask me. Why should anyone do what they don't need so long as they are aware of the issues. I'm glad you brought that up though. Thanks. – batbrat Feb 04 '12 at 15:09
  • @Michael, I've used freeglut, Qt and FLTK while writing simple stuff. I don't think you should quit on SDL really. What you should do depends on what you need to get done. Research it a bit and then decide. – batbrat Feb 04 '12 at 15:11
  • @batbrat: Qt and FLTK would be overkill. GLFW is very much like SDL, actually most of the SDL calls can be replaced 1:1 with the apropriate functions from SDL. That's why I suggested GLFW in the first place. The transistion effort is minimal. – datenwolf Feb 04 '12 at 15:20
  • For now I was happy to just have a play around with code and build on a program that moves a square around the screen. I want to eventually make a simple FPS game in OpenGL that uses textures and then move onto other areas of programming such as WinAPI and networking. Thank you both for the suggestions and help in this question though. –  Feb 04 '12 at 16:27