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