Cover page images (elite)

Laboratorio Grafica al Calcolatore 2009/2010: Lecture 1 - Windows and Basic rendering

Roberto Toldo, <nome.cognome@univr.it >




Hit the space bar for next slide

Lecture Objectives

At the completion of this module, you will be able to

OpenGL is for Rendering, not Windowing

OpenGL is designed for 2D and 3D rendering only

GLUT to the Rescue!

There many differences in the main loops, messaging, and other aspects of IRIX versus Windows NT programs, especially when using the Microsoft Foundation Classes (MFC) in the latter.

GLUT is used in this course so that we can concentrate on OpenGL

Note: GLUT is a bit out of date, but is simple and still fits our scope. Other cross-platform, more complete, library exists, e.g. freeglut, SDL ...

Initializing the GLUT Library

int glutInit( int *argcp, char **argv )

Retrieving GLUT State Information

int glutGet( GLenum state )

Initializing the Window Size and Position

void glutInitWindowSize( int width, int height ) 
void glutInitWindowPosition( int x, int y )

Notes:

Because window size does not include borders, you get exactly the usable area that you ask for.

Configuring a Window

void glutInitDisplayMode( GLenum mode ) 

Bitmasks Description
GLUT_RGBA
Request RGBA window (default)
GLUT_RGB
An alias for GLUT_RGBA
GLUT_INDEX
Request color-index window
GLUT_SINGLE
Request single-buffered window (default)
GLUT_DOUBLE
Request double-buffered window
GLUT_DEPTH
Request accompanying depth buffer (default)
GLUT_STENCIL
Request accompanying stencil buffer
GLUT_ACCUM
Request accompanying accumulation buffer
GLUT_ALPHA
Request accompanying alpha destination buffer
GLUT_MULTISAMPLE
Request a window with multi-sampling support
GLUT_STEREO
Request a window with stereo support
GLUT_LUMINANCE
Request a window with a luminance color model

Notes:

You can bitwise-OR modes together to get a window with multiple features, however, some of the modes are mutually exclusive. For example, if you specify both double and single buffering, you will get a double buffered window. If you specify both color index and RGBA mode, you will get an RGBA window.

See the glutInitDisplayMode man page for the current list of display mode bitmasks.

Creating a Window

int glutCreateWindow( char *title ) 

Notes:

All of the examples in this class pass argv[0] to glutCreateWindow, so that the title matches the name of the program.

    glutCreateWindow( argv[0] );

Registering a Display Function

void glutDisplayFunc( void (*func)(void) ) 

The Main Loop

After initializing the window(s), a GLUT program enters the GLUT event processing loop.

void glutMainLoop( GLvoid ) 

Example: window.c

/* window.c - open a window in a specified position */

#include <GL/glut.h>    /* includes gl.h, glu.h */

GLvoid drawScene( GLvoid );

void
main( int argc, char *argv[] )
{
    GLsizei width, height;

    glutInit( &argc, argv );

    /* create a window that is 1/4 the size of the screen,
    * and position it in the middle of the screen.
    */
    width = glutGet( GLUT_SCREEN_WIDTH ); 
    height = glutGet( GLUT_SCREEN_HEIGHT );
    glutInitWindowPosition( width / 4, height / 4 );
    glutInitWindowSize( width / 2, height / 2 );
    glutInitDisplayMode( GLUT_RGBA );
    glutCreateWindow( argv[0] );

    glutDisplayFunc( drawScene );
    glutMainLoop();
}

GLvoid
drawScene( GLvoid )
{
    /* You will do all of your OpenGL rendering here */
}

Notes:

This program simply creates a window. A display function is specified, but it does not do any rendering.

The program uses glutGet() to find the screen dimensions, and uses this information to specify the position and size of the window.

The program uses glutInitDisplayMode() to specify the type of window to use, and then creates the window using glutCreateWindow(). The program passes argv[0] to glutCreateWindow() so that the title bar will display the program name.

Lastly, the program enters the event processing loop.

Lab: Configuring an IDE and Compiling

Objective: Compile window.c using an IDE(Integrated development environment).

Configuring glut with Eclipse under a linux system ***


Configuring glut with Visual Studio under a Microsoft Windows


Clearing the Window

GLvoid glClear( GLbitfield mask ) 

Setting the Clear Color

GLvoid glClearColor(GLclampf red, GLclampf green,
                    GLclampf blue, GLclampf alpha)

Making Sure Everything Is Drawn

GLvoid glFlush( GLvoid ) 

Really Making Sure Everything Is Drawn

GLvoid glFinish( GLvoid ) 

Checking For Errors

To minimize the impact on performance, OpenGL just sets a flag when an error occurs.

       GLenum glGetError( GLvoid ) 

Example: background.c

/* background.c - open a window and clear the background.
 *   glutMainLoop() calls drawScene whenever the window needs
 *   to be updated.
 */

#include <GL/glut.h>    /* includes gl.h, glu.h */

#include <stdio.h>

/* Function Prototypes */
GLvoid initgfx( GLvoid );
GLvoid drawScene( GLvoid );
void checkError( char * );

