JMU
Scientific Animation
An Introduction


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Definitions
Common Types of Scientific Animation
Common Types of Scientific Animation (cont.)
An Easy Approach
Example: A Spinning Globe
Example: A Spinning Globe (cont.)
Handling "Ticks"
svaexamples/cartography/globe-rotating.c (Fragment: onTimer)
        /**
 * The timer callback
 *
 * @param value   The animation time (in milliseconds)
 */
void onTimer(int value)
{

   if (rotation == ROTATING)
   {
      // Update the rotation angle (for the current axis
      // of rotation)
      angle += 2.0;
      if(angle > 360.0) angle -= 360.0;
      svaSetRotation(0.0, angle, 0.0);
   }
   else if (rotation == RESETTING)
   {
      angle = 0.0;      
      svaSetRotation(0.0, angle, 0.0);
      rotation = STOPPED;
   }
}
        
Example: A Spinning Globe (cont.)
Rendering Each Frame is Done as in our Earlier Visualization
svaexamples/cartography/globe-rotating.c (Fragment: onDisplay)
        /**
 * The display callback
 */
void onDisplay()
{
   double                              alpha;   
   feature                             *f;
   GLenum                              type;   
   GLfloat                             v[3];
   

   for (int i=0; i<numberOfFeatures; i++)
   {
      // Get the Feature
      f = &features[i];


      // Determine the Feature's type
      if      (strcmp(f->type, "POLYGON") == 0)    type = GL_POLYGON;
      else if (strcmp(f->type, "LINE_STRIP") == 0) type = GL_LINE_STRIP;
      else                                         type = GL_POINTS;

      // Begin the graphics primitive
      glBegin(type);
      {
         glColor3fv(colors[f->id]);
         
         for (int j=0; j<f->size; j++)
         {
            // Use the Cartesian coordinates
            v[0] = f->x[j];
            v[1] = f->y[j];
            v[2] = f->z[j];
            
            glVertex3fv(v);
         }
      }
      glEnd();
   }
}
        
Example: A Spinning Globe (cont.)
Starting and Stopping the Animation
svaexamples/cartography/globe-rotating.c (Fragment: onMouseClick)
        /**
 * The mouse callback (i.e., the function that is called
 * each time a mouse button is pressed or released).
 *
 * @param button The button (e.g., SVA_LEFT_BUTTON)
 * @param state  The state (e.g., SVA_UP or SVA_DOWN)
 * @param x      The x-position of the mouse
 * @param y      The y-position of the mouse
 */
void onMouseClick(int button, int state, GLfloat x, GLfloat y)
{
   if (state == SVA_DOWN)
   {
      if(button == SVA_LEFT_BUTTON)
      {
         if      (rotation == STOPPED)  rotation = ROTATING;
         else if (rotation == ROTATING) rotation = STOPPED;
      }
      else if(button == SVA_RIGHT_BUTTON)
      {
         rotation = RESETTING;
      }
   }
}
        
Example: A Globe that Unfolds
Example: A Globe that Unfolds (cont.)
Handling "Ticks"
svaexamples/cartography/globe-unfolding.c (Fragment: onTimer)
        /**
 * The timer callback
 */
void onTimer(int value)
{
   if (status == UNFOLDING)
   {
      svaSetRotation(0.0, 0.0, 0.0);

      step++;
      if (step > NUMSTEPS) step = NUMSTEPS;
   }
   else if (status == STOPPED)
   {
      step = 0;      
   }
}
        
Example: A Globe that Unfolds (cont.)
Rendering Each Frame
svaexamples/cartography/globe-unfolding.c (Fragment: onDisplay)
        /**
 * The display callback
 */
void onDisplay()
{
   feature                             *f;
   float                               alpha;   
   GLenum                              type;   
   GLfloat                             v[3];
   

   for (int i=0; i<numberOfFeatures; i++)
   {
      // Get the Feature
      f = &features[i];

      // Determine the Feature's type
      if      (strcmp(f->type, "POLYGON") == 0)    type = GL_POLYGON;
      else if (strcmp(f->type, "LINE_STRIP") == 0) type = GL_LINE_STRIP;
      else                                         type = GL_POINTS;

      // Begin the graphics primitive
      glBegin(type);
      {
         glColor3fv(colors[f->id]);
         
         for (int j=0; j<f->size; j++)
         {
            if (status == STOPPED)
            {
               // Use the Cartesian coordinates
               v[0] = f->x[j];
               v[1] = f->y[j];
               v[2] = f->z[j];
            }
            else if (status == UNFOLDING)
            {
               // Interpolate between Cartesian and projected coordinates
               alpha = (float)step / NUMSTEPS;
               
               v[0] = (1.-alpha)*f->x[j] + alpha*f->xProj[j];
               v[1] = (1.-alpha)*f->y[j] + alpha*f->yProj[j];
               v[2] = (1.-alpha)*f->z[j] + alpha*1.0;
            }
            
            glVertex3fv(v);
         }
      }
      glEnd();
   }
}
        
Example: A Crawling Inchworm
Example: A Crawling Inchworm (cont.)
Describing the Curve
svaexamples/curves/inchy.c (Fragment: data)
        GLfloat   data[][3] = { {-1.0,  0.0,  0.0}, // p1
                        { 0.0,  0.0,  0.0}, // c1
                        {-1.0,  0.0,  0.0}, // c2
                        { 0.0,  0.0,  0.0}  // p2
                     };
        
Example: A Crawling Inchworm (cont.)
Rendering the Curve
svaexamples/curves/inchy.c (Fragment: onDisplay)
        /**
 * The display callback
 */
void onDisplay()
{
   GLfloat      v[3];
   

   // Clear the screen
   glClear(GL_COLOR_BUFFER_BIT);

   // Set the color
   glColor3f(1.0, 0.0, 0.0);

   // Create the mapping
   glMap1f(GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, &data[0][0]);


   // Draw the curve, piece by piece
   glBegin(GL_LINE_STRIP);
   {
      for (int i=0; i<100; i++)
      {
         glEvalCoord1f(((float)i)/100.0);             
      }
   }
   glEnd();


   // Instead of the above, one could use:
   //
   // glMapGrid1f(100, 0.0, 1.0 );         
   // glEvalMesh1(GL_LINE, 0, 100);
}
        
Example: A Crawling Inchworm (cont.)
Handling "Ticks"
svaexamples/curves/inchy.c (Fragment: onTimer)
        /**
 * The timer callback
 */
void onTimer(int time)
{
   if (status != STOPPED) frame++;
   
   if (status == BACK_MOVING)
   {
      // Move p1
      data[0][0] += 0.05;      

      // Move c2
      data[2][0] += 0.05;      
      data[2][1] += 0.05;      

      if (frame == 10) 
      {
         frame = 0;      
         status = FRONT_MOVING;         
      }
   }
   else if (status == FRONT_MOVING)
   {
      // Move p2
      data[3][0] += 0.05;      

      // Move c1
      data[1][0] += 0.05;      

      // Move c2
      data[2][1] -= 0.05;      

      if (frame == 10) 
      {
         frame = 0;      
         status = BACK_MOVING;
      }
   }
}