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@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 18typedef enum{ QUIT, TESSELATE, CLEAR } menu_entries; 19typedef enum{ DEFINE, TESSELATED } mode_type; 20 21static GLsizei width, height; 22static GLuint contour_cnt; 23static GLuint triangle_cnt; 24 25static mode_type mode; 26static int menu; 27 28static GLuint list_start; 29 30static GLfloat edge_color[3]; 31 32static struct { 33 GLfloat p[MAX_POINTS][2]; 34 GLuint point_cnt; 35} contours[MAX_CONTOURS]; 36 37static struct { 38 GLsizei no; 39 GLfloat p[3][2]; 40 GLclampf color[3][3]; 41} triangles[MAX_TRIANGLES]; 42 43 44 45static 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 61static 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 68static 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 82static 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 116static 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 138static 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 153static void set_screen_wh( GLsizei w, GLsizei h ) 154{ 155 width = w; 156 height = h; 157} 158 159static 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 225static 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 256static 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 280static 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 299static 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 378static 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 392static void quit( void ) 393{ 394 exit( 0 ); 395} 396 397static 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 414static 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 438static 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 460static 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 477static 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 485int 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