cleaning up mixed tabs and spaces
[freeglut] / progs / demos / shapes / shapes.c
index bf7664a..69c0a1a 100644 (file)
@@ -5,14 +5,18 @@
     in OpenGLUT.  It may also be useful to see which
     parameters control what behavior in the OpenGLUT
     objects.
     in OpenGLUT.  It may also be useful to see which
     parameters control what behavior in the OpenGLUT
     objects.
+
     Spinning wireframe and solid-shaded shapes are
     displayed.  Some parameters can be adjusted.
     Spinning wireframe and solid-shaded shapes are
     displayed.  Some parameters can be adjusted.
+
    Keys:
       -    <tt>Esc &nbsp;</tt> Quit
       -    <tt>q Q &nbsp;</tt> Quit
       -    <tt>i I &nbsp;</tt> Show info
    Keys:
       -    <tt>Esc &nbsp;</tt> Quit
       -    <tt>q Q &nbsp;</tt> Quit
       -    <tt>i I &nbsp;</tt> Show info
+      -    <tt>p P &nbsp;</tt> Toggle perspective or orthographic projection
+      -    <tt>r R &nbsp;</tt> Toggle fixed or animated rotation around model X-axis
+      -    <tt>s S &nbsp;</tt> Toggle toggle fixed function or shader render path
+      -    <tt>n N &nbsp;</tt> Toggle visualization of object's normal vectors
       -    <tt>= + &nbsp;</tt> Increase \a slices
       -    <tt>- _ &nbsp;</tt> Decreate \a slices
       -    <tt>, < &nbsp;</tt> Decreate \a stacks
       -    <tt>= + &nbsp;</tt> Increase \a slices
       -    <tt>- _ &nbsp;</tt> Decreate \a slices
       -    <tt>, < &nbsp;</tt> Decreate \a stacks
@@ -30,7 +34,7 @@
 
     \author  Portions Copyright (C) 2004, the OpenGLUT project contributors. <br>
              OpenGLUT branched from freeglut in February, 2004.
 
     \author  Portions Copyright (C) 2004, the OpenGLUT project contributors. <br>
              OpenGLUT branched from freeglut in February, 2004.
+
     \image   html openglut_shapes.png OpenGLUT Geometric Shapes Demonstration
     \include demos/shapes/shapes.c
 */
     \image   html openglut_shapes.png OpenGLUT Geometric Shapes Demonstration
     \include demos/shapes/shapes.c
 */
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stddef.h>
 
 
-#ifdef WIN32
+#include "glmatrix.h"
+
+#ifdef _MSC_VER
 /* DUMP MEMORY LEAKS */
 #include <crtdbg.h>
 #endif
 
 /* DUMP MEMORY LEAKS */
 #include <crtdbg.h>
 #endif
 
