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