1f220fa62Smrg/*
2f220fa62Smrg * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3f220fa62Smrg * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
4f220fa62Smrg *
5f220fa62Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6f220fa62Smrg * copy of this software and associated documentation files (the "Software"),
7f220fa62Smrg * to deal in the Software without restriction, including without limitation
8f220fa62Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9f220fa62Smrg * and/or sell copies of the Software, and to permit persons to whom the
10f220fa62Smrg * Software is furnished to do so, subject to the following conditions:
11f220fa62Smrg *
12f220fa62Smrg * The above copyright notice including the dates of first publication and
13f220fa62Smrg * either this permission notice or a reference to
14f220fa62Smrg * http://oss.sgi.com/projects/FreeB/
15f220fa62Smrg * shall be included in all copies or substantial portions of the Software.
16f220fa62Smrg *
17f220fa62Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18f220fa62Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19f220fa62Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20f220fa62Smrg * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21f220fa62Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
22f220fa62Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23f220fa62Smrg * SOFTWARE.
24f220fa62Smrg *
25f220fa62Smrg * Except as contained in this notice, the name of Silicon Graphics, Inc.
26f220fa62Smrg * shall not be used in advertising or otherwise to promote the sale, use or
27f220fa62Smrg * other dealings in this Software without prior written authorization from
28f220fa62Smrg * Silicon Graphics, Inc.
29f220fa62Smrg */
30f220fa62Smrg
31f220fa62Smrg#include "gluos.h"
32f220fa62Smrg#include "gluint.h"
33f220fa62Smrg#include <stdio.h>
34f220fa62Smrg#include <stdlib.h>
35f220fa62Smrg#include <math.h>
36f220fa62Smrg#include <GL/gl.h>
37f220fa62Smrg#include <GL/glu.h>
38f220fa62Smrg
39f220fa62Smrg/* Make it not a power of two to avoid cache thrashing on the chip */
40f220fa62Smrg#define CACHE_SIZE	240
41f220fa62Smrg
42f220fa62Smrg#undef	PI
43f220fa62Smrg#define PI	      3.14159265358979323846
44f220fa62Smrg
45f220fa62Smrgstruct GLUquadric {
46f220fa62Smrg    GLint	normals;
47f220fa62Smrg    GLboolean	textureCoords;
48f220fa62Smrg    GLint	orientation;
49f220fa62Smrg    GLint	drawStyle;
50f220fa62Smrg    void	(GLAPIENTRY *errorCallback)( GLint );
51f220fa62Smrg};
52f220fa62Smrg
53f220fa62SmrgGLUquadric * GLAPIENTRY
54f220fa62SmrggluNewQuadric(void)
55f220fa62Smrg{
56f220fa62Smrg    GLUquadric *newstate;
57f220fa62Smrg
58f220fa62Smrg    newstate = (GLUquadric *) malloc(sizeof(GLUquadric));
59f220fa62Smrg    if (newstate == NULL) {
60f220fa62Smrg	/* Can't report an error at this point... */
61f220fa62Smrg	return NULL;
62f220fa62Smrg    }
63f220fa62Smrg    newstate->normals = GLU_SMOOTH;
64f220fa62Smrg    newstate->textureCoords = GL_FALSE;
65f220fa62Smrg    newstate->orientation = GLU_OUTSIDE;
66f220fa62Smrg    newstate->drawStyle = GLU_FILL;
67f220fa62Smrg    newstate->errorCallback = NULL;
68f220fa62Smrg    return newstate;
69f220fa62Smrg}
70f220fa62Smrg
71f220fa62Smrg
72f220fa62Smrgvoid GLAPIENTRY
73f220fa62SmrggluDeleteQuadric(GLUquadric *state)
74f220fa62Smrg{
75f220fa62Smrg    free(state);
76f220fa62Smrg}
77f220fa62Smrg
78f220fa62Smrgstatic void gluQuadricError(GLUquadric *qobj, GLenum which)
79f220fa62Smrg{
80f220fa62Smrg    if (qobj->errorCallback) {
81f220fa62Smrg	qobj->errorCallback(which);
82f220fa62Smrg    }
83f220fa62Smrg}
84f220fa62Smrg
85f220fa62Smrgvoid GLAPIENTRY
86f220fa62SmrggluQuadricCallback(GLUquadric *qobj, GLenum which, _GLUfuncptr fn)
87f220fa62Smrg{
88f220fa62Smrg    switch (which) {
89f220fa62Smrg      case GLU_ERROR:
90f220fa62Smrg	qobj->errorCallback = (void (GLAPIENTRY *)(GLint)) fn;
91f220fa62Smrg	break;
92f220fa62Smrg      default:
93f220fa62Smrg	gluQuadricError(qobj, GLU_INVALID_ENUM);
94f220fa62Smrg	return;
95f220fa62Smrg    }
96f220fa62Smrg}
97f220fa62Smrg
98f220fa62Smrgvoid GLAPIENTRY
99f220fa62SmrggluQuadricNormals(GLUquadric *qobj, GLenum normals)
100f220fa62Smrg{
101f220fa62Smrg    switch (normals) {
102f220fa62Smrg      case GLU_SMOOTH:
103f220fa62Smrg      case GLU_FLAT:
104f220fa62Smrg      case GLU_NONE:
105f220fa62Smrg	break;
106f220fa62Smrg      default:
107f220fa62Smrg	gluQuadricError(qobj, GLU_INVALID_ENUM);
108f220fa62Smrg	return;
109f220fa62Smrg    }
110f220fa62Smrg    qobj->normals = normals;
111f220fa62Smrg}
112f220fa62Smrg
113f220fa62Smrgvoid GLAPIENTRY
114f220fa62SmrggluQuadricTexture(GLUquadric *qobj, GLboolean textureCoords)
115f220fa62Smrg{
116f220fa62Smrg    qobj->textureCoords = textureCoords;
117f220fa62Smrg}
118f220fa62Smrg
119f220fa62Smrgvoid GLAPIENTRY
120f220fa62SmrggluQuadricOrientation(GLUquadric *qobj, GLenum orientation)
121f220fa62Smrg{
122f220fa62Smrg    switch(orientation) {
123f220fa62Smrg      case GLU_OUTSIDE:
124f220fa62Smrg      case GLU_INSIDE:
125f220fa62Smrg	break;
126f220fa62Smrg      default:
127f220fa62Smrg	gluQuadricError(qobj, GLU_INVALID_ENUM);
128f220fa62Smrg	return;
129f220fa62Smrg    }
130f220fa62Smrg    qobj->orientation = orientation;
131f220fa62Smrg}
132f220fa62Smrg
133f220fa62Smrgvoid GLAPIENTRY
134f220fa62SmrggluQuadricDrawStyle(GLUquadric *qobj, GLenum drawStyle)
135f220fa62Smrg{
136f220fa62Smrg    switch(drawStyle) {
137f220fa62Smrg      case GLU_POINT:
138f220fa62Smrg      case GLU_LINE:
139f220fa62Smrg      case GLU_FILL:
140f220fa62Smrg      case GLU_SILHOUETTE:
141f220fa62Smrg	break;
142f220fa62Smrg      default:
143f220fa62Smrg	gluQuadricError(qobj, GLU_INVALID_ENUM);
144f220fa62Smrg	return;
145f220fa62Smrg    }
146f220fa62Smrg    qobj->drawStyle = drawStyle;
147f220fa62Smrg}
148f220fa62Smrg
149f220fa62Smrgvoid GLAPIENTRY
150f220fa62SmrggluCylinder(GLUquadric *qobj, GLdouble baseRadius, GLdouble topRadius,
151f220fa62Smrg		GLdouble height, GLint slices, GLint stacks)
152f220fa62Smrg{
153f220fa62Smrg    GLint i,j;
154f220fa62Smrg    GLfloat sinCache[CACHE_SIZE];
155f220fa62Smrg    GLfloat cosCache[CACHE_SIZE];
156f220fa62Smrg    GLfloat sinCache2[CACHE_SIZE];
157f220fa62Smrg    GLfloat cosCache2[CACHE_SIZE];
158f220fa62Smrg    GLfloat sinCache3[CACHE_SIZE];
159f220fa62Smrg    GLfloat cosCache3[CACHE_SIZE];
160f220fa62Smrg    GLfloat angle;
161f220fa62Smrg    GLfloat zLow, zHigh;
162f220fa62Smrg    GLfloat sintemp, costemp;
163f220fa62Smrg    GLfloat length;
164f220fa62Smrg    GLfloat deltaRadius;
165f220fa62Smrg    GLfloat zNormal;
166f220fa62Smrg    GLfloat xyNormalRatio;
167f220fa62Smrg    GLfloat radiusLow, radiusHigh;
168f220fa62Smrg    int needCache2, needCache3;
169f220fa62Smrg
170f220fa62Smrg    if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
171f220fa62Smrg
172f220fa62Smrg    if (slices < 2 || stacks < 1 || baseRadius < 0.0 || topRadius < 0.0 ||
173f220fa62Smrg	    height < 0.0) {
174f220fa62Smrg	gluQuadricError(qobj, GLU_INVALID_VALUE);
175f220fa62Smrg	return;
176f220fa62Smrg    }
177f220fa62Smrg
178f220fa62Smrg    /* Compute length (needed for normal calculations) */
179f220fa62Smrg    deltaRadius = baseRadius - topRadius;
180f220fa62Smrg    length = SQRT(deltaRadius*deltaRadius + height*height);
181f220fa62Smrg    if (length == 0.0) {
182f220fa62Smrg	gluQuadricError(qobj, GLU_INVALID_VALUE);
183f220fa62Smrg	return;
184f220fa62Smrg    }
185f220fa62Smrg
186f220fa62Smrg    /* Cache is the vertex locations cache */
187f220fa62Smrg    /* Cache2 is the various normals at the vertices themselves */
188f220fa62Smrg    /* Cache3 is the various normals for the faces */
189f220fa62Smrg    needCache2 = needCache3 = 0;
190f220fa62Smrg    if (qobj->normals == GLU_SMOOTH) {
191f220fa62Smrg	needCache2 = 1;
192f220fa62Smrg    }
193f220fa62Smrg
194f220fa62Smrg    if (qobj->normals == GLU_FLAT) {
195f220fa62Smrg	if (qobj->drawStyle != GLU_POINT) {
196f220fa62Smrg	    needCache3 = 1;
197f220fa62Smrg	}
198f220fa62Smrg	if (qobj->drawStyle == GLU_LINE) {
199f220fa62Smrg	    needCache2 = 1;
200f220fa62Smrg	}
201f220fa62Smrg    }
202f220fa62Smrg
203f220fa62Smrg    zNormal = deltaRadius / length;
204f220fa62Smrg    xyNormalRatio = height / length;
205f220fa62Smrg
206f220fa62Smrg    for (i = 0; i < slices; i++) {
207f220fa62Smrg	angle = 2 * PI * i / slices;
208f220fa62Smrg	if (needCache2) {
209f220fa62Smrg	    if (qobj->orientation == GLU_OUTSIDE) {
210f220fa62Smrg		sinCache2[i] = xyNormalRatio * SIN(angle);
211f220fa62Smrg		cosCache2[i] = xyNormalRatio * COS(angle);
212f220fa62Smrg	    } else {
213f220fa62Smrg		sinCache2[i] = -xyNormalRatio * SIN(angle);
214f220fa62Smrg		cosCache2[i] = -xyNormalRatio * COS(angle);
215f220fa62Smrg	    }
216f220fa62Smrg	}
217f220fa62Smrg	sinCache[i] = SIN(angle);
218f220fa62Smrg	cosCache[i] = COS(angle);
219f220fa62Smrg    }
220f220fa62Smrg
221f220fa62Smrg    if (needCache3) {
222f220fa62Smrg	for (i = 0; i < slices; i++) {
223f220fa62Smrg	    angle = 2 * PI * (i-0.5) / slices;
224f220fa62Smrg	    if (qobj->orientation == GLU_OUTSIDE) {
225f220fa62Smrg		sinCache3[i] = xyNormalRatio * SIN(angle);
226f220fa62Smrg		cosCache3[i] = xyNormalRatio * COS(angle);
227f220fa62Smrg	    } else {
228f220fa62Smrg		sinCache3[i] = -xyNormalRatio * SIN(angle);
229f220fa62Smrg		cosCache3[i] = -xyNormalRatio * COS(angle);
230f220fa62Smrg	    }
231f220fa62Smrg	}
232f220fa62Smrg    }
233f220fa62Smrg
234f220fa62Smrg    sinCache[slices] = sinCache[0];
235f220fa62Smrg    cosCache[slices] = cosCache[0];
236f220fa62Smrg    if (needCache2) {
237f220fa62Smrg	sinCache2[slices] = sinCache2[0];
238f220fa62Smrg	cosCache2[slices] = cosCache2[0];
239f220fa62Smrg    }
240f220fa62Smrg    if (needCache3) {
241f220fa62Smrg	sinCache3[slices] = sinCache3[0];
242f220fa62Smrg	cosCache3[slices] = cosCache3[0];
243f220fa62Smrg    }
244f220fa62Smrg
245f220fa62Smrg    switch (qobj->drawStyle) {
246f220fa62Smrg      case GLU_FILL:
247f220fa62Smrg	/* Note:
248f220fa62Smrg	** An argument could be made for using a TRIANGLE_FAN for the end
249f220fa62Smrg	** of the cylinder of either radii is 0.0 (a cone).  However, a
250f220fa62Smrg	** TRIANGLE_FAN would not work in smooth shading mode (the common
251f220fa62Smrg	** case) because the normal for the apex is different for every
252f220fa62Smrg	** triangle (and TRIANGLE_FAN doesn't let me respecify that normal).
253f220fa62Smrg	** Now, my choice is GL_TRIANGLES, or leave the GL_QUAD_STRIP and
254f220fa62Smrg	** just let the GL trivially reject one of the two triangles of the
255f220fa62Smrg	** QUAD.  GL_QUAD_STRIP is probably faster, so I will leave this code
256f220fa62Smrg	** alone.
257f220fa62Smrg	*/
258f220fa62Smrg	for (j = 0; j < stacks; j++) {
259f220fa62Smrg	    zLow = j * height / stacks;
260f220fa62Smrg	    zHigh = (j + 1) * height / stacks;
261f220fa62Smrg	    radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
262f220fa62Smrg	    radiusHigh = baseRadius - deltaRadius * ((float) (j + 1) / stacks);
263f220fa62Smrg
264f220fa62Smrg	    glBegin(GL_QUAD_STRIP);
265f220fa62Smrg	    for (i = 0; i <= slices; i++) {
266f220fa62Smrg		switch(qobj->normals) {
267f220fa62Smrg		  case GLU_FLAT:
268f220fa62Smrg		    glNormal3f(sinCache3[i], cosCache3[i], zNormal);
269f220fa62Smrg		    break;
270f220fa62Smrg		  case GLU_SMOOTH:
271f220fa62Smrg		    glNormal3f(sinCache2[i], cosCache2[i], zNormal);
272f220fa62Smrg		    break;
273f220fa62Smrg		  case GLU_NONE:
274f220fa62Smrg		  default:
275f220fa62Smrg		    break;
276f220fa62Smrg		}
277f220fa62Smrg		if (qobj->orientation == GLU_OUTSIDE) {
278f220fa62Smrg		    if (qobj->textureCoords) {
279f220fa62Smrg			glTexCoord2f(1 - (float) i / slices,
280f220fa62Smrg				(float) j / stacks);
281f220fa62Smrg		    }
282f220fa62Smrg		    glVertex3f(radiusLow * sinCache[i],
283f220fa62Smrg			    radiusLow * cosCache[i], zLow);
284f220fa62Smrg		    if (qobj->textureCoords) {
285f220fa62Smrg			glTexCoord2f(1 - (float) i / slices,
286f220fa62Smrg				(float) (j+1) / stacks);
287f220fa62Smrg		    }
288f220fa62Smrg		    glVertex3f(radiusHigh * sinCache[i],
289f220fa62Smrg			    radiusHigh * cosCache[i], zHigh);
290f220fa62Smrg		} else {
291f220fa62Smrg		    if (qobj->textureCoords) {
292f220fa62Smrg			glTexCoord2f(1 - (float) i / slices,
293f220fa62Smrg				(float) (j+1) / stacks);
294f220fa62Smrg		    }
295f220fa62Smrg		    glVertex3f(radiusHigh * sinCache[i],
296f220fa62Smrg			    radiusHigh * cosCache[i], zHigh);
297f220fa62Smrg		    if (qobj->textureCoords) {
298f220fa62Smrg			glTexCoord2f(1 - (float) i / slices,
299f220fa62Smrg				(float) j / stacks);
300f220fa62Smrg		    }
301f220fa62Smrg		    glVertex3f(radiusLow * sinCache[i],
302f220fa62Smrg			    radiusLow * cosCache[i], zLow);
303f220fa62Smrg		}
304f220fa62Smrg	    }
305f220fa62Smrg	    glEnd();
306f220fa62Smrg	}
307f220fa62Smrg	break;
308f220fa62Smrg      case GLU_POINT:
309f220fa62Smrg	glBegin(GL_POINTS);
310f220fa62Smrg	for (i = 0; i < slices; i++) {
311f220fa62Smrg	    switch(qobj->normals) {
312f220fa62Smrg	      case GLU_FLAT:
313f220fa62Smrg	      case GLU_SMOOTH:
314f220fa62Smrg		glNormal3f(sinCache2[i], cosCache2[i], zNormal);
315f220fa62Smrg		break;
316f220fa62Smrg	      case GLU_NONE:
317f220fa62Smrg	      default:
318f220fa62Smrg		break;
319f220fa62Smrg	    }
320f220fa62Smrg	    sintemp = sinCache[i];
321f220fa62Smrg	    costemp = cosCache[i];
322f220fa62Smrg	    for (j = 0; j <= stacks; j++) {
323f220fa62Smrg		zLow = j * height / stacks;
324f220fa62Smrg		radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
325f220fa62Smrg
326f220fa62Smrg		if (qobj->textureCoords) {
327f220fa62Smrg		    glTexCoord2f(1 - (float) i / slices,
328f220fa62Smrg			    (float) j / stacks);
329f220fa62Smrg		}
330f220fa62Smrg		glVertex3f(radiusLow * sintemp,
331f220fa62Smrg			radiusLow * costemp, zLow);
332f220fa62Smrg	    }
333f220fa62Smrg	}
334f220fa62Smrg	glEnd();
335f220fa62Smrg	break;
336f220fa62Smrg      case GLU_LINE:
337f220fa62Smrg	for (j = 1; j < stacks; j++) {
338f220fa62Smrg	    zLow = j * height / stacks;
339f220fa62Smrg	    radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
340f220fa62Smrg
341f220fa62Smrg	    glBegin(GL_LINE_STRIP);
342f220fa62Smrg	    for (i = 0; i <= slices; i++) {
343f220fa62Smrg		switch(qobj->normals) {
344f220fa62Smrg		  case GLU_FLAT:
345f220fa62Smrg		    glNormal3f(sinCache3[i], cosCache3[i], zNormal);
346f220fa62Smrg		    break;
347f220fa62Smrg		  case GLU_SMOOTH:
348f220fa62Smrg		    glNormal3f(sinCache2[i], cosCache2[i], zNormal);
349f220fa62Smrg		    break;
350f220fa62Smrg		  case GLU_NONE:
351f220fa62Smrg		  default:
352f220fa62Smrg		    break;
353f220fa62Smrg		}
354f220fa62Smrg		if (qobj->textureCoords) {
355f220fa62Smrg		    glTexCoord2f(1 - (float) i / slices,
356f220fa62Smrg			    (float) j / stacks);
357f220fa62Smrg		}
358f220fa62Smrg		glVertex3f(radiusLow * sinCache[i],
359f220fa62Smrg			radiusLow * cosCache[i], zLow);
360f220fa62Smrg	    }
361f220fa62Smrg	    glEnd();
362f220fa62Smrg	}
363f220fa62Smrg	/* Intentionally fall through here... */
364f220fa62Smrg      case GLU_SILHOUETTE:
365f220fa62Smrg	for (j = 0; j <= stacks; j += stacks) {
366f220fa62Smrg	    zLow = j * height / stacks;
367f220fa62Smrg	    radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
368f220fa62Smrg
369f220fa62Smrg	    glBegin(GL_LINE_STRIP);
370f220fa62Smrg	    for (i = 0; i <= slices; i++) {
371f220fa62Smrg		switch(qobj->normals) {
372f220fa62Smrg		  case GLU_FLAT:
373f220fa62Smrg		    glNormal3f(sinCache3[i], cosCache3[i], zNormal);
374f220fa62Smrg		    break;
375f220fa62Smrg		  case GLU_SMOOTH:
376f220fa62Smrg		    glNormal3f(sinCache2[i], cosCache2[i], zNormal);
377f220fa62Smrg		    break;
378f220fa62Smrg		  case GLU_NONE:
379f220fa62Smrg		  default:
380f220fa62Smrg		    break;
381f220fa62Smrg		}
382f220fa62Smrg		if (qobj->textureCoords) {
383f220fa62Smrg		    glTexCoord2f(1 - (float) i / slices,
384f220fa62Smrg			    (float) j / stacks);
385f220fa62Smrg		}
386f220fa62Smrg		glVertex3f(radiusLow * sinCache[i], radiusLow * cosCache[i],
387f220fa62Smrg			zLow);
388f220fa62Smrg	    }
389f220fa62Smrg	    glEnd();
390f220fa62Smrg	}
391f220fa62Smrg	for (i = 0; i < slices; i++) {
392f220fa62Smrg	    switch(qobj->normals) {
393f220fa62Smrg	      case GLU_FLAT:
394f220fa62Smrg	      case GLU_SMOOTH:
395f220fa62Smrg		glNormal3f(sinCache2[i], cosCache2[i], 0.0);
396f220fa62Smrg		break;
397f220fa62Smrg	      case GLU_NONE:
398f220fa62Smrg	      default:
399f220fa62Smrg		break;
400f220fa62Smrg	    }
401f220fa62Smrg	    sintemp = sinCache[i];
402f220fa62Smrg	    costemp = cosCache[i];
403f220fa62Smrg	    glBegin(GL_LINE_STRIP);
404f220fa62Smrg	    for (j = 0; j <= stacks; j++) {
405f220fa62Smrg		zLow = j * height / stacks;
406f220fa62Smrg		radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
407f220fa62Smrg
408f220fa62Smrg		if (qobj->textureCoords) {
409f220fa62Smrg		    glTexCoord2f(1 - (float) i / slices,
410f220fa62Smrg			    (float) j / stacks);
411f220fa62Smrg		}
412f220fa62Smrg		glVertex3f(radiusLow * sintemp,
413f220fa62Smrg			radiusLow * costemp, zLow);
414f220fa62Smrg	    }
415f220fa62Smrg	    glEnd();
416f220fa62Smrg	}
417f220fa62Smrg	break;
418f220fa62Smrg      default:
419f220fa62Smrg	break;
420f220fa62Smrg    }
421f220fa62Smrg}
422f220fa62Smrg
423f220fa62Smrgvoid GLAPIENTRY
424f220fa62SmrggluDisk(GLUquadric *qobj, GLdouble innerRadius, GLdouble outerRadius,
425f220fa62Smrg	    GLint slices, GLint loops)
426f220fa62Smrg{
427f220fa62Smrg    gluPartialDisk(qobj, innerRadius, outerRadius, slices, loops, 0.0, 360.0);
428f220fa62Smrg}
429f220fa62Smrg
430f220fa62Smrgvoid GLAPIENTRY
431f220fa62SmrggluPartialDisk(GLUquadric *qobj, GLdouble innerRadius,
432f220fa62Smrg		   GLdouble outerRadius, GLint slices, GLint loops,
433f220fa62Smrg		   GLdouble startAngle, GLdouble sweepAngle)
434f220fa62Smrg{
435f220fa62Smrg    GLint i,j;
436f220fa62Smrg    GLfloat sinCache[CACHE_SIZE];
437f220fa62Smrg    GLfloat cosCache[CACHE_SIZE];
438f220fa62Smrg    GLfloat angle;
439f220fa62Smrg    GLfloat sintemp, costemp;
440f220fa62Smrg    GLfloat deltaRadius;
441f220fa62Smrg    GLfloat radiusLow, radiusHigh;
442f220fa62Smrg    GLfloat texLow = 0.0, texHigh = 0.0;
443f220fa62Smrg    GLfloat angleOffset;
444f220fa62Smrg    GLint slices2;
445f220fa62Smrg    GLint finish;
446f220fa62Smrg
447f220fa62Smrg    if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
448f220fa62Smrg    if (slices < 2 || loops < 1 || outerRadius <= 0.0 || innerRadius < 0.0 ||
449f220fa62Smrg	    innerRadius > outerRadius) {
450f220fa62Smrg	gluQuadricError(qobj, GLU_INVALID_VALUE);
451f220fa62Smrg	return;
452f220fa62Smrg    }
453f220fa62Smrg
454f220fa62Smrg    if (sweepAngle < -360.0) sweepAngle = 360.0;
455f220fa62Smrg    if (sweepAngle > 360.0) sweepAngle = 360.0;
456f220fa62Smrg    if (sweepAngle < 0) {
457f220fa62Smrg	startAngle += sweepAngle;
458f220fa62Smrg	sweepAngle = -sweepAngle;
459f220fa62Smrg    }
460f220fa62Smrg
461f220fa62Smrg    if (sweepAngle == 360.0) {
462f220fa62Smrg	slices2 = slices;
463f220fa62Smrg    } else {
464f220fa62Smrg	slices2 = slices + 1;
465f220fa62Smrg    }
466f220fa62Smrg
467f220fa62Smrg    /* Compute length (needed for normal calculations) */
468f220fa62Smrg    deltaRadius = outerRadius - innerRadius;
469f220fa62Smrg
470f220fa62Smrg    /* Cache is the vertex locations cache */
471f220fa62Smrg
472f220fa62Smrg    angleOffset = startAngle / 180.0 * PI;
473f220fa62Smrg    for (i = 0; i <= slices; i++) {
474f220fa62Smrg	angle = angleOffset + ((PI * sweepAngle) / 180.0) * i / slices;
475f220fa62Smrg	sinCache[i] = SIN(angle);
476f220fa62Smrg	cosCache[i] = COS(angle);
477f220fa62Smrg    }
478f220fa62Smrg
479f220fa62Smrg    if (sweepAngle == 360.0) {
480f220fa62Smrg	sinCache[slices] = sinCache[0];
481f220fa62Smrg	cosCache[slices] = cosCache[0];
482f220fa62Smrg    }
483f220fa62Smrg
484f220fa62Smrg    switch(qobj->normals) {
485f220fa62Smrg      case GLU_FLAT:
486f220fa62Smrg      case GLU_SMOOTH:
487f220fa62Smrg	if (qobj->orientation == GLU_OUTSIDE) {
488f220fa62Smrg	    glNormal3f(0.0, 0.0, 1.0);
489f220fa62Smrg	} else {
490f220fa62Smrg	    glNormal3f(0.0, 0.0, -1.0);
491f220fa62Smrg	}
492f220fa62Smrg	break;
493f220fa62Smrg      default:
494f220fa62Smrg      case GLU_NONE:
495f220fa62Smrg	break;
496f220fa62Smrg    }
497f220fa62Smrg
498f220fa62Smrg    switch (qobj->drawStyle) {
499f220fa62Smrg      case GLU_FILL:
500f220fa62Smrg	if (innerRadius == 0.0) {
501f220fa62Smrg	    finish = loops - 1;
502f220fa62Smrg	    /* Triangle strip for inner polygons */
503f220fa62Smrg	    glBegin(GL_TRIANGLE_FAN);
504f220fa62Smrg	    if (qobj->textureCoords) {
505f220fa62Smrg		glTexCoord2f(0.5, 0.5);
506f220fa62Smrg	    }
507f220fa62Smrg	    glVertex3f(0.0, 0.0, 0.0);
508f220fa62Smrg	    radiusLow = outerRadius -
509f220fa62Smrg		    deltaRadius * ((float) (loops-1) / loops);
510f220fa62Smrg	    if (qobj->textureCoords) {
511f220fa62Smrg		texLow = radiusLow / outerRadius / 2;
512f220fa62Smrg	    }
513f220fa62Smrg
514f220fa62Smrg	    if (qobj->orientation == GLU_OUTSIDE) {
515f220fa62Smrg		for (i = slices; i >= 0; i--) {
516f220fa62Smrg		    if (qobj->textureCoords) {
517f220fa62Smrg			glTexCoord2f(texLow * sinCache[i] + 0.5,
518f220fa62Smrg				texLow * cosCache[i] + 0.5);
519f220fa62Smrg		    }
520f220fa62Smrg		    glVertex3f(radiusLow * sinCache[i],
521f220fa62Smrg			    radiusLow * cosCache[i], 0.0);
522f220fa62Smrg		}
523f220fa62Smrg	    } else {
524f220fa62Smrg		for (i = 0; i <= slices; i++) {
525f220fa62Smrg		    if (qobj->textureCoords) {
526f220fa62Smrg			glTexCoord2f(texLow * sinCache[i] + 0.5,
527f220fa62Smrg				texLow * cosCache[i] + 0.5);
528f220fa62Smrg		    }
529f220fa62Smrg		    glVertex3f(radiusLow * sinCache[i],
530f220fa62Smrg			    radiusLow * cosCache[i], 0.0);
531f220fa62Smrg		}
532f220fa62Smrg	    }
533f220fa62Smrg	    glEnd();
534f220fa62Smrg	} else {
535f220fa62Smrg	    finish = loops;
536f220fa62Smrg	}
537f220fa62Smrg	for (j = 0; j < finish; j++) {
538f220fa62Smrg	    radiusLow = outerRadius - deltaRadius * ((float) j / loops);
539f220fa62Smrg	    radiusHigh = outerRadius - deltaRadius * ((float) (j + 1) / loops);
540f220fa62Smrg	    if (qobj->textureCoords) {
541f220fa62Smrg		texLow = radiusLow / outerRadius / 2;
542f220fa62Smrg		texHigh = radiusHigh / outerRadius / 2;
543f220fa62Smrg	    }
544f220fa62Smrg
545f220fa62Smrg	    glBegin(GL_QUAD_STRIP);
546f220fa62Smrg	    for (i = 0; i <= slices; i++) {
547f220fa62Smrg		if (qobj->orientation == GLU_OUTSIDE) {
548f220fa62Smrg		    if (qobj->textureCoords) {
549f220fa62Smrg			glTexCoord2f(texLow * sinCache[i] + 0.5,
550f220fa62Smrg				texLow * cosCache[i] + 0.5);
551f220fa62Smrg		    }
552f220fa62Smrg		    glVertex3f(radiusLow * sinCache[i],
553f220fa62Smrg			    radiusLow * cosCache[i], 0.0);
554f220fa62Smrg
555f220fa62Smrg		    if (qobj->textureCoords) {
556f220fa62Smrg			glTexCoord2f(texHigh * sinCache[i] + 0.5,
557f220fa62Smrg				texHigh * cosCache[i] + 0.5);
558f220fa62Smrg		    }
559f220fa62Smrg		    glVertex3f(radiusHigh * sinCache[i],
560f220fa62Smrg			    radiusHigh * cosCache[i], 0.0);
561f220fa62Smrg		} else {
562f220fa62Smrg		    if (qobj->textureCoords) {
563f220fa62Smrg			glTexCoord2f(texHigh * sinCache[i] + 0.5,
564f220fa62Smrg				texHigh * cosCache[i] + 0.5);
565f220fa62Smrg		    }
566f220fa62Smrg		    glVertex3f(radiusHigh * sinCache[i],
567f220fa62Smrg			    radiusHigh * cosCache[i], 0.0);
568f220fa62Smrg
569f220fa62Smrg		    if (qobj->textureCoords) {
570f220fa62Smrg			glTexCoord2f(texLow * sinCache[i] + 0.5,
571f220fa62Smrg				texLow * cosCache[i] + 0.5);
572f220fa62Smrg		    }
573f220fa62Smrg		    glVertex3f(radiusLow * sinCache[i],
574f220fa62Smrg			    radiusLow * cosCache[i], 0.0);
575f220fa62Smrg		}
576f220fa62Smrg	    }
577f220fa62Smrg	    glEnd();
578f220fa62Smrg	}
579f220fa62Smrg	break;
580f220fa62Smrg      case GLU_POINT:
581f220fa62Smrg	glBegin(GL_POINTS);
582f220fa62Smrg	for (i = 0; i < slices2; i++) {
583f220fa62Smrg	    sintemp = sinCache[i];
584f220fa62Smrg	    costemp = cosCache[i];
585f220fa62Smrg	    for (j = 0; j <= loops; j++) {
586f220fa62Smrg		radiusLow = outerRadius - deltaRadius * ((float) j / loops);
587f220fa62Smrg
588f220fa62Smrg		if (qobj->textureCoords) {
589f220fa62Smrg		    texLow = radiusLow / outerRadius / 2;
590f220fa62Smrg
591f220fa62Smrg		    glTexCoord2f(texLow * sinCache[i] + 0.5,
592f220fa62Smrg			    texLow * cosCache[i] + 0.5);
593f220fa62Smrg		}
594f220fa62Smrg		glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
595f220fa62Smrg	    }
596f220fa62Smrg	}
597f220fa62Smrg	glEnd();
598f220fa62Smrg	break;
599f220fa62Smrg      case GLU_LINE:
600f220fa62Smrg	if (innerRadius == outerRadius) {
601f220fa62Smrg	    glBegin(GL_LINE_STRIP);
602f220fa62Smrg
603f220fa62Smrg	    for (i = 0; i <= slices; i++) {
604f220fa62Smrg		if (qobj->textureCoords) {
605f220fa62Smrg		    glTexCoord2f(sinCache[i] / 2 + 0.5,
606f220fa62Smrg			    cosCache[i] / 2 + 0.5);
607f220fa62Smrg		}
608f220fa62Smrg		glVertex3f(innerRadius * sinCache[i],
609f220fa62Smrg			innerRadius * cosCache[i], 0.0);
610f220fa62Smrg	    }
611f220fa62Smrg	    glEnd();
612f220fa62Smrg	    break;
613f220fa62Smrg	}
614f220fa62Smrg	for (j = 0; j <= loops; j++) {
615f220fa62Smrg	    radiusLow = outerRadius - deltaRadius * ((float) j / loops);
616f220fa62Smrg	    if (qobj->textureCoords) {
617f220fa62Smrg		texLow = radiusLow / outerRadius / 2;
618f220fa62Smrg	    }
619f220fa62Smrg
620f220fa62Smrg	    glBegin(GL_LINE_STRIP);
621f220fa62Smrg	    for (i = 0; i <= slices; i++) {
622f220fa62Smrg		if (qobj->textureCoords) {
623f220fa62Smrg		    glTexCoord2f(texLow * sinCache[i] + 0.5,
624f220fa62Smrg			    texLow * cosCache[i] + 0.5);
625f220fa62Smrg		}
626f220fa62Smrg		glVertex3f(radiusLow * sinCache[i],
627f220fa62Smrg			radiusLow * cosCache[i], 0.0);
628f220fa62Smrg	    }
629f220fa62Smrg	    glEnd();
630f220fa62Smrg	}
631f220fa62Smrg	for (i=0; i < slices2; i++) {
632f220fa62Smrg	    sintemp = sinCache[i];
633f220fa62Smrg	    costemp = cosCache[i];
634f220fa62Smrg	    glBegin(GL_LINE_STRIP);
635f220fa62Smrg	    for (j = 0; j <= loops; j++) {
636f220fa62Smrg		radiusLow = outerRadius - deltaRadius * ((float) j / loops);
637f220fa62Smrg		if (qobj->textureCoords) {
638f220fa62Smrg		    texLow = radiusLow / outerRadius / 2;
639f220fa62Smrg		}
640f220fa62Smrg
641f220fa62Smrg		if (qobj->textureCoords) {
642f220fa62Smrg		    glTexCoord2f(texLow * sinCache[i] + 0.5,
643f220fa62Smrg			    texLow * cosCache[i] + 0.5);
644f220fa62Smrg		}
645f220fa62Smrg		glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
646f220fa62Smrg	    }
647f220fa62Smrg	    glEnd();
648f220fa62Smrg	}
649f220fa62Smrg	break;
650f220fa62Smrg      case GLU_SILHOUETTE:
651f220fa62Smrg	if (sweepAngle < 360.0) {
652f220fa62Smrg	    for (i = 0; i <= slices; i+= slices) {
653f220fa62Smrg		sintemp = sinCache[i];
654f220fa62Smrg		costemp = cosCache[i];
655f220fa62Smrg		glBegin(GL_LINE_STRIP);
656f220fa62Smrg		for (j = 0; j <= loops; j++) {
657f220fa62Smrg		    radiusLow = outerRadius - deltaRadius * ((float) j / loops);
658f220fa62Smrg
659f220fa62Smrg		    if (qobj->textureCoords) {
660f220fa62Smrg			texLow = radiusLow / outerRadius / 2;
661f220fa62Smrg			glTexCoord2f(texLow * sinCache[i] + 0.5,
662f220fa62Smrg				texLow * cosCache[i] + 0.5);
663f220fa62Smrg		    }
664f220fa62Smrg		    glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
665f220fa62Smrg		}
666f220fa62Smrg		glEnd();
667f220fa62Smrg	    }
668f220fa62Smrg	}
669f220fa62Smrg	for (j = 0; j <= loops; j += loops) {
670f220fa62Smrg	    radiusLow = outerRadius - deltaRadius * ((float) j / loops);
671f220fa62Smrg	    if (qobj->textureCoords) {
672f220fa62Smrg		texLow = radiusLow / outerRadius / 2;
673f220fa62Smrg	    }
674f220fa62Smrg
675f220fa62Smrg	    glBegin(GL_LINE_STRIP);
676f220fa62Smrg	    for (i = 0; i <= slices; i++) {
677f220fa62Smrg		if (qobj->textureCoords) {
678f220fa62Smrg		    glTexCoord2f(texLow * sinCache[i] + 0.5,
679f220fa62Smrg			    texLow * cosCache[i] + 0.5);
680f220fa62Smrg		}
681f220fa62Smrg		glVertex3f(radiusLow * sinCache[i],
682f220fa62Smrg			radiusLow * cosCache[i], 0.0);
683f220fa62Smrg	    }
684f220fa62Smrg	    glEnd();
685f220fa62Smrg	    if (innerRadius == outerRadius) break;
686f220fa62Smrg	}
687f220fa62Smrg	break;
688f220fa62Smrg      default:
689f220fa62Smrg	break;
690f220fa62Smrg    }
691f220fa62Smrg}
692f220fa62Smrg
693f220fa62Smrgvoid GLAPIENTRY
694f220fa62SmrggluSphere(GLUquadric *qobj, GLdouble radius, GLint slices, GLint stacks)
695f220fa62Smrg{
696f220fa62Smrg    GLint i,j;
697f220fa62Smrg    GLfloat sinCache1a[CACHE_SIZE];
698f220fa62Smrg    GLfloat cosCache1a[CACHE_SIZE];
699f220fa62Smrg    GLfloat sinCache2a[CACHE_SIZE];
700f220fa62Smrg    GLfloat cosCache2a[CACHE_SIZE];
701f220fa62Smrg    GLfloat sinCache3a[CACHE_SIZE];
702f220fa62Smrg    GLfloat cosCache3a[CACHE_SIZE];
703f220fa62Smrg    GLfloat sinCache1b[CACHE_SIZE];
704f220fa62Smrg    GLfloat cosCache1b[CACHE_SIZE];
705f220fa62Smrg    GLfloat sinCache2b[CACHE_SIZE];
706f220fa62Smrg    GLfloat cosCache2b[CACHE_SIZE];
707f220fa62Smrg    GLfloat sinCache3b[CACHE_SIZE];
708f220fa62Smrg    GLfloat cosCache3b[CACHE_SIZE];
709f220fa62Smrg    GLfloat angle;
710f220fa62Smrg    GLfloat zLow, zHigh;
711f220fa62Smrg    GLfloat sintemp1 = 0.0, sintemp2 = 0.0, sintemp3 = 0.0, sintemp4 = 0.0;
712f220fa62Smrg    GLfloat costemp1 = 0.0, costemp2 = 0.0, costemp3 = 0.0, costemp4 = 0.0;
713f220fa62Smrg    GLboolean needCache2, needCache3;
714f220fa62Smrg    GLint start, finish;
715f220fa62Smrg
716f220fa62Smrg    if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
717f220fa62Smrg    if (stacks >= CACHE_SIZE) stacks = CACHE_SIZE-1;
718f220fa62Smrg    if (slices < 2 || stacks < 1 || radius < 0.0) {
719f220fa62Smrg	gluQuadricError(qobj, GLU_INVALID_VALUE);
720f220fa62Smrg	return;
721f220fa62Smrg    }
722f220fa62Smrg
723f220fa62Smrg    /* Cache is the vertex locations cache */
724f220fa62Smrg    /* Cache2 is the various normals at the vertices themselves */
725f220fa62Smrg    /* Cache3 is the various normals for the faces */
726f220fa62Smrg    needCache2 = needCache3 = GL_FALSE;
727f220fa62Smrg
728f220fa62Smrg    if (qobj->normals == GLU_SMOOTH) {
729f220fa62Smrg	needCache2 = GL_TRUE;
730f220fa62Smrg    }
731f220fa62Smrg
732f220fa62Smrg    if (qobj->normals == GLU_FLAT) {
733f220fa62Smrg	if (qobj->drawStyle != GLU_POINT) {
734f220fa62Smrg	    needCache3 = GL_TRUE;
735f220fa62Smrg	}
736f220fa62Smrg	if (qobj->drawStyle == GLU_LINE) {
737f220fa62Smrg	    needCache2 = GL_TRUE;
738f220fa62Smrg	}
739f220fa62Smrg    }
740f220fa62Smrg
741f220fa62Smrg    for (i = 0; i < slices; i++) {
742f220fa62Smrg	angle = 2 * PI * i / slices;
743f220fa62Smrg	sinCache1a[i] = SIN(angle);
744f220fa62Smrg	cosCache1a[i] = COS(angle);
745f220fa62Smrg	if (needCache2) {
746f220fa62Smrg	    sinCache2a[i] = sinCache1a[i];
747f220fa62Smrg	    cosCache2a[i] = cosCache1a[i];
748f220fa62Smrg	}
749f220fa62Smrg    }
750f220fa62Smrg
751f220fa62Smrg    for (j = 0; j <= stacks; j++) {
752f220fa62Smrg	angle = PI * j / stacks;
753f220fa62Smrg	if (needCache2) {
754f220fa62Smrg	    if (qobj->orientation == GLU_OUTSIDE) {
755f220fa62Smrg		sinCache2b[j] = SIN(angle);
756f220fa62Smrg		cosCache2b[j] = COS(angle);
757f220fa62Smrg	    } else {
758f220fa62Smrg		sinCache2b[j] = -SIN(angle);
759f220fa62Smrg		cosCache2b[j] = -COS(angle);
760f220fa62Smrg	    }
761f220fa62Smrg	}
762f220fa62Smrg	sinCache1b[j] = radius * SIN(angle);
763f220fa62Smrg	cosCache1b[j] = radius * COS(angle);
764f220fa62Smrg    }
765f220fa62Smrg    /* Make sure it comes to a point */
766f220fa62Smrg    sinCache1b[0] = 0;
767f220fa62Smrg    sinCache1b[stacks] = 0;
768f220fa62Smrg
769f220fa62Smrg    if (needCache3) {
770f220fa62Smrg	for (i = 0; i < slices; i++) {
771f220fa62Smrg	    angle = 2 * PI * (i-0.5) / slices;
772f220fa62Smrg	    sinCache3a[i] = SIN(angle);
773f220fa62Smrg	    cosCache3a[i] = COS(angle);
774f220fa62Smrg	}
775f220fa62Smrg	for (j = 0; j <= stacks; j++) {
776f220fa62Smrg	    angle = PI * (j - 0.5) / stacks;
777f220fa62Smrg	    if (qobj->orientation == GLU_OUTSIDE) {
778f220fa62Smrg		sinCache3b[j] = SIN(angle);
779f220fa62Smrg		cosCache3b[j] = COS(angle);
780f220fa62Smrg	    } else {
781f220fa62Smrg		sinCache3b[j] = -SIN(angle);
782f220fa62Smrg		cosCache3b[j] = -COS(angle);
783f220fa62Smrg	    }
784f220fa62Smrg	}
785f220fa62Smrg    }
786f220fa62Smrg
787f220fa62Smrg    sinCache1a[slices] = sinCache1a[0];
788f220fa62Smrg    cosCache1a[slices] = cosCache1a[0];
789f220fa62Smrg    if (needCache2) {
790f220fa62Smrg	sinCache2a[slices] = sinCache2a[0];
791f220fa62Smrg	cosCache2a[slices] = cosCache2a[0];
792f220fa62Smrg    }
793f220fa62Smrg    if (needCache3) {
794f220fa62Smrg	sinCache3a[slices] = sinCache3a[0];
795f220fa62Smrg	cosCache3a[slices] = cosCache3a[0];
796f220fa62Smrg    }
797f220fa62Smrg
798f220fa62Smrg    switch (qobj->drawStyle) {
799f220fa62Smrg      case GLU_FILL:
800f220fa62Smrg	/* Do ends of sphere as TRIANGLE_FAN's (if not texturing)
801f220fa62Smrg	** We don't do it when texturing because we need to respecify the
802f220fa62Smrg	** texture coordinates of the apex for every adjacent vertex (because
803f220fa62Smrg	** it isn't a constant for that point)
804f220fa62Smrg	*/
805f220fa62Smrg	if (!(qobj->textureCoords)) {
806f220fa62Smrg	    start = 1;
807f220fa62Smrg	    finish = stacks - 1;
808f220fa62Smrg
809f220fa62Smrg	    /* Low end first (j == 0 iteration) */
810f220fa62Smrg	    sintemp2 = sinCache1b[1];
811f220fa62Smrg	    zHigh = cosCache1b[1];
812f220fa62Smrg	    switch(qobj->normals) {
813f220fa62Smrg	      case GLU_FLAT:
814f220fa62Smrg		sintemp3 = sinCache3b[1];
815f220fa62Smrg		costemp3 = cosCache3b[1];
816f220fa62Smrg		break;
817f220fa62Smrg	      case GLU_SMOOTH:
818f220fa62Smrg		sintemp3 = sinCache2b[1];
819f220fa62Smrg		costemp3 = cosCache2b[1];
820f220fa62Smrg		glNormal3f(sinCache2a[0] * sinCache2b[0],
821f220fa62Smrg			cosCache2a[0] * sinCache2b[0],
822f220fa62Smrg			cosCache2b[0]);
823f220fa62Smrg		break;
824f220fa62Smrg	      default:
825f220fa62Smrg		break;
826f220fa62Smrg	    }
827f220fa62Smrg	    glBegin(GL_TRIANGLE_FAN);
828f220fa62Smrg	    glVertex3f(0.0, 0.0, radius);
829f220fa62Smrg	    if (qobj->orientation == GLU_OUTSIDE) {
830f220fa62Smrg		for (i = slices; i >= 0; i--) {
831f220fa62Smrg		    switch(qobj->normals) {
832f220fa62Smrg		      case GLU_SMOOTH:
833f220fa62Smrg			glNormal3f(sinCache2a[i] * sintemp3,
834f220fa62Smrg				cosCache2a[i] * sintemp3,
835f220fa62Smrg				costemp3);
836f220fa62Smrg			break;
837f220fa62Smrg		      case GLU_FLAT:
838f220fa62Smrg			if (i != slices) {
839f220fa62Smrg			    glNormal3f(sinCache3a[i+1] * sintemp3,
840f220fa62Smrg				    cosCache3a[i+1] * sintemp3,
841f220fa62Smrg				    costemp3);
842f220fa62Smrg			}
843f220fa62Smrg			break;
844f220fa62Smrg		      case GLU_NONE:
845f220fa62Smrg		      default:
846f220fa62Smrg			break;
847f220fa62Smrg		    }
848f220fa62Smrg		    glVertex3f(sintemp2 * sinCache1a[i],
849f220fa62Smrg			    sintemp2 * cosCache1a[i], zHigh);
850f220fa62Smrg		}
851f220fa62Smrg	    } else {
852f220fa62Smrg		for (i = 0; i <= slices; i++) {
853f220fa62Smrg		    switch(qobj->normals) {
854f220fa62Smrg		      case GLU_SMOOTH:
855f220fa62Smrg			glNormal3f(sinCache2a[i] * sintemp3,
856f220fa62Smrg				cosCache2a[i] * sintemp3,
857f220fa62Smrg				costemp3);
858f220fa62Smrg			break;
859f220fa62Smrg		      case GLU_FLAT:
860f220fa62Smrg			glNormal3f(sinCache3a[i] * sintemp3,
861f220fa62Smrg				cosCache3a[i] * sintemp3,
862f220fa62Smrg				costemp3);
863f220fa62Smrg			break;
864f220fa62Smrg		      case GLU_NONE:
865f220fa62Smrg		      default:
866f220fa62Smrg			break;
867f220fa62Smrg		    }
868f220fa62Smrg		    glVertex3f(sintemp2 * sinCache1a[i],
869f220fa62Smrg			    sintemp2 * cosCache1a[i], zHigh);
870f220fa62Smrg		}
871f220fa62Smrg	    }
872f220fa62Smrg	    glEnd();
873f220fa62Smrg
874f220fa62Smrg	    /* High end next (j == stacks-1 iteration) */
875f220fa62Smrg	    sintemp2 = sinCache1b[stacks-1];
876f220fa62Smrg	    zHigh = cosCache1b[stacks-1];
877f220fa62Smrg	    switch(qobj->normals) {
878f220fa62Smrg	      case GLU_FLAT:
879f220fa62Smrg		sintemp3 = sinCache3b[stacks];
880f220fa62Smrg		costemp3 = cosCache3b[stacks];
881f220fa62Smrg		break;
882f220fa62Smrg	      case GLU_SMOOTH:
883f220fa62Smrg		sintemp3 = sinCache2b[stacks-1];
884f220fa62Smrg		costemp3 = cosCache2b[stacks-1];
885f220fa62Smrg		glNormal3f(sinCache2a[stacks] * sinCache2b[stacks],
886f220fa62Smrg			cosCache2a[stacks] * sinCache2b[stacks],
887f220fa62Smrg			cosCache2b[stacks]);
888f220fa62Smrg		break;
889f220fa62Smrg	      default:
890f220fa62Smrg		break;
891f220fa62Smrg	    }
892f220fa62Smrg	    glBegin(GL_TRIANGLE_FAN);
893f220fa62Smrg	    glVertex3f(0.0, 0.0, -radius);
894f220fa62Smrg	    if (qobj->orientation == GLU_OUTSIDE) {
895f220fa62Smrg		for (i = 0; i <= slices; i++) {
896f220fa62Smrg		    switch(qobj->normals) {
897f220fa62Smrg		      case GLU_SMOOTH:
898f220fa62Smrg			glNormal3f(sinCache2a[i] * sintemp3,
899f220fa62Smrg				cosCache2a[i] * sintemp3,
900f220fa62Smrg				costemp3);
901f220fa62Smrg			break;
902f220fa62Smrg		      case GLU_FLAT:
903f220fa62Smrg			glNormal3f(sinCache3a[i] * sintemp3,
904f220fa62Smrg				cosCache3a[i] * sintemp3,
905f220fa62Smrg				costemp3);
906f220fa62Smrg			break;
907f220fa62Smrg		      case GLU_NONE:
908f220fa62Smrg		      default:
909f220fa62Smrg			break;
910f220fa62Smrg		    }
911f220fa62Smrg		    glVertex3f(sintemp2 * sinCache1a[i],
912f220fa62Smrg			    sintemp2 * cosCache1a[i], zHigh);
913f220fa62Smrg		}
914f220fa62Smrg	    } else {
915f220fa62Smrg		for (i = slices; i >= 0; i--) {
916f220fa62Smrg		    switch(qobj->normals) {
917f220fa62Smrg		      case GLU_SMOOTH:
918f220fa62Smrg			glNormal3f(sinCache2a[i] * sintemp3,
919f220fa62Smrg				cosCache2a[i] * sintemp3,
920f220fa62Smrg				costemp3);
921f220fa62Smrg			break;
922f220fa62Smrg		      case GLU_FLAT:
923f220fa62Smrg			if (i != slices) {
924f220fa62Smrg			    glNormal3f(sinCache3a[i+1] * sintemp3,
925f220fa62Smrg				    cosCache3a[i+1] * sintemp3,
926f220fa62Smrg				    costemp3);
927f220fa62Smrg			}
928f220fa62Smrg			break;
929f220fa62Smrg		      case GLU_NONE:
930f220fa62Smrg		      default:
931f220fa62Smrg			break;
932f220fa62Smrg		    }
933f220fa62Smrg		    glVertex3f(sintemp2 * sinCache1a[i],
934f220fa62Smrg			    sintemp2 * cosCache1a[i], zHigh);
935f220fa62Smrg		}
936f220fa62Smrg	    }
937f220fa62Smrg	    glEnd();
938f220fa62Smrg	} else {
939f220fa62Smrg	    start = 0;
940f220fa62Smrg	    finish = stacks;
941f220fa62Smrg	}
942f220fa62Smrg	for (j = start; j < finish; j++) {
943f220fa62Smrg	    zLow = cosCache1b[j];
944f220fa62Smrg	    zHigh = cosCache1b[j+1];
945f220fa62Smrg	    sintemp1 = sinCache1b[j];
946f220fa62Smrg	    sintemp2 = sinCache1b[j+1];
947f220fa62Smrg	    switch(qobj->normals) {
948f220fa62Smrg	      case GLU_FLAT:
949f220fa62Smrg		sintemp4 = sinCache3b[j+1];
950f220fa62Smrg		costemp4 = cosCache3b[j+1];
951f220fa62Smrg		break;
952f220fa62Smrg	      case GLU_SMOOTH:
953f220fa62Smrg		if (qobj->orientation == GLU_OUTSIDE) {
954f220fa62Smrg		    sintemp3 = sinCache2b[j+1];
955f220fa62Smrg		    costemp3 = cosCache2b[j+1];
956f220fa62Smrg		    sintemp4 = sinCache2b[j];
957f220fa62Smrg		    costemp4 = cosCache2b[j];
958f220fa62Smrg		} else {
959f220fa62Smrg		    sintemp3 = sinCache2b[j];
960f220fa62Smrg		    costemp3 = cosCache2b[j];
961f220fa62Smrg		    sintemp4 = sinCache2b[j+1];
962f220fa62Smrg		    costemp4 = cosCache2b[j+1];
963f220fa62Smrg		}
964f220fa62Smrg		break;
965f220fa62Smrg	      default:
966f220fa62Smrg		break;
967f220fa62Smrg	    }
968f220fa62Smrg
969f220fa62Smrg	    glBegin(GL_QUAD_STRIP);
970f220fa62Smrg	    for (i = 0; i <= slices; i++) {
971f220fa62Smrg		switch(qobj->normals) {
972f220fa62Smrg		  case GLU_SMOOTH:
973f220fa62Smrg		    glNormal3f(sinCache2a[i] * sintemp3,
974f220fa62Smrg			    cosCache2a[i] * sintemp3,
975f220fa62Smrg			    costemp3);
976f220fa62Smrg		    break;
977f220fa62Smrg		  case GLU_FLAT:
978f220fa62Smrg		  case GLU_NONE:
979f220fa62Smrg		  default:
980f220fa62Smrg		    break;
981f220fa62Smrg		}
982f220fa62Smrg		if (qobj->orientation == GLU_OUTSIDE) {
983f220fa62Smrg		    if (qobj->textureCoords) {
984f220fa62Smrg			glTexCoord2f(1 - (float) i / slices,
985f220fa62Smrg				1 - (float) (j+1) / stacks);
986f220fa62Smrg		    }
987f220fa62Smrg		    glVertex3f(sintemp2 * sinCache1a[i],
988f220fa62Smrg			    sintemp2 * cosCache1a[i], zHigh);
989f220fa62Smrg		} else {
990f220fa62Smrg		    if (qobj->textureCoords) {
991f220fa62Smrg			glTexCoord2f(1 - (float) i / slices,
992f220fa62Smrg				1 - (float) j / stacks);
993f220fa62Smrg		    }
994f220fa62Smrg		    glVertex3f(sintemp1 * sinCache1a[i],
995f220fa62Smrg			    sintemp1 * cosCache1a[i], zLow);
996f220fa62Smrg		}
997f220fa62Smrg		switch(qobj->normals) {
998f220fa62Smrg		  case GLU_SMOOTH:
999f220fa62Smrg		    glNormal3f(sinCache2a[i] * sintemp4,
1000f220fa62Smrg			    cosCache2a[i] * sintemp4,
1001f220fa62Smrg			    costemp4);
1002f220fa62Smrg		    break;
1003f220fa62Smrg		  case GLU_FLAT:
1004f220fa62Smrg		    glNormal3f(sinCache3a[i] * sintemp4,
1005f220fa62Smrg			    cosCache3a[i] * sintemp4,
1006f220fa62Smrg			    costemp4);
1007f220fa62Smrg		    break;
1008f220fa62Smrg		  case GLU_NONE:
1009f220fa62Smrg		  default:
1010f220fa62Smrg		    break;
1011f220fa62Smrg		}
1012f220fa62Smrg		if (qobj->orientation == GLU_OUTSIDE) {
1013f220fa62Smrg		    if (qobj->textureCoords) {
1014f220fa62Smrg			glTexCoord2f(1 - (float) i / slices,
1015f220fa62Smrg				1 - (float) j / stacks);
1016f220fa62Smrg		    }
1017f220fa62Smrg		    glVertex3f(sintemp1 * sinCache1a[i],
1018f220fa62Smrg			    sintemp1 * cosCache1a[i], zLow);
1019f220fa62Smrg		} else {
1020f220fa62Smrg		    if (qobj->textureCoords) {
1021f220fa62Smrg			glTexCoord2f(1 - (float) i / slices,
1022f220fa62Smrg				1 - (float) (j+1) / stacks);
1023f220fa62Smrg		    }
1024f220fa62Smrg		    glVertex3f(sintemp2 * sinCache1a[i],
1025f220fa62Smrg			    sintemp2 * cosCache1a[i], zHigh);
1026f220fa62Smrg		}
1027f220fa62Smrg	    }
1028f220fa62Smrg	    glEnd();
1029f220fa62Smrg	}
1030f220fa62Smrg	break;
1031f220fa62Smrg      case GLU_POINT:
1032f220fa62Smrg	glBegin(GL_POINTS);
1033f220fa62Smrg	for (j = 0; j <= stacks; j++) {
1034f220fa62Smrg	    sintemp1 = sinCache1b[j];
1035f220fa62Smrg	    costemp1 = cosCache1b[j];
1036f220fa62Smrg	    switch(qobj->normals) {
1037f220fa62Smrg	      case GLU_FLAT:
1038f220fa62Smrg	      case GLU_SMOOTH:
1039f220fa62Smrg		sintemp2 = sinCache2b[j];
1040f220fa62Smrg		costemp2 = cosCache2b[j];
1041f220fa62Smrg		break;
1042f220fa62Smrg	      default:
1043f220fa62Smrg		break;
1044f220fa62Smrg	    }
1045f220fa62Smrg	    for (i = 0; i < slices; i++) {
1046f220fa62Smrg		switch(qobj->normals) {
1047f220fa62Smrg		  case GLU_FLAT:
1048f220fa62Smrg		  case GLU_SMOOTH:
1049f220fa62Smrg		    glNormal3f(sinCache2a[i] * sintemp2,
1050f220fa62Smrg			    cosCache2a[i] * sintemp2,
1051f220fa62Smrg			    costemp2);
1052f220fa62Smrg		    break;
1053f220fa62Smrg		  case GLU_NONE:
1054f220fa62Smrg		  default:
1055f220fa62Smrg		    break;
1056f220fa62Smrg		}
1057f220fa62Smrg
1058f220fa62Smrg		zLow = j * radius / stacks;
1059f220fa62Smrg
1060f220fa62Smrg		if (qobj->textureCoords) {
1061f220fa62Smrg		    glTexCoord2f(1 - (float) i / slices,
1062f220fa62Smrg			    1 - (float) j / stacks);
1063f220fa62Smrg		}
1064f220fa62Smrg		glVertex3f(sintemp1 * sinCache1a[i],
1065f220fa62Smrg			sintemp1 * cosCache1a[i], costemp1);
1066f220fa62Smrg	    }
1067f220fa62Smrg	}
1068f220fa62Smrg	glEnd();
1069f220fa62Smrg	break;
1070f220fa62Smrg      case GLU_LINE:
1071f220fa62Smrg      case GLU_SILHOUETTE:
1072f220fa62Smrg	for (j = 1; j < stacks; j++) {
1073f220fa62Smrg	    sintemp1 = sinCache1b[j];
1074f220fa62Smrg	    costemp1 = cosCache1b[j];
1075f220fa62Smrg	    switch(qobj->normals) {
1076f220fa62Smrg	      case GLU_FLAT:
1077f220fa62Smrg	      case GLU_SMOOTH:
1078f220fa62Smrg		sintemp2 = sinCache2b[j];
1079f220fa62Smrg		costemp2 = cosCache2b[j];
1080f220fa62Smrg		break;
1081f220fa62Smrg	      default:
1082f220fa62Smrg		break;
1083f220fa62Smrg	    }
1084f220fa62Smrg
1085f220fa62Smrg	    glBegin(GL_LINE_STRIP);
1086f220fa62Smrg	    for (i = 0; i <= slices; i++) {
1087f220fa62Smrg		switch(qobj->normals) {
1088f220fa62Smrg		  case GLU_FLAT:
1089f220fa62Smrg		    glNormal3f(sinCache3a[i] * sintemp2,
1090f220fa62Smrg			    cosCache3a[i] * sintemp2,
1091f220fa62Smrg			    costemp2);
1092f220fa62Smrg		    break;
1093f220fa62Smrg		  case GLU_SMOOTH:
1094f220fa62Smrg		    glNormal3f(sinCache2a[i] * sintemp2,
1095f220fa62Smrg			    cosCache2a[i] * sintemp2,
1096f220fa62Smrg			    costemp2);
1097f220fa62Smrg		    break;
1098f220fa62Smrg		  case GLU_NONE:
1099f220fa62Smrg		  default:
1100f220fa62Smrg		    break;
1101f220fa62Smrg		}
1102f220fa62Smrg		if (qobj->textureCoords) {
1103f220fa62Smrg		    glTexCoord2f(1 - (float) i / slices,
1104f220fa62Smrg			    1 - (float) j / stacks);
1105f220fa62Smrg		}
1106f220fa62Smrg		glVertex3f(sintemp1 * sinCache1a[i],
1107f220fa62Smrg			sintemp1 * cosCache1a[i], costemp1);
1108f220fa62Smrg	    }
1109f220fa62Smrg	    glEnd();
1110f220fa62Smrg	}
1111f220fa62Smrg	for (i = 0; i < slices; i++) {
1112f220fa62Smrg	    sintemp1 = sinCache1a[i];
1113f220fa62Smrg	    costemp1 = cosCache1a[i];
1114f220fa62Smrg	    switch(qobj->normals) {
1115f220fa62Smrg	      case GLU_FLAT:
1116f220fa62Smrg	      case GLU_SMOOTH:
1117f220fa62Smrg		sintemp2 = sinCache2a[i];
1118f220fa62Smrg		costemp2 = cosCache2a[i];
1119f220fa62Smrg		break;
1120f220fa62Smrg	      default:
1121f220fa62Smrg		break;
1122f220fa62Smrg	    }
1123f220fa62Smrg
1124f220fa62Smrg	    glBegin(GL_LINE_STRIP);
1125f220fa62Smrg	    for (j = 0; j <= stacks; j++) {
1126f220fa62Smrg		switch(qobj->normals) {
1127f220fa62Smrg		  case GLU_FLAT:
1128f220fa62Smrg		    glNormal3f(sintemp2 * sinCache3b[j],
1129f220fa62Smrg			    costemp2 * sinCache3b[j],
1130f220fa62Smrg			    cosCache3b[j]);
1131f220fa62Smrg		    break;
1132f220fa62Smrg		  case GLU_SMOOTH:
1133f220fa62Smrg		    glNormal3f(sintemp2 * sinCache2b[j],
1134f220fa62Smrg			    costemp2 * sinCache2b[j],
1135f220fa62Smrg			    cosCache2b[j]);
1136f220fa62Smrg		    break;
1137f220fa62Smrg		  case GLU_NONE:
1138f220fa62Smrg		  default:
1139f220fa62Smrg		    break;
1140f220fa62Smrg		}
1141f220fa62Smrg
1142f220fa62Smrg		if (qobj->textureCoords) {
1143f220fa62Smrg		    glTexCoord2f(1 - (float) i / slices,
1144f220fa62Smrg			    1 - (float) j / stacks);
1145f220fa62Smrg		}
1146f220fa62Smrg		glVertex3f(sintemp1 * sinCache1b[j],
1147f220fa62Smrg			costemp1 * sinCache1b[j], cosCache1b[j]);
1148f220fa62Smrg	    }
1149f220fa62Smrg	    glEnd();
1150f220fa62Smrg	}
1151f220fa62Smrg	break;
1152f220fa62Smrg      default:
1153f220fa62Smrg	break;
1154f220fa62Smrg    }
1155f220fa62Smrg}
1156