void
main( int argc, char *argv[] )
{
    GLsizei width, height;

    glutInit( &argc, argv );

    /* create a window that is 1/4 the size of the screen,
     * and position it in the middle of the screen.
     */

    width = glutGet( GLUT_SCREEN_WIDTH ); 
    height = glutGet( GLUT_SCREEN_HEIGHT );
    glutInitWindowPosition( width / 4, height / 4 );
    glutInitWindowSize( width / 2, height / 2 );
    glutInitDisplayMode( GLUT_RGBA );
    glutCreateWindow( argv[0] );

    initgfx();

    glutDisplayFunc( drawScene ); 
    glutMainLoop();
}

GLvoid
initgfx( GLvoid )
{
    /* set clear color to magenta */
    glClearColor( 1.0, 0.0, 1.0, 1.0 );
}

void 
checkError( char *label )
{
    GLenum error;
    while ( (error = glGetError()) != GL_NO_ERROR )
        printf( "%s: %s\n", label, gluErrorString(error) );
}

GLvoid
drawScene( GLvoid )
{
    glClear( GL_COLOR_BUFFER_BIT );

    /* Do all your OpenGL rendering here */

    checkError( "drawScene" );
    glFlush();
}

Notes:

This is the same program as window.c, except that we have added some actual OpenGL rendering and error checking.

The clear color is set to something other than the default in initgfx().

The first thing drawScene() does is call glClear() to repaint the window to the clear color. It then calls checkError() to check if any error flags were set, and glFlush() to force the rendering to start.

stdio.h was included for printf().

Input Processing

A variety of input devices can be used to control the behavior of your program.

Keyboard Callback for ASCII Input

void glutKeyboardFunc( void (*func)(unsigned char key,
                       int x, int y) )
       void keyboard(unsigned char key, int x, int y)
       {
            switch (key) {
            case ' ':    /* space key */
                 /* change background color */
                 break;
            case 27:     /* Escape key */
                 exit(0);
            }
       }

Keyboard Callback for Special Keys

void glutSpecialFunc( void (*func)(int key, int x, 
                      int y) )
       void specialkeys(int key, int x, int y) 
       {
            switch (key) {
            case GLUT_KEY_F1:
                 /* print Help information */
                 break;
            case GLUT_KEY_UP:
                 /* move viewpoint up */
                 break;
            }
       }

Forcing a Redisplay

When you modify something that affects your scene, you must tell the window system.

void glutPostRedisplay( void )

Example: input.c

/* input.c - open a window and clear the background.
 *             Set up a callback to handle ASCII keyboard input.
 *
 *     SPACE key         - generates a random background color
 *     Escape Key        - exit program
 */

#include <GL/glut.h>    /* includes gl.h, glu.h */

#include <stdlib.h>
#include <stdio.h>
#include <math.h>

/* Function Prototypes */

GLvoid initgfx( GLvoid );
GLvoid keyboard( GLubyte, GLint, GLint );
GLvoid drawScene( GLvoid );

void checkError( char * );
void printHelp( char * );

/* Global Definitions */

#define KEY_ESC     27      /* ascii value for the escape key */

/* Macro RANDOM() provides a consistent interface across both
 * IRIX and NT platforms to returns a random number between
 * 0.0 and 1.0.
 */
#ifdef WIN32
#define RANDOM()      ((double)rand()/RAND_MAX)
#endif
#ifdef __sgi
#define RANDOM()      drand48()
#endif


void
main( int argc, char *argv[] )
{
    GLsizei width, height;

    glutInit( &argc, argv );

    width = glutGet( GLUT_SCREEN_WIDTH ); 
    height = glutGet( GLUT_SCREEN_HEIGHT );
    glutInitWindowPosition( width / 4, height / 4 );
    glutInitWindowSize( width / 2, height / 2 );
    glutInitDisplayMode( GLUT_RGBA );
    glutCreateWindow( argv[0] );

    initgfx();

    glutKeyboardFunc( keyboard );
    glutDisplayFunc( drawScene ); 

    printHelp( argv[0] );

    glutMainLoop();
}

void
printHelp( char *progname )
{
    fprintf(stdout, 
            "\n%s - demonstrates how to handle keyboard input\n\n"
            "SPACE Key      - generates a random background color\n"
            "Escape Key     - exit the program\n\n",
            progname);
}

GLvoid
initgfx( GLvoid )
{
    /* set clear color to magenta */
    glClearColor( 1.0, 0.0, 1.0, 1.0 );
}

void 
checkError( char *label )
{
    GLenum error;
    while ( (error = glGetError()) != GL_NO_ERROR )
         printf( "%s: %s\n", label, gluErrorString(error) );
}

GLvoid 
keyboard( GLubyte key, GLint x, GLint y )
{
    switch (key) {
    case ' ':              /* SPACE key */
         /* generate a random background color */
         glClearColor( RANDOM(), RANDOM(), RANDOM(), 1.0 ); 
         glutPostRedisplay();
         break;
    case KEY_ESC:     /* Exit when the Escape key is pressed */
         exit(0);
    }
}

