Here's the new demo I was talking about.  I forgot the most important
change - the old tessellator did:

glBegin( GL_TRIANGLES );

<output one triangle>

glEnd();

but I'm doing:

glBegin( GL_TRIANGLES );

<output all triangles>

glEnd();

So, this demo now stores all the output triangles and renders them once
the tessellation is finished.

I've fixed the winding rules a lot, so now stacked contours are handled
as they should be.  I'm just cleaning up my deallocation of the deleted
contours, but it's basically ready to commit and this is one of the last
major things that needed to be finalized.  I've just got to investigate
the spiral contour case a little further, but this is a major step
forward.

I should be ready to commit all of my changes tommorrow night after I
fix up the deallocation.

-- Gareth
/* $Id: tessdemo.c,v 1.2 1999/09/19 20:09:00 tanner Exp $ */

/*
 * A demo of the GLU polygon tesselation functions written by Bogdan Sikorski.
 * This demo isn't built by the Makefile because it needs GLUT.  After you've
 * installed GLUT you can try this demo.
 * Here's the command for IRIX, for example:
   cc -g -ansi -prototypes -fullwarn -float -I../include -DSHM tess_demo.c -L../lib 
-lglut -lMesaGLU -lMesaGL -lm -lX11 -lXext -lXmu -lfpe -lXext -o tess_demo
 */


/*
 * $Log: tessdemo.c,v $
 * Revision 1.2  1999/09/19 20:09:00  tanner
 *
 * lots of autoconf updates
 *
 * Revision 1.1.1.1  1999/08/19 00:55:40  jtg
 * Imported sources
 *
 * Revision 3.5  1999/03/28 18:24:37  brianp
 * minor clean-up
 *
 * Revision 3.4  1999/02/14 03:37:07  brianp
 * fixed callback problem
 *
 * Revision 3.3  1998/07/26 01:25:26  brianp
 * removed include of gl.h and glu.h
 *
 * Revision 3.2  1998/06/29 02:37:30  brianp
 * minor changes for Windows (Ted Jump)
 *
 * Revision 3.1  1998/06/09 01:53:49  brianp
 * main() should return an int
 *
 * Revision 3.0  1998/02/14 18:42:29  brianp
 * initial rev
 *
 */


#include <GL/glut.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_POINTS      256
#define MAX_CONTOURS    32
#define MAX_TRIANGLES   256

#ifndef GLCALLBACK
#ifdef CALLBACK
#define GLCALLBACK CALLBACK
#else
#define GLCALLBACK
#endif
#endif

typedef enum{ QUIT, TESSELATE, CLEAR } menu_entries;
typedef enum{ DEFINE, TESSELATED } mode_type;

static GLsizei          width, height;
static GLuint           contour_cnt;
static GLuint           triangle_cnt;

static mode_type        mode;
static int              menu;

static GLuint           list_start;

static GLfloat          edge_color[3];

static struct
{
   GLint        p[MAX_POINTS][2];
   GLuint       point_cnt;
} contours[MAX_CONTOURS];

static struct
{
   GLsizei      no;
   GLint        p[3][2];
   GLclampf     color[3][3];
} triangles[MAX_TRIANGLES];



void GLCALLBACK my_error( GLenum err )
{
   int          len, i;
   char const   *str;

   glColor3f( 0.9, 0.9, 0.9 );
   glRasterPos2i( 5, 5 );

   str = (const char *) gluErrorString( err );
   len = strlen( str );

   for ( i = 0 ; i < len ; i++ ) {
      glutBitmapCharacter( GLUT_BITMAP_9_BY_15, str[i] );
   }
}

void GLCALLBACK begin_callback( GLenum mode )
{
   /* Allow multiple triangles to be output inside the begin/end pair. */
   triangle_cnt = 0;
   triangles[triangle_cnt].no = 0;
}

void GLCALLBACK edge_callback( GLenum flag )
{
   /* Persist the edge flag across triangles. */
   if ( flag == GL_TRUE )
   {
      edge_color[0] = 1.0;
      edge_color[1] = 1.0;
      edge_color[2] = 0.5;
   }
   else
   {
      edge_color[0] = 1.0;
      edge_color[1] = 0.0;
      edge_color[2] = 0.0;
   }
}

void GLCALLBACK end_callback()
{
   GLint        i;

   glBegin( GL_LINES );

   /* Output the three edges of each triangle as lines colored
      according to their edge flag. */
   for ( i = 0 ; i < triangle_cnt ; i++ )
   {
      glColor3f( triangles[i].color[0][0],
                 triangles[i].color[0][1],
                 triangles[i].color[0][2] );

      glVertex2i( triangles[i].p[0][0], triangles[i].p[0][1] );
      glVertex2i( triangles[i].p[1][0], triangles[i].p[1][1] );

      glColor3f( triangles[i].color[1][0],
                 triangles[i].color[1][1],
                 triangles[i].color[1][2] );

      glVertex2i( triangles[i].p[1][0], triangles[i].p[1][1] );
      glVertex2i( triangles[i].p[2][0], triangles[i].p[2][1] );

      glColor3f( triangles[i].color[2][0],
                 triangles[i].color[2][1],
                 triangles[i].color[2][2] );

      glVertex2i( triangles[i].p[2][0], triangles[i].p[2][1] );
      glVertex2i( triangles[i].p[0][0], triangles[i].p[0][1] );
   }

   glEnd();
}

