Пример #1
0
static void
do_normal2 (Bool frontp, XYZ a, XYZ b, XYZ c)
{
  if (frontp)
    do_normal (a.x, a.y, a.z,
               b.x, b.y, b.z,
               c.x, c.y, c.z);
  else
    do_normal (b.x, b.y, b.z,
               a.x, a.y, a.z,
               c.x, c.y, c.z);
}
Пример #2
0
int
unit_teapot (int grid, int wire_p)
{
  int polys = sizeof (teapot_triangles) / sizeof (*teapot_triangles) / 9;
  int i;
  const GLfloat *p = teapot_triangles;
  GLfloat scale = 1 / 2.3;

  glPushMatrix();
  glScalef (scale, scale, scale);
  glTranslatef (0, -1.25, 0);

  if (wire_p)
    {
      glBegin (GL_LINES);
      for (i = 0; i < polys; i++)
        {
          XYZ p1, p2, p3;
          p1.x = *p++; p1.y = *p++; p1.z = *p++;
          p2.x = *p++; p2.y = *p++; p2.z = *p++;
          p3.x = *p++; p3.y = *p++; p3.z = *p++;
          glVertex3f (p1.x, p1.y, p1.z);   /* Draw 2 edges of each triangle */
          glVertex3f (p2.x, p2.y, p2.z);
          glVertex3f (p1.x, p1.y, p1.z);
          glVertex3f (p3.x, p3.y, p3.z);
          i++;				   /* Skip every other triangle */
          p += 9;
        }
      glEnd();
      polys /= 2;
    }
  else
    {
      glFrontFace (GL_CCW);
      glBegin (GL_TRIANGLES);
      for (i = 0; i < polys; i++)
        {
          XYZ p1, p2, p3;
          p1.x = *p++; p1.y = *p++; p1.z = *p++;
          p2.x = *p++; p2.y = *p++; p2.z = *p++;
          p3.x = *p++; p3.y = *p++; p3.z = *p++;
          do_normal (p1.x, p1.y, p1.z,
                     p2.x, p2.y, p2.z,
                     p3.x, p3.y, p3.z);
          glVertex3f (p1.x, p1.y, p1.z);
          glVertex3f (p2.x, p2.y, p2.z);
          glVertex3f (p3.x, p3.y, p3.z);
        }
      glEnd();
    }
  glPopMatrix();

  return polys;
}
Пример #3
0
static void
triangle (GLfloat x1, GLfloat y1, GLfloat z1,
          GLfloat x2, GLfloat y2, GLfloat z2,
          GLfloat x3, GLfloat y3, GLfloat z3,
          Bool wireframe_p)
{
  if (wireframe_p)
    glBegin (GL_LINE_LOOP);
  else
    {
      do_normal (x1, y1, z1,  x2, y2, z2,  x3, y3, z3);
      glBegin (GL_TRIANGLES);
    }
  glVertex3f (x1, y1, z1);
  glVertex3f (x2, y2, z2);
  glVertex3f (x3, y3, z3);
  glEnd();
}
Пример #4
0
static void
folding_walls (ModeInfo *mi, GLfloat ratio, Bool top_p)
{
  lament_configuration *lc = &lcs[MI_SCREEN(mi)];
  Bool wire = MI_IS_WIREFRAME(mi);
  const GLfloat pa[4][2] = {{ -0.5,      -0.215833 },
                            {  0,         0.5      },
                            {  0.5,       0        },
                            { -0.215833, -0.5      }};
  const int tex[6] = { 0, 5, 1,  4, 2, 3 };
  const GLfloat top = -pa[0][1];
  GLfloat end_angle = 30.85;
  GLfloat rr = sin (ratio / 2 * M_PI);
  GLfloat offa = 0.15 * rr;
  GLfloat offb = 0.06 * rr;
  GLfloat p[4][3];
  GLfloat t[4][2];
  int i;

  glPushMatrix();

  if (top_p)
    {
      glRotatef (60, 1, -1, 1);
      glRotatef (180, 0, 1, 0);
      glRotatef (90, 1, 0, 0);
    }
  else
    {
      glRotatef (180, 1, 0, 0);
    }

  /* Scale down the points near the axis */

  p[0][0] = pa[0][0];
  p[0][1] = 0.5;
  p[0][2] = pa[0][1];

  p[1][0] = pa[1][0] - offb;
  p[1][1] = 0.5;
  p[1][2] = pa[1][1] - offa;

  p[2][0] = pa[2][0] - offa;
  p[2][1] = 0.5;
  p[2][2] = pa[2][1] - offb;

  p[3][0] = pa[3][0];
  p[3][1] = 0.5;
  p[3][2] = pa[3][1];

  if (!wire)
    {
      glEnable (GL_BLEND);
      glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    }

  for (i = 0; i < 3; i++)
    {
      glPushMatrix();

      if (i == 1)
        {
          glRotatef (-90, 1, 0, 0);
          glRotatef (180, 1, 1, 0);
        }
      else if (i == 2)
        {
          glRotatef (-90, 1, 0, 0);
          glRotatef (180, 0, 1, 0);
          glRotatef (90, 0, 1, 0);
        }

      glRotatef (-90, 0, 1, 0);

      glTranslatef (-(top/2 + 0.25), 0.5, -(top/2 + 0.25));
      glRotatef (-45, 0, 1, 0);
      glRotatef (ratio * -end_angle, 0, 0, 1);
      glRotatef (45, 0, 1, 0);
      glTranslatef (top/2 + 0.25, -0.5, top/2 + 0.25);

      /* Get the texture coordinates right.
         This is hairy and incomprehensible. */

      t[0][0] = pa[0][1] + 0.5; t[0][1] = pa[0][0] + 0.5;
      t[1][0] = pa[1][1] + 0.5; t[1][1] = pa[1][0] + 0.5;
      t[2][0] = pa[2][1] + 0.5; t[2][1] = pa[2][0] + 0.5;
      t[3][0] = pa[3][1] + 0.5; t[3][1] = pa[3][0] + 0.5;

      if (i == 0 && !top_p)
        {
# define SWAP(A,B) A = 1-A, B = 1-B
          SWAP(t[0][0], t[0][1]);
          SWAP(t[1][0], t[1][1]);
          SWAP(t[2][0], t[2][1]);
          SWAP(t[3][0], t[3][1]);
# undef SWAP
        }
      else if (i == 0 && top_p)
        {
          GLfloat ot[4][3];
          memcpy (ot, t, sizeof(t));
# define SWAP(A,B) A = 1-A, B = 1-B
          SWAP(t[0][0], ot[2][1]);
          SWAP(t[1][0], ot[3][1]);
          SWAP(t[2][0], ot[0][1]);
          SWAP(t[3][0], ot[1][1]);
# undef SWAP
        }
      else if (i == 1)
        {
          GLfloat f;
# define SWAP(A,B) f = A, A = B, B = -f
          SWAP(t[0][0], t[0][1]);
          SWAP(t[1][0], t[1][1]);
          SWAP(t[2][0], t[2][1]);
          SWAP(t[3][0], t[3][1]);
# undef SWAP
        }

      set_colors_alpha (exterior_color, 1-ratio);
      glBindTexture (GL_TEXTURE_2D, lc->texids[tex[i + (top_p ? 3 : 0)]]);

      glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
      do_normal (p[0][0], p[0][1], p[0][2],
                 p[1][0], p[1][1], p[1][2],
                 p[2][0], p[2][1], p[2][2]);
      glTexCoord2fv(t[0]); glVertex3fv(p[0]);
      glTexCoord2fv(t[1]); glVertex3fv(p[1]);
      glTexCoord2fv(t[2]); glVertex3fv(p[2]);
      glTexCoord2fv(t[3]); glVertex3fv(p[3]);
      glEnd();
      mi->polygon_count++;

      /* The triangles between the quads */
# if 0
      /* #### There is a f*****g gap between the two black triangles 
         that I can't figure out!  So instead of drawing the triangles,
         we build a black shield around the middle bit in leviathan()
         and count on back-face culling to have roughly the same effect.
       */
      if (!wire)
        {
          GLfloat pp[4][3];
          memcpy (pp, p, sizeof(pp));
          memcpy (pp[2], pp[1], sizeof(pp[1]));
          pp[2][0] -= 0.5 * (1-ratio);
          pp[2][1] -= 0.5 * (1-ratio);

          glBindTexture (GL_TEXTURE_2D, 0);
          set_colors_alpha (black_color, 1-ratio);

          glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLES);
          do_normal (pp[0][0], pp[0][1], pp[0][2],
                     pp[2][0], pp[2][1], pp[2][2],
                     pp[1][0], pp[1][1], pp[1][2]);
          glVertex3fv(pp[0]);
          glVertex3fv(pp[2]);
          glVertex3fv(pp[1]);
          glEnd();
          mi->polygon_count++;
        }
# endif

      glPopMatrix();
    }

  if (! wire) glDisable (GL_BLEND);

  glPopMatrix();
}
Пример #5
0
static void
leviathan (ModeInfo *mi, GLfloat ratio, GLfloat alpha, Bool top_p)
{
  lament_configuration *lc = &lcs[MI_SCREEN(mi)];
  Bool wire = MI_IS_WIREFRAME(mi);
  GLfloat r = 0.34;
  GLfloat z = 2 * ratio;
  XYZ p[3];
  int i;

  GLfloat th = acos (2 / sqrt (6));  /* Line up with cube's diagonal */

  glPushMatrix();

  glRotatef (-45, 0, 1, 0);
  glRotatef (-th * 180 / M_PI, 0, 0, 1);

  if (!top_p)
    glRotatef (180, 0, 0, 1);

  for (i = 0; i < countof(p); i++)
    {
      GLfloat th = i * M_PI * 2 / countof(p);
      p[i].x = cos(th) * r;
      p[i].y = sin(th) * r;
    }

  glFrontFace (GL_CCW);
  for (i = 0; i < countof(p); i++)
    {
      int j = (i + 1) % countof(p);
/*      if (top_p)*/
        do_normal (z, 0, 0,
                   0, p[i].x, p[i].y,
                   0, p[j].x, p[j].y);
/*
      else
        do_normal (z, 0, 0,
                   0, p[j].y, p[j].z,
                   0, p[i].y, p[i].z);
*/

      if (do_texture)  /* Leviathan is the final texture */
        glBindTexture (GL_TEXTURE_2D, lc->texids[countof(lc->texids) - 1]);

      set_colors (leviathan_color);

      glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
      glTexCoord2f (0.5, 1);
      glVertex3f (z, 0, 0);

      glTexCoord2f (0, 0);
      glVertex3f (0, p[i].x, p[i].y);

      glTexCoord2f (1, 0);
      glVertex3f (0, p[j].x, p[j].y);
      glEnd();
      mi->polygon_count++;

      /* Shield for fading */
      if (alpha < 0.9 && !wire)
        {
          GLfloat a = 0.35;
          GLfloat b = 0.69;

          set_colors_alpha (black_color, 1-alpha);
          glBindTexture (GL_TEXTURE_2D, 0);
          if (!wire)
            {
              glEnable (GL_BLEND);
              glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            }

          glBegin (wire ? GL_LINE_LOOP : GL_QUADS);

          glVertex3f (z*a, p[j].x * b, p[j].y * b);
          glVertex3f (z*a, p[i].x * b, p[i].y * b);
          glVertex3f (0, p[i].x * 1.01, p[i].y * 1.01);
          glVertex3f (0, p[j].x * 1.01, p[j].y * 1.01);
          glEnd();
          mi->polygon_count++;
          glDisable (GL_BLEND);
        }
    }

  glPopMatrix();
}
Пример #6
0
static void new_ship(ModeInfo *mi)
{
  commander_conf *cp = &commander[MI_SCREEN(mi)];
  int i;
  GLfloat *this_v;
  GLint *p;
  /*GLfloat *this_n;*/
  int count;
#if 0
  int wire = MI_IS_WIREFRAME(mi);

  GLfloat bcolor[4] = {0.2, 0.2, 0.2, 0.2};
  GLfloat bspec[4]  = {0.1, 0.1, 0.1, 0.1};
  GLfloat bshiny    = 32.0;
  GLfloat pos[4] = {-8.0, -8.0, -16.0, 0.0}; /* -6 -6 -16 */
  GLfloat amb[4] = {0.2, 0.2, 0.2, 0.4};
  GLfloat dif[4] = {0.2, 0.2, 0.2, 0.2};
  GLfloat spc[4] = {0.0, 0.0, 0.0, 0.0};

	if(!wire) {
		glEnable(GL_LIGHTING);
		glEnable(GL_LIGHT0);

		glLightfv(GL_LIGHT0, GL_POSITION, pos);
		glLightfv(GL_LIGHT0, GL_AMBIENT,  amb);
		glLightfv(GL_LIGHT0, GL_DIFFUSE,  dif);
		glLightfv(GL_LIGHT0, GL_SPECULAR, spc);

		glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, bcolor);
		glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR, bspec);
		glMateriali  (GL_FRONT_AND_BACK, GL_SHININESS, bshiny);
	}