GLvoid
drawScene( GLvoid )
{
    glClear( GL_COLOR_BUFFER_BIT );

    /* Do all your OpenGL rendering here */

    checkError( "drawScene" );
    glFlush();
}

Notes:

This program is the same as the background program, except that it uses a keyboard callback function to handle input.

The keyboard callback recognizes two keys: the <Space> key, and the <Escape> key. When the <Space> key is pressed, it randomly changes the background color. When the <Escape> key is pressed, the program exits.

The macro RANDOM() is used in this program to provide a consistent interface across both IRIX and NT platforms. If you wish to use RANDOM() in your lab programs, it is defined in the file ~opengl/include/random.h.

Lab: Color and Input

  1. Find a color that you would like to use as a background color.

  2. Have you downloaded source code?
    Download it: LaboratorioGrafica.zip and the README file for explanations.

  3. Modify your ../tutorial/exercises/clearcolor.c program to

    o Exit when the <Esc> key is pressed

    o Use keyboard input to change the clear color

    o Print help information when the <F1> key is pressed

  4. Compile and run your program either using make:
            make clearcolor 
            ./clearcolor
    

    or an IDE.

Glut C Quick Reference

GLvoid glClear( GLbitfield mask ) 

Paints the current window with the current clear color. The four values that can be bitwise ORed into mask are GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_ACCUM_BUFFER_BIT, and GL_STENCIL_BUFFER_BIT.


GLvoid glClearColor( GLclampf red, GLclampf green,
GLclampf blue, GLclampf alpha )

Sets the current clear color.


GLvoid glFinish( GLvoid ) 

Forces all pending operations to complete.


GLvoid glFlush( GLvoid )

Forces all pending operations to begin.


GLenum glGetError( GLvoid ) 

Returns a constant identifying one error at a time.


const GLubyte* gluErrorString( GLenum errorCode )

Returns an error message string for the specified OpenGL or GLU error code.


int glutCreateWindow( char *title )

Returns a unique identifier for the new window title is displayed in the window's title bar


void glutDisplayFunc( void (*func)(void) ) 

Sets up a callback function to update the contents of the window for the current window.


int glutGet( GLenum state )

Retrieves GLUT state information. For a full list of the state constants, see the GLUT specification.


int glutInit( int *argcp, char **argv )

Initializes the GLUT library and negotiates a session with the window system.


void glutInitWindowSize( int width, int height ) 

Sets window width and height in pixels, not including borders.


void glutInitWindowPosition( int x, int y ) 

Sets window position in pixels relative to the upper-left corner of the screen.


void glutInitDisplayMode( GLenum mode )

Specifies the type of window to create. mode is a bitwise-OR of bitmasks.


void glutMainLoop( GLvoid ) 

An infinite loop that invokes callbacks, as necessary. Must be last function in main().


void glutKeyboardFunc( void (*func)(unsigned char key, int
 x, int y) )

Sets up a keyboard callback function for the current window, to be invoked when an ASCII key is pressed.


void glutSpecialFunc( void(*func)(int key, int x, int y) )

Sets up a special key callback for the current window. key is a GLUT_KEY_* constant indicating which key was pressed.


void glutPostRedisplay( void )

Marks the current window as needing to be redisplayed.

Rendering With OpenGL

Vertices

What Are World Coordinates?

World coordinates are where your geometric models live. They are

Defining the Viewing Volume

GLvoid glOrtho( GLdouble left, GLdouble right,
                GLdouble bottom, GLdouble top,
                GLdouble nearClip, GLdouble farClip );

Notes:

The viewing volume and the glOrtho function are discussed more fully in next Lecture, "Basic Transformations".

Note that the variable names nearClip and farClip are used, rather than near and far. The words near and far are reserved in Microsoft Visual C++, and must be avoided in code that is intended to be portable.

Viewing Volume Is Mapped to Window

Objects rendered outside of the viewing volume are clipped (not drawn).

   glOrtho( -2.0, 2.0, -2.0, 2.0, -2.0, 2.0 );

Specifying Vertices

GLvoid glVertex2f( GLfloat x, GLfloat y )

Partial List of Vector and Scalar Forms for glVertex*()
Scalar Forms Vector Forms
glVertex2s( x, y )
glVertex2i( x, y )
glVertex2f( x, y )
glVertex2d( x, y )
glVertex2sv( v )
glVertex2iv( v )
glVertex2fv( v )
glVertex2dv( v )
z = 0
w = 1
glVertex3s( x, y, z )
glVertex3i( x, y, z )
glVertex3f( x, y, z )
glVertex3d( x, y, z )
glVertex3sv( v )
glVertex3iv( v )
glVertex3fv( v )
glVertex3dv( v )
w = 1

Drawing Geometric Primitives

GLvoid glBegin( GLenum mode )

GLvoid glEnd( GLvoid )

mode Description
GL_POINTS
Points
GL_LINES
Disconnected line segments
GL_LINE_STRIP
Connected line segments
GL_LINE_LOOP
Closed line segments
GL_POLYGON
Polygon
GL_TRIANGLES
Disconnected Triangles
GL_TRIANGLE_STRIP
Connected triangles that form a strip
GL_TRIANGLE_FAN
Connected triangles that form a fan
GL_QUADS
Disconnected quadrilaterals
GL_QUAD_STRIP
Connected quadrilaterals