void GLCALLBACK vertex_callback( void *data )
{
   GLsizei      no;
   GLint        *p;

   p = (GLint *) data;
   no = triangles[triangle_cnt].no;

   triangles[triangle_cnt].p[no][0] = p[0];
   triangles[triangle_cnt].p[no][1] = p[1];

   triangles[triangle_cnt].color[no][0] = edge_color[0];
   triangles[triangle_cnt].color[no][1] = edge_color[1];
   triangles[triangle_cnt].color[no][2] = edge_color[2];

   /* After every three vertices, initialize the next triangle. */
   if ( ++(triangles[triangle_cnt].no) == 3 )
   {
      triangle_cnt++;
      triangles[triangle_cnt].no = 0;
   }
}

void set_screen_wh( GLsizei w, GLsizei h )
{
   width = w;
   height = h;
}

void tesse( void )
{
   GLUtesselator        *tobj;
   GLdouble             data[3];
   GLuint               i, j, point_cnt;

   list_start = glGenLists( 2 );

   tobj = gluNewTess();

   if ( tobj != NULL )
   {
      gluTessCallback( tobj, GLU_BEGIN, glBegin );
      gluTessCallback( tobj, GLU_VERTEX, glVertex2iv );
      gluTessCallback( tobj, GLU_END, glEnd );
      gluTessCallback( tobj, GLU_ERROR, my_error );

      glNewList( list_start, GL_COMPILE );
      gluBeginPolygon( tobj );

      for ( j = 0 ; j <= contour_cnt ; j++ )
      {
         point_cnt = contours[j].point_cnt;
         gluNextContour( tobj, GLU_UNKNOWN );

         for ( i = 0 ; i < point_cnt ; i++ )
         {
            data[0] = (GLdouble)( contours[j].p[i][0] );
            data[1] = (GLdouble)( contours[j].p[i][1] );
            data[2] = 0.0;
            gluTessVertex( tobj, data, contours[j].p[i] );
         }
      }

      gluEndPolygon( tobj );
      glEndList();

      gluTessCallback( tobj, GLU_BEGIN, begin_callback );
      gluTessCallback( tobj, GLU_VERTEX, vertex_callback );
      gluTessCallback( tobj, GLU_END, end_callback );
      gluTessCallback( tobj, GLU_EDGE_FLAG, edge_callback );

      glNewList( list_start + 1, GL_COMPILE );
      gluBeginPolygon( tobj );

      for ( j = 0 ; j <= contour_cnt ; j++ )
      {
         point_cnt = contours[j].point_cnt;
         gluNextContour( tobj, GLU_UNKNOWN );

         for ( i = 0 ; i < point_cnt ; i++ )
         {
            data[0] = (GLdouble)( contours[j].p[i][0] );
            data[1] = (GLdouble)( contours[j].p[i][1] );
            data[2] = 0.0;
            gluTessVertex( tobj, data, contours[j].p[i] );
         }
      }

      gluEndPolygon( tobj );
      glEndList();

      gluDeleteTess( tobj );

      glutMouseFunc( NULL );
      mode = TESSELATED;
   }
}

void left_down( int x1, int y1 )
{
   GLint        P[2];
   GLuint       point_cnt;

   /* translate GLUT into GL coordinates */

   P[0] = x1;
   P[1] = height - y1;

   point_cnt = contours[contour_cnt].point_cnt;

   contours[contour_cnt].p[point_cnt][0] = P[0];
   contours[contour_cnt].p[point_cnt][1] = P[1];

   glBegin( GL_LINES );

   if ( point_cnt )
   {
      glVertex2iv( contours[contour_cnt].p[point_cnt-1] );
      glVertex2iv( P );
   }
   else
   {
      glVertex2iv( P );
      glVertex2iv( P );
   }

   glEnd();
   glFinish();

   contours[contour_cnt].point_cnt++;
}

void middle_down( int x1, int y1 )
{
   GLuint       point_cnt;
   (void) x1;
   (void) y1;

   point_cnt = contours[contour_cnt].point_cnt;

   if ( point_cnt > 2 )
   {
      glBegin( GL_LINES );

      glVertex2iv( contours[contour_cnt].p[0] );
      glVertex2iv( contours[contour_cnt].p[point_cnt-1] );

      contours[contour_cnt].p[point_cnt][0] = -1;

      glEnd();
      glFinish();

      contour_cnt++;
      contours[contour_cnt].point_cnt = 0;
   }
}

