Subversion Repositories shark

Rev

Blame | Last modification | View Log | RSS feed

/* $Id: quadric.c,v 1.1 2003-02-28 11:42:07 pj Exp $ */

/*
 * Mesa 3-D graphics library
 * Version:  3.3
 * Copyright (C) 1999-2000  Brian Paul
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */



/* TODO:
 *   texture coordinate support
 *   flip normals according to orientation
 *   there's still some inside/outside orientation bugs in possibly all
 *     but the sphere function
 */



#ifdef PC_HEADER
#include "all.h"
#else
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include "gluP.h"
#endif



#ifndef M_PI
#  define M_PI (3.1415926)
#endif


/*
 * Convert degrees to radians:
 */

#define DEG_TO_RAD(A)   ((A)*(M_PI/180.0))


/*
 * Sin and Cos for degree angles:
 */

#define SIND( A )   sin( (A)*(M_PI/180.0) )
#define COSD( A)    cos( (A)*(M_PI/180.0) )


/*
 * Texture coordinates if texture flag is set
 */

#define TXTR_COORD(x,y)    if (qobj->TextureFlag) glTexCoord2f(x,y);



struct GLUquadric
{
   GLenum DrawStyle;            /* GLU_FILL, LINE, SILHOUETTE, or POINT */
   GLenum Orientation;          /* GLU_INSIDE or GLU_OUTSIDE */
   GLboolean TextureFlag;       /* Generate texture coords? */
   GLenum Normals;              /* GLU_NONE, GLU_FLAT, or GLU_SMOOTH */
   void (GLCALLBACK * ErrorFunc) (GLenum err);  /* Error handler callback function */
};



/*
 * Process a GLU error.
 */

static void
quadric_error(GLUquadricObj * qobj, GLenum error, const char *msg)
{
   /* Call the error call back function if any */
   if (qobj->ErrorFunc) {
      (*qobj->ErrorFunc) (error);
   }
   /* Print a message to stdout if MESA_DEBUG variable is defined */
   if (getenv("MESA_DEBUG")) {
      fprintf(stderr, "GLUError: %s: %s\n", (char *) gluErrorString(error),
              msg);
   }
}




GLUquadricObj *GLAPIENTRY
gluNewQuadric(void)
{
   GLUquadricObj *q;

   q = (GLUquadricObj *) malloc(sizeof(struct GLUquadric));
   if (q) {
      q->DrawStyle = GLU_FILL;
      q->Orientation = GLU_OUTSIDE;
      q->TextureFlag = GL_FALSE;
      q->Normals = GLU_SMOOTH;
      q->ErrorFunc = NULL;
   }
   return q;
}



void GLAPIENTRY
gluDeleteQuadric(GLUquadricObj * state)
{
   if (state) {
      free((void *) state);
   }
}



/*
 * Set the drawing style to be GLU_FILL, GLU_LINE, GLU_SILHOUETTE,
 * or GLU_POINT.
 */

void GLAPIENTRY
gluQuadricDrawStyle(GLUquadricObj * quadObject, GLenum drawStyle)
{
   if (quadObject && (drawStyle == GLU_FILL || drawStyle == GLU_LINE
                      || drawStyle == GLU_SILHOUETTE
                      || drawStyle == GLU_POINT)) {
      quadObject->DrawStyle = drawStyle;
   }
   else {
      quadric_error(quadObject, GLU_INVALID_ENUM, "qluQuadricDrawStyle");
   }
}



/*
 * Set the orientation to GLU_INSIDE or GLU_OUTSIDE.
 */

void GLAPIENTRY
gluQuadricOrientation(GLUquadricObj * quadObject, GLenum orientation)
{
   if (quadObject
       && (orientation == GLU_INSIDE || orientation == GLU_OUTSIDE)) {
      quadObject->Orientation = orientation;
   }
   else {
      quadric_error(quadObject, GLU_INVALID_ENUM, "qluQuadricOrientation");
   }
}



/*
 * Set the error handler callback function.
 */