+/* report GL errors, if any, to stderr */
+void checkError(const char *functionName)
+{
+    GLenum error;
+    while (( error = glGetError() ) != GL_NO_ERROR) {
+        fprintf (stderr, "GL error 0x%X detected in %s\n", error, functionName);
+    }
+}
+
+/*
+ * OpenGL 2+ shader mode needs some function and macro definitions,
+ * avoiding a dependency on additional libraries like GLEW or the
+ * GL/glext.h header
+ */
+#ifndef GL_FRAGMENT_SHADER
+#define GL_FRAGMENT_SHADER 0x8B30
+#endif
+
+#ifndef GL_VERTEX_SHADER
+#define GL_VERTEX_SHADER 0x8B31
+#endif
+
+#ifndef GL_COMPILE_STATUS
+#define GL_COMPILE_STATUS 0x8B81
+#endif
+
+#ifndef GL_LINK_STATUS
+#define GL_LINK_STATUS 0x8B82
+#endif
+
+#ifndef GL_INFO_LOG_LENGTH
+#define GL_INFO_LOG_LENGTH 0x8B84
+#endif
+
+typedef ptrdiff_t ourGLsizeiptr;
+typedef char ourGLchar;
+
+#ifndef APIENTRY
+#define APIENTRY
+#endif
+
+#ifndef GL_VERSION_2_0
+typedef GLuint (APIENTRY *PFNGLCREATESHADERPROC) (GLenum type);
+typedef void (APIENTRY *PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const ourGLchar **string, const GLint *length);
+typedef void (APIENTRY *PFNGLCOMPILESHADERPROC) (GLuint shader);
+typedef GLuint (APIENTRY *PFNGLCREATEPROGRAMPROC) (void);
+typedef void (APIENTRY *PFNGLATTACHSHADERPROC) (GLuint program, GLuint shader);
+typedef void (APIENTRY *PFNGLLINKPROGRAMPROC) (GLuint program);
+typedef void (APIENTRY *PFNGLUSEPROGRAMPROC) (GLuint program);
+typedef void (APIENTRY *PFNGLGETSHADERIVPROC) (GLuint shader, GLenum pname, GLint *params);
+typedef void (APIENTRY *PFNGLGETSHADERINFOLOGPROC) (GLuint shader, GLsizei bufSize, GLsizei *length, ourGLchar *infoLog);
+typedef void (APIENTRY *PFNGLGETPROGRAMIVPROC) (GLenum target, GLenum pname, GLint *params);
+typedef void (APIENTRY *PFNGLGETPROGRAMINFOLOGPROC) (GLuint program, GLsizei bufSize, GLsizei *length, ourGLchar *infoLog);
+typedef GLint (APIENTRY *PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const ourGLchar *name);
+typedef GLint (APIENTRY *PFNGLGETUNIFORMLOCATIONPROC) (GLuint program, const ourGLchar *name);
+typedef void (APIENTRY *PFNGLUNIFORMMATRIX4FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+typedef void (APIENTRY *PFNGLUNIFORMMATRIX3FVPROC) (GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+#endif
+
+PFNGLCREATESHADERPROC gl_CreateShader;
+PFNGLSHADERSOURCEPROC gl_ShaderSource;
+PFNGLCOMPILESHADERPROC gl_CompileShader;
+PFNGLCREATEPROGRAMPROC gl_CreateProgram;
+PFNGLATTACHSHADERPROC gl_AttachShader;
+PFNGLLINKPROGRAMPROC gl_LinkProgram;
+PFNGLUSEPROGRAMPROC gl_UseProgram;
+PFNGLGETSHADERIVPROC gl_GetShaderiv;
+PFNGLGETSHADERINFOLOGPROC gl_GetShaderInfoLog;
+PFNGLGETPROGRAMIVPROC gl_GetProgramiv;
+PFNGLGETPROGRAMINFOLOGPROC gl_GetProgramInfoLog;
+PFNGLGETATTRIBLOCATIONPROC gl_GetAttribLocation;
+PFNGLGETUNIFORMLOCATIONPROC gl_GetUniformLocation;
+PFNGLUNIFORMMATRIX4FVPROC gl_UniformMatrix4fv;
+PFNGLUNIFORMMATRIX3FVPROC gl_UniformMatrix3fv;
+
+void initExtensionEntries(void)
+{
+    gl_CreateShader = (PFNGLCREATESHADERPROC) glutGetProcAddress ("glCreateShader");
+    gl_ShaderSource = (PFNGLSHADERSOURCEPROC) glutGetProcAddress ("glShaderSource");
+    gl_CompileShader = (PFNGLCOMPILESHADERPROC) glutGetProcAddress ("glCompileShader");
+    gl_CreateProgram = (PFNGLCREATEPROGRAMPROC) glutGetProcAddress ("glCreateProgram");
+    gl_AttachShader = (PFNGLATTACHSHADERPROC) glutGetProcAddress ("glAttachShader");
+    gl_LinkProgram = (PFNGLLINKPROGRAMPROC) glutGetProcAddress ("glLinkProgram");
+    gl_UseProgram = (PFNGLUSEPROGRAMPROC) glutGetProcAddress ("glUseProgram");
+    gl_GetShaderiv = (PFNGLGETSHADERIVPROC) glutGetProcAddress ("glGetShaderiv");
+    gl_GetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) glutGetProcAddress ("glGetShaderInfoLog");
+    gl_GetProgramiv = (PFNGLGETPROGRAMIVPROC) glutGetProcAddress ("glGetProgramiv");
+    gl_GetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) glutGetProcAddress ("glGetProgramInfoLog");
+    gl_GetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) glutGetProcAddress ("glGetAttribLocation");
+    gl_GetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) glutGetProcAddress ("glGetUniformLocation");
+    gl_UniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) glutGetProcAddress ("glUniformMatrix4fv");
+    gl_UniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) glutGetProcAddress ("glUniformMatrix3fv");
+    if (!gl_CreateShader || !gl_ShaderSource || !gl_CompileShader || !gl_CreateProgram || !gl_AttachShader || !gl_LinkProgram || !gl_UseProgram || !gl_GetShaderiv || !gl_GetShaderInfoLog || !gl_GetProgramiv || !gl_GetProgramInfoLog || !gl_GetAttribLocation || !gl_GetUniformLocation || !gl_UniformMatrix4fv || !gl_UniformMatrix3fv)
+    {
+        fprintf (stderr, "glCreateShader, glShaderSource, glCompileShader, glCreateProgram, glAttachShader, glLinkProgram, glUseProgram, glGetShaderiv, glGetShaderInfoLog, glGetProgramiv, glGetProgramInfoLog, glGetAttribLocation, glGetUniformLocation, glUniformMatrix4fv or gl_UniformMatrix3fv not found");
+        exit(1);
+    }
+}
+
+const ourGLchar *vertexShaderSource[] = {
+    "/**",
+    " * From the OpenGL Programming wikibook: http://en.wikibooks.org/wiki/GLSL_Programming/GLUT/Smooth_Specular_Highlights",
+    " * This file is in the public domain.",
+    " * Contributors: Sylvain Beucler",
+    " */",
+    "attribute vec3 fg_coord;",
+    "attribute vec3 fg_normal;",
+    "varying vec4 position;  /* position of the vertex (and fragment) in world space */",
+    "varying vec3 varyingNormalDirection;  /* surface normal vector in world space */",
+    "uniform mat4 m, p;      /* don't need v, as always identity in our demo */",
+    "uniform mat3 m_3x3_inv_transp;",
+    " ",
+    "void main()",
+    "{",
+    "  vec4 fg_coord4 = vec4(fg_coord, 1.0);",
+    "  position = m * fg_coord4;",
+    "  varyingNormalDirection = normalize(m_3x3_inv_transp * fg_normal);",
+    " ",
+    "  mat4 mvp = p*m;   /* normally p*v*m */",
+    "  gl_Position = mvp * fg_coord4;",
+    "}"
+};
+
+const ourGLchar *fragmentShaderSource[] = {
+    "/**",
+    " * From the OpenGL Programming wikibook: http://en.wikibooks.org/wiki/GLSL_Programming/GLUT/Smooth_Specular_Highlights",
+    " * This file is in the public domain.",
+    " * Contributors: Martin Kraus, Sylvain Beucler",
+    " */",
+    "varying vec4 position;  /* position of the vertex (and fragment) in world space */",
+    "varying vec3 varyingNormalDirection;  /* surface normal vector in world space */",
+    "/* uniform mat4 v_inv;   // in this demo, the view matrix is always an identity matrix */",
+    " ",
+    "struct lightSource",
+    "{",
+    "  vec4 position;",
+    "  vec4 diffuse;",
+    "  vec4 specular;",
+    "  float constantAttenuation, linearAttenuation, quadraticAttenuation;",
+    "  float spotCutoff, spotExponent;",
+    "  vec3 spotDirection;",
+    "};",
+    "lightSource light0 = lightSource(",
+    "  vec4(2.0, 5.0, 5.0, 0.0),",
+    "  vec4(1.0, 1.0, 1.0, 1.0),",
+    "  vec4(1.0, 1.0, 1.0, 1.0),",
+    "    0.0, 1.0, 0.0,",
+    "  180.0, 0.0,",
+    "  vec3(0.0, 0.0, 0.0)",
+    ");",
+    "vec4 scene_ambient = vec4(0.2, 0.2, 0.2, 1.0);",
+    " ",
+    "struct material",
+    "{",
+    "  vec4 ambient;",
+    "  vec4 diffuse;",
+    "  vec4 specular;",
+    "  float shininess;",
+    "};",
+    "material frontMaterial = material(",
+    "  vec4(1.0, 0.0, 0.0, 1.0),",
+    "  vec4(1.0, 0.0, 0.0, 1.0),",
+    "  vec4(1.0, 1.0, 1.0, 1.0),",
+    "  100.0",
+    ");",
+    " ",
+    "void main()",
+    "{",
+    "  vec3 normalDirection = normalize(varyingNormalDirection);",
+    "  /* vec3 viewDirection = normalize(vec3(v_inv * vec4(0.0, 0.0, 0.0, 1.0) - position)); */",
+    "  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 */",
+    "  vec3 lightDirection;",
+    "  float attenuation;",
+    " ",
+    "  if (0.0 == light0.position.w) /* directional light? */",
+    "    {",
+    "      attenuation = 1.0; /* no attenuation */",
+    "      lightDirection = normalize(vec3(light0.position));",
+    "    } ",
+    "  else /* point light or spotlight (or other kind of light) */",
+    "    {",
+    "      vec3 positionToLightSource = vec3(light0.position - position);",
+    "      float distance = length(positionToLightSource);",
+    "      lightDirection = normalize(positionToLightSource);",
+    "      attenuation = 1.0 / (light0.constantAttenuation",
+    "                           + light0.linearAttenuation * distance",
+    "                           + light0.quadraticAttenuation * distance * distance);",
+    " ",
+    "      if (light0.spotCutoff <= 90.0) /* spotlight? */",
+    "        {",
+    "          float clampedCosine = max(0.0, dot(-lightDirection, light0.spotDirection));",
+    "          if (clampedCosine < cos(radians(light0.spotCutoff))) /* outside of spotlight cone? */",
+    "            {",
+    "              attenuation = 0.0;",
+    "            }",
+    "          else",
+    "            {",
+    "              attenuation = attenuation * pow(clampedCosine, light0.spotExponent);   ",
+    "            }",
+    "        }",
+    "    }",
+    " ",
+    "  vec3 ambientLighting = vec3(scene_ambient) * vec3(frontMaterial.ambient);",
+    " ",
+    "  vec3 diffuseReflection = attenuation ",
+    "    * vec3(light0.diffuse) * vec3(frontMaterial.diffuse)",
+    "    * max(0.0, dot(normalDirection, lightDirection));",
+    " ",
+    "  vec3 specularReflection;",
+    "  if (dot(normalDirection, lightDirection) < 0.0) /* light source on the wrong side? */",
+    "    {",
+    "      specularReflection = vec3(0.0, 0.0, 0.0); /* no specular reflection */",
+    "    }",
+    "  else /* light source on the right side */",
+    "    {",
+    "      specularReflection = attenuation * vec3(light0.specular) * vec3(frontMaterial.specular) ",
+    "        * pow(max(0.0, dot(reflect(-lightDirection, normalDirection), viewDirection)), frontMaterial.shininess);",
+    "    }",
+    " ",
+    "  gl_FragColor = vec4(ambientLighting + diffuseReflection + specularReflection, 1.0);",
+    "}"
+};
+
+GLint getAttribOrUniformLocation(const char* name, GLuint program, GLboolean isAttrib)
+{
+    if (isAttrib)
+    {
+        GLint attrib = gl_GetAttribLocation(program, name);
+        if (attrib == -1)
+        {
+            fprintf(stderr, "Warning: Could not bind attrib %s\n", name);
+        }
+
+        checkError ("getAttribOrUniformLocation");
+        return attrib;
+    }
+    else
+    {
+        GLint uniform = gl_GetUniformLocation(program, name);
+        if (uniform == -1)
+        {
+            fprintf(stderr, "Warning: Could not bind uniform %s\n", name);
+        }
+
+        checkError ("getAttribOrUniformLocation");
+        return uniform;
+    }
+}
+
+GLuint program;
+GLint attribute_fg_coord = -1, attribute_fg_normal = -1;
+GLint uniform_m = -1, uniform_p = -1, uniform_m_3x3_inv_transp = -1;
+GLint shaderReady = 0;  /* Set to 1 when all initialization went well, to -1 when shader somehow unusable. */
+
+
+
+void compileAndCheck(GLuint shader)
+{
+    GLint status;
+    gl_CompileShader (shader);
+    gl_GetShaderiv (shader, GL_COMPILE_STATUS, &status);
+    if (status == GL_FALSE) {
+        GLint infoLogLength;
+        ourGLchar *infoLog;
+        gl_GetShaderiv (shader, GL_INFO_LOG_LENGTH, &infoLogLength);
+        infoLog = (ourGLchar*) malloc (infoLogLength);
+        gl_GetShaderInfoLog (shader, infoLogLength, NULL, infoLog);
+        fprintf (stderr, "compile log: %s\n", infoLog);
+        free (infoLog);
+    }
+    checkError ("compileAndCheck");
+}
+
+GLuint compileShaderSource(GLenum type, GLsizei count, const ourGLchar **string)
+{
+    GLuint shader = gl_CreateShader (type);
+    gl_ShaderSource (shader, count, string, NULL);
+
+    checkError ("compileShaderSource");
+
+    compileAndCheck (shader);
+    return shader;
+}
+
+void linkAndCheck(GLuint program)
+{
+    GLint status;
+    gl_LinkProgram (program);
+    gl_GetProgramiv (program, GL_LINK_STATUS, &status);
+    if (status == GL_FALSE) {
+        GLint infoLogLength;
+        ourGLchar *infoLog;
+        gl_GetProgramiv (program, GL_INFO_LOG_LENGTH, &infoLogLength);
+        infoLog = (ourGLchar*) malloc (infoLogLength);
+        gl_GetProgramInfoLog (program, infoLogLength, NULL, infoLog);
+        fprintf (stderr, "link log: %s\n", infoLog);
+        free (infoLog);
+    }
+    checkError ("linkAndCheck");
+}
+
+void createProgram(GLuint vertexShader, GLuint fragmentShader)
+{
+    program = gl_CreateProgram ();
+    if (vertexShader != 0) {
+        gl_AttachShader (program, vertexShader);
+    }
+    if (fragmentShader != 0) {
+        gl_AttachShader (program, fragmentShader);
+    }
+
+    checkError ("createProgram");
+
+    linkAndCheck (program);
+}
+
+void initShader(void)
+{
+    const GLsizei vertexShaderLines = sizeof(vertexShaderSource) / sizeof(ourGLchar*);
+    GLuint vertexShader =
+        compileShaderSource (GL_VERTEX_SHADER, vertexShaderLines, vertexShaderSource);
+
+    const GLsizei fragmentShaderLines = sizeof(fragmentShaderSource) / sizeof(ourGLchar*);
+    GLuint fragmentShader =
+        compileShaderSource (GL_FRAGMENT_SHADER, fragmentShaderLines, fragmentShaderSource);
+
+    checkError ("initShader - 1");
+
+    createProgram (vertexShader, fragmentShader);
+
+    gl_UseProgram (program);
+
+    attribute_fg_coord      = getAttribOrUniformLocation("fg_coord"         , program, GL_TRUE);
+    attribute_fg_normal     = getAttribOrUniformLocation("fg_normal"        , program, GL_TRUE);
+    uniform_m               = getAttribOrUniformLocation("m"                , program, GL_FALSE);
+    uniform_p               = getAttribOrUniformLocation("p"                , program, GL_FALSE);
+    uniform_m_3x3_inv_transp= getAttribOrUniformLocation("m_3x3_inv_transp" , program, GL_FALSE);
+
+    gl_UseProgram (0);
+
+    if (attribute_fg_coord==-1 || attribute_fg_normal==-1 ||
+        uniform_m==-1 || uniform_p==-1 || uniform_m_3x3_inv_transp==-1)
+        shaderReady = -1;
+    else
+        shaderReady = 1;
+
+    checkError ("initShader - 2");
+}
+
 /*
  * This macro is only intended to be used on arrays, of course.
  */
 /*
  * This macro is only intended to be used on arrays, of course.
  */
