Edit

IABSD.fr/xenocara/lib/libGLU/src/libutil/quad.c

Branch :

  • Show log

    Commit

  • Author : jsg
    Date : 2013-09-01 03:51:12
    Hash : 729f7da4
    Message : Update to GLU 9.0.0, GLU was previously part of Mesa but is now seperate. tested in a ports bulk build by landry@, ok matthieu@

  • lib/libGLU/src/libutil/quad.c
  • /*
     * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
     * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
     *
     * Permission is hereby granted, free of charge, to any person obtaining a
     * copy of this software and associated documentation files (the "Software"),
     * to deal in the Software without restriction, including without limitation
     * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     * and/or sell copies of the Software, and to permit persons to whom the
     * Software is furnished to do so, subject to the following conditions:
     *
     * The above copyright notice including the dates of first publication and
     * either this permission notice or a reference to
     * http://oss.sgi.com/projects/FreeB/
     * shall be included in all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     * SILICON GRAPHICS, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
     * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     * SOFTWARE.
     *
     * Except as contained in this notice, the name of Silicon Graphics, Inc.
     * shall not be used in advertising or otherwise to promote the sale, use or
     * other dealings in this Software without prior written authorization from
     * Silicon Graphics, Inc.
     */
    
    #include "gluos.h"
    #include "gluint.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include <GL/gl.h>
    #include <GL/glu.h>
    
    /* Make it not a power of two to avoid cache thrashing on the chip */
    #define CACHE_SIZE	240
    
    #undef	PI
    #define PI	      3.14159265358979323846
    
    struct GLUquadric {
        GLint	normals;
        GLboolean	textureCoords;
        GLint	orientation;
        GLint	drawStyle;
        void	(GLAPIENTRY *errorCallback)( GLint );
    };
    
    GLUquadric * GLAPIENTRY
    gluNewQuadric(void)
    {
        GLUquadric *newstate;
    
        newstate = (GLUquadric *) malloc(sizeof(GLUquadric));
        if (newstate == NULL) {
    	/* Can't report an error at this point... */
    	return NULL;
        }
        newstate->normals = GLU_SMOOTH;
        newstate->textureCoords = GL_FALSE;
        newstate->orientation = GLU_OUTSIDE;
        newstate->drawStyle = GLU_FILL;
        newstate->errorCallback = NULL;
        return newstate;
    }
    
    
    void GLAPIENTRY
    gluDeleteQuadric(GLUquadric *state)
    {
        free(state);
    }
    
    static void gluQuadricError(GLUquadric *qobj, GLenum which)
    {
        if (qobj->errorCallback) {
    	qobj->errorCallback(which);
        }
    }
    
    void GLAPIENTRY
    gluQuadricCallback(GLUquadric *qobj, GLenum which, _GLUfuncptr fn)
    {
        switch (which) {
          case GLU_ERROR:
    	qobj->errorCallback = (void (GLAPIENTRY *)(GLint)) fn;
    	break;
          default:
    	gluQuadricError(qobj, GLU_INVALID_ENUM);
    	return;
        }
    }
    
    void GLAPIENTRY
    gluQuadricNormals(GLUquadric *qobj, GLenum normals)
    {
        switch (normals) {
          case GLU_SMOOTH:
          case GLU_FLAT:
          case GLU_NONE:
    	break;
          default:
    	gluQuadricError(qobj, GLU_INVALID_ENUM);
    	return;
        }
        qobj->normals = normals;
    }
    
    void GLAPIENTRY
    gluQuadricTexture(GLUquadric *qobj, GLboolean textureCoords)
    {
        qobj->textureCoords = textureCoords;
    }
    
    void GLAPIENTRY
    gluQuadricOrientation(GLUquadric *qobj, GLenum orientation)
    {
        switch(orientation) {
          case GLU_OUTSIDE:
          case GLU_INSIDE:
    	break;
          default:
    	gluQuadricError(qobj, GLU_INVALID_ENUM);
    	return;
        }
        qobj->orientation = orientation;
    }
    
    void GLAPIENTRY
    gluQuadricDrawStyle(GLUquadric *qobj, GLenum drawStyle)
    {
        switch(drawStyle) {
          case GLU_POINT:
          case GLU_LINE:
          case GLU_FILL:
          case GLU_SILHOUETTE:
    	break;
          default:
    	gluQuadricError(qobj, GLU_INVALID_ENUM);
    	return;
        }
        qobj->drawStyle = drawStyle;
    }
    
    void GLAPIENTRY
    gluCylinder(GLUquadric *qobj, GLdouble baseRadius, GLdouble topRadius,
    		GLdouble height, GLint slices, GLint stacks)
    {
        GLint i,j;
        GLfloat sinCache[CACHE_SIZE];
        GLfloat cosCache[CACHE_SIZE];
        GLfloat sinCache2[CACHE_SIZE];
        GLfloat cosCache2[CACHE_SIZE];
        GLfloat sinCache3[CACHE_SIZE];
        GLfloat cosCache3[CACHE_SIZE];
        GLfloat angle;
        GLfloat zLow, zHigh;
        GLfloat sintemp, costemp;
        GLfloat length;
        GLfloat deltaRadius;
        GLfloat zNormal;
        GLfloat xyNormalRatio;
        GLfloat radiusLow, radiusHigh;
        int needCache2, needCache3;
    
        if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
    
        if (slices < 2 || stacks < 1 || baseRadius < 0.0 || topRadius < 0.0 ||
    	    height < 0.0) {
    	gluQuadricError(qobj, GLU_INVALID_VALUE);
    	return;
        }
    
        /* Compute length (needed for normal calculations) */
        deltaRadius = baseRadius - topRadius;
        length = SQRT(deltaRadius*deltaRadius + height*height);
        if (length == 0.0) {
    	gluQuadricError(qobj, GLU_INVALID_VALUE);
    	return;
        }
    
        /* Cache is the vertex locations cache */
        /* Cache2 is the various normals at the vertices themselves */
        /* Cache3 is the various normals for the faces */
        needCache2 = needCache3 = 0;
        if (qobj->normals == GLU_SMOOTH) {
    	needCache2 = 1;
        }
    
        if (qobj->normals == GLU_FLAT) {
    	if (qobj->drawStyle != GLU_POINT) {
    	    needCache3 = 1;
    	}
    	if (qobj->drawStyle == GLU_LINE) {
    	    needCache2 = 1;
    	}
        }
    
        zNormal = deltaRadius / length;
        xyNormalRatio = height / length;
    
        for (i = 0; i < slices; i++) {
    	angle = 2 * PI * i / slices;
    	if (needCache2) {
    	    if (qobj->orientation == GLU_OUTSIDE) {
    		sinCache2[i] = xyNormalRatio * SIN(angle);
    		cosCache2[i] = xyNormalRatio * COS(angle);
    	    } else {
    		sinCache2[i] = -xyNormalRatio * SIN(angle);
    		cosCache2[i] = -xyNormalRatio * COS(angle);
    	    }
    	}
    	sinCache[i] = SIN(angle);
    	cosCache[i] = COS(angle);
        }
    
        if (needCache3) {
    	for (i = 0; i < slices; i++) {
    	    angle = 2 * PI * (i-0.5) / slices;
    	    if (qobj->orientation == GLU_OUTSIDE) {
    		sinCache3[i] = xyNormalRatio * SIN(angle);
    		cosCache3[i] = xyNormalRatio * COS(angle);
    	    } else {
    		sinCache3[i] = -xyNormalRatio * SIN(angle);
    		cosCache3[i] = -xyNormalRatio * COS(angle);
    	    }
    	}
        }
    
        sinCache[slices] = sinCache[0];
        cosCache[slices] = cosCache[0];
        if (needCache2) {
    	sinCache2[slices] = sinCache2[0];
    	cosCache2[slices] = cosCache2[0];
        }
        if (needCache3) {
    	sinCache3[slices] = sinCache3[0];
    	cosCache3[slices] = cosCache3[0];
        }
    
        switch (qobj->drawStyle) {
          case GLU_FILL:
    	/* Note:
    	** An argument could be made for using a TRIANGLE_FAN for the end
    	** of the cylinder of either radii is 0.0 (a cone).  However, a
    	** TRIANGLE_FAN would not work in smooth shading mode (the common
    	** case) because the normal for the apex is different for every
    	** triangle (and TRIANGLE_FAN doesn't let me respecify that normal).
    	** Now, my choice is GL_TRIANGLES, or leave the GL_QUAD_STRIP and
    	** just let the GL trivially reject one of the two triangles of the
    	** QUAD.  GL_QUAD_STRIP is probably faster, so I will leave this code
    	** alone.
    	*/
    	for (j = 0; j < stacks; j++) {
    	    zLow = j * height / stacks;
    	    zHigh = (j + 1) * height / stacks;
    	    radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
    	    radiusHigh = baseRadius - deltaRadius * ((float) (j + 1) / stacks);
    
    	    glBegin(GL_QUAD_STRIP);
    	    for (i = 0; i <= slices; i++) {
    		switch(qobj->normals) {
    		  case GLU_FLAT:
    		    glNormal3f(sinCache3[i], cosCache3[i], zNormal);
    		    break;
    		  case GLU_SMOOTH:
    		    glNormal3f(sinCache2[i], cosCache2[i], zNormal);
    		    break;
    		  case GLU_NONE:
    		  default:
    		    break;
    		}
    		if (qobj->orientation == GLU_OUTSIDE) {
    		    if (qobj->textureCoords) {
    			glTexCoord2f(1 - (float) i / slices,
    				(float) j / stacks);
    		    }
    		    glVertex3f(radiusLow * sinCache[i],
    			    radiusLow * cosCache[i], zLow);
    		    if (qobj->textureCoords) {
    			glTexCoord2f(1 - (float) i / slices,
    				(float) (j+1) / stacks);
    		    }
    		    glVertex3f(radiusHigh * sinCache[i],
    			    radiusHigh * cosCache[i], zHigh);
    		} else {
    		    if (qobj->textureCoords) {
    			glTexCoord2f(1 - (float) i / slices,
    				(float) (j+1) / stacks);
    		    }
    		    glVertex3f(radiusHigh * sinCache[i],
    			    radiusHigh * cosCache[i], zHigh);
    		    if (qobj->textureCoords) {
    			glTexCoord2f(1 - (float) i / slices,
    				(float) j / stacks);
    		    }
    		    glVertex3f(radiusLow * sinCache[i],
    			    radiusLow * cosCache[i], zLow);
    		}
    	    }
    	    glEnd();
    	}
    	break;
          case GLU_POINT:
    	glBegin(GL_POINTS);
    	for (i = 0; i < slices; i++) {
    	    switch(qobj->normals) {
    	      case GLU_FLAT:
    	      case GLU_SMOOTH:
    		glNormal3f(sinCache2[i], cosCache2[i], zNormal);
    		break;
    	      case GLU_NONE:
    	      default:
    		break;
    	    }
    	    sintemp = sinCache[i];
    	    costemp = cosCache[i];
    	    for (j = 0; j <= stacks; j++) {
    		zLow = j * height / stacks;
    		radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
    
    		if (qobj->textureCoords) {
    		    glTexCoord2f(1 - (float) i / slices,
    			    (float) j / stacks);
    		}
    		glVertex3f(radiusLow * sintemp,
    			radiusLow * costemp, zLow);
    	    }
    	}
    	glEnd();
    	break;
          case GLU_LINE:
    	for (j = 1; j < stacks; j++) {
    	    zLow = j * height / stacks;
    	    radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
    
    	    glBegin(GL_LINE_STRIP);
    	    for (i = 0; i <= slices; i++) {
    		switch(qobj->normals) {
    		  case GLU_FLAT:
    		    glNormal3f(sinCache3[i], cosCache3[i], zNormal);
    		    break;
    		  case GLU_SMOOTH:
    		    glNormal3f(sinCache2[i], cosCache2[i], zNormal);
    		    break;
    		  case GLU_NONE:
    		  default:
    		    break;
    		}
    		if (qobj->textureCoords) {
    		    glTexCoord2f(1 - (float) i / slices,
    			    (float) j / stacks);
    		}
    		glVertex3f(radiusLow * sinCache[i],
    			radiusLow * cosCache[i], zLow);
    	    }
    	    glEnd();
    	}
    	/* Intentionally fall through here... */
          case GLU_SILHOUETTE:
    	for (j = 0; j <= stacks; j += stacks) {
    	    zLow = j * height / stacks;
    	    radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
    
    	    glBegin(GL_LINE_STRIP);
    	    for (i = 0; i <= slices; i++) {
    		switch(qobj->normals) {
    		  case GLU_FLAT:
    		    glNormal3f(sinCache3[i], cosCache3[i], zNormal);
    		    break;
    		  case GLU_SMOOTH:
    		    glNormal3f(sinCache2[i], cosCache2[i], zNormal);
    		    break;
    		  case GLU_NONE:
    		  default:
    		    break;
    		}
    		if (qobj->textureCoords) {
    		    glTexCoord2f(1 - (float) i / slices,
    			    (float) j / stacks);
    		}
    		glVertex3f(radiusLow * sinCache[i], radiusLow * cosCache[i],
    			zLow);
    	    }
    	    glEnd();
    	}
    	for (i = 0; i < slices; i++) {
    	    switch(qobj->normals) {
    	      case GLU_FLAT:
    	      case GLU_SMOOTH:
    		glNormal3f(sinCache2[i], cosCache2[i], 0.0);
    		break;
    	      case GLU_NONE:
    	      default:
    		break;
    	    }
    	    sintemp = sinCache[i];
    	    costemp = cosCache[i];
    	    glBegin(GL_LINE_STRIP);
    	    for (j = 0; j <= stacks; j++) {
    		zLow = j * height / stacks;
    		radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
    
    		if (qobj->textureCoords) {
    		    glTexCoord2f(1 - (float) i / slices,
    			    (float) j / stacks);
    		}
    		glVertex3f(radiusLow * sintemp,
    			radiusLow * costemp, zLow);
    	    }
    	    glEnd();
    	}
    	break;
          default:
    	break;
        }
    }
    
    void GLAPIENTRY
    gluDisk(GLUquadric *qobj, GLdouble innerRadius, GLdouble outerRadius,
    	    GLint slices, GLint loops)
    {
        gluPartialDisk(qobj, innerRadius, outerRadius, slices, loops, 0.0, 360.0);
    }
    
    void GLAPIENTRY
    gluPartialDisk(GLUquadric *qobj, GLdouble innerRadius,
    		   GLdouble outerRadius, GLint slices, GLint loops,
    		   GLdouble startAngle, GLdouble sweepAngle)
    {
        GLint i,j;
        GLfloat sinCache[CACHE_SIZE];
        GLfloat cosCache[CACHE_SIZE];
        GLfloat angle;
        GLfloat sintemp, costemp;
        GLfloat deltaRadius;
        GLfloat radiusLow, radiusHigh;
        GLfloat texLow = 0.0, texHigh = 0.0;
        GLfloat angleOffset;
        GLint slices2;
        GLint finish;
    
        if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
        if (slices < 2 || loops < 1 || outerRadius <= 0.0 || innerRadius < 0.0 ||
    	    innerRadius > outerRadius) {
    	gluQuadricError(qobj, GLU_INVALID_VALUE);
    	return;
        }
    
        if (sweepAngle < -360.0) sweepAngle = 360.0;
        if (sweepAngle > 360.0) sweepAngle = 360.0;
        if (sweepAngle < 0) {
    	startAngle += sweepAngle;
    	sweepAngle = -sweepAngle;
        }
    
        if (sweepAngle == 360.0) {
    	slices2 = slices;
        } else {
    	slices2 = slices + 1;
        }
    
        /* Compute length (needed for normal calculations) */
        deltaRadius = outerRadius - innerRadius;
    
        /* Cache is the vertex locations cache */
    
        angleOffset = startAngle / 180.0 * PI;
        for (i = 0; i <= slices; i++) {
    	angle = angleOffset + ((PI * sweepAngle) / 180.0) * i / slices;
    	sinCache[i] = SIN(angle);
    	cosCache[i] = COS(angle);
        }
    
        if (sweepAngle == 360.0) {
    	sinCache[slices] = sinCache[0];
    	cosCache[slices] = cosCache[0];
        }
    
        switch(qobj->normals) {
          case GLU_FLAT:
          case GLU_SMOOTH:
    	if (qobj->orientation == GLU_OUTSIDE) {
    	    glNormal3f(0.0, 0.0, 1.0);
    	} else {
    	    glNormal3f(0.0, 0.0, -1.0);
    	}
    	break;
          default:
          case GLU_NONE:
    	break;
        }
    
        switch (qobj->drawStyle) {
          case GLU_FILL:
    	if (innerRadius == 0.0) {
    	    finish = loops - 1;
    	    /* Triangle strip for inner polygons */
    	    glBegin(GL_TRIANGLE_FAN);
    	    if (qobj->textureCoords) {
    		glTexCoord2f(0.5, 0.5);
    	    }
    	    glVertex3f(0.0, 0.0, 0.0);
    	    radiusLow = outerRadius -
    		    deltaRadius * ((float) (loops-1) / loops);
    	    if (qobj->textureCoords) {
    		texLow = radiusLow / outerRadius / 2;
    	    }
    
    	    if (qobj->orientation == GLU_OUTSIDE) {
    		for (i = slices; i >= 0; i--) {
    		    if (qobj->textureCoords) {
    			glTexCoord2f(texLow * sinCache[i] + 0.5,
    				texLow * cosCache[i] + 0.5);
    		    }
    		    glVertex3f(radiusLow * sinCache[i],
    			    radiusLow * cosCache[i], 0.0);
    		}
    	    } else {
    		for (i = 0; i <= slices; i++) {
    		    if (qobj->textureCoords) {
    			glTexCoord2f(texLow * sinCache[i] + 0.5,
    				texLow * cosCache[i] + 0.5);
    		    }
    		    glVertex3f(radiusLow * sinCache[i],
    			    radiusLow * cosCache[i], 0.0);
    		}
    	    }
    	    glEnd();
    	} else {
    	    finish = loops;
    	}
    	for (j = 0; j < finish; j++) {
    	    radiusLow = outerRadius - deltaRadius * ((float) j / loops);
    	    radiusHigh = outerRadius - deltaRadius * ((float) (j + 1) / loops);
    	    if (qobj->textureCoords) {
    		texLow = radiusLow / outerRadius / 2;
    		texHigh = radiusHigh / outerRadius / 2;
    	    }
    
    	    glBegin(GL_QUAD_STRIP);
    	    for (i = 0; i <= slices; i++) {
    		if (qobj->orientation == GLU_OUTSIDE) {
    		    if (qobj->textureCoords) {
    			glTexCoord2f(texLow * sinCache[i] + 0.5,
    				texLow * cosCache[i] + 0.5);
    		    }
    		    glVertex3f(radiusLow * sinCache[i],
    			    radiusLow * cosCache[i], 0.0);
    
    		    if (qobj->textureCoords) {
    			glTexCoord2f(texHigh * sinCache[i] + 0.5,
    				texHigh * cosCache[i] + 0.5);
    		    }
    		    glVertex3f(radiusHigh * sinCache[i],
    			    radiusHigh * cosCache[i], 0.0);
    		} else {
    		    if (qobj->textureCoords) {
    			glTexCoord2f(texHigh * sinCache[i] + 0.5,
    				texHigh * cosCache[i] + 0.5);
    		    }
    		    glVertex3f(radiusHigh * sinCache[i],
    			    radiusHigh * cosCache[i], 0.0);
    
    		    if (qobj->textureCoords) {
    			glTexCoord2f(texLow * sinCache[i] + 0.5,
    				texLow * cosCache[i] + 0.5);
    		    }
    		    glVertex3f(radiusLow * sinCache[i],
    			    radiusLow * cosCache[i], 0.0);
    		}
    	    }
    	    glEnd();
    	}
    	break;
          case GLU_POINT:
    	glBegin(GL_POINTS);
    	for (i = 0; i < slices2; i++) {
    	    sintemp = sinCache[i];
    	    costemp = cosCache[i];
    	    for (j = 0; j <= loops; j++) {
    		radiusLow = outerRadius - deltaRadius * ((float) j / loops);
    
    		if (qobj->textureCoords) {
    		    texLow = radiusLow / outerRadius / 2;
    
    		    glTexCoord2f(texLow * sinCache[i] + 0.5,
    			    texLow * cosCache[i] + 0.5);
    		}
    		glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
    	    }
    	}
    	glEnd();
    	break;
          case GLU_LINE:
    	if (innerRadius == outerRadius) {
    	    glBegin(GL_LINE_STRIP);
    
    	    for (i = 0; i <= slices; i++) {
    		if (qobj->textureCoords) {
    		    glTexCoord2f(sinCache[i] / 2 + 0.5,
    			    cosCache[i] / 2 + 0.5);
    		}
    		glVertex3f(innerRadius * sinCache[i],
    			innerRadius * cosCache[i], 0.0);
    	    }
    	    glEnd();
    	    break;
    	}
    	for (j = 0; j <= loops; j++) {
    	    radiusLow = outerRadius - deltaRadius * ((float) j / loops);
    	    if (qobj->textureCoords) {
    		texLow = radiusLow / outerRadius / 2;
    	    }
    
    	    glBegin(GL_LINE_STRIP);
    	    for (i = 0; i <= slices; i++) {
    		if (qobj->textureCoords) {
    		    glTexCoord2f(texLow * sinCache[i] + 0.5,
    			    texLow * cosCache[i] + 0.5);
    		}
    		glVertex3f(radiusLow * sinCache[i],
    			radiusLow * cosCache[i], 0.0);
    	    }
    	    glEnd();
    	}
    	for (i=0; i < slices2; i++) {
    	    sintemp = sinCache[i];
    	    costemp = cosCache[i];
    	    glBegin(GL_LINE_STRIP);
    	    for (j = 0; j <= loops; j++) {
    		radiusLow = outerRadius - deltaRadius * ((float) j / loops);
    		if (qobj->textureCoords) {
    		    texLow = radiusLow / outerRadius / 2;
    		}
    
    		if (qobj->textureCoords) {
    		    glTexCoord2f(texLow * sinCache[i] + 0.5,
    			    texLow * cosCache[i] + 0.5);
    		}
    		glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
    	    }
    	    glEnd();
    	}
    	break;
          case GLU_SILHOUETTE:
    	if (sweepAngle < 360.0) {
    	    for (i = 0; i <= slices; i+= slices) {
    		sintemp = sinCache[i];
    		costemp = cosCache[i];
    		glBegin(GL_LINE_STRIP);
    		for (j = 0; j <= loops; j++) {
    		    radiusLow = outerRadius - deltaRadius * ((float) j / loops);
    
    		    if (qobj->textureCoords) {
    			texLow = radiusLow / outerRadius / 2;
    			glTexCoord2f(texLow * sinCache[i] + 0.5,
    				texLow * cosCache[i] + 0.5);
    		    }
    		    glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
    		}
    		glEnd();
    	    }
    	}
    	for (j = 0; j <= loops; j += loops) {
    	    radiusLow = outerRadius - deltaRadius * ((float) j / loops);
    	    if (qobj->textureCoords) {
    		texLow = radiusLow / outerRadius / 2;
    	    }
    
    	    glBegin(GL_LINE_STRIP);
    	    for (i = 0; i <= slices; i++) {
    		if (qobj->textureCoords) {
    		    glTexCoord2f(texLow * sinCache[i] + 0.5,
    			    texLow * cosCache[i] + 0.5);
    		}
    		glVertex3f(radiusLow * sinCache[i],
    			radiusLow * cosCache[i], 0.0);
    	    }
    	    glEnd();
    	    if (innerRadius == outerRadius) break;
    	}
    	break;
          default:
    	break;
        }
    }
    
    void GLAPIENTRY
    gluSphere(GLUquadric *qobj, GLdouble radius, GLint slices, GLint stacks)
    {
        GLint i,j;
        GLfloat sinCache1a[CACHE_SIZE];
        GLfloat cosCache1a[CACHE_SIZE];
        GLfloat sinCache2a[CACHE_SIZE];
        GLfloat cosCache2a[CACHE_SIZE];
        GLfloat sinCache3a[CACHE_SIZE];
        GLfloat cosCache3a[CACHE_SIZE];
        GLfloat sinCache1b[CACHE_SIZE];
        GLfloat cosCache1b[CACHE_SIZE];
        GLfloat sinCache2b[CACHE_SIZE];
        GLfloat cosCache2b[CACHE_SIZE];
        GLfloat sinCache3b[CACHE_SIZE];
        GLfloat cosCache3b[CACHE_SIZE];
        GLfloat angle;
        GLfloat zLow, zHigh;
        GLfloat sintemp1 = 0.0, sintemp2 = 0.0, sintemp3 = 0.0, sintemp4 = 0.0;
        GLfloat costemp1 = 0.0, costemp2 = 0.0, costemp3 = 0.0, costemp4 = 0.0;
        GLboolean needCache2, needCache3;
        GLint start, finish;
    
        if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
        if (stacks >= CACHE_SIZE) stacks = CACHE_SIZE-1;
        if (slices < 2 || stacks < 1 || radius < 0.0) {
    	gluQuadricError(qobj, GLU_INVALID_VALUE);
    	return;
        }
    
        /* Cache is the vertex locations cache */
        /* Cache2 is the various normals at the vertices themselves */
        /* Cache3 is the various normals for the faces */
        needCache2 = needCache3 = GL_FALSE;
    
        if (qobj->normals == GLU_SMOOTH) {
    	needCache2 = GL_TRUE;
        }
    
        if (qobj->normals == GLU_FLAT) {
    	if (qobj->drawStyle != GLU_POINT) {
    	    needCache3 = GL_TRUE;
    	}
    	if (qobj->drawStyle == GLU_LINE) {
    	    needCache2 = GL_TRUE;
    	}
        }
    
        for (i = 0; i < slices; i++) {
    	angle = 2 * PI * i / slices;
    	sinCache1a[i] = SIN(angle);
    	cosCache1a[i] = COS(angle);
    	if (needCache2) {
    	    sinCache2a[i] = sinCache1a[i];
    	    cosCache2a[i] = cosCache1a[i];
    	}
        }
    
        for (j = 0; j <= stacks; j++) {
    	angle = PI * j / stacks;
    	if (needCache2) {
    	    if (qobj->orientation == GLU_OUTSIDE) {
    		sinCache2b[j] = SIN(angle);
    		cosCache2b[j] = COS(angle);
    	    } else {
    		sinCache2b[j] = -SIN(angle);
    		cosCache2b[j] = -COS(angle);
    	    }
    	}
    	sinCache1b[j] = radius * SIN(angle);
    	cosCache1b[j] = radius * COS(angle);
        }
        /* Make sure it comes to a point */
        sinCache1b[0] = 0;
        sinCache1b[stacks] = 0;
    
        if (needCache3) {
    	for (i = 0; i < slices; i++) {
    	    angle = 2 * PI * (i-0.5) / slices;
    	    sinCache3a[i] = SIN(angle);
    	    cosCache3a[i] = COS(angle);
    	}
    	for (j = 0; j <= stacks; j++) {
    	    angle = PI * (j - 0.5) / stacks;
    	    if (qobj->orientation == GLU_OUTSIDE) {
    		sinCache3b[j] = SIN(angle);
    		cosCache3b[j] = COS(angle);
    	    } else {
    		sinCache3b[j] = -SIN(angle);
    		cosCache3b[j] = -COS(angle);
    	    }
    	}
        }
    
        sinCache1a[slices] = sinCache1a[0];
        cosCache1a[slices] = cosCache1a[0];
        if (needCache2) {
    	sinCache2a[slices] = sinCache2a[0];
    	cosCache2a[slices] = cosCache2a[0];
        }
        if (needCache3) {
    	sinCache3a[slices] = sinCache3a[0];
    	cosCache3a[slices] = cosCache3a[0];
        }
    
        switch (qobj->drawStyle) {
          case GLU_FILL:
    	/* Do ends of sphere as TRIANGLE_FAN's (if not texturing)
    	** We don't do it when texturing because we need to respecify the
    	** texture coordinates of the apex for every adjacent vertex (because
    	** it isn't a constant for that point)
    	*/
    	if (!(qobj->textureCoords)) {
    	    start = 1;
    	    finish = stacks - 1;
    
    	    /* Low end first (j == 0 iteration) */
    	    sintemp2 = sinCache1b[1];
    	    zHigh = cosCache1b[1];
    	    switch(qobj->normals) {
    	      case GLU_FLAT:
    		sintemp3 = sinCache3b[1];
    		costemp3 = cosCache3b[1];
    		break;
    	      case GLU_SMOOTH:
    		sintemp3 = sinCache2b[1];
    		costemp3 = cosCache2b[1];
    		glNormal3f(sinCache2a[0] * sinCache2b[0],
    			cosCache2a[0] * sinCache2b[0],
    			cosCache2b[0]);
    		break;
    	      default:
    		break;
    	    }
    	    glBegin(GL_TRIANGLE_FAN);
    	    glVertex3f(0.0, 0.0, radius);
    	    if (qobj->orientation == GLU_OUTSIDE) {
    		for (i = slices; i >= 0; i--) {
    		    switch(qobj->normals) {
    		      case GLU_SMOOTH:
    			glNormal3f(sinCache2a[i] * sintemp3,
    				cosCache2a[i] * sintemp3,
    				costemp3);
    			break;
    		      case GLU_FLAT:
    			if (i != slices) {
    			    glNormal3f(sinCache3a[i+1] * sintemp3,
    				    cosCache3a[i+1] * sintemp3,
    				    costemp3);
    			}
    			break;
    		      case GLU_NONE:
    		      default:
    			break;
    		    }
    		    glVertex3f(sintemp2 * sinCache1a[i],
    			    sintemp2 * cosCache1a[i], zHigh);
    		}
    	    } else {
    		for (i = 0; i <= slices; i++) {
    		    switch(qobj->normals) {
    		      case GLU_SMOOTH:
    			glNormal3f(sinCache2a[i] * sintemp3,
    				cosCache2a[i] * sintemp3,
    				costemp3);
    			break;
    		      case GLU_FLAT:
    			glNormal3f(sinCache3a[i] * sintemp3,
    				cosCache3a[i] * sintemp3,
    				costemp3);
    			break;
    		      case GLU_NONE:
    		      default:
    			break;
    		    }
    		    glVertex3f(sintemp2 * sinCache1a[i],
    			    sintemp2 * cosCache1a[i], zHigh);
    		}
    	    }
    	    glEnd();
    
    	    /* High end next (j == stacks-1 iteration) */
    	    sintemp2 = sinCache1b[stacks-1];
    	    zHigh = cosCache1b[stacks-1];
    	    switch(qobj->normals) {
    	      case GLU_FLAT:
    		sintemp3 = sinCache3b[stacks];
    		costemp3 = cosCache3b[stacks];
    		break;
    	      case GLU_SMOOTH:
    		sintemp3 = sinCache2b[stacks-1];
    		costemp3 = cosCache2b[stacks-1];
    		glNormal3f(sinCache2a[stacks] * sinCache2b[stacks],
    			cosCache2a[stacks] * sinCache2b[stacks],
    			cosCache2b[stacks]);
    		break;
    	      default:
    		break;
    	    }
    	    glBegin(GL_TRIANGLE_FAN);
    	    glVertex3f(0.0, 0.0, -radius);
    	    if (qobj->orientation == GLU_OUTSIDE) {
    		for (i = 0; i <= slices; i++) {
    		    switch(qobj->normals) {
    		      case GLU_SMOOTH:
    			glNormal3f(sinCache2a[i] * sintemp3,
    				cosCache2a[i] * sintemp3,
    				costemp3);
    			break;
    		      case GLU_FLAT:
    			glNormal3f(sinCache3a[i] * sintemp3,
    				cosCache3a[i] * sintemp3,
    				costemp3);
    			break;
    		      case GLU_NONE:
    		      default:
    			break;
    		    }
    		    glVertex3f(sintemp2 * sinCache1a[i],
    			    sintemp2 * cosCache1a[i], zHigh);
    		}
    	    } else {
    		for (i = slices; i >= 0; i--) {
    		    switch(qobj->normals) {
    		      case GLU_SMOOTH:
    			glNormal3f(sinCache2a[i] * sintemp3,
    				cosCache2a[i] * sintemp3,
    				costemp3);
    			break;
    		      case GLU_FLAT:
    			if (i != slices) {
    			    glNormal3f(sinCache3a[i+1] * sintemp3,
    				    cosCache3a[i+1] * sintemp3,
    				    costemp3);
    			}
    			break;
    		      case GLU_NONE:
    		      default:
    			break;
    		    }
    		    glVertex3f(sintemp2 * sinCache1a[i],
    			    sintemp2 * cosCache1a[i], zHigh);
    		}
    	    }
    	    glEnd();
    	} else {
    	    start = 0;
    	    finish = stacks;
    	}
    	for (j = start; j < finish; j++) {
    	    zLow = cosCache1b[j];
    	    zHigh = cosCache1b[j+1];
    	    sintemp1 = sinCache1b[j];
    	    sintemp2 = sinCache1b[j+1];
    	    switch(qobj->normals) {
    	      case GLU_FLAT:
    		sintemp4 = sinCache3b[j+1];
    		costemp4 = cosCache3b[j+1];
    		break;
    	      case GLU_SMOOTH:
    		if (qobj->orientation == GLU_OUTSIDE) {
    		    sintemp3 = sinCache2b[j+1];
    		    costemp3 = cosCache2b[j+1];
    		    sintemp4 = sinCache2b[j];
    		    costemp4 = cosCache2b[j];
    		} else {
    		    sintemp3 = sinCache2b[j];
    		    costemp3 = cosCache2b[j];
    		    sintemp4 = sinCache2b[j+1];
    		    costemp4 = cosCache2b[j+1];
    		}
    		break;
    	      default:
    		break;
    	    }
    
    	    glBegin(GL_QUAD_STRIP);
    	    for (i = 0; i <= slices; i++) {
    		switch(qobj->normals) {
    		  case GLU_SMOOTH:
    		    glNormal3f(sinCache2a[i] * sintemp3,
    			    cosCache2a[i] * sintemp3,
    			    costemp3);
    		    break;
    		  case GLU_FLAT:
    		  case GLU_NONE:
    		  default:
    		    break;
    		}
    		if (qobj->orientation == GLU_OUTSIDE) {
    		    if (qobj->textureCoords) {
    			glTexCoord2f(1 - (float) i / slices,
    				1 - (float) (j+1) / stacks);
    		    }
    		    glVertex3f(sintemp2 * sinCache1a[i],
    			    sintemp2 * cosCache1a[i], zHigh);
    		} else {
    		    if (qobj->textureCoords) {
    			glTexCoord2f(1 - (float) i / slices,
    				1 - (float) j / stacks);
    		    }
    		    glVertex3f(sintemp1 * sinCache1a[i],
    			    sintemp1 * cosCache1a[i], zLow);
    		}
    		switch(qobj->normals) {
    		  case GLU_SMOOTH:
    		    glNormal3f(sinCache2a[i] * sintemp4,
    			    cosCache2a[i] * sintemp4,
    			    costemp4);
    		    break;
    		  case GLU_FLAT:
    		    glNormal3f(sinCache3a[i] * sintemp4,
    			    cosCache3a[i] * sintemp4,
    			    costemp4);
    		    break;
    		  case GLU_NONE:
    		  default:
    		    break;
    		}
    		if (qobj->orientation == GLU_OUTSIDE) {
    		    if (qobj->textureCoords) {
    			glTexCoord2f(1 - (float) i / slices,
    				1 - (float) j / stacks);
    		    }
    		    glVertex3f(sintemp1 * sinCache1a[i],
    			    sintemp1 * cosCache1a[i], zLow);
    		} else {
    		    if (qobj->textureCoords) {
    			glTexCoord2f(1 - (float) i / slices,
    				1 - (float) (j+1) / stacks);
    		    }
    		    glVertex3f(sintemp2 * sinCache1a[i],
    			    sintemp2 * cosCache1a[i], zHigh);
    		}
    	    }
    	    glEnd();
    	}
    	break;
          case GLU_POINT:
    	glBegin(GL_POINTS);
    	for (j = 0; j <= stacks; j++) {
    	    sintemp1 = sinCache1b[j];
    	    costemp1 = cosCache1b[j];
    	    switch(qobj->normals) {
    	      case GLU_FLAT:
    	      case GLU_SMOOTH:
    		sintemp2 = sinCache2b[j];
    		costemp2 = cosCache2b[j];
    		break;
    	      default:
    		break;
    	    }
    	    for (i = 0; i < slices; i++) {
    		switch(qobj->normals) {
    		  case GLU_FLAT:
    		  case GLU_SMOOTH:
    		    glNormal3f(sinCache2a[i] * sintemp2,
    			    cosCache2a[i] * sintemp2,
    			    costemp2);
    		    break;
    		  case GLU_NONE:
    		  default:
    		    break;
    		}
    
    		zLow = j * radius / stacks;
    
    		if (qobj->textureCoords) {
    		    glTexCoord2f(1 - (float) i / slices,
    			    1 - (float) j / stacks);
    		}
    		glVertex3f(sintemp1 * sinCache1a[i],
    			sintemp1 * cosCache1a[i], costemp1);
    	    }
    	}
    	glEnd();
    	break;
          case GLU_LINE:
          case GLU_SILHOUETTE:
    	for (j = 1; j < stacks; j++) {
    	    sintemp1 = sinCache1b[j];
    	    costemp1 = cosCache1b[j];
    	    switch(qobj->normals) {
    	      case GLU_FLAT:
    	      case GLU_SMOOTH:
    		sintemp2 = sinCache2b[j];
    		costemp2 = cosCache2b[j];
    		break;
    	      default:
    		break;
    	    }
    
    	    glBegin(GL_LINE_STRIP);
    	    for (i = 0; i <= slices; i++) {
    		switch(qobj->normals) {
    		  case GLU_FLAT:
    		    glNormal3f(sinCache3a[i] * sintemp2,
    			    cosCache3a[i] * sintemp2,
    			    costemp2);
    		    break;
    		  case GLU_SMOOTH:
    		    glNormal3f(sinCache2a[i] * sintemp2,
    			    cosCache2a[i] * sintemp2,
    			    costemp2);
    		    break;
    		  case GLU_NONE:
    		  default:
    		    break;
    		}
    		if (qobj->textureCoords) {
    		    glTexCoord2f(1 - (float) i / slices,
    			    1 - (float) j / stacks);
    		}
    		glVertex3f(sintemp1 * sinCache1a[i],
    			sintemp1 * cosCache1a[i], costemp1);
    	    }
    	    glEnd();
    	}
    	for (i = 0; i < slices; i++) {
    	    sintemp1 = sinCache1a[i];
    	    costemp1 = cosCache1a[i];
    	    switch(qobj->normals) {
    	      case GLU_FLAT:
    	      case GLU_SMOOTH:
    		sintemp2 = sinCache2a[i];
    		costemp2 = cosCache2a[i];
    		break;
    	      default:
    		break;
    	    }
    
    	    glBegin(GL_LINE_STRIP);
    	    for (j = 0; j <= stacks; j++) {
    		switch(qobj->normals) {
    		  case GLU_FLAT:
    		    glNormal3f(sintemp2 * sinCache3b[j],
    			    costemp2 * sinCache3b[j],
    			    cosCache3b[j]);
    		    break;
    		  case GLU_SMOOTH:
    		    glNormal3f(sintemp2 * sinCache2b[j],
    			    costemp2 * sinCache2b[j],
    			    cosCache2b[j]);
    		    break;
    		  case GLU_NONE:
    		  default:
    		    break;
    		}
    
    		if (qobj->textureCoords) {
    		    glTexCoord2f(1 - (float) i / slices,
    			    1 - (float) j / stacks);
    		}
    		glVertex3f(sintemp1 * sinCache1b[j],
    			costemp1 * sinCache1b[j], cosCache1b[j]);
    	    }
    	    glEnd();
    	}
    	break;
          default:
    	break;
        }
    }