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