@@ -60,68 +416,122 @@ static int function_index;
 static int slices = 16;
 static int stacks = 16;
 static double irad = .25;
 static int slices = 16;
 static int stacks = 16;
 static double irad = .25;
-static double orad = 1.0;
+static double orad = 1.0;   /* doubles as size for objects other than Torus */
 static int depth = 4;
 static double offset[ 3 ] = { 0, 0, 0 };
 static GLboolean show_info = GL_TRUE;
 static int depth = 4;
 static double offset[ 3 ] = { 0, 0, 0 };
 static GLboolean show_info = GL_TRUE;
+static float ar;
+static GLboolean persProject = GL_TRUE;
+static GLboolean animateXRot = GL_FALSE;
+static GLboolean useShader   = GL_FALSE;
+static GLboolean visNormals  = GL_FALSE;
+
+/*
+ * Enum to tell drawSizeInfo what to draw for each object
+ */
+#define GEO_NO_SIZE 0
+#define GEO_SIZE 1
+#define GEO_SCALE 2
+#define GEO_INNER_OUTER_RAD 4
+#define GEO_RAD 8
+#define GEO_BASE_HEIGHT 16
+#define GEO_RAD_HEIGHT 32
 
 /*
  * These one-liners draw particular objects, fetching appropriate
  * information from the above globals.  They are just thin wrappers
 
 /*
  * These one-liners draw particular objects, fetching appropriate
  * information from the above globals.  They are just thin wrappers
- * for the OpenGLUT objects.
+ * for the FreeGLUT objects.
  */
  */
