Open GL Super Bible

Previous Table of Contents Next


Listing 18-1 LETTER.C: Tessellating the polygon for the letter A

/*
 * "letter.c" - A test program demonstrating the use of the GLU polygon
 *              tessellator.
 */

#include <GL/glaux.h>

/*
 * These #define constants are provided for compatibility between MS
 * Windows and the rest of the world.
 *
 * CALLBACK and APIENTRY are function modifiers under MS Windows.
 */

#ifndef WIN32
#  define CALLBACK
#  define APIENTRY
#endif /* !WIN32 */

GLfloat rotation = 0.0;

/*
 * 'reshape_scene()' - Change the size of the scene…
 */

void CALLBACK
reshape_scene(GLsizei width,   /* I - Width of the window in pixels */
              GLsizei height)  /* I - Height of the window in pixels */
{
 /*
  * Reset the current viewport and perspective transformation…
  */

  glViewport(0, 0, width, height);

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(22.5, (float)width / (float)height, 0.1, 1000.0);

  glMatrixMode(GL_MODELVIEW);
}

/*
 * 'draw_scene()' - Draw a scene containing the letter A.

 */



void CALLBACK

draw_scene(void)

{

  GLUtriangulatorObj   *tess;

  static GLdouble      outside[7][3] =

  {

    { 0.0, 1.0, 0.0 },

    { -0.5, -1.0, 0.0 },

    { -0.4, -1.0, 0.0 },

    { -0.2, -0.1, 0.0 },

    { 0.2, -0.1, 0.0 },

    { 0.4, -1.0, 0.0
 },

{ 0.5,
-1.0,
0.0
  }   };
  static GLdouble      inside[3][3] =
  
        
        
        
        
        
        
        
  
          
  {
    { 0.0, 0.6, 0.0 },
    { -0.1, 0.1, 0.0 },
    { 0.1, 0.1, 0.0 }
  };
  static float   red_light[4] = { 1.0, 0.0, 0.0, 1.0 };
  static float   red_pos[4] = { 1.0, 1.0, 1.0, 0.0 };
  static float   blue_light[4] = { 0.0, 0.0, 1.0, 1.0 };
  static float   blue_pos[4] = { -1.0, -1.0, -1.0, 0.0 };

/*
  * Enable drawing features that we need…
  */

  glEnable(GL_DEPTH_TEST);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
  glEnable(GL_LIGHT1);

  glShadeModel(GL_SMOOTH);

 /*
  * Clear the color and depth buffers…
  */

  glClearColor(0.0, 0.0, 0.0, 0.0);
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 /*
  * Draw the cube and sphere in different colors…
  *
  * We have positioned two lights in this scene.  The first is red and
  * located above, to the right, and behind the viewer.  The second is blue
  * and located below, to the left, and in front of the viewer.
  */

  glLightfv(GL_LIGHT0, GL_DIFFUSE, red_light);
  glLightfv(GL_LIGHT0, GL_POSITION, red_pos);

  glLightfv(GL_LIGHT1, GL_DIFFUSE, blue_light);
  glLightfv(GL_LIGHT1, GL_POSITION, blue_pos);

  glEnable(GL_COLOR_MATERIAL);

  glPushMatrix();
    glTranslatef(0.0, 0.0, -15.0);
    glRotatef(-rotation, 0.0, 1.0, 0.0);

    glColor3f(0.0, 1.0, 0.0);

    tess = gluNewTess();
    gluTessCallback(tess, GLU_BEGIN, glBegin);
    gluTessCallback(tess, GLU_VERTEX, glVertex3dv);
    gluTessCallback(tess, GLU_END, glEnd);
    gluBeginPolygon(tess);
      gluTessVertex(tess, outside[0], outside[0]);
      gluTessVertex(tess, outside[1], outside[1]);
      gluTessVertex(tess, outside[2], outside[2]);
      gluTessVertex(tess, outside[3], outside[3]);
      gluTessVertex(tess, outside[4], outside[4]);
      gluTessVertex(tess, outside[5], outside[5]);
      gluTessVertex(tess, outside[6], outside[6]);
    gluNextContour(tess, GLU_INTERIOR);
      gluTessVertex(tess, inside[0], inside[0]);
      gluTessVertex(tess, inside[1], inside[1]);
      gluTessVertex(tess, inside[2], inside[2]);
    gluEndPolygon(tess);
    gluDeleteTess(tess);
  glPopMatrix();

  auxSwapBuffers();
}

/*
 * 'rotate_objects()' - Rotate while we are idle…
 */

void CALLBACK
rotate_objects(void)
{
  rotation += 2.0;
  if (rotation >= 360.0)
    rotation -= 360.0;

  draw_scene();
}

/*
 * 'main()' - Initialize the window and display the scene until the user
 *            presses the ESCape key.
 */

void
main(void)
{
  auxInitDisplayMode(AUX_RGB | AUX_DOUBLE | AUX_DEPTH);
  auxInitWindow("GLU Polygon Letter");

  auxReshapeFunc(reshape_scene);
  auxIdleFunc(rotate_objects);

  auxMainLoop(draw_scene);
}

Callback Functions

The glu defines several callback functions that can be used for special effects. The gluTessCallback function allows you to change these functions to do something of your own. It takes three arguments:

void gluTessCallback(GLUtriangulatorObj *tobj, GLenum which, void (*fn)());

The which argument specifies the callback function to define and must be one of the arguments in Table 18-2.

Table 18-2 Tessellator Callback Functions

which argument Description

GLU_BEGIN Specifies a function that is called to begin a GL_TRIANGLES, GL_TRIANGLE_STRIP, or GL_TRIANGLE_FAN primitive. The function must accept a single GLenum parameter that specifies the primitive to be rendered and is usually set to glBegin.
GLU_EDGE_FLAG Specifies a function that marks whether succeeding GLU_VERTEX callbacks refer to original or generated vertices. The function must accept a single GLboolean argument that is GL_TRUE for original and GL_FALSE for generated vertices.
GLU_VERTEX Specifies a function that is called before every vertex is sent, usually with glVertex3dv. The function receives a copy of the third argument to gluTessVertex.
GLU_END Specifies a function that marks the end of a drawing primitive, usually glEnd. It takes no arguments.
GLU_ERROR Specifies a function that is called when an error occurs. It must take a single argument of type GLenum.

Normally, you will use the GLU_BEGIN, GLU_END, GLU_VERTEX, and GLU_ERROR callback. GLU_BEGIN, GLU_END, and GLU_VERTEX correspond to glBegin, glEnd, and glVertex3dv, respectively. A simple function to display errors sent from the tessellator is in Listing 18-2.

Listing 18-2 A simple tessllator error-callback function

void
tess_error_callback(GLenum error)
{
  MessageBeep(MB_ICONEXCLAMATION);
  MessageBox(NULL, gluErrorString(error), “GLU Error”, MB_OK |
             MB_ICONEXCLAMATION);
}


Previous Table of Contents Next