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