cleaning up mixed tabs and spaces
[freeglut] / progs / demos / shapes / shapes.c
index c6527fc..69c0a1a 100644 (file)
@@ -5,16 +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
       -    <tt>p P &nbsp;</tt> Toggle perspective or orthographic projection
       -    <tt>r R &nbsp;</tt> Toggle fixed or animated rotation around model X-axis
    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
@@ -32,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
 */
@@ -42,6 +44,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stddef.h>
 
 #include "glmatrix.h"
 
 
 #include "glmatrix.h"
 
 #include <crtdbg.h>
 #endif
 
 #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, 
+ * OpenGL 2+ shader mode needs some function and macro definitions,
  * avoiding a dependency on additional libraries like GLEW or the
  * GL/glext.h header
  */
  * avoiding a dependency on additional libraries like GLEW or the
  * GL/glext.h header
  */
@@ -82,9 +94,7 @@ typedef char ourGLchar;
 #define APIENTRY
 #endif
 
 #define APIENTRY
 #endif
 
-typedef void (APIENTRY *PFNGLGENBUFFERSPROC) (GLsizei n, GLuint *buffers);
-typedef void (APIENTRY *PFNGLBINDBUFFERPROC) (GLenum target, GLuint buffer);
-typedef void (APIENTRY *PFNGLBUFFERDATAPROC) (GLenum target, ourGLsizeiptr size, const GLvoid *data, GLenum usage);
+#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 *PFNGLCREATESHADERPROC) (GLenum type);
 typedef void (APIENTRY *PFNGLSHADERSOURCEPROC) (GLuint shader, GLsizei count, const ourGLchar **string, const GLint *length);
 typedef void (APIENTRY *PFNGLCOMPILESHADERPROC) (GLuint shader);
@@ -100,6 +110,7 @@ typedef GLint (APIENTRY *PFNGLGETATTRIBLOCATIONPROC) (GLuint program, const ourG
 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);
 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;
 
 PFNGLCREATESHADERPROC gl_CreateShader;
 PFNGLSHADERSOURCEPROC gl_ShaderSource;