void GLAPIENTRY
gluQuadricCallback(GLUquadricObj * qobj,
                   GLenum which, void (GLCALLBACK * fn) ())
{
   /*
    * UGH, this is a mess!  I thought ANSI was a standard.
    */

   if (qobj && which == GLU_ERROR) {
#ifdef __CYGWIN32__
      qobj->ErrorFunc = (void (GLCALLBACKPCAST) (GLenum)) fn;
#elif defined(OPENSTEP)
      qobj->ErrorFunc = (void (*)(GLenum)) fn;
#elif defined(_WIN32)
      qobj->ErrorFunc = (void (GLCALLBACK *) (int)) fn;
#elif defined(__STORM__)
      qobj->ErrorFunc = (void (GLCALLBACK *) (GLenum)) fn;
#elif defined(__BEOS__)
      qobj->ErrorFunc = (void (*)(GLenum)) fn;
#else
      qobj->ErrorFunc = (void (GLCALLBACK *) ()) fn;
#endif
   }
}


void GLAPIENTRY
gluQuadricNormals(GLUquadricObj * quadObject, GLenum normals)
{
   if (quadObject
       && (normals == GLU_NONE || normals == GLU_FLAT
           || normals == GLU_SMOOTH)) {
      quadObject->Normals = normals;
   }
}


void GLAPIENTRY
gluQuadricTexture(GLUquadricObj * quadObject, GLboolean textureCoords)
{
   if (quadObject) {
      quadObject->TextureFlag = textureCoords;
   }
}




/*
 * Call glNormal3f after scaling normal to unit length.
 */

static void
normal3f(GLfloat x, GLfloat y, GLfloat z)
{
   GLdouble mag;

   mag = sqrt(x * x + y * y + z * z);
   if (mag > 0.00001F) {
      x /= mag;
      y /= mag;
      z /= mag;
   }
   glNormal3f(x, y, z);
}



void GLAPIENTRY
gluCylinder(GLUquadricObj * qobj,
            GLdouble baseRadius, GLdouble topRadius,
            GLdouble height, GLint slices, GLint stacks)
{
   GLdouble da, r, dr, dz;
   GLfloat x, y, z, nz, nsign;
   GLint i, j;

   if (qobj->Orientation == GLU_INSIDE) {
      nsign = -1.0;
   }
   else {
      nsign = 1.0;
   }

   da = 2.0 * M_PI / slices;
   dr = (topRadius - baseRadius) / stacks;
   dz = height / stacks;
   nz = (baseRadius - topRadius) / height;      /* Z component of normal vectors */

   if (qobj->DrawStyle == GLU_POINT) {
      glBegin(GL_POINTS);
      for (i = 0; i < slices; i++) {
         x = cos(i * da);
         y = sin(i * da);
         normal3f(x * nsign, y * nsign, nz * nsign);

         z = 0.0;
         r = baseRadius;
         for (j = 0; j <= stacks; j++) {
            glVertex3f(x * r, y * r, z);
            z += dz;
            r += dr;
         }
      }
      glEnd();
   }
   else if (qobj->DrawStyle == GLU_LINE || qobj->DrawStyle == GLU_SILHOUETTE) {
      /* Draw rings */
      if (qobj->DrawStyle == GLU_LINE) {
         z = 0.0;
         r = baseRadius;
         for (j = 0; j <= stacks; j++) {
            glBegin(GL_LINE_LOOP);
            for (i = 0; i < slices; i++) {
               x = cos(i * da);
               y = sin(i * da);
               normal3f(x * nsign, y * nsign, nz * nsign);
               glVertex3f(x * r, y * r, z);
            }
            glEnd();
            z += dz;
            r += dr;
         }
      }
      else {
         /* draw one ring at each end */
         if (baseRadius != 0.0) {
            glBegin(GL_LINE_LOOP);
            for (i = 0; i < slices; i++) {
               x = cos(i * da);
               y = sin(i * da);
               normal3f(x * nsign, y * nsign, nz * nsign);
               glVertex3f(x * baseRadius, y * baseRadius, 0.0);
            }
            glEnd();
            glBegin(GL_LINE_LOOP);
            for (i = 0; i < slices; i++) {
               x = cos(i * da);
               y = sin(i * da);
               normal3f(x * nsign, y * nsign, nz * nsign);
               glVertex3f(x * topRadius, y * topRadius, height);
            }
            glEnd();
         }
      }
      /* draw length lines */
      glBegin(GL_LINES);
      for (i = 0; i < slices; i++) {
         x = cos(i * da);
         y = sin(i * da);
         normal3f(x * nsign, y * nsign, nz * nsign);
         glVertex3f(x * baseRadius, y * baseRadius, 0.0);
         glVertex3f(x * topRadius, y * topRadius, height);
      }
      glEnd();
   }
   else if (qobj->DrawStyle == GLU_FILL) {
      GLfloat ds = 1.0 / slices;
      GLfloat dt = 1.0 / stacks;
      GLfloat t = 0.0;
      z = 0.0;
      r = baseRadius;
      for (j = 0; j < stacks; j++) {
         GLfloat s = 0.0;
         glBegin(GL_QUAD_STRIP);
         for (i = 0; i <= slices; i++) {
            GLfloat x, y;
            if (i == slices) {
               x = sin(0.0);
               y = cos(0.0);
            }
            else {
               x = sin(i * da);
               y = cos(i * da);
            }
            if (nsign == 1.0) {
               normal3f(x * nsign, y * nsign, nz * nsign);
               TXTR_COORD(s, t);
               glVertex3f(x * r, y * r, z);
               normal3f(x * nsign, y * nsign, nz * nsign);
               TXTR_COORD(s, t + dt);
               glVertex3f(x * (r + dr), y * (r + dr), z + dz);
            }
            else {
               normal3f(x * nsign, y * nsign, nz * nsign);
               TXTR_COORD(s, t);
               glVertex3f(x * r, y * r, z);
               normal3f(x * nsign, y * nsign, nz * nsign);
               TXTR_COORD(s, t + dt);
               glVertex3f(x * (r + dr), y * (r + dr), z + dz);
            }
            s += ds;
         }                      /* for slices */
         glEnd();
         r += dr;
         t += dt;
         z += dz;
      }                         /* for stacks */
   }
}





