[WINGDI.H]
[reactos.git] / reactos / dll / win32 / glu32 / 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 #ifndef GLU_ERROR
45 #define GLU_ERROR 100103
46 #endif
47
48 /* Make it not a power of two to avoid cache thrashing on the chip */
49 #define CACHE_SIZE 240
50
51 #undef PI
52 #define PI 3.14159265358979323846
53
54 struct GLUquadric {
55 GLint normals;
56 GLboolean textureCoords;
57 GLint orientation;
58 GLint drawStyle;
59 void (GLAPIENTRY *errorCallback)( GLint );
60 };
61
62 GLUquadric * GLAPIENTRY
63 gluNewQuadric(void)
64 {
65 GLUquadric *newstate;
66
67 newstate = (GLUquadric *) malloc(sizeof(GLUquadric));
68 if (newstate == NULL) {
69 /* Can't report an error at this point... */
70 return NULL;
71 }
72 newstate->normals = GLU_SMOOTH;
73 newstate->textureCoords = GL_FALSE;
74 newstate->orientation = GLU_OUTSIDE;
75 newstate->drawStyle = GLU_FILL;
76 newstate->errorCallback = NULL;
77 return newstate;
78 }
79
80
81 void GLAPIENTRY
82 gluDeleteQuadric(GLUquadric *state)
83 {
84 free(state);
85 }
86
87 static void gluQuadricError(GLUquadric *qobj, GLenum which)
88 {
89 if (qobj->errorCallback) {
90 qobj->errorCallback(which);
91 }
92 }
93
94 void GLAPIENTRY
95 gluQuadricCallback(GLUquadric *qobj, GLenum which, _GLUfuncptr fn)
96 {
97 switch (which) {
98 case GLU_ERROR:
99 qobj->errorCallback = (void (GLAPIENTRY *)(GLint)) fn;
100 break;
101 default:
102 gluQuadricError(qobj, GLU_INVALID_ENUM);
103 return;
104 }
105 }
106
107 void GLAPIENTRY
108 gluQuadricNormals(GLUquadric *qobj, GLenum normals)
109 {
110 switch (normals) {
111 case GLU_SMOOTH:
112 case GLU_FLAT:
113 case GLU_NONE:
114 break;
115 default:
116 gluQuadricError(qobj, GLU_INVALID_ENUM);
117 return;
118 }
119 qobj->normals = normals;
120 }
121
122 void GLAPIENTRY
123 gluQuadricTexture(GLUquadric *qobj, GLboolean textureCoords)
124 {
125 qobj->textureCoords = textureCoords;
126 }
127
128 void GLAPIENTRY
129 gluQuadricOrientation(GLUquadric *qobj, GLenum orientation)
130 {
131 switch(orientation) {
132 case GLU_OUTSIDE:
133 case GLU_INSIDE:
134 break;
135 default:
136 gluQuadricError(qobj, GLU_INVALID_ENUM);
137 return;
138 }
139 qobj->orientation = orientation;
140 }
141
142 void GLAPIENTRY
143 gluQuadricDrawStyle(GLUquadric *qobj, GLenum drawStyle)
144 {
145 switch(drawStyle) {
146 case GLU_POINT:
147 case GLU_LINE:
148 case GLU_FILL:
149 case GLU_SILHOUETTE:
150 break;
151 default:
152 gluQuadricError(qobj, GLU_INVALID_ENUM);
153 return;
154 }
155 qobj->drawStyle = drawStyle;
156 }
157
158 void GLAPIENTRY
159 gluCylinder(GLUquadric *qobj, GLdouble baseRadius, GLdouble topRadius,
160 GLdouble height, GLint slices, GLint stacks)
161 {
162 GLint i,j;
163 GLfloat sinCache[CACHE_SIZE];
164 GLfloat cosCache[CACHE_SIZE];
165 GLfloat sinCache2[CACHE_SIZE];
166 GLfloat cosCache2[CACHE_SIZE];
167 GLfloat sinCache3[CACHE_SIZE];
168 GLfloat cosCache3[CACHE_SIZE];
169 GLfloat angle;
170 GLfloat zLow, zHigh;
171 GLfloat sintemp, costemp;
172 GLfloat length;
173 GLfloat deltaRadius;
174 GLfloat zNormal;
175 GLfloat xyNormalRatio;
176 GLfloat radiusLow, radiusHigh;
177 int needCache2, needCache3;
178
179 if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
180
181 if (slices < 2 || stacks < 1 || baseRadius < 0.0 || topRadius < 0.0 ||
182 height < 0.0) {
183 gluQuadricError(qobj, GLU_INVALID_VALUE);
184 return;
185 }
186
187 /* Compute length (needed for normal calculations) */
188 deltaRadius = baseRadius - topRadius;
189 length = SQRT(deltaRadius*deltaRadius + height*height);
190 if (length == 0.0) {
191 gluQuadricError(qobj, GLU_INVALID_VALUE);
192 return;
193 }
194
195 /* Cache is the vertex locations cache */
196 /* Cache2 is the various normals at the vertices themselves */
197 /* Cache3 is the various normals for the faces */
198 needCache2 = needCache3 = 0;
199 if (qobj->normals == GLU_SMOOTH) {
200 needCache2 = 1;
201 }
202
203 if (qobj->normals == GLU_FLAT) {
204 if (qobj->drawStyle != GLU_POINT) {
205 needCache3 = 1;
206 }
207 if (qobj->drawStyle == GLU_LINE) {
208 needCache2 = 1;
209 }
210 }
211
212 zNormal = deltaRadius / length;
213 xyNormalRatio = height / length;
214
215 for (i = 0; i < slices; i++) {
216 angle = 2 * PI * i / slices;
217 if (needCache2) {
218 if (qobj->orientation == GLU_OUTSIDE) {
219 sinCache2[i] = xyNormalRatio * SIN(angle);
220 cosCache2[i] = xyNormalRatio * COS(angle);
221 } else {
222 sinCache2[i] = -xyNormalRatio * SIN(angle);
223 cosCache2[i] = -xyNormalRatio * COS(angle);
224 }
225 }
226 sinCache[i] = SIN(angle);
227 cosCache[i] = COS(angle);
228 }
229
230 if (needCache3) {
231 for (i = 0; i < slices; i++) {
232 angle = 2 * PI * (i-0.5) / slices;
233 if (qobj->orientation == GLU_OUTSIDE) {
234 sinCache3[i] = xyNormalRatio * SIN(angle);
235 cosCache3[i] = xyNormalRatio * COS(angle);
236 } else {
237 sinCache3[i] = -xyNormalRatio * SIN(angle);
238 cosCache3[i] = -xyNormalRatio * COS(angle);
239 }
240 }
241 }
242
243 sinCache[slices] = sinCache[0];
244 cosCache[slices] = cosCache[0];
245 if (needCache2) {
246 sinCache2[slices] = sinCache2[0];
247 cosCache2[slices] = cosCache2[0];
248 }
249 if (needCache3) {
250 sinCache3[slices] = sinCache3[0];
251 cosCache3[slices] = cosCache3[0];
252 }
253
254 switch (qobj->drawStyle) {
255 case GLU_FILL:
256 /* Note:
257 ** An argument could be made for using a TRIANGLE_FAN for the end
258 ** of the cylinder of either radii is 0.0 (a cone). However, a
259 ** TRIANGLE_FAN would not work in smooth shading mode (the common
260 ** case) because the normal for the apex is different for every
261 ** triangle (and TRIANGLE_FAN doesn't let me respecify that normal).
262 ** Now, my choice is GL_TRIANGLES, or leave the GL_QUAD_STRIP and
263 ** just let the GL trivially reject one of the two triangles of the
264 ** QUAD. GL_QUAD_STRIP is probably faster, so I will leave this code
265 ** alone.
266 */
267 for (j = 0; j < stacks; j++) {
268 zLow = j * height / stacks;
269 zHigh = (j + 1) * height / stacks;
270 radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
271 radiusHigh = baseRadius - deltaRadius * ((float) (j + 1) / stacks);
272
273 glBegin(GL_QUAD_STRIP);
274 for (i = 0; i <= slices; i++) {
275 switch(qobj->normals) {
276 case GLU_FLAT:
277 glNormal3f(sinCache3[i], cosCache3[i], zNormal);
278 break;
279 case GLU_SMOOTH:
280 glNormal3f(sinCache2[i], cosCache2[i], zNormal);
281 break;
282 case GLU_NONE:
283 default:
284 break;
285 }
286 if (qobj->orientation == GLU_OUTSIDE) {
287 if (qobj->textureCoords) {
288 glTexCoord2f(1 - (float) i / slices,
289 (float) j / stacks);
290 }
291 glVertex3f(radiusLow * sinCache[i],
292 radiusLow * cosCache[i], zLow);
293 if (qobj->textureCoords) {
294 glTexCoord2f(1 - (float) i / slices,
295 (float) (j+1) / stacks);
296 }
297 glVertex3f(radiusHigh * sinCache[i],
298 radiusHigh * cosCache[i], zHigh);
299 } else {
300 if (qobj->textureCoords) {
301 glTexCoord2f(1 - (float) i / slices,
302 (float) (j+1) / stacks);
303 }
304 glVertex3f(radiusHigh * sinCache[i],
305 radiusHigh * cosCache[i], zHigh);
306 if (qobj->textureCoords) {
307 glTexCoord2f(1 - (float) i / slices,
308 (float) j / stacks);
309 }
310 glVertex3f(radiusLow * sinCache[i],
311 radiusLow * cosCache[i], zLow);
312 }
313 }
314 glEnd();
315 }
316 break;
317 case GLU_POINT:
318 glBegin(GL_POINTS);
319 for (i = 0; i < slices; i++) {
320 switch(qobj->normals) {
321 case GLU_FLAT:
322 case GLU_SMOOTH:
323 glNormal3f(sinCache2[i], cosCache2[i], zNormal);
324 break;
325 case GLU_NONE:
326 default:
327 break;
328 }
329 sintemp = sinCache[i];
330 costemp = cosCache[i];
331 for (j = 0; j <= stacks; j++) {
332 zLow = j * height / stacks;
333 radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
334
335 if (qobj->textureCoords) {
336 glTexCoord2f(1 - (float) i / slices,
337 (float) j / stacks);
338 }
339 glVertex3f(radiusLow * sintemp,
340 radiusLow * costemp, zLow);
341 }
342 }
343 glEnd();
344 break;
345 case GLU_LINE:
346 for (j = 1; j < stacks; j++) {
347 zLow = j * height / stacks;
348 radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
349
350 glBegin(GL_LINE_STRIP);
351 for (i = 0; i <= slices; i++) {
352 switch(qobj->normals) {
353 case GLU_FLAT:
354 glNormal3f(sinCache3[i], cosCache3[i], zNormal);
355 break;
356 case GLU_SMOOTH:
357 glNormal3f(sinCache2[i], cosCache2[i], zNormal);
358 break;
359 case GLU_NONE:
360 default:
361 break;
362 }
363 if (qobj->textureCoords) {
364 glTexCoord2f(1 - (float) i / slices,
365 (float) j / stacks);
366 }
367 glVertex3f(radiusLow * sinCache[i],
368 radiusLow * cosCache[i], zLow);
369 }
370 glEnd();
371 }
372 /* Intentionally fall through here... */
373 case GLU_SILHOUETTE:
374 for (j = 0; j <= stacks; j += stacks) {
375 zLow = j * height / stacks;
376 radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
377
378 glBegin(GL_LINE_STRIP);
379 for (i = 0; i <= slices; i++) {
380 switch(qobj->normals) {
381 case GLU_FLAT:
382 glNormal3f(sinCache3[i], cosCache3[i], zNormal);
383 break;
384 case GLU_SMOOTH:
385 glNormal3f(sinCache2[i], cosCache2[i], zNormal);
386 break;
387 case GLU_NONE:
388 default:
389 break;
390 }
391 if (qobj->textureCoords) {
392 glTexCoord2f(1 - (float) i / slices,
393 (float) j / stacks);
394 }
395 glVertex3f(radiusLow * sinCache[i], radiusLow * cosCache[i],
396 zLow);
397 }
398 glEnd();
399 }
400 for (i = 0; i < slices; i++) {
401 switch(qobj->normals) {
402 case GLU_FLAT:
403 case GLU_SMOOTH:
404 glNormal3f(sinCache2[i], cosCache2[i], 0.0);
405 break;
406 case GLU_NONE:
407 default:
408 break;
409 }
410 sintemp = sinCache[i];
411 costemp = cosCache[i];
412 glBegin(GL_LINE_STRIP);
413 for (j = 0; j <= stacks; j++) {
414 zLow = j * height / stacks;
415 radiusLow = baseRadius - deltaRadius * ((float) j / stacks);
416
417 if (qobj->textureCoords) {
418 glTexCoord2f(1 - (float) i / slices,
419 (float) j / stacks);
420 }
421 glVertex3f(radiusLow * sintemp,
422 radiusLow * costemp, zLow);
423 }
424 glEnd();
425 }
426 break;
427 default:
428 break;
429 }
430 }
431
432 void GLAPIENTRY
433 gluDisk(GLUquadric *qobj, GLdouble innerRadius, GLdouble outerRadius,
434 GLint slices, GLint loops)
435 {
436 gluPartialDisk(qobj, innerRadius, outerRadius, slices, loops, 0.0, 360.0);
437 }
438
439 void GLAPIENTRY
440 gluPartialDisk(GLUquadric *qobj, GLdouble innerRadius,
441 GLdouble outerRadius, GLint slices, GLint loops,
442 GLdouble startAngle, GLdouble sweepAngle)
443 {
444 GLint i,j;
445 GLfloat sinCache[CACHE_SIZE];
446 GLfloat cosCache[CACHE_SIZE];
447 GLfloat angle;
448 GLfloat sintemp, costemp;
449 GLfloat deltaRadius;
450 GLfloat radiusLow, radiusHigh;
451 GLfloat texLow = 0, texHigh = 0;
452 GLfloat angleOffset;
453 GLint slices2;
454 GLint finish;
455
456 if (slices >= CACHE_SIZE) slices = CACHE_SIZE-1;
457 if (slices < 2 || loops < 1 || outerRadius <= 0.0 || innerRadius < 0.0 ||
458 innerRadius > outerRadius) {
459 gluQuadricError(qobj, GLU_INVALID_VALUE);
460 return;
461 }
462
463 if (sweepAngle < -360.0) sweepAngle = 360.0;
464 if (sweepAngle > 360.0) sweepAngle = 360.0;
465 if (sweepAngle < 0) {
466 startAngle += sweepAngle;
467 sweepAngle = -sweepAngle;
468 }
469
470 if (sweepAngle == 360.0) {
471 slices2 = slices;
472 } else {
473 slices2 = slices + 1;
474 }
475
476 /* Compute length (needed for normal calculations) */
477 deltaRadius = outerRadius - innerRadius;
478
479 /* Cache is the vertex locations cache */
480
481 angleOffset = startAngle / 180.0 * PI;
482 for (i = 0; i <= slices; i++) {
483 angle = angleOffset + ((PI * sweepAngle) / 180.0) * i / slices;
484 sinCache[i] = SIN(angle);
485 cosCache[i] = COS(angle);
486 }
487
488 if (sweepAngle == 360.0) {
489 sinCache[slices] = sinCache[0];
490 cosCache[slices] = cosCache[0];
491 }
492
493 switch(qobj->normals) {
494 case GLU_FLAT:
495 case GLU_SMOOTH:
496 if (qobj->orientation == GLU_OUTSIDE) {
497 glNormal3f(0.0, 0.0, 1.0);
498 } else {
499 glNormal3f(0.0, 0.0, -1.0);
500 }
501 break;
502 default:
503 case GLU_NONE:
504 break;
505 }
506
507 switch (qobj->drawStyle) {
508 case GLU_FILL:
509 if (innerRadius == 0.0) {
510 finish = loops - 1;
511 /* Triangle strip for inner polygons */
512 glBegin(GL_TRIANGLE_FAN);
513 if (qobj->textureCoords) {
514 glTexCoord2f(0.5, 0.5);
515 }
516 glVertex3f(0.0, 0.0, 0.0);
517 radiusLow = outerRadius -
518 deltaRadius * ((float) (loops-1) / loops);
519 if (qobj->textureCoords) {
520 texLow = radiusLow / outerRadius / 2;
521 }
522
523 if (qobj->orientation == GLU_OUTSIDE) {
524 for (i = slices; i >= 0; 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 } else {
533 for (i = 0; i <= slices; i++) {
534 if (qobj->textureCoords) {
535 glTexCoord2f(texLow * sinCache[i] + 0.5,
536 texLow * cosCache[i] + 0.5);
537 }
538 glVertex3f(radiusLow * sinCache[i],
539 radiusLow * cosCache[i], 0.0);
540 }
541 }
542 glEnd();
543 } else {
544 finish = loops;
545 }
546 for (j = 0; j < finish; j++) {
547 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
548 radiusHigh = outerRadius - deltaRadius * ((float) (j + 1) / loops);
549 if (qobj->textureCoords) {
550 texLow = radiusLow / outerRadius / 2;
551 texHigh = radiusHigh / outerRadius / 2;
552 }
553
554 glBegin(GL_QUAD_STRIP);
555 for (i = 0; i <= slices; i++) {
556 if (qobj->orientation == GLU_OUTSIDE) {
557 if (qobj->textureCoords) {
558 glTexCoord2f(texLow * sinCache[i] + 0.5,
559 texLow * cosCache[i] + 0.5);
560 }
561 glVertex3f(radiusLow * sinCache[i],
562 radiusLow * cosCache[i], 0.0);
563
564 if (qobj->textureCoords) {
565 glTexCoord2f(texHigh * sinCache[i] + 0.5,
566 texHigh * cosCache[i] + 0.5);
567 }
568 glVertex3f(radiusHigh * sinCache[i],
569 radiusHigh * cosCache[i], 0.0);
570 } else {
571 if (qobj->textureCoords) {
572 glTexCoord2f(texHigh * sinCache[i] + 0.5,
573 texHigh * cosCache[i] + 0.5);
574 }
575 glVertex3f(radiusHigh * sinCache[i],
576 radiusHigh * cosCache[i], 0.0);
577
578 if (qobj->textureCoords) {
579 glTexCoord2f(texLow * sinCache[i] + 0.5,
580 texLow * cosCache[i] + 0.5);
581 }
582 glVertex3f(radiusLow * sinCache[i],
583 radiusLow * cosCache[i], 0.0);
584 }
585 }
586 glEnd();
587 }
588 break;
589 case GLU_POINT:
590 glBegin(GL_POINTS);
591 for (i = 0; i < slices2; i++) {
592 sintemp = sinCache[i];
593 costemp = cosCache[i];
594 for (j = 0; j <= loops; j++) {
595 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
596
597 if (qobj->textureCoords) {
598 texLow = radiusLow / outerRadius / 2;
599
600 glTexCoord2f(texLow * sinCache[i] + 0.5,
601 texLow * cosCache[i] + 0.5);
602 }
603 glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
604 }
605 }
606 glEnd();
607 break;
608 case GLU_LINE:
609 if (innerRadius == outerRadius) {
610 glBegin(GL_LINE_STRIP);
611
612 for (i = 0; i <= slices; i++) {
613 if (qobj->textureCoords) {
614 glTexCoord2f(sinCache[i] / 2 + 0.5,
615 cosCache[i] / 2 + 0.5);
616 }
617 glVertex3f(innerRadius * sinCache[i],
618 innerRadius * cosCache[i], 0.0);
619 }
620 glEnd();
621 break;
622 }
623 for (j = 0; j <= loops; j++) {
624 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
625 if (qobj->textureCoords) {
626 texLow = radiusLow / outerRadius / 2;
627 }
628
629 glBegin(GL_LINE_STRIP);
630 for (i = 0; i <= slices; i++) {
631 if (qobj->textureCoords) {
632 glTexCoord2f(texLow * sinCache[i] + 0.5,
633 texLow * cosCache[i] + 0.5);
634 }
635 glVertex3f(radiusLow * sinCache[i],
636 radiusLow * cosCache[i], 0.0);
637 }
638 glEnd();
639 }
640 for (i=0; i < slices2; i++) {
641 sintemp = sinCache[i];
642 costemp = cosCache[i];
643 glBegin(GL_LINE_STRIP);
644 for (j = 0; j <= loops; j++) {
645 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
646 if (qobj->textureCoords) {
647 texLow = radiusLow / outerRadius / 2;
648 }
649
650 if (qobj->textureCoords) {
651 glTexCoord2f(texLow * sinCache[i] + 0.5,
652 texLow * cosCache[i] + 0.5);
653 }
654 glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
655 }
656 glEnd();
657 }
658 break;
659 case GLU_SILHOUETTE:
660 if (sweepAngle < 360.0) {
661 for (i = 0; i <= slices; i+= slices) {
662 sintemp = sinCache[i];
663 costemp = cosCache[i];
664 glBegin(GL_LINE_STRIP);
665 for (j = 0; j <= loops; j++) {
666 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
667
668 if (qobj->textureCoords) {
669 texLow = radiusLow / outerRadius / 2;
670 glTexCoord2f(texLow * sinCache[i] + 0.5,
671 texLow * cosCache[i] + 0.5);
672 }
673 glVertex3f(radiusLow * sintemp, radiusLow * costemp, 0.0);
674 }
675 glEnd();
676 }
677 }
678 for (j = 0; j <= loops; j += loops) {
679 radiusLow = outerRadius - deltaRadius * ((float) j / loops);
680 if (qobj->textureCoords) {
681 texLow = radiusLow / outerRadius / 2;
682 }
683
684 glBegin(GL_LINE_STRIP);
685 for (i = 0; i <= slices; i++) {
686 if (qobj->textureCoords) {
687 glTexCoord2f(texLow * sinCache[i] + 0.5,
688 texLow * cosCache[i] + 0.5);
689 }
690 glVertex3f(radiusLow * sinCache[i],
691 radiusLow * cosCache[i], 0.0);
692 }
693 glEnd();
694 if (innerRadius == outerRadius) break;
695 }
696 break;
697 default:
698 break;
699 }
700 }
701
702 void GLAPIENTRY
703 gluSphere(GLUquadric *qobj, GLdouble radius, GLint slices, GLint stacks)
704 {
705 GLint i,j;
706 GLfloat sinCache1a[CACHE_SIZE];
707 GLfloat cosCache1a[CACHE_SIZE];
708 GLfloat sinCache2a[CACHE_SIZE];
709 GLfloat cosCache2a[CACHE_SIZE];
710 GLfloat sinCache3a[CACHE_SIZE];
711 GLfloat cosCache3a[CACHE_SIZE];
712 GLfloat sinCache1b[CACHE_SIZE];
713 GLfloat cosCache1b[CACHE_SIZE];
714 GLfloat sinCache2b[CACHE_SIZE];
715 GLfloat cosCache2b[CACHE_SIZE];
716 GLfloat sinCache3b[CACHE_SIZE];
717 GLfloat cosCache3b[CACHE_SIZE];
718 GLfloat angle;
719 GLfloat zLow, zHigh;
720 GLfloat sintemp1, sintemp2=0, sintemp3=0, sintemp4=0;
721 GLfloat costemp1, costemp2=0, costemp3=0, costemp4=0;
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 }