JMU
Animation in OpenGL
An Introduction


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Definitions
A Simple Animation Loop
  1. Transform the content
  2. Render the content "off screen"
  3. Clear the screen
  4. Move the off-screen "image" to the screen
The Content
openglexamples/basics/animation.c (Fragment: content)
        // Face colors
GLfloat colors[][3] = {
    { 1.0, 0.0, 0.0 },
    { 1.0, 1.0, 0.0 },
    { 0.0, 1.0, 0.0 },
    { 0.0, 0.0, 1.0 },
    { 1.0, 0.0, 1.0 },
    { 0.0, 1.0, 1.0 } };

// Faces of the cube
GLint faces[][4] = {
    { 4, 5, 6, 7 },
    { 1, 2, 6, 5 },
    { 0, 1, 5, 4 },
    { 0, 3, 2, 1 },
    { 0, 4, 7, 3 },
    { 2, 3, 7, 6 } };

// Vertices
GLfloat vertices[][3] = {
    { -1.0, -1.0, -1.0 },
    {  1.0, -1.0, -1.0 },
    {  1.0,  1.0, -1.0 },
    { -1.0,  1.0, -1.0 },
    { -1.0, -1.0,  1.0 },
    {  1.0, -1.0,  1.0 },
    {  1.0,  1.0,  1.0 },
    { -1.0,  1.0,  1.0 } };
        
Initialization
openglexamples/basics/animation.c (Fragment: init)
        /**
 * The entry point of the application.
 *
 * @param argc  The number of command line arguments
 * @param argv  The array of command line arguments
 * @return      A status code
 */
int main(int argc, char **argv) {
  glutInit(&argc, argv);

  // Enable double-bufferng, RGB colors, and depth buffering
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);

  glutInitWindowSize(500, 500);
  glutCreateWindow("Animation");

  // Callbacks
  glutReshapeFunc(reshape);
  glutDisplayFunc(display);
  glutMouseFunc(mouse);

  // Enable necesssary functionality
  glEnable(GL_DEPTH_TEST);

  // Start the event loop
  glutMainLoop();
}
        
Updating the Content
openglexamples/basics/animation.c (Fragment: update)
        /**
 * Update the content
 */
void update() {
  // Update the rotation angle (for the current axis
  // of rotation)
  angle[axis] += 2.0;

  if (angle[axis] > 360.0)
    angle[axis] -= 360.0;

  // Make the modelview matrix current
  glMatrixMode(GL_MODELVIEW);

  // Clear the modelview matrix
  glLoadIdentity();

  // Concatenate the three rotations
  glRotatef(angle[0], 1.0, 0.0, 0.0);
  glRotatef(angle[1], 0.0, 1.0, 0.0);
  glRotatef(angle[2], 0.0, 0.0, 1.0);
}
        
Rendering/Displaying the Content
openglexamples/basics/animation.c (Fragment: display)
        /**
 * The display callback
 */
void display() {
  // Clear the screen
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

  // Draw the cube
  for (int f = 0; f < 6; f++) {
    glBegin(GL_POLYGON);
    glColor3fv(colors[f]);
    for (int i = 0; i < 4; i++) {
      int v;
      v = faces[f][i];

      glVertex3fv(vertices[v]);
    }
    glEnd();
  }

  // Force the rendering (off-screen)
  glFlush();

  // Handle the double buffering
  glutSwapBuffers();
}
        
A Common (Bad) Way to Animate
Animate as Fast as You Can
openglexamples/basics/badanimation.c (Fragment: setupIdle)
          glutIdleFunc(idle);
        
openglexamples/basics/badanimation.c (Fragment: idle)
        /**
 * The idle callback
 */
void idle() {
  // Update the content
  update();

  // Request a callback to the DisplayFunc
  glutPostRedisplay();
}
        
The Correct Way to Animate
Use a Timer
openglexamples/basics/animation.c (Fragment: setupTimer)
          glutTimerFunc(delay, timer, 0);
        
openglexamples/basics/animation.c (Fragment: timer)
        /**
 * The timer callback
 */
void timer(int value) {
  // Update the content
  update();

  // Request a callback to the DisplayFunc
  glutPostRedisplay();

  // Re-start the timer
  glutTimerFunc(delay, timer, 0);
}