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