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