torus ported. All shapes drawn with glDrawArrays and glDrawElements now.
[freeglut] / src / fg_geometry.c
index 9489a3b..7880381 100644 (file)
@@ -853,7 +853,7 @@ static void fghGenerateSphere(GLfloat radius, GLint slices, GLint stacks, GLfloa
     /* Allocate vertex and normal buffers, bail out if memory allocation fails */
     *vertices = malloc((*nVert)*3*sizeof(GLfloat));
     *normals  = malloc((*nVert)*3*sizeof(GLfloat));
-    if (!(vertices) || !(normals))
+    if (!(*vertices) || !(*normals))
     {
         free(*vertices);
         free(*normals);
@@ -949,7 +949,7 @@ void fghGenerateCone(
     /* Allocate vertex and normal buffers, bail out if memory allocation fails */
     *vertices = malloc((*nVert)*3*sizeof(GLfloat));
     *normals  = malloc((*nVert)*3*sizeof(GLfloat));
-    if (!(vertices) || !(normals))
+    if (!(*vertices) || !(*normals))
     {
         free(*vertices);
         free(*normals);
@@ -1031,7 +1031,7 @@ void fghGenerateCylinder(
     /* Allocate vertex and normal buffers, bail out if memory allocation fails */
     *vertices = malloc((*nVert)*3*sizeof(GLfloat));
     *normals  = malloc((*nVert)*3*sizeof(GLfloat));
-    if (!(vertices) || !(normals))
+    if (!(*vertices) || !(*normals))
     {
         free(*vertices);
         free(*normals);
@@ -1098,6 +1098,67 @@ void fghGenerateCylinder(
     free(sint);
     free(cost);
 }
+
+void fghGenerateTorus(
+    double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings, /*  input */
+    GLfloat **vertices, GLfloat **normals, int* nVert                     /* output */
+    )
+{
+    GLfloat  iradius = (float)dInnerRadius;
+    GLfloat  oradius = (float)dOuterRadius;
+    int    i, j;
+
+    /* Pre-computed circle */
+    GLfloat *spsi, *cpsi;
+    GLfloat *sphi, *cphi;
+
+    /* number of unique vertices */
+    if (nSides<2 || nRings<2)
+    {
+        /* nothing to generate */
+        *nVert = 0;
+        return;
+    }
+    *nVert = nSides * nRings;
+
+    if ((*nVert) > 65535)
+        fgWarning("fghGenerateTorus: too many slices or stacks requested, indices will wrap");
+
+    /* precompute values on unit circle */
+    fghCircleTable(&spsi,&cpsi, nRings,FALSE);
+    fghCircleTable(&sphi,&cphi,-nSides,FALSE);
+
+    /* Allocate vertex and normal buffers, bail out if memory allocation fails */
+    *vertices = malloc((*nVert)*3*sizeof(GLfloat));
+    *normals  = malloc((*nVert)*3*sizeof(GLfloat));
+    if (!(*vertices) || !(*normals))
+    {
+        free(*vertices);
+        free(*normals);
+        fgError("Failed to allocate memory in fghGenerateTorus");
+    }
+
+    for( j=0; j<nRings; j++ )
+    {
+        for( i=0; i<nSides; i++ )
+        {
+            int offset = 3 * ( j * nSides + i ) ;
+
+            (*vertices)[offset  ] = cpsi[j] * ( oradius + cphi[i] * iradius ) ;
+            (*vertices)[offset+1] = spsi[j] * ( oradius + cphi[i] * iradius ) ;
+            (*vertices)[offset+2] =                       sphi[i] * iradius  ;
+            (*normals )[offset  ] = cpsi[j] * cphi[i] ;
+            (*normals )[offset+1] = spsi[j] * cphi[i] ;
+            (*normals )[offset+2] =           sphi[i] ;
+        }
+    }
+
+    /* Release sin and cos tables */
+    free(spsi);
+    free(cpsi);
+    free(sphi);
+    free(cphi);
+}
 #endif
 
 /* -- INTERNAL DRAWING functions --------------------------------------- */
@@ -1235,7 +1296,7 @@ static void fghSphere( double radius, GLint slices, GLint stacks, GLboolean useW
         {
             free(stackIdx);
             free(sliceIdx);
-            fgError("Failed to allocate memory in fghGenerateSphere");
+            fgError("Failed to allocate memory in fghSphere");
         }
 
         /* generate for each stack */
@@ -1295,7 +1356,7 @@ static void fghSphere( double radius, GLint slices, GLint stacks, GLboolean useW
         if (!(stripIdx))
         {
             free(stripIdx);
-            fgError("Failed to allocate memory in fghGenerateSphere");
+            fgError("Failed to allocate memory in fghSphere");
         }
 
         /* top stack */
@@ -1382,7 +1443,7 @@ static void fghCone( double base, double height, GLint slices, GLint stacks, GLb
         {
             free(stackIdx);
             free(sliceIdx);
-            fgError("Failed to allocate memory in fghGenerateCone");
+            fgError("Failed to allocate memory in fghCone");
         }
 
         /* generate for each stack */
@@ -1437,7 +1498,7 @@ static void fghCone( double base, double height, GLint slices, GLint stacks, GLb
         if (!(stripIdx))
         {
             free(stripIdx);
-            fgError("Failed to allocate memory in fghGenerateCone");
+            fgError("Failed to allocate memory in fghCone");
         }
 
         /* top stack */
@@ -1513,7 +1574,7 @@ static void fghCylinder( double radius, double height, GLint slices, GLint stack
         {
             free(stackIdx);
             free(sliceIdx);
-            fgError("Failed to allocate memory in fghGenerateCylinder");
+            fgError("Failed to allocate memory in fghCylinder");
         }
 
         /* generate for each stack */
@@ -1568,7 +1629,7 @@ static void fghCylinder( double radius, double height, GLint slices, GLint stack
         if (!(stripIdx))
         {
             free(stripIdx);
-            fgError("Failed to allocate memory in fghGenerateCylinder");
+            fgError("Failed to allocate memory in fghCylinder");
         }
 
         /* top stack */
@@ -1627,6 +1688,121 @@ static void fghCylinder( double radius, double height, GLint slices, GLint stack
     free(normals);
 }
 
+static void fghTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings, GLboolean useWireMode )
+{
+    int i,j,idx, nVert;
+    GLfloat *vertices, *normals;
+
+    /* Generate vertices and normals */
+    fghGenerateTorus((GLfloat)dInnerRadius,(GLfloat)dOuterRadius,nSides,nRings, &vertices,&normals,&nVert);
+
+    if (nVert==0)
+        /* nothing to draw */
+        return;
+
+    if (useWireMode)
+    {
+        GLushort  *sideIdx, *ringIdx;
+        /* First, generate vertex index arrays for drawing with glDrawElements
+         * We have a bunch of line_loops to draw each side, and a
+         * bunch for each ring.
+         */
+
+        ringIdx = malloc(nRings*nSides*sizeof(GLushort));
+        sideIdx = malloc(nSides*nRings*sizeof(GLushort));
+        if (!(ringIdx) || !(sideIdx))
+        {
+            free(ringIdx);
+            free(sideIdx);
+            fgError("Failed to allocate memory in fghTorus");
+        }
+
+        /* generate for each ring */
+        for( j=0,idx=0; j<nRings; j++ )
+            for( i=0; i<nSides; i++, idx++ )
+                ringIdx[idx] = j * nSides + i;
+
+        /* generate for each side */
+        for( i=0,idx=0; i<nSides; i++ )
+            for( j=0; j<nRings; j++, idx++ )
+                sideIdx[idx] = j * nSides + i;
+
+        /* draw */
+        glEnableClientState(GL_VERTEX_ARRAY);
+        glEnableClientState(GL_NORMAL_ARRAY);
+
+        glVertexPointer(3, GL_FLOAT, 0, vertices);
+        glNormalPointer(GL_FLOAT, 0, normals);
+        /*draw rings*/
+        for( i=0; i<nSides; i++ )
+            glDrawElements(GL_LINE_LOOP,nRings,GL_UNSIGNED_SHORT,ringIdx+i*nRings);
+        /*draw sides*/
+        for (i=0; i<nRings; i++)
+            glDrawElements(GL_LINE_LOOP,nSides,GL_UNSIGNED_SHORT,sideIdx+i*nSides);
+
+        glDisableClientState(GL_VERTEX_ARRAY);
+        glDisableClientState(GL_NORMAL_ARRAY);
+
+        /* cleanup allocated memory */
+        free(sideIdx);
+        free(ringIdx);
+    }
+    else
+    {
+        /* clearly, this branch is TODO */
+        /* First, generate vertex index arrays for drawing with glDrawElements
+         * All stacks, including top and bottom are covered with a triangle
+         * strip.
+         */
+        GLushort  *stripIdx;
+
+        /* Allocate buffers for indices, bail out if memory allocation fails */
+        stripIdx = malloc((nRings+1)*2*nSides*sizeof(GLushort));
+        if (!(stripIdx))
+        {
+            free(stripIdx);
+            fgError("Failed to allocate memory in fghTorus");
+        }
+
+        for( i=0, idx=0; i<nSides; i++ )
+        {
+            int ioff = 1;
+            if (i==nSides-1)
+                ioff = -i;
+
+            for( j=0; j<nRings; j++, idx+=2 )
+            {
+                int offset = j * nSides + i;
+                stripIdx[idx  ] = offset;
+                stripIdx[idx+1] = offset + ioff;
+            }
+            /* repeat first to close off shape */
+            stripIdx[idx  ] = i;
+            stripIdx[idx+1] = i + ioff;
+            idx +=2;
+        }
+
+        /* draw */
+        glEnableClientState(GL_VERTEX_ARRAY);
+        glEnableClientState(GL_NORMAL_ARRAY);
+
+        glVertexPointer(3, GL_FLOAT, 0, vertices);
+        glNormalPointer(GL_FLOAT, 0, normals);
+        for (i=0; i<nSides; i++)
+            glDrawElements(GL_TRIANGLE_STRIP,(nRings+1)*2,GL_UNSIGNED_SHORT,stripIdx+i*(nRings+1)*2);
+
+        glDisableClientState(GL_VERTEX_ARRAY);
+        glDisableClientState(GL_NORMAL_ARRAY);
+
+        /* cleanup allocated memory */
+        free(stripIdx);
+    }
+
+    /* cleanup allocated memory */
+    free(vertices);
+    free(normals);
+}
+
 
 /* -- INTERFACE FUNCTIONS ---------------------------------------------- */
 
@@ -1700,91 +1876,9 @@ void FGAPIENTRY glutWireCylinder(double radius, double height, GLint slices, GLi
  */
 void FGAPIENTRY glutWireTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
 {
-  GLfloat  iradius = (float)dInnerRadius, oradius = (float)dOuterRadius;
-  GLfloat phi, psi, dpsi, dphi;
-  GLfloat *vertex, *normal;
-  int    i, j;
-  GLfloat spsi, cpsi, sphi, cphi ;
-
-  FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTorus" );
-
-  if ( nSides < 1 ) nSides = 1;
-  if ( nRings < 1 ) nRings = 1;
-
-  /* Allocate the vertices array */
-  vertex = (GLfloat *)calloc( sizeof(GLfloat), 3 * nSides * nRings );
-  normal = (GLfloat *)calloc( sizeof(GLfloat), 3 * nSides * nRings );
-
-  glPushMatrix();
-
-  dpsi =  2.0f * (GLfloat)M_PI / (GLfloat)(nRings) ;
-  dphi = -2.0f * (GLfloat)M_PI / (GLfloat)(nSides) ;
-  psi  = 0.0f;
-
-  for( j=0; j<nRings; j++ )
-  {
-#ifdef __cplusplus
-    cpsi = cosf( psi ) ;
-    spsi = sinf( psi ) ;
-#else
-    cpsi = (float)cos( (double)psi ) ;
-    spsi = (float)sin( (double)psi ) ;
-#endif  /* __cplusplus */
-    phi = 0.0f;
-
-    for( i=0; i<nSides; i++ )
-    {
-      int offset = 3 * ( j * nSides + i ) ;
-#ifdef __cplusplus
-      cphi = cosf( phi ) ;
-      sphi = sinf( phi ) ;
-#else
-      cphi = (float)cos( (double)phi ) ;
-      sphi = (float)sin( (double)phi ) ;
-#endif  /* __cplusplus */
-      *(vertex + offset + 0) = cpsi * ( oradius + cphi * iradius ) ;
-      *(vertex + offset + 1) = spsi * ( oradius + cphi * iradius ) ;
-      *(vertex + offset + 2) =                    sphi * iradius  ;
-      *(normal + offset + 0) = cpsi * cphi ;
-      *(normal + offset + 1) = spsi * cphi ;
-      *(normal + offset + 2) =        sphi ;
-      phi += dphi;
-    }
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireTorus" );
 
-    psi += dpsi;
-  }
-
-  for( i=0; i<nSides; i++ )
-  {
-    glBegin( GL_LINE_LOOP );
-
-    for( j=0; j<nRings; j++ )
-    {
-      int offset = 3 * ( j * nSides + i ) ;
-      glNormal3fv( normal + offset );
-      glVertex3fv( vertex + offset );
-    }
-
-    glEnd();
-  }
-
-  for( j=0; j<nRings; j++ )
-  {
-    glBegin(GL_LINE_LOOP);
-
-    for( i=0; i<nSides; i++ )
-    {
-      int offset = 3 * ( j * nSides + i ) ;
-      glNormal3fv( normal + offset );
-      glVertex3fv( vertex + offset );
-    }
-
-    glEnd();
-  }
-
-  free ( vertex ) ;
-  free ( normal ) ;
-  glPopMatrix();
+    fghTorus(dInnerRadius, dOuterRadius, nSides, nRings, TRUE);
 }
 
 /*
@@ -1792,86 +1886,9 @@ void FGAPIENTRY glutWireTorus( double dInnerRadius, double dOuterRadius, GLint n
  */
 void FGAPIENTRY glutSolidTorus( double dInnerRadius, double dOuterRadius, GLint nSides, GLint nRings )
 {
-  GLfloat  iradius = (float)dInnerRadius, oradius = (float)dOuterRadius;
-  GLfloat phi, psi, dpsi, dphi;
-  GLfloat *vertex, *normal;
-  int    i, j;
-  GLfloat spsi, cpsi, sphi, cphi ;
-
-  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 */
-  vertex = (GLfloat *)calloc( sizeof(GLfloat), 3 * nSides * nRings );
-  normal = (GLfloat *)calloc( sizeof(GLfloat), 3 * nSides * nRings );
-
-  glPushMatrix();
-
-  dpsi =  2.0f * (GLfloat)M_PI / (GLfloat)(nRings - 1) ;
-  dphi = -2.0f * (GLfloat)M_PI / (GLfloat)(nSides - 1) ;
-  psi  = 0.0f;
-
-  for( j=0; j<nRings; j++ )
-  {
-#ifdef __cplusplus
-    cpsi = cosf( psi ) ;
-    spsi = sinf( psi ) ;
-#else
-    cpsi = (float)cos( (double)psi ) ;
-    spsi = (float)sin( (double)psi ) ;
-#endif  /* __cplusplus */
-    phi = 0.0f;
-
-    for( i=0; i<nSides; i++ )
-    {
-      int offset = 3 * ( j * nSides + i ) ;
-#ifdef __cplusplus
-      cphi = cosf( phi ) ;
-      sphi = sinf( phi ) ;
-#else
-      cphi = (float)cos( (double)phi ) ;
-      sphi = (float)sin( (double)phi ) ;
-#endif  /* __cplusplus */
-      *(vertex + offset + 0) = cpsi * ( oradius + cphi * iradius ) ;
-      *(vertex + offset + 1) = spsi * ( oradius + cphi * iradius ) ;
-      *(vertex + offset + 2) =                    sphi * iradius  ;
-      *(normal + offset + 0) = cpsi * cphi ;
-      *(normal + offset + 1) = spsi * cphi ;
-      *(normal + offset + 2) =        sphi ;
-      phi += dphi;
-    }
-
-    psi += dpsi;
-  }
-
-    glBegin( GL_QUADS );
-  for( i=0; i<nSides-1; i++ )
-  {
-    for( j=0; j<nRings-1; j++ )
-    {
-      int offset = 3 * ( j * nSides + i ) ;
-      glNormal3fv( normal + offset );
-      glVertex3fv( vertex + offset );
-      glNormal3fv( normal + offset + 3 );
-      glVertex3fv( vertex + offset + 3 );
-      glNormal3fv( normal + offset + 3 * nSides + 3 );
-      glVertex3fv( vertex + offset + 3 * nSides + 3 );
-      glNormal3fv( normal + offset + 3 * nSides );
-      glVertex3fv( vertex + offset + 3 * nSides );
-    }
-  }
-
-  glEnd();
+    FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidTorus" );
 
-  free ( vertex ) ;
-  free ( normal ) ;
-  glPopMatrix();
+    fghTorus(dInnerRadius, dOuterRadius, nSides, nRings, FALSE);
 }
 #endif /* EGL_VERSION_1_0 */