fixing conflicts with opengl headers on some systems, same solution as
[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
424 /*
425  * These one-liners draw particular objects, fetching appropriate
426  * information from the above globals.  They are just thin wrappers
427  * for the FreeGLUT objects.
428  */
429 static void drawSolidTetrahedron(void)         { glutSolidTetrahedron ();                        }
430 static void drawWireTetrahedron(void)          { glutWireTetrahedron ();                         }
431 static void drawSolidCube(void)                { glutSolidCube(orad);                            }  /* orad doubles as size input */
432 static void drawWireCube(void)                 { glutWireCube(orad);                             }  /* orad doubles as size input */
433 static void drawSolidOctahedron(void)          { glutSolidOctahedron ();                         }
434 static void drawWireOctahedron(void)           { glutWireOctahedron ();                          }
435 static void drawSolidDodecahedron(void)        { glutSolidDodecahedron ();                       }
436 static void drawWireDodecahedron(void)         { glutWireDodecahedron ();                        }
437 static void drawSolidRhombicDodecahedron(void) { glutSolidRhombicDodecahedron ();                }
438 static void drawWireRhombicDodecahedron(void)  { glutWireRhombicDodecahedron ();                 }
439 static void drawSolidIcosahedron(void)         { glutSolidIcosahedron ();                        }
440 static void drawWireIcosahedron(void)          { glutWireIcosahedron ();                         }
441 static void drawSolidSierpinskiSponge(void)    { glutSolidSierpinskiSponge (depth, offset, orad);}  /* orad doubles as size input */
442 static void drawWireSierpinskiSponge(void)     { glutWireSierpinskiSponge (depth, offset, orad); }  /* orad doubles as size input */
443 static void drawSolidTorus(void)               { glutSolidTorus(irad,orad,slices,stacks);        }
444 static void drawWireTorus(void)                { glutWireTorus (irad,orad,slices,stacks);        }
445 static void drawSolidSphere(void)              { glutSolidSphere(orad,slices,stacks);            }  /* orad doubles as size input */
446 static void drawWireSphere(void)               { glutWireSphere(orad,slices,stacks);             }  /* orad doubles as size input */
447 static void drawSolidCone(void)                { glutSolidCone(orad,orad,slices,stacks);         }  /* orad doubles as size input */
448 static void drawWireCone(void)                 { glutWireCone(orad,orad,slices,stacks);          }  /* orad doubles as size input */
449 static void drawSolidCylinder(void)            { glutSolidCylinder(orad,orad,slices,stacks);     }  /* orad doubles as size input */
450 static void drawWireCylinder(void)             { glutWireCylinder(orad,orad,slices,stacks);      }  /* orad doubles as size input */
451 static void drawSolidTeapot(void)
452 {
453     /* per Glut manpage, it should be noted that the teapot is rendered
454      * with clockwise winding for front facing polygons...
455      */
456     glFrontFace(GL_CW);
457     glutSolidTeapot(orad);  /* orad doubles as size input */
458     glFrontFace(GL_CCW);
459 }
460 static void drawWireTeapot(void)
461 {
462     /* per Glut manpage, it should be noted that the teapot is rendered
463      * with clockwise winding for front facing polygons...
464      */
465     glFrontFace(GL_CW);
466     glutWireTeapot(orad);  /* orad doubles as size input */
467     glFrontFace(GL_CCW);
468 }
469
470 #define RADIUS    1.0f
471
472 static void drawSolidCuboctahedron(void)
473 {
474   glBegin( GL_TRIANGLES );
475     glNormal3d( 0.577350269189, 0.577350269189, 0.577350269189); glVertex3d( RADIUS, RADIUS, 0.0 ); glVertex3d( 0.0, RADIUS, RADIUS ); glVertex3d( RADIUS, 0.0, RADIUS );
476     glNormal3d( 0.577350269189, 0.577350269189,-0.577350269189); glVertex3d( RADIUS, RADIUS, 0.0 ); glVertex3d( RADIUS, 0.0,-RADIUS ); glVertex3d( 0.0, RADIUS,-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( 0.0,-RADIUS,-RADIUS ); glVertex3d( RADIUS, 0.0,-RADIUS );
479     glNormal3d(-0.577350269189, 0.577350269189, 0.577350269189); glVertex3d(-RADIUS, RADIUS, 0.0 ); glVertex3d(-RADIUS, 0.0, RADIUS ); glVertex3d( 0.0, RADIUS, RADIUS );
480     glNormal3d(-0.577350269189, 0.577350269189,-0.577350269189); glVertex3d(-RADIUS, RADIUS, 0.0 ); glVertex3d( 0.0, RADIUS,-RADIUS ); glVertex3d(-RADIUS, 0.0,-RADIUS );
481     glNormal3d(-0.577350269189,-0.577350269189, 0.577350269189); glVertex3d(-RADIUS,-RADIUS, 0.0 ); glVertex3d( 0.0,-RADIUS, RADIUS ); glVertex3d(-RADIUS, 0.0, RADIUS );
482     glNormal3d(-0.577350269189,-0.577350269189,-0.577350269189); glVertex3d(-RADIUS,-RADIUS, 0.0 ); glVertex3d(-RADIUS, 0.0,-RADIUS ); glVertex3d( 0.0,-RADIUS,-RADIUS );
483   glEnd();
484
485   glBegin( GL_QUADS );
486     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 );
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( 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 );
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, 0.0, 1.0 ); glVertex3d( RADIUS, 0.0, RADIUS ); glVertex3d( 0.0, RADIUS, RADIUS ); glVertex3d(-RADIUS, 0.0, RADIUS ); 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   glEnd();
493 }
494
495 static void drawWireCuboctahedron(void)
496 {
497   glBegin( GL_LINE_LOOP );
498     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 );
499   glEnd();
500   glBegin( GL_LINE_LOOP );
501     glNormal3d(-1.0, 0.0, 0.0 ); glVertex3d(-RADIUS, RADIUS, 0.0 ); glVertex3d(-RADIUS, 0.0,-RADIUS ); glVertex3d(-RADIUS,-RADIUS, 0.0 ); glVertex3d(-RADIUS, 0.0, RADIUS );
502   glEnd();
503   glBegin( GL_LINE_LOOP );
504     glNormal3d( 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 );
505   glEnd();
506   glBegin( GL_LINE_LOOP );
507     glNormal3d( 0.0,-1.0, 0.0 ); glVertex3d( RADIUS,-RADIUS, 0.0 ); glVertex3d( 0.0,-RADIUS, RADIUS ); glVertex3d(-RADIUS,-RADIUS, 0.0 ); glVertex3d( 0.0,-RADIUS,-RADIUS );
508   glEnd();
509   glBegin( GL_LINE_LOOP );
510     glNormal3d( 0.0, 0.0, 1.0 ); glVertex3d( RADIUS, 0.0, RADIUS ); glVertex3d( 0.0, RADIUS, RADIUS ); glVertex3d(-RADIUS, 0.0, RADIUS ); glVertex3d( 0.0,-RADIUS, RADIUS );
511   glEnd();
512   glBegin( GL_LINE_LOOP );
513     glNormal3d( 0.0, 0.0,-1.0 ); glVertex3d( RADIUS, 0.0,-RADIUS ); glVertex3d( 0.0,-RADIUS,-RADIUS ); glVertex3d(-RADIUS, 0.0,-RADIUS ); glVertex3d( 0.0, RADIUS,-RADIUS );
514   glEnd();
515 }
516
517 #undef RADIUS
518
519 /*
520  * This structure defines an entry in our function-table.
521  */
522 typedef struct
523 {
524     const char * const name;
525     void (*solid) (void);
526     void (*wire)  (void);
527 } entry;
528
529 #define ENTRY(e) {#e, drawSolid##e, drawWire##e}
530 static const entry table [] =
531 {
532     ENTRY (Tetrahedron),
533     ENTRY (Cube),
534     ENTRY (Octahedron),
535     ENTRY (Dodecahedron),
536     ENTRY (RhombicDodecahedron),
537     ENTRY (Icosahedron),
538     ENTRY (SierpinskiSponge),
539     ENTRY (Teapot),
540     ENTRY (Torus),
541     ENTRY (Sphere),
542     ENTRY (Cone),
543     ENTRY (Cylinder),
544     ENTRY (Cuboctahedron)
545 };
546 #undef ENTRY
547
548 /*!
549     Does printf()-like work using freeglut
550     glutBitmapString().  Uses a fixed font.  Prints
551     at the indicated row/column position.
552
553     Limitation: Cannot address pixels.
554     Limitation: Renders in screen coords, not model coords.
555 */
556 static void shapesPrintf (int row, int col, const char *fmt, ...)
557 {
558     static char buf[256];
559     int viewport[4];
560     void *font = GLUT_BITMAP_9_BY_15;
561     va_list args;
562
563     va_start(args, fmt);
564 #if defined(WIN32) && !defined(__CYGWIN__)
565     (void) _vsnprintf (buf, sizeof(buf), fmt, args);
566 #else
567     (void) vsnprintf (buf, sizeof(buf), fmt, args);
568 #endif
569     va_end(args);
570
571     glGetIntegerv(GL_VIEWPORT,viewport);
572
573     glPushMatrix();
574     glLoadIdentity();
575
576     glMatrixMode(GL_PROJECTION);
577     glPushMatrix();
578     glLoadIdentity();
579
580         glOrtho(0,viewport[2],0,viewport[3],-1,1);
581
582         glRasterPos2i
583         (
584               glutBitmapWidth(font, ' ') * col,
585             - glutBitmapHeight(font) * row + viewport[3]
586         );
587         glutBitmapString (font, (unsigned char*)buf);
588
589     glPopMatrix();
590     glMatrixMode(GL_MODELVIEW);
591     glPopMatrix();
592 }
593
594 /* GLUT callback Handlers */
595
596 static void
597 resize(int width, int height)
598 {
599     ar = (float) width / (float) height;
600
601     glViewport(0, 0, width, height);
602 }
603
604 static void display(void)
605 {
606     const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
607     const double a = t*90.0;
608     const double b = (animateXRot?t:1)*60.0;
609
610     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
611
612     if (useShader && !shaderReady)
613         initShader();
614
615     if (useShader && shaderReady)
616     {
617         /* setup use of shader (and vertex buffer by FreeGLUT) */
618         gl_UseProgram (program);
619         glutSetVertexAttribCoord3(attribute_fg_coord);
620         glutSetVertexAttribNormal(attribute_fg_normal);
621
622         gl_matrix_mode(GL_PROJECTION);
623         gl_load_identity();
624         if (persProject)
625             gl_frustum(-ar, ar, -1.f, 1.f, 2.f, 100.f);
626         else
627             gl_ortho(-ar*3, ar*3, -3.f, 3.f, 2.f, 100.f);
628         gl_UniformMatrix4fv (uniform_p, 1, GL_FALSE, get_matrix(GL_PROJECTION));
629
630
631         gl_matrix_mode(GL_MODELVIEW);
632         gl_load_identity();
633
634         gl_push_matrix();
635             /* Not in reverse order like normal OpenGL, our util library multiplies the matrices in the order they are specified in */
636             gl_rotatef((float)a,0,0,1);
637             gl_rotatef((float)b,1,0,0);
638             gl_translatef(0,1.2f,-6);
639             gl_UniformMatrix4fv (uniform_m               , 1, GL_FALSE, get_matrix(GL_MODELVIEW));
640             gl_UniformMatrix3fv (uniform_m_3x3_inv_transp, 1, GL_FALSE, get_inv_transpose_3x3(GL_MODELVIEW));
641             table [function_index].solid ();
642         gl_pop_matrix();
643
644         gl_push_matrix();
645             gl_rotatef((float)a,0,0,1);
646             gl_rotatef((float)b,1,0,0);
647             gl_translatef(0,-1.2f,-6);
648             gl_UniformMatrix4fv (uniform_m               , 1, GL_FALSE, get_matrix(GL_MODELVIEW));
649             gl_UniformMatrix3fv (uniform_m_3x3_inv_transp, 1, GL_FALSE, get_inv_transpose_3x3(GL_MODELVIEW));
650             table [function_index].wire ();
651         gl_pop_matrix();
652
653         gl_UseProgram (0);
654         glutSetVertexAttribCoord3(-1);
655         glutSetVertexAttribNormal(-1);
656
657         checkError ("display");
658     }
659     else
660     {
661         /* fixed function pipeline */
662         glMatrixMode(GL_PROJECTION);
663         glLoadIdentity();
664         if (persProject)
665             glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
666         else
667             glOrtho(-ar*3, ar*3, -3.0, 3.0, 2.0, 100.0);
668         glMatrixMode(GL_MODELVIEW);
669         glLoadIdentity();
670
671         glEnable(GL_LIGHTING);
672
673         glColor3d(1,0,0);
674
675         glPushMatrix();
676             glTranslated(0,1.2,-6);
677             glRotated(b,1,0,0);
678             glRotated(a,0,0,1);
679             table [function_index].solid ();
680         glPopMatrix();
681
682         glPushMatrix();
683             glTranslated(0,-1.2,-6);
684             glRotated(b,1,0,0);
685             glRotated(a,0,0,1);
686             table [function_index].wire ();
687         glPopMatrix();
688
689         glDisable(GL_LIGHTING);
690         glColor3d(0.1,0.1,0.4);
691     }
692
693     if( show_info ) {
694         shapesPrintf (1, 1, "Shape PgUp PgDn: %s", table [function_index].name);
695         shapesPrintf (2, 1, "Slices +-: %d   Stacks <>: %d", slices, stacks);
696         shapesPrintf (3, 1, "nSides +-: %d   nRings <>: %d", slices, stacks);
697         shapesPrintf (4, 1, "Depth  (): %d", depth);
698         shapesPrintf (5, 1, "Outer radius  Up  Down : %f", orad);
699         shapesPrintf (6, 1, "Inner radius Left Right: %f", irad);
700         if (persProject)
701             shapesPrintf (7, 1, "Perspective projection");
702         else
703             shapesPrintf (7, 1, "Orthographic projection");
704         if (useShader)
705             shapesPrintf (8, 1, "Using shader");
706         else
707             shapesPrintf (8, 1, "Using fixed function pipeline");
708     } else {
709         printf ( "Shape %d slides %d stacks %d\n", function_index, slices, stacks ) ;
710     }
711
712     glutSwapBuffers();
713 }
714
715
716 static void
717 key(unsigned char key, int x, int y)
718 {
719     switch (key)
720     {
721     case 27 :
722     case 'Q':
723     case 'q': glutLeaveMainLoop () ;      break;
724
725     case 'I':
726     case 'i': show_info=!show_info;       break;
727
728     case '=':
729     case '+': slices++;                   break;
730
731     case '-':
732     case '_': if( slices > -1 ) slices--; break;
733
734     case ',':
735     case '<': if( stacks > -1 ) stacks--; break;
736
737     case '.':
738     case '>': stacks++;                   break;
739
740     case '9': 
741     case '(': if( depth > -1 ) depth--;   break;
742
743     case '0': 
744     case ')': ++depth;                    break;
745
746     case 'P':
747     case 'p': persProject=!persProject;   break;
748
749     case 'R':
750     case 'r': animateXRot=!animateXRot;   break;
751
752     case 'S':
753     case 's': useShader=!useShader;       break;
754
755     default:
756         break;
757     }
758
759     glutPostRedisplay();
760 }
761
762 static void special (int key, int x, int y)
763 {
764     switch (key)
765     {
766     case GLUT_KEY_PAGE_UP:    ++function_index; break;
767     case GLUT_KEY_PAGE_DOWN:  --function_index; break;
768     case GLUT_KEY_UP:         orad *= 2;        break;
769     case GLUT_KEY_DOWN:       orad /= 2;        break;
770
771     case GLUT_KEY_RIGHT:      irad *= 2;        break;
772     case GLUT_KEY_LEFT:       irad /= 2;        break;
773
774     default:
775         break;
776     }
777
778     if (0 > function_index)
779         function_index = NUMBEROF (table) - 1;
780
781     if (NUMBEROF (table) <= ( unsigned )function_index)
782         function_index = 0;
783 }
784
785
786 static void
787 idle(void)
788 {
789     glutPostRedisplay();
790 }
791
792 const GLfloat light_ambient[]  = { 0.0f, 0.0f, 0.0f, 1.0f };
793 const GLfloat light_diffuse[]  = { 1.0f, 1.0f, 1.0f, 1.0f };
794 const GLfloat light_specular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
795 const GLfloat light_position[] = { 2.0f, 5.0f, 5.0f, 0.0f };
796
797 const GLfloat mat_ambient[]    = { 0.7f, 0.7f, 0.7f, 1.0f };
798 const GLfloat mat_diffuse[]    = { 0.8f, 0.8f, 0.8f, 1.0f };
799 const GLfloat mat_specular[]   = { 1.0f, 1.0f, 1.0f, 1.0f };
800 const GLfloat high_shininess[] = { 100.0f };
801
802 /* Program entry point */
803
804 int
805 main(int argc, char *argv[])
806 {
807     glutInitWindowSize(640,480);
808     glutInitWindowPosition(40,40);
809     glutInit(&argc, argv);
810     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
811
812     glutCreateWindow("FreeGLUT Shapes");
813
814     glutReshapeFunc(resize);
815     glutDisplayFunc(display);
816     glutKeyboardFunc(key);
817     glutSpecialFunc(special);
818     glutIdleFunc(idle);
819
820     glutSetOption ( GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION ) ;
821
822     glClearColor(1,1,1,1);
823     glEnable(GL_CULL_FACE);
824     glCullFace(GL_BACK);
825
826     glEnable(GL_DEPTH_TEST);
827     glDepthFunc(GL_LESS);
828
829     glEnable(GL_LIGHT0);
830     glEnable(GL_NORMALIZE);
831     glEnable(GL_COLOR_MATERIAL);
832
833     glLightfv(GL_LIGHT0, GL_AMBIENT,  light_ambient);
834     glLightfv(GL_LIGHT0, GL_DIFFUSE,  light_diffuse);
835     glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
836     glLightfv(GL_LIGHT0, GL_POSITION, light_position);
837
838     glMaterialfv(GL_FRONT, GL_AMBIENT,   mat_ambient);
839     glMaterialfv(GL_FRONT, GL_DIFFUSE,   mat_diffuse);
840     glMaterialfv(GL_FRONT, GL_SPECULAR,  mat_specular);
841     glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
842
843     initExtensionEntries();
844
845     glutMainLoop();
846
847 #ifdef _MSC_VER
848     /* DUMP MEMORY LEAK INFORMATION */
849     _CrtDumpMemoryLeaks () ;
850 #endif
851
852     return EXIT_SUCCESS;
853 }