void GLAPIENTRY
gluSphere(GLUquadricObj * qobj, GLdouble radius, GLint slices, GLint stacks)
{
   GLfloat rho, drho, theta, dtheta;
   GLfloat x, y, z;
   GLfloat s, t, ds, dt;
   GLint i, j, imin, imax;
   GLboolean normals;
   GLfloat nsign;

   if (qobj->Normals == GLU_NONE) {
      normals = GL_FALSE;
   }
   else {
      normals = GL_TRUE;
   }
   if (qobj->Orientation == GLU_INSIDE) {
      nsign = -1.0;
   }
   else {
      nsign = 1.0;
   }

   drho = M_PI / (GLfloat) stacks;
   dtheta = 2.0 * M_PI / (GLfloat) slices;

   /* texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis */
   /* t goes from -1.0/+1.0 at z = -radius/+radius (linear along longitudes) */
   /* cannot use triangle fan on texturing (s coord. at top/bottom tip varies) */

   if (qobj->DrawStyle == GLU_FILL) {
      if (!qobj->TextureFlag) {
         /* draw +Z end as a triangle fan */
         glBegin(GL_TRIANGLE_FAN);
         glNormal3f(0.0, 0.0, 1.0);
         glVertex3f(0.0, 0.0, nsign * radius);
         for (j = 0; j <= slices; j++) {
            theta = (j == slices) ? 0.0 : j * dtheta;
            x = -sin(theta) * sin(drho);
            y = cos(theta) * sin(drho);
            z = nsign * cos(drho);
            if (normals)
               glNormal3f(x * nsign, y * nsign, z * nsign);
            glVertex3f(x * radius, y * radius, z * radius);
         }
         glEnd();
      }

      ds = 1.0 / slices;
      dt = 1.0 / stacks;
      t = 1.0;                  /* because loop now runs from 0 */
      if (qobj->TextureFlag) {
         imin = 0;
         imax = stacks;
      }
      else {
         imin = 1;
         imax = stacks - 1;
      }

      /* draw intermediate stacks as quad strips */
      for (i = imin; i < imax; i++) {
         rho = i * drho;
         glBegin(GL_QUAD_STRIP);
         s = 0.0;
         for (j = 0; j <= slices; j++) {
            theta = (j == slices) ? 0.0 : j * dtheta;
            x = -sin(theta) * sin(rho);
            y = cos(theta) * sin(rho);
            z = nsign * cos(rho);
            if (normals)
               glNormal3f(x * nsign, y * nsign, z * nsign);
            TXTR_COORD(s, t);
            glVertex3f(x * radius, y * radius, z * radius);
            x = -sin(theta) * sin(rho + drho);
            y = cos(theta) * sin(rho + drho);
            z = nsign * cos(rho + drho);
            if (normals)
               glNormal3f(x * nsign, y * nsign, z * nsign);
            TXTR_COORD(s, t - dt);
            s += ds;
            glVertex3f(x * radius, y * radius, z * radius);
         }
         glEnd();
         t -= dt;
      }

      if (!qobj->TextureFlag) {
         /* draw -Z end as a triangle fan */
         glBegin(GL_TRIANGLE_FAN);
         glNormal3f(0.0, 0.0, -1.0);
         glVertex3f(0.0, 0.0, -radius * nsign);
         rho = M_PI - drho;
         s = 1.0;
         t = dt;
         for (j = slices; j >= 0; j--) {
            theta = (j == slices) ? 0.0 : j * dtheta;
            x = -sin(theta) * sin(rho);
            y = cos(theta) * sin(rho);
            z = nsign * cos(rho);
            if (normals)
               glNormal3f(x * nsign, y * nsign, z * nsign);
            s -= ds;
            glVertex3f(x * radius, y * radius, z * radius);
         }
         glEnd();
      }
   }
   else if (qobj->DrawStyle == GLU_LINE || qobj->DrawStyle == GLU_SILHOUETTE) {
      /* draw stack lines */
      for (i = 1; i < stacks; i++) {    /* stack line at i==stacks-1 was missing here */
         rho = i * drho;
         glBegin(GL_LINE_LOOP);
         for (j = 0; j < slices; j++) {
            theta = j * dtheta;
            x = cos(theta) * sin(rho);
            y = sin(theta) * sin(rho);
            z = cos(rho);
            if (normals)
               glNormal3f(x * nsign, y * nsign, z * nsign);
            glVertex3f(x * radius, y * radius, z * radius);
         }
         glEnd();
      }
      /* draw slice lines */
      for (j = 0; j < slices; j++) {
         theta = j * dtheta;
         glBegin(GL_LINE_STRIP);
         for (i = 0; i <= stacks; i++) {
            rho = i * drho;
            x = cos(theta) * sin(rho);
            y = sin(theta) * sin(rho);
            z = cos(rho);
            if (normals)
               glNormal3f(x * nsign, y * nsign, z * nsign);
            glVertex3f(x * radius, y * radius, z * radius);
         }
         glEnd();
      }
   }
   else if (qobj->DrawStyle == GLU_POINT) {
      /* top and bottom-most points */
      glBegin(GL_POINTS);
      if (normals)
         glNormal3f(0.0, 0.0, nsign);
      glVertex3d(0.0, 0.0, radius);
      if (normals)
         glNormal3f(0.0, 0.0, -nsign);
      glVertex3d(0.0, 0.0, -radius);

      /* loop over stacks */
      for (i = 1; i < stacks - 1; i++) {
         rho = i * drho;
         for (j = 0; j < slices; j++) {
            theta = j * dtheta;
            x = cos(theta) * sin(rho);
            y = sin(theta) * sin(rho);
            z = cos(rho);
            if (normals)
               glNormal3f(x * nsign, y * nsign, z * nsign);
            glVertex3f(x * radius, y * radius, z * radius);
         }
      }
      glEnd();
   }

}



