Home | History | Annotate | Line # | Download | only in libutil
      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