added a few more scale/bias/lookup functions (for future use)
[mesa.git] / src / glu / mesa / quadric.c
1 /* $Id: quadric.c,v 1.1 1999/08/19 00:55:42 jtg Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.1
6 * Copyright (C) 1995-1999 Brian Paul
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23
24 /*
25 * $Log: quadric.c,v $
26 * Revision 1.1 1999/08/19 00:55:42 jtg
27 * Initial revision
28 *
29 * Revision 1.19 1999/02/27 13:55:31 brianp
30 * fixed BeOS-related GLU typedef problems
31 *
32 * Revision 1.18 1999/01/03 03:23:15 brianp
33 * now using GLAPIENTRY and GLCALLBACK keywords (Ted Jump)
34 *
35 * Revision 1.17 1999/01/03 03:19:15 brianp
36 * rewrote some of gluCylinder
37 *
38 * Revision 1.16 1998/06/01 01:08:36 brianp
39 * small update for Next/OpenStep from Alexander Mai
40 *
41 * Revision 1.15 1998/03/15 18:28:54 brianp
42 * reimplemented gluDisk() point and line mode
43 *
44 * Revision 1.14 1998/03/15 18:14:17 brianp
45 * fixed a compiler cast warning
46 *
47 * Revision 1.13 1998/02/07 14:28:34 brianp
48 * another change to gluQuadricCallback(), this time for StormC compiler
49 *
50 * Revision 1.12 1998/02/05 00:43:19 brianp
51 * Yes, still another change to gluQuadricCallback()!
52 *
53 * Revision 1.11 1998/02/04 00:27:43 brianp
54 * yet another change to gluQuadricCallback()!
55 *
56 * Revision 1.10 1998/02/04 00:23:23 brianp
57 * fixed CALLBACK problem in gluQuadricCallback() (Stephane Rehel)
58 *
59 * Revision 1.9 1998/02/04 00:20:09 brianp
60 * added missing (int) in ErrorFunc cast
61 *
62 * Revision 1.8 1998/01/16 03:37:51 brianp
63 * fixed another assignment warning in gluQuadricCallback()
64 *
65 * Revision 1.7 1998/01/16 03:35:26 brianp
66 * fixed Windows compilation warnings (Theodore Jump)
67 *
68 * Revision 1.6 1997/10/29 02:02:20 brianp
69 * various MS Windows compiler changes (David Bucciarelli, v20 3dfx driver)
70 *
71 * Revision 1.5 1997/09/17 01:51:48 brianp
72 * changed glu*Callback() functions to match prototype in glu.h
73 *
74 * Revision 1.4 1997/07/24 01:28:44 brianp
75 * changed precompiled header symbol from PCH to PC_HEADER
76 *
77 * Revision 1.3 1997/05/28 02:29:38 brianp
78 * added support for precompiled headers (PCH), inserted APIENTRY keyword
79 *
80 * Revision 1.2 1997/03/12 02:15:38 brianp
81 * fixed problem in gluPartialDisk() reported by Kenneth H. Carpenter
82 *
83 * Revision 1.1 1996/09/27 01:19:39 brianp
84 * Initial revision
85 *
86 */
87
88
89 /* TODO:
90 * texture coordinate support
91 * flip normals according to orientation
92 * there's still some inside/outside orientation bugs in possibly all
93 * but the sphere function
94 */
95
96
97 #ifdef PC_HEADER
98 #include "all.h"
99 #else
100 #include <math.h>
101 #include <stdio.h>
102 #include <stdlib.h>
103 #include "gluP.h"
104 #endif
105
106
107
108 #ifndef M_PI
109 # define M_PI (3.1415926)
110 #endif
111
112
113 /*
114 * Convert degrees to radians:
115 */
116 #define DEG_TO_RAD(A) ((A)*(M_PI/180.0))
117
118
119 /*
120 * Sin and Cos for degree angles:
121 */
122 #define SIND( A ) sin( (A)*(M_PI/180.0) )
123 #define COSD( A) cos( (A)*(M_PI/180.0) )
124
125
126 /*
127 * Texture coordinates if texture flag is set
128 */
129 #define TXTR_COORD(x,y) if (qobj->TextureFlag) glTexCoord2f(x,y);
130
131
132
133 struct GLUquadric {
134 GLenum DrawStyle; /* GLU_FILL, LINE, SILHOUETTE, or POINT */
135 GLenum Orientation; /* GLU_INSIDE or GLU_OUTSIDE */
136 GLboolean TextureFlag; /* Generate texture coords? */
137 GLenum Normals; /* GLU_NONE, GLU_FLAT, or GLU_SMOOTH */
138 void (GLCALLBACK *ErrorFunc)(GLenum err); /* Error handler callback function */
139 };
140
141
142
143 /*
144 * Process a GLU error.
145 */
146 static void quadric_error( GLUquadricObj *qobj, GLenum error, const char *msg )
147 {
148 /* Call the error call back function if any */
149 if (qobj->ErrorFunc) {
150 (*qobj->ErrorFunc)( error );
151 }
152 /* Print a message to stdout if MESA_DEBUG variable is defined */
153 if (getenv("MESA_DEBUG")) {
154 fprintf(stderr,"GLUError: %s: %s\n", (char*) gluErrorString(error), msg);
155 }
156 }
157
158
159
160
161 GLUquadricObj * GLAPIENTRY gluNewQuadric( void )
162 {
163 GLUquadricObj *q;
164
165 q = (GLUquadricObj *) malloc( sizeof(struct GLUquadric) );
166 if (q) {
167 q->DrawStyle = GLU_FILL;
168 q->Orientation = GLU_OUTSIDE;
169 q->TextureFlag = GL_FALSE;
170 q->Normals = GLU_SMOOTH;
171 q->ErrorFunc = NULL;
172 }
173 return q;
174 }
175
176
177
178 void GLAPIENTRY gluDeleteQuadric( GLUquadricObj *state )
179 {
180 if (state) {
181 free( (void *) state );
182 }
183 }
184
185
186
187 /*
188 * Set the drawing style to be GLU_FILL, GLU_LINE, GLU_SILHOUETTE,
189 * or GLU_POINT.
190 */
191 void GLAPIENTRY gluQuadricDrawStyle( GLUquadricObj *quadObject, GLenum drawStyle )
192 {
193 if (quadObject && (drawStyle==GLU_FILL || drawStyle==GLU_LINE
194 || drawStyle==GLU_SILHOUETTE || drawStyle==GLU_POINT)) {
195 quadObject->DrawStyle = drawStyle;
196 }
197 else {
198 quadric_error( quadObject, GLU_INVALID_ENUM, "qluQuadricDrawStyle" );
199 }
200 }
201
202
203
204 /*
205 * Set the orientation to GLU_INSIDE or GLU_OUTSIDE.
206 */
207 void GLAPIENTRY gluQuadricOrientation( GLUquadricObj *quadObject,
208 GLenum orientation )
209 {
210 if (quadObject && (orientation==GLU_INSIDE || orientation==GLU_OUTSIDE)) {
211 quadObject->Orientation = orientation;
212 }
213 else {
214 quadric_error( quadObject, GLU_INVALID_ENUM, "qluQuadricOrientation" );
215 }
216 }
217
218
219
220 /*
221 * Set the error handler callback function.
222 */
223 void GLAPIENTRY gluQuadricCallback( GLUquadricObj *qobj,
224 GLenum which, void (GLCALLBACK *fn)() )
225 {
226 /*
227 * UGH, this is a mess! I thought ANSI was a standard.
228 */
229 if (qobj && which==GLU_ERROR) {
230 #ifdef __CYGWIN32__
231 qobj->ErrorFunc = (void(*)(int))fn;
232 #elif defined(OPENSTEP)
233 qobj->ErrorFunc = (void(*)(GLenum))fn;
234 #elif defined(_WIN32)
235 qobj->ErrorFunc = (void(GLCALLBACK*)(int))fn;
236 #elif defined(__STORM__)
237 qobj->ErrorFunc = (void(GLCALLBACK*)(GLenum))fn;
238 #elif defined(__BEOS__)
239 qobj->ErrorFunc = (void(*)(GLenum))fn;
240 #else
241 qobj->ErrorFunc = (void(GLCALLBACK*)())fn;
242 #endif
243 }
244 }
245
246
247 void GLAPIENTRY gluQuadricNormals( GLUquadricObj *quadObject, GLenum normals )
248 {
249 if (quadObject
250 && (normals==GLU_NONE || normals==GLU_FLAT || normals==GLU_SMOOTH)) {
251 quadObject->Normals = normals;
252 }
253 }
254
255
256 void GLAPIENTRY gluQuadricTexture( GLUquadricObj *quadObject,
257 GLboolean textureCoords )
258 {
259 if (quadObject) {
260 quadObject->TextureFlag = textureCoords;
261 }
262 }
263
264
265
266
267 /*
268 * Call glNormal3f after scaling normal to unit length.
269 */
270 static void normal3f( GLfloat x, GLfloat y, GLfloat z )
271 {
272 GLdouble mag;
273
274 mag = sqrt( x*x + y*y + z*z );
275 if (mag>0.00001F) {
276 x /= mag;
277 y /= mag;
278 z /= mag;
279 }
280 glNormal3f( x, y, z );
281 }
282
283
284
285 void GLAPIENTRY gluCylinder( GLUquadricObj *qobj,
286 GLdouble baseRadius, GLdouble topRadius,
287 GLdouble height, GLint slices, GLint stacks )
288 {
289 GLdouble da, r, dr, dz;
290 GLfloat x, y, z, nz, nsign;
291 GLint i, j;
292
293 if (qobj->Orientation==GLU_INSIDE) {
294 nsign = -1.0;
295 }
296 else {
297 nsign = 1.0;
298 }
299
300 da = 2.0*M_PI / slices;
301 dr = (topRadius-baseRadius) / stacks;
302 dz = height / stacks;
303 nz = (baseRadius-topRadius) / height; /* Z component of normal vectors */
304
305 if (qobj->DrawStyle==GLU_POINT) {
306 glBegin( GL_POINTS );
307 for (i=0;i<slices;i++) {
308 x = cos(i*da);
309 y = sin(i*da);
310 normal3f( x*nsign, y*nsign, nz*nsign );
311
312 z = 0.0;
313 r = baseRadius;
314 for (j=0;j<=stacks;j++) {
315 glVertex3f( x*r, y*r, z );
316 z += dz;
317 r += dr;
318 }
319 }
320 glEnd();
321 }
322 else if (qobj->DrawStyle==GLU_LINE || qobj->DrawStyle==GLU_SILHOUETTE) {
323 /* Draw rings */
324 if (qobj->DrawStyle==GLU_LINE) {
325 z = 0.0;
326 r = baseRadius;
327 for (j=0;j<=stacks;j++) {
328 glBegin( GL_LINE_LOOP );
329 for (i=0;i<slices;i++) {
330 x = cos(i*da);
331 y = sin(i*da);
332 normal3f( x*nsign, y*nsign, nz*nsign );
333 glVertex3f( x*r, y*r, z );
334 }
335 glEnd();
336 z += dz;
337 r += dr;
338 }
339 }
340 else {
341 /* draw one ring at each end */
342 if (baseRadius!=0.0) {
343 glBegin( GL_LINE_LOOP );
344 for (i=0;i<slices;i++) {
345 x = cos(i*da);
346 y = sin(i*da);
347 normal3f( x*nsign, y*nsign, nz*nsign );
348 glVertex3f( x*baseRadius, y*baseRadius, 0.0 );
349 }
350 glEnd();
351 glBegin( GL_LINE_LOOP );
352 for (i=0;i<slices;i++) {
353 x = cos(i*da);
354 y = sin(i*da);
355 normal3f( x*nsign, y*nsign, nz*nsign );
356 glVertex3f( x*topRadius, y*topRadius, height );
357 }
358 glEnd();
359 }
360 }
361 /* draw length lines */
362 glBegin( GL_LINES );
363 for (i=0;i<slices;i++) {
364 x = cos(i*da);
365 y = sin(i*da);
366 normal3f( x*nsign, y*nsign, nz*nsign );
367 glVertex3f( x*baseRadius, y*baseRadius, 0.0 );
368 glVertex3f( x*topRadius, y*topRadius, height );
369 }
370 glEnd();
371 }
372 else if (qobj->DrawStyle==GLU_FILL) {
373 GLfloat ds = 1.0 / slices;
374 GLfloat dt = 1.0 / stacks;
375 GLfloat t = 0.0;
376 z = 0.0;
377 r = baseRadius;
378 for (j=0;j<stacks;j++) {
379 GLfloat s = 0.0;
380 glBegin( GL_QUAD_STRIP );
381 for (i=0;i<=slices;i++) {
382 GLfloat x, y;
383 if (i == slices) {
384 x = sin(0);
385 y = cos(0);
386 }
387 else {
388 x = sin(i * da);
389 y = cos(i * da);
390 }
391 if (nsign==1.0) {
392 normal3f( x*nsign, y*nsign, nz*nsign );
393 TXTR_COORD(s, t);
394 glVertex3f( x * r, y * r, z );
395 normal3f( x*nsign, y*nsign, nz*nsign );
396 TXTR_COORD(s, t + dt);
397 glVertex3f( x * (r + dr), y * (r + dr), z + dz);
398 }
399 else {
400 normal3f( x*nsign, y*nsign, nz*nsign );
401 TXTR_COORD(s, t);
402 glVertex3f( x * r, y * r, z );
403 normal3f( x*nsign, y*nsign, nz*nsign );
404 TXTR_COORD(s, t + dt);
405 glVertex3f( x * (r + dr), y * (r + dr), z + dz);
406 }
407 s += ds;
408 } /* for slices */
409 glEnd();
410 r += dr;
411 t += dt;
412 z += dz;
413 } /* for stacks */
414 }
415 }
416
417
418
419
420
421 void GLAPIENTRY gluSphere( GLUquadricObj *qobj,
422 GLdouble radius, GLint slices, GLint stacks )
423 {
424 GLfloat rho, drho, theta, dtheta;
425 GLfloat x, y, z;
426 GLfloat s, t, ds, dt;
427 GLint i, j, imin, imax;
428 GLboolean normals;
429 GLfloat nsign;
430
431 if (qobj->Normals==GLU_NONE) {
432 normals = GL_FALSE;
433 }
434 else {
435 normals = GL_TRUE;
436 }
437 if (qobj->Orientation==GLU_INSIDE) {
438 nsign = -1.0;
439 }
440 else {
441 nsign = 1.0;
442 }
443
444 drho = M_PI / (GLfloat) stacks;
445 dtheta = 2.0 * M_PI / (GLfloat) slices;
446
447 /* texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis */
448 /* t goes from -1.0/+1.0 at z = -radius/+radius (linear along longitudes) */
449 /* cannot use triangle fan on texturing (s coord. at top/bottom tip varies) */
450
451 if (qobj->DrawStyle==GLU_FILL) {
452 if (!qobj->TextureFlag) {
453 /* draw +Z end as a triangle fan */
454 glBegin( GL_TRIANGLE_FAN );
455 glNormal3f( 0.0, 0.0, 1.0 );
456 TXTR_COORD(0.5,1.0);
457 glVertex3f( 0.0, 0.0, nsign * radius );
458 for (j=0;j<=slices;j++) {
459 theta = (j==slices) ? 0.0 : j * dtheta;
460 x = -sin(theta) * sin(drho);
461 y = cos(theta) * sin(drho);
462 z = nsign * cos(drho);
463 if (normals) glNormal3f( x*nsign, y*nsign, z*nsign );
464 glVertex3f( x*radius, y*radius, z*radius );
465 }
466 glEnd();
467 }
468
469 ds = 1.0 / slices;
470 dt = 1.0 / stacks;
471 t = 1.0; /* because loop now runs from 0 */
472 if (qobj->TextureFlag) {
473 imin = 0;
474 imax = stacks;
475 }
476 else {
477 imin = 1;
478 imax = stacks-1;
479 }
480
481 /* draw intermediate stacks as quad strips */
482 for (i=imin;i<imax;i++) {
483 rho = i * drho;
484 glBegin( GL_QUAD_STRIP );
485 s = 0.0;
486 for (j=0;j<=slices;j++) {
487 theta = (j==slices) ? 0.0 : j * dtheta;
488 x = -sin(theta) * sin(rho);
489 y = cos(theta) * sin(rho);
490 z = nsign * cos(rho);
491 if (normals) glNormal3f( x*nsign, y*nsign, z*nsign );
492 TXTR_COORD(s,t);
493 glVertex3f( x*radius, y*radius, z*radius );
494 x = -sin(theta) * sin(rho+drho);
495 y = cos(theta) * sin(rho+drho);
496 z = nsign * cos(rho+drho);
497 if (normals) glNormal3f( x*nsign, y*nsign, z*nsign );
498 TXTR_COORD(s,t-dt);
499 s += ds;
500 glVertex3f( x*radius, y*radius, z*radius );
501 }
502 glEnd();
503 t -= dt;
504 }
505
506 if (!qobj->TextureFlag) {
507 /* draw -Z end as a triangle fan */
508 glBegin( GL_TRIANGLE_FAN );
509 glNormal3f( 0.0, 0.0, -1.0 );
510 TXTR_COORD(0.5,0.0);
511 glVertex3f( 0.0, 0.0, -radius*nsign );
512 rho = M_PI - drho;
513 s = 1.0;
514 t = dt;
515 for (j=slices;j>=0;j--) {
516 theta = (j==slices) ? 0.0 : j * dtheta;
517 x = -sin(theta) * sin(rho);
518 y = cos(theta) * sin(rho);
519 z = nsign * cos(rho);
520 if (normals) glNormal3f( x*nsign, y*nsign, z*nsign );
521 TXTR_COORD(s,t);
522 s -= ds;
523 glVertex3f( x*radius, y*radius, z*radius );
524 }
525 glEnd();
526 }
527 }
528 else if (qobj->DrawStyle==GLU_LINE || qobj->DrawStyle==GLU_SILHOUETTE) {
529 /* draw stack lines */
530 for (i=1;i<stacks;i++) { /* stack line at i==stacks-1 was missing here */
531 rho = i * drho;
532 glBegin( GL_LINE_LOOP );
533 for (j=0;j<slices;j++) {
534 theta = j * dtheta;
535 x = cos(theta) * sin(rho);
536 y = sin(theta) * sin(rho);
537 z = cos(rho);
538 if (normals) glNormal3f( x*nsign, y*nsign, z*nsign );
539 glVertex3f( x*radius, y*radius, z*radius );
540 }
541 glEnd();
542 }
543 /* draw slice lines */
544 for (j=0;j<slices;j++) {
545 theta = j * dtheta;
546 glBegin( GL_LINE_STRIP );
547 for (i=0;i<=stacks;i++) {
548 rho = i * drho;
549 x = cos(theta) * sin(rho);
550 y = sin(theta) * sin(rho);
551 z = cos(rho);
552 if (normals) glNormal3f( x*nsign, y*nsign, z*nsign );
553 glVertex3f( x*radius, y*radius, z*radius );
554 }
555 glEnd();
556 }
557 }
558 else if (qobj->DrawStyle==GLU_POINT) {
559 /* top and bottom-most points */
560 glBegin( GL_POINTS );
561 if (normals) glNormal3f( 0.0, 0.0, nsign );
562 glVertex3d( 0.0, 0.0, radius );
563 if (normals) glNormal3f( 0.0, 0.0, -nsign );
564 glVertex3d( 0.0, 0.0, -radius );
565
566 /* loop over stacks */
567 for (i=1;i<stacks-1;i++) {
568 rho = i * drho;
569 for (j=0;j<slices;j++) {
570 theta = j * dtheta;
571 x = cos(theta) * sin(rho);
572 y = sin(theta) * sin(rho);
573 z = cos(rho);
574 if (normals) glNormal3f( x*nsign, y*nsign, z*nsign );
575 glVertex3f( x*radius, y*radius, z*radius );
576 }
577 }
578 glEnd();
579 }
580
581 }
582
583
584
585 void GLAPIENTRY gluDisk( GLUquadricObj *qobj,
586 GLdouble innerRadius, GLdouble outerRadius,
587 GLint slices, GLint loops )
588 {
589 GLfloat da, dr;
590 #if 0
591 GLdouble a, da;
592 GLfloat r, dr;
593 GLfloat x, y;
594 GLfloat r1, r2, dtc;
595 GLint s, l;
596 #endif
597
598 /* Normal vectors */
599 if (qobj->Normals!=GLU_NONE) {
600 if (qobj->Orientation==GLU_OUTSIDE) {
601 glNormal3f( 0.0, 0.0, +1.0 );
602 }
603 else {
604 glNormal3f( 0.0, 0.0, -1.0 );
605 }
606 }
607
608 da = 2.0*M_PI / slices;
609 dr = (outerRadius-innerRadius) / (GLfloat) loops;
610
611 switch (qobj->DrawStyle) {
612 case GLU_FILL:
613 {
614 /* texture of a gluDisk is a cut out of the texture unit square
615 * x, y in [-outerRadius, +outerRadius]; s, t in [0, 1]
616 * (linear mapping)
617 */
618 GLfloat dtc = 2.0f * outerRadius;
619 GLfloat sa,ca;
620 GLfloat r1 = innerRadius;
621 GLint l;
622 for (l=0; l<loops; l++) {
623 GLfloat r2 = r1 + dr;
624 if (qobj->Orientation==GLU_OUTSIDE) {
625 GLint s;
626 glBegin( GL_QUAD_STRIP );
627 for (s=0;s<=slices;s++) {
628 GLfloat a;
629 if (s==slices) a = 0.0;
630 else a = s * da;
631 sa = sin(a); ca = cos(a);
632 TXTR_COORD(0.5+sa*r2/dtc,0.5+ca*r2/dtc);
633 glVertex2f( r2*sa, r2*ca );
634 TXTR_COORD(0.5+sa*r1/dtc,0.5+ca*r1/dtc);
635 glVertex2f( r1*sa, r1*ca );
636 }
637 glEnd();
638 }
639 else {
640 GLint s;
641 glBegin( GL_QUAD_STRIP );
642 for (s=slices;s>=0;s--) {
643 GLfloat a;
644 if (s==slices) a = 0.0;
645 else a = s * da;
646 sa = sin(a); ca = cos(a);
647 TXTR_COORD(0.5-sa*r2/dtc,0.5+ca*r2/dtc);
648 glVertex2f( r2*sa, r2*ca );
649 TXTR_COORD(0.5-sa*r1/dtc,0.5+ca*r1/dtc);
650 glVertex2f( r1*sa, r1*ca );
651 }
652 glEnd();
653 }
654 r1 = r2;
655 }
656 break;
657 }
658 case GLU_LINE:
659 {
660 GLint l, s;
661 /* draw loops */
662 for (l=0; l<=loops; l++) {
663 GLfloat r = innerRadius + l * dr;
664 glBegin( GL_LINE_LOOP );
665 for (s=0; s<slices; s++) {
666 GLfloat a = s * da;
667 glVertex2f( r*sin(a), r*cos(a) );
668 }
669 glEnd();
670 }
671 /* draw spokes */
672 for (s=0; s<slices; s++) {
673 GLfloat a = s * da;
674 GLfloat x = sin(a);
675 GLfloat y = cos(a);
676 glBegin( GL_LINE_STRIP );
677 for (l=0; l<=loops; l++) {
678 GLfloat r = innerRadius + l * dr;
679 glVertex2f( r*x, r*y );
680 }
681 glEnd();
682 }
683 break;
684 }
685 case GLU_POINT:
686 {
687 GLint s;
688 glBegin( GL_POINTS );
689 for (s=0; s<slices; s++) {
690 GLfloat a = s * da;
691 GLfloat x = sin(a);
692 GLfloat y = cos(a);
693 GLint l;
694 for (l=0; l<=loops; l++) {
695 GLfloat r = innerRadius * l * dr;
696 glVertex2f( r*x, r*y );
697 }
698 }
699 glEnd();
700 break;
701 }
702 case GLU_SILHOUETTE:
703 {
704 if (innerRadius!=0.0) {
705 GLfloat a;
706 glBegin( GL_LINE_LOOP );
707 for (a=0.0; a<2.0*M_PI; a+=da) {
708 GLfloat x = innerRadius * sin(a);
709 GLfloat y = innerRadius * cos(a);
710 glVertex2f( x, y );
711 }
712 glEnd();
713 }
714 {
715 GLfloat a;
716 glBegin( GL_LINE_LOOP );
717 for (a=0; a<2.0*M_PI; a+=da) {
718 GLfloat x = outerRadius * sin(a);
719 GLfloat y = outerRadius * cos(a);
720 glVertex2f( x, y );
721 }
722 glEnd();
723 }
724 break;
725 }
726 default:
727 abort();
728 }
729 }
730
731
732
733 void GLAPIENTRY gluPartialDisk( GLUquadricObj *qobj, GLdouble innerRadius,
734 GLdouble outerRadius, GLint slices, GLint loops,
735 GLdouble startAngle, GLdouble sweepAngle )
736 {
737 if (qobj->Normals!=GLU_NONE) {
738 if (qobj->Orientation==GLU_OUTSIDE) {
739 glNormal3f( 0.0, 0.0, +1.0 );
740 }
741 else {
742 glNormal3f( 0.0, 0.0, -1.0 );
743 }
744 }
745
746 if (qobj->DrawStyle==GLU_POINT) {
747 GLint loop, slice;
748 GLdouble radius, delta_radius;
749 GLdouble angle, delta_angle;
750 delta_radius = (outerRadius - innerRadius) / (loops-1);
751 delta_angle = DEG_TO_RAD((sweepAngle) / (slices-1));
752 glBegin( GL_POINTS );
753 radius = innerRadius;
754 for (loop=0; loop<loops; loop++) {
755 angle = DEG_TO_RAD(startAngle);
756 for (slice=0; slice<slices; slice++) {
757 glVertex2d( radius * sin(angle), radius * cos(angle) );
758 angle += delta_angle;
759 }
760 radius += delta_radius;
761 }
762 glEnd();
763 }
764 else if (qobj->DrawStyle==GLU_LINE) {
765 GLint loop, slice;
766 GLdouble radius, delta_radius;
767 GLdouble angle, delta_angle;
768 delta_radius = (outerRadius - innerRadius) / loops;
769 delta_angle = DEG_TO_RAD(sweepAngle / slices);
770 /* draw rings */
771 radius = innerRadius;
772 for (loop=0; loop<loops; loop++) {
773 angle = DEG_TO_RAD(startAngle);
774 glBegin( GL_LINE_STRIP );
775 for (slice=0; slice<slices; slice++) {
776 glVertex2d( radius * sin(angle), radius * cos(angle) );
777 angle += delta_angle;
778 }
779 glEnd();
780 radius += delta_radius;
781 }
782 /* draw spokes */
783 angle = DEG_TO_RAD(startAngle);
784 for (slice=0; slice<slices; slice++) {
785 radius = innerRadius;
786 glBegin( GL_LINE_STRIP );
787 for (loop=0; loop<loops; loop++) {
788 glVertex2d( radius * sin(angle), radius * cos(angle) );
789 radius += delta_radius;
790 }
791 glEnd();
792 angle += delta_angle;
793 }
794 }
795 else if (qobj->DrawStyle==GLU_SILHOUETTE) {
796 GLint slice;
797 GLdouble angle, delta_angle;
798 delta_angle = DEG_TO_RAD(sweepAngle / slices);
799 /* draw outer ring */
800 glBegin( GL_LINE_STRIP );
801 angle = DEG_TO_RAD(startAngle);
802 for (slice=0; slice<=slices; slice++) {
803 glVertex2d( outerRadius * sin(angle), outerRadius * cos(angle) );
804 angle += delta_angle;
805 }
806 glEnd();
807 /* draw inner ring */
808 if (innerRadius>0.0) {
809 glBegin( GL_LINE_STRIP );
810 angle = DEG_TO_RAD(startAngle);
811 for (slice=0; slice<slices; slice++) {
812 glVertex2d( innerRadius * sin(angle), innerRadius * cos(angle) );
813 angle += delta_angle;
814 }
815 glEnd();
816 }
817 /* draw spokes */
818 if (sweepAngle<360.0) {
819 GLdouble stopAngle = startAngle + sweepAngle;
820 glBegin( GL_LINES );
821 glVertex2d( innerRadius*SIND(startAngle), innerRadius*COSD(startAngle) );
822 glVertex2d( outerRadius*SIND(startAngle), outerRadius*COSD(startAngle) );
823 glVertex2d( innerRadius*SIND(stopAngle), innerRadius*COSD(stopAngle) );
824 glVertex2d( outerRadius*SIND(stopAngle), outerRadius*COSD(stopAngle) );
825 glEnd();
826 }
827 }
828 else if (qobj->DrawStyle==GLU_FILL) {
829 GLint loop, slice;
830 GLdouble radius, delta_radius;
831 GLdouble angle, delta_angle;
832 delta_radius = (outerRadius - innerRadius) / loops;
833 delta_angle = DEG_TO_RAD(sweepAngle / slices);
834 radius = innerRadius;
835 for (loop=0; loop<loops; loop++) {
836 glBegin( GL_QUAD_STRIP );
837 angle = DEG_TO_RAD(startAngle);
838 for (slice=0; slice<slices; slice++) {
839 if (qobj->Orientation==GLU_OUTSIDE) {
840 glVertex2d( (radius+delta_radius)*sin(angle),
841 (radius+delta_radius)*cos(angle) );
842 glVertex2d( radius * sin(angle), radius * cos(angle) );
843 }
844 else {
845 glVertex2d( radius * sin(angle), radius * cos(angle) );
846 glVertex2d( (radius+delta_radius)*sin(angle),
847 (radius+delta_radius)*cos(angle) );
848 }
849 angle += delta_angle;
850 }
851 glEnd();
852 radius += delta_radius;
853 }
854 }
855 }
856
857
858