-static void drawSolidTetrahedron(void)         { glutSolidTetrahedron ();                      }
-static void drawWireTetrahedron(void)          { glutWireTetrahedron ();                       }
-static void drawSolidCube(void)                { glutSolidCube(1);                             }
-static void drawWireCube(void)                 { glutWireCube(1);                              }
-static void drawSolidOctahedron(void)          { glutSolidOctahedron ();                       }
-static void drawWireOctahedron(void)           { glutWireOctahedron ();                        }
-static void drawSolidDodecahedron(void)        { glutSolidDodecahedron ();                     }
-static void drawWireDodecahedron(void)         { glutWireDodecahedron ();                      }
-static void drawSolidRhombicDodecahedron(void) { glutSolidRhombicDodecahedron ();              }
-static void drawWireRhombicDodecahedron(void)  { glutWireRhombicDodecahedron ();               }
-static void drawSolidIcosahedron(void)         { glutSolidIcosahedron ();                      }
-static void drawWireIcosahedron(void)          { glutWireIcosahedron ();                       }
-static void drawSolidSierpinskiSponge(void)    { glutSolidSierpinskiSponge (depth, offset, 1); }
-static void drawWireSierpinskiSponge(void)     { glutWireSierpinskiSponge (depth, offset, 1);  }
-static void drawSolidTeapot(void)              { glutSolidTeapot(1);                           }
-static void drawWireTeapot(void)               { glutWireTeapot(1);                            }
-static void drawSolidTorus(void)               { glutSolidTorus(irad,orad,slices,stacks);      }
-static void drawWireTorus(void)                { glutWireTorus (irad,orad,slices,stacks);      }
-static void drawSolidSphere(void)              { glutSolidSphere(1,slices,stacks);             }
-static void drawWireSphere(void)               { glutWireSphere(1,slices,stacks);              }
-static void drawSolidCone(void)                { glutSolidCone(1,1,slices,stacks);             }
-static void drawWireCone(void)                 { glutWireCone(1,1,slices,stacks);              }
-static void drawSolidCylinder(void)            { glutSolidCylinder(1,1,slices,stacks);         }
-static void drawWireCylinder(void)             { glutWireCylinder(1,1,slices,stacks);          }
+static void drawSolidTetrahedron(void)         { glutSolidTetrahedron ();                        }
+static void drawWireTetrahedron(void)          { glutWireTetrahedron ();                         }
+static void drawSolidCube(void)                { glutSolidCube(orad);                            }  /* orad doubles as size input */
+static void drawWireCube(void)                 { glutWireCube(orad);                             }  /* orad doubles as size input */
+static void drawSolidOctahedron(void)          { glutSolidOctahedron ();                         }
+static void drawWireOctahedron(void)           { glutWireOctahedron ();                          }
+static void drawSolidDodecahedron(void)        { glutSolidDodecahedron ();                       }
+static void drawWireDodecahedron(void)         { glutWireDodecahedron ();                        }
+static void drawSolidRhombicDodecahedron(void) { glutSolidRhombicDodecahedron ();                }
+static void drawWireRhombicDodecahedron(void)  { glutWireRhombicDodecahedron ();                 }
+static void drawSolidIcosahedron(void)         { glutSolidIcosahedron ();                        }
+static void drawWireIcosahedron(void)          { glutWireIcosahedron ();                         }
+static void drawSolidSierpinskiSponge(void)    { glutSolidSierpinskiSponge (depth, offset, orad);}  /* orad doubles as size input */
+static void drawWireSierpinskiSponge(void)     { glutWireSierpinskiSponge (depth, offset, orad); }  /* orad doubles as size input */
+static void drawSolidTorus(void)               { glutSolidTorus(irad,orad,slices,stacks);        }
+static void drawWireTorus(void)                { glutWireTorus (irad,orad,slices,stacks);        }
+static void drawSolidSphere(void)              { glutSolidSphere(orad,slices,stacks);            }  /* orad doubles as size input */
+static void drawWireSphere(void)               { glutWireSphere(orad,slices,stacks);             }  /* orad doubles as size input */
+static void drawSolidCone(void)                { glutSolidCone(irad,orad,slices,stacks);         }  /* irad doubles as base input, and orad as height input */
+static void drawWireCone(void)                 { glutWireCone(irad,orad,slices,stacks);          }  /* irad doubles as base input, and orad as height input */
+static void drawSolidCylinder(void)            { glutSolidCylinder(irad,orad,slices,stacks);     }  /* irad doubles as radius input, and orad as height input */
+static void drawWireCylinder(void)             { glutWireCylinder(irad,orad,slices,stacks);      }  /* irad doubles as radius input, and orad as height input */
+/* per Glut manpage, it should be noted that the teapot is rendered
+ * with clockwise winding for front facing polygons...
+ * Same for the teacup and teaspoon
+ */
+static void drawSolidTeapot(void)
+{   glFrontFace(GL_CW);    glutSolidTeapot(orad);   glFrontFace(GL_CCW);    /* orad doubles as size input */}
+static void drawWireTeapot(void)
+{   glFrontFace(GL_CW);    glutWireTeapot(orad);    glFrontFace(GL_CCW);    /* orad doubles as size input */}
+static void drawSolidTeacup(void)
+{   glFrontFace(GL_CW);    glutSolidTeacup(orad);   glFrontFace(GL_CCW);    /* orad doubles as size input */}
+static void drawWireTeacup(void)
+{   glFrontFace(GL_CW);    glutWireTeacup(orad);    glFrontFace(GL_CCW);    /* orad doubles as size input */}
+static void drawSolidTeaspoon(void)
+{   glFrontFace(GL_CW);    glutSolidTeaspoon(orad); glFrontFace(GL_CCW);    /* orad doubles as size input */}
+static void drawWireTeaspoon(void)
+{   glFrontFace(GL_CW);    glutWireTeaspoon(orad);  glFrontFace(GL_CCW);    /* orad doubles as size input */}
+
+#define RADIUSFAC    0.70710678118654752440084436210485f
+
 static void drawSolidCuboctahedron(void)
 {
 static void drawSolidCuboctahedron(void)
 {
-#define RADIUS    1.0f
+  GLfloat radius = RADIUSFAC*(GLfloat)orad; /* orad doubles as size */
   glBegin( GL_TRIANGLES );
   glBegin( GL_TRIANGLES );
-    glNormal3d( 0.577350269189, 0.577350269189, 0.577350269189); glVertex3d( RADIUS, RADIUS, 0.0 ); glVertex3d( 0.0, RADIUS, RADIUS ); glVertex3d( RADIUS, 0.0, RADIUS );
-    glNormal3d( 0.577350269189, 0.577350269189,-0.577350269189); glVertex3d( RADIUS, RADIUS, 0.0 ); glVertex3d( RADIUS, 0.0,-RADIUS ); glVertex3d( 0.0, RADIUS,-RADIUS );
-    glNormal3d( 0.577350269189,-0.577350269189, 0.577350269189); glVertex3d( RADIUS,-RADIUS, 0.0 ); glVertex3d( RADIUS, 0.0, RADIUS ); glVertex3d( 0.0,-RADIUS, RADIUS );
-    glNormal3d( 0.577350269189,-0.577350269189,-0.577350269189); glVertex3d( RADIUS,-RADIUS, 0.0 ); glVertex3d( 0.0,-RADIUS,-RADIUS ); glVertex3d( RADIUS, 0.0,-RADIUS );
-    glNormal3d(-0.577350269189, 0.577350269189, 0.577350269189); glVertex3d(-RADIUS, RADIUS, 0.0 ); glVertex3d(-RADIUS, 0.0, RADIUS ); glVertex3d( 0.0, RADIUS, RADIUS );
-    glNormal3d(-0.577350269189, 0.577350269189,-0.577350269189); glVertex3d(-RADIUS, RADIUS, 0.0 ); glVertex3d( 0.0, RADIUS,-RADIUS ); glVertex3d(-RADIUS, 0.0,-RADIUS );
-    glNormal3d(-0.577350269189,-0.577350269189, 0.577350269189); glVertex3d(-RADIUS,-RADIUS, 0.0 ); glVertex3d( 0.0,-RADIUS, RADIUS ); glVertex3d(-RADIUS, 0.0, RADIUS );
-    glNormal3d(-0.577350269189,-0.577350269189,-0.577350269189); glVertex3d(-RADIUS,-RADIUS, 0.0 ); glVertex3d(-RADIUS, 0.0,-RADIUS ); glVertex3d( 0.0,-RADIUS,-RADIUS );
+    glNormal3d( 0.577350269189, 0.577350269189, 0.577350269189); glVertex3d( radius, radius, 0.0 ); glVertex3d( 0.0, radius, radius ); glVertex3d( radius, 0.0, radius );
+    glNormal3d( 0.577350269189, 0.577350269189,-0.577350269189); glVertex3d( radius, radius, 0.0 ); glVertex3d( radius, 0.0,-radius ); glVertex3d( 0.0, radius,-radius );
+    glNormal3d( 0.577350269189,-0.577350269189, 0.577350269189); glVertex3d( radius,-radius, 0.0 ); glVertex3d( radius, 0.0, radius ); glVertex3d( 0.0,-radius, radius );
+    glNormal3d( 0.577350269189,-0.577350269189,-0.577350269189); glVertex3d( radius,-radius, 0.0 ); glVertex3d( 0.0,-radius,-radius ); glVertex3d( radius, 0.0,-radius );
+    glNormal3d(-0.577350269189, 0.577350269189, 0.577350269189); glVertex3d(-radius, radius, 0.0 ); glVertex3d(-radius, 0.0, radius ); glVertex3d( 0.0, radius, radius );
+    glNormal3d(-0.577350269189, 0.577350269189,-0.577350269189); glVertex3d(-radius, radius, 0.0 ); glVertex3d( 0.0, radius,-radius ); glVertex3d(-radius, 0.0,-radius );
+    glNormal3d(-0.577350269189,-0.577350269189, 0.577350269189); glVertex3d(-radius,-radius, 0.0 ); glVertex3d( 0.0,-radius, radius ); glVertex3d(-radius, 0.0, radius );
+    glNormal3d(-0.577350269189,-0.577350269189,-0.577350269189); glVertex3d(-radius,-radius, 0.0 ); glVertex3d(-radius, 0.0,-radius ); glVertex3d( 0.0,-radius,-radius );
   glEnd();
 
   glBegin( GL_QUADS );
   glEnd();
 
   glBegin( GL_QUADS );
-    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 );
-    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 );
-    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 );
-    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 );
-    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 );
-    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 );
+    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 );
+    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 );
+    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 );
+    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 );
+    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 );
+    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 );
   glEnd();
   glEnd();
