shapes demo: added flat shading option (fixed-function only)
[freeglut] / progs / demos / shapes / shapes.c
index 7326914..09fb5ef 100644 (file)
@@ -5,16 +5,18 @@
     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.
+
    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
@@ -32,7 +34,7 @@
 
     \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
 */
@@ -42,6 +44,7 @@
 #include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <stddef.h>
 
 #include "glmatrix.h"
 
@@ -60,7 +63,7 @@ void checkError(const char *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
  */
@@ -91,9 +94,7 @@ typedef char ourGLchar;
 #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);
@@ -109,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);
+#endif
 
 PFNGLCREATESHADERPROC gl_CreateShader;
 PFNGLSHADERSOURCEPROC gl_ShaderSource;
@@ -143,6 +145,11 @@ void initExtensionEntries(void)
     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[] = {
@@ -190,13 +197,13 @@ const ourGLchar *fragmentShaderSource[] = {
     "};",
     "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)",
     ");",
-    "vec4 scene_ambient = vec4(0.0, 0.0, 0.0, 1.0);",
+    "vec4 scene_ambient = vec4(0.2, 0.2, 0.2, 1.0);",
     " ",
     "struct material",
     "{",
@@ -276,9 +283,10 @@ GLint getAttribOrUniformLocation(const char* name, GLuint program, GLboolean isA
         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
@@ -286,16 +294,16 @@ GLint getAttribOrUniformLocation(const char* name, GLuint program, GLboolean isA
         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;
     }
-    checkError ("getAttribOrUniformLocation");
 }
 
 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 shaderReady = 0;  /* Set to 1 when all initialization went well, to -1 when shader somehow unusable. */
 
@@ -416,6 +424,19 @@ static float ar;
 static GLboolean persProject = GL_TRUE;
 static GLboolean animateXRot = GL_FALSE;
 static GLboolean useShader   = GL_FALSE;
+static GLboolean visNormals  = GL_FALSE;
+static GLboolean flat;
+
+/*
+ * 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
@@ -440,77 +461,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 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)
-{
-    /* 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)
-{
-    /* 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)
 {
+  GLfloat radius = RADIUSFAC*(GLfloat)orad; /* orad doubles as size */
   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 );
-    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)
 {
+  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 );
+    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 );
+    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 );
+    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 );
+    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 );
+    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 );
+    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 RADIUS
+#undef RADIUSFAC
 
 /*
  * This structure defines an entry in our function-table.
@@ -520,24 +541,27 @@ typedef struct
     const char * const name;
     void (*solid) (void);
     void (*wire)  (void);
+    int drawSizeInfoFlag;
 } entry;
 
-#define ENTRY(e) {#e, drawSolid##e, drawWire##e}
+#define ENTRY(e,f) {#e, drawSolid##e, drawWire##e,f}
 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
 
@@ -587,8 +611,66 @@ static void shapesPrintf (int row, int col, const char *fmt, ...)
     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 (flat)
+            shapesPrintf (row++, 1, "Flat shading (f)");
+        else
+            shapesPrintf (row++, 1, "Smooth shading (f)");
+    }
+    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)
 {
@@ -600,11 +682,15 @@ resize(int width, int height)
 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);
 
+    glutSetOption(GLUT_GEOMETRY_VISUALIZE_NORMALS,visNormals);  /* Normals visualized or not? */
+
+    glShadeModel(flat ? GL_FLAT : GL_SMOOTH);  /* flat or gouraud shading */
+
     if (useShader && !shaderReady)
         initShader();
 
@@ -614,6 +700,7 @@ static void display(void)
         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();
@@ -686,24 +773,12 @@ static void display(void)
         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 ) ;
-    }
 
     glutSwapBuffers();
 }
@@ -733,10 +808,10 @@ key(unsigned char key, int x, int y)
     case '.':
     case '>': stacks++;                   break;
 
-    case '9': 
+    case '9':
     case '(': if( depth > -1 ) depth--;   break;
 
-    case '0': 
+    case '0':
     case ')': ++depth;                    break;
 
     case 'P':
@@ -746,7 +821,20 @@ key(unsigned char key, int x, int y)
     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 'F':
+    case 'f':
+        flat ^= 1;
+        break;
+
+    case 'N':
+    case 'n': visNormals=!visNormals;     break;
 
     default:
         break;
@@ -776,6 +864,15 @@ static void special (int key, int x, int y)
 
     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;
+    }
 }
 
 
@@ -800,7 +897,7 @@ const GLfloat high_shininess[] = { 100.0f };
 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);