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