Notes:

A common programming typographical error is glBegin(GL_LINE) -- note that it should be GL_LINES with an S. The code compiles but causes a runtime OpenGL error. The rest of the glBegin()/glEnd() block is ignored.

Another common error is to forget the parenthesis after glEnd. This is a legal C statement, but it doesn't do anything useful. Your glBegin()/glEnd() will not be properly terminated, and you will generally get errors.

Calling checkError() at the bottom of drawScene is a good way to find these types of errors.

glBegin()/ glEnd() pairs cannot be nested.

Points

Every vertex produces a point.

static float v[] = { 0.3, 0.7 };

glPointSize( 3.5 );
glBegin( GL_POINTS );
   glVertex2fv( v );
   glVertex2f( 0.6, 0.2 );
glEnd();

Use glPointSize( GLfloat size ) to control the size of the points.

Notes:

Note that the points are square. This is because pixels are square.

Both scalar and vector forms of glVertex*() can be intermixed in the same glBegin()/glEnd() group.

The size parameter for glPointSize() specifies the diameter in pixels of the point. Non-integral sizes are rounded to the nearest integer.

Be aware that glPointSize() cannot be called inside a glBegin()/glEnd block().

Specifying an Object's Color

GLvoid glColor3f( GLfloat red, GLfloat green,
                  GLfloat blue )

Notes:

Vector and scalar forms of glColor*()

Data Type Scalar Forms Vector Forms
GLbyte glColor3b(r, g, b) glColor3bv(v)
GLubyte glColor3ub(r, g, b) glColor3ubv(v)
GLshort glColor3s(r, g, b) glColor3sv(v)
GLushort glColor3us(r, g, b) glColor3usv(v)
GLint glColor3i(r, g, b) glColor3iv(v)
GLuint glColor3ui(r, g, b) glColor3uiv(v)
GLfloat glColor3f(r, g, b) glColor3fv(v)
GLdouble glColor3d(r, g, b) glColor3dv(v)

Lines

Every pair of vertices produces a line segment.

static float v[] = { 0.3, 0.7 };

glColor3f( 1.0, 0.0, 0.0 );
glLineWidth( 2.5 );
glBegin( GL_LINES );
   glVertex2fv( v );
   glVertex2f( 0.6, 0.2 );
   glVertex2f( 0.3, 0.2 );
   glVertex2f( 0.6, 0.7 );
glEnd();

Use glLineWidth( GLfloat size ) to control the width of the lines.

Notes:

The width parameter for glLineWidth() specifies the width of the line. Non-integral widths are rounded to the nearest integer.

Be aware that glLineWidth() cannot be called inside a glBegin()/glEnd block().

Modeling

Modeling is the process of composing more complex objects using OpenGL primitives.

Notes:

You will need to determine all of the vertices that make up your object.

Hint: It is usually easier to model objects near the origin.

Example: grid.c

/*  grid.c  - open a window, clear the background, and render a
 *       grid of points or lines centered around the origin.
 *
 *     SPACE key       - toggle between point/line grid
 *     ESCAPE key      - exit program
 */

#include <GL/glut.h>    /* includes gl.h, glu.h */

#include <stdio.h>

/*  Function Prototypes  */

GLvoid  initgfx( GLvoid );
GLvoid  keyboard( GLubyte, GLint, GLint );
GLvoid  drawScene( GLvoid );

void printHelp( char * );

/* Global Definitions */

#define KEY_ESC        27      /* ascii value for the escape key */

static GLint pointGrid = GL_TRUE;

void
main( int argc, char *argv[] )
{
   GLsizei width, height;

   glutInit( &argc, argv );

   width = glutGet( GLUT_SCREEN_WIDTH ); 
   height = glutGet( GLUT_SCREEN_HEIGHT );
   glutInitWindowPosition( width / 4, height / 4 );
   glutInitWindowSize( width / 2, height / 2 );
   glutInitDisplayMode( GLUT_RGBA );
   glutCreateWindow( argv[0] );

   initgfx();

   glutKeyboardFunc( keyboard );
   glutDisplayFunc( drawScene ); 

   printHelp( argv[0] );

   glutMainLoop();
}

void
printHelp( char *progname )
{
   fprintf(stdout, 
           "\n%s - demonstrates simple rendering primitives\n\n"
           "SPACE Key      - toggle between point/line grid\n"
           "Escape Key     - exit the program\n\n",
           progname);
}

GLvoid
initgfx( GLvoid )
{
   glClearColor( 0.0, 0.0, 1.0, 1.0 );

   glOrtho( -2.0, 2.0, -2.0, 2.0, -1.0, 1.0 );
}

GLvoid 
keyboard( GLubyte key, GLint x, GLint y )
{
   switch (key) {
   case ' ':
       pointGrid = !pointGrid;
       glutPostRedisplay();
       break;
   case KEY_ESC:   /* Exit whenever the Escape key is pressed */
       exit(0);
   }
}

