Home | History | Annotate | Line # | Download | only in demos
      1 
      2 /*
      3  * A demo of the GLU polygon tesselation functions written by Bogdan Sikorski.
      4  * Updated for GLU 1.3 tessellation by Gareth Hughes <gareth (at) valinux.com>
      5  */
      6 
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <string.h>
     10 #include "glut_wrap.h"
     11 
     12 #define MAX_POINTS	256
     13 #define MAX_CONTOURS	32
     14 #define MAX_TRIANGLES	256
     15 
     16 #ifdef GLU_VERSION_1_2
     17 
     18 typedef enum{ QUIT, TESSELATE, CLEAR } menu_entries;
     19 typedef enum{ DEFINE, TESSELATED } mode_type;
     20 
     21 static GLsizei		width, height;
     22 static GLuint		contour_cnt;
     23 static GLuint		triangle_cnt;
     24 
     25 static mode_type 	mode;
     26 static int		menu;
     27 
     28 static GLuint		list_start;
     29 
     30 static GLfloat		edge_color[3];
     31 
     32 static struct {
     33    GLfloat	p[MAX_POINTS][2];
     34    GLuint	point_cnt;
     35 } contours[MAX_CONTOURS];
     36 
     37 static struct {
     38    GLsizei	no;
     39    GLfloat	p[3][2];
     40    GLclampf	color[3][3];
     41 } triangles[MAX_TRIANGLES];
     42 
     43 
     44 
     45 static void GLAPIENTRY error_callback( GLenum err )
     46 {
     47    int		len, i;
     48    char const	*str;
     49 
     50    glColor3f( 0.9, 0.9, 0.9 );
     51    glRasterPos2i( 5, 5 );
     52 
     53    str = (const char *) gluErrorString( err );
     54    len = strlen( str );
     55 
     56    for ( i = 0 ; i < len ; i++ ) {
     57       glutBitmapCharacter( GLUT_BITMAP_9_BY_15, str[i] );
     58    }
     59 }
     60 
     61 static void GLAPIENTRY begin_callback( GLenum mode )
     62 {
     63    /* Allow multiple triangles to be output inside the begin/end pair. */
     64    triangle_cnt = 0;
     65    triangles[triangle_cnt].no = 0;
     66 }
     67 
     68 static void GLAPIENTRY edge_callback( GLenum flag )
     69 {
     70    /* Persist the edge flag across triangles. */
     71    if ( flag == GL_TRUE ) {
     72       edge_color[0] = 1.0;
     73       edge_color[1] = 1.0;
     74       edge_color[2] = 0.5;
     75    } else {
     76       edge_color[0] = 1.0;
     77       edge_color[1] = 0.0;
     78       edge_color[2] = 0.0;
     79    }
     80 }
     81 
     82 static void GLAPIENTRY end_callback(void)
     83 {
     84    GLuint	i;
     85 
     86    glBegin( GL_LINES );
     87 
     88    /* Output the three edges of each triangle as lines colored
     89       according to their edge flag. */
     90    for ( i = 0 ; i < triangle_cnt ; i++ ) {
     91       glColor3f( triangles[i].color[0][0],
     92 		 triangles[i].color[0][1],
     93 		 triangles[i].color[0][2] );
     94 
     95       glVertex2f( triangles[i].p[0][0], triangles[i].p[0][1] );
     96       glVertex2f( triangles[i].p[1][0], triangles[i].p[1][1] );
     97 
     98       glColor3f( triangles[i].color[1][0],
     99 		 triangles[i].color[1][1],
    100 		 triangles[i].color[1][2] );
    101 
    102       glVertex2f( triangles[i].p[1][0], triangles[i].p[1][1] );
    103       glVertex2f( triangles[i].p[2][0], triangles[i].p[2][1] );
    104 
    105       glColor3f( triangles[i].color[2][0],
    106 		 triangles[i].color[2][1],
    107 		 triangles[i].color[2][2] );
    108 
    109       glVertex2f( triangles[i].p[2][0], triangles[i].p[2][1] );
    110       glVertex2f( triangles[i].p[0][0], triangles[i].p[0][1] );
    111    }
    112 
    113    glEnd();
    114 }
    115 
    116 static void GLAPIENTRY vertex_callback( void *data )
    117 {
    118    GLsizei	no;
    119    GLfloat	*p;
    120 
    121    p = (GLfloat *) data;
    122    no = triangles[triangle_cnt].no;
    123 
    124    triangles[triangle_cnt].p[no][0] = p[0];
    125    triangles[triangle_cnt].p[no][1] = p[1];
    126 
    127    triangles[triangle_cnt].color[no][0] = edge_color[0];
    128    triangles[triangle_cnt].color[no][1] = edge_color[1];
    129    triangles[triangle_cnt].color[no][2] = edge_color[2];
    130 
    131    /* After every three vertices, initialize the next triangle. */
    132    if ( ++(triangles[triangle_cnt].no) == 3 ) {
    133       triangle_cnt++;
    134       triangles[triangle_cnt].no = 0;
    135    }
    136 }
    137 
    138 static void GLAPIENTRY combine_callback( GLdouble coords[3],
    139 				       GLdouble *vertex_data[4],
    140 				       GLfloat weight[4], void **data )
    141 {
    142    GLfloat	*vertex;
    143 
    144    vertex = (GLfloat *) malloc( 2 * sizeof(GLfloat) );
    145 
    146    vertex[0] = (GLfloat) coords[0];
    147    vertex[1] = (GLfloat) coords[1];
    148 
    149    *data = vertex;
    150 }
    151 
    152 
    153 static void set_screen_wh( GLsizei w, GLsizei h )
    154 {
    155    width = w;
    156    height = h;
    157 }
    158 
    159 static void tesse( void )
    160 {
    161    GLUtesselator	*tobj;
    162    GLdouble		data[3];
    163    GLuint		i, j, point_cnt;
    164 
    165    list_start = glGenLists( 2 );
    166 
    167    tobj = gluNewTess();
    168 
    169    if ( tobj != NULL ) {
    170       gluTessNormal( tobj, 0.0, 0.0, 1.0 );
    171       gluTessCallback( tobj, GLU_TESS_BEGIN, glBegin );
    172       gluTessCallback( tobj, GLU_TESS_VERTEX, glVertex2fv );
    173       gluTessCallback( tobj, GLU_TESS_END, glEnd );
    174       gluTessCallback( tobj, GLU_TESS_ERROR, error_callback );
    175       gluTessCallback( tobj, GLU_TESS_COMBINE, combine_callback );
    176 
    177       glNewList( list_start, GL_COMPILE );
    178       gluBeginPolygon( tobj );
    179 
    180       for ( j = 0 ; j <= contour_cnt ; j++ ) {
    181 	 point_cnt = contours[j].point_cnt;
    182 	 gluNextContour( tobj, GLU_UNKNOWN );
    183 
    184 	 for ( i = 0 ; i < point_cnt ; i++ ) {
    185 	    data[0] = (GLdouble)( contours[j].p[i][0] );
    186 	    data[1] = (GLdouble)( contours[j].p[i][1] );
    187 	    data[2] = 0.0;
    188 	    gluTessVertex( tobj, data, contours[j].p[i] );
    189 	 }
    190       }
    191 
    192       gluEndPolygon( tobj );
    193       glEndList();
    194 
    195       gluTessCallback( tobj, GLU_TESS_BEGIN, begin_callback );
    196       gluTessCallback( tobj, GLU_TESS_VERTEX, vertex_callback );
    197       gluTessCallback( tobj, GLU_TESS_END, end_callback );
    198       gluTessCallback( tobj, GLU_TESS_EDGE_FLAG, edge_callback );
    199 
    200       glNewList( list_start + 1, GL_COMPILE );
    201       gluBeginPolygon( tobj );
    202 
    203       for ( j = 0 ; j <= contour_cnt ; j++ ) {
    204 	 point_cnt = contours[j].point_cnt;
    205 	 gluNextContour( tobj, GLU_UNKNOWN );
    206 
    207 	 for ( i = 0 ; i < point_cnt ; i++ ) {
    208 	    data[0] = (GLdouble)( contours[j].p[i][0] );
    209 	    data[1] = (GLdouble)( contours[j].p[i][1] );
    210 	    data[2] = 0.0;
    211 	    gluTessVertex( tobj, data, contours[j].p[i] );
    212 	 }
    213       }
    214 
    215       gluEndPolygon( tobj );
    216       glEndList();
    217 
    218       gluDeleteTess( tobj );
    219 
    220       glutMouseFunc( NULL );
    221       mode = TESSELATED;
    222    }
    223 }
    224 
    225 static void left_down( int x1, int y1 )
    226 {
    227    GLfloat	P[2];
    228    GLuint	point_cnt;
    229 
    230    /* translate GLUT into GL coordinates */
    231 
    232    P[0] = x1;
    233    P[1] = height - y1;
    234 
    235    point_cnt = contours[contour_cnt].point_cnt;
    236 
    237    contours[contour_cnt].p[point_cnt][0] = P[0];
    238    contours[contour_cnt].p[point_cnt][1] = P[1];
    239 
    240    glBegin( GL_LINES );
    241 
    242    if ( point_cnt ) {
    243       glVertex2fv( contours[contour_cnt].p[point_cnt-1] );
    244       glVertex2fv( P );
    245    } else {
    246       glVertex2fv( P );
    247       glVertex2fv( P );
    248    }
    249 
    250    glEnd();
    251    glFinish();
    252 
    253    contours[contour_cnt].point_cnt++;
    254 }
    255 
    256 static void middle_down( int x1, int y1 )
    257 {
    258    GLuint	point_cnt;
    259    (void) x1;
    260    (void) y1;
    261 
    262    point_cnt = contours[contour_cnt].point_cnt;
    263 
    264    if ( point_cnt > 2 ) {
    265       glBegin( GL_LINES );
    266 
    267       glVertex2fv( contours[contour_cnt].p[0] );
    268       glVertex2fv( contours[contour_cnt].p[point_cnt-1] );
    269 
    270       contours[contour_cnt].p[point_cnt][0] = -1;
    271 
    272       glEnd();
    273       glFinish();
    274 
    275       contour_cnt++;
    276       contours[contour_cnt].point_cnt = 0;
    277    }
    278 }
    279 
    280 static void mouse_clicked( int button, int state, int x, int y )
    281 {
    282    x -= x%10;
    283    y -= y%10;
    284 
    285    switch ( button ) {
    286    case GLUT_LEFT_BUTTON:
    287       if ( state == GLUT_DOWN ) {
    288 	 left_down( x, y );
    289       }
    290       break;
    291    case GLUT_MIDDLE_BUTTON:
    292       if ( state == GLUT_DOWN ) {
    293 	 middle_down( x, y );
    294       }
    295       break;
    296    }
    297 }
    298 
    299 static void display( void )
    300 {
    301    GLuint i,j;
    302    GLsizei ii, jj;
    303    GLuint point_cnt;
    304 
    305    glClear( GL_COLOR_BUFFER_BIT );
    306 
    307    switch ( mode ) {
    308    case DEFINE:
    309       /* draw grid */
    310       glColor3f( 0.6, 0.5, 0.5 );
    311 
    312       glBegin( GL_LINES );
    313 
    314       for ( ii = 0 ; ii < width ; ii += 10 ) {
    315 	 for ( jj = 0 ; jj < height ; jj += 10 ) {
    316 	    glVertex2i( 0, jj );
    317 	    glVertex2i( width, jj );
    318 	    glVertex2i( ii, height );
    319 	    glVertex2i( ii, 0 );
    320 	 }
    321       }
    322 
    323       glEnd();
    324 
    325       glColor3f( 1.0, 1.0, 0.0 );
    326 
    327       for ( i = 0 ; i <= contour_cnt ; i++ ) {
    328 	 point_cnt = contours[i].point_cnt;
    329 
    330 	 glBegin( GL_LINES );
    331 
    332 	 switch ( point_cnt ) {
    333 	 case 0:
    334 	    break;
    335 	 case 1:
    336 	    glVertex2fv( contours[i].p[0] );
    337 	    glVertex2fv( contours[i].p[0] );
    338 	    break;
    339 	 case 2:
    340 	    glVertex2fv( contours[i].p[0] );
    341 	    glVertex2fv( contours[i].p[1] );
    342 	    break;
    343 	 default:
    344 	    --point_cnt;
    345 	    for ( j = 0 ; j < point_cnt ; j++ ) {
    346 	       glVertex2fv( contours[i].p[j] );
    347 	       glVertex2fv( contours[i].p[j+1] );
    348 	    }
    349 	    if ( contours[i].p[j+1][0] == -1 ) {
    350 	       glVertex2fv( contours[i].p[0] );
    351 	       glVertex2fv( contours[i].p[j] );
    352 	    }
    353 	    break;
    354 	 }
    355 
    356 	 glEnd();
    357       }
    358 
    359       glFinish();
    360       break;
    361 
    362    case TESSELATED:
    363       /* draw triangles */
    364       glColor3f( 0.7, 0.7, 0.0 );
    365       glCallList( list_start );
    366 
    367       glLineWidth( 2.0 );
    368       glCallList( list_start + 1 );
    369       glLineWidth( 1.0 );
    370 
    371       glFlush();
    372       break;
    373    }
    374 
    375    glColor3f( 1.0, 1.0, 0.0 );
    376 }
    377 
    378 static void clear( void )
    379 {
    380    contour_cnt = 0;
    381    contours[0].point_cnt = 0;
    382    triangle_cnt = 0;
    383 
    384    glutMouseFunc( mouse_clicked );
    385 
    386    mode = DEFINE;
    387 
    388    glDeleteLists( list_start, 2 );
    389    list_start = 0;
    390 }
    391 
    392 static void quit( void )
    393 {
    394    exit( 0 );
    395 }
    396 
    397 static void menu_selected( int entry )
    398 {
    399    switch ( entry ) {
    400    case CLEAR:
    401       clear();
    402       break;
    403    case TESSELATE:
    404       tesse();
    405       break;
    406    case QUIT:
    407       quit();
    408       break;
    409    }
    410 
    411    glutPostRedisplay();
    412 }
    413 
    414 static void key_pressed( unsigned char key, int x, int y )
    415 {
    416    (void) x;
    417    (void) y;
    418 
    419    switch ( key ) {
    420    case 'c':
    421    case 'C':
    422       clear();
    423       break;
    424    case 't':
    425    case 'T':
    426       tesse();
    427       break;
    428    case 27:
    429    case 'q':
    430    case 'Q':
    431       quit();
    432       break;
    433    }
    434 
    435    glutPostRedisplay();
    436 }
    437 
    438 static void myinit( void )
    439 {
    440    /* clear background to gray */
    441    glClearColor( 0.4, 0.4, 0.4, 0.0 );
    442    glShadeModel( GL_FLAT );
    443    glPolygonMode( GL_FRONT, GL_FILL );
    444 
    445    menu = glutCreateMenu( menu_selected );
    446 
    447    glutAddMenuEntry( "clear", CLEAR );
    448    glutAddMenuEntry( "tesselate", TESSELATE );
    449    glutAddMenuEntry( "quit", QUIT );
    450 
    451    glutAttachMenu( GLUT_RIGHT_BUTTON );
    452 
    453    glutMouseFunc( mouse_clicked );
    454    glutKeyboardFunc( key_pressed );
    455 
    456    contour_cnt = 0;
    457    mode = DEFINE;
    458 }
    459 
    460 static void reshape( GLsizei w, GLsizei h )
    461 {
    462    glViewport( 0, 0, w, h );
    463 
    464    glMatrixMode( GL_PROJECTION );
    465    glLoadIdentity();
    466    glOrtho( 0.0, (GLdouble)w, 0.0, (GLdouble)h, -1.0, 1.0 );
    467 
    468    glMatrixMode( GL_MODELVIEW );
    469    glLoadIdentity();
    470 
    471    set_screen_wh( w, h );
    472 }
    473 
    474 #endif
    475 
    476 
    477 static void usage( void )
    478 {
    479    printf( "Use left mouse button to place vertices.\n" );
    480    printf( "Press middle mouse button when done.\n" );
    481    printf( "Select tesselate from the pop-up menu.\n" );
    482 }
    483 
    484 
    485 int main( int argc, char **argv )
    486 {
    487    const char *version = (const char *) gluGetString( GLU_VERSION );
    488    printf( "GLU version string: %s\n", version );
    489    if ( strstr( version, "1.0" ) || strstr( version, "1.1" ) ) {
    490       fprintf( stderr, "Sorry, this demo reqiures GLU 1.2 or later.\n" );
    491       exit( 1 );
    492    }
    493 
    494    usage();
    495 
    496    glutInitWindowSize( 400, 400 );
    497    glutInit( &argc, argv );
    498    glutInitDisplayMode( GLUT_SINGLE | GLUT_RGB );
    499    glutCreateWindow( argv[0] );
    500 
    501    /* GH: Bit of a hack...
    502     */
    503 #ifdef GLU_VERSION_1_2
    504    myinit();
    505 
    506    glutDisplayFunc( display );
    507    glutReshapeFunc( reshape );
    508 
    509    glutMainLoop();
    510 #endif
    511 
    512    return 0;
    513 }
    514