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