GLvoid
drawScene( GLvoid )
{
   GLfloat x, y;

   glClear( GL_COLOR_BUFFER_BIT );

   glColor3f( 1.0, 1.0, 1.0 );

   if (pointGrid) {
       /* Render a grid composed of evenly spaced points */
       glPointSize( 3.5 ); 

       glBegin( GL_POINTS );
          for ( x = -1.0; x < 1.1; x += 0.1 ) 
             for ( y = -1.0; y < 1.1; y += 0.1 )
                glVertex2f( x, y );
       glEnd();
   } else {
       /* Draw a line grid centered at the origin */
       glLineWidth( 2.5 );

       glBegin( GL_LINES );
          for ( x = -1.0; x < 1.1; x += 0.1 ) {/* draw vertical lines */
             glVertex2f( x, -1.0 );
             glVertex2f( x, 1.0 );
          }
          for ( y = -1.0; y < 1.1; y += 0.1 ) {/* draw horizontal lines */
             glVertex2f( -1.0, y );
             glVertex2f( 1.0, y );
          }
       glEnd();
   }

   glFlush();
}

Notes:

This program draws a grid centered around the origin. The <Space> key can be pressed to toggle between a line grid and a point grid.

initgfx() calls glOrtho() to set up the viewing volume.

The following are calls in drawScene():

In this program the point and line sizes could have been set in initgfx(). They are set in drawScene() because in many programs these attributes are set and changed several times within a scene.

Line Segments

Connected

float v[] = { 0.3, 0.7 };

glBegin( GL_LINE_STRIP );
   glVertex2fv( v );
   glVertex2f( 0.6, 0.2 );
   glVertex2i( 1, 1 );
glEnd();

Closed

float v[] = { 0.3, 0.7 };

glBegin( GL_LINE_LOOP );
   glVertex2fv( v );
   glVertex2f( 0.6, 0.2 );
   glVertex2i( 1, 1 );
glEnd();

Polygons

Draws a simple convex polygon.

static float v[] = { 0.5, 0.1 };

glBegin( GL_POLYGON );
   glVertex2fv( v );
   glVertex2f( 0.9, 0.3 );
   glVertex2f( 0.8, 0.9 );
   glVertex2f( 0.3, 0.7 );
   glVertex2f( 0.2, 0.4 );
glEnd();

Polygons are filled by default.

Constraints on Polygons

OpenGL places restrictions on what constitutes a primitive polygon.

Non-convex polygons do not meet these constraints and may not render correctly.

Notes:

For a polygon to be convex, any line connecting two points in the polygon must lie entirely inside of the polygon.

Polygons that are not coplanar may become non-convex when viewed from a different viewpoint.

Non-convex filled polygons might not draw as expected. On many systems only the convex hull will be filled.

Break non-convex polygons into sets of convex polygons (triangles). This is called tessellation. The GLU library provides some tessellation functions (see the gluBeginPolygon(3G) man page).

Polygon Faces

GLvoid glFrontFace( GLenum mode )

Notes:

The decision of whether a face is front or back depends on the sign of the polygon's area computed in window coordinates.

If glFrontFace() is not called, counterclockwise vertex ordering is assumed to specify the front face.

By default, both front and back polygons are drawn, even though we may never see the back side. You will learn how to tell OpenGL not to draw the unseen faces in the Depth Buffering module.

Rectangles

OpenGL provides an efficient way to draw filled rectangles.

GLvoid glRectf( GLfloat x1, GLfloat y1, GLfloat 
                x2, GLfloat y2 )

Example: checkerboard.c

/*  checkerboard.c  - open a window, clear the background, and 
 *       render a checkerboard composed of flat shaded rectangles.
 *
 *     Escape key   - exit program
 */
#include <GL/glut.h>    /* includes gl.h, glu.h */
#include <stdio.h>

/*  Function Prototypes  */

GLvoid  initgfx( GLvoid );
GLvoid  keyboard( GLubyte, GLint, GLint );
GLvoid  drawScene( GLvoid );

void printHelp( char * );

/* Global Definitions */

#define KEY_ESC        27      /* ascii value for the escape key */

void
main( int argc, char *argv[] )
{
   GLsizei width, height;

   glutInit( &argc, argv );

   /* create a window that is 1/4 the size of the screen,
    * and position it in the middle of the screen.
    */

   width = glutGet( GLUT_SCREEN_WIDTH ); 
       height = glutGet( GLUT_SCREEN_HEIGHT );
       glutInitWindowPosition( width / 4, height / 4 );
       glutInitWindowSize( width / 2, height / 2 );
       glutInitDisplayMode( GLUT_RGBA );
       glutCreateWindow( argv[0] );

       initgfx();

       glutKeyboardFunc( keyboard );
       glutDisplayFunc( drawScene ); 

       printHelp( argv[0] );

       glutMainLoop();
}

void
printHelp( char *progname )
{
   fprintf(stdout, "\n%s - renders a checkerboard\n\n"
           "Escape Key   - exit the program\n\n",
           progname);
}

