GLUT_GEOMETRY_VISUALIZE_NORMALS is a better name than GLUT_OBJECTS_VISUALIZE_NORMALS
[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>p P &nbsp;</tt> Toggle perspective or orthographic projection
17       -    <tt>r R &nbsp;</tt> Toggle fixed or animated rotation around model X-axis
18       -    <tt>= + &nbsp;</tt> Increase \a slices
19       -    <tt>- _ &nbsp;</tt> Decreate \a slices
20       -    <tt>, < &nbsp;</tt> Decreate \a stacks
21       -    <tt>. > &nbsp;</tt> Increase \a stacks
22       -    <tt>9 ( &nbsp;</tt> Decreate \a depth  (Sierpinski Sponge)
23       -    <tt>0 ) &nbsp;</tt> Increase \a depth  (Sierpinski Sponge)
24       -    <tt>up&nbsp; &nbsp;</tt> Increase "outer radius"
25       -    <tt>down&nbsp;</tt> Decrease "outer radius"
26       -    <tt>left&nbsp;</tt> Decrease "inner radius"
27       -    <tt>right</tt> Increase "inner radius"
28       -    <tt>PgUp&nbsp;</tt> Next shape-drawing function
29       -    <tt>PgDn&nbsp;</tt> Prev shape-drawing function
30
31     \author  Written by Nigel Stewart November 2003
32
33     \author  Portions Copyright (C) 2004, the OpenGLUT project contributors. <br>
34              OpenGLUT branched from freeglut in February, 2004.
35  
36     \image   html openglut_shapes.png OpenGLUT Geometric Shapes Demonstration
37     \include demos/shapes/shapes.c
38 */
39
40 #include <GL/freeglut.h>
41
42 #include <stdarg.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45
46 #include "glmatrix.h"
47
48 #ifdef _MSC_VER
49 /* DUMP MEMORY LEAKS */
50 #include <crtdbg.h>
51 #endif
52
53 /* report GL errors, if any, to stderr */
54 void checkError(const char *functionName)
55 {
56     GLenum error;
57     while (( error = glGetError() ) != GL_NO_ERROR) {
58         fprintf (stderr, "GL error 0x%X detected in %s\n", error, functionName);
59     }
60 }
61
62 /*
63  * OpenGL 2+ shader mode needs some function and macro definitions, 
64  * avoiding a dependency on additional libraries like GLEW or the
65  * GL/glext.h header
66  */
67 #ifndef GL_FRAGMENT_SHADER
68 #define GL_FRAGMENT_SHADER 0x8B30
69 #endif
70
71 #ifndef GL_VERTEX_SHADER
72 #define GL_VERTEX_SHADER 0x8B31
73 #endif
74
75 #ifndef GL_COMPILE_STATUS
76 #define GL_COMPILE_STATUS 0x8B81
77 #endif
78
79 #ifndef GL_LINK_STATUS
80 #define GL_LINK_STATUS 0x8B82
81 #endif
82
83 #ifndef GL_INFO_LOG_LENGTH
84 #define GL_INFO_LOG_LENGTH 0x8B84
85 #endif
86
87 typedef ptrdiff_t ourGLsizeiptr;
88 typedef char ourGLchar;
89
90 #ifndef APIENTRY
91 #define APIENTRY
92 #endif
93
94 #ifndef GL_VERSION_1_5
95 typedef void (APIENTRY *PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
96 typedef void (APIENTRY *PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
97 typedef void (APIENTRY *PFNGLBUFFERDATAPROC) (GLenum target, ourGLsizeiptr size, const GLvoid *data, GLenum usage);
98 #endif
99 #ifndef GL_VERSION_2_0
100 typedef GLuint (APIENTRY *PFNGLCREATESHADERPROC) (GLenum type);
101 typedef void (APIENTRY *PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const ourGLchar **string, const GLint *length);
102 typedef void (APIENTRY *PFNGLCOMPILESHADERPROC) (GLuint shader);
103 typedef GLuint (APIENTRY *PFNGLCREATEPROGRAMPROC) (void);
104 typedef void (APIENTRY *PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
105 typedef void (APIENTRY *PFNGLLINKPROGRAMPROC) (GLuint program);
106 typedef void (APIENTRY *PFNGLUSEPROGRAMPROC) (GLuint program);
107 typedef void (APIENTRY *PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
108 typedef void (APIENTRY *PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, ourGLchar *infoLog);
109 typedef void (APIENTRY *PFNGLGETPROGRAMIVPROC) (GLenum target, GLenum pname, GLint *params);
110 typedef void (APIENTRY *PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, ourGLchar *infoLog);
111 typedef GLint (APIENTRY *PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const ourGLchar *name);
112 typedef GLint (APIENTRY *PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const ourGLchar *name);
113 typedef void (APIENTRY *PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
114 typedef void (APIENTRY *PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
115 #endif
116
117 PFNGLCREATESHADERPROC gl_CreateShader;
118 PFNGLSHADERSOURCEPROC gl_ShaderSource;
119 PFNGLCOMPILESHADERPROC gl_CompileShader;
120 PFNGLCREATEPROGRAMPROC gl_CreateProgram;
121 PFNGLATTACHSHADERPROC gl_AttachShader;
122 PFNGLLINKPROGRAMPROC gl_LinkProgram;
123 PFNGLUSEPROGRAMPROC gl_UseProgram;
124 PFNGLGETSHADERIVPROC gl_GetShaderiv;
125 PFNGLGETSHADERINFOLOGPROC gl_GetShaderInfoLog;
126 PFNGLGETPROGRAMIVPROC gl_GetProgramiv;
127 PFNGLGETPROGRAMINFOLOGPROC gl_GetProgramInfoLog;
128 PFNGLGETATTRIBLOCATIONPROC gl_GetAttribLocation;
129 PFNGLGETUNIFORMLOCATIONPROC gl_GetUniformLocation;
130 PFNGLUNIFORMMATRIX4FVPROC gl_UniformMatrix4fv;
131 PFNGLUNIFORMMATRIX3FVPROC gl_UniformMatrix3fv;
132
133 void initExtensionEntries(void)
134 {
135     gl_CreateShader = (PFNGLCREATESHADERPROC) glutGetProcAddress ("glCreateShader");
136     gl_ShaderSource = (PFNGLSHADERSOURCEPROC) glutGetProcAddress ("glShaderSource");
137     gl_CompileShader = (PFNGLCOMPILESHADERPROC) glutGetProcAddress ("glCompileShader");
138     gl_CreateProgram = (PFNGLCREATEPROGRAMPROC) glutGetProcAddress ("glCreateProgram");
139     gl_AttachShader = (PFNGLATTACHSHADERPROC) glutGetProcAddress ("glAttachShader");
140     gl_LinkProgram = (PFNGLLINKPROGRAMPROC) glutGetProcAddress ("glLinkProgram");
141     gl_UseProgram = (PFNGLUSEPROGRAMPROC) glutGetProcAddress ("glUseProgram");
142     gl_GetShaderiv = (PFNGLGETSHADERIVPROC) glutGetProcAddress ("glGetShaderiv");
143     gl_GetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) glutGetProcAddress ("glGetShaderInfoLog");
144     gl_GetProgramiv = (PFNGLGETPROGRAMIVPROC) glutGetProcAddress ("glGetProgramiv");
145     gl_GetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) glutGetProcAddress ("glGetProgramInfoLog");
146     gl_GetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) glutGetProcAddress ("glGetAttribLocation");
147     gl_GetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) glutGetProcAddress ("glGetUniformLocation");
148     gl_UniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) glutGetProcAddress ("glUniformMatrix4fv");
149     gl_UniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) glutGetProcAddress ("glUniformMatrix3fv");
150 }
151
152 const ourGLchar *vertexShaderSource[] = {
153     "/**",
154     " * From the OpenGL Programming wikibook: http://en.wikibooks.org/wiki/GLSL_Programming/GLUT/Smooth_Specular_Highlights",
155     " * This file is in the public domain.",
156     " * Contributors: Sylvain Beucler",
157     " */",
158     "attribute vec3 fg_coord;",
159     "attribute vec3 fg_normal;",
160     "varying vec4 position;  /* position of the vertex (and fragment) in world space */",
161     "varying vec3 varyingNormalDirection;  /* surface normal vector in world space */",
162     "uniform mat4 m, p;      /* don't need v, as always identity in our demo */",
163     "uniform mat3 m_3x3_inv_transp;",
164     " ",
165     "void main()",
166     "{",
167     "  vec4 fg_coord4 = vec4(fg_coord, 1.0);",
168     "  position = m * fg_coord4;",
169     "  varyingNormalDirection = normalize(m_3x3_inv_transp * fg_normal);",
170     " ",
171     "  mat4 mvp = p*m;   /* normally p*v*m */",
172     "  gl_Position = mvp * fg_coord4;",
173     "}"
174 };
175
176 const ourGLchar *fragmentShaderSource[] = {
177     "/**",
178     " * From the OpenGL Programming wikibook: http://en.wikibooks.org/wiki/GLSL_Programming/GLUT/Smooth_Specular_Highlights",
179     " * This file is in the public domain.",
180     " * Contributors: Martin Kraus, Sylvain Beucler",
181     " */",
182     "varying vec4 position;  /* position of the vertex (and fragment) in world space */",
183     "varying vec3 varyingNormalDirection;  /* surface normal vector in world space */",
184     "/* uniform mat4 v_inv;   // in this demo, the view matrix is always an identity matrix */",
185     " ",
186     "struct lightSource",
187     "{",
188     "  vec4 position;",
189     "  vec4 diffuse;",
190     "  vec4 specular;",
191     "  float constantAttenuation, linearAttenuation, quadraticAttenuation;",
192     "  float spotCutoff, spotExponent;",
193     "  vec3 spotDirection;",
194     "};",
195     "lightSource light0 = lightSource(",
196     "  vec4(2.0, 5.0, 5.0, 0.0),",
197     "  vec4(1.0, 1.0, 1.0, 1.0),",
198     "  vec4(1.0, 1.0, 1.0, 1.0),",
199     "    0.0, 1.0, 0.0,",
200     "  180.0, 0.0,",
201     "  vec3(0.0, 0.0, 0.0)",
202     ");",
203     "vec4 scene_ambient = vec4(0.2, 0.2, 0.2, 1.0);",
204     " ",
205     "struct material",
206     "{",
207     "  vec4 ambient;",
208     "  vec4 diffuse;",
209     "  vec4 specular;",
210     "  float shininess;",
211     "};",
212     "material frontMaterial = material(",
213     "  vec4(1.0, 0.0, 0.0, 1.0),",
214     "  vec4(1.0, 0.0, 0.0, 1.0),",
215     "  vec4(1.0, 1.0, 1.0, 1.0),",
216     "  100.0",
217     ");",
218     " ",
219     "void main()",
220     "{",
221     "  vec3 normalDirection = normalize(varyingNormalDirection);",
222     "  /* vec3 viewDirection = normalize(vec3(v_inv * vec4(0.0, 0.0, 0.0, 1.0) - position)); */",
223     "  vec3 viewDirection = normalize(vec3(vec4(0.0, 0.0, 0.0, 1.0) - position));    /* in this demo, the view matrix is always an identity matrix */",
224     "  vec3 lightDirection;",
225     "  float attenuation;",
226     " ",
227     "  if (0.0 == light0.position.w) /* directional light? */",
228     "    {",
229     "      attenuation = 1.0; /* no attenuation */",
230     "      lightDirection = normalize(vec3(light0.position));",
231     "    } ",
232     "  else /* point light or spotlight (or other kind of light) */",
233     "    {",
234     "      vec3 positionToLightSource = vec3(light0.position - position);",
235     "      float distance = length(positionToLightSource);",
236     "      lightDirection = normalize(positionToLightSource);",
237     "      attenuation = 1.0 / (light0.constantAttenuation",
238     "                           + light0.linearAttenuation * distance",
239     "                           + light0.quadraticAttenuation * distance * distance);",
240     " ",
241     "      if (light0.spotCutoff <= 90.0) /* spotlight? */",
242     "        {",
243     "          float clampedCosine = max(0.0, dot(-lightDirection, light0.spotDirection));",
244     "          if (clampedCosine < cos(radians(light0.spotCutoff))) /* outside of spotlight cone? */",
245     "            {",
246     "              attenuation = 0.0;",
247     "            }",
248     "          else",
249     "            {",
250     "              attenuation = attenuation * pow(clampedCosine, light0.spotExponent);   ",
251     "            }",
252     "        }",
253     "    }",
254     " ",
255     "  vec3 ambientLighting = vec3(scene_ambient) * vec3(frontMaterial.ambient);",
256     " ",
257     "  vec3 diffuseReflection = attenuation ",
258     "    * vec3(light0.diffuse) * vec3(frontMaterial.diffuse)",
259     "    * max(0.0, dot(normalDirection, lightDirection));",
260     " ",
261     "  vec3 specularReflection;",
262     "  if (dot(normalDirection, lightDirection) < 0.0) /* light source on the wrong side? */",
263     "    {",
264     "      specularReflection = vec3(0.0, 0.0, 0.0); /* no specular reflection */",
265     "    }",
266     "  else /* light source on the right side */",
267     "    {",
268     "      specularReflection = attenuation * vec3(light0.specular) * vec3(frontMaterial.specular) ",
269     "        * pow(max(0.0, dot(reflect(-lightDirection, normalDirection), viewDirection)), frontMaterial.shininess);",
270     "    }",
271     " ",
272     "  gl_FragColor = vec4(ambientLighting + diffuseReflection + specularReflection, 1.0);",
273     "}"
274 };
275
276 GLint getAttribOrUniformLocation(const char* name, GLuint program, GLboolean isAttrib)
277 {
278     if (isAttrib)
279     {
280         GLint attrib = gl_GetAttribLocation(program, name);
281         if (attrib == -1)
282         {
283             fprintf(stderr, "Warning: Could not bind attrib %s\n", name);  
284         }
285
286         return attrib;
287     }
288     else
289     {
290         GLint uniform = gl_GetUniformLocation(program, name);
291         if (uniform == -1)
292         {
293             fprintf(stderr, "Warning: Could not bind uniform %s\n", name);  
294         }
295
296         return uniform;
297     }
298     checkError ("getAttribOrUniformLocation");
299 }
300
301 GLuint program;
302 GLint attribute_fg_coord = -1, attribute_fg_normal = -1;  
303 GLint uniform_m = -1, uniform_p = -1, uniform_m_3x3_inv_transp = -1;
304 GLint shaderReady = 0;  /* Set to 1 when all initialization went well, to -1 when shader somehow unusable. */
305
306
307
308 void compileAndCheck(GLuint shader)
309 {
310     GLint status;
311     gl_CompileShader (shader);
312     gl_GetShaderiv (shader, GL_COMPILE_STATUS, &status);
313     if (status == GL_FALSE) {
314         GLint infoLogLength;
315         ourGLchar *infoLog;
316         gl_GetShaderiv (shader, GL_INFO_LOG_LENGTH, &infoLogLength);
317         infoLog = (ourGLchar*) malloc (infoLogLength);
318         gl_GetShaderInfoLog (shader, infoLogLength, NULL, infoLog);
319         fprintf (stderr, "compile log: %s\n", infoLog);
320         free (infoLog);
321     }
322     checkError ("compileAndCheck");
323 }
324
325 GLuint compileShaderSource(GLenum type, GLsizei count, const ourGLchar **string)
326 {
327     GLuint shader = gl_CreateShader (type);
328     gl_ShaderSource (shader, count, string, NULL);
329
330     checkError ("compileShaderSource");
331
332     compileAndCheck (shader);
333     return shader;
334 }
335
336 void linkAndCheck(GLuint program)
337 {
338     GLint status;
339     gl_LinkProgram (program);
340     gl_GetProgramiv (program, GL_LINK_STATUS, &status);
341     if (status == GL_FALSE) {
342         GLint infoLogLength;
343         ourGLchar *infoLog;
344         gl_GetProgramiv (program, GL_INFO_LOG_LENGTH, &infoLogLength);
345         infoLog = (ourGLchar*) malloc (infoLogLength);
346         gl_GetProgramInfoLog (program, infoLogLength, NULL, infoLog);
347         fprintf (stderr, "link log: %s\n", infoLog);
348         free (infoLog);
349     }
350     checkError ("linkAndCheck");
351 }
352
353 void createProgram(GLuint vertexShader, GLuint fragmentShader)
354 {
355     program = gl_CreateProgram ();
356     if (vertexShader != 0) {
357         gl_AttachShader (program, vertexShader);
358     }
359     if (fragmentShader != 0) {
360         gl_AttachShader (program, fragmentShader);
361     }
362
363     checkError ("createProgram");
364
365     linkAndCheck (program);
366 }
367
368 void initShader(void)
369 {
370     const GLsizei vertexShaderLines = sizeof(vertexShaderSource) / sizeof(ourGLchar*);
371     GLuint vertexShader =
372         compileShaderSource (GL_VERTEX_SHADER, vertexShaderLines, vertexShaderSource);
373
374     const GLsizei fragmentShaderLines = sizeof(fragmentShaderSource) / sizeof(ourGLchar*);
375     GLuint fragmentShader =
376         compileShaderSource (GL_FRAGMENT_SHADER, fragmentShaderLines, fragmentShaderSource);
377
378     checkError ("initShader - 1");
379
380     createProgram (vertexShader, fragmentShader);
381
382     gl_UseProgram (program);
383
384     attribute_fg_coord      = getAttribOrUniformLocation("fg_coord"         , program, GL_TRUE);
385     attribute_fg_normal     = getAttribOrUniformLocation("fg_normal"        , program, GL_TRUE);
386     uniform_m               = getAttribOrUniformLocation("m"                , program, GL_FALSE);
387     uniform_p               = getAttribOrUniformLocation("p"                , program, GL_FALSE);
388     uniform_m_3x3_inv_transp= getAttribOrUniformLocation("m_3x3_inv_transp" , program, GL_FALSE);
389
390     gl_UseProgram (0);
391
392     if (attribute_fg_coord==-1 || attribute_fg_normal==-1 ||
393         uniform_m==-1 || uniform_p==-1 || uniform_m_3x3_inv_transp==-1)
394         shaderReady = -1;
395     else
396         shaderReady = 1;
397
398     checkError ("initShader - 2");
399 }
400
401 /*
402  * This macro is only intended to be used on arrays, of course.
403  */
404 #define NUMBEROF(x) ((sizeof(x))/(sizeof(x[0])))
405
406 /*
407  * These global variables control which object is drawn,
408  * and how it is drawn.  No object uses all of these
409  * variables.
410  */
411 static int function_index;
412 static int slices = 16;
413 static int stacks = 16;
414 static double irad = .25;
415 static double orad = 1.0;   /* doubles as size for objects other than Torus */
416 static int depth = 4;
417 static double offset[ 3 ] = { 0, 0, 0 };
418 static GLboolean show_info = GL_TRUE;
419 static float ar;
420 static GLboolean persProject = GL_TRUE;
421 static GLboolean animateXRot = GL_FALSE;
422 static GLboolean useShader   = GL_FALSE;
423 static GLboolean visNormals  = GL_FALSE;
424
425 /*
426  * These one-liners draw particular objects, fetching appropriate
427  * information from the above globals.  They are just thin wrappers
428  * for the FreeGLUT objects.
429  */
430 static void drawSolidTetrahedron(void)         { glutSolidTetrahedron ();                        }
431 static void drawWireTetrahedron(void)          { glutWireTetrahedron ();                         }
432 static void drawSolidCube(void)                { glutSolidCube(orad);                            }  /* orad doubles as size input */
433 static void drawWireCube(void)                 { glutWireCube(orad);                             }  /* orad doubles as size input */
434 static void drawSolidOctahedron(void)          { glutSolidOctahedron ();                         }
435 static void drawWireOctahedron(void)           { glutWireOctahedron ();                          }
436 static void drawSolidDodecahedron(void)        { glutSolidDodecahedron ();                       }
437 static void drawWireDodecahedron(void)         { glutWireDodecahedron ();                        }
438 static void drawSolidRhombicDodecahedron(void) { glutSolidRhombicDodecahedron ();                }
439 static void drawWireRhombicDodecahedron(void)  { glutWireRhombicDodecahedron ();                 }
440 static void drawSolidIcosahedron(void)         { glutSolidIcosahedron ();                        }
441 static void drawWireIcosahedron(void)          { glutWireIcosahedron ();                         }
442 static void drawSolidSierpinskiSponge(void)    { glutSolidSierpinskiSponge (depth, offset, orad);}  /* orad doubles as size input */
443 static void drawWireSierpinskiSponge(void)     { glutWireSierpinskiSponge (depth, offset, orad); }  /* orad doubles as size input */
444 static void drawSolidTorus(void)               { glutSolidTorus(irad,orad,slices,stacks);        }
445 static void drawWireTorus(void)                { glutWireTorus (irad,orad,slices,stacks);        }
446 static void drawSolidSphere(void)              { glutSolidSphere(orad,slices,stacks);            }  /* orad doubles as size input */
447 static void drawWireSphere(void)               { glutWireSphere(orad,slices,stacks);             }  /* orad doubles as size input */
448 static void drawSolidCone(void)                { glutSolidCone(orad,orad,slices,stacks);         }  /* orad doubles as size input */
449 static void drawWireCone(void)                 { glutWireCone(orad,orad,slices,stacks);          }  /* orad doubles as size input */
450 static void drawSolidCylinder(void)            { glutSolidCylinder(orad,orad,slices,stacks);     }  /* orad doubles as size input */
451 static void drawWireCylinder(void)             { glutWireCylinder(orad,orad,slices,stacks);      }  /* orad doubles as size input */
452 static void drawSolidTeapot(void)
453 {
454     /* per Glut manpage, it should be noted that the teapot is rendered
455      * with clockwise winding for front facing polygons...
456      */
457     glFrontFace(GL_CW);
458     glutSolidTeapot(orad);  /* orad doubles as size input */
459     glFrontFace(GL_CCW);
460 }
461 static void drawWireTeapot(void)
462 {
463     /* per Glut manpage, it should be noted that the teapot is rendered
464      * with clockwise winding for front facing polygons...
465      */
466     glFrontFace(GL_CW);
467     glutWireTeapot(orad);  /* orad doubles as size input */
468     glFrontFace(GL_CCW);
469 }
470
471 #define RADIUSFAC    0.70710678118654752440084436210485f
472
473 static void drawSolidCuboctahedron(void)
474 {
475   GLfloat radius = RADIUSFAC*(GLfloat)orad; /* orad doubles as size */
476   glBegin( GL_TRIANGLES );
477     glNormal3d( 0.577350269189, 0.577350269189, 0.577350269189); glVertex3d( radius, radius, 0.0 ); glVertex3d( 0.0, radius, radius ); glVertex3d( radius, 0.0, radius );
478     glNormal3d( 0.577350269189, 0.577350269189,-0.577350269189); glVertex3d( radius, radius, 0.0 ); glVertex3d( radius, 0.0,-radius ); glVertex3d( 0.0, radius,-radius );
479     glNormal3d( 0.577350269189,-0.577350269189, 0.577350269189); glVertex3d( radius,-radius, 0.0 ); glVertex3d( radius, 0.0, radius ); glVertex3d( 0.0,-radius, radius );
480     glNormal3d( 0.577350269189,-0.577350269189,-0.577350269189); glVertex3d( radius,-radius, 0.0 ); glVertex3d( 0.0,-radius,-radius ); glVertex3d( radius, 0.0,-radius );
481     glNormal3d(-0.577350269189, 0.577350269189, 0.577350269189); glVertex3d(-radius, radius, 0.0 ); glVertex3d(-radius, 0.0, radius ); glVertex3d( 0.0, radius, radius );
482     glNormal3d(-0.577350269189, 0.577350269189,-0.577350269189); glVertex3d(-radius, radius, 0.0 ); glVertex3d( 0.0, radius,-radius ); glVertex3d(-radius, 0.0,-radius );
483     glNormal3d(-0.577350269189,-0.577350269189, 0.577350269189); glVertex3d(-radius,-radius, 0.0 ); glVertex3d( 0.0,-radius, radius ); glVertex3d(-radius, 0.0, radius );
484     glNormal3d(-0.577350269189,-0.577350269189,-0.577350269189); glVertex3d(-radius,-radius, 0.0 ); glVertex3d(-radius, 0.0,-radius ); glVertex3d( 0.0,-radius,-radius );
485   glEnd();
486
487   glBegin( GL_QUADS );
488     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 );
489     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 );
490     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 );
491     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 );
492     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 );
493     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 );
494   glEnd();
495 }
496
497 static void drawWireCuboctahedron(void)
498 {
499   GLfloat radius = RADIUSFAC*(GLfloat)orad; /* orad doubles as size */
500   glBegin( GL_LINE_LOOP );
501     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 );
502   glEnd();
503   glBegin( GL_LINE_LOOP );
504     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 );
505   glEnd();
506   glBegin( GL_LINE_LOOP );
507     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 );
508   glEnd();
509   glBegin( GL_LINE_LOOP );
510     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 );
511   glEnd();
512   glBegin( GL_LINE_LOOP );
513     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 );
514   glEnd();
515   glBegin( GL_LINE_LOOP );
516     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 );
517   glEnd();
518 }
519
520 #undef RADIUSFAC
521
522 /*
523  * This structure defines an entry in our function-table.
524  */
525 typedef struct
526 {
527     const char * const name;
528     void (*solid) (void);
529     void (*wire)  (void);
530 } entry;
531
532 #define ENTRY(e) {#e, drawSolid##e, drawWire##e}
533 static const entry table [] =
534 {
535     ENTRY (Tetrahedron),
536     ENTRY (Cube),
537     ENTRY (Octahedron),
538     ENTRY (Dodecahedron),
539     ENTRY (RhombicDodecahedron),
540     ENTRY (Icosahedron),
541     ENTRY (SierpinskiSponge),
542     ENTRY (Teapot),
543     ENTRY (Torus),
544     ENTRY (Sphere),
545     ENTRY (Cone),
546     ENTRY (Cylinder),
547     ENTRY (Cuboctahedron)   /* This one doesn't work when in shader mode and is then skipped */
548 };
549 #undef ENTRY
550
551 /*!
552     Does printf()-like work using freeglut
553     glutBitmapString().  Uses a fixed font.  Prints
554     at the indicated row/column position.
555
556     Limitation: Cannot address pixels.
557     Limitation: Renders in screen coords, not model coords.
558 */
559 static void shapesPrintf (int row, int col, const char *fmt, ...)
560 {
561     static char buf[256];
562     int viewport[4];
563     void *font = GLUT_BITMAP_9_BY_15;
564     va_list args;
565
566     va_start(args, fmt);
567 #if defined(WIN32) && !defined(__CYGWIN__)
568     (void) _vsnprintf (buf, sizeof(buf), fmt, args);
569 #else
570     (void) vsnprintf (buf, sizeof(buf), fmt, args);
571 #endif
572     va_end(args);
573
574     glGetIntegerv(GL_VIEWPORT,viewport);
575
576     glPushMatrix();
577     glLoadIdentity();
578
579     glMatrixMode(GL_PROJECTION);
580     glPushMatrix();
581     glLoadIdentity();
582
583         glOrtho(0,viewport[2],0,viewport[3],-1,1);
584
585         glRasterPos2i
586         (
587               glutBitmapWidth(font, ' ') * col,
588             - glutBitmapHeight(font) * row + viewport[3]
589         );
590         glutBitmapString (font, (unsigned char*)buf);
591
592     glPopMatrix();
593     glMatrixMode(GL_MODELVIEW);
594     glPopMatrix();
595 }
596
597 /* GLUT callback Handlers */
598
599 static void
600 resize(int width, int height)
601 {
602     ar = (float) width / (float) height;
603
604     glViewport(0, 0, width, height);
605 }
606
607 static void display(void)
608 {
609     const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
610     const double a = t*89.0;
611     const double b = (animateXRot?t:1)*67.0;
612
613     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
614
615     glutSetOption(GLUT_GEOMETRY_VISUALIZE_NORMALS,visNormals);  /* Normals visualized or not? */
616
617     if (useShader && !shaderReady)
618         initShader();
619
620     if (useShader && shaderReady)
621     {
622         /* setup use of shader (and vertex buffer by FreeGLUT) */
623         gl_UseProgram (program);
624         glutSetVertexAttribCoord3(attribute_fg_coord);
625         glutSetVertexAttribNormal(attribute_fg_normal);
626
627         gl_matrix_mode(GL_PROJECTION);
628         gl_load_identity();
629         if (persProject)
630             gl_frustum(-ar, ar, -1.f, 1.f, 2.f, 100.f);
631         else
632             gl_ortho(-ar*3, ar*3, -3.f, 3.f, 2.f, 100.f);
633         gl_UniformMatrix4fv (uniform_p, 1, GL_FALSE, get_matrix(GL_PROJECTION));
634
635
636         gl_matrix_mode(GL_MODELVIEW);
637         gl_load_identity();
638
639         gl_push_matrix();
640             /* Not in reverse order like normal OpenGL, our util library multiplies the matrices in the order they are specified in */
641             gl_rotatef((float)a,0,0,1);
642             gl_rotatef((float)b,1,0,0);
643             gl_translatef(0,1.2f,-6);
644             gl_UniformMatrix4fv (uniform_m               , 1, GL_FALSE, get_matrix(GL_MODELVIEW));
645             gl_UniformMatrix3fv (uniform_m_3x3_inv_transp, 1, GL_FALSE, get_inv_transpose_3x3(GL_MODELVIEW));
646             table [function_index].solid ();
647         gl_pop_matrix();
648
649         gl_push_matrix();
650             gl_rotatef((float)a,0,0,1);
651             gl_rotatef((float)b,1,0,0);
652             gl_translatef(0,-1.2f,-6);
653             gl_UniformMatrix4fv (uniform_m               , 1, GL_FALSE, get_matrix(GL_MODELVIEW));
654             gl_UniformMatrix3fv (uniform_m_3x3_inv_transp, 1, GL_FALSE, get_inv_transpose_3x3(GL_MODELVIEW));
655             table [function_index].wire ();
656         gl_pop_matrix();
657
658         gl_UseProgram (0);
659         glutSetVertexAttribCoord3(-1);
660         glutSetVertexAttribNormal(-1);
661
662         checkError ("display");
663     }
664     else
665     {
666         /* fixed function pipeline */
667         glMatrixMode(GL_PROJECTION);
668         glLoadIdentity();
669         if (persProject)
670             glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
671         else
672             glOrtho(-ar*3, ar*3, -3.0, 3.0, 2.0, 100.0);
673         glMatrixMode(GL_MODELVIEW);
674         glLoadIdentity();
675
676         glEnable(GL_LIGHTING);
677
678         glColor3d(1,0,0);
679
680         glPushMatrix();
681             glTranslated(0,1.2,-6);
682             glRotated(b,1,0,0);
683             glRotated(a,0,0,1);
684             table [function_index].solid ();
685         glPopMatrix();
686
687         glPushMatrix();
688             glTranslated(0,-1.2,-6);
689             glRotated(b,1,0,0);
690             glRotated(a,0,0,1);
691             table [function_index].wire ();
692         glPopMatrix();
693
694         glDisable(GL_LIGHTING);
695         glColor3d(0.1,0.1,0.4);
696     }
697
698     if( show_info ) {
699         shapesPrintf (1, 1, "Shape PgUp PgDn: %s", table [function_index].name);
700         shapesPrintf (2, 1, "Slices +-: %d   Stacks <>: %d", slices, stacks);
701         shapesPrintf (3, 1, "nSides +-: %d   nRings <>: %d", slices, stacks);
702         shapesPrintf (4, 1, "Depth  (): %d", depth);
703         shapesPrintf (5, 1, "Outer radius  Up  Down : %f", orad);
704         shapesPrintf (6, 1, "Inner radius Left Right: %f", irad);
705         if (persProject)
706             shapesPrintf (7, 1, "Perspective projection (p)");
707         else
708             shapesPrintf (7, 1, "Orthographic projection (p)");
709         if (useShader)
710             shapesPrintf (8, 1, "Using shader (s)");
711         else
712             shapesPrintf (8, 1, "Using fixed function pipeline (s)");
713         if (animateXRot)
714             shapesPrintf (9, 1, "2D rotation (r)");
715         else
716             shapesPrintf (9, 1, "1D rotation (r)");
717         shapesPrintf (10, 1, "visualizing normals: %i (n)",visNormals);
718     } else {
719         /* print to command line instead */
720         printf ( "Shape %d slides %d stacks %d\n", function_index, slices, stacks ) ;
721     }
722
723     glutSwapBuffers();
724 }
725
726
727 static void
728 key(unsigned char key, int x, int y)
729 {
730     switch (key)
731     {
732     case 27 :
733     case 'Q':
734     case 'q': glutLeaveMainLoop () ;      break;
735
736     case 'I':
737     case 'i': show_info=!show_info;       break;
738
739     case '=':
740     case '+': slices++;                   break;
741
742     case '-':
743     case '_': if( slices > -1 ) slices--; break;
744
745     case ',':
746     case '<': if( stacks > -1 ) stacks--; break;
747
748     case '.':
749     case '>': stacks++;                   break;
750
751     case '9': 
752     case '(': if( depth > -1 ) depth--;   break;
753
754     case '0': 
755     case ')': ++depth;                    break;
756
757     case 'P':
758     case 'p': persProject=!persProject;   break;
759
760     case 'R':
761     case 'r': animateXRot=!animateXRot;   break;
762
763     case 'S':
764     case 's':
765         useShader=!useShader;
766         /* Cuboctahedron can't be shown when in shader mode, move to next */
767         if (useShader && NUMBEROF (table)-1 == ( unsigned )function_index)
768                 function_index = 0;
769         break;
770
771     case 'N':
772     case 'n': visNormals=!visNormals;     break;
773
774     default:
775         break;
776     }
777
778     glutPostRedisplay();
779 }
780
781 static void special (int key, int x, int y)
782 {
783     switch (key)
784     {
785     case GLUT_KEY_PAGE_UP:    ++function_index; break;
786     case GLUT_KEY_PAGE_DOWN:  --function_index; break;
787     case GLUT_KEY_UP:         orad *= 2;        break;
788     case GLUT_KEY_DOWN:       orad /= 2;        break;
789
790     case GLUT_KEY_RIGHT:      irad *= 2;        break;
791     case GLUT_KEY_LEFT:       irad /= 2;        break;
792
793     default:
794         break;
795     }
796
797     if (0 > function_index)
798         function_index = NUMBEROF (table) - 1;
799
800     if (NUMBEROF (table) <= ( unsigned )function_index)
801         function_index = 0;
802
803     /* Cuboctahedron can't be shown when in shader mode, skip it */
804     if (useShader && NUMBEROF (table)-1 == ( unsigned )function_index)
805         if (key==GLUT_KEY_PAGE_UP)
806             function_index = 0;
807         else
808             function_index -= 1;
809 }
810
811
812 static void
813 idle(void)
814 {
815     glutPostRedisplay();
816 }
817
818 const GLfloat light_ambient[]  = { 0.0f, 0.0f, 0.0f, 1.0f };
819 const GLfloat light_diffuse[]  = { 1.0f, 1.0f, 1.0f, 1.0f };
820 const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
821 const GLfloat light_position[] = { 2.0f, 5.0f, 5.0f, 0.0f };
822
823 const GLfloat mat_ambient[]    = { 0.7f, 0.7f, 0.7f, 1.0f };
824 const GLfloat mat_diffuse[]    = { 0.8f, 0.8f, 0.8f, 1.0f };
825 const GLfloat mat_specular[]   = { 1.0f, 1.0f, 1.0f, 1.0f };
826 const GLfloat high_shininess[] = { 100.0f };
827
828 /* Program entry point */
829
830 int
831 main(int argc, char *argv[])
832 {
833     glutInitWindowSize(800,600);
834     glutInitWindowPosition(40,40);
835     glutInit(&argc, argv);
836     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
837
838     glutCreateWindow("FreeGLUT Shapes");
839
840     glutReshapeFunc(resize);
841     glutDisplayFunc(display);
842     glutKeyboardFunc(key);
843     glutSpecialFunc(special);
844     glutIdleFunc(idle);
845
846     glutSetOption ( GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION ) ;
847
848     glClearColor(1,1,1,1);
849     glEnable(GL_CULL_FACE);
850     glCullFace(GL_BACK);
851
852     glEnable(GL_DEPTH_TEST);
853     glDepthFunc(GL_LESS);
854
855     glEnable(GL_LIGHT0);
856     glEnable(GL_NORMALIZE);
857     glEnable(GL_COLOR_MATERIAL);
858
859     glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
860     glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
861     glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
862     glLightfv(GL_LIGHT0, GL_POSITION, light_position);
863
864     glMaterialfv(GL_FRONT, GL_AMBIENT,   mat_ambient);
865     glMaterialfv(GL_FRONT, GL_DIFFUSE,   mat_diffuse);
866     glMaterialfv(GL_FRONT, GL_SPECULAR,  mat_specular);
867     glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
868
869     initExtensionEntries();
870
871     glutMainLoop();
872
873 #ifdef _MSC_VER
874     /* DUMP MEMORY LEAK INFORMATION */
875     _CrtDumpMemoryLeaks () ;
876 #endif
877
878     return EXIT_SUCCESS;
879 }