Release 2.16.
[wine.git] / dlls / glu32 / quad.c
blobf9914ed31c894fd96f78cb8ae0eb9b112c7a5dca
1 /*
2 * SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
3 * Copyright (C) 1991-2000 Silicon Graphics, Inc. All Rights Reserved.
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:
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.
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.
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.
31 #include "config.h"
32 #include "wine/port.h"
34 #include <stdarg.h>
35 #include <math.h>
37 #include "windef.h"
38 #include "winbase.h"
39 #include "wine/wgl.h"
40 #include "wine/glu.h"
42 /* Make it not a power of two to avoid cache thrashing on the chip */
43 #define CACHE_SIZE 240
45 struct GLUquadric {
46 GLint normals;
47 GLboolean textureCoords;
48 GLint orientation;
49 GLint drawStyle;
50 void (GLAPIENTRY *errorCallback)( GLint );
53 /***********************************************************************
54 * gluNewQuadric (GLU32.@)
56 GLUquadric * WINAPI gluNewQuadric(void)
58 GLUquadric *newstate;
60 newstate = HeapAlloc(GetProcessHeap(), 0, sizeof(GLUquadric));
61 if (newstate == NULL) {
62 /* Can't report an error at this point... */
63 return NULL;
65 newstate->normals = GLU_SMOOTH;
66 newstate->textureCoords = GL_FALSE;
67 newstate->orientation = GLU_OUTSIDE;
68 newstate->drawStyle = GLU_FILL;
69 newstate->errorCallback = NULL;
70 return newstate;
74 /***********************************************************************
75 * gluDeleteQuadric (GLU32.@)
77 void WINAPI gluDeleteQuadric( GLUquadric *state )
79 HeapFree(GetProcessHeap(), 0, state);
82 static void gluQuadricError(GLUquadric *qobj, GLenum which)
84 if (qobj->errorCallback) {
85 qobj->errorCallback(which);
89 /***********************************************************************
90 * gluQuadricCallback (GLU32.@)
92 void WINAPI gluQuadricCallback( GLUquadric *qobj, GLenum which, void (CALLBACK *fn)(void) )
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;
104 /***********************************************************************
105 * gluQuadricNormals (GLU32.@)
107 void WINAPI gluQuadricNormals( GLUquadric *qobj, GLenum normals )
109 switch (normals) {
110 case GLU_SMOOTH:
111 case GLU_FLAT:
112 case GLU_NONE:
113 break;
114 default:
115 gluQuadricError(qobj, GLU_INVALID_ENUM);
116 return;
118 qobj->normals = normals;
121 /***********************************************************************
122 * gluQuadricTexture (GLU32.@)
124 void WINAPI gluQuadricTexture( GLUquadric *qobj, GLboolean textureCoords )
126 qobj->textureCoords = textureCoords;
129 /***********************************************************************
130 * gluQuadricOrientation (GLU32.@)
132 void WINAPI gluQuadricOrientation( GLUquadric *qobj, GLenum orientation )
134 switch(orientation) {
135 case GLU_OUTSIDE:
136 case GLU_INSIDE:
137 break;
138 default:
139 gluQuadricError(qobj, GLU_INVALID_ENUM);
140 return;
142 qobj->orientation = orientation;
145 /***********************************************************************
146 * gluQuadricDrawStyle (GLU32.@)
148 void WINAPI gluQuadricDrawStyle( GLUquadric *qobj, GLenum drawStyle )
150 switch(drawStyle) {
151 case GLU_POINT:
152 case GLU_LINE:
153 case GLU_FILL:
154 case GLU_SILHOUETTE:
155 break;
156 default:
157 gluQuadricError(qobj, GLU_INVALID_ENUM);
158 return;
160 qobj->drawStyle = drawStyle;
163 /***********************************************************************
164 * gluCylinder (GLU32.@)
166 void WINAPI gluCylinder( GLUquadric *qobj, GLdouble baseRadius, GLdouble topRadius,
167 GLdouble height, GLint slices, GLint stacks )
169 GLint i,j;
170 GLfloat sinCache[CACHE_SIZE];
171 GLfloat cosCache[CACHE_SIZE];
172 GLfloat sinCache2[CACHE_SIZE];
173 GLfloat cosCache2[CACHE_SIZE];
174 GLfloat sinCache3[CACHE_SIZE];
175 GLfloat cosCache3[CACHE_SIZE];
176 GLfloat angle;
177 GLfloat zLow, zHigh;
178 GLfloat sintemp, costemp;
179 GLfloat length;
180 GLfloat deltaRadius;
181 GLfloat zNormal;
182 GLfloat xyNormalRatio;
183 GLfloat radiusLow, radiusHigh;
184 int needCache2, needCache3;
186 if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
188 if (slices < 2 || stacks < 1 || baseRadius < 0.0 || topRadius < 0.0 ||
189 height < 0.0) {
190 gluQuadricError(qobj, GLU_INVALID_VALUE);
191 return;
194 /* Compute length (needed for normal calculations) */
195 deltaRadius = baseRadius - topRadius;
196 length = sqrtf(deltaRadius*deltaRadius + height*height);
197 if (length == 0.0) {
198 gluQuadricError(qobj, GLU_INVALID_VALUE);
199 return;
202 /* Cache is the vertex locations cache */
203 /* Cache2 is the various normals at the vertices themselves */
204 /* Cache3 is the various normals for the faces */
205 needCache2 = needCache3 = 0;
206 if (qobj->normals == GLU_SMOOTH) {
207 needCache2 = 1;
210 if (qobj->normals == GLU_FLAT) {
211 if (qobj->drawStyle != GLU_POINT) {
212 needCache3 = 1;
214 if (qobj->drawStyle == GLU_LINE) {
215 needCache2 = 1;
219 zNormal = deltaRadius / length;
220 xyNormalRatio = height / length;
222 for (i = 0; i < slices; i++) {
223 angle = 2 * M_PI * i / slices;
224 if (needCache2) {
225 if (qobj->orientation == GLU_OUTSIDE) {
226 sinCache2[i] = xyNormalRatio * sinf(angle);
227 cosCache2[i] = xyNormalRatio * cosf(angle);
228 } else {
229 sinCache2[i] = -xyNormalRatio * sinf(angle);
230 cosCache2[i] = -xyNormalRatio * cosf(angle);
233 sinCache[i] = sinf(angle);
234 cosCache[i] = cosf(angle);
237 if (needCache3) {
238 for (i = 0; i < slices; i++) {
239 angle = 2 * M_PI * (i-0.5) / slices;
240 if (qobj->orientation == GLU_OUTSIDE) {
241 sinCache3[i] = xyNormalRatio * sinf(angle);
242 cosCache3[i] = xyNormalRatio * cosf(angle);
243 } else {
244 sinCache3[i] = -xyNormalRatio * sinf(angle);
245 cosCache3[i] = -xyNormalRatio * cosf(angle);
250 sinCache[slices] = sinCache[0];
251 cosCache[slices] = cosCache[0];
252 if (needCache2) {
253 sinCache2[slices] = sinCache2[0];
254 cosCache2[slices] = cosCache2[0];
256 if (needCache3) {
257 sinCache3[slices] = sinCache3[0];
258 cosCache3[slices] = cosCache3[0];
261 switch (qobj->drawStyle) {
262 case GLU_FILL:
263 /* Note:
264 ** An argument could be made for using a TRIANGLE_FAN for the end
265 ** of the cylinder of either radii is 0.0 (a cone). However, a
266 ** TRIANGLE_FAN would not work in smooth shading mode (the common
267 ** case) because the normal for the apex is different for every
268 ** triangle (and TRIANGLE_FAN doesn't let me respecify that normal).
269 ** Now, my choice is GL_TRIANGLES, or leave the GL_QUAD_STRIP and
270 ** just let the GL trivially reject one of the two triangles of the
271 ** QUAD. GL_QUAD_STRIP is probably faster, so I will leave this code
272 ** alone.
274 for (j = 0; j < stacks; j++) {
275 zLow = j * height / stacks;
276 zHigh = (j + 1) * height / stacks;
277 radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
278 radiusHigh = baseRadius - deltaRadius * ((float) (j + 1) / stacks);
280 glBegin(GL_QUAD_STRIP);
281 for (i = 0; i <= slices; i++) {
282 switch(qobj->normals) {
283 case GLU_FLAT:
284 glNormal3f(sinCache3[i], cosCache3[i], zNormal);
285 break;
286 case GLU_SMOOTH:
287 glNormal3f(sinCache2[i], cosCache2[i], zNormal);
288 break;
289 case GLU_NONE:
290 default:
291 break;
293 if (qobj->orientation == GLU_OUTSIDE) {
294 if (qobj->textureCoords) {
295 glTexCoord2f(1 - (float) i / slices,
296 (float) j / stacks);
298 glVertex3f(radiusLow * sinCache[i],
299 radiusLow * cosCache[i], zLow);
300 if (qobj->textureCoords) {
301 glTexCoord2f(1 - (float) i / slices,
302 (float) (j+1) / stacks);
304 glVertex3f(radiusHigh * sinCache[i],
305 radiusHigh * cosCache[i], zHigh);
306 } else {
307 if (qobj->textureCoords) {
308 glTexCoord2f(1 - (float) i / slices,
309 (float) (j+1) / stacks);
311 glVertex3f(radiusHigh * sinCache[i],
312 radiusHigh * cosCache[i], zHigh);
313 if (qobj->textureCoords) {
314 glTexCoord2f(1 - (float) i / slices,
315 (float) j / stacks);
317 glVertex3f(radiusLow * sinCache[i],
318 radiusLow * cosCache[i], zLow);
321 glEnd();
323 break;
324 case GLU_POINT:
325 glBegin(GL_POINTS);
326 for (i = 0; i < slices; i++) {
327 switch(qobj->normals) {
328 case GLU_FLAT:
329 case GLU_SMOOTH:
330 glNormal3f(sinCache2[i], cosCache2[i], zNormal);
331 break;
332 case GLU_NONE:
333 default:
334 break;
336 sintemp = sinCache[i];
337 costemp = cosCache[i];
338 for (j = 0; j <= stacks; j++) {
339 zLow = j * height / stacks;
340 radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
342 if (qobj->textureCoords) {
343 glTexCoord2f(1 - (float) i / slices,
344 (float) j / stacks);
346 glVertex3f(radiusLow * sintemp,
347 radiusLow * costemp, zLow);
350 glEnd();
351 break;
352 case GLU_LINE:
353 for (j = 1; j < stacks; j++) {
354 zLow = j * height / stacks;
355 radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
357 glBegin(GL_LINE_STRIP);
358 for (i = 0; i <= slices; i++) {
359 switch(qobj->normals) {
360 case GLU_FLAT:
361 glNormal3f(sinCache3[i], cosCache3[i], zNormal);
362 break;
363 case GLU_SMOOTH:
364 glNormal3f(sinCache2[i], cosCache2[i], zNormal);
365 break;
366 case GLU_NONE:
367 default:
368 break;
370 if (qobj->textureCoords) {
371 glTexCoord2f(1 - (float) i / slices,
372 (float) j / stacks);
374 glVertex3f(radiusLow * sinCache[i],
375 radiusLow * cosCache[i], zLow);
377 glEnd();
379 /* Intentionally fall through here... */
380 case GLU_SILHOUETTE:
381 for (j = 0; j <= stacks; j += stacks) {
382 zLow = j * height / stacks;
383 radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
385 glBegin(GL_LINE_STRIP);
386 for (i = 0; i <= slices; i++) {
387 switch(qobj->normals) {
388 case GLU_FLAT:
389 glNormal3f(sinCache3[i], cosCache3[i], zNormal);
390 break;
391 case GLU_SMOOTH:
392 glNormal3f(sinCache2[i], cosCache2[i], zNormal);
393 break;
394 case GLU_NONE:
395 default:
396 break;
398 if (qobj->textureCoords) {
399 glTexCoord2f(1 - (float) i / slices,
400 (float) j / stacks);
402 glVertex3f(radiusLow * sinCache[i], radiusLow * cosCache[i],
403 zLow);
405 glEnd();
407 for (i = 0; i < slices; i++) {
408 switch(qobj->normals) {
409 case GLU_FLAT:
410 case GLU_SMOOTH:
411 glNormal3f(sinCache2[i], cosCache2[i], 0.0);
412 break;
413 case GLU_NONE:
414 default:
415 break;
417 sintemp = sinCache[i];
418 costemp = cosCache[i];
419 glBegin(GL_LINE_STRIP);
420 for (j = 0; j <= stacks; j++) {
421 zLow = j * height / stacks;
422 radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
424 if (qobj->textureCoords) {
425 glTexCoord2f(1 - (float) i / slices,
426 (float) j / stacks);
428 glVertex3f(radiusLow * sintemp,
429 radiusLow * costemp, zLow);
431 glEnd();
433 break;
434 default:
435 break;
439 /***********************************************************************
440 * gluDisk (GLU32.@)
442 void WINAPI gluDisk( GLUquadric *qobj, GLdouble innerRadius, GLdouble outerRadius,
443 GLint slices, GLint loops )
445 gluPartialDisk(qobj, innerRadius, outerRadius, slices, loops, 0.0, 360.0);
448 /***********************************************************************
449 * gluPartialDisk (GLU32.@)
451 void WINAPI gluPartialDisk( GLUquadric *qobj, GLdouble innerRadius, GLdouble outerRadius,
452 GLint slices, GLint loops, GLdouble startAngle, GLdouble sweepAngle )
454 GLint i,j;
455 GLfloat sinCache[CACHE_SIZE];
456 GLfloat cosCache[CACHE_SIZE];
457 GLfloat angle;
458 GLfloat sintemp, costemp;
459 GLfloat deltaRadius;
460 GLfloat radiusLow, radiusHigh;
461 GLfloat texLow = 0.0, texHigh = 0.0;
462 GLfloat angleOffset;
463 GLint slices2;
464 GLint finish;
466 if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
467 if (slices < 2 || loops < 1 || outerRadius <= 0.0 || innerRadius < 0.0 ||
468 innerRadius > outerRadius) {
469 gluQuadricError(qobj, GLU_INVALID_VALUE);
470 return;
473 if (sweepAngle < -360.0) sweepAngle = 360.0;
474 if (sweepAngle > 360.0) sweepAngle = 360.0;
475 if (sweepAngle < 0) {
476 startAngle += sweepAngle;
477 sweepAngle = -sweepAngle;
480 if (sweepAngle == 360.0) {
481 slices2 = slices;
482 } else {
483 slices2 = slices + 1;
486 /* Compute length (needed for normal calculations) */
487 deltaRadius = outerRadius - innerRadius;
489 /* Cache is the vertex locations cache */
491 angleOffset = startAngle / 180.0 * M_PI;
492 for (i = 0; i <= slices; i++) {
493 angle = angleOffset + ((M_PI * sweepAngle) / 180.0) * i / slices;
494 sinCache[i] = sinf(angle);
495 cosCache[i] = cosf(angle);
498 if (sweepAngle == 360.0) {
499 sinCache[slices] = sinCache[0];
500 cosCache[slices] = cosCache[0];
503 switch(qobj->normals) {
504 case GLU_FLAT:
505 case GLU_SMOOTH:
506 if (qobj->orientation == GLU_OUTSIDE) {
507 glNormal3f(0.0, 0.0, 1.0);
508 } else {
509 glNormal3f(0.0, 0.0, -1.0);
511 break;
512 default:
513 case GLU_NONE:
514 break;
517 switch (qobj->drawStyle) {
518 case GLU_FILL:
519 if (innerRadius == 0.0) {
520 finish = loops - 1;
521 /* Triangle strip for inner polygons */
522 glBegin(GL_TRIANGLE_FAN);
523 if (qobj->textureCoords) {
524 glTexCoord2f(0.5, 0.5);
526 glVertex3f(0.0, 0.0, 0.0);
527 radiusLow = outerRadius -
528 deltaRadius * ((float) (loops-1) / loops);
529 if (qobj->textureCoords) {
530 texLow = radiusLow / outerRadius / 2;
533 if (qobj->orientation == GLU_OUTSIDE) {
534 for (i = slices; i >= 0; i--) {
535 if (qobj->textureCoords) {
536 glTexCoord2f(texLow * sinCache[i] + 0.5,
537 texLow * cosCache[i] + 0.5);
539 glVertex3f(radiusLow * sinCache[i],
540 radiusLow * cosCache[i], 0.0);
542 } else {
543 for (i = 0; i <= slices; i++) {
544 if (qobj->textureCoords) {
545 glTexCoord2f(texLow * sinCache[i] + 0.5,
546 texLow * cosCache[i] + 0.5);
548 glVertex3f(radiusLow * sinCache[i],
549 radiusLow * cosCache[i], 0.0);
552 glEnd();
553 } else {
554 finish = loops;
556 for (j = 0; j < finish; j++) {
557 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
558 radiusHigh = outerRadius - deltaRadius * ((float) (j + 1) / loops);
559 if (qobj->textureCoords) {
560 texLow = radiusLow / outerRadius / 2;
561 texHigh = radiusHigh / outerRadius / 2;
564 glBegin(GL_QUAD_STRIP);
565 for (i = 0; i <= slices; i++) {
566 if (qobj->orientation == GLU_OUTSIDE) {
567 if (qobj->textureCoords) {
568 glTexCoord2f(texLow * sinCache[i] + 0.5,
569 texLow * cosCache[i] + 0.5);
571 glVertex3f(radiusLow * sinCache[i],
572 radiusLow * cosCache[i], 0.0);
574 if (qobj->textureCoords) {
575 glTexCoord2f(texHigh * sinCache[i] + 0.5,
576 texHigh * cosCache[i] + 0.5);
578 glVertex3f(radiusHigh * sinCache[i],
579 radiusHigh * cosCache[i], 0.0);
580 } else {
581 if (qobj->textureCoords) {
582 glTexCoord2f(texHigh * sinCache[i] + 0.5,
583 texHigh * cosCache[i] + 0.5);
585 glVertex3f(radiusHigh * sinCache[i],
586 radiusHigh * cosCache[i], 0.0);
588 if (qobj->textureCoords) {
589 glTexCoord2f(texLow * sinCache[i] + 0.5,
590 texLow * cosCache[i] + 0.5);
592 glVertex3f(radiusLow * sinCache[i],
593 radiusLow * cosCache[i], 0.0);
596 glEnd();
598 break;
599 case GLU_POINT:
600 glBegin(GL_POINTS);
601 for (i = 0; i < slices2; i++) {
602 sintemp = sinCache[i];
603 costemp = cosCache[i];
604 for (j = 0; j <= loops; j++) {
605 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
607 if (qobj->textureCoords) {
608 texLow = radiusLow / outerRadius / 2;
610 glTexCoord2f(texLow * sinCache[i] + 0.5,
611 texLow * cosCache[i] + 0.5);
613 glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
616 glEnd();
617 break;
618 case GLU_LINE:
619 if (innerRadius == outerRadius) {
620 glBegin(GL_LINE_STRIP);
622 for (i = 0; i <= slices; i++) {
623 if (qobj->textureCoords) {
624 glTexCoord2f(sinCache[i] / 2 + 0.5,
625 cosCache[i] / 2 + 0.5);
627 glVertex3f(innerRadius * sinCache[i],
628 innerRadius * cosCache[i], 0.0);
630 glEnd();
631 break;
633 for (j = 0; j <= loops; j++) {
634 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
635 if (qobj->textureCoords) {
636 texLow = radiusLow / outerRadius / 2;
639 glBegin(GL_LINE_STRIP);
640 for (i = 0; i <= slices; i++) {
641 if (qobj->textureCoords) {
642 glTexCoord2f(texLow * sinCache[i] + 0.5,
643 texLow * cosCache[i] + 0.5);
645 glVertex3f(radiusLow * sinCache[i],
646 radiusLow * cosCache[i], 0.0);
648 glEnd();
650 for (i=0; i < slices2; i++) {
651 sintemp = sinCache[i];
652 costemp = cosCache[i];
653 glBegin(GL_LINE_STRIP);
654 for (j = 0; j <= loops; j++) {
655 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
656 if (qobj->textureCoords) {
657 texLow = radiusLow / outerRadius / 2;
660 if (qobj->textureCoords) {
661 glTexCoord2f(texLow * sinCache[i] + 0.5,
662 texLow * cosCache[i] + 0.5);
664 glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
666 glEnd();
668 break;
669 case GLU_SILHOUETTE:
670 if (sweepAngle < 360.0) {
671 for (i = 0; i <= slices; i+= slices) {
672 sintemp = sinCache[i];
673 costemp = cosCache[i];
674 glBegin(GL_LINE_STRIP);
675 for (j = 0; j <= loops; j++) {
676 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
678 if (qobj->textureCoords) {
679 texLow = radiusLow / outerRadius / 2;
680 glTexCoord2f(texLow * sinCache[i] + 0.5,
681 texLow * cosCache[i] + 0.5);
683 glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
685 glEnd();
688 for (j = 0; j <= loops; j += loops) {
689 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
690 if (qobj->textureCoords) {
691 texLow = radiusLow / outerRadius / 2;
694 glBegin(GL_LINE_STRIP);
695 for (i = 0; i <= slices; i++) {
696 if (qobj->textureCoords) {
697 glTexCoord2f(texLow * sinCache[i] + 0.5,
698 texLow * cosCache[i] + 0.5);
700 glVertex3f(radiusLow * sinCache[i],
701 radiusLow * cosCache[i], 0.0);
703 glEnd();
704 if (innerRadius == outerRadius) break;
706 break;
707 default:
708 break;
712 /***********************************************************************
713 * gluSphere (GLU32.@)
715 void WINAPI gluSphere( GLUquadric *qobj, GLdouble radius, GLint slices, GLint stacks )
717 GLint i,j;
718 GLfloat sinCache1a[CACHE_SIZE];
719 GLfloat cosCache1a[CACHE_SIZE];
720 GLfloat sinCache2a[CACHE_SIZE];
721 GLfloat cosCache2a[CACHE_SIZE];
722 GLfloat sinCache3a[CACHE_SIZE];
723 GLfloat cosCache3a[CACHE_SIZE];
724 GLfloat sinCache1b[CACHE_SIZE];
725 GLfloat cosCache1b[CACHE_SIZE];
726 GLfloat sinCache2b[CACHE_SIZE];
727 GLfloat cosCache2b[CACHE_SIZE];
728 GLfloat sinCache3b[CACHE_SIZE];
729 GLfloat cosCache3b[CACHE_SIZE];
730 GLfloat angle;
731 GLfloat zLow, zHigh;
732 GLfloat sintemp1 = 0.0, sintemp2 = 0.0, sintemp3 = 0.0, sintemp4 = 0.0;
733 GLfloat costemp1 = 0.0, costemp2 = 0.0, costemp3 = 0.0, costemp4 = 0.0;
734 GLboolean needCache2, needCache3;
735 GLint start, finish;
737 if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
738 if (stacks >= CACHE_SIZE) stacks = CACHE_SIZE-1;
739 if (slices < 2 || stacks < 1 || radius < 0.0) {
740 gluQuadricError(qobj, GLU_INVALID_VALUE);
741 return;
744 /* Cache is the vertex locations cache */
745 /* Cache2 is the various normals at the vertices themselves */
746 /* Cache3 is the various normals for the faces */
747 needCache2 = needCache3 = GL_FALSE;
749 if (qobj->normals == GLU_SMOOTH) {
750 needCache2 = GL_TRUE;
753 if (qobj->normals == GLU_FLAT) {
754 if (qobj->drawStyle != GLU_POINT) {
755 needCache3 = GL_TRUE;
757 if (qobj->drawStyle == GLU_LINE) {
758 needCache2 = GL_TRUE;
762 for (i = 0; i < slices; i++) {
763 angle = 2 * M_PI * i / slices;
764 sinCache1a[i] = sinf(angle);
765 cosCache1a[i] = cosf(angle);
766 if (needCache2) {
767 sinCache2a[i] = sinCache1a[i];
768 cosCache2a[i] = cosCache1a[i];
772 for (j = 0; j <= stacks; j++) {
773 angle = M_PI * j / stacks;
774 if (needCache2) {
775 if (qobj->orientation == GLU_OUTSIDE) {
776 sinCache2b[j] = sinf(angle);
777 cosCache2b[j] = cosf(angle);
778 } else {
779 sinCache2b[j] = -sinf(angle);
780 cosCache2b[j] = -cosf(angle);
783 sinCache1b[j] = radius * sinf(angle);
784 cosCache1b[j] = radius * cosf(angle);
786 /* Make sure it comes to a point */
787 sinCache1b[0] = 0;
788 sinCache1b[stacks] = 0;
790 if (needCache3) {
791 for (i = 0; i < slices; i++) {
792 angle = 2 * M_PI * (i-0.5) / slices;
793 sinCache3a[i] = sinf(angle);
794 cosCache3a[i] = cosf(angle);
796 for (j = 0; j <= stacks; j++) {
797 angle = M_PI * (j - 0.5) / stacks;
798 if (qobj->orientation == GLU_OUTSIDE) {
799 sinCache3b[j] = sinf(angle);
800 cosCache3b[j] = cosf(angle);
801 } else {
802 sinCache3b[j] = -sinf(angle);
803 cosCache3b[j] = -cosf(angle);
808 sinCache1a[slices] = sinCache1a[0];
809 cosCache1a[slices] = cosCache1a[0];
810 if (needCache2) {
811 sinCache2a[slices] = sinCache2a[0];
812 cosCache2a[slices] = cosCache2a[0];
814 if (needCache3) {
815 sinCache3a[slices] = sinCache3a[0];
816 cosCache3a[slices] = cosCache3a[0];
819 switch (qobj->drawStyle) {
820 case GLU_FILL:
821 /* Do ends of sphere as TRIANGLE_FAN's (if not texturing)
822 ** We don't do it when texturing because we need to respecify the
823 ** texture coordinates of the apex for every adjacent vertex (because
824 ** it isn't a constant for that point)
826 if (!(qobj->textureCoords)) {
827 start = 1;
828 finish = stacks - 1;
830 /* Low end first (j == 0 iteration) */
831 sintemp2 = sinCache1b[1];
832 zHigh = cosCache1b[1];
833 switch(qobj->normals) {
834 case GLU_FLAT:
835 sintemp3 = sinCache3b[1];
836 costemp3 = cosCache3b[1];
837 break;
838 case GLU_SMOOTH:
839 sintemp3 = sinCache2b[1];
840 costemp3 = cosCache2b[1];
841 glNormal3f(sinCache2a[0] * sinCache2b[0],
842 cosCache2a[0] * sinCache2b[0],
843 cosCache2b[0]);
844 break;
845 default:
846 break;
848 glBegin(GL_TRIANGLE_FAN);
849 glVertex3f(0.0, 0.0, radius);
850 if (qobj->orientation == GLU_OUTSIDE) {
851 for (i = slices; i >= 0; i--) {
852 switch(qobj->normals) {
853 case GLU_SMOOTH:
854 glNormal3f(sinCache2a[i] * sintemp3,
855 cosCache2a[i] * sintemp3,
856 costemp3);
857 break;
858 case GLU_FLAT:
859 if (i != slices) {
860 glNormal3f(sinCache3a[i+1] * sintemp3,
861 cosCache3a[i+1] * sintemp3,
862 costemp3);
864 break;
865 case GLU_NONE:
866 default:
867 break;
869 glVertex3f(sintemp2 * sinCache1a[i],
870 sintemp2 * cosCache1a[i], zHigh);
872 } else {
873 for (i = 0; i <= slices; i++) {
874 switch(qobj->normals) {
875 case GLU_SMOOTH:
876 glNormal3f(sinCache2a[i] * sintemp3,
877 cosCache2a[i] * sintemp3,
878 costemp3);
879 break;
880 case GLU_FLAT:
881 glNormal3f(sinCache3a[i] * sintemp3,
882 cosCache3a[i] * sintemp3,
883 costemp3);
884 break;
885 case GLU_NONE:
886 default:
887 break;
889 glVertex3f(sintemp2 * sinCache1a[i],
890 sintemp2 * cosCache1a[i], zHigh);
893 glEnd();
895 /* High end next (j == stacks-1 iteration) */
896 sintemp2 = sinCache1b[stacks-1];
897 zHigh = cosCache1b[stacks-1];
898 switch(qobj->normals) {
899 case GLU_FLAT:
900 sintemp3 = sinCache3b[stacks];
901 costemp3 = cosCache3b[stacks];
902 break;
903 case GLU_SMOOTH:
904 sintemp3 = sinCache2b[stacks-1];
905 costemp3 = cosCache2b[stacks-1];
906 glNormal3f(sinCache2a[stacks] * sinCache2b[stacks],
907 cosCache2a[stacks] * sinCache2b[stacks],
908 cosCache2b[stacks]);
909 break;
910 default:
911 break;
913 glBegin(GL_TRIANGLE_FAN);
914 glVertex3f(0.0, 0.0, -radius);
915 if (qobj->orientation == GLU_OUTSIDE) {
916 for (i = 0; i <= slices; i++) {
917 switch(qobj->normals) {
918 case GLU_SMOOTH:
919 glNormal3f(sinCache2a[i] * sintemp3,
920 cosCache2a[i] * sintemp3,
921 costemp3);
922 break;
923 case GLU_FLAT:
924 glNormal3f(sinCache3a[i] * sintemp3,
925 cosCache3a[i] * sintemp3,
926 costemp3);
927 break;
928 case GLU_NONE:
929 default:
930 break;
932 glVertex3f(sintemp2 * sinCache1a[i],
933 sintemp2 * cosCache1a[i], zHigh);
935 } else {
936 for (i = slices; i >= 0; i--) {
937 switch(qobj->normals) {
938 case GLU_SMOOTH:
939 glNormal3f(sinCache2a[i] * sintemp3,
940 cosCache2a[i] * sintemp3,
941 costemp3);
942 break;
943 case GLU_FLAT:
944 if (i != slices) {
945 glNormal3f(sinCache3a[i+1] * sintemp3,
946 cosCache3a[i+1] * sintemp3,
947 costemp3);
949 break;
950 case GLU_NONE:
951 default:
952 break;
954 glVertex3f(sintemp2 * sinCache1a[i],
955 sintemp2 * cosCache1a[i], zHigh);
958 glEnd();
959 } else {
960 start = 0;
961 finish = stacks;
963 for (j = start; j < finish; j++) {
964 zLow = cosCache1b[j];
965 zHigh = cosCache1b[j+1];
966 sintemp1 = sinCache1b[j];
967 sintemp2 = sinCache1b[j+1];
968 switch(qobj->normals) {
969 case GLU_FLAT:
970 sintemp4 = sinCache3b[j+1];
971 costemp4 = cosCache3b[j+1];
972 break;
973 case GLU_SMOOTH:
974 if (qobj->orientation == GLU_OUTSIDE) {
975 sintemp3 = sinCache2b[j+1];
976 costemp3 = cosCache2b[j+1];
977 sintemp4 = sinCache2b[j];
978 costemp4 = cosCache2b[j];
979 } else {
980 sintemp3 = sinCache2b[j];
981 costemp3 = cosCache2b[j];
982 sintemp4 = sinCache2b[j+1];
983 costemp4 = cosCache2b[j+1];
985 break;
986 default:
987 break;
990 glBegin(GL_QUAD_STRIP);
991 for (i = 0; i <= slices; i++) {
992 switch(qobj->normals) {
993 case GLU_SMOOTH:
994 glNormal3f(sinCache2a[i] * sintemp3,
995 cosCache2a[i] * sintemp3,
996 costemp3);
997 break;
998 case GLU_FLAT:
999 case GLU_NONE:
1000 default:
1001 break;
1003 if (qobj->orientation == GLU_OUTSIDE) {
1004 if (qobj->textureCoords) {
1005 glTexCoord2f(1 - (float) i / slices,
1006 1 - (float) (j+1) / stacks);
1008 glVertex3f(sintemp2 * sinCache1a[i],
1009 sintemp2 * cosCache1a[i], zHigh);
1010 } else {
1011 if (qobj->textureCoords) {
1012 glTexCoord2f(1 - (float) i / slices,
1013 1 - (float) j / stacks);
1015 glVertex3f(sintemp1 * sinCache1a[i],
1016 sintemp1 * cosCache1a[i], zLow);
1018 switch(qobj->normals) {
1019 case GLU_SMOOTH:
1020 glNormal3f(sinCache2a[i] * sintemp4,
1021 cosCache2a[i] * sintemp4,
1022 costemp4);
1023 break;
1024 case GLU_FLAT:
1025 glNormal3f(sinCache3a[i] * sintemp4,
1026 cosCache3a[i] * sintemp4,
1027 costemp4);
1028 break;
1029 case GLU_NONE:
1030 default:
1031 break;
1033 if (qobj->orientation == GLU_OUTSIDE) {
1034 if (qobj->textureCoords) {
1035 glTexCoord2f(1 - (float) i / slices,
1036 1 - (float) j / stacks);
1038 glVertex3f(sintemp1 * sinCache1a[i],
1039 sintemp1 * cosCache1a[i], zLow);
1040 } else {
1041 if (qobj->textureCoords) {
1042 glTexCoord2f(1 - (float) i / slices,
1043 1 - (float) (j+1) / stacks);
1045 glVertex3f(sintemp2 * sinCache1a[i],
1046 sintemp2 * cosCache1a[i], zHigh);
1049 glEnd();
1051 break;
1052 case GLU_POINT:
1053 glBegin(GL_POINTS);
1054 for (j = 0; j <= stacks; j++) {
1055 sintemp1 = sinCache1b[j];
1056 costemp1 = cosCache1b[j];
1057 switch(qobj->normals) {
1058 case GLU_FLAT:
1059 case GLU_SMOOTH:
1060 sintemp2 = sinCache2b[j];
1061 costemp2 = cosCache2b[j];
1062 break;
1063 default:
1064 break;
1066 for (i = 0; i < slices; i++) {
1067 switch(qobj->normals) {
1068 case GLU_FLAT:
1069 case GLU_SMOOTH:
1070 glNormal3f(sinCache2a[i] * sintemp2,
1071 cosCache2a[i] * sintemp2,
1072 costemp2);
1073 break;
1074 case GLU_NONE:
1075 default:
1076 break;
1079 zLow = j * radius / stacks;
1081 if (qobj->textureCoords) {
1082 glTexCoord2f(1 - (float) i / slices,
1083 1 - (float) j / stacks);
1085 glVertex3f(sintemp1 * sinCache1a[i],
1086 sintemp1 * cosCache1a[i], costemp1);
1089 glEnd();
1090 break;
1091 case GLU_LINE:
1092 case GLU_SILHOUETTE:
1093 for (j = 1; j < stacks; j++) {
1094 sintemp1 = sinCache1b[j];
1095 costemp1 = cosCache1b[j];
1096 switch(qobj->normals) {
1097 case GLU_FLAT:
1098 case GLU_SMOOTH:
1099 sintemp2 = sinCache2b[j];
1100 costemp2 = cosCache2b[j];
1101 break;
1102 default:
1103 break;
1106 glBegin(GL_LINE_STRIP);
1107 for (i = 0; i <= slices; i++) {
1108 switch(qobj->normals) {
1109 case GLU_FLAT:
1110 glNormal3f(sinCache3a[i] * sintemp2,
1111 cosCache3a[i] * sintemp2,
1112 costemp2);
1113 break;
1114 case GLU_SMOOTH:
1115 glNormal3f(sinCache2a[i] * sintemp2,
1116 cosCache2a[i] * sintemp2,
1117 costemp2);
1118 break;
1119 case GLU_NONE:
1120 default:
1121 break;
1123 if (qobj->textureCoords) {
1124 glTexCoord2f(1 - (float) i / slices,
1125 1 - (float) j / stacks);
1127 glVertex3f(sintemp1 * sinCache1a[i],
1128 sintemp1 * cosCache1a[i], costemp1);
1130 glEnd();
1132 for (i = 0; i < slices; i++) {
1133 sintemp1 = sinCache1a[i];
1134 costemp1 = cosCache1a[i];
1135 switch(qobj->normals) {
1136 case GLU_FLAT:
1137 case GLU_SMOOTH:
1138 sintemp2 = sinCache2a[i];
1139 costemp2 = cosCache2a[i];
1140 break;
1141 default:
1142 break;
1145 glBegin(GL_LINE_STRIP);
1146 for (j = 0; j <= stacks; j++) {
1147 switch(qobj->normals) {
1148 case GLU_FLAT:
1149 glNormal3f(sintemp2 * sinCache3b[j],
1150 costemp2 * sinCache3b[j],
1151 cosCache3b[j]);
1152 break;
1153 case GLU_SMOOTH:
1154 glNormal3f(sintemp2 * sinCache2b[j],
1155 costemp2 * sinCache2b[j],
1156 cosCache2b[j]);
1157 break;
1158 case GLU_NONE:
1159 default:
1160 break;
1163 if (qobj->textureCoords) {
1164 glTexCoord2f(1 - (float) i / slices,
1165 1 - (float) j / stacks);
1167 glVertex3f(sintemp1 * sinCache1b[j],
1168 costemp1 * sinCache1b[j], cosCache1b[j]);
1170 glEnd();
1172 break;
1173 default:
1174 break;