GLvoid
initgfx( GLvoid )
{
   glClearColor( 0.0, 0.0, 1.0, 1.0 );

   glOrtho( -2.0, 2.0, -2.0, 2.0, -1.0, 1.0 );
}

GLvoid 
keyboard( GLubyte key, GLint x, GLint y )
{
   switch (key) {
   case KEY_ESC:   /* Exit whenever the Escape key is pressed */
       exit(0);
   }
}

GLvoid
drawScene( GLvoid )
{
   GLfloat         x, y;

   static GLfloat  redColor[] = { 1.0, 0.0, 0.0 };
   static GLfloat  blackColor[] = { 0.0, 0.0, 0.0 };

   /* alternate between red and black rectangles */
   GLboolean       useRed = GL_TRUE;  

   glClear( GL_COLOR_BUFFER_BIT );

   /* Draw a checkerboard composed of 0.1 by 0.1 rectangles 
    * (For convenience, this code as been added to the class 
    * library as Checkerboard()).
    */

   for ( x = -1.0; x < 1.0; x += 0.1 ) {
      useRed = !useRed;
      for ( y = -1.0; y < 1.0; y += 0.1 ) {
         if ( useRed )
            glColor3fv( redColor );
         else
            glColor3fv( blackColor );
         glRectf( x, y, x + 0.1, y + 0.1 );
         useRed = !useRed;
      }
   }

   glFlush();
}

Notes:

This program draws red and black squares in an alternating pattern to form a checkerboard. Note the calls to glRectf*() in drawScene().

To save space in future examples, the code to create the checkerboard has been added to the class library in a function called Checkerboard(). You can use this function in your laboratory exercises.

Lab: Rendering

  1. For the shapes below, indicate how you would set up your viewing volume, and list the sequence of color and drawing routines you would use to create them.
    If you enter in the directory ../tutorial/exercises you'll find some files (shape_{a,b,c,d}.c) from which you can start: follow comments to understand where and what you must insert in the program.




  2. Moreover, in the directory ../tutorial/exercises you can find the incomplete program objects.c.
    The goal is modify the program to add some simple modeled objects into drawScene().
    When you'll edit the file objects.c you'll find some comments: follow them to complete the program.

Notes:

For example, you might create a building with an angled roof, a door and windows, or a stick figure of a tree, or an aerial view of a sports field.

Triangles

Draws a series of independent triangles.

glBegin( GL_TRIANGLES );
         /* first triangle */
       glVertex2f( 0.3, 0.7 );
       glVertex2f( 0.6, 0.2 );
       glVertex2i( 1, 1 );

       /* second triangle */
       glVertex2f( 0.2, 0.8 );
       glVertex2f( 0.3, 1.0 );
       glVertex2f( 0.1, 0.9 );
glEnd();

Triangle Strips and Fans

Strips

Draws a series of triangles that share sides.

  • This is generally the fastest way to draw 3D surfaces, use whenever possible.
glBegin( GL_TRIANGLE_STRIP );
   glVertex3fv( v0 );
   glVertex3fv( v1 );
   glVertex3fv( v2 );
   glVertex3fv( v3 );
   glVertex3fv( v4 );
   glVertex3fv( v5 );
glEnd();

Fans

Draws a series of triangles with v0 at the center.

  • Useful for rendering filled arcs and circles.
glBegin( GL_TRIANGLE_FAN );
   glVertex3fv( v0 );
   glVertex3fv( v1 );
   glVertex3fv( v2 );
   glVertex3fv( v3 );
   glVertex3fv( v4 );
   glVertex3fv( v5 );
glEnd();

Notes:

The drawing order for triangle strips is such that the orientation (CW or CCW) is the same for all triangles:

   (v0,v1,v2), (v2,v1,v3), (v2,v3,v4), (v4,v3,v5)

Drawing triangle strips is generally the fastest way to draw 3D surfaces because

The drawing order for triangle fans is such that the orientation is the same for all triangles:

   (v0,v1,v2), (v0,v2,v3), (v0,v3,v4), (v0,v4,v5)

For those with an IRIS GL background, there is no equivalent of the IRIS GL function swaptmesh() in OpenGL. To get the behavior of swaptmesh() (although without the efficiency), specify the last vertex again instead of calling swaptmesh().

The "Lecture Summary" contains more information on triangle strips and fans.

Quads

Draws a series of independent quadrilaterals.

glBegin( GL_QUADS );
       /* draw first quad */
         glVertex3fv( v0 );
         glVertex3fv( v1 );
         glVertex3fv( v2 );
         glVertex3fv( v3 );

         /* draw second quad */
         glVertex3fv( v4 );
         glVertex3fv( v5 );
         glVertex3fv( v6 );
         glVertex3fv( v7 );
glEnd();

Notes:

GL_QUADS is faster than GL_POLYGON for four sided polygons.

Hint: Independent quadrilaterals should be lumped together and drawn in one begin/end block if possible.

Quad Strips

Draws a series of quadrilaterals that share sides.

glBegin( GL_QUAD_STRIP );
       glVertex3fv( v0 );
       glVertex3fv( v1 );
       glVertex3fv( v2 );
       glVertex3fv( v3 );
       glVertex3fv( v4 );
       glVertex3fv( v5 );
       glVertex3fv( v6 );
       glVertex3fv( v7 );
       glVertex3fv( v8 );
       glVertex3fv( v9 );

