Ortho2d view changed on re-display

Hi,

I’m trying out a zooming in-and-out with orthogonal projection. The following program changes the orthogonal projection between -200…200 by -200…200 (largest) to -100…100 by -100…100 (smallest). 4 triangles are drawn.

Everything seems to work fine if I let the program run on its own. (I don’t care about aspect ratio for now.)
But then I noticed something.

If I force a redisplay by covering my opengl program’s window completely with another window, I notice that frequently the objects have been scaled. The scaling can be quite random. Furthermore, if the program’s window is only partially covered and then revealed, everything would be fine and the 4 triangles are not scaled. The random scaling occur only when the program’s window is fully covered by another window. The same problem also occurs if I minimize and then maximize the program’s window.

However I notice that the display is fine if I just move the program’s window around.

Can someone explain what’s happening? I’m sure I’m missing something very important here.


#include <GL/freeglut.h>

const int M = 400;      // window is M-by-M
float x = M/2, y = M/2; // gluOrtho2d is set to -x....x by -y...y.

const float abs_d = 50; // speed of zooming
float d = -abs_d;       // velocity of zooming

int prev_time;

void display()
{
    // Calculate new x, y for new ortho2d viewing volume
    int curr_time = glutGet(GLUT_ELAPSED_TIME);
    float elapsed_time = (curr_time - prev_time) / 1000.0;
    prev_time = curr_time;
    if (elapsed_time <= 0) return;    
    float dt = elapsed_time; // shorthand
    x += d * dt;
    y += d * dt;
        
    if (x < 100) 
    {
        d = abs_d; // switch to zoom out 
        x = 100;
    }
    else if (x > M/2) 
    {
        d = -abs_d; // switch to zoom in
        x = M/2;
    }

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(-x, x, -y, y);

    // Draw 4 triangles
    glClear(GL_COLOR_BUFFER_BIT);

    glBegin(GL_TRIANGLES);

    glColor3f(1.0f, 0.0f, 0.0f);
    glVertex2f(0, 0);
    glVertex2f(-100, 0);
    glVertex2f(-100, 100);

    glColor3f(0.0f, 1.0f, 0.0f);
    glVertex2f(100, 0);
    glVertex2f(180, 0);
    glVertex2f(50, -100);

    glColor3f(0.0f, 0.0f, 1.0f);
    glVertex2f(-50, 0);
    glVertex2f(0, -100);
    glVertex2f(0, -150);

    glColor3f(0.5f, 0.5f, 0.5f);
    glVertex2f(100, 150);
    glVertex2f(50, 120);
    glVertex2f(100, 70);
    
    glEnd();        
    glutSwapBuffers();
}

void timer_callback(int x)
{
    glutPostRedisplay();
    glutTimerFunc(50, timer_callback, 0);
}

int main(int argc, char ** argv)
{
    glutInit(&argc, argv);
    glutInitWindowPosition(0, 0);
    glutInitWindowSize(M, M);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    glutCreateWindow("test");
    glClearColor(1.0, 1.0, 1.0, 0.0);
    glutDisplayFunc(display);
    
    glutTimerFunc(50, timer_callback, 0);
    prev_time = glutGet(GLUT_ELAPSED_TIME);
    glEnable(GL_SMOOTH);
    glutMainLoop();

    return 0;
}