Fixing a bug in the Sierpinski sponge code that made the application crash if called...
[freeglut] / src / freeglut_geometry.c
index 36f6a78..b41b5b7 100644 (file)
  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  */
 
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "../include/GL/freeglut.h"
-
-
+#include <GL/freeglut.h>
 #include "freeglut_internal.h"
 
 /*
@@ -74,12 +68,12 @@ void FGAPIENTRY glutWireCube( GLdouble dSize )
 {
     double size = dSize * 0.5;
 
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCube" );
+
 #   define V(a,b,c) glVertex3d( a size, b size, c size );
 #   define N(a,b,c) glNormal3d( a, b, c );
 
-    /*
-     * PWO: I dared to convert the code to use macros...
-     */
+    /* PWO: I dared to convert the code to use macros... */
     glBegin( GL_LINE_LOOP ); N( 1.0, 0.0, 0.0); V(+,-,+); V(+,-,-); V(+,+,-); V(+,+,+); glEnd();
     glBegin( GL_LINE_LOOP ); N( 0.0, 1.0, 0.0); V(+,+,+); V(+,+,-); V(-,+,-); V(-,+,+); glEnd();
     glBegin( GL_LINE_LOOP ); N( 0.0, 0.0, 1.0); V(+,+,+); V(-,+,+); V(-,-,+); V(+,-,+); glEnd();