void GLAPIENTRY
gluDisk(GLUquadricObj * qobj,
        GLdouble innerRadius, GLdouble outerRadius, GLint slices, GLint loops)
{
   GLfloat da, dr;
#if 0
   GLdouble a, da;
   GLfloat r, dr;
   GLfloat x, y;
   GLfloat r1, r2, dtc;
   GLint s, l;
#endif

   /* Normal vectors */
   if (qobj->Normals != GLU_NONE) {
      if (qobj->Orientation == GLU_OUTSIDE) {
         glNormal3f(0.0, 0.0, +1.0);
      }
      else {
         glNormal3f(0.0, 0.0, -1.0);
      }
   }

   da = 2.0 * M_PI / slices;
   dr = (outerRadius - innerRadius) / (GLfloat) loops;

   switch (qobj->DrawStyle) {
   case GLU_FILL:
      {
         /* texture of a gluDisk is a cut out of the texture unit square
          * x, y in [-outerRadius, +outerRadius]; s, t in [0, 1]
          * (linear mapping)
          */

         GLfloat dtc = 2.0f * outerRadius;
         GLfloat sa, ca;
         GLfloat r1 = innerRadius;
         GLint l;
         for (l = 0; l < loops; l++) {
            GLfloat r2 = r1 + dr;
            if (qobj->Orientation == GLU_OUTSIDE) {
               GLint s;
               glBegin(GL_QUAD_STRIP);
               for (s = 0; s <= slices; s++) {
                  GLfloat a;
                  if (s == slices)
                     a = 0.0;
                  else
                     a = s * da;
                  sa = sin(a);
                  ca = cos(a);
                  TXTR_COORD(0.5 + sa * r2 / dtc, 0.5 + ca * r2 / dtc);
                  glVertex2f(r2 * sa, r2 * ca);
                  TXTR_COORD(0.5 + sa * r1 / dtc, 0.5 + ca * r1 / dtc);
                  glVertex2f(r1 * sa, r1 * ca);
               }
               glEnd();
            }
            else {
               GLint s;
               glBegin(GL_QUAD_STRIP);
               for (s = slices; s >= 0; s--) {
                  GLfloat a;
                  if (s == slices)
                     a = 0.0;
                  else
                     a = s * da;
                  sa = sin(a);
                  ca = cos(a);
                  TXTR_COORD(0.5 - sa * r2 / dtc, 0.5 + ca * r2 / dtc);
                  glVertex2f(r2 * sa, r2 * ca);
                  TXTR_COORD(0.5 - sa * r1 / dtc, 0.5 + ca * r1 / dtc);
                  glVertex2f(r1 * sa, r1 * ca);
               }
               glEnd();
            }
            r1 = r2;
         }
         break;
      }
   case GLU_LINE:
      {
         GLint l, s;
         /* draw loops */
         for (l = 0; l <= loops; l++) {
            GLfloat r = innerRadius + l * dr;
            glBegin(GL_LINE_LOOP);
            for (s = 0; s < slices; s++) {
               GLfloat a = s * da;
               glVertex2f(r * sin(a), r * cos(a));
            }
            glEnd();
         }
         /* draw spokes */
         for (s = 0; s < slices; s++) {
            GLfloat a = s * da;
            GLfloat x = sin(a);
            GLfloat y = cos(a);
            glBegin(GL_LINE_STRIP);
            for (l = 0; l <= loops; l++) {
               GLfloat r = innerRadius + l * dr;
               glVertex2f(r * x, r * y);
            }
            glEnd();
         }
         break;
      }
   case GLU_POINT:
      {
         GLint s;
         glBegin(GL_POINTS);
         for (s = 0; s < slices; s++) {
            GLfloat a = s * da;
            GLfloat x = sin(a);
            GLfloat y = cos(a);
            GLint l;
            for (l = 0; l <= loops; l++) {
               GLfloat r = innerRadius * l * dr;
               glVertex2f(r * x, r * y);
            }
         }
         glEnd();
         break;
      }
   case GLU_SILHOUETTE:
      {
         if (innerRadius != 0.0) {
            GLfloat a;
            glBegin(GL_LINE_LOOP);
            for (a = 0.0; a < 2.0 * M_PI; a += da) {
               GLfloat x = innerRadius * sin(a);
               GLfloat y = innerRadius * cos(a);
               glVertex2f(x, y);
            }
            glEnd();
         }
         {
            GLfloat a;
            glBegin(GL_LINE_LOOP);
            for (a = 0; a < 2.0 * M_PI; a += da) {
               GLfloat x = outerRadius * sin(a);
               GLfloat y = outerRadius * cos(a);
               glVertex2f(x, y);
            }
            glEnd();
         }
         break;
      }
   default:
      abort();
   }
}