@@ -134,6 +145,11 @@ void initExtensionEntries(void)
     gl_GetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) glutGetProcAddress ("glGetUniformLocation");
     gl_UniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) glutGetProcAddress ("glUniformMatrix4fv");
     gl_UniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) glutGetProcAddress ("glUniformMatrix3fv");
     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[] = {
 }
 
 const ourGLchar *vertexShaderSource[] = {
@@ -144,9 +160,9 @@ const ourGLchar *vertexShaderSource[] = {
     " */",
     "attribute vec3 fg_coord;",
     "attribute vec3 fg_normal;",
     " */",
     "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",
+    "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()",
     "uniform mat3 m_3x3_inv_transp;",
     " ",
     "void main()",
@@ -155,7 +171,7 @@ const ourGLchar *vertexShaderSource[] = {
     "  position = m * fg_coord4;",
     "  varyingNormalDirection = normalize(m_3x3_inv_transp * fg_normal);",
     " ",
     "  position = m * fg_coord4;",
     "  varyingNormalDirection = normalize(m_3x3_inv_transp * fg_normal);",
     " ",
-    "  mat4 mvp = p*m;   // normally p*v*m",
+    "  mat4 mvp = p*m;   /* normally p*v*m */",
     "  gl_Position = mvp * fg_coord4;",
     "}"
 };
     "  gl_Position = mvp * fg_coord4;",
     "}"
 };
@@ -166,9 +182,9 @@ const ourGLchar *fragmentShaderSource[] = {
     " * This file is in the public domain.",
     " * Contributors: Martin Kraus, Sylvain Beucler",
     " */",
     " * 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",
+    "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",
     "{",
     " ",
     "struct lightSource",
     "{",
@@ -181,13 +197,13 @@ const ourGLchar *fragmentShaderSource[] = {
     "};",
     "lightSource light0 = lightSource(",
     "  vec4(2.0, 5.0, 5.0, 0.0),",
     "};",
     "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,",
+    "  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)",
     ");",
     "  180.0, 0.0,",
     "  vec3(0.0, 0.0, 0.0)",
     ");",
-    "vec4 scene_ambient = vec4(1.0, 0.0, 0.0, 1.0);",
+    "vec4 scene_ambient = vec4(0.2, 0.2, 0.2, 1.0);",
     " ",
     "struct material",
     "{",
     " ",
     "struct material",
     "{",
@@ -197,8 +213,8 @@ const ourGLchar *fragmentShaderSource[] = {
     "  float shininess;",
     "};",
     "material frontMaterial = material(",
     "  float shininess;",
     "};",
     "material frontMaterial = material(",
-    "  vec4(0.7, 0.7, 0.7, 1.0),",
-    "  vec4(0.8, 0.8, 0.8, 1.0),",
+    "  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",
     ");",
     "  vec4(1.0, 1.0, 1.0, 1.0),",
     "  100.0",
     ");",
@@ -206,17 +222,17 @@ const ourGLchar *fragmentShaderSource[] = {
     "void main()",
     "{",
     "  vec3 normalDirection = normalize(varyingNormalDirection);",
     "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 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;",
     " ",
     "  vec3 lightDirection;",
     "  float attenuation;",
     " ",
-    "  if (0.0 == light0.position.w) // directional light?",
+    "  if (0.0 == light0.position.w) /* directional light? */",
     "    {",
     "    {",
-    "      attenuation = 1.0; // no attenuation",
+    "      attenuation = 1.0; /* no attenuation */",
     "      lightDirection = normalize(vec3(light0.position));",
     "    } ",
     "      lightDirection = normalize(vec3(light0.position));",
     "    } ",
-    "  else // point light or spotlight (or other kind of light) ",
+    "  else /* point light or spotlight (or other kind of light) */",
     "    {",
     "      vec3 positionToLightSource = vec3(light0.position - position);",
     "      float distance = length(positionToLightSource);",
     "    {",
     "      vec3 positionToLightSource = vec3(light0.position - position);",
     "      float distance = length(positionToLightSource);",
@@ -225,10 +241,10 @@ const ourGLchar *fragmentShaderSource[] = {
     "                           + light0.linearAttenuation * distance",
     "                           + light0.quadraticAttenuation * distance * distance);",
     " ",
     "                           + light0.linearAttenuation * distance",
     "                           + light0.quadraticAttenuation * distance * distance);",
     " ",
-    "      if (light0.spotCutoff <= 90.0) // spotlight?",
+    "      if (light0.spotCutoff <= 90.0) /* spotlight? */",
     "        {",
     "          float clampedCosine = max(0.0, dot(-lightDirection, light0.spotDirection));",
     "        {",
     "          float clampedCosine = max(0.0, dot(-lightDirection, light0.spotDirection));",
-    "          if (clampedCosine < cos(radians(light0.spotCutoff))) // outside of spotlight cone?",
+    "          if (clampedCosine < cos(radians(light0.spotCutoff))) /* outside of spotlight cone? */",
     "            {",
     "              attenuation = 0.0;",
     "            }",
     "            {",
     "              attenuation = 0.0;",
     "            }",
@@ -246,11 +262,11 @@ const ourGLchar *fragmentShaderSource[] = {
     "    * max(0.0, dot(normalDirection, lightDirection));",
     " ",
     "  vec3 specularReflection;",
     "    * max(0.0, dot(normalDirection, lightDirection));",
     " ",
     "  vec3 specularReflection;",
-    "  if (dot(normalDirection, lightDirection) < 0.0) // light source on the wrong side?",
+    "  if (dot(normalDirection, lightDirection) < 0.0) /* light source on the wrong side? */",
     "    {",
     "    {",
-    "      specularReflection = vec3(0.0, 0.0, 0.0); // no specular reflection",
+    "      specularReflection = vec3(0.0, 0.0, 0.0); /* no specular reflection */",
     "    }",
     "    }",
-    "  else // light source on the right side",
+    "  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);",
     "    {",
     "      specularReflection = attenuation * vec3(light0.specular) * vec3(frontMaterial.specular) ",
     "        * pow(max(0.0, dot(reflect(-lightDirection, normalDirection), viewDirection)), frontMaterial.shininess);",
@@ -267,9 +283,10 @@ GLint getAttribOrUniformLocation(const char* name, GLuint program, GLboolean isA
         GLint attrib = gl_GetAttribLocation(program, name);
         if (attrib == -1)
         {
         GLint attrib = gl_GetAttribLocation(program, name);
         if (attrib == -1)
         {
-            fprintf(stderr, "Warning: Could not bind attrib %s\n", name);  
+            fprintf(stderr, "Warning: Could not bind attrib %s\n", name);
         }
 
         }
 
+        checkError ("getAttribOrUniformLocation");
         return attrib;
     }
     else
         return attrib;
     }
     else
@@ -277,17 +294,18 @@ GLint getAttribOrUniformLocation(const char* name, GLuint program, GLboolean isA
         GLint uniform = gl_GetUniformLocation(program, name);
         if (uniform == -1)
         {
         GLint uniform = gl_GetUniformLocation(program, name);
         if (uniform == -1)
         {
-            fprintf(stderr, "Warning: Could not bind uniform %s\n", name);  
+            fprintf(stderr, "Warning: Could not bind uniform %s\n", name);
         }
 
         }
 
+        checkError ("getAttribOrUniformLocation");
         return uniform;
     }
 }
 
 GLuint program;
         return uniform;
     }
 }
 
 GLuint program;
-GLint attribute_fg_coord = -1, attribute_fg_normal = -1;  
+GLint attribute_fg_coord = -1, attribute_fg_normal = -1;
 GLint uniform_m = -1, uniform_p = -1, uniform_m_3x3_inv_transp = -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 somehow unusable.
+GLint shaderReady = 0;  /* Set to 1 when all initialization went well, to -1 when shader somehow unusable. */
 
 
 
 
 
 
@@ -305,12 +323,16 @@ void compileAndCheck(GLuint shader)
         fprintf (stderr, "compile log: %s\n", infoLog);
         free (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);
 }
 
 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;
 }
     compileAndCheck (shader);
     return shader;
 }
