ChinaMan
ChinaMan

Reputation: 39

OpenGL animation runs faster when glPushMatrix() and glPopMatrix() are removed

#include <iostream>
#include <GL/glut.h>
#include <math.h>

using namespace std;

#define WIDTH 400
#define HEIGHT 400

#include <math.h>
#define ColoredVertex(c, v) do{ glColor3fv(c); glVertex3fv(v); }while(0)

GLfloat angle = 0.0f;

void myDisplay(void)
{
     static int list = 0;
     if( list == 0 )
     {
         // 

         GLfloat
             PointA[] = { 0.5f, -sqrt(6.0f)/12, -sqrt(3.0f)/6},
             PointB[] = {-0.5f, -sqrt(6.0f)/12, -sqrt(3.0f)/6},
             PointC[] = { 0.0f, -sqrt(6.0f)/12,   sqrt(3.0f)/3},
             PointD[] = { 0.0f,    sqrt(6.0f)/4,              0};
         GLfloat
             ColorR[] = {1, 0, 0},
             ColorG[] = {0, 1, 0},
             ColorB[] = {0, 0, 1},
             ColorY[] = {1, 1, 0};

         list = glGenLists(1);
         glNewList(list, GL_COMPILE);
         glBegin(GL_TRIANGLES);
         // ABC
         ColoredVertex(ColorR, PointA);
         ColoredVertex(ColorG, PointB);
         ColoredVertex(ColorB, PointC);
         // ACD
         ColoredVertex(ColorR, PointA);
         ColoredVertex(ColorB, PointC);
         ColoredVertex(ColorY, PointD);
         // CBD
         ColoredVertex(ColorB, PointC);
         ColoredVertex(ColorG, PointB);
         ColoredVertex(ColorY, PointD);
         // BAD
         ColoredVertex(ColorG, PointB);
         ColoredVertex(ColorR, PointA);
         ColoredVertex(ColorY, PointD);
         glEnd();
         glEndList();

         glEnable(GL_DEPTH_TEST);
     }
     // 
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glPushMatrix();
     glRotatef(angle, 1, 0.5, 0);
     glCallList(list);
     glPopMatrix();
     glutSwapBuffers();
}

void myIdle(void)
{
     ++angle;
     if( angle >= 360.0f )
         angle = 0.0f;
     myDisplay();
}

int main(int argc, char* argv[])
{
     glutInit(&argc, argv);
     glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
     glutInitWindowPosition(200, 200);
     glutInitWindowSize(WIDTH, HEIGHT);
     glutCreateWindow("OpenGL window");
     glutDisplayFunc(&myDisplay);
     glutIdleFunc(&myIdle);
     glutMainLoop();
     return 0;
}

This is a quite basic example drawing a spinning tetrahedron. What I don't understand is the use of glPushMatrix() and glPopMatrix(). If I remove these codes, the program still works but the animation seems to perform way faster. I don't know what leads to that accelerration.
I've trid out another example to figure out the trick. I just change the myDisplay() function as follows.

void myDisplay(void){
     glEnable(GL_DEPTH_TEST);
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

     glMatrixMode(GL_PROJECTION);
     glLoadIdentity();
     gluPerspective(75, 1, 1, 400000000);
     glMatrixMode(GL_MODELVIEW);
     glLoadIdentity();
     gluLookAt(0, 0, 200000000, 0, 0, 0, 0, 1, 0);

     static int list = 0;
     static int earthList =0;

     if(list==0){
        list = glGenLists(1);

        glNewList(list, GL_COMPILE);
        glColor3f(1.0f, 0.0f, 0.0f);
        glutSolidSphere(69600000, 20, 20);
        glEndList();
     }
     if(earthList==0){
        earthList = glGenLists(1);

        glNewList(earthList, GL_COMPILE);
        glColor3f(0.0f, 0.0f, 1.0f);
        glutSolidSphere(15945000, 20, 20);
        glEndList();
     }

     // draw a red sun
     glCallList(list);

     // draw the earth
     //glPushMatrix();
     glRotatef(day/360.0*360.0, 0.0f, 0.0f, -1.0f);
     glTranslatef(150000000, 0.0f, 0.0f);
     glCallList(earthList);

     //glPopMatrix();

     glFlush();

     glutSwapBuffers();
} 

But this time, even if I remove the glPushMatrix() and glPopMatrix() functions, nothing appears to change. I don't see any difference. This really confuses me.
Can anyone explain what glPushMatrix() and glPopMatrix() do in these two examples?

Upvotes: 1

Views: 633

Answers (1)

JasonD
JasonD

Reputation: 16582

In GL, unless you specifically load a new matrix (glLoadIdentity() or similar) then matrix operations accumulate with whatever matrix is currently active. glPushMatrix() and glPopMatrix() allow you to store the current matrix on a stack, and retrieve it later, allowing you to make modifications which can be thrown away.

In your first example, removing glPushMatrix() and glPopMatrix() will result in the rotation being concatenated with the previous rotation, causing the rotation to rapidly accelerate (and I'd expect it to eventually reverse and go backwards as the angle goes beyond 180 degrees).

In your second example, you are reinitialising the model-view matrix with a glLoadIdentity() so there will be no such accumulation of transform.

Upvotes: 4

Related Questions