void GLAPIENTRY
gluPartialDisk(GLUquadricObj * qobj, GLdouble innerRadius,
               GLdouble outerRadius, GLint slices, GLint loops,
               GLdouble startAngle, GLdouble sweepAngle)
{
   if (qobj->Normals != GLU_NONE) {
      if (qobj->Orientation == GLU_OUTSIDE) {
         glNormal3f(0.0, 0.0, +1.0);
      }
      else {
         glNormal3f(0.0, 0.0, -1.0);
      }
   }

   if (qobj->DrawStyle == GLU_POINT) {
      GLint loop, slice;
      GLdouble radius, delta_radius;
      GLdouble angle, delta_angle;
      delta_radius = (outerRadius - innerRadius) / (loops - 1);
      delta_angle = DEG_TO_RAD((sweepAngle) / (slices - 1));
      glBegin(GL_POINTS);
      radius = innerRadius;
      for (loop = 0; loop < loops; loop++) {
         angle = DEG_TO_RAD(startAngle);
         for (slice = 0; slice < slices; slice++) {
            glVertex2d(radius * sin(angle), radius * cos(angle));
            angle += delta_angle;
         }
         radius += delta_radius;
      }
      glEnd();
   }
   else if (qobj->DrawStyle == GLU_LINE) {
      GLint loop, slice;
      GLdouble radius, delta_radius;
      GLdouble angle, delta_angle;
      delta_radius = (outerRadius - innerRadius) / loops;
      delta_angle = DEG_TO_RAD(sweepAngle / slices);
      /* draw rings */
      radius = innerRadius;
      for (loop = 0; loop < loops; loop++) {
         angle = DEG_TO_RAD(startAngle);
         glBegin(GL_LINE_STRIP);
         for (slice = 0; slice <= slices; slice++) {
            glVertex2d(radius * sin(angle), radius * cos(angle));
            angle += delta_angle;
         }
         glEnd();
         radius += delta_radius;
      }
      /* draw spokes */
      angle = DEG_TO_RAD(startAngle);
      for (slice = 0; slice <= slices; slice++) {
         radius = innerRadius;
         glBegin(GL_LINE_STRIP);
         for (loop = 0; loop < loops; loop++) {
            glVertex2d(radius * sin(angle), radius * cos(angle));
            radius += delta_radius;
         }
         glEnd();
         angle += delta_angle;
      }
   }
   else if (qobj->DrawStyle == GLU_SILHOUETTE) {
      GLint slice;
      GLdouble angle, delta_angle;
      delta_angle = DEG_TO_RAD(sweepAngle / slices);
      /* draw outer ring */
      glBegin(GL_LINE_STRIP);
      angle = DEG_TO_RAD(startAngle);
      for (slice = 0; slice <= slices; slice++) {
         glVertex2d(outerRadius * sin(angle), outerRadius * cos(angle));
         angle += delta_angle;
      }
      glEnd();
      /* draw inner ring */
      if (innerRadius > 0.0) {
         glBegin(GL_LINE_STRIP);
         angle = DEG_TO_RAD(startAngle);
         for (slice = 0; slice < slices; slice++) {
            glVertex2d(innerRadius * sin(angle), innerRadius * cos(angle));
            angle += delta_angle;
         }
         glEnd();
      }
      /* draw spokes */
      if (sweepAngle < 360.0) {
         GLdouble stopAngle = startAngle + sweepAngle;
         glBegin(GL_LINES);
         glVertex2d(innerRadius * SIND(startAngle),
                    innerRadius * COSD(startAngle));
         glVertex2d(outerRadius * SIND(startAngle),
                    outerRadius * COSD(startAngle));
         glVertex2d(innerRadius * SIND(stopAngle),
                    innerRadius * COSD(stopAngle));
         glVertex2d(outerRadius * SIND(stopAngle),
                    outerRadius * COSD(stopAngle));
         glEnd();
      }
   }
   else if (qobj->DrawStyle == GLU_FILL) {
      GLint loop, slice;
      GLdouble radius, delta_radius;
      GLdouble angle, delta_angle;
      delta_radius = (outerRadius - innerRadius) / loops;
      delta_angle = DEG_TO_RAD(sweepAngle / slices);
      radius = innerRadius;
      for (loop = 0; loop < loops; loop++) {
         glBegin(GL_QUAD_STRIP);
         angle = DEG_TO_RAD(startAngle);
         for (slice = 0; slice <= slices; slice++) {
            if (qobj->Orientation == GLU_OUTSIDE) {
               glVertex2d((radius + delta_radius) * sin(angle),
                          (radius + delta_radius) * cos(angle));
               glVertex2d(radius * sin(angle), radius * cos(angle));
            }
            else {
               glVertex2d(radius * sin(angle), radius * cos(angle));
               glVertex2d((radius + delta_radius) * sin(angle),
                          (radius + delta_radius) * cos(angle));
            }
            angle += delta_angle;
         }
         glEnd();
         radius += delta_radius;
      }
   }
}