bf7664a81ea09419b2a10637494fce0ba383573a
[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 static void drawSolidCuboctahedron(void)
98 {
99 #define RADIUS    1.0f
100   glBegin( GL_TRIANGLES );
101     glNormal3d( 0.577350269189, 0.577350269189, 0.577350269189); glVertex3d( RADIUS, RADIUS, 0.0 ); glVertex3d( 0.0, RADIUS, RADIUS ); glVertex3d( RADIUS, 0.0, RADIUS );
102     glNormal3d( 0.577350269189, 0.577350269189,-0.577350269189); glVertex3d( RADIUS, RADIUS, 0.0 ); glVertex3d( RADIUS, 0.0,-RADIUS ); glVertex3d( 0.0, RADIUS,-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(-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( 0.0,-RADIUS, RADIUS ); glVertex3d(-RADIUS, 0.0, RADIUS );
108     glNormal3d(-0.577350269189,-0.577350269189,-0.577350269189); glVertex3d(-RADIUS,-RADIUS, 0.0 ); glVertex3d(-RADIUS, 0.0,-RADIUS ); glVertex3d( 0.0,-RADIUS,-RADIUS );
109   glEnd();
110
111   glBegin( GL_QUADS );
112     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 );
113     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 );
114     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 );
115     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 );
116     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 );
117     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 );
118   glEnd();
119 #undef RADIUS
120 }
121 static void drawWireCuboctahedron(void)
122 {
123 }
124
125 /*
126  * This structure defines an entry in our function-table.
127  */
128 typedef struct
129 {
130     const char * const name;
131     void (*solid) (void);
132     void (*wire)  (void);
133 } entry;
134
135 #define ENTRY(e) {#e, drawSolid##e, drawWire##e}
136 static const entry table [] =
137 {
138     ENTRY (Tetrahedron),
139     ENTRY (Cube),
140     ENTRY (Octahedron),
141     ENTRY (Dodecahedron),
142     ENTRY (RhombicDodecahedron),
143     ENTRY (Icosahedron),
144     ENTRY (SierpinskiSponge),
145     ENTRY (Teapot),
146     ENTRY (Torus),
147     ENTRY (Sphere),
148     ENTRY (Cone),
149     ENTRY (Cylinder),
150     ENTRY (Cuboctahedron)
151 };
152 #undef ENTRY
153
154 /*!
155     Does printf()-like work using freeglut/OpenGLUT
156     glutBitmapString().  Uses a fixed font.  Prints
157     at the indicated row/column position.
158
159     Limitation: Cannot address pixels.
160     Limitation: Renders in screen coords, not model coords.
161
162     \note Uses a fixed, 256-byte array for holding strings.
163           The best way around this would be to use vasprintf(),
164           but that is not available on WIN32, I believe.
165           Another alternative would be to write our own formatter
166           from scratch and emit the characters one at a time to
167           the GLUT bitmap single-character drawing routine.
168           We could also use vsnprintf(), but I'm not sure if
169           that is standard...
170 */
171 static void shapesPrintf (int row, int col, const char *fmt, ...)
172 {
173     static char buf[256];
174     int viewport[4];
175     void *font = GLUT_BITMAP_9_BY_15;
176     va_list args;
177
178     va_start(args, fmt);
179     (void) vsprintf (buf, fmt, args);
180     va_end(args);
181
182     glGetIntegerv(GL_VIEWPORT,viewport);
183
184     glPushMatrix();
185     glLoadIdentity();
186
187     glMatrixMode(GL_PROJECTION);
188     glPushMatrix();
189     glLoadIdentity();
190
191         glOrtho(0,viewport[2],0,viewport[3],-1,1);
192
193         glRasterPos2i
194         (
195               glutBitmapWidth(font, ' ') * col,
196             - glutBitmapHeight(font) * (row+2) + viewport[3]
197         );
198         glutBitmapString (font, (unsigned char*)buf);
199
200     glPopMatrix();
201     glMatrixMode(GL_MODELVIEW);
202     glPopMatrix();
203 }
204
205 /* GLUT callback Handlers */
206
207 static void
208 resize(int width, int height)
209 {
210     const float ar = (float) width / (float) height;
211
212     glViewport(0, 0, width, height);
213
214     glMatrixMode(GL_PROJECTION);
215     glLoadIdentity();
216     glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
217
218     glMatrixMode(GL_MODELVIEW);
219     glLoadIdentity() ;
220 }
221
222 static void display(void)
223 {
224     const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
225     const double a = t*90.0;
226
227     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
228
229     glEnable(GL_LIGHTING);
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     if( show_info ) {
251         shapesPrintf (1, 3, "Shape PgUp PgDn: %s", table [function_index].name);
252         shapesPrintf (2, 3, "Slices +-: %d   Stacks <>: %d", slices, stacks);
253         shapesPrintf (3, 3, "nSides +-: %d   nRings <>: %d", slices, stacks);
254         shapesPrintf (4, 3, "Depth  (): %d", depth);
255         shapesPrintf (5, 3, "Outer radius  Up  Down : %f", orad);
256         shapesPrintf (6, 3, "Inner radius Left Right: %f", irad);
257     } else {
258         printf ( "Shape %d slides %d stacks %d\n", function_index, slices, stacks ) ;
259     }
260
261     glutSwapBuffers();
262 }
263
264
265 static void
266 key(unsigned char key, int x, int y)
267 {
268     switch (key)
269     {
270     case 27 :
271     case 'Q':
272     case 'q': glutLeaveMainLoop () ;      break;
273
274     case 'I':
275     case 'i': show_info = ( show_info == GL_TRUE ) ? GL_FALSE : GL_TRUE; break;
276
277     case '=':
278     case '+': slices++;                   break;
279
280     case '-':
281     case '_': if( slices > -1 ) slices--; break;
282
283     case ',':
284     case '<': if( stacks > -1 ) stacks--; break;
285
286     case '.':
287     case '>': stacks++;                   break;
288
289     case '9': 
290     case '(': if( depth > -1 ) depth--;   break;
291
292     case '0': 
293     case ')': ++depth;                    break;
294
295     default:
296         break;
297     }
298
299     glutPostRedisplay();
300 }
301
302 static void special (int key, int x, int y)
303 {
304     switch (key)
305     {
306     case GLUT_KEY_PAGE_UP:    ++function_index; break;
307     case GLUT_KEY_PAGE_DOWN:  --function_index; break;
308     case GLUT_KEY_UP:         orad *= 2;        break;
309     case GLUT_KEY_DOWN:       orad /= 2;        break;
310
311     case GLUT_KEY_RIGHT:      irad *= 2;        break;
312     case GLUT_KEY_LEFT:       irad /= 2;        break;
313
314     default:
315         break;
316     }
317
318     if (0 > function_index)
319         function_index = NUMBEROF (table) - 1;
320
321     if (NUMBEROF (table) <= ( unsigned )function_index)
322         function_index = 0;
323 }
324
325
326 static void
327 idle(void)
328 {
329     glutPostRedisplay();
330 }
331
332 const GLfloat light_ambient[]  = { 0.0f, 0.0f, 0.0f, 1.0f };
333 const GLfloat light_diffuse[]  = { 1.0f, 1.0f, 1.0f, 1.0f };
334 const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
335 const GLfloat light_position[] = { 2.0f, 5.0f, 5.0f, 0.0f };
336
337 const GLfloat mat_ambient[]    = { 0.7f, 0.7f, 0.7f, 1.0f };
338 const GLfloat mat_diffuse[]    = { 0.8f, 0.8f, 0.8f, 1.0f };
339 const GLfloat mat_specular[]   = { 1.0f, 1.0f, 1.0f, 1.0f };
340 const GLfloat high_shininess[] = { 100.0f };
341
342 /* Program entry point */
343
344 int
345 main(int argc, char *argv[])
346 {
347     glutInitWindowSize(640,480);
348     glutInitWindowPosition(40,40);
349     glutInit(&argc, argv);
350     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
351
352     glutCreateWindow("OpenGLUT Shapes");
353
354     glutReshapeFunc(resize);
355     glutDisplayFunc(display);
356     glutKeyboardFunc(key);
357     glutSpecialFunc(special);
358     glutIdleFunc(idle);
359
360     glutSetOption ( GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION ) ;
361
362     glClearColor(1,1,1,1);
363     glEnable(GL_CULL_FACE);
364     glCullFace(GL_BACK);
365
366     glEnable(GL_DEPTH_TEST);
367     glDepthFunc(GL_LESS);
368
369     glEnable(GL_LIGHT0);
370     glEnable(GL_NORMALIZE);
371     glEnable(GL_COLOR_MATERIAL);
372
373     glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
374     glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
375     glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
376     glLightfv(GL_LIGHT0, GL_POSITION, light_position);
377
378     glMaterialfv(GL_FRONT, GL_AMBIENT,   mat_ambient);
379     glMaterialfv(GL_FRONT, GL_DIFFUSE,   mat_diffuse);
380     glMaterialfv(GL_FRONT, GL_SPECULAR,  mat_specular);
381     glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
382
383     glutMainLoop();
384
385 #ifdef WIN32
386     /* DUMP MEMORY LEAK INFORMATION */
387     _CrtDumpMemoryLeaks () ;
388 #endif
389
390     return EXIT_SUCCESS;
391 }