glEnd();

Notes:

The drawing order is such that the orientation is the same for all quadrilaterals:

(v0,v1,v3,v2),(v2,v3,v5,v4),(v4,v5,v7,v6), (v6,v7,v9,v8)

It is important that the quadrilaterals be coplanar. Quadrilaterals can be used for modeling things that you know will not produce a non-coplanar set of points, such as a cylinder.

Shading Models

A line or filled polygon can be drawn with a single color or with many different colors.

Flat Shading

GLvoid glShadeModel( GLenum mode )

glShadeModel( GL_FLAT );
glBegin( GL_POLYGON );
       glColor3fv( red );     /* this call sets the color */
       glVertex2f( 0.7, 0.8 ); 
       glColor3fv( white );    /* this call is ignored */
       glVertex2f( 0.1, 0.1 );
       glVertex2f( 0.9, 0.1 ); 
glEnd();

Notes:

Counting vertices (starting from 1 after glBegin()):

Primitive Vertex that determines primitive's color
Single polygon (i=1) 1
Triangle strip i+2
Triangle fan i+2
Independent triangle 3i
Quad strip 2i+2
Independent quad 4i

Smooth Shading

GLvoid glShadeModel( GLenum mode )

glShadeModel( GL_SMOOTH );
glBegin( GL_POLYGON );
       glColor3fv( red ); 
       glVertex2f( 0.7, 0.8 ); 
       glColor3fv( white );
       glVertex2f( 0.1, 0.1 ); 
       glVertex2f( 0.9, 0.1 ); 
glEnd();

Example: shadeModel.c

/*  shadeModel.c  - open a window, clear the background, and render a
 *     line, a triangle fan and a quad strip using flat/smooth shading.
 *
 *     SPACE key       - toggle between flat/smooth shading
 *     ESCAPE key      - exit program
 */

#include <GL/glut.h>    /* includes gl.h, glu.h */

#include <stdio.h>

/*  Function Prototypes  */

GLvoid  initgfx( GLvoid );
GLvoid  keyboard( GLubyte, GLint, GLint );
GLvoid  drawScene( GLvoid );

void printHelp( char * );

/* Global Definitions */

#define KEY_ESC        27      /* ascii value for the escape key */

static GLint flatShading = GL_FALSE;

void
main( int argc, char *argv[] )
{
   GLsizei width, height;

   glutInit( &argc, argv );

   width = glutGet( GLUT_SCREEN_WIDTH ); 
   height = glutGet( GLUT_SCREEN_HEIGHT );
   glutInitWindowPosition( width / 4, height / 4 );
   glutInitWindowSize( width / 2, height / 2 );
   glutInitDisplayMode( GLUT_RGBA );
   glutCreateWindow( argv[0] );

   initgfx();

   glutKeyboardFunc( keyboard );
   glutDisplayFunc( drawScene ); 

   printHelp( argv[0] );

   glutMainLoop();
}

void
printHelp( char *progname )
{
   fprintf(stdout, "\n%s - demonstrates shading models\n\n"
           "SPACE Key    - toggle between flat/smooth shading\n"
           "Escape Key   - exit the program\n\n",
           progname);
}

GLvoid
initgfx( GLvoid )
{
   glClearColor( 0.0, 0.0, 1.0, 1.0 );

   glOrtho( 0.0, 1.0, 0.0, 1.0, -1.0, 1.0 );
}

GLvoid 
keyboard( GLubyte key, GLint x, GLint y )
{
   switch (key) {
   case ' ':
       flatShading = !flatShading;
       if (flatShading) 
           glShadeModel(GL_FLAT);
       else
           glShadeModel(GL_SMOOTH);
       glutPostRedisplay();
       break;
   case KEY_ESC:   /* Exit whenever the Escape key is pressed */
       exit(0);
   }
}