@@ -98,12 +92,12 @@ void FGAPIENTRY glutSolidCube( GLdouble dSize )
 {
     double size = dSize * 0.5;
 
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCube" );
+
 #   define V(a,b,c) glVertex3d( a size, b size, c size );
 #   define N(a,b,c) glNormal3d( a, b, c );
 
-    /*
-     * PWO: Again, I dared to convert the code to use macros...
-     */
+    /* PWO: Again, I dared to convert the code to use macros... */
     glBegin( GL_QUADS );
         N( 1.0, 0.0, 0.0); V(+,-,+); V(+,-,-); V(+,+,-); V(+,+,+);
         N( 0.0, 1.0, 0.0); V(+,+,+); V(+,+,-); V(-,+,-); V(-,+,+);
@@ -127,7 +121,7 @@ void FGAPIENTRY glutSolidCube( GLdouble dSize )
  *    The sign of n can be flipped to get the reverse loop
  */
 
-static void circleTable(double **sint,double **cost,const int n)
+static void fghCircleTable(double **sint,double **cost,const int n)
 {
     int i;
 
@@ -137,7 +131,7 @@ static void circleTable(double **sint,double **cost,const int n)
 
     /* Determine the angle between samples */
 
-    const double angle = 2*M_PI/(double)n;
+    const double angle = 2*M_PI/(double)( ( n == 0 ) ? 1 : n );
 
     /* Allocate memory for n samples, plus duplicate of first entry at the end */
 
@@ -150,12 +144,15 @@ static void circleTable(double **sint,double **cost,const int n)
     {
         free(*sint);
         free(*cost);
-        fgError("Failed to allocate memory in circleTable");
+        fgError("Failed to allocate memory in fghCircleTable");
     }
 
     /* Compute cos and sin around the circle */
 
-    for (i=0; i<size; i++)
+    (*sint)[0] = 0.0;
+    (*cost)[0] = 1.0;
+
+    for (i=1; i<size; i++)
     {
         (*sint)[i] = sin(angle*i);
         (*cost)[i] = cos(angle*i);
@@ -183,15 +180,18 @@ void FGAPIENTRY glutSolidSphere(GLdouble radius, GLint slices, GLint stacks)
 
     double *sint1,*cost1;
     double *sint2,*cost2;
-    circleTable(&sint1,&cost1,-slices);
-    circleTable(&sint2,&cost2,stacks*2);
+
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSphere" );
+
+    fghCircleTable(&sint1,&cost1,-slices);
+    fghCircleTable(&sint2,&cost2,stacks*2);
 
     /* The top stack is covered with a triangle fan */
 
     z0 = 1.0;
-    z1 = cost2[1];
+    z1 = cost2[(stacks>0)?1:0];
     r0 = 0.0;
-    r1 = sint2[1];
+    r1 = sint2[(stacks>0)?1:0];
 
     glBegin(GL_TRIANGLE_FAN);
 
@@ -199,7 +199,7 @@ void FGAPIENTRY glutSolidSphere(GLdouble radius, GLint slices, GLint stacks)
         glVertex3d(0,0,radius);
 
         for (j=slices; j>=0; j--)
-        {       
+        {
             glNormal3d(cost1[j]*r1,        sint1[j]*r1,        z1       );
             glVertex3d(cost1[j]*r1*radius, sint1[j]*r1*radius, z1*radius);
         }
@@ -253,7 +253,7 @@ void FGAPIENTRY glutSolidSphere(GLdouble radius, GLint slices, GLint stacks)
 }
 
 /*
- * Draws a solid sphere
+ * Draws a wire sphere
  */
 void FGAPIENTRY glutWireSphere(GLdouble radius, GLint slices, GLint stacks)
 {
@@ -265,11 +265,14 @@ void FGAPIENTRY glutWireSphere(GLdouble radius, GLint slices, GLint stacks)
     double x,y,z;
 
     /* Pre-computed circle */
-        
+
     double *sint1,*cost1;
     double *sint2,*cost2;
-    circleTable(&sint1,&cost1,-slices  );
-    circleTable(&sint2,&cost2, stacks*2);
+
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSphere" );
+
+    fghCircleTable(&sint1,&cost1,-slices  );
+    fghCircleTable(&sint2,&cost2, stacks*2);
 
     /* Draw a line loop for each stack */
 
@@ -331,8 +334,8 @@ void FGAPIENTRY glutSolidCone( GLdouble base, GLdouble height, GLint slices, GLi
     double z0,z1;
     double r0,r1;
 
-    const double zStep = height/stacks;
-    const double rStep = base/stacks;
+    const double zStep = height / ( ( stacks > 0 ) ? stacks : 1 );
+    const double rStep = base / ( ( stacks > 0 ) ? stacks : 1 );
 
     /* Scaling factors for vertex normals */
 
@@ -342,7 +345,10 @@ void FGAPIENTRY glutSolidCone( GLdouble base, GLdouble height, GLint slices, GLi
     /* Pre-computed circle */
 
     double *sint,*cost;
-    circleTable(&sint,&cost,-slices);
+
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCone" );
+
+    fghCircleTable(&sint,&cost,-slices);
 
     /* Cover the circular base with a triangle fan... */
 
@@ -415,8 +421,8 @@ void FGAPIENTRY glutWireCone( GLdouble base, GLdouble height, GLint slices, GLin
     double z = 0.0;
     double r = base;
 
-    const double zStep = height/stacks;
-    const double rStep = base/stacks;
+    const double zStep = height / ( ( stacks > 0 ) ? stacks : 1 );
+    const double rStep = base / ( ( stacks > 0 ) ? stacks : 1 );
 
     /* Scaling factors for vertex normals */
 
@@ -426,7 +432,10 @@ void FGAPIENTRY glutWireCone( GLdouble base, GLdouble height, GLint slices, GLin
     /* Pre-computed circle */
 
     double *sint,*cost;
-    circleTable(&sint,&cost,-slices);
+
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCone" );
+
+    fghCircleTable(&sint,&cost,-slices);
 
     /* Draw the stacks... */
 
@@ -477,13 +486,16 @@ void FGAPIENTRY glutSolidCylinder(GLdouble radius, GLdouble height, GLint slices
 
     /* Step in z and radius as stacks are drawn. */
 
-          double z0,z1;
-    const double zStep = height/stacks;
+    double z0,z1;
+    const double zStep = height / ( ( stacks > 0 ) ? stacks : 1 );
 
     /* Pre-computed circle */
 
     double *sint,*cost;
-    circleTable(&sint,&cost,-slices);
+
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCylinder" );
+
+    fghCircleTable(&sint,&cost,-slices);
 
     /* Cover the base and top */
 
@@ -531,7 +543,7 @@ void FGAPIENTRY glutSolidCylinder(GLdouble radius, GLdouble height, GLint slices
 
 /*
  * Draws a wire cylinder
-   */
+ */
 void FGAPIENTRY glutWireCylinder(GLdouble radius, GLdouble height, GLint slices, GLint stacks)
 {
     int i,j;
@@ -539,12 +551,15 @@ void FGAPIENTRY glutWireCylinder(GLdouble radius, GLdouble height, GLint slices,
     /* Step in z and radius as stacks are drawn. */
 
           double z = 0.0;
-    const double zStep = height/stacks;
+    const double zStep = height / ( ( stacks > 0 ) ? stacks : 1 );
 
     /* Pre-computed circle */
 
     double *sint,*cost;
-    circleTable(&sint,&cost,-slices);
+
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCylinder" );
+
+    fghCircleTable(&sint,&cost,-slices);
 
     /* Draw the stacks... */
 
@@ -586,7 +601,7 @@ void FGAPIENTRY glutWireCylinder(GLdouble radius, GLdouble height, GLint slices,
 }
 
 /*
- *
+ * Draws a wire torus
  */
 void FGAPIENTRY glutWireTorus( GLdouble dInnerRadius, GLdouble dOuterRadius, GLint nSides, GLint nRings )
 {
@@ -595,9 +610,12 @@ void FGAPIENTRY glutWireTorus( GLdouble dInnerRadius, GLdouble dOuterRadius, GLi
   int    i, j;
   double spsi, cpsi, sphi, cphi ;
 
-  /*
-   * Allocate the vertices array
-   */
+  FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTorus" );
+
+  if ( nSides < 1 ) nSides = 1;
+  if ( nRings < 1 ) nRings = 1;
+
+  /* Allocate the vertices array */
   vertex = (double *)calloc( sizeof(double), 3 * nSides * nRings );
   normal = (double *)calloc( sizeof(double), 3 * nSides * nRings );
 
@@ -664,7 +682,7 @@ void FGAPIENTRY glutWireTorus( GLdouble dInnerRadius, GLdouble dOuterRadius, GLi
 }
 
 /*
- *
+ * Draws a solid torus
  */
 void FGAPIENTRY glutSolidTorus( GLdouble dInnerRadius, GLdouble dOuterRadius, GLint nSides, GLint nRings )
 {
@@ -673,15 +691,16 @@ void FGAPIENTRY glutSolidTorus( GLdouble dInnerRadius, GLdouble dOuterRadius, GL
   int    i, j;
   double spsi, cpsi, sphi, cphi ;
 
-  /*
-   * Increment the number of sides and rings to allow for one more point than surface
-   */
+  FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTorus" );
+
+  if ( nSides < 1 ) nSides = 1;
+  if ( nRings < 1 ) nRings = 1;
+
+  /* Increment the number of sides and rings to allow for one more point than surface */
   nSides ++ ;
   nRings ++ ;
 
-  /*
-   * Allocate the vertices array
-   */
+  /* Allocate the vertices array */
   vertex = (double *)calloc( sizeof(double), 3 * nSides * nRings );
   normal = (double *)calloc( sizeof(double), 3 * nSides * nRings );
 
@@ -743,10 +762,13 @@ void FGAPIENTRY glutSolidTorus( GLdouble dInnerRadius, GLdouble dOuterRadius, GL
  */
 void FGAPIENTRY glutWireDodecahedron( void )
 {
+  FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireDodecahedron" );
+
   /* Magic Numbers:  It is possible to create a dodecahedron by attaching two pentagons to each face of
    * of a cube.  The coordinates of the points are:
    *   (+-x,0, z); (+-1, 1, 1); (0, z, x )
-   * where x = 0.61803398875 and z = 1.61803398875.
+   * where x = (-1 + sqrt(5))/2, z = (1 + sqrt(5))/2  or
+   *       x = 0.61803398875 and z = 1.61803398875.
    */
   glBegin ( GL_LINE_LOOP ) ;
   glNormal3d (  0.0,  0.525731112119,  0.850650808354 ) ; glVertex3d (  0.0,  1.61803398875,  0.61803398875 ) ; glVertex3d ( -1.0,  1.0,  1.0 ) ; glVertex3d ( -0.61803398875, 0.0,  1.61803398875 ) ; glVertex3d (  0.61803398875, 0.0,  1.61803398875 ) ; glVertex3d (  1.0,  1.0,  1.0 ) ;
@@ -793,10 +815,13 @@ void FGAPIENTRY glutWireDodecahedron( void )
  */
 void FGAPIENTRY glutSolidDodecahedron( void )
 {
+  FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidDodecahedron" );
+
   /* Magic Numbers:  It is possible to create a dodecahedron by attaching two pentagons to each face of
    * of a cube.  The coordinates of the points are:
    *   (+-x,0, z); (+-1, 1, 1); (0, z, x )
-   * where x = 0.61803398875 and z = 1.61803398875.
+   * where x = (-1 + sqrt(5))/2, z = (1 + sqrt(5))/2 or
+   *       x = 0.61803398875 and z = 1.61803398875.
    */
   glBegin ( GL_POLYGON ) ;
   glNormal3d (  0.0,  0.525731112119,  0.850650808354 ) ; glVertex3d (  0.0,  1.61803398875,  0.61803398875 ) ; glVertex3d ( -1.0,  1.0,  1.0 ) ; glVertex3d ( -0.61803398875, 0.0,  1.61803398875 ) ; glVertex3d (  0.61803398875, 0.0,  1.61803398875 ) ; glVertex3d (  1.0,  1.0,  1.0 ) ;
@@ -843,16 +868,18 @@ void FGAPIENTRY glutSolidDodecahedron( void )
  */
 void FGAPIENTRY glutWireOctahedron( void )
 {
+  FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireOctahedron" );
+
 #define RADIUS    1.0f
   glBegin( GL_LINE_LOOP );
     glNormal3d( 0.577350269189, 0.577350269189, 0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS );
-    glNormal3d( 0.577350269189, 0.577350269189,-0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS );
-    glNormal3d( 0.577350269189,-0.577350269189, 0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS );
+    glNormal3d( 0.577350269189, 0.577350269189,-0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS ); glVertex3d( 0.0, RADIUS, 0.0 );
+    glNormal3d( 0.577350269189,-0.577350269189, 0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS ); glVertex3d( 0.0,-RADIUS, 0.0 );
     glNormal3d( 0.577350269189,-0.577350269189,-0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS );
-    glNormal3d(-0.577350269189, 0.577350269189, 0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS );
+    glNormal3d(-0.577350269189, 0.577350269189, 0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS ); glVertex3d( 0.0, RADIUS, 0.0 );
     glNormal3d(-0.577350269189, 0.577350269189,-0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS );
     glNormal3d(-0.577350269189,-0.577350269189, 0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS );
-    glNormal3d(-0.577350269189,-0.577350269189,-0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS );
+    glNormal3d(-0.577350269189,-0.577350269189,-0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS ); glVertex3d( 0.0,-RADIUS, 0.0 );
   glEnd();
 #undef RADIUS
 }
@@ -862,45 +889,56 @@ void FGAPIENTRY glutWireOctahedron( void )
  */
 void FGAPIENTRY glutSolidOctahedron( void )
 {
+  FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidOctahedron" );
+
 #define RADIUS    1.0f
   glBegin( GL_TRIANGLES );
     glNormal3d( 0.577350269189, 0.577350269189, 0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS );
-    glNormal3d( 0.577350269189, 0.577350269189,-0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS );
-    glNormal3d( 0.577350269189,-0.577350269189, 0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS );
+    glNormal3d( 0.577350269189, 0.577350269189,-0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS ); glVertex3d( 0.0, RADIUS, 0.0 );
+    glNormal3d( 0.577350269189,-0.577350269189, 0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS ); glVertex3d( 0.0,-RADIUS, 0.0 );
     glNormal3d( 0.577350269189,-0.577350269189,-0.577350269189); glVertex3d( RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS );
-    glNormal3d(-0.577350269189, 0.577350269189, 0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS );
+    glNormal3d(-0.577350269189, 0.577350269189, 0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS ); glVertex3d( 0.0, RADIUS, 0.0 );
     glNormal3d(-0.577350269189, 0.577350269189,-0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS );
     glNormal3d(-0.577350269189,-0.577350269189, 0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0, RADIUS );
-    glNormal3d(-0.577350269189,-0.577350269189,-0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0,-RADIUS, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS );
+    glNormal3d(-0.577350269189,-0.577350269189,-0.577350269189); glVertex3d(-RADIUS, 0.0, 0.0 ); glVertex3d( 0.0, 0.0,-RADIUS ); glVertex3d( 0.0,-RADIUS, 0.0 );
   glEnd();
 #undef RADIUS
 }
 
+/* Magic Numbers:  r0 = ( 1, 0, 0 )
+ *                 r1 = ( -1/3, 2 sqrt(2) / 3, 0 )
+ *                 r2 = ( -1/3, -sqrt(2) / 3, sqrt(6) / 3 )
+ *                 r3 = ( -1/3, -sqrt(2) / 3, -sqrt(6) / 3 )
+ * |r0| = |r1| = |r2| = |r3| = 1
+ * Distance between any two points is 2 sqrt(6) / 3
+ *
+ * Normals:  The unit normals are simply the negative of the coordinates of the point not on the surface.
+ */
+
+#define NUM_TETR_FACES     4
+
+static GLdouble tet_r[4][3] = { {             1.0,             0.0,             0.0 },
+                                { -0.333333333333,  0.942809041582,             0.0 },
+                                { -0.333333333333, -0.471404520791,  0.816496580928 },
+                                { -0.333333333333, -0.471404520791, -0.816496580928 } } ;
+
+static GLint tet_i[4][3] =  /* Vertex indices */
+{
+  { 1, 3, 2 }, { 0, 2, 3 }, { 0, 3, 1 }, { 0, 1, 2 }
+} ;
+
 /*
  *
  */
 void FGAPIENTRY glutWireTetrahedron( void )
 {
-  /* Magic Numbers:  r0 = ( 1, 0, 0 )
-   *                 r1 = ( -1/3, 2 sqrt(2) / 3, 0 )
-   *                 r2 = ( -1/3, -sqrt(2) / 3, sqrt(6) / 3 )
-   *                 r3 = ( -1/3, -sqrt(2) / 3, -sqrt(6) / 3 )
-   * |r0| = |r1| = |r2| = |r3| = 1
-   * Distance between any two points is 2 sqrt(6) / 3
-   *
-   * Normals:  The unit normals are simply the negative of the coordinates of the point not on the surface.
-   */
-
-  double r0[3] = {             1.0,             0.0,             0.0 } ;
-  double r1[3] = { -0.333333333333,  0.942809041582,             0.0 } ;
-  double r2[3] = { -0.333333333333, -0.471404520791,  0.816496580928 } ;
-  double r3[3] = { -0.333333333333, -0.471404520791, -0.816496580928 } ;
+  FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTetrahedron" );
 
   glBegin( GL_LINE_LOOP ) ;
-    glNormal3d (           -1.0,             0.0,             0.0 ) ; glVertex3dv ( r1 ) ; glVertex3dv ( r3 ) ; glVertex3dv ( r2 ) ;
-    glNormal3d ( 0.333333333333, -0.942809041582,             0.0 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r2 ) ; glVertex3dv ( r3 ) ;
-    glNormal3d ( 0.333333333333,  0.471404520791, -0.816496580928 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r3 ) ; glVertex3dv ( r1 ) ;
-    glNormal3d ( 0.333333333333,  0.471404520791,  0.816496580928 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r1 ) ; glVertex3dv ( r2 ) ;
+    glNormal3d ( -tet_r[0][0], -tet_r[0][1], -tet_r[0][2] ) ; glVertex3dv ( tet_r[1] ) ; glVertex3dv ( tet_r[3] ) ; glVertex3dv ( tet_r[2] ) ;
+    glNormal3d ( -tet_r[1][0], -tet_r[1][1], -tet_r[1][2] ) ; glVertex3dv ( tet_r[0] ) ; glVertex3dv ( tet_r[2] ) ; glVertex3dv ( tet_r[3] ) ;
+    glNormal3d ( -tet_r[2][0], -tet_r[2][1], -tet_r[2][2] ) ; glVertex3dv ( tet_r[0] ) ; glVertex3dv ( tet_r[3] ) ; glVertex3dv ( tet_r[1] ) ;
+    glNormal3d ( -tet_r[3][0], -tet_r[3][1], -tet_r[3][2] ) ; glVertex3dv ( tet_r[0] ) ; glVertex3dv ( tet_r[1] ) ; glVertex3dv ( tet_r[2] ) ;
   glEnd() ;
 }
 
@@ -909,26 +947,13 @@ void FGAPIENTRY glutWireTetrahedron( void )
  */
 void FGAPIENTRY glutSolidTetrahedron( void )
 {
-  /* Magic Numbers:  r0 = ( 1, 0, 0 )
-   *                 r1 = ( -1/3, 2 sqrt(2) / 3, 0 )
-   *                 r2 = ( -1/3, -sqrt(2) / 3, sqrt(6) / 3 )
-   *                 r3 = ( -1/3, -sqrt(2) / 3, -sqrt(6) / 3 )
-   * |r0| = |r1| = |r2| = |r3| = 1
-   * Distance between any two points is 2 sqrt(6) / 3
-   *
-   * Normals:  The unit normals are simply the negative of the coordinates of the point not on the surface.
-   */
-
-  double r0[3] = {             1.0,             0.0,             0.0 } ;
-  double r1[3] = { -0.333333333333,  0.942809041582,             0.0 } ;
-  double r2[3] = { -0.333333333333, -0.471404520791,  0.816496580928 } ;
-  double r3[3] = { -0.333333333333, -0.471404520791, -0.816496580928 } ;
+  FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTetrahedron" );
 
   glBegin( GL_TRIANGLES ) ;
-    glNormal3d (           -1.0,             0.0,             0.0 ) ; glVertex3dv ( r1 ) ; glVertex3dv ( r3 ) ; glVertex3dv ( r2 ) ;
-    glNormal3d ( 0.333333333333, -0.942809041582,             0.0 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r2 ) ; glVertex3dv ( r3 ) ;
-    glNormal3d ( 0.333333333333,  0.471404520791, -0.816496580928 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r3 ) ; glVertex3dv ( r1 ) ;
-    glNormal3d ( 0.333333333333,  0.471404520791,  0.816496580928 ) ; glVertex3dv ( r0 ) ; glVertex3dv ( r1 ) ; glVertex3dv ( r2 ) ;
+    glNormal3d ( -tet_r[0][0], -tet_r[0][1], -tet_r[0][2] ) ; glVertex3dv ( tet_r[1] ) ; glVertex3dv ( tet_r[3] ) ; glVertex3dv ( tet_r[2] ) ;
+    glNormal3d ( -tet_r[1][0], -tet_r[1][1], -tet_r[1][2] ) ; glVertex3dv ( tet_r[0] ) ; glVertex3dv ( tet_r[2] ) ; glVertex3dv ( tet_r[3] ) ;
+    glNormal3d ( -tet_r[2][0], -tet_r[2][1], -tet_r[2][2] ) ; glVertex3dv ( tet_r[0] ) ; glVertex3dv ( tet_r[3] ) ; glVertex3dv ( tet_r[1] ) ;
+    glNormal3d ( -tet_r[3][0], -tet_r[3][1], -tet_r[3][2] ) ; glVertex3dv ( tet_r[0] ) ; glVertex3dv ( tet_r[1] ) ; glVertex3dv ( tet_r[2] ) ;
   glEnd() ;
 }
 
@@ -947,6 +972,9 @@ int icos_v [20][3] = { { 0, 1, 2 }, { 0, 2, 3 }, { 0, 3, 4 }, { 0, 4, 5 }, { 0,
 void FGAPIENTRY glutWireIcosahedron( void )
 {
   int i ;
+
+  FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireIcosahedron" );
+
   for ( i = 0; i < 20; i++ )
   {
     double normal[3] ;
@@ -969,6 +997,8 @@ void FGAPIENTRY glutSolidIcosahedron( void )
 {
   int i ;
 
+  FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidIcosahedron" );
+
   glBegin ( GL_TRIANGLES ) ;
   for ( i = 0; i < 20; i++ )
   {
@@ -1005,6 +1035,9 @@ double rdod_n[12][3] = {
 void FGAPIENTRY glutWireRhombicDodecahedron( void )
 {
   int i ;
+
+  FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireRhombicDodecahedron" );
+
   for ( i = 0; i < 12; i++ )
   {
     glBegin ( GL_LINE_LOOP ) ;
@@ -1024,6 +1057,8 @@ void FGAPIENTRY glutSolidRhombicDodecahedron( void )
 {
   int i ;
 
+  FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidRhombicDodecahedron" );
+
   glBegin ( GL_QUADS ) ;
   for ( i = 0; i < 12; i++ )
   {
@@ -1037,68 +1072,42 @@ void FGAPIENTRY glutSolidRhombicDodecahedron( void )
   glEnd () ;
 }
 
-#define NUM_FACES     4
-
-static GLdouble tetrahedron_v[4][3] =  /* Vertices */
-{
-  { -0.5, -0.288675134595, -0.144337567297 },
-  {  0.5, -0.288675134595, -0.144337567297 },
-  {  0.0,  0.577350269189, -0.144337567297 },
-  {  0.0,  0.0,             0.672159013631 }
-} ;
-
-static GLint tetrahedron_i[4][3] =  /* Vertex indices */
-{
-  { 0, 1, 2 }, { 0, 2, 3 }, { 0, 3, 1 }, { 1, 3, 2 }
-} ;
-
-static GLdouble tetrahedron_n[4][3] =  /* Normals */
-{
-  {  0.0,             0.0,            -1.0 },
-  { -0.816496580928,  0.471404520791,  0.333333333333 },
-  {  0.0,            -0.942809041582,  0.333333333333 },
-  {  0.816496580928,  0.471404520791,  0.333333333333 }
-} ;
-
 void FGAPIENTRY glutWireSierpinskiSponge ( int num_levels, GLdouble offset[3], GLdouble scale )
 {
   int i, j ;
 
+  FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireSierpinskiSponge" );
+
   if ( num_levels == 0 )
   {
 
-    for ( i = 0 ; i < NUM_FACES ; i++ )
+    for ( i = 0 ; i < NUM_TETR_FACES ; i++ )
     {
       glBegin ( GL_LINE_LOOP ) ;
-      glNormal3dv ( tetrahedron_n[i] ) ;
+      glNormal3d ( -tet_r[i][0], -tet_r[i][1], -tet_r[i][2] ) ;
       for ( j = 0; j < 3; j++ )
       {
-        double x = offset[0] + scale * tetrahedron_v[tetrahedron_i[i][j]][0] ;
-        double y = offset[1] + scale * tetrahedron_v[tetrahedron_i[i][j]][1] ;
-        double z = offset[2] + scale * tetrahedron_v[tetrahedron_i[i][j]][2] ;
+        double x = offset[0] + scale * tet_r[tet_i[i][j]][0] ;
+        double y = offset[1] + scale * tet_r[tet_i[i][j]][1] ;
+        double z = offset[2] + scale * tet_r[tet_i[i][j]][2] ;
         glVertex3d ( x, y, z ) ;
       }
 
       glEnd () ;
     }
   }
-  else
+  else if ( num_levels > 0 )
   {
     GLdouble local_offset[3] ;  /* Use a local variable to avoid buildup of roundoff errors */
     num_levels -- ;
     scale /= 2.0 ;
-    local_offset[0] = offset[0] + scale * tetrahedron_v[0][0] ;
-    local_offset[1] = offset[1] + scale * tetrahedron_v[0][1] ;
-    local_offset[2] = offset[2] + scale * tetrahedron_v[0][2] ;
-    glutWireSierpinskiSponge ( num_levels, local_offset, scale ) ;
-    local_offset[0] += scale ;
-    glutWireSierpinskiSponge ( num_levels, local_offset, scale ) ;
-    local_offset[0] -= 0.5            * scale ;
-    local_offset[1] += 0.866025403784 * scale ;
-    glutWireSierpinskiSponge ( num_levels, local_offset, scale ) ;
-    local_offset[1] -= 0.577350269189 * scale ;
-    local_offset[2] += 0.816496580928 * scale ;
-    glutWireSierpinskiSponge ( num_levels, local_offset, scale ) ;
+    for ( i = 0 ; i < NUM_TETR_FACES ; i++ )
+    {
+      local_offset[0] = offset[0] + scale * tet_r[i][0] ;
+      local_offset[1] = offset[1] + scale * tet_r[i][1] ;
+      local_offset[2] = offset[2] + scale * tet_r[i][2] ;
+      glutWireSierpinskiSponge ( num_levels, local_offset, scale ) ;
+    }
   }
 }
 
@@ -1106,44 +1115,39 @@ void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, GLdouble offset[3],
 {
   int i, j ;
 
+  FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSierpinskiSponge" );
+
   if ( num_levels == 0 )
   {
     glBegin ( GL_TRIANGLES ) ;
 
-    for ( i = 0 ; i < NUM_FACES ; i++ )
+    for ( i = 0 ; i < NUM_TETR_FACES ; i++ )
     {
-      glNormal3dv ( tetrahedron_n[i] ) ;
+      glNormal3d ( -tet_r[i][0], -tet_r[i][1], -tet_r[i][2] ) ;
       for ( j = 0; j < 3; j++ )
       {
-        double x = offset[0] + scale * tetrahedron_v[tetrahedron_i[i][j]][0] ;
-        double y = offset[1] + scale * tetrahedron_v[tetrahedron_i[i][j]][1] ;
-        double z = offset[2] + scale * tetrahedron_v[tetrahedron_i[i][j]][2] ;
+        double x = offset[0] + scale * tet_r[tet_i[i][j]][0] ;
+        double y = offset[1] + scale * tet_r[tet_i[i][j]][1] ;
+        double z = offset[2] + scale * tet_r[tet_i[i][j]][2] ;
         glVertex3d ( x, y, z ) ;
       }
     }
 
     glEnd () ;
   }
-  else
+  else if ( num_levels > 0 )
   {
     GLdouble local_offset[3] ;  /* Use a local variable to avoid buildup of roundoff errors */
     num_levels -- ;
     scale /= 2.0 ;
-    local_offset[0] = offset[0] + scale * tetrahedron_v[0][0] ;
-    local_offset[1] = offset[1] + scale * tetrahedron_v[0][1] ;
-    local_offset[2] = offset[2] + scale * tetrahedron_v[0][2] ;
-    glutSolidSierpinskiSponge ( num_levels, local_offset, scale ) ;
-    local_offset[0] += scale ;
-    glutSolidSierpinskiSponge ( num_levels, local_offset, scale ) ;
-    local_offset[0] -= 0.5            * scale ;
-    local_offset[1] += 0.866025403784 * scale ;
-    glutSolidSierpinskiSponge ( num_levels, local_offset, scale ) ;
-    local_offset[1] -= 0.577350269189 * scale ;
-    local_offset[2] += 0.816496580928 * scale ;
-    glutSolidSierpinskiSponge ( num_levels, local_offset, scale ) ;
+    for ( i = 0 ; i < NUM_TETR_FACES ; i++ )
+    {
+      local_offset[0] = offset[0] + scale * tet_r[i][0] ;
+      local_offset[1] = offset[1] + scale * tet_r[i][1] ;
+      local_offset[2] = offset[2] + scale * tet_r[i][2] ;
+      glutSolidSierpinskiSponge ( num_levels, local_offset, scale ) ;
+    }
   }
 }
 
-#undef NUM_FACES
-
 /*** END OF FILE ***/