Merge commit 'origin/gallium-0.1' into gallium-0.2
[mesa.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 }