GLvoid
drawScene( GLvoid )
{
   static GLfloat    blackColor[] = { 0.0, 0.0, 0.0 };
   static GLfloat    redColor[]  = { 1.0, 0.0, 0.0 };
   static GLfloat    purpleColor[] = { 1.0, 0.0, 1.0 };
   static GLfloat    yellowColor[] = { 1.0, 1.0, 0.0 };
   static GLfloat    whiteColor[] = { 1.0, 1.0, 1.0 };
   static GLfloat    darkgreenColor[] = { 0.0, 0.5, 0.0 };
   
   glClear( GL_COLOR_BUFFER_BIT );

   /* Draw a point */
   glBegin( GL_POINTS );
     glColor3fv( whiteColor );
     glVertex2f( 0.3, 0.85 );
     glColor3f( 1.0, 0.50, 0.0 );   /* Orange */
     glVertex2f( 3.0, 9.65 );       /* This point is clipped */
   glEnd();

   /* Gouraud shade a line */
   glBegin( GL_LINES );
     glColor3f( 1.0, 0.0, 0.0 );    /* Red */
     glVertex2f( 0.1, 0.1 );
     glColor3fv( yellowColor );
     glVertex2f( 0.2, 0.9 );
   glEnd();

   /* Gouraud shade a polygon */
   glBegin( GL_POLYGON );
     glColor3fv( purpleColor );
     glVertex2f( 0.5, 0.1 );
     glColor3fv( redColor );
     glVertex2f( 1.0, 0.4 );
     glColor3fv( blackColor );
     glVertex2f( 0.9, 1.0 );
     glColor3fv( darkgreenColor );
     glVertex2f( 0.3, 0.8 );
     glColor3fv( whiteColor );
     glVertex2f( 0.1, 0.5 );
   glEnd();

   /* Draw a triangle fan */
   glBegin( GL_TRIANGLE_FAN );
     glColor3fv( blackColor );
     glVertex2f( 0.4, 0.4 );
     glColor3fv( redColor );
     glVertex2f( 0.3, 0.4 );
     glColor3f( 0.0, 0.0, 1.0 );   /* blue */
     glVertex2f( 0.4, 0.5 );
     glColor3fv( yellowColor );
     glVertex2f( 0.5, 0.5 );
     glColor3fv( whiteColor );
     glVertex2f( 0.5, 0.4 );
     glColor3fv( darkgreenColor );
     glVertex2f( 0.4, 0.3 );
   glEnd();

   glFlush();
}

Notes:

This program renders points, a line, a polygon and a triangle fan. Press the <Space> key to toggle between flat and smooth shading.

What calls to glColor*() affect the color of the individual triangles in the fan when smooth shading is enabled?

What color call determines the primitive color when flat shading is enabled?

Hints for Fast Rendering

Lab: Rendering and the Shading Model

  1. Change directory to ../siggraph_2001_demos/bin and run ./shape.
    This tutorial program allows you to choose a geometric primitive and adjust its parameters.
    To change primitive you must move the mouse cursor on the right side of the windows and click the rigth mouse button. Now you can choose what you want.
    If you click the right mouse button on the left side of the window you can change other options.
    Exercise: for each primitive you must change parameters and the options.

  2. Use one or more of the following primitives to add some more objects to your objects.c program:
          GL_TRIANGLES
          GL_TRIANGLE_STRIP
          GL_TRIANGLE_FAN
          GL_QUADS
          GL_QUAD_STRIP
        
  3. Smooth shade at least one polygon in your scene.
    You can start from ../tutorial/exercises/objects2.c and add the missing window and the sun.

  4. Modify the program to toggle between smooth shading and flat shading when the <s> key is pressed.

OpenGL C Quick Reference

GLvoid glBegin( GLenum mode )
GLvoid glEnd( GLvoid )

Delimit the vertices of a primitive or a group of like primitives. Ten symbolic constants are accepted as the mode: GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP, and GL_POLYGON.


GLvoid glColor3[bsidf]( TYPE red, TYPE green, TYPE blue )
GLvoid glColor3u[bsi]( TYPE red, TYPE green, TYPE blue )
GLvoid glColor4[bsidf]( TYPE red, TYPE green, TYPE blue, 
TYPE alpha )
GLvoid glColor4u[bsi]( TYPE red, TYPE green, TYPE blue, 
TYPE alpha )
GLvoid glColor[34][bsidf]v( const TYPE *v )
GLvoid glColor[34]u[bsi]v( const TYPE *v )

Sets the current color using red, green, blue and alpha values. The coordinate type must match the command; byte (b), short (s), integer (i), double (d), float (f), unsigned byte (ub), unsigned short (ub) or unsigned integer (ui).


GLvoid glRect[sifd]( TYPE x1, TYPE y1, TYPE x2, TYPE y2 )
GLvoid glRect[sifd]v( const TYPE *v1, const TYPE *v2 )

Specify two vertices that define opposite corners of a filled rectangle. The coordinate type must match the command; byte (b), short (s), integer (i), double (d), or float (f).


GLvoid glShadeModel( Glenum mode )

Select flat or smooth shading. Accepted values for mode are: GL_FLAT, and GL_SMOOTH (default).


GLvoid glVertex2[bsidf]( TYPE x, TYPE y )
GLvoid glVertex3[bsidf]( TYPE x, TYPE y, TYPE z )
GLvoid glVertex4[bsidf]( TYPE x, TYPE y, TYPE z, TYPE w )
GLvoid glVertex[234][bsidf]v( const TYPE *v )

Specify a vertex using 2, 3, or 4 coordinates. The coordinate type must match the command; byte (b), short (s), integer (i), double (d), or float (f).

mElite 01: Let's start our elite

Our purpose is the creation of a simple clone of elite step-by-step. For knowing something more about this video game you can visit this web site:
http://www.iancgbell.clara.net/elite/.
The first step is to draw a planet and an artificial satellite in 2D using orthogonal projection and polygons as seen in lecture 2 and to handle the pression of some keys as introduced in lecture 1. Now, download the program sketch >>here<< and complete the code in ordert to:

You can click >>here<< to download a simple program that shows you what you have to realize. You have to run
chmod +x melite1b
if you want a successful execution of the program.