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