per old glut manpages, glutTeapot calls generate clockwise frontfacing
[freeglut] / progs / demos / shapes / shapes.c
1 /*! \file    shapes.c
2     \ingroup demos
3
4     This program is a test harness for the various shapes
5     in OpenGLUT.  It may also be useful to see which
6     parameters control what behavior in the OpenGLUT
7     objects.
8  
9     Spinning wireframe and solid-shaded shapes are
10     displayed.  Some parameters can be adjusted.
11  
12    Keys:
13       -    <tt>Esc &nbsp;</tt> Quit
14       -    <tt>q Q &nbsp;</tt> Quit
15       -    <tt>i I &nbsp;</tt> Show info
16       -    <tt>p P &nbsp;</tt> Toggle perspective or orthographic projection
17       -    <tt>= + &nbsp;</tt> Increase \a slices
18       -    <tt>- _ &nbsp;</tt> Decreate \a slices
19       -    <tt>, < &nbsp;</tt> Decreate \a stacks
20       -    <tt>. > &nbsp;</tt> Increase \a stacks
21       -    <tt>9 ( &nbsp;</tt> Decreate \a depth  (Sierpinski Sponge)
22       -    <tt>0 ) &nbsp;</tt> Increase \a depth  (Sierpinski Sponge)
23       -    <tt>up&nbsp; &nbsp;</tt> Increase "outer radius"
24       -    <tt>down&nbsp;</tt> Decrease "outer radius"
25       -    <tt>left&nbsp;</tt> Decrease "inner radius"
26       -    <tt>right</tt> Increase "inner radius"
27       -    <tt>PgUp&nbsp;</tt> Next shape-drawing function
28       -    <tt>PgDn&nbsp;</tt> Prev shape-drawing function
29
30     \author  Written by Nigel Stewart November 2003
31
32     \author  Portions Copyright (C) 2004, the OpenGLUT project contributors. <br>
33              OpenGLUT branched from freeglut in February, 2004.
34  
35     \image   html openglut_shapes.png OpenGLUT Geometric Shapes Demonstration
36     \include demos/shapes/shapes.c
37 */
38
39 #include <GL/freeglut.h>
40
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44
45 #ifdef _MSC_VER
46 /* DUMP MEMORY LEAKS */
47 #include <crtdbg.h>
48 #endif
49
50 /*
51  * This macro is only intended to be used on arrays, of course.
52  */
53 #define NUMBEROF(x) ((sizeof(x))/(sizeof(x[0])))
54
55 /*
56  * These global variables control which object is drawn,
57  * and how it is drawn.  No object uses all of these
58  * variables.
59  */
60 static int function_index;
61 static int slices = 16;
62 static int stacks = 16;
63 static double irad = .25;
64 static double orad = 1.0;   /* doubles as size for objects other than Torus */
65 static int depth = 4;
66 static double offset[ 3 ] = { 0, 0, 0 };
67 static GLboolean show_info = GL_TRUE;
68 static float ar;
69 static GLboolean persProject = GL_TRUE;
70
71 /*
72  * These one-liners draw particular objects, fetching appropriate
73  * information from the above globals.  They are just thin wrappers
74  * for the FreeGLUT objects.
75  */
76 static void drawSolidTetrahedron(void)         { glutSolidTetrahedron ();                        }
77 static void drawWireTetrahedron(void)          { glutWireTetrahedron ();                         }
78 static void drawSolidCube(void)                { glutSolidCube(orad);                            }  /* orad doubles as size input */
79 static void drawWireCube(void)                 { glutWireCube(orad);                             }  /* orad doubles as size input */
80 static void drawSolidOctahedron(void)          { glutSolidOctahedron ();                         }
81 static void drawWireOctahedron(void)           { glutWireOctahedron ();                          }
82 static void drawSolidDodecahedron(void)        { glutSolidDodecahedron ();                       }
83 static void drawWireDodecahedron(void)         { glutWireDodecahedron ();                        }
84 static void drawSolidRhombicDodecahedron(void) { glutSolidRhombicDodecahedron ();                }
85 static void drawWireRhombicDodecahedron(void)  { glutWireRhombicDodecahedron ();                 }
86 static void drawSolidIcosahedron(void)         { glutSolidIcosahedron ();                        }
87 static void drawWireIcosahedron(void)          { glutWireIcosahedron ();                         }
88 static void drawSolidSierpinskiSponge(void)    { glutSolidSierpinskiSponge (depth, offset, orad);}  /* orad doubles as size input */
89 static void drawWireSierpinskiSponge(void)     { glutWireSierpinskiSponge (depth, offset, orad); }  /* orad doubles as size input */
90 static void drawSolidTorus(void)               { glutSolidTorus(irad,orad,slices,stacks);        }
91 static void drawWireTorus(void)                { glutWireTorus (irad,orad,slices,stacks);        }
92 static void drawSolidSphere(void)              { glutSolidSphere(orad,slices,stacks);            }  /* orad doubles as size input */
93 static void drawWireSphere(void)               { glutWireSphere(orad,slices,stacks);             }  /* orad doubles as size input */
94 static void drawSolidCone(void)                { glutSolidCone(orad,orad,slices,stacks);         }  /* orad doubles as size input */
95 static void drawWireCone(void)                 { glutWireCone(orad,orad,slices,stacks);          }  /* orad doubles as size input */
96 static void drawSolidCylinder(void)            { glutSolidCylinder(orad,orad,slices,stacks);     }  /* orad doubles as size input */
97 static void drawWireCylinder(void)             { glutWireCylinder(orad,orad,slices,stacks);      }  /* orad doubles as size input */
98 static void drawSolidTeapot(void)
99 {
100     /* per Glut manpage, it should be noted that the teapot is rendered
101      * with clockwise winding for front facing polygons...
102      */
103     glFrontFace(GL_CW);
104     glutSolidTeapot(orad);  /* orad doubles as size input */
105     glFrontFace(GL_CCW);
106 }
107 static void drawWireTeapot(void)
108 {
109     /* per Glut manpage, it should be noted that the teapot is rendered
110      * with clockwise winding for front facing polygons...
111      */
112     glFrontFace(GL_CW);
113     glutWireTeapot(orad);  /* orad doubles as size input */
114     glFrontFace(GL_CCW);
115 }
116
117 #define RADIUS    1.0f
118
119 static void drawSolidCuboctahedron(void)
120 {
121   glBegin( GL_TRIANGLES );
122     glNormal3d( 0.577350269189, 0.577350269189, 0.577350269189); glVertex3d( RADIUS, RADIUS, 0.0 ); glVertex3d( 0.0, RADIUS, RADIUS ); glVertex3d( RADIUS, 0.0, RADIUS );
123     glNormal3d( 0.577350269189, 0.577350269189,-0.577350269189); glVertex3d( RADIUS, RADIUS, 0.0 ); glVertex3d( RADIUS, 0.0,-RADIUS ); glVertex3d( 0.0, RADIUS,-RADIUS );
124     glNormal3d( 0.577350269189,-0.577350269189, 0.577350269189); glVertex3d( RADIUS,-RADIUS, 0.0 ); glVertex3d( RADIUS, 0.0, RADIUS ); glVertex3d( 0.0,-RADIUS, RADIUS );
125     glNormal3d( 0.577350269189,-0.577350269189,-0.577350269189); glVertex3d( RADIUS,-RADIUS, 0.0 ); glVertex3d( 0.0,-RADIUS,-RADIUS ); glVertex3d( RADIUS, 0.0,-RADIUS );
126     glNormal3d(-0.577350269189, 0.577350269189, 0.577350269189); glVertex3d(-RADIUS, RADIUS, 0.0 ); glVertex3d(-RADIUS, 0.0, RADIUS ); glVertex3d( 0.0, RADIUS, RADIUS );
127     glNormal3d(-0.577350269189, 0.577350269189,-0.577350269189); glVertex3d(-RADIUS, RADIUS, 0.0 ); glVertex3d( 0.0, RADIUS,-RADIUS ); glVertex3d(-RADIUS, 0.0,-RADIUS );
128     glNormal3d(-0.577350269189,-0.577350269189, 0.577350269189); glVertex3d(-RADIUS,-RADIUS, 0.0 ); glVertex3d( 0.0,-RADIUS, RADIUS ); glVertex3d(-RADIUS, 0.0, RADIUS );
129     glNormal3d(-0.577350269189,-0.577350269189,-0.577350269189); glVertex3d(-RADIUS,-RADIUS, 0.0 ); glVertex3d(-RADIUS, 0.0,-RADIUS ); glVertex3d( 0.0,-RADIUS,-RADIUS );
130   glEnd();
131
132   glBegin( GL_QUADS );
133     glNormal3d( 1.0, 0.0, 0.0 ); glVertex3d( RADIUS, RADIUS, 0.0 ); glVertex3d( RADIUS, 0.0, RADIUS ); glVertex3d( RADIUS,-RADIUS, 0.0 ); glVertex3d( RADIUS, 0.0,-RADIUS );
134     glNormal3d(-1.0, 0.0, 0.0 ); glVertex3d(-RADIUS, RADIUS, 0.0 ); glVertex3d(-RADIUS, 0.0,-RADIUS ); glVertex3d(-RADIUS,-RADIUS, 0.0 ); glVertex3d(-RADIUS, 0.0, RADIUS );
135     glNormal3d( 0.0, 1.0, 0.0 ); glVertex3d( RADIUS, RADIUS, 0.0 ); glVertex3d( 0.0, RADIUS,-RADIUS ); glVertex3d(-RADIUS, RADIUS, 0.0 ); glVertex3d( 0.0, RADIUS, RADIUS );
136     glNormal3d( 0.0,-1.0, 0.0 ); glVertex3d( RADIUS,-RADIUS, 0.0 ); glVertex3d( 0.0,-RADIUS, RADIUS ); glVertex3d(-RADIUS,-RADIUS, 0.0 ); glVertex3d( 0.0,-RADIUS,-RADIUS );
137     glNormal3d( 0.0, 0.0, 1.0 ); glVertex3d( RADIUS, 0.0, RADIUS ); glVertex3d( 0.0, RADIUS, RADIUS ); glVertex3d(-RADIUS, 0.0, RADIUS ); glVertex3d( 0.0,-RADIUS, RADIUS );
138     glNormal3d( 0.0, 0.0,-1.0 ); glVertex3d( RADIUS, 0.0,-RADIUS ); glVertex3d( 0.0,-RADIUS,-RADIUS ); glVertex3d(-RADIUS, 0.0,-RADIUS ); glVertex3d( 0.0, RADIUS,-RADIUS );
139   glEnd();
140 }
141
142 static void drawWireCuboctahedron(void)
143 {
144   glBegin( GL_LINE_LOOP );
145     glNormal3d( 1.0, 0.0, 0.0 ); glVertex3d( RADIUS, RADIUS, 0.0 ); glVertex3d( RADIUS, 0.0, RADIUS ); glVertex3d( RADIUS,-RADIUS, 0.0 ); glVertex3d( RADIUS, 0.0,-RADIUS );
146   glEnd();
147   glBegin( GL_LINE_LOOP );
148     glNormal3d(-1.0, 0.0, 0.0 ); glVertex3d(-RADIUS, RADIUS, 0.0 ); glVertex3d(-RADIUS, 0.0,-RADIUS ); glVertex3d(-RADIUS,-RADIUS, 0.0 ); glVertex3d(-RADIUS, 0.0, RADIUS );
149   glEnd();
150   glBegin( GL_LINE_LOOP );
151     glNormal3d( 0.0, 1.0, 0.0 ); glVertex3d( RADIUS, RADIUS, 0.0 ); glVertex3d( 0.0, RADIUS,-RADIUS ); glVertex3d(-RADIUS, RADIUS, 0.0 ); glVertex3d( 0.0, RADIUS, RADIUS );
152   glEnd();
153   glBegin( GL_LINE_LOOP );
154     glNormal3d( 0.0,-1.0, 0.0 ); glVertex3d( RADIUS,-RADIUS, 0.0 ); glVertex3d( 0.0,-RADIUS, RADIUS ); glVertex3d(-RADIUS,-RADIUS, 0.0 ); glVertex3d( 0.0,-RADIUS,-RADIUS );
155   glEnd();
156   glBegin( GL_LINE_LOOP );
157     glNormal3d( 0.0, 0.0, 1.0 ); glVertex3d( RADIUS, 0.0, RADIUS ); glVertex3d( 0.0, RADIUS, RADIUS ); glVertex3d(-RADIUS, 0.0, RADIUS ); glVertex3d( 0.0,-RADIUS, RADIUS );
158   glEnd();
159   glBegin( GL_LINE_LOOP );
160     glNormal3d( 0.0, 0.0,-1.0 ); glVertex3d( RADIUS, 0.0,-RADIUS ); glVertex3d( 0.0,-RADIUS,-RADIUS ); glVertex3d(-RADIUS, 0.0,-RADIUS ); glVertex3d( 0.0, RADIUS,-RADIUS );
161   glEnd();
162 }
163
164 #undef RADIUS
165
166 /*
167  * This structure defines an entry in our function-table.
168  */
169 typedef struct
170 {
171     const char * const name;
172     void (*solid) (void);
173     void (*wire)  (void);
174 } entry;
175
176 #define ENTRY(e) {#e, drawSolid##e, drawWire##e}
177 static const entry table [] =
178 {
179     ENTRY (Tetrahedron),
180     ENTRY (Cube),
181     ENTRY (Octahedron),
182     ENTRY (Dodecahedron),
183     ENTRY (RhombicDodecahedron),
184     ENTRY (Icosahedron),
185     ENTRY (SierpinskiSponge),
186     ENTRY (Teapot),
187     ENTRY (Torus),
188     ENTRY (Sphere),
189     ENTRY (Cone),
190     ENTRY (Cylinder),
191     ENTRY (Cuboctahedron)
192 };
193 #undef ENTRY
194
195 /*!
196     Does printf()-like work using freeglut
197     glutBitmapString().  Uses a fixed font.  Prints
198     at the indicated row/column position.
199
200     Limitation: Cannot address pixels.
201     Limitation: Renders in screen coords, not model coords.
202 */
203 static void shapesPrintf (int row, int col, const char *fmt, ...)
204 {
205     static char buf[256];
206     int viewport[4];
207     void *font = GLUT_BITMAP_9_BY_15;
208     va_list args;
209
210     va_start(args, fmt);
211 #if defined(WIN32) && !defined(__CYGWIN__)
212     (void) _vsnprintf (buf, sizeof(buf), fmt, args);
213 #else
214     (void) vsnprintf (buf, sizeof(buf), fmt, args);
215 #endif
216     va_end(args);
217
218     glGetIntegerv(GL_VIEWPORT,viewport);
219
220     glPushMatrix();
221     glLoadIdentity();
222
223     glMatrixMode(GL_PROJECTION);
224     glPushMatrix();
225     glLoadIdentity();
226
227         glOrtho(0,viewport[2],0,viewport[3],-1,1);
228
229         glRasterPos2i
230         (
231               glutBitmapWidth(font, ' ') * col,
232             - glutBitmapHeight(font) * row + viewport[3]
233         );
234         glutBitmapString (font, (unsigned char*)buf);
235
236     glPopMatrix();
237     glMatrixMode(GL_MODELVIEW);
238     glPopMatrix();
239 }
240
241 /* GLUT callback Handlers */
242
243 static void
244 resize(int width, int height)
245 {
246     ar = (float) width / (float) height;
247
248     glViewport(0, 0, width, height);
249 }
250
251 static void display(void)
252 {
253     const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
254     const double a = t*90.0;
255
256     glMatrixMode(GL_PROJECTION);
257     glLoadIdentity();
258     if (persProject)
259         glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
260     else
261         glOrtho(-ar*3, ar*3, -3.0, 3.0, 2.0, 100.0);
262     glMatrixMode(GL_MODELVIEW);
263     glLoadIdentity();
264
265     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
266
267     glEnable(GL_LIGHTING);
268
269     glColor3d(1,0,0);
270
271     glPushMatrix();
272         glTranslated(0,1.2,-6);
273         glRotated(60,1,0,0);
274         glRotated(a,0,0,1);
275         table [function_index].solid ();
276     glPopMatrix();
277
278     glPushMatrix();
279         glTranslated(0,-1.2,-6);
280         glRotated(60,1,0,0);
281         glRotated(a,0,0,1);
282         table [function_index].wire ();
283     glPopMatrix();
284
285     glDisable(GL_LIGHTING);
286     glColor3d(0.1,0.1,0.4);
287
288     if( show_info ) {
289         shapesPrintf (1, 1, "Shape PgUp PgDn: %s", table [function_index].name);
290         shapesPrintf (2, 1, "Slices +-: %d   Stacks <>: %d", slices, stacks);
291         shapesPrintf (3, 1, "nSides +-: %d   nRings <>: %d", slices, stacks);
292         shapesPrintf (4, 1, "Depth  (): %d", depth);
293         shapesPrintf (5, 1, "Outer radius  Up  Down : %f", orad);
294         shapesPrintf (6, 1, "Inner radius Left Right: %f", irad);
295     } else {
296         printf ( "Shape %d slides %d stacks %d\n", function_index, slices, stacks ) ;
297     }
298
299     glutSwapBuffers();
300 }
301
302
303 static void
304 key(unsigned char key, int x, int y)
305 {
306     switch (key)
307     {
308     case 27 :
309     case 'Q':
310     case 'q': glutLeaveMainLoop () ;      break;
311
312     case 'I':
313     case 'i': show_info = ( show_info == GL_TRUE ) ? GL_FALSE : GL_TRUE; break;
314
315     case '=':
316     case '+': slices++;                   break;
317
318     case '-':
319     case '_': if( slices > -1 ) slices--; break;
320
321     case ',':
322     case '<': if( stacks > -1 ) stacks--; break;
323
324     case '.':
325     case '>': stacks++;                   break;
326
327     case '9': 
328     case '(': if( depth > -1 ) depth--;   break;
329
330     case '0': 
331     case ')': ++depth;                    break;
332
333     case 'P':
334     case 'p': persProject=!persProject;   break;
335
336     default:
337         break;
338     }
339
340     glutPostRedisplay();
341 }
342
343 static void special (int key, int x, int y)
344 {
345     switch (key)
346     {
347     case GLUT_KEY_PAGE_UP:    ++function_index; break;
348     case GLUT_KEY_PAGE_DOWN:  --function_index; break;
349     case GLUT_KEY_UP:         orad *= 2;        break;
350     case GLUT_KEY_DOWN:       orad /= 2;        break;
351
352     case GLUT_KEY_RIGHT:      irad *= 2;        break;
353     case GLUT_KEY_LEFT:       irad /= 2;        break;
354
355     default:
356         break;
357     }
358
359     if (0 > function_index)
360         function_index = NUMBEROF (table) - 1;
361
362     if (NUMBEROF (table) <= ( unsigned )function_index)
363         function_index = 0;
364 }
365
366
367 static void
368 idle(void)
369 {
370     glutPostRedisplay();
371 }
372
373 const GLfloat light_ambient[]  = { 0.0f, 0.0f, 0.0f, 1.0f };
374 const GLfloat light_diffuse[]  = { 1.0f, 1.0f, 1.0f, 1.0f };
375 const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
376 const GLfloat light_position[] = { 2.0f, 5.0f, 5.0f, 0.0f };
377
378 const GLfloat mat_ambient[]    = { 0.7f, 0.7f, 0.7f, 1.0f };
379 const GLfloat mat_diffuse[]    = { 0.8f, 0.8f, 0.8f, 1.0f };
380 const GLfloat mat_specular[]   = { 1.0f, 1.0f, 1.0f, 1.0f };
381 const GLfloat high_shininess[] = { 100.0f };
382
383 /* Program entry point */
384
385 int
386 main(int argc, char *argv[])
387 {
388     glutInitWindowSize(640,480);
389     glutInitWindowPosition(40,40);
390     glutInit(&argc, argv);
391     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
392
393     glutCreateWindow("FreeGLUT Shapes");
394
395     glutReshapeFunc(resize);
396     glutDisplayFunc(display);
397     glutKeyboardFunc(key);
398     glutSpecialFunc(special);
399     glutIdleFunc(idle);
400
401     glutSetOption ( GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION ) ;
402
403     glClearColor(1,1,1,1);
404     glEnable(GL_CULL_FACE);
405     glCullFace(GL_BACK);
406
407     glEnable(GL_DEPTH_TEST);
408     glDepthFunc(GL_LESS);
409
410     glEnable(GL_LIGHT0);
411     glEnable(GL_NORMALIZE);
412     glEnable(GL_COLOR_MATERIAL);
413
414     glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
415     glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
416     glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
417     glLightfv(GL_LIGHT0, GL_POSITION, light_position);
418
419     glMaterialfv(GL_FRONT, GL_AMBIENT,   mat_ambient);
420     glMaterialfv(GL_FRONT, GL_DIFFUSE,   mat_diffuse);
421     glMaterialfv(GL_FRONT, GL_SPECULAR,  mat_specular);
422     glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
423
424     glutMainLoop();
425
426 #ifdef _MSC_VER
427     /* DUMP MEMORY LEAK INFORMATION */
428     _CrtDumpMemoryLeaks () ;
429 #endif
430
431     return EXIT_SUCCESS;
432 }