@@ -329,6 +351,7 @@ void linkAndCheck(GLuint program)
         fprintf (stderr, "link log: %s\n", infoLog);
         free (infoLog);
     }
         fprintf (stderr, "link log: %s\n", infoLog);
         free (infoLog);
     }
+    checkError ("linkAndCheck");
 }
 
 void createProgram(GLuint vertexShader, GLuint fragmentShader)
 }
 
 void createProgram(GLuint vertexShader, GLuint fragmentShader)
@@ -340,6 +363,9 @@ void createProgram(GLuint vertexShader, GLuint fragmentShader)
     if (fragmentShader != 0) {
         gl_AttachShader (program, fragmentShader);
     }
     if (fragmentShader != 0) {
         gl_AttachShader (program, fragmentShader);
     }
+
+    checkError ("createProgram");
+
     linkAndCheck (program);
 }
 
     linkAndCheck (program);
 }
 
@@ -353,6 +379,8 @@ void initShader(void)
     GLuint fragmentShader =
         compileShaderSource (GL_FRAGMENT_SHADER, fragmentShaderLines, fragmentShaderSource);
 
     GLuint fragmentShader =
         compileShaderSource (GL_FRAGMENT_SHADER, fragmentShaderLines, fragmentShaderSource);
 
+    checkError ("initShader - 1");
+
     createProgram (vertexShader, fragmentShader);
 
     gl_UseProgram (program);
     createProgram (vertexShader, fragmentShader);
 
     gl_UseProgram (program);
@@ -370,6 +398,8 @@ void initShader(void)
         shaderReady = -1;
     else
         shaderReady = 1;
         shaderReady = -1;
     else
         shaderReady = 1;
+
+    checkError ("initShader - 2");
 }
 
 /*
 }
 
 /*
@@ -394,6 +424,18 @@ static float ar;
 static GLboolean persProject = GL_TRUE;
 static GLboolean animateXRot = GL_FALSE;
 static GLboolean useShader   = GL_FALSE;
 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
 
 /*
  * These one-liners draw particular objects, fetching appropriate
@@ -418,77 +460,77 @@ static void drawSolidTorus(void)               { glutSolidTorus(irad,orad,slices
 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 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(orad,orad,slices,stacks);         }  /* orad doubles as size input */