#endif

  cp->list = glGenLists(1);
  glNewList(cp->list, GL_COMPILE);
  if(MI_IS_MONO(mi)) {
    /* FIXME support mono display */
    abort();
  }

	/* wireframe strategy: use stencil buffer, not polygon offset,
	 * because it's impossible to get the right parameters for
	 * glPolygonOffset() reliably */
  
	/* hidden-line removal as per
	 * http://glprogramming.com/red/chapter14.html#name16
	 */

	/* TODO:
		 - reinstate choice of wireframe vs filled
		 - rationalise some of the duplicated code below
	 */

	glEnable(GL_STENCIL_TEST);
	glEnable(GL_DEPTH_TEST);
	glClear(GL_STENCIL_BUFFER_BIT);
	glStencilFunc(GL_ALWAYS, 0, 1);
	glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);

	glColor3f(1.0, 1.0, 1.0);

	p=ship_f[cp->which];
	this_v=ship_v[cp->which];

	/* for debugging - draw axes */
#if 0
	glLineWidth(1); 
	glBegin(GL_LINES); glVertex3f(0,0,0); glVertex3f(10,0,0); glEnd();
	glBegin(GL_LINES); glVertex3f(0,0,0); glVertex3f(0,10,0); glEnd();
	glBegin(GL_LINES); glVertex3f(0.1,0,0); glVertex3f(0.1,10,0); glEnd();
	glBegin(GL_LINES); glVertex3f(0,0,0); glVertex3f(0,0,10); glEnd();
	glBegin(GL_LINES); glVertex3f(0,0.1,0); glVertex3f(0,0.1,10); glEnd();
	glBegin(GL_LINES); glVertex3f(0,0.2,0); glVertex3f(0,0.2,10); glEnd();
