Syllabus   Blank Homework   Quizzes  
Notes   Labs   Scores   Blank

Lecture Notes
Dr. Tong Lai Yu, 2010
    1. Introduction
    2. OpenGL Shading Language ( GLSL ) I
    3. GLSL II
    4. Curve and Surface Design
    5. Modeling Shapes with Polygonal Meshes
    6. Texture Mapping
    7. Casting Shadows
    8. Tools for Raster Display
    9. Parsing External Objects

    Tools for Raster Display

    1. Rasterization

    2. Geometric entities are rasterized into fragments
    3. Each fragment corresponds to a point on an integer grid: a displayed pixel Hence each fragment is a potential pixel
    4. Each fragment has
      • A color
      • Possibly a depth value
      • Texture coordinates

      Viewport
      Transformation
      Rasterization
       
      Per fragment
      operations
      Screen
      display

    5. Pixel values for display are saved in a frame buffer. ( Can be in video card or main memory. )
    6. Manipulating Pixmaps

      pixmap ( pixel map ) -- a rectangular array of numerical values

      Pixmap Operations:

    7. Drawing a Picture

      Can be done by directly writing to the frame buffer.

    8. Copying a Pixmap from one region to another

      glReadPixel()     Reads a region of the frame buffer into off-screen memory.
      glCopyPixel()     Copy a region of the frame buffer into another region of the frame buffer.
      glDrawPixel()     Draws a given pixmap ( save in a buffer array ) into the frame buffer.

    9. Scaling and Rotating a Pixmap

    10. Comparing Two Pixmaps

    11. Representing and Coloring Regions in a Pixmap
      pattern recognition, region filling
    12. Pixmaps Data Types

      bitmap: each pixel is stored in one single bit, either on or off
      grayscale:     single byte, 0 for black, 255 for white
      LUT indices:     Each pixel contains a number that represents an index into a color look-up table ( LUT )
      RGB pixmap:     Each pixel conists of 3 bytes for Red, Green, Blue ( true color )
      RGBA pixmap:     Each pixel conists of 4 bytes for Red, Green, Blue, Alpha

      Manipulating Image Data

      void glReadPixels( GLint x, GLint y, GLsizei width, GLsizei height,
                             GLenum format, GLenum type, GLvoid *pixels );
      Reads a block of pixels from the frame buffer.
      	 x, y 
      	       Specify the window coordinates of the first pixel that
      	       is read from the	frame buffer.  This location is	the
      	       lower left corner of a rectangular block	of pixels.
      
      	  width, height
      	       Specify the dimensions of the pixel rectangle.  width
      	       and height of one correspond to a single	pixel.
      
      	  format
      	       Specifies the format of the pixel data.	The following
      	       symbolic	values are accepted:  GL_COLOR_INDEX,
      	       GL_STENCIL_INDEX, GL_DEPTH_COMPONENT, GL_RED, GL_GREEN,
      	       GL_BLUE,	GL_ALPHA, GL_RGB, GL_RGBA, GL_LUMINANCE, and
      	       GL_LUMINANCE_ALPHA.
      
      	  type 
      	       Specifies the data type of the pixel data.  Must	be one
      	       of GL_UNSIGNED_BYTE, GL_BYTE, GL_BITMAP,
      	       GL_UNSIGNED_SHORT, GL_SHORT, GL_UNSIGNED_INT, GL_INT,
      	       or GL_FLOAT.
      
      	  pixels
      	       Returns the pixel data.

      void glDrawPixels( GLsizei width, GLsizei height, GLenum format,
                             GLenum type, GLvoid *pixels );
      Writes a block of pixels to the frame buffer.
        	width, height	Specify	the dimensions of the pixel rectangle
      			to be written into the frame buffer.
      
      	  format	Specifies the format of	the pixel data.
      			Symbolic constants GL_COLOR_INDEX,
      			GL_STENCIL_INDEX, GL_DEPTH_COMPONENT, GL_RGBA,
      			GL_RED,	GL_GREEN, GL_BLUE, GL_ALPHA, GL_RGB,
      			GL_LUMINANCE, and GL_LUMINANCE_ALPHA are
      			accepted.
      
      	  type		Specifies the data type	for pixels.  Symbolic
      			constants GL_UNSIGNED_BYTE, GL_BYTE,
      			GL_BITMAP, GL_UNSIGNED_SHORT, GL_SHORT,
      			GL_UNSIGNED_INT, GL_INT, and GL_FLOAT are
      			accepted.
      
      	  pixels	Specifies a pointer to the pixel data.
          

      void glCopyPixels( GLint x, GLint y, GLsizei width, GLsizei height,
                             GLenum type );
      Copies pixels in the frame buffer
        	x, y 
      	       Specify the window coordinates of the lower left	corner
      	       of the rectangular region of pixels to be copied.
      
      	  width, height
      	       Specify the dimensions of the rectangular region	of
      	       pixels to be copied.  Both must be nonnegative.
      
      	  type Specifies whether color values, depth values, or
      	       stencil values are to be	copied.	 Symbolic constants
      	       GL_COLOR, GL_DEPTH, and GL_STENCIL are accepted.
          

    13. Rendering an Image

      Reading a PNG file

    14. PNG ( Portable Network Graphics ) -- an Open, Extensible Image Format with Lossless Compression.
      • Designed in 1995 specifically in response to the patent problems with the LZW algorithm used in GIF.
      • It is 'completely' patent-free.
      • Supports alpha channels; allows up to 254 levels of partial transparency.
      • Supports gamma correction.
      • See http://www.libpng.org/

    15. Imageio library utility:
      • Developed by Adrien Treuille at http://www.cs.cmu.edu/~treuille/resc/imageio/
      • A simple library allows users read and write png and tiff files:
        	
        		Application program:
        			#include "imageio.h"
        	
        		linked by:	
        			g++ -o program program.o  imageio.o
        		

      • Read a PNG image into memory
        	unsigned char *loadImageRGBA(unsigned char *fileName, int *width, int *height);
        	
        Returns a pointer pointing to the uncompressed image data. width and height will contain information of image width and height.

      • Save memory data into PNG file
         
        	bool saveImageRGBA(char *fileName, unsigned char *buffer, int width, int height);
          	
      • Example
        	int width, height;
        	char *filename = "house.png";
        
         	unsigned char *ibuff = loadImageRGBA( filename, &width, &height);
          	glRasterPos2f ( 1.0, 2.0 );		//position to display image
          	glDrawPixels ( width, height, GL_RGBA, GL_UNSIGNED_BYTE, ibuff );
        	

        Complete Code

        /*
         * render-img0.cpp
         * Demo program showing how to read in a png image file and render it.
         * @Author: T.L. Yu, 2008F
         *
         */
        
        #include <GL/gl.h>
        #include <GL/glu.h>
        #include <GL/glut.h>
        #include <stdlib.h>
        #include <stdio.h>
        #include <string.h>
        #include "imageio.h"
        
        int window;
        int anglex= 0, angley = 0, anglez = 0;		//rotation angles
        int screenWidth = 500, screenHeight = 500;
        unsigned char *ibuff;				//image buffer pointer
        
        void init(void)
        {    
           glClearColor (1, 1, 1, 0.0);
           glShadeModel(GL_FLAT);
        }
        
        void display(void)
        {
           glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
          
           char *filename = "house.png";		//image file
           int iwidth, iheight;	
        
           ibuff = loadImageRGBA( filename, &iwidth, &iheight);
           glPushMatrix(); 
           glRotatef( anglex, 1.0, 0.0, 0.0);		//rotate object along x-axis
           glRotatef( angley, 0.0, 1.0, 0.0);		//rotate along y-axis	
           glRotatef( anglez, 0.0, 0.0, 1.0);		//rotate along z-axis
        
           glRasterPos2f ( 1.0, 1.0 );			//position to display image
           glDrawPixels ( iwidth, iheight, GL_RGBA, GL_UNSIGNED_BYTE, ibuff );
        
           glPopMatrix();
           glFlush();
        }
        
        void keyboard(unsigned char key, int x, int y)
        {
          switch(key) {
            case 'x':
              anglex = ( anglex + 3 ) % 360;
              break;
            case 'X':
              anglex = ( anglex - 3 ) % 360;
              break;
            case 'y':
              angley = ( angley + 3 ) % 360;
              break;
            case 'Y':
              angley = ( angley - 3 ) % 360;
              break;
            case 'z':
              anglez = ( anglez + 3 ) % 360;
              break;
            case 'Z':
              anglez = ( anglez - 3 ) % 360;
              break;
            case 'r':	//reset
              anglex = angley = anglez = 0;
            case 27: /* escape */
                glutDestroyWindow(window);
                exit(0);
          }
          glutPostRedisplay();
        }
        
        void reshape(int w, int h)
        {
           glViewport(0, 0, (GLsizei) w, (GLsizei) h);
           glMatrixMode(GL_PROJECTION);
           glLoadIdentity();
           gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 30.0);
           glMatrixMode(GL_MODELVIEW);
           glLoadIdentity();
           gluLookAt ( 0, 0, 5, 0, 0, 0, 0, 1, 0 );
        }
        
        int main(int argc, char** argv)
        {
           glutInit(&argc, argv);
           glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
           glutInitWindowSize(screenWidth, screenHeight);
           glutInitWindowPosition(100, 100);
           window = glutCreateWindow(argv[0]);
           init();
           glutDisplayFunc(display);
           glutReshapeFunc(reshape);
           glutKeyboardFunc(keyboard);
           glutMainLoop();
           return 0; 
        }
        	
    16. The convert utility

    17. A member of the ImageMagick suite of tools.

    18. Convert between image formats as well as resize an image, blur, crop, despeckle, dither, draw on, flip, join, re-sample, and much more.

    19. Run 'convert -help' to get a summary of convert command options.

    20. Examples:
        	$convert house.jpg house.png
        
        	$convert house.jpg -resize 60% house.png
        
        	$convert -size 128x128 xc:transparent -font Bookman-DemiItalic -pointsize 28 -channel RGBA \
        		-gaussian 0x4 -fill lightgreen -stroke green -draw "text 0,20 'CS 520'" cs520.png
        	
           			
    21. Combining Pixmaps

      Pixmaps can be combined pixelwise.

    22. Averaging two images:

        C[i][j] = ( A[i][j] + B[i][j] ) / 2

      Differencing two images can be used for compression:

        C[i][j] = A[i][j] - B[i][j] )

      Finding where one image is brighter than another:

        C[i][j] = ( A[i][j] - B[i][j] )
    23. Weighted average:

        C[i][j] = f * A[i][j] + ( 1 - f ) * B[i][j]

    24. Dissolving one image into another
        A( 1 - t ) + B t

    25. Logical Combination of Pixmaps

    26. Each pixel value may be treated as a collection of bits. For example, in RGB mode, pixel A = (21, 127, 0 ) and pixel B = ( 1, 2, 7 ). A and B can be ORed to form new pixel value C:
        	pixel A : 00010101 01111111 00000000
        	pixel B : 00000001 00000010 00000111
        	------------------------------------
        	pixel C : 00010101 01111111 00000111		C = A OR B
        	

    27. OpenGL commands
        glEnable( GL_COLOR_LOGIC_OP ); glLogicOp ( GL_OR ); //Destination = Source OR Destination

    28. void glLogicOp( GLenum opcode )
               	       ____________________________________
      		      |	    opcode	| resulting value |
      		      |_________________|_________________|
      		      |	   GL_CLEAR	|	 0	  |
      		      |	    GL_SET	|	 1	  |
      		      |	   GL_COPY	|	 s	  |
      		      |GL_COPY_INVERTED	|	~s	  |
      		      |	   GL_NOOP	|	 d	  |
      		      |	  GL_INVERT	|	~d	  |
      		      |	    GL_AND	|      s & d	  |
      		      |	   GL_NAND	|    ~(s & d)	  |
      		      |	    GL_OR	|      s | d	  |
      		      |	    GL_NOR	|    ~(s | d)	  |
      		      |	    GL_XOR	|      s ^ d	  |
      		      |	   GL_EQUIV	|    ~(s ^ d)	  |
      		      |	GL_AND_REVERSE	|     s	& ~d	  |
      		      |GL_AND_INVERTED	|     ~s & d	  |
      		      |	GL_OR_REVERSE	|     s	| ~d	  |
      		      |	GL_OR_INVERTED	|     ~s | d	  |
      		      |_________________|_________________|
      		

    29. Example: Rubber Rectangle Drawing
      /*
       * rubber.cpp
       * CS 520 demo program showing rubber rectangular drawing.
       * To simplify things, viewport and world window are set to the same.
       * @Author: T.L. Yu, 2009W
       *
       */
      
      #include <GL/gl.h>
      #include <GL/glu.h>
      #include <GL/glut.h>
      #include <stdlib.h>
      #include <stdio.h>
      
      int window;
      int screenWidth = 500, screenHeight = 500;
      int left, bottom, right, top;			//rectangular area
      
      void init(void)
      {    
         glClearColor (1, 1, 1, 0.0);
         glPolygonMode( GL_FRONT, GL_LINE );
         glPolygonMode( GL_BACK, GL_LINE );
         glMatrixMode( GL_PROJECTION );
         glLoadIdentity();
         gluOrtho2D( 0.0, screenWidth, 0.0, screenHeight );	//set to screen values to simplify 
      }
      
      void display(void)
      {
         glClear(GL_COLOR_BUFFER_BIT);
         glColor3f ( 1, 0, 0 );
         glBegin( GL_TRIANGLES);		//arbitrarily draw something
           glVertex2i ( 100, 100 );
           glVertex2i ( 200, 100 );
           glVertex2i ( 150, 150 );
         glEnd();
      }
      
      void keyboard(unsigned char key, int x, int y)
      {
        switch(key) {
          case 27: /* escape */
              glutDestroyWindow(window);
              exit(0);
        }
      }
      
      void myMouse( int button, int state, int x, int y )
      {
        if ( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN ) {
          glEnable( GL_COLOR_LOGIC_OP );	//enable logical operations
          glLogicOp ( GL_XOR );		//set it to XOR mode
          left = right = x;			//set the pivot
          top = bottom = screenHeight - y;	 
        } else if ( button == GLUT_LEFT_BUTTON && state == GLUT_UP ) {
          glDisable( GL_COLOR_LOGIC_OP );	//disable logical operations
          glColor3f ( 0.0, 0.0, 1.0 );
          glRecti ( left, bottom, right, top );//draw the final rectangle	
          glFlush();
        }
      }
      
      void mouseMove ( int mx, int my )
      {
        glRecti ( left, bottom, right, top );		//erase old rectangle
        right = mx;					
        bottom = screenHeight - my;			//flip y-coordinates
        glColor3f ( 0, 1, 1 );
        glRecti ( left, bottom, right, top );		//draw the new rectangle
        glFlush();
      }
      
      int main(int argc, char** argv)
      {
         glutInit(&argc, argv);
         glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB );
         glutInitWindowSize(screenWidth, screenHeight);
         glutInitWindowPosition(100, 100);
         window = glutCreateWindow(argv[0]);
         init();
         glutDisplayFunc(display);
         glutMouseFunc( myMouse );
         glutMotionFunc( mouseMove );
         glutKeyboardFunc(keyboard);
         glutMainLoop();
         return 0; 
      }
      	

    30. Example: Swapping two images
    31. A
    32. B

    33. A XOR ( A XOR B ) = B
    34. B XOR ( A XOR B ) = A

    35. B XOR ( A XOR B ) = A
    36. A XOR ( A XOR B ) = B

      int iwidth, iheight;
      unsigned char *ibuff[2];                                //image buffer pointers
      
      void init(void)
      {
         glClearColor (0, 0, 0, 0);
         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
         glShadeModel(GL_FLAT);
      
         //assume both images are of the same size
         char filename[][20] = {"tom.png", "maricel.png"};    //image files
         for ( int i = 0; i < 2; ++i )
           ibuff[i] = loadImageRGBA( filename[i], &iwidth, &iheight);
      }
      
      void display(void)
      {
         glEnable(GL_COLOR_LOGIC_OP);
         glLogicOp ( GL_XOR );
         static bool first = true;
      
         glRasterPos2f ( -2.0, 0.0 );                 //position to display image
         glDrawPixels ( iwidth, iheight, GL_RGBA, GL_UNSIGNED_BYTE, ibuff[0] );
         if ( !first )
            glDrawPixels ( iwidth, iheight, GL_RGBA, GL_UNSIGNED_BYTE, ibuff[1] );
      
         glRasterPos2f ( 1.0, 0.0 );                  //position to display image
         glDrawPixels ( iwidth, iheight, GL_RGBA, GL_UNSIGNED_BYTE, ibuff[1] );
         if ( !first )
           glDrawPixels ( iwidth, iheight, GL_RGBA, GL_UNSIGNED_BYTE, ibuff[0] );
      
         first = false;
         glutSwapBuffers();
         glFlush();
      }	

    37. Mapping Window Coordinates to World Coordinates

      The mouse only returns two dimensional values of the screen cursor location. We may need to convert this to three dimensional world coordinates. This can be done by the reversal of the transformations.

      	  GLint	gluUnProject( GLdouble x,, GLdouble y, GLdouble z,
       				const GLdouble modelMatrix[16],
       				const GLdouble projMatrix[16],
      				const GLint viewport[4],
      				GLdouble *X, GLdouble *Y, GLdouble *Z )
      	
       	x,y, z
      			Specify the window coordinates to be mapped.
      
      	 modelMatrix	Specifies the modelview matrix.
      
      	projMatrix	Specifies the	projection matrix.
      
      	viewport	Specifies the	viewport.
      
      	X, Y, Z
      			Returns the computed world ( object ) coordinates.
      	

      On the other hand,

                GLint gluProject( GLdouble X,, GLdouble Y, GLdouble Z,
                                      const GLdouble modelMatrix[16],
                                      const GLdouble projMatrix[16],
                                      const GLint viewport[4],
                                      GLdouble *x, GLdouble *y, GLdouble *z )
       
      mimics the transformation pipeline, mapping the specified world coordinates, (X, Y, Z) to window coordinates (x, y, z).

      Example:

      /* A simplified routine for  converting two-dimensional screen pixel coordinates to three-dimensional
       * World coordinates.
       * Input: (x, y) are screen pixel coordinates; z is set to 0.
       * Output: (*X, *Y, *Z) are world coordinates
       */
      void twoD2threeD( int x, int y, double *X, double *Y, double *Z )
      {
        int viewport[4];                      //where the viewport values will be stored
        double modelviewMatrix[16];           //where Modelview Matrix will be stored
        double projectionMatrix[16];          //where Projection Matrix will be stored
      
        glGetIntegerv( GL_VIEWPORT, viewport );//retrieve current viewport: viewport[0] = x-origin, 
                                               //viewport[1]=y-origin, viewport[2]=width, viewport[3]=height
        glGetDoublev( GL_MODELVIEW_MATRIX, modelviewMatrix );  //retrieve Modelview Matrix
        glGetDoublev( GL_PROJECTION_MATRIX, projectionMatrix );//retrieve Projection Matrix
      
        GLfloat z = 0;
        /*
          In practice, you should actually define the near and far edge z values which are
          clipped to [0, 1].
        */
      
        gluUnProject ( x, y, z, modelviewMatrix, projectionMatrix, viewport, X, Y, Z );
      }	

    38. Dragging an Image

      1. Use gluUnproject() to convert cursor locations to world coordinates.
      2. Use glRasterPos() to specify position for displaying image.
      3. Use glDrawPixels() to display image.

      /*
       * render-img.cpp
       * Demo of dragging an image.
       * @Author: T.L. Yu, 2009W for CS 520
       *
       */
      
      #include <GL/gl.h>
      #include <GL/glu.h>
      #include <GL/glut.h>
      #include "imageio.h"
      
      int window;
      int screenWidth = 500, screenHeight = 500;
      float imgX = -1.0, imgY = 1.0, imgZ = -24.0;	//image display position
      unsigned char *ibuff;
      
      void init(void)
      {    
         glClearColor (1, 1, 1, 0.0);
         glShadeModel(GL_FLAT);
      
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
      }
      
      void display(void)
      {
         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        
         char *filename = "house.png";
         int   iwidth, iheight;
         
         ibuff = loadImageRGBA( filename, &iwidth, &iheight);
      
         glRasterPos3f ( imgX, imgY, imgZ );		//position to display image
         glDrawPixels ( iwidth, iheight, GL_RGBA, GL_UNSIGNED_BYTE, ibuff );
      
         glFlush();
      }
      
      void keyboard(unsigned char key, int x, int y)
      {
        switch(key) {
          case 27: /* escape */
              glutDestroyWindow(window);
              exit(0);
        }
      }
      
      void reshape(int w, int h)
      {
         glViewport(0, 0, (GLsizei) w, (GLsizei) h);
         glMatrixMode(GL_PROJECTION);
         glLoadIdentity();
         gluPerspective(60.0, (GLfloat) w/(GLfloat) h, 1.0, 30.0);
         glMatrixMode(GL_MODELVIEW);
         glLoadIdentity();
         gluLookAt ( 0, 0, 5, 0, 0, 0, 0, 1, 0 );
      }
      
      
      /* A simplified routine for  converting two-dimensional screen pixel coordinates to three-dimensional
       * World coordinates.
       * Input: (x, y) are screen pixel coordinates; z is set to 0.
       * Output: (*X, *Y, *Z) are world coordinates
       */
      void twoD2threeD( int x, int y, double *X, double *Y, double *Z )
      {
        int viewport[4];                      //where the viewport values will be stored
        double modelviewMatrix[16];           //where Modelview Matrix will be stored
        double projectionMatrix[16];          //where Projection Matrix will be stored
      
        glGetIntegerv( GL_VIEWPORT, viewport );//retrieve current viewport: viewport[0] = x-origin, 
                                               //viewport[1]=y-origin, viewport[2]=width, viewport[3]=height
        glGetDoublev( GL_MODELVIEW_MATRIX, modelviewMatrix );  //retrieve Modelview Matrix
        glGetDoublev( GL_PROJECTION_MATRIX, projectionMatrix );//retrieve Projection Matrix
      
        GLfloat z = 0;
        /*
          In practice, you should actually define the near and far edge z values which are
          clipped to [0, 1].
        */
      
        gluUnProject ( x, y, z, modelviewMatrix, projectionMatrix, viewport, X, Y, Z );
      }
      
      void myMouse( int button, int state, int x, int y )
      {
        float xw, yw, zw;
            
        if ( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN ) {
        } 
      }
      
      void mouseMove ( int mx, int my )
      {
        double xw, yw, zw;				//world coordinates
        twoD2threeD( mx, screenHeight-my, &xw, &yw, &zw );
        
        imgX = xw;
        imgY = yw;
        imgZ = zw;
        glutPostRedisplay();
      }
      
        
      int main(int argc, char** argv)
      {
         glutInit(&argc, argv);
         glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);
         glutInitWindowSize(screenWidth, screenHeight);
         glutInitWindowPosition(100, 100);
         window = glutCreateWindow(argv[0]);
         init();
         glutDisplayFunc(display);
         glutReshapeFunc(reshape);
         glutKeyboardFunc(keyboard);
         glutMouseFunc( myMouse );
         glutMotionFunc( mouseMove );
         glutMainLoop();
         return 0; 
      }
       	

    39. Animation in OpenGL

    40. May use callback functions glutIdleFunc() and/or glutVisibilityFunc() to do animation.

    41. Global idle callback function:
        void glutIdleFunc ( void (* func)() );

      sets the callback function to func. Passing NULL to glutIdleFunc() disables the generation of the idle callback.
      e.g.
         	glutIdleFunc ( idle );
        	......
        	void idle(void)
        	{
            		time += 0.02;
            		glutSetWindow ( window );
            		glutPostRedisplay();
        	}
        	

      We should stop rendering when the window is not visible:

        	void visible ( int vis )
        	{
           	    if ( vis == GLUT_VISIBLE )
               		glutIdleFunc ( idle );
           	    else
               		glutIdleFunc ( NULL );  //disable idle callback
        	}
        	
      For animation applications, it is better not to set up the idle callback before calling glutMainLoop(), but to use the visibility callback to install idle callback when the window first becomes visible on the screen.

      An example:
        	void idle ()
        	{
           	    static unsigned int prev_time = SDL_GetTicks();
        
           	    int current_time = SDL_GetTicks();  //ms since library starts
           	    int diff = current_time - prev_time;
           	    if ( diff < 100 ){    //10 fps ~ 100 ms / frame
              	      int delay = 100 - ( current_time - prev_time );
                      SDL_Delay ( delay );
           	    }
           	    prev_time = SDL_GetTicks();
           	    animate();
        	}
        
        	int main( int argc, char *argv[] )
        	{
           	  glutInit(&argc,argv);
           	  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB );
        
           	  glutCreateWindow("Animation Demo");
           	  glutReshapeWindow( 500, 500 );
           	  glutInitWindowPosition(100, 100);
           	  glutDisplayFunc(display);
           	  glutIdleFunc ( idle );    //for animation
        
           	  glutKeyboardFunc(keyboard);
           	  init();
           	  glutMainLoop();
           	  return 0;
        	}
        	

    42. Using glutVisibilityFunc():
        void glutVisibilityFunc ( void ( * func )(int state));

      sets the visibility callback for the current window; func is the new visibility callback function.
        	The state  callback parameter is either GLUT_NOT_VISIBLE or GLUT_VISIBLE depending on 
        	the current visibility of the window. GLUT_VISIBLE does not distinguish a window being totally 
        	versus partially visible.  GLUT_NOT_VISIBLE indicates that no part of the window is visible, 
        	i.e., until the window's visibility changes, all further rendering to the window is discarded.
        	GLUT considers a window visible if any pixel of the window is visible or any pixel of any 
        	descendant window is visible on the screen.
        	Passing NULL to glutVisibilityFunc() disables the generation of the visibility callback.
        	
      Works along with the function glutTimerFunc() to set the frame rate:
        void glutTimerFunc ( unsigned int msecs, void (*func)(int value), value);
        	msecs specifies the number of milliseconds to pass before calling the callback,
          	func specifies the timer callback function, and
          	value specifies the integer value to pass to the timer callback function.
        	
        Example:
        void timerHandle ( int value )
        {
           animate();
           glutPostRedisplay();
           glutTimerFunc ( 100, timerHandle, 0 );
        }
        
        void visHandle( int visible )
        {
           if (visible == GLUT_VISIBLE)
              timerHandle ( 0 );  //start animation when visible
        }
        
        int main( int argc, char *argv[] )
        {
           glutInit(&argc,argv);
           glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB );
        
           glutCreateWindow("Tweening Demo");
           glutReshapeWindow( 500, 500 );
           glutInitWindowPosition(100, 100);
           glutDisplayFunc(display);
           glutVisibilityFunc( visHandle );
        
           glutKeyboardFunc(keyboard);
           init();
           glutMainLoop();
           return(0);
        }