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