Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / glu / sgi / libutil / quad.c
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 }