Syllabus   Blank Homework   Quizzes  
Notes   Labs   Scores   Blank


Lecture Notes
Dr. Tong Yu, Sept. 2013
All the materials presented here are adopted from the textbook and the listed references.
    1. Introduction
    2. Line Drawing
    3. Drawing Objects
    4. More Drawing Tools
    5. Vertex Array
    6. Normal Vectors and Polygonal Models of Surfaces
    7. Viewing I -- Affine Transformations
    8. Viewing II -- Projections
    9. Color
    10. Lighting
    11. Blending, antialiasing, fog ..
    12. Display Lists, Bitmaps and Images
    Appendix. Games and SDL

    Display Lists, Bitmaps and Images

    There can be no friendship without confidence,
    and no confidence without integrity.
    Samuel Johnson

    1. Display Lists

      Display list -- a group of OpenGL commands that have been stored for later execution.

      Properties:

    2. A convenient and efficient way to name and organize a set of OpenGL commands,

    3. The commands in a display list are executed in the order in which they were issued ( stored ),

    4. Most OpenGL commands can be either stored in a display list or issued in immediate mode, which causes them to be executed immediately,

    5. You can freely mix immediate-mode programming and display lists within a single program.
    6. Why Use Display Lists?

    7. may improve performance since we can use them to store commands for later execution,

    8. faster execution if we cache commands in a display list where the commands to draw an object will be used multiple times

    9. we can use display list to define a geometry shape or a state and execute them multiple times
    10. Notes:

    11. Once a display list is created, all vertex and pixel data are evaluated and copied
      into the display list memory on the server machine

    12. Display list is a server state and thus can be shared by clients.

    13. Once a display list is compiled, it cannot be modified later.

    14. Any client related commands cannot be put in a display list. e.g. glFlush(), glFinish()

    15. Any command returning a value cannot be put in a display list. e.g. glReadPixels()
    16. Examples of Using a Display List

      Drawing a torus

      //torus.cpp
      #include <GL/gl.h>
      #include <GL/glu.h>
      #include <stdio.h>
      #include <math.h>
      #include <GL/glut.h>
      #include <stdlib.h>
      
      GLuint theTorus;
      
      /* Draw a torus */
      static void torus(int numc, int numt)
      {
         int i, j, k;
         double s, t, x, y, z, twopi;
      
         twopi = 2 * (double)M_PI;
         for (i = 0; i < numc; i++) {
            glBegin(GL_QUAD_STRIP);
            for (j = 0; j <= numt; j++) {
               for (k = 1; k >= 0; k--) {
                  s = (i + k) % numc + 0.5;
                  t = j % numt;
      
                  x = (1+.1*cos(s*twopi/numc))*cos(t*twopi/numt);
                  y = (1+.1*cos(s*twopi/numc))*sin(t*twopi/numt);
                  z = .1 * sin(s * twopi / numc);
                  glVertex3f(x, y, z);
               }
            }
            glEnd();
         }
      }
      
      /* Create display list with Torus and initialize state*/
      static void init(void)
      {
         theTorus = glGenLists (1);
         glNewList(theTorus, GL_COMPILE);
         torus(8, 25);
         glEndList();
      
         glShadeModel(GL_FLAT);
         glClearColor(0.0, 0.0, 0.0, 0.0);
      }
      
      void display(void)
      {
         glClear(GL_COLOR_BUFFER_BIT);
         glColor3f (1.0, 1.0, 1.0);
         glCallList(theTorus);
         glFlush();
      }
      
      void reshape(int w, int h)
      {
         glViewport(0, 0, (GLsizei) w, (GLsizei) h);
         glMatrixMode(GL_PROJECTION);
         glLoadIdentity();
         gluPerspective(30, (GLfloat) w/(GLfloat) h, 1.0, 100.0);
         glMatrixMode(GL_MODELVIEW);
         glLoadIdentity();
         gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0);
      }
      
      /* Rotate about x-axis when .x. typed; rotate about y-axis
         when .y. typed; .i. returns torus to original view */
      void keyboard(unsigned char key, int x, int y)
      {
         switch (key) {
         case `x':
         case `X':
            glRotatef(30.,1.0,0.0,0.0);
            glutPostRedisplay();
            break;
         case `y':
         case `Y':
            glRotatef(30.,0.0,1.0,0.0);
            glutPostRedisplay();
            break;
         case `i':
         case `I':
            glLoadIdentity();
            gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0);
            glutPostRedisplay();
            break;
         case 27:
            exit(0);
            break;
         }
      }
      
      int main(int argc, char **argv)
      {
         glutInitWindowSize(200, 200);
         glutInit(&argc, argv);
         glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
         glutCreateWindow(argv[0]);
         init();
         glutReshapeFunc(reshape);
         glutKeyboardFunc(keyboard);
         glutDisplayFunc(display);
         glutMainLoop();
         return 0;
      }
        

      Rotate about
      x-axis





       

      Rotate about
      y-axis





      GLuint glGenLists(GLsizei range);
      Allocates range number of contiguous, previously unallocated display-list indices. The integer returned is the index that marks the beginning of a contiguous block of empty display-list indices. The returned indices are all marked as empty and used, so subsequent calls to glGenLists() don't return these indices until they're deleted. Zero is returned if the requested number of indices isn't available, or if range is zero.

      void glNewList (GLuint list, GLenum mode);
      Specifies the start of a display list. OpenGL routines that are called subsequently (until glEndList() is called to end the display list) are stored in a display list, except for a few restricted OpenGL routines that can't be stored. (Those restricted routines are executed immediately, during the creation of the display list.) list is a nonzero positive integer that uniquely identifies the display list. The possible values for mode are GL_COMPILE and GL_COMPILE_AND_EXECUTE. Use GL_COMPILE if you don't want the OpenGL commands executed as they're placed in the display list; to cause the commands to be executed immediately as well as placed in the display list for later use, specify GL_COMPILE_AND_EXECUTE.

      void glEndList (void);
      Marks the end of a display list.

      Drawing Triangles

      //list.cpp
      #include <GL/gl.h>
      #include <GL/glu.h>
      #include <GL/glut.h>
      #include <stdlib.h>
      
      GLuint listName;
      
      static void init (void)
      {
         listName = glGenLists (1);
         glNewList (listName, GL_COMPILE);
            glColor3f (1.0, 0.0, 0.0);  /*  current color red  */
            glBegin (GL_TRIANGLES);
            glVertex2f (0.0, 0.0);
            glVertex2f (1.0, 0.0);
            glVertex2f (0.0, 1.0);
            glEnd ();
            glTranslatef (1.5, 0.0, 0.0); /*  move position  */
         glEndList ();
         glShadeModel (GL_FLAT);
      }
      
      static void drawLine (void)
      {
         glBegin (GL_LINES);
         glVertex2f (0.0, 0.5);
         glVertex2f (15.0, 0.5);
         glEnd ();
      }
      
      void display(void)
      {
         GLuint i;
      
         glClear (GL_COLOR_BUFFER_BIT);
         glColor3f (0.0, 1.0, 0.0);  /*  current color green  */
         for (i = 0; i < 10; i++)    /*  draw 10 triangles    */
            glCallList (listName);
         drawLine ();  /*  is this line green?  NO!  */
                       /*  where is the line drawn?  */
         glFlush ();
      }
      
      void reshape(int w, int h)
      {
         glViewport(0, 0, w, h);
         glMatrixMode(GL_PROJECTION);
         glLoadIdentity();
         if (w <= h) 
            gluOrtho2D (0.0, 2.0, -0.5 * (GLfloat) h/(GLfloat) w, 
               1.5 * (GLfloat) h/(GLfloat) w);
         else 
            gluOrtho2D (0.0, 2.0*(GLfloat) w/(GLfloat) h, -0.5, 1.5); 
         glMatrixMode(GL_MODELVIEW);
         glLoadIdentity();
      }
      
      void keyboard(unsigned char key, int x, int y)
      {
         switch (key) {
            case 27:
               exit(0);
         }
      }
      
      int main(int argc, char** argv)
      {
         glutInit(&argc, argv);
         glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
         glutInitWindowSize(650, 50);
         glutCreateWindow(argv[0]);
         init ();
         glutReshapeFunc (reshape);
         glutKeyboardFunc (keyboard);
         glutDisplayFunc (display);
         glutMainLoop();
         return 0;
      }
      

    17. Bitmaps and Fonts

      bitmap -- a rectangular array of 0s and 1s that serves as a drawing mask for a corresponding rectangular portion of the window.

      Suppose you're drawing a bitmap and that the current raster color is red. Wherever there's a 1 in the bitmap, the corresponding pixel is replaced by a red pixel

      If there's a 0 in the bitmap, the contents of the pixel are unaffected. The most common use of bitmaps is for drawing characters on the screen.

      void glBitmap(GLsizei width, GLsizei height, GLfloat xbo, GLfloat ybo, GLfloat xbi, GLfloat ybi, const GLubyte *bitmap);
      Draws the bitmap specified by bitmap, which is a pointer to the bitmap image. The origin of the bitmap is placed at the current raster position. If the current raster position is invalid, nothing is drawn, and the raster position remains invalid. The width and height arguments indicate the width and height, in pixels, of the bitmap. The width need not be a multiple of 8, although the data is stored in unsigned characters of 8 bits each. Use xbo and ybo to define the origin of the bitmap (positive values move the origin up and to the right of the raster position; negative values move it down and to the left); xbi and ybi indicate the x and y increments that are added to the raster position after the bitmap is rasterized.

      //drawf.cpp
      #include <GL/gl.h>
      #include <GL/glu.h>
      #include <GL/glut.h>
      #include <stdlib.h>
      
      GLubyte rasters[24] = {
         0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00,
         0xff, 0x00, 0xff, 0x00, 0xc0, 0x00, 0xc0, 0x00, 0xc0, 0x00,
         0xff, 0xc0, 0xff, 0xc0};
      
      void init(void)
      {
         //set image storage mode
         glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
         glClearColor (0.0, 0.0, 0.0, 0.0);
      }
      
      void display(void)
      {
         glClear(GL_COLOR_BUFFER_BIT);
         glColor3f (1.0, 1.0, 1.0);
         glRasterPos2i (20, 20);
         glBitmap (10, 12, 0.0, 0.0, 11.0, 0.0, rasters);
         glBitmap (10, 12, 0.0, 0.0, 11.0, 0.0, rasters);
         glBitmap (10, 12, 0.0, 0.0, 11.0, 0.0, rasters);
         glFlush();
      }
      
      void reshape(int w, int h)
      {
         glViewport(0, 0, (GLsizei) w, (GLsizei) h);
         glMatrixMode(GL_PROJECTION);
         glLoadIdentity();
         glOrtho (0, w, 0, h, -1.0, 1.0);
         glMatrixMode(GL_MODELVIEW);
      }
      
      void keyboard(unsigned char key, int x, int y)
      {
         switch (key) {
            case 27:
               exit(0);
         }
      }
      
      int main(int argc, char** argv)
      {
         glutInit(&argc, argv);
         glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
         glutInitWindowSize(100, 100);
         glutInitWindowPosition(100, 100);
         glutCreateWindow(argv[0]);
         init();
         glutReshapeFunc(reshape);
         glutKeyboardFunc(keyboard);
         glutDisplayFunc(display);
         glutMainLoop();
         return 0;
      }
      

       

       

       

       

       

       

       

       

      Example: Defining and and Using a Complete Font

      void glCallLists( GLsizei n, GLenum type, const GLvoid * lists);
      n: the number of display lists to be executed
      type: the type of values in lists, including symbolic constants GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT, GL_FLOAT, GL_2_BYTES, GL_3_BYTES, and GL_4_BYTES
      lists:     the address of an array of name offsets in the display list; pointer type is void because the offsets can be bytes, shorts, ints, or floats, depending on the value of type

      //font.cpp
      #include <GL/gl.h>
      #include <GL/glu.h>
      #include <GL/glut.h>
      #include <stdlib.h>
      #include <string.h>
      
      GLubyte space[] =
          {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
      GLubyte letters[][13] = {
          {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0x66, 0x3c, 0x18},
          {0x00, 0x00, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
          {0x00, 0x00, 0x7e, 0xe7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},
          {0x00, 0x00, 0xfc, 0xce, 0xc7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc7, 0xce, 0xfc},
          {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xc0, 0xff},
          {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfc, 0xc0, 0xc0, 0xc0, 0xff},
          {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xe7, 0x7e},
          {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xff, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
          {0x00, 0x00, 0x7e, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x7e},
          {0x00, 0x00, 0x7c, 0xee, 0xc6, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06},
          {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xe0, 0xf0, 0xd8, 0xcc, 0xc6, 0xc3},
          {0x00, 0x00, 0xff, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0},
          {0x00, 0x00, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xdb, 0xff, 0xff, 0xe7, 0xc3},
          {0x00, 0x00, 0xc7, 0xc7, 0xcf, 0xcf, 0xdf, 0xdb, 0xfb, 0xf3, 0xf3, 0xe3, 0xe3},
          {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xe7, 0x7e},
          {0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
          {0x00, 0x00, 0x3f, 0x6e, 0xdf, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0x66, 0x3c},
          {0x00, 0x00, 0xc3, 0xc6, 0xcc, 0xd8, 0xf0, 0xfe, 0xc7, 0xc3, 0xc3, 0xc7, 0xfe},
          {0x00, 0x00, 0x7e, 0xe7, 0x03, 0x03, 0x07, 0x7e, 0xe0, 0xc0, 0xc0, 0xe7, 0x7e},
          {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xff},
          {0x00, 0x00, 0x7e, 0xe7, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
          {0x00, 0x00, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
          {0x00, 0x00, 0xc3, 0xe7, 0xff, 0xff, 0xdb, 0xdb, 0xc3, 0xc3, 0xc3, 0xc3, 0xc3},
          {0x00, 0x00, 0xc3, 0x66, 0x66, 0x3c, 0x3c, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3},
          {0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x3c, 0x66, 0x66, 0xc3},
          {0x00, 0x00, 0xff, 0xc0, 0xc0, 0x60, 0x30, 0x7e, 0x0c, 0x06, 0x03, 0x03, 0xff}
      };
      
      GLuint fontOffset;
      
      void makeRasterFont(void)
      {
         GLuint i, j;
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
      
         fontOffset = glGenLists (128);
         for (i = 0,j = `A'; i < 26; i++,j++) {
            glNewList(fontOffset + j, GL_COMPILE);
            glBitmap(8, 13, 0.0, 2.0, 10.0, 0.0, letters[i]);
            glEndList();
         }
         glNewList(fontOffset + ` `, GL_COMPILE);
         glBitmap(8, 13, 0.0, 2.0, 10.0, 0.0, space);
         glEndList();
      }
      
      void init(void)
      {
         glClear(GL_COLOR_BUFFER_BIT);
         glClearColor( 1.0, 1.0, 1.0, 1.0 );
         glShadeModel (GL_FLAT);
         makeRasterFont();
      }
      
      void printString(char *s)
      {
         glPushAttrib (GL_LIST_BIT);
         glListBase(fontOffset);
         glCallLists(strlen(s), GL_UNSIGNED_BYTE, (GLubyte *) s);
         glPopAttrib ();
      }
      
      /* Everything above this line could be in a library 
       * that defines a font.  To make it work, you've got 
       * to call makeRasterFont() before you start making 
       * calls to printString().
       */
      void display(void)
      {
         GLfloat black[3] = { 0.0, 0.0, 0.0 };
      
         glClear(GL_COLOR_BUFFER_BIT);
      
         glColor3fv( black );
      
         glRasterPos2i(20, 60);
         printString("THE QUICK BROWN FOX JUMPS");
         glRasterPos2i(20, 40);
         printString( "OVER A LAZY DOG" );
         glFlush ();
      }
      
      void reshape(int w, int h)
      {
         glViewport(0, 0, (GLsizei) w, (GLsizei) h);
         glMatrixMode(GL_PROJECTION);
         glLoadIdentity();
         glOrtho (0.0, w, 0.0, h, -1.0, 1.0);
         glMatrixMode(GL_MODELVIEW);
      }
      
      void keyboard(unsigned char key, int x, int y)
      {
         switch (key) {
            case 27:
               exit(0);
         }
      }
      
      int main(int argc, char** argv)
      {
         glutInit(&argc, argv);
         glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
         glutInitWindowSize(300, 100);
         glutInitWindowPosition (100, 100);
         glutCreateWindow(argv[0]);
         init();
         glutReshapeFunc(reshape);
         glutKeyboardFunc(keyboard);
         glutDisplayFunc(display);
         glutMainLoop();
         return 0;
      }
      

    18. Images

      An image is similar to a bitmap, but instead of containing only a single bit for each pixel in a rectangular region of the screen, an image can contain much more information such as a complete ( R, G, B, A ) color of each pixel.

      Image sources:

    19. A photograph that's digitized with a scanner,

    20. An image that was first generated on the screen by a graphics program using the graphics hardware and then read back, pixel by pixel

    21. A software program that generated the image in memory pixel by pixel
    22. Manipulating Image data:

    23. glReadPixels() -- Reads a rectangular array of pixels from the framebuffer and stores the data in processor memory.

    24. glDrawPixels() -- Writes a rectangular array of pixels from data kept in processor memory into the framebuffer at the current raster position specified by glRasterPos*().

    25. glCopyPixels() -- Copies a rectangular array of pixels from one part of the framebuffer to another. This command behaves similarly to a call to glReadPixels() followed by a call to glDrawPixels(), but the data is never written into processor memory.
    26. Pixel Data Flow:

      void glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels);
      Reads pixel data from the framebuffer rectangle whose lower-left corner is at (x, y) and whose dimensions are width and height and stores it in the array pointed to by pixels. format indicates the kind of pixel data elements that are read (an index value or an R, G, B, or A component value, as listed in Table below), and type indicates the data type of each element shown below.

      Table: Pixel Formats for glReadPixels() or glDrawPixels()

      format Constant

      Pixel Format

      GL_COLOR_INDEX

      A single color index

      GL_RGB

      A red color component, followed by a green color component, followed by a blue color component

      GL_RGBA

      A red color component, followed by a green color component, followed by a blue color component, followed by an alpha color component

      GL_RED

      A single red color component

      GL_GREEN

      A single green color component

      GL_BLUE

      A single blue color component

      GL_ALPHA

      A single alpha color component

      GL_LUMINANCE

      A single luminance component

      GL_LUMINANCE_ALPHA

      A luminance component followed by an alpha color component

      GL_STENCIL_INDEX

      A single stencil index

      GL_DEPTH_COMPONENT

      A single depth component


      Table: Data Types for glReadPixels() or glDrawPixels()

      type Constant

      Data Type

      GL_UNSIGNED_BYTE

      unsigned 8-bit integer

      GL_BYTE

      signed 8-bit integer

      GL_BITMAP

      single bits in unsigned 8-bit integers using the same format as glBitmap()

      GL_UNSIGNED_SHORT

      unsigned 16-bit integer

      GL_SHORT

      signed 16-bit integer

      GL_UNSIGNED_INT

      unsigned 32-bit integer

      GL_INT

      signed 32-bit integer

      GL_FLOAT

      single-precision floating point

      void glDrawPixels(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels);
      Draws a rectangle of pixel data with dimensions width and height. The pixel rectangle is drawn with its lower-left corner at the current raster position. format and type have the same meaning as with glReadPixels(). The array pointed to by pixels contains the pixel data to be drawn.

      void glCopyPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum buffer);
      Copies pixel data from the framebuffer rectangle whose lower-left corner is at (x, y) and whose dimensions are width and height. The data is copied to a new position whose lower-left corner is given by the current raster position. buffer is either GL_COLOR, GL_STENCIL, or GL_DEPTH, specifying the framebuffer that is used. glCopyPixels() behaves similarly to a glReadPixels() followed by a glDrawPixels(), with the following translation for the buffer to format parameter:

    27. If buffer is GL_DEPTH or GL_STENCIL, then GL_DEPTH_COMPONENT or GL_STENCIL_INDEX is used, respectively.

    28. If GL_COLOR is specified, GL_RGBA or GL_COLOR_INDEX is used, depending on whether the system is in RGBA or color-index mode.
    29. Example: image.cpp -- displaying a checker board
      #define checkImageWidth 64
      #define checkImageHeight 64
      GLubyte checkImage[checkImageHeight][checkImageWidth][3];
      
      void makeCheckImage(void)
      {
         int i, j, c;
         
         for (i = 0; i < checkImageHeight; i++) {
            for (j = 0; j < checkImageWidth; j++) {	//start from lower-left corner
               c = ((((i&0x8)==0)^((j&0x8))==0))*255; //0 or 255 --> black or white
               checkImage[i][j][0] = (GLubyte) c;	//red component
               checkImage[i][j][1] = (GLubyte) c;	//green component
               checkImage[i][j][2] = (GLubyte) c;	//blue  component
            }
         }
      }
      
      void init(void)
      {  
         glClearColor (0.0, 0.0, 0.0, 0.0);
         glShadeModel(GL_FLAT);
         makeCheckImage();
      
         //Sets pixel-storage mode
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
      }
      void display(void)
      {
         glClear(GL_COLOR_BUFFER_BIT);
         glRasterPos2i(0, 0);
         glDrawPixels(checkImageWidth, checkImageHeight, GL_RGB,
                      GL_UNSIGNED_BYTE, checkImage);
         glFlush();
      }
      

      You may zoom and drag the board:

      void motion(int x, int y)
      {
         static GLint screeny;
      
         screeny = height - (GLint) y;
         glRasterPos2i (x, screeny);
         glPixelZoom (zoomFactor, zoomFactor);
         glCopyPixels (0, 0, checkImageWidth, checkImageHeight, GL_COLOR);
         glPixelZoom (1.0, 1.0);
         glFlush ();
      }
      
      void keyboard(unsigned char key, int x, int y)
      {
         switch (key) {
            case 'r':
            case 'R':
               zoomFactor = 1.0;
               glutPostRedisplay();
               printf ("zoomFactor reset to 1.0\n");
               break;
            case 'z':
               zoomFactor += 0.5;
               if (zoomFactor >= 3.0) 
                  zoomFactor = 3.0;
               printf ("zoomFactor is now %4.1f\n", zoomFactor);
               break;
            case 'Z':
               zoomFactor -= 0.5;
               if (zoomFactor <= 0.5) 
                  zoomFactor = 0.5;
               printf ("zoomFactor is now %4.1f\n", zoomFactor);
               break;
            case 27:
       exit(0);
               break;
            default:
               break;
         }
      }
      
      int main(int argc, char** argv)
      {
         glutInit(&argc, argv);
         glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
         glutInitWindowSize(250, 250);
         glutInitWindowPosition(100, 100);
         glutCreateWindow(argv[0]);
         init();
         glutDisplayFunc(display);
         glutReshapeFunc(reshape);
         glutKeyboardFunc(keyboard);
         glutMotionFunc(motion);
         glutMainLoop();
         return 0; 
      }