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