SGI SI GLU library
[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: 2001/03/17 00:25:41 $ $Revision: 1.1 $
35 ** $Header: /home/krh/git/sync/mesa-cvs-repo/Mesa/src/glu/sgi/libutil/quad.c,v 1.1 2001/03/17 00:25:41 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, void (GLAPIENTRY *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,max;
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 x, y, 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,max;
442 GLfloat sinCache[CACHE_SIZE];
443 GLfloat cosCache[CACHE_SIZE];
444 GLfloat angle;
445 GLfloat x, y;
446 GLfloat sintemp, costemp;
447 GLfloat deltaRadius;
448 GLfloat radiusLow, radiusHigh;
449 GLfloat texLow, texHigh;
450 GLfloat angleOffset;
451 GLint slices2;
452 GLint finish;
453
454 if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
455 if (slices < 2 || loops < 1 || outerRadius <= 0.0 || innerRadius < 0.0 ||
456 innerRadius > outerRadius) {
457 gluQuadricError(qobj, GLU_INVALID_VALUE);
458 return;
459 }
460
461 if (sweepAngle < -360.0) sweepAngle = 360.0;
462 if (sweepAngle > 360.0) sweepAngle = 360.0;
463 if (sweepAngle < 0) {
464 startAngle += sweepAngle;
465 sweepAngle = -sweepAngle;
466 }
467
468 if (sweepAngle == 360.0) {
469 slices2 = slices;
470 } else {
471 slices2 = slices + 1;
472 }
473
474 /* Compute length (needed for normal calculations) */
475 deltaRadius = outerRadius - innerRadius;
476
477 /* Cache is the vertex locations cache */
478
479 angleOffset = startAngle / 180.0 * PI;
480 for (i = 0; i <= slices; i++) {
481 angle = angleOffset + ((PI * sweepAngle) / 180.0) * i / slices;
482 sinCache[i] = SIN(angle);
483 cosCache[i] = COS(angle);
484 }
485
486 if (sweepAngle == 360.0) {
487 sinCache[slices] = sinCache[0];
488 cosCache[slices] = cosCache[0];
489 }
490
491 switch(qobj->normals) {
492 case GLU_FLAT:
493 case GLU_SMOOTH:
494 if (qobj->orientation == GLU_OUTSIDE) {
495 glNormal3f(0.0, 0.0, 1.0);
496 } else {
497 glNormal3f(0.0, 0.0, -1.0);
498 }
499 break;
500 default:
501 case GLU_NONE:
502 break;
503 }
504
505 switch (qobj->drawStyle) {
506 case GLU_FILL:
507 if (innerRadius == 0.0) {
508 finish = loops - 1;
509 /* Triangle strip for inner polygons */
510 glBegin(GL_TRIANGLE_FAN);
511 if (qobj->textureCoords) {
512 glTexCoord2f(0.5, 0.5);
513 }
514 glVertex3f(0.0, 0.0, 0.0);
515 radiusLow = outerRadius -
516 deltaRadius * ((float) (loops-1) / loops);
517 if (qobj->textureCoords) {
518 texLow = radiusLow / outerRadius / 2;
519 }
520
521 if (qobj->orientation == GLU_OUTSIDE) {
522 for (i = slices; i >= 0; i--) {
523 if (qobj->textureCoords) {
524 glTexCoord2f(texLow * sinCache[i] + 0.5,
525 texLow * cosCache[i] + 0.5);
526 }
527 glVertex3f(radiusLow * sinCache[i],
528 radiusLow * cosCache[i], 0.0);
529 }
530 } else {
531 for (i = 0; i <= slices; i++) {
532 if (qobj->textureCoords) {
533 glTexCoord2f(texLow * sinCache[i] + 0.5,
534 texLow * cosCache[i] + 0.5);
535 }
536 glVertex3f(radiusLow * sinCache[i],
537 radiusLow * cosCache[i], 0.0);
538 }
539 }
540 glEnd();
541 } else {
542 finish = loops;
543 }
544 for (j = 0; j < finish; j++) {
545 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
546 radiusHigh = outerRadius - deltaRadius * ((float) (j + 1) / loops);
547 if (qobj->textureCoords) {
548 texLow = radiusLow / outerRadius / 2;
549 texHigh = radiusHigh / outerRadius / 2;
550 }
551
552 glBegin(GL_QUAD_STRIP);
553 for (i = 0; i <= slices; i++) {
554 if (qobj->orientation == GLU_OUTSIDE) {
555 if (qobj->textureCoords) {
556 glTexCoord2f(texLow * sinCache[i] + 0.5,
557 texLow * cosCache[i] + 0.5);
558 }
559 glVertex3f(radiusLow * sinCache[i],
560 radiusLow * cosCache[i], 0.0);
561
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 } else {
569 if (qobj->textureCoords) {
570 glTexCoord2f(texHigh * sinCache[i] + 0.5,
571 texHigh * cosCache[i] + 0.5);
572 }
573 glVertex3f(radiusHigh * sinCache[i],
574 radiusHigh * cosCache[i], 0.0);
575
576 if (qobj->textureCoords) {
577 glTexCoord2f(texLow * sinCache[i] + 0.5,
578 texLow * cosCache[i] + 0.5);
579 }
580 glVertex3f(radiusLow * sinCache[i],
581 radiusLow * cosCache[i], 0.0);
582 }
583 }
584 glEnd();
585 }
586 break;
587 case GLU_POINT:
588 glBegin(GL_POINTS);
589 for (i = 0; i < slices2; i++) {
590 sintemp = sinCache[i];
591 costemp = cosCache[i];
592 for (j = 0; j <= loops; j++) {
593 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
594
595 if (qobj->textureCoords) {
596 texLow = radiusLow / outerRadius / 2;
597
598 glTexCoord2f(texLow * sinCache[i] + 0.5,
599 texLow * cosCache[i] + 0.5);
600 }
601 glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
602 }
603 }
604 glEnd();
605 break;
606 case GLU_LINE:
607 if (innerRadius == outerRadius) {
608 glBegin(GL_LINE_STRIP);
609
610 for (i = 0; i <= slices; i++) {
611 if (qobj->textureCoords) {
612 glTexCoord2f(sinCache[i] / 2 + 0.5,
613 cosCache[i] / 2 + 0.5);
614 }
615 glVertex3f(innerRadius * sinCache[i],
616 innerRadius * cosCache[i], 0.0);
617 }
618 glEnd();
619 break;
620 }
621 for (j = 0; j <= loops; j++) {
622 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
623 if (qobj->textureCoords) {
624 texLow = radiusLow / outerRadius / 2;
625 }
626
627 glBegin(GL_LINE_STRIP);
628 for (i = 0; i <= slices; i++) {
629 if (qobj->textureCoords) {
630 glTexCoord2f(texLow * sinCache[i] + 0.5,
631 texLow * cosCache[i] + 0.5);
632 }
633 glVertex3f(radiusLow * sinCache[i],
634 radiusLow * cosCache[i], 0.0);
635 }
636 glEnd();
637 }
638 for (i=0; i < slices2; i++) {
639 sintemp = sinCache[i];
640 costemp = cosCache[i];
641 glBegin(GL_LINE_STRIP);
642 for (j = 0; j <= loops; j++) {
643 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
644 if (qobj->textureCoords) {
645 texLow = radiusLow / outerRadius / 2;
646 }
647
648 if (qobj->textureCoords) {
649 glTexCoord2f(texLow * sinCache[i] + 0.5,
650 texLow * cosCache[i] + 0.5);
651 }
652 glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
653 }
654 glEnd();
655 }
656 break;
657 case GLU_SILHOUETTE:
658 if (sweepAngle < 360.0) {
659 for (i = 0; i <= slices; i+= slices) {
660 sintemp = sinCache[i];
661 costemp = cosCache[i];
662 glBegin(GL_LINE_STRIP);
663 for (j = 0; j <= loops; j++) {
664 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
665
666 if (qobj->textureCoords) {
667 texLow = radiusLow / outerRadius / 2;
668 glTexCoord2f(texLow * sinCache[i] + 0.5,
669 texLow * cosCache[i] + 0.5);
670 }
671 glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
672 }
673 glEnd();
674 }
675 }
676 for (j = 0; j <= loops; j += loops) {
677 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
678 if (qobj->textureCoords) {
679 texLow = radiusLow / outerRadius / 2;
680 }
681
682 glBegin(GL_LINE_STRIP);
683 for (i = 0; i <= slices; i++) {
684 if (qobj->textureCoords) {
685 glTexCoord2f(texLow * sinCache[i] + 0.5,
686 texLow * cosCache[i] + 0.5);
687 }
688 glVertex3f(radiusLow * sinCache[i],
689 radiusLow * cosCache[i], 0.0);
690 }
691 glEnd();
692 if (innerRadius == outerRadius) break;
693 }
694 break;
695 default:
696 break;
697 }
698 }
699
700 void GLAPIENTRY
701 gluSphere(GLUquadric *qobj, GLdouble radius, GLint slices, GLint stacks)
702 {
703 GLint i,j,max;
704 GLfloat sinCache1a[CACHE_SIZE];
705 GLfloat cosCache1a[CACHE_SIZE];
706 GLfloat sinCache2a[CACHE_SIZE];
707 GLfloat cosCache2a[CACHE_SIZE];
708 GLfloat sinCache3a[CACHE_SIZE];
709 GLfloat cosCache3a[CACHE_SIZE];
710 GLfloat sinCache1b[CACHE_SIZE];
711 GLfloat cosCache1b[CACHE_SIZE];
712 GLfloat sinCache2b[CACHE_SIZE];
713 GLfloat cosCache2b[CACHE_SIZE];
714 GLfloat sinCache3b[CACHE_SIZE];
715 GLfloat cosCache3b[CACHE_SIZE];
716 GLfloat angle;
717 GLfloat x, y, zLow, zHigh;
718 GLfloat sintemp1, sintemp2, sintemp3, sintemp4;
719 GLfloat costemp1, costemp2, costemp3, costemp4;
720 GLfloat zNormal;
721 GLfloat xyNormalRatio;
722 GLboolean needCache2, needCache3;
723 GLint start, finish;
724
725 if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
726 if (stacks >= CACHE_SIZE) stacks = CACHE_SIZE-1;
727 if (slices < 2 || stacks < 1 || radius < 0.0) {
728 gluQuadricError(qobj, GLU_INVALID_VALUE);
729 return;
730 }
731
732 /* Cache is the vertex locations cache */
733 /* Cache2 is the various normals at the vertices themselves */
734 /* Cache3 is the various normals for the faces */
735 needCache2 = needCache3 = GL_FALSE;
736
737 if (qobj->normals == GLU_SMOOTH) {
738 needCache2 = GL_TRUE;
739 }
740
741 if (qobj->normals == GLU_FLAT) {
742 if (qobj->drawStyle != GLU_POINT) {
743 needCache3 = GL_TRUE;
744 }
745 if (qobj->drawStyle == GLU_LINE) {
746 needCache2 = GL_TRUE;
747 }
748 }
749
750 for (i = 0; i < slices; i++) {
751 angle = 2 * PI * i / slices;
752 sinCache1a[i] = SIN(angle);
753 cosCache1a[i] = COS(angle);
754 if (needCache2) {
755 sinCache2a[i] = sinCache1a[i];
756 cosCache2a[i] = cosCache1a[i];
757 }
758 }
759
760 for (j = 0; j <= stacks; j++) {
761 angle = PI * j / stacks;
762 if (needCache2) {
763 if (qobj->orientation == GLU_OUTSIDE) {
764 sinCache2b[j] = SIN(angle);
765 cosCache2b[j] = COS(angle);
766 } else {
767 sinCache2b[j] = -SIN(angle);
768 cosCache2b[j] = -COS(angle);
769 }
770 }
771 sinCache1b[j] = radius * SIN(angle);
772 cosCache1b[j] = radius * COS(angle);
773 }
774 /* Make sure it comes to a point */
775 sinCache1b[0] = 0;
776 sinCache1b[stacks] = 0;
777
778 if (needCache3) {
779 for (i = 0; i < slices; i++) {
780 angle = 2 * PI * (i-0.5) / slices;
781 sinCache3a[i] = SIN(angle);
782 cosCache3a[i] = COS(angle);
783 }
784 for (j = 0; j <= stacks; j++) {
785 angle = PI * (j - 0.5) / stacks;
786 if (qobj->orientation == GLU_OUTSIDE) {
787 sinCache3b[j] = SIN(angle);
788 cosCache3b[j] = COS(angle);
789 } else {
790 sinCache3b[j] = -SIN(angle);
791 cosCache3b[j] = -COS(angle);
792 }
793 }
794 }
795
796 sinCache1a[slices] = sinCache1a[0];
797 cosCache1a[slices] = cosCache1a[0];
798 if (needCache2) {
799 sinCache2a[slices] = sinCache2a[0];
800 cosCache2a[slices] = cosCache2a[0];
801 }
802 if (needCache3) {
803 sinCache3a[slices] = sinCache3a[0];
804 cosCache3a[slices] = cosCache3a[0];
805 }
806
807 switch (qobj->drawStyle) {
808 case GLU_FILL:
809 /* Do ends of sphere as TRIANGLE_FAN's (if not texturing)
810 ** We don't do it when texturing because we need to respecify the
811 ** texture coordinates of the apex for every adjacent vertex (because
812 ** it isn't a constant for that point)
813 */
814 if (!(qobj->textureCoords)) {
815 start = 1;
816 finish = stacks - 1;
817
818 /* Low end first (j == 0 iteration) */
819 sintemp2 = sinCache1b[1];
820 zHigh = cosCache1b[1];
821 switch(qobj->normals) {
822 case GLU_FLAT:
823 sintemp3 = sinCache3b[1];
824 costemp3 = cosCache3b[1];
825 break;
826 case GLU_SMOOTH:
827 sintemp3 = sinCache2b[1];
828 costemp3 = cosCache2b[1];
829 glNormal3f(sinCache2a[0] * sinCache2b[0],
830 cosCache2a[0] * sinCache2b[0],
831 cosCache2b[0]);
832 break;
833 default:
834 break;
835 }
836 glBegin(GL_TRIANGLE_FAN);
837 glVertex3f(0.0, 0.0, radius);
838 if (qobj->orientation == GLU_OUTSIDE) {
839 for (i = slices; i >= 0; i--) {
840 switch(qobj->normals) {
841 case GLU_SMOOTH:
842 glNormal3f(sinCache2a[i] * sintemp3,
843 cosCache2a[i] * sintemp3,
844 costemp3);
845 break;
846 case GLU_FLAT:
847 if (i != slices) {
848 glNormal3f(sinCache3a[i+1] * sintemp3,
849 cosCache3a[i+1] * sintemp3,
850 costemp3);
851 }
852 break;
853 case GLU_NONE:
854 default:
855 break;
856 }
857 glVertex3f(sintemp2 * sinCache1a[i],
858 sintemp2 * cosCache1a[i], zHigh);
859 }
860 } else {
861 for (i = 0; i <= slices; i++) {
862 switch(qobj->normals) {
863 case GLU_SMOOTH:
864 glNormal3f(sinCache2a[i] * sintemp3,
865 cosCache2a[i] * sintemp3,
866 costemp3);
867 break;
868 case GLU_FLAT:
869 glNormal3f(sinCache3a[i] * sintemp3,
870 cosCache3a[i] * sintemp3,
871 costemp3);
872 break;
873 case GLU_NONE:
874 default:
875 break;
876 }
877 glVertex3f(sintemp2 * sinCache1a[i],
878 sintemp2 * cosCache1a[i], zHigh);
879 }
880 }
881 glEnd();
882
883 /* High end next (j == stacks-1 iteration) */
884 sintemp2 = sinCache1b[stacks-1];
885 zHigh = cosCache1b[stacks-1];
886 switch(qobj->normals) {
887 case GLU_FLAT:
888 sintemp3 = sinCache3b[stacks];
889 costemp3 = cosCache3b[stacks];
890 break;
891 case GLU_SMOOTH:
892 sintemp3 = sinCache2b[stacks-1];
893 costemp3 = cosCache2b[stacks-1];
894 glNormal3f(sinCache2a[stacks] * sinCache2b[stacks],
895 cosCache2a[stacks] * sinCache2b[stacks],
896 cosCache2b[stacks]);
897 break;
898 default:
899 break;
900 }
901 glBegin(GL_TRIANGLE_FAN);
902 glVertex3f(0.0, 0.0, -radius);
903 if (qobj->orientation == GLU_OUTSIDE) {
904 for (i = 0; i <= slices; i++) {
905 switch(qobj->normals) {
906 case GLU_SMOOTH:
907 glNormal3f(sinCache2a[i] * sintemp3,
908 cosCache2a[i] * sintemp3,
909 costemp3);
910 break;
911 case GLU_FLAT:
912 glNormal3f(sinCache3a[i] * sintemp3,
913 cosCache3a[i] * sintemp3,
914 costemp3);
915 break;
916 case GLU_NONE:
917 default:
918 break;
919 }
920 glVertex3f(sintemp2 * sinCache1a[i],
921 sintemp2 * cosCache1a[i], zHigh);
922 }
923 } else {
924 for (i = slices; i >= 0; i--) {
925 switch(qobj->normals) {
926 case GLU_SMOOTH:
927 glNormal3f(sinCache2a[i] * sintemp3,
928 cosCache2a[i] * sintemp3,
929 costemp3);
930 break;
931 case GLU_FLAT:
932 if (i != slices) {
933 glNormal3f(sinCache3a[i+1] * sintemp3,
934 cosCache3a[i+1] * sintemp3,
935 costemp3);
936 }
937 break;
938 case GLU_NONE:
939 default:
940 break;
941 }
942 glVertex3f(sintemp2 * sinCache1a[i],
943 sintemp2 * cosCache1a[i], zHigh);
944 }
945 }
946 glEnd();
947 } else {
948 start = 0;
949 finish = stacks;
950 }
951 for (j = start; j < finish; j++) {
952 zLow = cosCache1b[j];
953 zHigh = cosCache1b[j+1];
954 sintemp1 = sinCache1b[j];
955 sintemp2 = sinCache1b[j+1];
956 switch(qobj->normals) {
957 case GLU_FLAT:
958 sintemp4 = sinCache3b[j+1];
959 costemp4 = cosCache3b[j+1];
960 break;
961 case GLU_SMOOTH:
962 if (qobj->orientation == GLU_OUTSIDE) {
963 sintemp3 = sinCache2b[j+1];
964 costemp3 = cosCache2b[j+1];
965 sintemp4 = sinCache2b[j];
966 costemp4 = cosCache2b[j];
967 } else {
968 sintemp3 = sinCache2b[j];
969 costemp3 = cosCache2b[j];
970 sintemp4 = sinCache2b[j+1];
971 costemp4 = cosCache2b[j+1];
972 }
973 break;
974 default:
975 break;
976 }
977
978 glBegin(GL_QUAD_STRIP);
979 for (i = 0; i <= slices; i++) {
980 switch(qobj->normals) {
981 case GLU_SMOOTH:
982 glNormal3f(sinCache2a[i] * sintemp3,
983 cosCache2a[i] * sintemp3,
984 costemp3);
985 break;
986 case GLU_FLAT:
987 case GLU_NONE:
988 default:
989 break;
990 }
991 if (qobj->orientation == GLU_OUTSIDE) {
992 if (qobj->textureCoords) {
993 glTexCoord2f(1 - (float) i / slices,
994 1 - (float) (j+1) / stacks);
995 }
996 glVertex3f(sintemp2 * sinCache1a[i],
997 sintemp2 * cosCache1a[i], zHigh);
998 } else {
999 if (qobj->textureCoords) {
1000 glTexCoord2f(1 - (float) i / slices,
1001 1 - (float) j / stacks);
1002 }
1003 glVertex3f(sintemp1 * sinCache1a[i],
1004 sintemp1 * cosCache1a[i], zLow);
1005 }
1006 switch(qobj->normals) {
1007 case GLU_SMOOTH:
1008 glNormal3f(sinCache2a[i] * sintemp4,
1009 cosCache2a[i] * sintemp4,
1010 costemp4);
1011 break;
1012 case GLU_FLAT:
1013 glNormal3f(sinCache3a[i] * sintemp4,
1014 cosCache3a[i] * sintemp4,
1015 costemp4);
1016 break;
1017 case GLU_NONE:
1018 default:
1019 break;
1020 }
1021 if (qobj->orientation == GLU_OUTSIDE) {
1022 if (qobj->textureCoords) {
1023 glTexCoord2f(1 - (float) i / slices,
1024 1 - (float) j / stacks);
1025 }
1026 glVertex3f(sintemp1 * sinCache1a[i],
1027 sintemp1 * cosCache1a[i], zLow);
1028 } else {
1029 if (qobj->textureCoords) {
1030 glTexCoord2f(1 - (float) i / slices,
1031 1 - (float) (j+1) / stacks);
1032 }
1033 glVertex3f(sintemp2 * sinCache1a[i],
1034 sintemp2 * cosCache1a[i], zHigh);
1035 }
1036 }
1037 glEnd();
1038 }
1039 break;
1040 case GLU_POINT:
1041 glBegin(GL_POINTS);
1042 for (j = 0; j <= stacks; j++) {
1043 sintemp1 = sinCache1b[j];
1044 costemp1 = cosCache1b[j];
1045 switch(qobj->normals) {
1046 case GLU_FLAT:
1047 case GLU_SMOOTH:
1048 sintemp2 = sinCache2b[j];
1049 costemp2 = cosCache2b[j];
1050 break;
1051 default:
1052 break;
1053 }
1054 for (i = 0; i < slices; i++) {
1055 switch(qobj->normals) {
1056 case GLU_FLAT:
1057 case GLU_SMOOTH:
1058 glNormal3f(sinCache2a[i] * sintemp2,
1059 cosCache2a[i] * sintemp2,
1060 costemp2);
1061 break;
1062 case GLU_NONE:
1063 default:
1064 break;
1065 }
1066
1067 zLow = j * radius / stacks;
1068
1069 if (qobj->textureCoords) {
1070 glTexCoord2f(1 - (float) i / slices,
1071 1 - (float) j / stacks);
1072 }
1073 glVertex3f(sintemp1 * sinCache1a[i],
1074 sintemp1 * cosCache1a[i], costemp1);
1075 }
1076 }
1077 glEnd();
1078 break;
1079 case GLU_LINE:
1080 case GLU_SILHOUETTE:
1081 for (j = 1; j < stacks; j++) {
1082 sintemp1 = sinCache1b[j];
1083 costemp1 = cosCache1b[j];
1084 switch(qobj->normals) {
1085 case GLU_FLAT:
1086 case GLU_SMOOTH:
1087 sintemp2 = sinCache2b[j];
1088 costemp2 = cosCache2b[j];
1089 break;
1090 default:
1091 break;
1092 }
1093
1094 glBegin(GL_LINE_STRIP);
1095 for (i = 0; i <= slices; i++) {
1096 switch(qobj->normals) {
1097 case GLU_FLAT:
1098 glNormal3f(sinCache3a[i] * sintemp2,
1099 cosCache3a[i] * sintemp2,
1100 costemp2);
1101 break;
1102 case GLU_SMOOTH:
1103 glNormal3f(sinCache2a[i] * sintemp2,
1104 cosCache2a[i] * sintemp2,
1105 costemp2);
1106 break;
1107 case GLU_NONE:
1108 default:
1109 break;
1110 }
1111 if (qobj->textureCoords) {
1112 glTexCoord2f(1 - (float) i / slices,
1113 1 - (float) j / stacks);
1114 }
1115 glVertex3f(sintemp1 * sinCache1a[i],
1116 sintemp1 * cosCache1a[i], costemp1);
1117 }
1118 glEnd();
1119 }
1120 for (i = 0; i < slices; i++) {
1121 sintemp1 = sinCache1a[i];
1122 costemp1 = cosCache1a[i];
1123 switch(qobj->normals) {
1124 case GLU_FLAT:
1125 case GLU_SMOOTH:
1126 sintemp2 = sinCache2a[i];
1127 costemp2 = cosCache2a[i];
1128 break;
1129 default:
1130 break;
1131 }
1132
1133 glBegin(GL_LINE_STRIP);
1134 for (j = 0; j <= stacks; j++) {
1135 switch(qobj->normals) {
1136 case GLU_FLAT:
1137 glNormal3f(sintemp2 * sinCache3b[j],
1138 costemp2 * sinCache3b[j],
1139 cosCache3b[j]);
1140 break;
1141 case GLU_SMOOTH:
1142 glNormal3f(sintemp2 * sinCache2b[j],
1143 costemp2 * sinCache2b[j],
1144 cosCache2b[j]);
1145 break;
1146 case GLU_NONE:
1147 default:
1148 break;
1149 }
1150
1151 if (qobj->textureCoords) {
1152 glTexCoord2f(1 - (float) i / slices,
1153 1 - (float) j / stacks);
1154 }
1155 glVertex3f(sintemp1 * sinCache1b[j],
1156 costemp1 * sinCache1b[j], cosCache1b[j]);
1157 }
1158 glEnd();
1159 }
1160 break;
1161 default:
1162 break;
1163 }
1164 }