-static void drawWireCone(void)                 { glutWireCone(orad,orad,slices,stacks);          }  /* orad doubles as size input */
-static void drawSolidCylinder(void)            { glutSolidCylinder(orad,orad,slices,stacks);     }  /* orad doubles as size input */
-static void drawWireCylinder(void)             { glutWireCylinder(orad,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)
 static void drawSolidTeapot(void)
-{
-    /* per Glut manpage, it should be noted that the teapot is rendered
-     * with clockwise winding for front facing polygons...
-     */
-    glFrontFace(GL_CW);
-    glutSolidTeapot(orad);  /* orad doubles as size input */
-    glFrontFace(GL_CCW);
-}
+{   glFrontFace(GL_CW);    glutSolidTeapot(orad);   glFrontFace(GL_CCW);    /* orad doubles as size input */}
 static void drawWireTeapot(void)
 static void drawWireTeapot(void)
-{
-    /* per Glut manpage, it should be noted that the teapot is rendered
-     * with clockwise winding for front facing polygons...
-     */
-    glFrontFace(GL_CW);
-    glutWireTeapot(orad);  /* orad doubles as size input */
-    glFrontFace(GL_CCW);
-}
-
-#define RADIUS    1.0f
+{   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)
 {
+  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();
 }
 
 static void drawWireCuboctahedron(void)
 {
   glEnd();
 }
 
 static void drawWireCuboctahedron(void)
 {
+  GLfloat radius = RADIUSFAC*(GLfloat)orad; /* orad doubles as size */
   glBegin( GL_LINE_LOOP );
   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 );
+    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 );
   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 );
+    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 );
   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 );
+    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 );
   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 );
+    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 );
   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 );
+    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 );
   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 );
+    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
+#undef RADIUSFAC
 
 /*
  * This structure defines an entry in our function-table.
 
 /*
  * This structure defines an entry in our function-table.
@@ -498,24 +540,27 @@ 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
 
@@ -565,8 +610,61 @@ 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)
 {
@@ -578,20 +676,23 @@ resize(int width, int height)
 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 b = (animateXRot?t:1)*60.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);
 
+    glutSetOption(GLUT_GEOMETRY_VISUALIZE_NORMALS,visNormals);  /* Normals visualized or not? */
+
     if (useShader && !shaderReady)
         initShader();
 
     if (useShader && shaderReady)
     {
     if (useShader && !shaderReady)
         initShader();
 
     if (useShader && shaderReady)
     {
-        // setup use of shader (and vertex buffer by FreeGLUT)
+        /* setup use of shader (and vertex buffer by FreeGLUT) */
         gl_UseProgram (program);
         glutSetVertexAttribCoord3(attribute_fg_coord);
         glutSetVertexAttribNormal(attribute_fg_normal);
         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();
 
         gl_matrix_mode(GL_PROJECTION);
         gl_load_identity();
@@ -627,6 +728,8 @@ static void display(void)
         gl_UseProgram (0);
         glutSetVertexAttribCoord3(-1);
         glutSetVertexAttribNormal(-1);
         gl_UseProgram (0);
         glutSetVertexAttribCoord3(-1);
         glutSetVertexAttribNormal(-1);
+
+        checkError ("display");
     }
     else
     {
     }
     else
     {
@@ -662,24 +765,12 @@ static void display(void)
         glColor3d(0.1,0.1,0.4);
     }
 
         glColor3d(0.1,0.1,0.4);
     }
 
-    if( show_info ) {
-        shapesPrintf (1, 1, "Shape PgUp PgDn: %s", table [function_index].name);
-        shapesPrintf (2, 1, "Slices +-: %d   Stacks <>: %d", slices, stacks);
-        shapesPrintf (3, 1, "nSides +-: %d   nRings <>: %d", slices, stacks);
-        shapesPrintf (4, 1, "Depth  (): %d", depth);
-        shapesPrintf (5, 1, "Outer radius  Up  Down : %f", orad);
-        shapesPrintf (6, 1, "Inner radius Left Right: %f", irad);
-        if (persProject)
-            shapesPrintf (7, 1, "Perspective projection");
-        else
-            shapesPrintf (7, 1, "Orthographic projection");
-        if (useShader)
-            shapesPrintf (8, 1, "Using shader");
-        else
-            shapesPrintf (8, 1, "Using fixed function pipeline");
-    } 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();
 }
@@ -709,10 +800,10 @@ 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 'P':
     case ')': ++depth;                    break;
 
     case 'P':
@@ -722,7 +813,15 @@ key(unsigned char key, int x, int y)
     case 'r': animateXRot=!animateXRot;   break;
 
     case 'S':
     case 'r': animateXRot=!animateXRot;   break;
 
     case 'S':
-    case 's': useShader=!useShader;       break;
+    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;
@@ -752,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;
+    }
 }
 
 
 }
 
 
@@ -776,7 +884,7 @@ 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);
     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);
     glutInitWindowPosition(40,40);
     glutInit(&argc, argv);
     glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH | GLUT_MULTISAMPLE);