-#undef RADIUS
 }
 }
+
 static void drawWireCuboctahedron(void)
 {
 static void drawWireCuboctahedron(void)
 {
+  GLfloat radius = RADIUSFAC*(GLfloat)orad; /* orad doubles as size */
+  glBegin( GL_LINE_LOOP );
+    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 );
+  glEnd();
+  glBegin( GL_LINE_LOOP );
+    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 );
+  glEnd();
+  glBegin( GL_LINE_LOOP );
+    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 );
+  glEnd();
+  glBegin( GL_LINE_LOOP );
+    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 );
+  glEnd();
+  glBegin( GL_LINE_LOOP );
+    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 );
+  glEnd();
+  glBegin( GL_LINE_LOOP );
+    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 );
+  glEnd();
 }
 
 }
 
+#undef RADIUSFAC
+
 /*
  * This structure defines an entry in our function-table.
  */
 /*
  * This structure defines an entry in our function-table.
  */
@@ -130,43 +540,37 @@ typedef struct
     const char * const name;
     void (*solid) (void);
     void (*wire)  (void);
     const char * const name;
     void (*solid) (void);
     void (*wire)  (void);
+    int drawSizeInfoFlag;
 } entry;
 
 } entry;
 
-#define ENTRY(e) {#e, drawSolid##e, drawWire##e}
+#define ENTRY(e,f) {#e, drawSolid##e, drawWire##e,f}
 static const entry table [] =
 {
 static const entry table [] =
 {
-    ENTRY (Tetrahedron),
-    ENTRY (Cube),
-    ENTRY (Octahedron),
-    ENTRY (Dodecahedron),
-    ENTRY (RhombicDodecahedron),
-    ENTRY (Icosahedron),
-    ENTRY (SierpinskiSponge),
-    ENTRY (Teapot),
-    ENTRY (Torus),
-    ENTRY (Sphere),
-    ENTRY (Cone),
-    ENTRY (Cylinder),
-    ENTRY (Cuboctahedron)
+    ENTRY (Tetrahedron,GEO_NO_SIZE),
+    ENTRY (Cube,GEO_SIZE),
+    ENTRY (Octahedron,GEO_NO_SIZE),
+    ENTRY (Dodecahedron,GEO_NO_SIZE),
+    ENTRY (RhombicDodecahedron,GEO_NO_SIZE),
+    ENTRY (Icosahedron,GEO_NO_SIZE),
+    ENTRY (SierpinskiSponge,GEO_SCALE),
+    ENTRY (Teapot,GEO_SIZE),
+    ENTRY (Teacup,GEO_SIZE),
+    ENTRY (Teaspoon,GEO_SIZE),
+    ENTRY (Torus,GEO_INNER_OUTER_RAD),
+    ENTRY (Sphere,GEO_RAD),
+    ENTRY (Cone,GEO_BASE_HEIGHT),
+    ENTRY (Cylinder,GEO_RAD_HEIGHT),
+    ENTRY (Cuboctahedron,GEO_SIZE)   /* This one doesn't work when in shader mode and is then skipped */
 };
 #undef ENTRY
 
 /*!
 };
 #undef ENTRY
 
 /*!
-    Does printf()-like work using freeglut/OpenGLUT
+    Does printf()-like work using freeglut
     glutBitmapString().  Uses a fixed font.  Prints
     at the indicated row/column position.
 
     Limitation: Cannot address pixels.
     Limitation: Renders in screen coords, not model coords.
     glutBitmapString().  Uses a fixed font.  Prints
     at the indicated row/column position.
 
     Limitation: Cannot address pixels.
     Limitation: Renders in screen coords, not model coords.
-
-    \note Uses a fixed, 256-byte array for holding strings.
-          The best way around this would be to use vasprintf(),
-          but that is not available on WIN32, I believe.
-          Another alternative would be to write our own formatter
-          from scratch and emit the characters one at a time to
-          the GLUT bitmap single-character drawing routine.
-          We could also use vsnprintf(), but I'm not sure if
-          that is standard...
 */
 static void shapesPrintf (int row, int col, const char *fmt, ...)
 {
 */
 static void shapesPrintf (int row, int col, const char *fmt, ...)
 {
@@ -176,7 +580,11 @@ static void shapesPrintf (int row, int col, const char *fmt, ...)
     va_list args;
 
     va_start(args, fmt);
     va_list args;
 
     va_start(args, fmt);
-    (void) vsprintf (buf, fmt, args);
+#if defined(WIN32) && !defined(__CYGWIN__)
+    (void) _vsnprintf (buf, sizeof(buf), fmt, args);
+#else
+    (void) vsnprintf (buf, sizeof(buf), fmt, args);
+#endif
     va_end(args);
 
     glGetIntegerv(GL_VIEWPORT,viewport);
     va_end(args);
 
     glGetIntegerv(GL_VIEWPORT,viewport);
@@ -193,7 +601,7 @@ static void shapesPrintf (int row, int col, const char *fmt, ...)
         glRasterPos2i
         (
               glutBitmapWidth(font, ' ') * col,
         glRasterPos2i
         (
               glutBitmapWidth(font, ' ') * col,
-            - glutBitmapHeight(font) * (row+2) + viewport[3]
+            - glutBitmapHeight(font) * row + viewport[3]
         );
         glutBitmapString (font, (unsigned char*)buf);
 
         );
         glutBitmapString (font, (unsigned char*)buf);
 
@@ -202,61 +610,167 @@ static void shapesPrintf (int row, int col, const char *fmt, ...)
     glPopMatrix();
 }
 
     glPopMatrix();
 }
 
-/* GLUT callback Handlers */
+/* Print info about the about the current shape and render state on the screen */
+static void DrawSizeInfo(int *row)
+{
+    switch (table [function_index].drawSizeInfoFlag)
+    {
+    case GEO_NO_SIZE:
+        break;
+    case GEO_SIZE:
+        shapesPrintf ((*row)++, 1, "Size  Up  Down : %f", orad);
+        break;
+    case GEO_SCALE:
+        shapesPrintf ((*row)++, 1, "Scale  Up  Down : %f", orad);
+        break;
+    case GEO_INNER_OUTER_RAD:
+        shapesPrintf ((*row)++, 1, "Inner radius Left Right: %f", irad);
+        shapesPrintf ((*row)++, 1, "Outer radius  Up  Down : %f", orad);
+        break;
+    case GEO_RAD:
+        shapesPrintf ((*row)++, 1, "Radius  Up  Down : %f", orad);
+        break;
+    case GEO_BASE_HEIGHT:
+        shapesPrintf ((*row)++, 1, "Base   Left Right: %f", irad);
+        shapesPrintf ((*row)++, 1, "Height  Up  Down : %f", orad);
+        break;
+    case GEO_RAD_HEIGHT:
+        shapesPrintf ((*row)++, 1, "Radius Left Right: %f", irad);
+        shapesPrintf ((*row)++, 1, "Height  Up  Down : %f", orad);
+        break;
+    }
+}
 
 
+static void drawInfo()
+{
+    int row = 1;
+    shapesPrintf (row++, 1, "Shape PgUp PgDn: %s", table [function_index].name);
+    shapesPrintf (row++, 1, "Slices +-: %d   Stacks <>: %d", slices, stacks);
+    shapesPrintf (row++, 1, "nSides +-: %d   nRings <>: %d", slices, stacks);
+    shapesPrintf (row++, 1, "Depth  (): %d", depth);
+    DrawSizeInfo(&row);
+    if (persProject)
+        shapesPrintf (row++, 1, "Perspective projection (p)");
+    else
+        shapesPrintf (row++, 1, "Orthographic projection (p)");
+    if (useShader)
+        shapesPrintf (row++, 1, "Using shader (s)");
+    else
+        shapesPrintf (row++, 1, "Using fixed function pipeline (s)");
+    if (animateXRot)
+        shapesPrintf (row++, 1, "2D rotation (r)");
+    else
+        shapesPrintf (row++, 1, "1D rotation (r)");
+    shapesPrintf (row++, 1, "visualizing normals: %i (n)",visNormals);
+}
+
+/* GLUT callback Handlers */
 static void
 resize(int width, int height)
 {
 static void
 resize(int width, int height)
 {
-    const float ar = (float) width / (float) height;
+    ar = (float) width / (float) height;
 
     glViewport(0, 0, width, height);
 
     glViewport(0, 0, width, height);
-
-    glMatrixMode(GL_PROJECTION);
-    glLoadIdentity();
-    glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
-
-    glMatrixMode(GL_MODELVIEW);
-    glLoadIdentity() ;
 }
 
 static void display(void)
 {
     const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
 }
 
 static void display(void)
 {
     const double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
-    const double a = t*90.0;
+    const double a = t*89.0;
+    const double b = (animateXRot?t:1)*67.0;
 
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
 
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
-    glEnable(GL_LIGHTING);
-
-    glColor3d(1,0,0);
+    glutSetOption(GLUT_GEOMETRY_VISUALIZE_NORMALS,visNormals);  /* Normals visualized or not? */
 
 
-    glPushMatrix();
-        glTranslated(0,1.2,-6);
-        glRotated(60,1,0,0);
-        glRotated(a,0,0,1);
-        table [function_index].solid ();
-    glPopMatrix();
+    if (useShader && !shaderReady)
+        initShader();
 
 
-    glPushMatrix();
-        glTranslated(0,-1.2,-6);
-        glRotated(60,1,0,0);
-        glRotated(a,0,0,1);
-        table [function_index].wire ();
-    glPopMatrix();
+    if (useShader && shaderReady)
+    {
+        /* setup use of shader (and vertex buffer by FreeGLUT) */
+        gl_UseProgram (program);
+        glutSetVertexAttribCoord3(attribute_fg_coord);
+        glutSetVertexAttribNormal(attribute_fg_normal);
+        /* There is also a glutSetVertexAttribTexCoord2, which is used only when drawing the teapot, teacup or teaspoon */
+
+        gl_matrix_mode(GL_PROJECTION);
+        gl_load_identity();
+        if (persProject)
+            gl_frustum(-ar, ar, -1.f, 1.f, 2.f, 100.f);
+        else
+            gl_ortho(-ar*3, ar*3, -3.f, 3.f, 2.f, 100.f);
+        gl_UniformMatrix4fv (uniform_p, 1, GL_FALSE, get_matrix(GL_PROJECTION));
+
+
+        gl_matrix_mode(GL_MODELVIEW);
+        gl_load_identity();
+
+        gl_push_matrix();
+            /* Not in reverse order like normal OpenGL, our util library multiplies the matrices in the order they are specified in */
+            gl_rotatef((float)a,0,0,1);
+            gl_rotatef((float)b,1,0,0);
+            gl_translatef(0,1.2f,-6);
+            gl_UniformMatrix4fv (uniform_m               , 1, GL_FALSE, get_matrix(GL_MODELVIEW));
+            gl_UniformMatrix3fv (uniform_m_3x3_inv_transp, 1, GL_FALSE, get_inv_transpose_3x3(GL_MODELVIEW));
+            table [function_index].solid ();
+        gl_pop_matrix();
+
+        gl_push_matrix();
+            gl_rotatef((float)a,0,0,1);
+            gl_rotatef((float)b,1,0,0);
+            gl_translatef(0,-1.2f,-6);
+            gl_UniformMatrix4fv (uniform_m               , 1, GL_FALSE, get_matrix(GL_MODELVIEW));
+            gl_UniformMatrix3fv (uniform_m_3x3_inv_transp, 1, GL_FALSE, get_inv_transpose_3x3(GL_MODELVIEW));
+            table [function_index].wire ();
+        gl_pop_matrix();
+
+        gl_UseProgram (0);
+        glutSetVertexAttribCoord3(-1);
+        glutSetVertexAttribNormal(-1);
+
+        checkError ("display");
+    }
+    else
+    {
+        /* fixed function pipeline */
+        glMatrixMode(GL_PROJECTION);
+        glLoadIdentity();
+        if (persProject)
+            glFrustum(-ar, ar, -1.0, 1.0, 2.0, 100.0);
+        else
+            glOrtho(-ar*3, ar*3, -3.0, 3.0, 2.0, 100.0);
+        glMatrixMode(GL_MODELVIEW);
+        glLoadIdentity();
+
+        glEnable(GL_LIGHTING);
+
+        glColor3d(1,0,0);
+
+        glPushMatrix();
+            glTranslated(0,1.2,-6);
+            glRotated(b,1,0,0);
+            glRotated(a,0,0,1);
+            table [function_index].solid ();
+        glPopMatrix();
+
+        glPushMatrix();
+            glTranslated(0,-1.2,-6);
+            glRotated(b,1,0,0);
+            glRotated(a,0,0,1);
+            table [function_index].wire ();
+        glPopMatrix();
+
+        glDisable(GL_LIGHTING);
+        glColor3d(0.1,0.1,0.4);
+    }
 
 
-    glDisable(GL_LIGHTING);
-    glColor3d(0.1,0.1,0.4);
-
-    if( show_info ) {
-        shapesPrintf (1, 3, "Shape PgUp PgDn: %s", table [function_index].name);
-        shapesPrintf (2, 3, "Slices +-: %d   Stacks <>: %d", slices, stacks);
-        shapesPrintf (3, 3, "nSides +-: %d   nRings <>: %d", slices, stacks);
-        shapesPrintf (4, 3, "Depth  (): %d", depth);
-        shapesPrintf (5, 3, "Outer radius  Up  Down : %f", orad);
-        shapesPrintf (6, 3, "Inner radius Left Right: %f", irad);
-    } else {
+    if( show_info )
+        /* print info to screen */
+        drawInfo();
+    else
+        /* print to command line instead */
         printf ( "Shape %d slides %d stacks %d\n", function_index, slices, stacks ) ;
         printf ( "Shape %d slides %d stacks %d\n", function_index, slices, stacks ) ;
-    }
 
     glutSwapBuffers();
 }
 
     glutSwapBuffers();
 }
@@ -272,7 +786,7 @@ key(unsigned char key, int x, int y)
     case 'q': glutLeaveMainLoop () ;      break;
 
     case 'I':
     case 'q': glutLeaveMainLoop () ;      break;
 
     case 'I':
-    case 'i': show_info = ( show_info == GL_TRUE ) ? GL_FALSE : GL_TRUE; break;
+    case 'i': show_info=!show_info;       break;
 
     case '=':
     case '+': slices++;                   break;
 
     case '=':
     case '+': slices++;                   break;
@@ -286,12 +800,29 @@ key(unsigned char key, int x, int y)
     case '.':
     case '>': stacks++;                   break;
 
     case '.':
     case '>': stacks++;                   break;
 
-    case '9': 
+    case '9':
     case '(': if( depth > -1 ) depth--;   break;
 
     case '(': if( depth > -1 ) depth--;   break;
 
-    case '0': 
+    case '0':
     case ')': ++depth;                    break;
 
     case ')': ++depth;                    break;
 
+    case 'P':
+    case 'p': persProject=!persProject;   break;
+
+    case 'R':
+    case 'r': animateXRot=!animateXRot;   break;
+
+    case 'S':
+    case 's':
+        useShader=!useShader;
+        /* Cuboctahedron can't be shown when in shader mode, move to next */
+        if (useShader && NUMBEROF (table)-1 == ( unsigned )function_index)
+                function_index = 0;
+        break;
+
+    case 'N':
+    case 'n': visNormals=!visNormals;     break;
+
     default:
         break;
     }
     default:
         break;
     }
