Fixing Microsoft compatibility with the new "vsnprintf" by putting an underscore...
[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 _MSC_VER
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 #if defined(WIN32) && !defined(__CYGWIN__)
193     (void) _vsnprintf (buf, sizeof(buf), fmt, args);
194 #else
195     (void) vsnprintf (buf, sizeof(buf), fmt, args);
196 #endif
197     va_end(args);
198
199     glGetIntegerv(GL_VIEWPORT,viewport);
200
201     glPushMatrix();
202     glLoadIdentity();
203
204     glMatrixMode(GL_PROJECTION);
205     glPushMatrix();
206     glLoadIdentity();
207
208         glOrtho(0,viewport[2],0,viewport[3],-1,1);
209
210         glRasterPos2i
211         (
212               glutBitmapWidth(font, ' ') * col,
213             - glutBitmapHeight(font) * (row+2) + viewport[3]
214         );
215         glutBitmapString (font, (unsigned char*)buf);
216
217     glPopMatrix();
218     glMatrixMode(GL_MODELVIEW);
219     glPopMatrix();
220 }
221
222 /* GLUT callback Handlers */
223
224 static void
225 resize(int width, int height)
226 {
227     const float ar = (float) width / (float) height;
228
229     glViewport(0, 0, width, height);
230
231     glMatrixMode(GL_PROJECTION);
232     glLoadIdentity();
233     glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
234
235     glMatrixMode(GL_MODELVIEW);
236     glLoadIdentity() ;
237 }
238
239 static void display(void)
240 {
241     const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
242     const double a = t*90.0;
243
244     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
245
246     glEnable(GL_LIGHTING);
247
248     glColor3d(1,0,0);
249
250     glPushMatrix();
251         glTranslated(0,1.2,-6);
252         glRotated(60,1,0,0);
253         glRotated(a,0,0,1);
254         table [function_index].solid ();
255     glPopMatrix();
256
257     glPushMatrix();
258         glTranslated(0,-1.2,-6);
259         glRotated(60,1,0,0);
260         glRotated(a,0,0,1);
261         table [function_index].wire ();
262     glPopMatrix();
263
264     glDisable(GL_LIGHTING);
265     glColor3d(0.1,0.1,0.4);
266
267     if( show_info ) {
268         shapesPrintf (1, 3, "Shape PgUp PgDn: %s", table [function_index].name);
269         shapesPrintf (2, 3, "Slices +-: %d   Stacks <>: %d", slices, stacks);
270         shapesPrintf (3, 3, "nSides +-: %d   nRings <>: %d", slices, stacks);
271         shapesPrintf (4, 3, "Depth  (): %d", depth);
272         shapesPrintf (5, 3, "Outer radius  Up  Down : %f", orad);
273         shapesPrintf (6, 3, "Inner radius Left Right: %f", irad);
274     } else {
275         printf ( "Shape %d slides %d stacks %d\n", function_index, slices, stacks ) ;
276     }
277
278     glutSwapBuffers();
279 }
280
281
282 static void
283 key(unsigned char key, int x, int y)
284 {
285     switch (key)
286     {
287     case 27 :
288     case 'Q':
289     case 'q': glutLeaveMainLoop () ;      break;
290
291     case 'I':
292     case 'i': show_info = ( show_info == GL_TRUE ) ? GL_FALSE : GL_TRUE; break;
293
294     case '=':
295     case '+': slices++;                   break;
296
297     case '-':
298     case '_': if( slices > -1 ) slices--; break;
299
300     case ',':
301     case '<': if( stacks > -1 ) stacks--; break;
302
303     case '.':
304     case '>': stacks++;                   break;
305
306     case '9': 
307     case '(': if( depth > -1 ) depth--;   break;
308
309     case '0': 
310     case ')': ++depth;                    break;
311
312     default:
313         break;
314     }
315
316     glutPostRedisplay();
317 }
318
319 static void special (int key, int x, int y)
320 {
321     switch (key)
322     {
323     case GLUT_KEY_PAGE_UP:    ++function_index; break;
324     case GLUT_KEY_PAGE_DOWN:  --function_index; break;
325     case GLUT_KEY_UP:         orad *= 2;        break;
326     case GLUT_KEY_DOWN:       orad /= 2;        break;
327
328     case GLUT_KEY_RIGHT:      irad *= 2;        break;
329     case GLUT_KEY_LEFT:       irad /= 2;        break;
330
331     default:
332         break;
333     }
334
335     if (0 > function_index)
336         function_index = NUMBEROF (table) - 1;
337
338     if (NUMBEROF (table) <= ( unsigned )function_index)
339         function_index = 0;
340 }
341
342
343 static void
344 idle(void)
345 {
346     glutPostRedisplay();
347 }
348
349 const GLfloat light_ambient[]  = { 0.0f, 0.0f, 0.0f, 1.0f };
350 const GLfloat light_diffuse[]  = { 1.0f, 1.0f, 1.0f, 1.0f };
351 const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
352 const GLfloat light_position[] = { 2.0f, 5.0f, 5.0f, 0.0f };
353
354 const GLfloat mat_ambient[]    = { 0.7f, 0.7f, 0.7f, 1.0f };
355 const GLfloat mat_diffuse[]    = { 0.8f, 0.8f, 0.8f, 1.0f };
356 const GLfloat mat_specular[]   = { 1.0f, 1.0f, 1.0f, 1.0f };
357 const GLfloat high_shininess[] = { 100.0f };
358
359 /* Program entry point */
360
361 int
362 main(int argc, char *argv[])
363 {
364     glutInitWindowSize(640,480);
365     glutInitWindowPosition(40,40);
366     glutInit(&argc, argv);
367     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
368
369     glutCreateWindow("OpenGLUT Shapes");
370
371     glutReshapeFunc(resize);
372     glutDisplayFunc(display);
373     glutKeyboardFunc(key);
374     glutSpecialFunc(special);
375     glutIdleFunc(idle);
376
377     glutSetOption ( GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION ) ;
378
379     glClearColor(1,1,1,1);
380     glEnable(GL_CULL_FACE);
381     glCullFace(GL_BACK);
382
383     glEnable(GL_DEPTH_TEST);
384     glDepthFunc(GL_LESS);
385
386     glEnable(GL_LIGHT0);
387     glEnable(GL_NORMALIZE);
388     glEnable(GL_COLOR_MATERIAL);
389
390     glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
391     glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
392     glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
393     glLightfv(GL_LIGHT0, GL_POSITION, light_position);
394
395     glMaterialfv(GL_FRONT, GL_AMBIENT,   mat_ambient);
396     glMaterialfv(GL_FRONT, GL_DIFFUSE,   mat_diffuse);
397     glMaterialfv(GL_FRONT, GL_SPECULAR,  mat_specular);
398     glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
399
400     glutMainLoop();
401
402 #ifdef _MSC_VER
403     /* DUMP MEMORY LEAK INFORMATION */
404     _CrtDumpMemoryLeaks () ;
405 #endif
406
407     return EXIT_SUCCESS;
408 }