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