@@ -320,6 +851,15 @@ static void special (int key, int x, int y)
 
     if (NUMBEROF (table) <= ( unsigned )function_index)
         function_index = 0;
 
     if (NUMBEROF (table) <= ( unsigned )function_index)
         function_index = 0;
+
+    /* Cuboctahedron can't be shown when in shader mode, skip it */
+    if (useShader && NUMBEROF (table)-1 == ( unsigned )function_index)
+    {
+        if (key==GLUT_KEY_PAGE_UP)
+            function_index = 0;
+        else
+            function_index -= 1;
+    }
 }
 
 
 }
 
 
@@ -344,12 +884,12 @@ const GLfloat high_shininess[] = { 100.0f };
 int
 main(int argc, char *argv[])
 {
 int
 main(int argc, char *argv[])
 {
-    glutInitWindowSize(640,480);
+    glutInitWindowSize(800,600);
     glutInitWindowPosition(40,40);
     glutInit(&argc, argv);
     glutInitWindowPosition(40,40);
     glutInit(&argc, argv);
-    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
 
 
-    glutCreateWindow("OpenGLUT Shapes");
+    glutCreateWindow("FreeGLUT Shapes");
 
     glutReshapeFunc(resize);
     glutDisplayFunc(display);
 
     glutReshapeFunc(resize);
     glutDisplayFunc(display);
@@ -380,9 +920,11 @@ main(int argc, char *argv[])
     glMaterialfv(GL_FRONT, GL_SPECULAR,  mat_specular);
     glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
 
     glMaterialfv(GL_FRONT, GL_SPECULAR,  mat_specular);
     glMaterialfv(GL_FRONT, GL_SHININESS, high_shininess);
 
+    initExtensionEntries();
+
     glutMainLoop();
 
     glutMainLoop();
 
-#ifdef WIN32
+#ifdef _MSC_VER
     /* DUMP MEMORY LEAK INFORMATION */
     _CrtDumpMemoryLeaks () ;
 #endif
     /* DUMP MEMORY LEAK INFORMATION */
     _CrtDumpMemoryLeaks () ;
 #endif