shapes demo: cuboctahedron is from the demo itself and not from FreeGLUT
[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 RADIUS    1.0f
472
473 static void drawSolidCuboctahedron(void)
474 {
475   glBegin( GL_TRIANGLES );
476     glNormal3d( 0.577350269189, 0.577350269189, 0.577350269189); glVertex3d( RADIUS, RADIUS, 0.0 ); glVertex3d( 0.0, RADIUS, RADIUS ); glVertex3d( RADIUS, 0.0, RADIUS );
477     glNormal3d( 0.577350269189, 0.577350269189,-0.577350269189); glVertex3d( RADIUS, RADIUS, 0.0 ); glVertex3d( RADIUS, 0.0,-RADIUS ); glVertex3d( 0.0, RADIUS,-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( 0.0,-RADIUS,-RADIUS ); glVertex3d( RADIUS, 0.0,-RADIUS );
480     glNormal3d(-0.577350269189, 0.577350269189, 0.577350269189); glVertex3d(-RADIUS, RADIUS, 0.0 ); glVertex3d(-RADIUS, 0.0, RADIUS ); glVertex3d( 0.0, RADIUS, RADIUS );
481     glNormal3d(-0.577350269189, 0.577350269189,-0.577350269189); glVertex3d(-RADIUS, RADIUS, 0.0 ); glVertex3d( 0.0, RADIUS,-RADIUS ); glVertex3d(-RADIUS, 0.0,-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(-RADIUS, 0.0,-RADIUS ); glVertex3d( 0.0,-RADIUS,-RADIUS );
484   glEnd();
485
486   glBegin( GL_QUADS );
487     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 );
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( 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 );
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, 0.0, 1.0 ); glVertex3d( RADIUS, 0.0, RADIUS ); glVertex3d( 0.0, RADIUS, RADIUS ); glVertex3d(-RADIUS, 0.0, RADIUS ); 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   glEnd();
494 }
495
496 static void drawWireCuboctahedron(void)
497 {
498   glBegin( GL_LINE_LOOP );
499     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 );
500   glEnd();
501   glBegin( GL_LINE_LOOP );
502     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 );
503   glEnd();
504   glBegin( GL_LINE_LOOP );
505     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 );
506   glEnd();
507   glBegin( GL_LINE_LOOP );
508     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 );
509   glEnd();
510   glBegin( GL_LINE_LOOP );
511     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 );
512   glEnd();
513   glBegin( GL_LINE_LOOP );
514     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 );
515   glEnd();
516 }
517
518 #undef RADIUS
519
520 /*
521  * This structure defines an entry in our function-table.
522  */
523 typedef struct
524 {
525     const char * const name;
526     void (*solid) (void);
527     void (*wire)  (void);
528 } entry;
529
530 #define ENTRY(e) {#e, drawSolid##e, drawWire##e}
531 static const entry table [] =
532 {
533     ENTRY (Tetrahedron),
534     ENTRY (Cube),
535     ENTRY (Octahedron),
536     ENTRY (Dodecahedron),
537     ENTRY (RhombicDodecahedron),
538     ENTRY (Icosahedron),
539     ENTRY (SierpinskiSponge),
540     ENTRY (Teapot),
541     ENTRY (Torus),
542     ENTRY (Sphere),
543     ENTRY (Cone),
544     ENTRY (Cylinder),
545     ENTRY (Cuboctahedron)   /* This one doesn't work when in shader mode and is then skipped */
546 };
547 #undef ENTRY
548
549 /*!
550     Does printf()-like work using freeglut
551     glutBitmapString().  Uses a fixed font.  Prints
552     at the indicated row/column position.
553
554     Limitation: Cannot address pixels.
555     Limitation: Renders in screen coords, not model coords.
556 */
557 static void shapesPrintf (int row, int col, const char *fmt, ...)
558 {
559     static char buf[256];
560     int viewport[4];
561     void *font = GLUT_BITMAP_9_BY_15;
562     va_list args;
563
564     va_start(args, fmt);
565 #if defined(WIN32) && !defined(__CYGWIN__)
566     (void) _vsnprintf (buf, sizeof(buf), fmt, args);
567 #else
568     (void) vsnprintf (buf, sizeof(buf), fmt, args);
569 #endif
570     va_end(args);
571
572     glGetIntegerv(GL_VIEWPORT,viewport);
573
574     glPushMatrix();
575     glLoadIdentity();
576
577     glMatrixMode(GL_PROJECTION);
578     glPushMatrix();
579     glLoadIdentity();
580
581         glOrtho(0,viewport[2],0,viewport[3],-1,1);
582
583         glRasterPos2i
584         (
585               glutBitmapWidth(font, ' ') * col,
586             - glutBitmapHeight(font) * row + viewport[3]
587         );
588         glutBitmapString (font, (unsigned char*)buf);
589
590     glPopMatrix();
591     glMatrixMode(GL_MODELVIEW);
592     glPopMatrix();
593 }
594
595 /* GLUT callback Handlers */
596
597 static void
598 resize(int width, int height)
599 {
600     ar = (float) width / (float) height;
601
602     glViewport(0, 0, width, height);
603 }
604
605 static void display(void)
606 {
607     const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
608     const double a = t*89.0;
609     const double b = (animateXRot?t:1)*67.0;
610
611     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
612
613     if (useShader && !shaderReady)
614         initShader();
615
616     if (useShader && shaderReady)
617     {
618         /* setup use of shader (and vertex buffer by FreeGLUT) */
619         gl_UseProgram (program);
620         glutSetVertexAttribCoord3(attribute_fg_coord);
621         glutSetVertexAttribNormal(attribute_fg_normal);
622
623         gl_matrix_mode(GL_PROJECTION);
624         gl_load_identity();
625         if (persProject)
626             gl_frustum(-ar, ar, -1.f, 1.f, 2.f, 100.f);
627         else
628             gl_ortho(-ar*3, ar*3, -3.f, 3.f, 2.f, 100.f);
629         gl_UniformMatrix4fv (uniform_p, 1, GL_FALSE, get_matrix(GL_PROJECTION));
630
631
632         gl_matrix_mode(GL_MODELVIEW);
633         gl_load_identity();
634
635         gl_push_matrix();
636             /* Not in reverse order like normal OpenGL, our util library multiplies the matrices in the order they are specified in */
637             gl_rotatef((float)a,0,0,1);
638             gl_rotatef((float)b,1,0,0);
639             gl_translatef(0,1.2f,-6);
640             gl_UniformMatrix4fv (uniform_m               , 1, GL_FALSE, get_matrix(GL_MODELVIEW));
641             gl_UniformMatrix3fv (uniform_m_3x3_inv_transp, 1, GL_FALSE, get_inv_transpose_3x3(GL_MODELVIEW));
642             table [function_index].solid ();
643         gl_pop_matrix();
644
645         gl_push_matrix();
646             gl_rotatef((float)a,0,0,1);
647             gl_rotatef((float)b,1,0,0);
648             gl_translatef(0,-1.2f,-6);
649             gl_UniformMatrix4fv (uniform_m               , 1, GL_FALSE, get_matrix(GL_MODELVIEW));
650             gl_UniformMatrix3fv (uniform_m_3x3_inv_transp, 1, GL_FALSE, get_inv_transpose_3x3(GL_MODELVIEW));
651             table [function_index].wire ();
652         gl_pop_matrix();
653
654         gl_UseProgram (0);
655         glutSetVertexAttribCoord3(-1);
656         glutSetVertexAttribNormal(-1);
657
658         checkError ("display");
659     }
660     else
661     {
662         /* fixed function pipeline */
663         glutSetOption(GLUT_OBJECTS_VISUALIZE_NORMALS,visNormals);   /* Normals visualized or not? */
664         glMatrixMode(GL_PROJECTION);
665         glLoadIdentity();
666         if (persProject)
667             glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
668         else
669             glOrtho(-ar*3, ar*3, -3.0, 3.0, 2.0, 100.0);
670         glMatrixMode(GL_MODELVIEW);
671         glLoadIdentity();
672
673         glEnable(GL_LIGHTING);
674
675         glColor3d(1,0,0);
676
677         glPushMatrix();
678             glTranslated(0,1.2,-6);
679             glRotated(b,1,0,0);
680             glRotated(a,0,0,1);
681             table [function_index].solid ();
682         glPopMatrix();
683
684         glPushMatrix();
685             glTranslated(0,-1.2,-6);
686             glRotated(b,1,0,0);
687             glRotated(a,0,0,1);
688             table [function_index].wire ();
689         glPopMatrix();
690
691         glDisable(GL_LIGHTING);
692         glColor3d(0.1,0.1,0.4);
693     }
694
695     if( show_info ) {
696         shapesPrintf (1, 1, "Shape PgUp PgDn: %s", table [function_index].name);
697         shapesPrintf (2, 1, "Slices +-: %d   Stacks <>: %d", slices, stacks);
698         shapesPrintf (3, 1, "nSides +-: %d   nRings <>: %d", slices, stacks);
699         shapesPrintf (4, 1, "Depth  (): %d", depth);
700         shapesPrintf (5, 1, "Outer radius  Up  Down : %f", orad);
701         shapesPrintf (6, 1, "Inner radius Left Right: %f", irad);
702         if (persProject)
703             shapesPrintf (7, 1, "Perspective projection (p)");
704         else
705             shapesPrintf (7, 1, "Orthographic projection (p)");
706         if (useShader)
707             shapesPrintf (8, 1, "Using shader (s)");
708         else
709             shapesPrintf (8, 1, "Using fixed function pipeline (s)");
710         if (animateXRot)
711             shapesPrintf (9, 1, "2D rotation (r)");
712         else
713             shapesPrintf (9, 1, "1D rotation (r)");
714         if (!useShader)
715             shapesPrintf (10, 1, "visualizing normals: %i (n)",visNormals);
716     } else {
717         /* print to command line instead */
718         printf ( "Shape %d slides %d stacks %d\n", function_index, slices, stacks ) ;
719     }
720
721     glutSwapBuffers();
722 }
723
724
725 static void
726 key(unsigned char key, int x, int y)
727 {
728     switch (key)
729     {
730     case 27 :
731     case 'Q':
732     case 'q': glutLeaveMainLoop () ;      break;
733
734     case 'I':
735     case 'i': show_info=!show_info;       break;
736
737     case '=':
738     case '+': slices++;                   break;
739
740     case '-':
741     case '_': if( slices > -1 ) slices--; break;
742
743     case ',':
744     case '<': if( stacks > -1 ) stacks--; break;
745
746     case '.':
747     case '>': stacks++;                   break;
748
749     case '9': 
750     case '(': if( depth > -1 ) depth--;   break;
751
752     case '0': 
753     case ')': ++depth;                    break;
754
755     case 'P':
756     case 'p': persProject=!persProject;   break;
757
758     case 'R':
759     case 'r': animateXRot=!animateXRot;   break;
760
761     case 'S':
762     case 's':
763         useShader=!useShader;
764         /* Cuboctahedron can't be shown when in shader mode, move to next */
765         if (useShader && NUMBEROF (table)-1 == ( unsigned )function_index)
766                 function_index = 0;
767         break;
768
769     case 'N':
770     case 'n': visNormals=!visNormals;     break;
771
772     default:
773         break;
774     }
775
776     glutPostRedisplay();
777 }
778
779 static void special (int key, int x, int y)
780 {
781     switch (key)
782     {
783     case GLUT_KEY_PAGE_UP:    ++function_index; break;
784     case GLUT_KEY_PAGE_DOWN:  --function_index; break;
785     case GLUT_KEY_UP:         orad *= 2;        break;
786     case GLUT_KEY_DOWN:       orad /= 2;        break;
787
788     case GLUT_KEY_RIGHT:      irad *= 2;        break;
789     case GLUT_KEY_LEFT:       irad /= 2;        break;
790
791     default:
792         break;
793     }
794
795     if (0 > function_index)
796         function_index = NUMBEROF (table) - 1;
797
798     if (NUMBEROF (table) <= ( unsigned )function_index)
799         function_index = 0;
800
801     /* Cuboctahedron can't be shown when in shader mode, skip it */
802     if (useShader && NUMBEROF (table)-1 == ( unsigned )function_index)
803         if (key==GLUT_KEY_PAGE_UP)
804             function_index = 0;
805         else
806             function_index -= 1;
807 }
808
809
810 static void
811 idle(void)
812 {
813     glutPostRedisplay();
814 }
815
816 const GLfloat light_ambient[]  = { 0.0f, 0.0f, 0.0f, 1.0f };
817 const GLfloat light_diffuse[]  = { 1.0f, 1.0f, 1.0f, 1.0f };
818 const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
819 const GLfloat light_position[] = { 2.0f, 5.0f, 5.0f, 0.0f };
820
821 const GLfloat mat_ambient[]    = { 0.7f, 0.7f, 0.7f, 1.0f };
822 const GLfloat mat_diffuse[]    = { 0.8f, 0.8f, 0.8f, 1.0f };
823 const GLfloat mat_specular[]   = { 1.0f, 1.0f, 1.0f, 1.0f };
824 const GLfloat high_shininess[] = { 100.0f };
825
826 /* Program entry point */
827
828 int
829 main(int argc, char *argv[])
830 {
831     glutInitWindowSize(800,600);
832     glutInitWindowPosition(40,40);
833     glutInit(&argc, argv);
834     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
835
836     glutCreateWindow("FreeGLUT Shapes");
837
838     glutReshapeFunc(resize);
839     glutDisplayFunc(display);
840     glutKeyboardFunc(key);
841     glutSpecialFunc(special);
842     glutIdleFunc(idle);
843
844     glutSetOption ( GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION ) ;
845
846     glClearColor(1,1,1,1);
847     glEnable(GL_CULL_FACE);
848     glCullFace(GL_BACK);
849
850     glEnable(GL_DEPTH_TEST);
851     glDepthFunc(GL_LESS);
852
853     glEnable(GL_LIGHT0);
854     glEnable(GL_NORMALIZE);
855     glEnable(GL_COLOR_MATERIAL);
856
857     glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
858     glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
859     glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
860     glLightfv(GL_LIGHT0, GL_POSITION, light_position);
861
862     glMaterialfv(GL_FRONT, GL_AMBIENT,   mat_ambient);
863     glMaterialfv(GL_FRONT, GL_DIFFUSE,   mat_diffuse);
864     glMaterialfv(GL_FRONT, GL_SPECULAR,  mat_specular);
865     glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
866
867     initExtensionEntries();
868
869     glutMainLoop();
870
871 #ifdef _MSC_VER
872     /* DUMP MEMORY LEAK INFORMATION */
873     _CrtDumpMemoryLeaks () ;
874 #endif
875
876     return EXIT_SUCCESS;
877 }