#endif

	/* draw the wireframe shape */
	while(*p != 0) {
		count=*p; p++;

		/* draw outline polygon */

		if(count==1) { glBegin(GL_POINTS); }
		else if(count==2) {
			/* chunky lines :-) */
			glLineWidth(2); 
			glBegin(GL_LINES);
		}
		else {
			glLineWidth(2); 
			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
			glBegin(GL_POLYGON); 
			do_normal(this_v[p[0]*3], this_v[p[0]*3+1], this_v[p[0]*3+2],
				this_v[p[1]*3], this_v[p[1]*3+1], this_v[p[1]*3+2],
				this_v[p[2]*3], this_v[p[2]*3+1], this_v[p[2]*3+2]);
		}
		for (i = 0 ; i < count ; i++) {
			glVertex3f(this_v[p[i]*3], this_v[p[i]*3+1], this_v[p[i]*3+2]);
		}
		glEnd();

		glColor3f(0.0, 0.0, 0.0);

		glStencilFunc(GL_EQUAL, 0, 1);
		glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);

		/* draw filled polygon */

		if(count>=3) {
			glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
			glBegin(GL_POLYGON); 
			do_normal(this_v[p[0]*3], this_v[p[0]*3+1], this_v[p[0]*3+2],
				this_v[p[1]*3], this_v[p[1]*3+1], this_v[p[1]*3+2],
				this_v[p[2]*3], this_v[p[2]*3+1], this_v[p[2]*3+2]);
			for (i = 0 ; i < count ; i++) {
				glVertex3f(this_v[p[i]*3], this_v[p[i]*3+1], this_v[p[i]*3+2]);
			}
			glEnd();
		}

		glColor3f(1.0, 1.0, 1.0);

		glStencilFunc(GL_ALWAYS, 0, 1);
		glStencilOp(GL_INVERT, GL_INVERT, GL_INVERT);

		/* draw outline polygon */

		if(count==1) { glBegin(GL_POINTS); }
		else if(count==2) {
			/* chunky lines :-) */
			glLineWidth(2); 
			glBegin(GL_LINES);
		}
		else {
			glLineWidth(2); 
			glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
			glBegin(GL_POLYGON); 
			do_normal(this_v[p[0]*3], this_v[p[0]*3+1], this_v[p[0]*3+2],
				this_v[p[1]*3], this_v[p[1]*3+1], this_v[p[1]*3+2],
				this_v[p[2]*3], this_v[p[2]*3+1], this_v[p[2]*3+2]);
		}
		for (i = 0 ; i < count ; i++) {
			glVertex3f(this_v[p[i]*3], this_v[p[i]*3+1], this_v[p[i]*3+2]);
		}
		glEnd();

		cp->npoints++;
		p+=count;
	}

  glEndList();
}
Пример #7
0
/* Given a function capable of generating a value at any XYZ position,
   creates OpenGL faces for the solids defined.

   init_fn is called at the beginning for initial, and returns an object.
   free_fn is called at the end.

   compute_fn is called for each XYZ in the specified grid, and returns
   the double value of that coordinate.  If smoothing is on, then
   compute_fn will also be called twice more for each emitted vertex,
   in order to calculate vertex normals (so don't assume it will only
   be called with values falling on the grid boundaries.)

   Points are inside an object if the are less than `isolevel', and
   outside otherwise.
*/
void
marching_cubes (int grid_size,     /* density of the mesh */
                double isolevel,   /* cutoff point for "in" versus "out" */
                int wireframe_p,   /* wireframe, or solid */
                int smooth_p,      /* smooth, or faceted */

                void * (*init_fn)    (double grid_size, void *closure1),
                double (*compute_fn) (double x, double y, double z,
                                      void *closure2),
                void   (*free_fn)    (void *closure2),
                void *closure1,

                unsigned long *polygon_count)
{
  int planesize = grid_size * grid_size;
  int x, y, z;
  void *closure2 = 0;
  unsigned long polys = 0;
  double *layers;

  layers = (double *) calloc (sizeof (*layers), planesize * 2);
  if (!layers)
    {
      fprintf (stderr, "%s: out of memory for %dx%dx%d grid\n",
               progname, grid_size, grid_size, 2);
      exit (1);
    }

  if (init_fn)
    closure2 = init_fn (grid_size, closure1);

  glFrontFace(GL_CCW);
  if (!wireframe_p)
    glBegin (GL_TRIANGLES);

  for (z = 0; z < grid_size; z++)
    {
      double *layer0 = (z & 1 ? layers+planesize : layers);
      double *layer1 = (z & 1 ? layers           : layers+planesize);
      double *row;

      /* Fill in the XY grid on the currently-bottommost layer. */
      row = layer1;
      for (y = 0; y < grid_size; y++, row += grid_size)
        {
          double *cell = row;
          for (x = 0; x < grid_size; x++, cell++)
            *cell = compute_fn (x, y, z, closure2);
        }

      /* Now we've completed one layer (an XY slice of Z.)  Now we can
         generate the polygons that fill the space between this layer
         and the previous one (unless this is the first layer.)
      */
      if (z == 0) continue;

      for (y = 1; y < grid_size; y += 1)
        for (x = 1; x < grid_size; x += 1)
          {
            TRIANGLE tri[6];
            int i, ntri;
            GRIDCELL cell;

            /* This is kinda hokey, there ought to be a more efficient
               way to do this... */
            cell.p[0].x = x-1; cell.p[0].y = y-1; cell.p[0].z = z-1;
            cell.p[1].x = x  ; cell.p[1].y = y-1; cell.p[1].z = z-1;
            cell.p[2].x = x  ; cell.p[2].y = y  ; cell.p[2].z = z-1;
            cell.p[3].x = x-1; cell.p[3].y = y  ; cell.p[3].z = z-1;
            cell.p[4].x = x-1; cell.p[4].y = y-1; cell.p[4].z = z  ;
            cell.p[5].x = x  ; cell.p[5].y = y-1; cell.p[5].z = z  ;
            cell.p[6].x = x  ; cell.p[6].y = y  ; cell.p[6].z = z  ;
            cell.p[7].x = x-1; cell.p[7].y = y  ; cell.p[7].z = z  ;

# define GRID(X,Y,WHICH) ((WHICH) \
                          ? layer1[((Y)*grid_size) + ((X))] \
                          : layer0[((Y)*grid_size) + ((X))])

            cell.val[0] = GRID (x-1, y-1, 0);
            cell.val[1] = GRID (x  , y-1, 0);
            cell.val[2] = GRID (x  , y  , 0);
            cell.val[3] = GRID (x-1, y  , 0);
            cell.val[4] = GRID (x-1, y-1, 1);
            cell.val[5] = GRID (x  , y-1, 1);
            cell.val[6] = GRID (x  , y  , 1);
            cell.val[7] = GRID (x-1, y  , 1);
# undef GRID

            /* Now generate the triangles for this cubic segment,
               and emit the GL faces.
            */
            ntri = march_one_cube (cell, isolevel, tri);
            polys += ntri;
            for (i = 0; i < ntri; i++)
              {
                if (wireframe_p) glBegin (GL_LINE_LOOP);

                /* If we're smoothing, we need to call the field function
                   again for each vertex (via function_normal().)  If we're
                   not smoothing, then we can just compute the normal from
                   this triangle.
                 */
                if (!smooth_p)
                  do_normal (tri[i].p[0].x, tri[i].p[0].y, tri[i].p[0].z,
                             tri[i].p[1].x, tri[i].p[1].y, tri[i].p[1].z,
                             tri[i].p[2].x, tri[i].p[2].y, tri[i].p[2].z);

# define VERT(X,Y,Z) \
                if (smooth_p) \
                  do_function_normal ((X), (Y), (Z), compute_fn, closure2); \
                glVertex3f ((X), (Y), (Z))

                VERT (tri[i].p[0].x, tri[i].p[0].y, tri[i].p[0].z);
                VERT (tri[i].p[1].x, tri[i].p[1].y, tri[i].p[1].z);
                VERT (tri[i].p[2].x, tri[i].p[2].y, tri[i].p[2].z);
# undef VERT
                if (wireframe_p) glEnd ();
              }
          }
    }

  if (!wireframe_p)
    glEnd ();

  free (layers);

  if (free_fn)
    free_fn (closure2);

  if (polygon_count)
    *polygon_count = polys;
}
Пример #8
0
static void
make_helix (logo_configuration *dc, int facetted, int wire)
{
  int wall_facets = dc->wall_facets / (facetted ? 15 : 1);
  GLfloat th;
  GLfloat max_th = M_PI * 2 * dc->turns;
  GLfloat th_inc = M_PI * 2 / wall_facets;

  GLfloat x1=0,  y1=0,  x2=0,  y2=0;
  GLfloat x1b=0, y1b=0, x2b=0, y2b=0;
  GLfloat z1=0, z2=0;
  GLfloat h1=0, h2=0;
  GLfloat h1off=0, h2off=0;
  GLfloat z_inc = dc->turn_spacing / wall_facets;

  th  = 0;
  x1  = 1;
  y1  = 0;
  x1b = 1 - dc->wall_thickness;
  y1b = 0;

  z1 = -(dc->turn_spacing * dc->turns / 2);

  h1 = (dc->wall_taper > 0 ? 0 : dc->wall_height / 2);
  h1off = (dc->wall_taper > 0 ? -dc->wall_height / 2 : 0);

  if (!dc->clockwise)
    z1 = -z1, z_inc = -z_inc, h1off = -h1off;

  /* Leading end-cap
   */
  if (!wire && h1 > 0)
    {
      GLfloat nx, ny;
      glFrontFace(GL_CCW);
      glBegin(GL_QUADS);
      nx = cos (th + M_PI/2);
      ny = sin (th + M_PI/2);
      glNormal3f(nx, ny, 0);
      glVertex3f( x1, y1,  z1 - h1 + h1off);
      glVertex3f( x1, y1,  z1 + h1 + h1off);
      glVertex3f(x1b, y1b, z1 + h1 + h1off);
      glVertex3f(x1b, y1b, z1 - h1 + h1off);
      glEnd();
    }

  while (th + th_inc <= max_th)
    {
      th += th_inc;

      x2 = cos (th);
      y2 = sin (th);
      z2 = z1 + z_inc;
      x2b = x2 * (1 - dc->wall_thickness);
      y2b = y2 * (1 - dc->wall_thickness);

      h2 = h1;
      h2off = h1off;

      if (dc->wall_taper > 0)
        {
          h2off = 0;
          if (th < dc->wall_taper)
            {
              h2 = dc->wall_height/2 * cos (M_PI / 2
                                            * (1 - (th / dc->wall_taper)));
              if (dc->clockwise)
                h2off = h2 - dc->wall_height/2;
              else
                h2off = dc->wall_height/2 - h2;
            }
          else if (th >= max_th - dc->wall_taper)
            {
              if (th + th_inc > max_th) /* edge case: always come to a point */
                h2 = 0;
              else
                h2 = dc->wall_height/2 * cos (M_PI / 2
                                              * (1 - ((max_th - th)
                                                      / dc->wall_taper)));
              if (dc->clockwise)
                h2off = dc->wall_height/2 - h2;
              else
                h2off = h2 - dc->wall_height/2;
            }
        }

      /* outer face
       */
      glFrontFace(GL_CW);
      glBegin(wire ? GL_LINES : GL_QUADS);
      glNormal3f(x1, y1, 0);
      glVertex3f(x1, y1, z1 - h1 + h1off);
      glVertex3f(x1, y1, z1 + h1 + h1off);
      glNormal3f(x2, y2, 0);
      glVertex3f(x2, y2, z2 + h2 + h2off);
      glVertex3f(x2, y2, z2 - h2 + h2off);
      glEnd();

      /* inner face
       */
      glFrontFace(GL_CCW);
      glBegin(wire ? GL_LINES : GL_QUADS);
      glNormal3f(-x1b, -y1b, 0);
      glVertex3f( x1b,  y1b, z1 - h1 + h1off);
      glVertex3f( x1b,  y1b, z1 + h1 + h1off);
      glNormal3f(-x2b, -y2b, 0);
      glVertex3f( x2b,  y2b, z2 + h2 + h2off);
      glVertex3f( x2b,  y2b, z2 - h2 + h2off);
      glEnd();

      /* top face
       */
      glFrontFace(GL_CCW);
      /* glNormal3f(0, 0, 1);*/
      do_normal (x2,   y2,  z2 + h2 + h2off,
                 x2b,  y2b, z2 + h2 + h2off,
                 x1b,  y1b, z1 + h1 + h1off);
      glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
      glVertex3f( x2,   y2,  z2 + h2 + h2off);
      glVertex3f( x2b,  y2b, z2 + h2 + h2off);
      glVertex3f( x1b,  y1b, z1 + h1 + h1off);
      glVertex3f( x1,   y1,  z1 + h1 + h1off);

      glEnd();

      /* bottom face
       */
      glFrontFace(GL_CCW);
      do_normal ( x1,   y1,  z1 - h1 + h1off,
                  x1b,  y1b, z1 - h1 + h1off,
                  x2b,  y2b, z2 - h2 + h2off);
      glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
      glNormal3f(0, 0, -1);
      glVertex3f( x1,   y1,  z1 - h1 + h1off);
      glVertex3f( x1b,  y1b, z1 - h1 + h1off);
      glVertex3f( x2b,  y2b, z2 - h2 + h2off);
      glVertex3f( x2,   y2,  z2 - h2 + h2off);
      glEnd();

      x1 = x2;
      y1 = y2;
      x1b = x2b;
      y1b = y2b;
      z1 += z_inc;
      h1 = h2;
      h1off = h2off;
    }

  /* Trailing end-cap
   */
  if (!wire && h2 > 0)
    {
      GLfloat nx, ny;
      glFrontFace(GL_CW);
      glBegin(GL_QUADS);
      nx = cos (th + M_PI/2);
      ny = sin (th + M_PI/2);
      glNormal3f(nx, ny, 0);
      glVertex3f(x2,  y2,  z1 - h2 + h2off);
      glVertex3f(x2,  y2,  z1 + h2 + h2off);
      glVertex3f(x2b, y2b, z1 + h2 + h2off);
      glVertex3f(x2b, y2b, z1 - h2 + h2off);
      glEnd();
    }
}