void mouse_clicked( int button, int state, int x, int y )
{
   x -= x%10;
   y -= y%10;

   switch ( button )
   {
   case GLUT_LEFT_BUTTON:
      if ( state == GLUT_DOWN ) {
         left_down( x, y );
      }
      break;
   case GLUT_MIDDLE_BUTTON:
      if ( state == GLUT_DOWN ) {
         middle_down( x, y );
      }
      break;
   }
}

void display( void )
{
   GLuint i,j;
   GLuint point_cnt;

   glClear( GL_COLOR_BUFFER_BIT );

   switch ( mode )
   {
   case DEFINE:
      /* draw grid */
      glColor3f( 0.6, 0.5, 0.5 );

      glBegin( GL_LINES );

      for ( i = 0 ; i < width ; i += 10 )
      {
         for ( j = 0 ; j < height ; j += 10 )
         {
            glVertex2i( 0, j );
            glVertex2i( width, j );
            glVertex2i( i, height );
            glVertex2i( i, 0 );
         }
      }

      glColor3f( 1.0, 1.0, 0.0 );

      for ( i = 0 ; i <= contour_cnt ; i++ )
      {
         point_cnt = contours[i].point_cnt;

         glBegin( GL_LINES );

         switch ( point_cnt )
         {
         case 0:
            break;
         case 1:
            glVertex2iv( contours[i].p[0] );
            glVertex2iv( contours[i].p[0] );
            break;
         case 2:
            glVertex2iv( contours[i].p[0] );
            glVertex2iv( contours[i].p[1] );
            break;
         default:
            --point_cnt;
            for ( j = 0 ; j < point_cnt ; j++ )
            {
               glVertex2iv( contours[i].p[j] );
               glVertex2iv( contours[i].p[j+1] );
            }
            if ( contours[i].p[j+1][0] == -1 )
            {
               glVertex2iv( contours[i].p[0] );
               glVertex2iv( contours[i].p[j] );
            }
            break;
         }

         glEnd();
      }

      glFinish();
      break;

   case TESSELATED:
      /* draw triangles */
      glColor3f( 0.7, 0.7, 0.0 );
      glCallList( list_start );

      glLineWidth( 2.0 );
      glCallList( list_start + 1 );
      glLineWidth( 1.0 );

      glFlush();
      break;
   }

   glColor3f( 1.0, 1.0, 0.0 );
}

void clear( void )
{
   contour_cnt = 0;
   contours[0].point_cnt = 0;
   triangle_cnt = 0;

   glutMouseFunc( mouse_clicked );

   mode = DEFINE;

   glDeleteLists( list_start, 2 );
   list_start = 0;
}

void quit( void )
{
   exit( 0 );
}

void menu_selected( int entry )
{
   switch ( entry )
   {
   case CLEAR:
      clear();
      break;
   case TESSELATE:
      tesse();
      break;
   case QUIT:
      quit();
      break;
   }

   glutPostRedisplay();
}

void key_pressed( unsigned char key, int x, int y )
{
   (void) x;
   (void) y;

   switch ( key )
   {
   case 'c':
   case 'C':
      clear();
      break;
   case 't':
   case 'T':
      tesse();
      break;
   case 'q':
   case 'Q':
      quit();
      break;
   }

   glutPostRedisplay();
}

void myinit( void )
{
   /* clear background to gray */
   glClearColor( 0.4, 0.4, 0.4, 0.0 );
   glShadeModel( GL_FLAT );
   glPolygonMode( GL_FRONT, GL_FILL );

   menu = glutCreateMenu( menu_selected );

   glutAddMenuEntry( "clear", CLEAR );
   glutAddMenuEntry( "tesselate", TESSELATE );
   glutAddMenuEntry( "quit", QUIT );

   glutAttachMenu( GLUT_RIGHT_BUTTON );

   glutMouseFunc( mouse_clicked );
   glutKeyboardFunc( key_pressed );

   contour_cnt = 0;
   mode = DEFINE;
}

static void reshape( GLsizei w, GLsizei h )
{
   glViewport( 0, 0, w, h );

   glMatrixMode( GL_PROJECTION );
   glLoadIdentity();
   glOrtho( 0.0, (GLdouble)w, 0.0, (GLdouble)h, -1.0, 1.0 );

   glMatrixMode( GL_MODELVIEW );
   glLoadIdentity();

   set_screen_wh( w, h );
}


static void usage( void )
{
   printf( "Use left mouse button to place vertices.\n" );
   printf( "Press middle mouse button when done.\n" );
   printf( "Select tesselate from the pop-up menu.\n" );
}


/*
 * Main Loop
 * Open window with initial window size, title bar,
 * RGBA display mode, and handle input events.
 */
int main( int argc, char **argv )
{
    usage();

    glutInit( &argc, argv );
    glutInitDisplayMode( GLUT_SINGLE | GLUT_RGB );
    glutInitWindowSize( 400, 400 );
    glutCreateWindow( argv[0] );

    myinit();

    glutDisplayFunc( display );
    glutReshapeFunc( reshape );

    glutMainLoop();

    return 0;
}

Reply via email to