132001f49Smrg 232001f49Smrg/* 332001f49Smrg * A demo of the GLU polygon tesselation functions written by Bogdan Sikorski. 432001f49Smrg * Updated for GLU 1.3 tessellation by Gareth Hughes <gareth@valinux.com> 532001f49Smrg */ 632001f49Smrg 732001f49Smrg#include <stdio.h> 832001f49Smrg#include <stdlib.h> 932001f49Smrg#include <string.h> 1032001f49Smrg#include "glut_wrap.h" 1132001f49Smrg 1232001f49Smrg#define MAX_POINTS 256 1332001f49Smrg#define MAX_CONTOURS 32 1432001f49Smrg#define MAX_TRIANGLES 256 1532001f49Smrg 1632001f49Smrg#ifdef GLU_VERSION_1_2 1732001f49Smrg 1832001f49Smrgtypedef enum{ QUIT, TESSELATE, CLEAR } menu_entries; 1932001f49Smrgtypedef enum{ DEFINE, TESSELATED } mode_type; 2032001f49Smrg 2132001f49Smrgstatic GLsizei width, height; 2232001f49Smrgstatic GLuint contour_cnt; 2332001f49Smrgstatic GLuint triangle_cnt; 2432001f49Smrg 2532001f49Smrgstatic mode_type mode; 2632001f49Smrgstatic int menu; 2732001f49Smrg 2832001f49Smrgstatic GLuint list_start; 2932001f49Smrg 3032001f49Smrgstatic GLfloat edge_color[3]; 3132001f49Smrg 3232001f49Smrgstatic struct { 3332001f49Smrg GLfloat p[MAX_POINTS][2]; 3432001f49Smrg GLuint point_cnt; 3532001f49Smrg} contours[MAX_CONTOURS]; 3632001f49Smrg 3732001f49Smrgstatic struct { 3832001f49Smrg GLsizei no; 3932001f49Smrg GLfloat p[3][2]; 4032001f49Smrg GLclampf color[3][3]; 4132001f49Smrg} triangles[MAX_TRIANGLES]; 4232001f49Smrg 4332001f49Smrg 4432001f49Smrg 4532001f49Smrgstatic void GLAPIENTRY error_callback( GLenum err ) 4632001f49Smrg{ 4732001f49Smrg int len, i; 4832001f49Smrg char const *str; 4932001f49Smrg 5032001f49Smrg glColor3f( 0.9, 0.9, 0.9 ); 5132001f49Smrg glRasterPos2i( 5, 5 ); 5232001f49Smrg 5332001f49Smrg str = (const char *) gluErrorString( err ); 5432001f49Smrg len = strlen( str ); 5532001f49Smrg 5632001f49Smrg for ( i = 0 ; i < len ; i++ ) { 5732001f49Smrg glutBitmapCharacter( GLUT_BITMAP_9_BY_15, str[i] ); 5832001f49Smrg } 5932001f49Smrg} 6032001f49Smrg 6132001f49Smrgstatic void GLAPIENTRY begin_callback( GLenum mode ) 6232001f49Smrg{ 6332001f49Smrg /* Allow multiple triangles to be output inside the begin/end pair. */ 6432001f49Smrg triangle_cnt = 0; 6532001f49Smrg triangles[triangle_cnt].no = 0; 6632001f49Smrg} 6732001f49Smrg 6832001f49Smrgstatic void GLAPIENTRY edge_callback( GLenum flag ) 6932001f49Smrg{ 7032001f49Smrg /* Persist the edge flag across triangles. */ 7132001f49Smrg if ( flag == GL_TRUE ) { 7232001f49Smrg edge_color[0] = 1.0; 7332001f49Smrg edge_color[1] = 1.0; 7432001f49Smrg edge_color[2] = 0.5; 7532001f49Smrg } else { 7632001f49Smrg edge_color[0] = 1.0; 7732001f49Smrg edge_color[1] = 0.0; 7832001f49Smrg edge_color[2] = 0.0; 7932001f49Smrg } 8032001f49Smrg} 8132001f49Smrg 8232001f49Smrgstatic void GLAPIENTRY end_callback(void) 8332001f49Smrg{ 8432001f49Smrg GLuint i; 8532001f49Smrg 8632001f49Smrg glBegin( GL_LINES ); 8732001f49Smrg 8832001f49Smrg /* Output the three edges of each triangle as lines colored 8932001f49Smrg according to their edge flag. */ 9032001f49Smrg for ( i = 0 ; i < triangle_cnt ; i++ ) { 9132001f49Smrg glColor3f( triangles[i].color[0][0], 9232001f49Smrg triangles[i].color[0][1], 9332001f49Smrg triangles[i].color[0][2] ); 9432001f49Smrg 9532001f49Smrg glVertex2f( triangles[i].p[0][0], triangles[i].p[0][1] ); 9632001f49Smrg glVertex2f( triangles[i].p[1][0], triangles[i].p[1][1] ); 9732001f49Smrg 9832001f49Smrg glColor3f( triangles[i].color[1][0], 9932001f49Smrg triangles[i].color[1][1], 10032001f49Smrg triangles[i].color[1][2] ); 10132001f49Smrg 10232001f49Smrg glVertex2f( triangles[i].p[1][0], triangles[i].p[1][1] ); 10332001f49Smrg glVertex2f( triangles[i].p[2][0], triangles[i].p[2][1] ); 10432001f49Smrg 10532001f49Smrg glColor3f( triangles[i].color[2][0], 10632001f49Smrg triangles[i].color[2][1], 10732001f49Smrg triangles[i].color[2][2] ); 10832001f49Smrg 10932001f49Smrg glVertex2f( triangles[i].p[2][0], triangles[i].p[2][1] ); 11032001f49Smrg glVertex2f( triangles[i].p[0][0], triangles[i].p[0][1] ); 11132001f49Smrg } 11232001f49Smrg 11332001f49Smrg glEnd(); 11432001f49Smrg} 11532001f49Smrg 11632001f49Smrgstatic void GLAPIENTRY vertex_callback( void *data ) 11732001f49Smrg{ 11832001f49Smrg GLsizei no; 11932001f49Smrg GLfloat *p; 12032001f49Smrg 12132001f49Smrg p = (GLfloat *) data; 12232001f49Smrg no = triangles[triangle_cnt].no; 12332001f49Smrg 12432001f49Smrg triangles[triangle_cnt].p[no][0] = p[0]; 12532001f49Smrg triangles[triangle_cnt].p[no][1] = p[1]; 12632001f49Smrg 12732001f49Smrg triangles[triangle_cnt].color[no][0] = edge_color[0]; 12832001f49Smrg triangles[triangle_cnt].color[no][1] = edge_color[1]; 12932001f49Smrg triangles[triangle_cnt].color[no][2] = edge_color[2]; 13032001f49Smrg 13132001f49Smrg /* After every three vertices, initialize the next triangle. */ 13232001f49Smrg if ( ++(triangles[triangle_cnt].no) == 3 ) { 13332001f49Smrg triangle_cnt++; 13432001f49Smrg triangles[triangle_cnt].no = 0; 13532001f49Smrg } 13632001f49Smrg} 13732001f49Smrg 13832001f49Smrgstatic void GLAPIENTRY combine_callback( GLdouble coords[3], 13932001f49Smrg GLdouble *vertex_data[4], 14032001f49Smrg GLfloat weight[4], void **data ) 14132001f49Smrg{ 14232001f49Smrg GLfloat *vertex; 14332001f49Smrg 14432001f49Smrg vertex = (GLfloat *) malloc( 2 * sizeof(GLfloat) ); 14532001f49Smrg 14632001f49Smrg vertex[0] = (GLfloat) coords[0]; 14732001f49Smrg vertex[1] = (GLfloat) coords[1]; 14832001f49Smrg 14932001f49Smrg *data = vertex; 15032001f49Smrg} 15132001f49Smrg 15232001f49Smrg 15332001f49Smrgstatic void set_screen_wh( GLsizei w, GLsizei h ) 15432001f49Smrg{ 15532001f49Smrg width = w; 15632001f49Smrg height = h; 15732001f49Smrg} 15832001f49Smrg 15932001f49Smrgstatic void tesse( void ) 16032001f49Smrg{ 16132001f49Smrg GLUtesselator *tobj; 16232001f49Smrg GLdouble data[3]; 16332001f49Smrg GLuint i, j, point_cnt; 16432001f49Smrg 16532001f49Smrg list_start = glGenLists( 2 ); 16632001f49Smrg 16732001f49Smrg tobj = gluNewTess(); 16832001f49Smrg 16932001f49Smrg if ( tobj != NULL ) { 17032001f49Smrg gluTessNormal( tobj, 0.0, 0.0, 1.0 ); 17132001f49Smrg gluTessCallback( tobj, GLU_TESS_BEGIN, glBegin ); 17232001f49Smrg gluTessCallback( tobj, GLU_TESS_VERTEX, glVertex2fv ); 17332001f49Smrg gluTessCallback( tobj, GLU_TESS_END, glEnd ); 17432001f49Smrg gluTessCallback( tobj, GLU_TESS_ERROR, error_callback ); 17532001f49Smrg gluTessCallback( tobj, GLU_TESS_COMBINE, combine_callback ); 17632001f49Smrg 17732001f49Smrg glNewList( list_start, GL_COMPILE ); 17832001f49Smrg gluBeginPolygon( tobj ); 17932001f49Smrg 18032001f49Smrg for ( j = 0 ; j <= contour_cnt ; j++ ) { 18132001f49Smrg point_cnt = contours[j].point_cnt; 18232001f49Smrg gluNextContour( tobj, GLU_UNKNOWN ); 18332001f49Smrg 18432001f49Smrg for ( i = 0 ; i < point_cnt ; i++ ) { 18532001f49Smrg data[0] = (GLdouble)( contours[j].p[i][0] ); 18632001f49Smrg data[1] = (GLdouble)( contours[j].p[i][1] ); 18732001f49Smrg data[2] = 0.0; 18832001f49Smrg gluTessVertex( tobj, data, contours[j].p[i] ); 18932001f49Smrg } 19032001f49Smrg } 19132001f49Smrg 19232001f49Smrg gluEndPolygon( tobj ); 19332001f49Smrg glEndList(); 19432001f49Smrg 19532001f49Smrg gluTessCallback( tobj, GLU_TESS_BEGIN, begin_callback ); 19632001f49Smrg gluTessCallback( tobj, GLU_TESS_VERTEX, vertex_callback ); 19732001f49Smrg gluTessCallback( tobj, GLU_TESS_END, end_callback ); 19832001f49Smrg gluTessCallback( tobj, GLU_TESS_EDGE_FLAG, edge_callback ); 19932001f49Smrg 20032001f49Smrg glNewList( list_start + 1, GL_COMPILE ); 20132001f49Smrg gluBeginPolygon( tobj ); 20232001f49Smrg 20332001f49Smrg for ( j = 0 ; j <= contour_cnt ; j++ ) { 20432001f49Smrg point_cnt = contours[j].point_cnt; 20532001f49Smrg gluNextContour( tobj, GLU_UNKNOWN ); 20632001f49Smrg 20732001f49Smrg for ( i = 0 ; i < point_cnt ; i++ ) { 20832001f49Smrg data[0] = (GLdouble)( contours[j].p[i][0] ); 20932001f49Smrg data[1] = (GLdouble)( contours[j].p[i][1] ); 21032001f49Smrg data[2] = 0.0; 21132001f49Smrg gluTessVertex( tobj, data, contours[j].p[i] ); 21232001f49Smrg } 21332001f49Smrg } 21432001f49Smrg 21532001f49Smrg gluEndPolygon( tobj ); 21632001f49Smrg glEndList(); 21732001f49Smrg 21832001f49Smrg gluDeleteTess( tobj ); 21932001f49Smrg 22032001f49Smrg glutMouseFunc( NULL ); 22132001f49Smrg mode = TESSELATED; 22232001f49Smrg } 22332001f49Smrg} 22432001f49Smrg 22532001f49Smrgstatic void left_down( int x1, int y1 ) 22632001f49Smrg{ 22732001f49Smrg GLfloat P[2]; 22832001f49Smrg GLuint point_cnt; 22932001f49Smrg 23032001f49Smrg /* translate GLUT into GL coordinates */ 23132001f49Smrg 23232001f49Smrg P[0] = x1; 23332001f49Smrg P[1] = height - y1; 23432001f49Smrg 23532001f49Smrg point_cnt = contours[contour_cnt].point_cnt; 23632001f49Smrg 23732001f49Smrg contours[contour_cnt].p[point_cnt][0] = P[0]; 23832001f49Smrg contours[contour_cnt].p[point_cnt][1] = P[1]; 23932001f49Smrg 24032001f49Smrg glBegin( GL_LINES ); 24132001f49Smrg 24232001f49Smrg if ( point_cnt ) { 24332001f49Smrg glVertex2fv( contours[contour_cnt].p[point_cnt-1] ); 24432001f49Smrg glVertex2fv( P ); 24532001f49Smrg } else { 24632001f49Smrg glVertex2fv( P ); 24732001f49Smrg glVertex2fv( P ); 24832001f49Smrg } 24932001f49Smrg 25032001f49Smrg glEnd(); 25132001f49Smrg glFinish(); 25232001f49Smrg 25332001f49Smrg contours[contour_cnt].point_cnt++; 25432001f49Smrg} 25532001f49Smrg 25632001f49Smrgstatic void middle_down( int x1, int y1 ) 25732001f49Smrg{ 25832001f49Smrg GLuint point_cnt; 25932001f49Smrg (void) x1; 26032001f49Smrg (void) y1; 26132001f49Smrg 26232001f49Smrg point_cnt = contours[contour_cnt].point_cnt; 26332001f49Smrg 26432001f49Smrg if ( point_cnt > 2 ) { 26532001f49Smrg glBegin( GL_LINES ); 26632001f49Smrg 26732001f49Smrg glVertex2fv( contours[contour_cnt].p[0] ); 26832001f49Smrg glVertex2fv( contours[contour_cnt].p[point_cnt-1] ); 26932001f49Smrg 27032001f49Smrg contours[contour_cnt].p[point_cnt][0] = -1; 27132001f49Smrg 27232001f49Smrg glEnd(); 27332001f49Smrg glFinish(); 27432001f49Smrg 27532001f49Smrg contour_cnt++; 27632001f49Smrg contours[contour_cnt].point_cnt = 0; 27732001f49Smrg } 27832001f49Smrg} 27932001f49Smrg 28032001f49Smrgstatic void mouse_clicked( int button, int state, int x, int y ) 28132001f49Smrg{ 28232001f49Smrg x -= x%10; 28332001f49Smrg y -= y%10; 28432001f49Smrg 28532001f49Smrg switch ( button ) { 28632001f49Smrg case GLUT_LEFT_BUTTON: 28732001f49Smrg if ( state == GLUT_DOWN ) { 28832001f49Smrg left_down( x, y ); 28932001f49Smrg } 29032001f49Smrg break; 29132001f49Smrg case GLUT_MIDDLE_BUTTON: 29232001f49Smrg if ( state == GLUT_DOWN ) { 29332001f49Smrg middle_down( x, y ); 29432001f49Smrg } 29532001f49Smrg break; 29632001f49Smrg } 29732001f49Smrg} 29832001f49Smrg 29932001f49Smrgstatic void display( void ) 30032001f49Smrg{ 30132001f49Smrg GLuint i,j; 30232001f49Smrg GLsizei ii, jj; 30332001f49Smrg GLuint point_cnt; 30432001f49Smrg 30532001f49Smrg glClear( GL_COLOR_BUFFER_BIT ); 30632001f49Smrg 30732001f49Smrg switch ( mode ) { 30832001f49Smrg case DEFINE: 30932001f49Smrg /* draw grid */ 31032001f49Smrg glColor3f( 0.6, 0.5, 0.5 ); 31132001f49Smrg 31232001f49Smrg glBegin( GL_LINES ); 31332001f49Smrg 31432001f49Smrg for ( ii = 0 ; ii < width ; ii += 10 ) { 31532001f49Smrg for ( jj = 0 ; jj < height ; jj += 10 ) { 31632001f49Smrg glVertex2i( 0, jj ); 31732001f49Smrg glVertex2i( width, jj ); 31832001f49Smrg glVertex2i( ii, height ); 31932001f49Smrg glVertex2i( ii, 0 ); 32032001f49Smrg } 32132001f49Smrg } 32232001f49Smrg 32332001f49Smrg glEnd(); 32432001f49Smrg 32532001f49Smrg glColor3f( 1.0, 1.0, 0.0 ); 32632001f49Smrg 32732001f49Smrg for ( i = 0 ; i <= contour_cnt ; i++ ) { 32832001f49Smrg point_cnt = contours[i].point_cnt; 32932001f49Smrg 33032001f49Smrg glBegin( GL_LINES ); 33132001f49Smrg 33232001f49Smrg switch ( point_cnt ) { 33332001f49Smrg case 0: 33432001f49Smrg break; 33532001f49Smrg case 1: 33632001f49Smrg glVertex2fv( contours[i].p[0] ); 33732001f49Smrg glVertex2fv( contours[i].p[0] ); 33832001f49Smrg break; 33932001f49Smrg case 2: 34032001f49Smrg glVertex2fv( contours[i].p[0] ); 34132001f49Smrg glVertex2fv( contours[i].p[1] ); 34232001f49Smrg break; 34332001f49Smrg default: 34432001f49Smrg --point_cnt; 34532001f49Smrg for ( j = 0 ; j < point_cnt ; j++ ) { 34632001f49Smrg glVertex2fv( contours[i].p[j] ); 34732001f49Smrg glVertex2fv( contours[i].p[j+1] ); 34832001f49Smrg } 34932001f49Smrg if ( contours[i].p[j+1][0] == -1 ) { 35032001f49Smrg glVertex2fv( contours[i].p[0] ); 35132001f49Smrg glVertex2fv( contours[i].p[j] ); 35232001f49Smrg } 35332001f49Smrg break; 35432001f49Smrg } 35532001f49Smrg 35632001f49Smrg glEnd(); 35732001f49Smrg } 35832001f49Smrg 35932001f49Smrg glFinish(); 36032001f49Smrg break; 36132001f49Smrg 36232001f49Smrg case TESSELATED: 36332001f49Smrg /* draw triangles */ 36432001f49Smrg glColor3f( 0.7, 0.7, 0.0 ); 36532001f49Smrg glCallList( list_start ); 36632001f49Smrg 36732001f49Smrg glLineWidth( 2.0 ); 36832001f49Smrg glCallList( list_start + 1 ); 36932001f49Smrg glLineWidth( 1.0 ); 37032001f49Smrg 37132001f49Smrg glFlush(); 37232001f49Smrg break; 37332001f49Smrg } 37432001f49Smrg 37532001f49Smrg glColor3f( 1.0, 1.0, 0.0 ); 37632001f49Smrg} 37732001f49Smrg 37832001f49Smrgstatic void clear( void ) 37932001f49Smrg{ 38032001f49Smrg contour_cnt = 0; 38132001f49Smrg contours[0].point_cnt = 0; 38232001f49Smrg triangle_cnt = 0; 38332001f49Smrg 38432001f49Smrg glutMouseFunc( mouse_clicked ); 38532001f49Smrg 38632001f49Smrg mode = DEFINE; 38732001f49Smrg 38832001f49Smrg glDeleteLists( list_start, 2 ); 38932001f49Smrg list_start = 0; 39032001f49Smrg} 39132001f49Smrg 39232001f49Smrgstatic void quit( void ) 39332001f49Smrg{ 39432001f49Smrg exit( 0 ); 39532001f49Smrg} 39632001f49Smrg 39732001f49Smrgstatic void menu_selected( int entry ) 39832001f49Smrg{ 39932001f49Smrg switch ( entry ) { 40032001f49Smrg case CLEAR: 40132001f49Smrg clear(); 40232001f49Smrg break; 40332001f49Smrg case TESSELATE: 40432001f49Smrg tesse(); 40532001f49Smrg break; 40632001f49Smrg case QUIT: 40732001f49Smrg quit(); 40832001f49Smrg break; 40932001f49Smrg } 41032001f49Smrg 41132001f49Smrg glutPostRedisplay(); 41232001f49Smrg} 41332001f49Smrg 41432001f49Smrgstatic void key_pressed( unsigned char key, int x, int y ) 41532001f49Smrg{ 41632001f49Smrg (void) x; 41732001f49Smrg (void) y; 41832001f49Smrg 41932001f49Smrg switch ( key ) { 42032001f49Smrg case 'c': 42132001f49Smrg case 'C': 42232001f49Smrg clear(); 42332001f49Smrg break; 42432001f49Smrg case 't': 42532001f49Smrg case 'T': 42632001f49Smrg tesse(); 42732001f49Smrg break; 42832001f49Smrg case 27: 42932001f49Smrg case 'q': 43032001f49Smrg case 'Q': 43132001f49Smrg quit(); 43232001f49Smrg break; 43332001f49Smrg } 43432001f49Smrg 43532001f49Smrg glutPostRedisplay(); 43632001f49Smrg} 43732001f49Smrg 43832001f49Smrgstatic void myinit( void ) 43932001f49Smrg{ 44032001f49Smrg /* clear background to gray */ 44132001f49Smrg glClearColor( 0.4, 0.4, 0.4, 0.0 ); 44232001f49Smrg glShadeModel( GL_FLAT ); 44332001f49Smrg glPolygonMode( GL_FRONT, GL_FILL ); 44432001f49Smrg 44532001f49Smrg menu = glutCreateMenu( menu_selected ); 44632001f49Smrg 44732001f49Smrg glutAddMenuEntry( "clear", CLEAR ); 44832001f49Smrg glutAddMenuEntry( "tesselate", TESSELATE ); 44932001f49Smrg glutAddMenuEntry( "quit", QUIT ); 45032001f49Smrg 45132001f49Smrg glutAttachMenu( GLUT_RIGHT_BUTTON ); 45232001f49Smrg 45332001f49Smrg glutMouseFunc( mouse_clicked ); 45432001f49Smrg glutKeyboardFunc( key_pressed ); 45532001f49Smrg 45632001f49Smrg contour_cnt = 0; 45732001f49Smrg mode = DEFINE; 45832001f49Smrg} 45932001f49Smrg 46032001f49Smrgstatic void reshape( GLsizei w, GLsizei h ) 46132001f49Smrg{ 46232001f49Smrg glViewport( 0, 0, w, h ); 46332001f49Smrg 46432001f49Smrg glMatrixMode( GL_PROJECTION ); 46532001f49Smrg glLoadIdentity(); 46632001f49Smrg glOrtho( 0.0, (GLdouble)w, 0.0, (GLdouble)h, -1.0, 1.0 ); 46732001f49Smrg 46832001f49Smrg glMatrixMode( GL_MODELVIEW ); 46932001f49Smrg glLoadIdentity(); 47032001f49Smrg 47132001f49Smrg set_screen_wh( w, h ); 47232001f49Smrg} 47332001f49Smrg 47432001f49Smrg#endif 47532001f49Smrg 47632001f49Smrg 47732001f49Smrgstatic void usage( void ) 47832001f49Smrg{ 47932001f49Smrg printf( "Use left mouse button to place vertices.\n" ); 48032001f49Smrg printf( "Press middle mouse button when done.\n" ); 48132001f49Smrg printf( "Select tesselate from the pop-up menu.\n" ); 48232001f49Smrg} 48332001f49Smrg 48432001f49Smrg 48532001f49Smrgint main( int argc, char **argv ) 48632001f49Smrg{ 48732001f49Smrg const char *version = (const char *) gluGetString( GLU_VERSION ); 48832001f49Smrg printf( "GLU version string: %s\n", version ); 48932001f49Smrg if ( strstr( version, "1.0" ) || strstr( version, "1.1" ) ) { 49032001f49Smrg fprintf( stderr, "Sorry, this demo reqiures GLU 1.2 or later.\n" ); 49132001f49Smrg exit( 1 ); 49232001f49Smrg } 49332001f49Smrg 49432001f49Smrg usage(); 49532001f49Smrg 49632001f49Smrg glutInitWindowSize( 400, 400 ); 49732001f49Smrg glutInit( &argc, argv ); 49832001f49Smrg glutInitDisplayMode( GLUT_SINGLE | GLUT_RGB ); 49932001f49Smrg glutCreateWindow( argv[0] ); 50032001f49Smrg 50132001f49Smrg /* GH: Bit of a hack... 50232001f49Smrg */ 50332001f49Smrg#ifdef GLU_VERSION_1_2 50432001f49Smrg myinit(); 50532001f49Smrg 50632001f49Smrg glutDisplayFunc( display ); 50732001f49Smrg glutReshapeFunc( reshape ); 50832001f49Smrg 50932001f49Smrg glutMainLoop(); 51032001f49Smrg#endif 51132001f49Smrg 51232001f49Smrg return 0; 51332001f49Smrg} 514