1 /* $Id: quadric.c,v 1.5 2000/01/11 17:21:14 brianp Exp $ */
4 * Mesa 3-D graphics library
6 * Copyright (C) 1999-2000 Brian Paul
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.
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.
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.
25 * texture coordinate support
26 * flip normals according to orientation
27 * there's still some inside/outside orientation bugs in possibly all
28 * but the sphere function
39 #include "tess_macros.h"
45 * Sin and Cos for degree angles:
47 #define SIND( A ) sin( (A)*(M_PI/180.0) )
48 #define COSD( A) cos( (A)*(M_PI/180.0) )
52 * Texture coordinates if texture flag is set
54 #define TXTR_COORD(x,y) if (qobj->TextureFlag) glTexCoord2f(x,y);
59 GLenum DrawStyle
; /* GLU_FILL, LINE, SILHOUETTE, or POINT */
60 GLenum Orientation
; /* GLU_INSIDE or GLU_OUTSIDE */
61 GLboolean TextureFlag
; /* Generate texture coords? */
62 GLenum Normals
; /* GLU_NONE, GLU_FLAT, or GLU_SMOOTH */
63 void (GLCALLBACKP ErrorFunc
)(GLenum err
); /* Error handler callback function */
69 * Process a GLU error.
71 static void quadric_error( GLUquadricObj
*qobj
, GLenum error
, const char *msg
)
73 /* Call the error call back function if any */
74 if (qobj
->ErrorFunc
) {
75 (*qobj
->ErrorFunc
)( error
);
77 /* Print a message to stdout if MESA_DEBUG variable is defined */
78 if (getenv("MESA_DEBUG")) {
79 fprintf(stderr
,"GLUError: %s: %s\n", (char*) gluErrorString(error
), msg
);
86 GLUquadricObj
* GLAPIENTRY
gluNewQuadric( void )
90 q
= (GLUquadricObj
*) malloc( sizeof(struct GLUquadric
) );
92 q
->DrawStyle
= GLU_FILL
;
93 q
->Orientation
= GLU_OUTSIDE
;
94 q
->TextureFlag
= GL_FALSE
;
95 q
->Normals
= GLU_SMOOTH
;
103 void GLAPIENTRY
gluDeleteQuadric( GLUquadricObj
*state
)
106 free( (void *) state
);
113 * Set the drawing style to be GLU_FILL, GLU_LINE, GLU_SILHOUETTE,
116 void GLAPIENTRY
gluQuadricDrawStyle( GLUquadricObj
*quadObject
, GLenum drawStyle
)
118 if (quadObject
&& (drawStyle
==GLU_FILL
|| drawStyle
==GLU_LINE
119 || drawStyle
==GLU_SILHOUETTE
|| drawStyle
==GLU_POINT
)) {
120 quadObject
->DrawStyle
= drawStyle
;
123 quadric_error( quadObject
, GLU_INVALID_ENUM
, "qluQuadricDrawStyle" );
130 * Set the orientation to GLU_INSIDE or GLU_OUTSIDE.
132 void GLAPIENTRY
gluQuadricOrientation( GLUquadricObj
*quadObject
,
135 if (quadObject
&& (orientation
==GLU_INSIDE
|| orientation
==GLU_OUTSIDE
)) {
136 quadObject
->Orientation
= orientation
;
139 quadric_error( quadObject
, GLU_INVALID_ENUM
, "qluQuadricOrientation" );
146 * Set the error handler callback function.
148 void GLAPIENTRY
gluQuadricCallback( GLUquadricObj
*qobj
,
149 GLenum which
, void (GLCALLBACKP fn
)() )
152 * UGH, this is a mess! I thought ANSI was a standard.
154 if (qobj
&& which
==GLU_ERROR
) {
156 qobj
->ErrorFunc
= (void(*)(int))fn
;
157 #elif defined(OPENSTEP)
158 qobj
->ErrorFunc
= (void(*)(GLenum
))fn
;
159 #elif defined(_WIN32)
160 qobj
->ErrorFunc
= (void(GLCALLBACKP
)(int))fn
;
161 #elif defined(__STORM__)
162 qobj
->ErrorFunc
= (void(GLCALLBACKP
)(GLenum
))fn
;
163 #elif defined(__BEOS__)
164 qobj
->ErrorFunc
= (void(*)(GLenum
))fn
;
166 qobj
->ErrorFunc
= (void(GLCALLBACKP
)())fn
;
172 void GLAPIENTRY
gluQuadricNormals( GLUquadricObj
*quadObject
, GLenum normals
)
175 && (normals
==GLU_NONE
|| normals
==GLU_FLAT
|| normals
==GLU_SMOOTH
)) {
176 quadObject
->Normals
= normals
;
181 void GLAPIENTRY
gluQuadricTexture( GLUquadricObj
*quadObject
,
182 GLboolean textureCoords
)
185 quadObject
->TextureFlag
= textureCoords
;
193 * Call glNormal3f after scaling normal to unit length.
195 static void normal3f( GLfloat x
, GLfloat y
, GLfloat z
)
199 mag
= sqrt( x
*x
+ y
*y
+ z
*z
);
205 glNormal3f( x
, y
, z
);
210 void GLAPIENTRY
gluCylinder( GLUquadricObj
*qobj
,
211 GLdouble baseRadius
, GLdouble topRadius
,
212 GLdouble height
, GLint slices
, GLint stacks
)
214 GLdouble da
, r
, dr
, dz
;
215 GLfloat x
, y
, z
, nz
, nsign
;
218 if (qobj
->Orientation
==GLU_INSIDE
) {
225 da
= 2.0*M_PI
/ slices
;
226 dr
= (topRadius
-baseRadius
) / stacks
;
227 dz
= height
/ stacks
;
228 nz
= (baseRadius
-topRadius
) / height
; /* Z component of normal vectors */
230 if (qobj
->DrawStyle
==GLU_POINT
) {
231 glBegin( GL_POINTS
);
232 for (i
=0;i
<slices
;i
++) {
235 normal3f( x
*nsign
, y
*nsign
, nz
*nsign
);
239 for (j
=0;j
<=stacks
;j
++) {
240 glVertex3f( x
*r
, y
*r
, z
);
247 else if (qobj
->DrawStyle
==GLU_LINE
|| qobj
->DrawStyle
==GLU_SILHOUETTE
) {
249 if (qobj
->DrawStyle
==GLU_LINE
) {
252 for (j
=0;j
<=stacks
;j
++) {
253 glBegin( GL_LINE_LOOP
);
254 for (i
=0;i
<slices
;i
++) {
257 normal3f( x
*nsign
, y
*nsign
, nz
*nsign
);
258 glVertex3f( x
*r
, y
*r
, z
);
266 /* draw one ring at each end */
267 if (baseRadius
!=0.0) {
268 glBegin( GL_LINE_LOOP
);
269 for (i
=0;i
<slices
;i
++) {
272 normal3f( x
*nsign
, y
*nsign
, nz
*nsign
);
273 glVertex3f( x
*baseRadius
, y
*baseRadius
, 0.0 );
276 glBegin( GL_LINE_LOOP
);
277 for (i
=0;i
<slices
;i
++) {
280 normal3f( x
*nsign
, y
*nsign
, nz
*nsign
);
281 glVertex3f( x
*topRadius
, y
*topRadius
, height
);
286 /* draw length lines */
288 for (i
=0;i
<slices
;i
++) {
291 normal3f( x
*nsign
, y
*nsign
, nz
*nsign
);
292 glVertex3f( x
*baseRadius
, y
*baseRadius
, 0.0 );
293 glVertex3f( x
*topRadius
, y
*topRadius
, height
);
297 else if (qobj
->DrawStyle
==GLU_FILL
) {
298 GLfloat ds
= 1.0 / slices
;
299 GLfloat dt
= 1.0 / stacks
;
303 for (j
=0;j
<stacks
;j
++) {
305 glBegin( GL_QUAD_STRIP
);
306 for (i
=0;i
<=slices
;i
++) {
317 normal3f( x
*nsign
, y
*nsign
, nz
*nsign
);
319 glVertex3f( x
* r
, y
* r
, z
);
320 normal3f( x
*nsign
, y
*nsign
, nz
*nsign
);
321 TXTR_COORD(s
, t
+ dt
);
322 glVertex3f( x
* (r
+ dr
), y
* (r
+ dr
), z
+ dz
);
325 normal3f( x
*nsign
, y
*nsign
, nz
*nsign
);
327 glVertex3f( x
* r
, y
* r
, z
);
328 normal3f( x
*nsign
, y
*nsign
, nz
*nsign
);
329 TXTR_COORD(s
, t
+ dt
);
330 glVertex3f( x
* (r
+ dr
), y
* (r
+ dr
), z
+ dz
);
346 void GLAPIENTRY
gluSphere( GLUquadricObj
*qobj
,
347 GLdouble radius
, GLint slices
, GLint stacks
)
349 GLfloat rho
, drho
, theta
, dtheta
;
351 GLfloat s
, t
, ds
, dt
;
352 GLint i
, j
, imin
, imax
;
356 if (qobj
->Normals
==GLU_NONE
) {
362 if (qobj
->Orientation
==GLU_INSIDE
) {
369 drho
= M_PI
/ (GLfloat
) stacks
;
370 dtheta
= 2.0 * M_PI
/ (GLfloat
) slices
;
372 /* texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis */
373 /* t goes from -1.0/+1.0 at z = -radius/+radius (linear along longitudes) */
374 /* cannot use triangle fan on texturing (s coord. at top/bottom tip varies) */
376 if (qobj
->DrawStyle
==GLU_FILL
) {
377 if (!qobj
->TextureFlag
) {
378 /* draw +Z end as a triangle fan */
379 glBegin( GL_TRIANGLE_FAN
);
380 glNormal3f( 0.0, 0.0, 1.0 );
382 glVertex3f( 0.0, 0.0, nsign
* radius
);
383 for (j
=0;j
<=slices
;j
++) {
384 theta
= (j
==slices
) ? 0.0 : j
* dtheta
;
385 x
= -sin(theta
) * sin(drho
);
386 y
= cos(theta
) * sin(drho
);
387 z
= nsign
* cos(drho
);
388 if (normals
) glNormal3f( x
*nsign
, y
*nsign
, z
*nsign
);
389 glVertex3f( x
*radius
, y
*radius
, z
*radius
);
396 t
= 1.0; /* because loop now runs from 0 */
397 if (qobj
->TextureFlag
) {
406 /* draw intermediate stacks as quad strips */
407 for (i
=imin
;i
<imax
;i
++) {
409 glBegin( GL_QUAD_STRIP
);
411 for (j
=0;j
<=slices
;j
++) {
412 theta
= (j
==slices
) ? 0.0 : j
* dtheta
;
413 x
= -sin(theta
) * sin(rho
);
414 y
= cos(theta
) * sin(rho
);
415 z
= nsign
* cos(rho
);
416 if (normals
) glNormal3f( x
*nsign
, y
*nsign
, z
*nsign
);
418 glVertex3f( x
*radius
, y
*radius
, z
*radius
);
419 x
= -sin(theta
) * sin(rho
+drho
);
420 y
= cos(theta
) * sin(rho
+drho
);
421 z
= nsign
* cos(rho
+drho
);
422 if (normals
) glNormal3f( x
*nsign
, y
*nsign
, z
*nsign
);
425 glVertex3f( x
*radius
, y
*radius
, z
*radius
);
431 if (!qobj
->TextureFlag
) {
432 /* draw -Z end as a triangle fan */
433 glBegin( GL_TRIANGLE_FAN
);
434 glNormal3f( 0.0, 0.0, -1.0 );
436 glVertex3f( 0.0, 0.0, -radius
*nsign
);
440 for (j
=slices
;j
>=0;j
--) {
441 theta
= (j
==slices
) ? 0.0 : j
* dtheta
;
442 x
= -sin(theta
) * sin(rho
);
443 y
= cos(theta
) * sin(rho
);
444 z
= nsign
* cos(rho
);
445 if (normals
) glNormal3f( x
*nsign
, y
*nsign
, z
*nsign
);
448 glVertex3f( x
*radius
, y
*radius
, z
*radius
);
453 else if (qobj
->DrawStyle
==GLU_LINE
|| qobj
->DrawStyle
==GLU_SILHOUETTE
) {
454 /* draw stack lines */
455 for (i
=1;i
<stacks
;i
++) { /* stack line at i==stacks-1 was missing here */
457 glBegin( GL_LINE_LOOP
);
458 for (j
=0;j
<slices
;j
++) {
460 x
= cos(theta
) * sin(rho
);
461 y
= sin(theta
) * sin(rho
);
463 if (normals
) glNormal3f( x
*nsign
, y
*nsign
, z
*nsign
);
464 glVertex3f( x
*radius
, y
*radius
, z
*radius
);
468 /* draw slice lines */
469 for (j
=0;j
<slices
;j
++) {
471 glBegin( GL_LINE_STRIP
);
472 for (i
=0;i
<=stacks
;i
++) {
474 x
= cos(theta
) * sin(rho
);
475 y
= sin(theta
) * sin(rho
);
477 if (normals
) glNormal3f( x
*nsign
, y
*nsign
, z
*nsign
);
478 glVertex3f( x
*radius
, y
*radius
, z
*radius
);
483 else if (qobj
->DrawStyle
==GLU_POINT
) {
484 /* top and bottom-most points */
485 glBegin( GL_POINTS
);
486 if (normals
) glNormal3f( 0.0, 0.0, nsign
);
487 glVertex3d( 0.0, 0.0, radius
);
488 if (normals
) glNormal3f( 0.0, 0.0, -nsign
);
489 glVertex3d( 0.0, 0.0, -radius
);
491 /* loop over stacks */
492 for (i
=1;i
<stacks
-1;i
++) {
494 for (j
=0;j
<slices
;j
++) {
496 x
= cos(theta
) * sin(rho
);
497 y
= sin(theta
) * sin(rho
);
499 if (normals
) glNormal3f( x
*nsign
, y
*nsign
, z
*nsign
);
500 glVertex3f( x
*radius
, y
*radius
, z
*radius
);
510 void GLAPIENTRY
gluDisk( GLUquadricObj
*qobj
,
511 GLdouble innerRadius
, GLdouble outerRadius
,
512 GLint slices
, GLint loops
)
524 if (qobj
->Normals
!=GLU_NONE
) {
525 if (qobj
->Orientation
==GLU_OUTSIDE
) {
526 glNormal3f( 0.0, 0.0, +1.0 );
529 glNormal3f( 0.0, 0.0, -1.0 );
533 da
= 2.0*M_PI
/ slices
;
534 dr
= (outerRadius
-innerRadius
) / (GLfloat
) loops
;
536 switch (qobj
->DrawStyle
) {
539 /* texture of a gluDisk is a cut out of the texture unit square
540 * x, y in [-outerRadius, +outerRadius]; s, t in [0, 1]
543 GLfloat dtc
= 2.0f
* outerRadius
;
545 GLfloat r1
= innerRadius
;
547 for (l
=0; l
<loops
; l
++) {
548 GLfloat r2
= r1
+ dr
;
549 if (qobj
->Orientation
==GLU_OUTSIDE
) {
551 glBegin( GL_QUAD_STRIP
);
552 for (s
=0;s
<=slices
;s
++) {
554 if (s
==slices
) a
= 0.0;
556 sa
= sin(a
); ca
= cos(a
);
557 TXTR_COORD(0.5+sa
*r2
/dtc
,0.5+ca
*r2
/dtc
);
558 glVertex2f( r2
*sa
, r2
*ca
);
559 TXTR_COORD(0.5+sa
*r1
/dtc
,0.5+ca
*r1
/dtc
);
560 glVertex2f( r1
*sa
, r1
*ca
);
566 glBegin( GL_QUAD_STRIP
);
567 for (s
=slices
;s
>=0;s
--) {
569 if (s
==slices
) a
= 0.0;
571 sa
= sin(a
); ca
= cos(a
);
572 TXTR_COORD(0.5-sa
*r2
/dtc
,0.5+ca
*r2
/dtc
);
573 glVertex2f( r2
*sa
, r2
*ca
);
574 TXTR_COORD(0.5-sa
*r1
/dtc
,0.5+ca
*r1
/dtc
);
575 glVertex2f( r1
*sa
, r1
*ca
);
587 for (l
=0; l
<=loops
; l
++) {
588 GLfloat r
= innerRadius
+ l
* dr
;
589 glBegin( GL_LINE_LOOP
);
590 for (s
=0; s
<slices
; s
++) {
592 glVertex2f( r
*sin(a
), r
*cos(a
) );
597 for (s
=0; s
<slices
; s
++) {
601 glBegin( GL_LINE_STRIP
);
602 for (l
=0; l
<=loops
; l
++) {
603 GLfloat r
= innerRadius
+ l
* dr
;
604 glVertex2f( r
*x
, r
*y
);
613 glBegin( GL_POINTS
);
614 for (s
=0; s
<slices
; s
++) {
619 for (l
=0; l
<=loops
; l
++) {
620 GLfloat r
= innerRadius
* l
* dr
;
621 glVertex2f( r
*x
, r
*y
);
629 if (innerRadius
!=0.0) {
631 glBegin( GL_LINE_LOOP
);
632 for (a
=0.0; a
<2.0*M_PI
; a
+=da
) {
633 GLfloat x
= innerRadius
* sin(a
);
634 GLfloat y
= innerRadius
* cos(a
);
641 glBegin( GL_LINE_LOOP
);
642 for (a
=0; a
<2.0*M_PI
; a
+=da
) {
643 GLfloat x
= outerRadius
* sin(a
);
644 GLfloat y
= outerRadius
* cos(a
);
658 void GLAPIENTRY
gluPartialDisk( GLUquadricObj
*qobj
, GLdouble innerRadius
,
659 GLdouble outerRadius
, GLint slices
, GLint loops
,
660 GLdouble startAngle
, GLdouble sweepAngle
)
662 if (qobj
->Normals
!=GLU_NONE
) {
663 if (qobj
->Orientation
==GLU_OUTSIDE
) {
664 glNormal3f( 0.0, 0.0, +1.0 );
667 glNormal3f( 0.0, 0.0, -1.0 );
671 if (qobj
->DrawStyle
==GLU_POINT
) {
673 GLdouble radius
, delta_radius
;
674 GLdouble angle
, delta_angle
;
675 delta_radius
= (outerRadius
- innerRadius
) / (loops
-1);
676 delta_angle
= DEG_TO_RAD((sweepAngle
) / (slices
-1));
677 glBegin( GL_POINTS
);
678 radius
= innerRadius
;
679 for (loop
=0; loop
<loops
; loop
++) {
680 angle
= DEG_TO_RAD(startAngle
);
681 for (slice
=0; slice
<slices
; slice
++) {
682 glVertex2d( radius
* sin(angle
), radius
* cos(angle
) );
683 angle
+= delta_angle
;
685 radius
+= delta_radius
;
689 else if (qobj
->DrawStyle
==GLU_LINE
) {
691 GLdouble radius
, delta_radius
;
692 GLdouble angle
, delta_angle
;
693 delta_radius
= (outerRadius
- innerRadius
) / loops
;
694 delta_angle
= DEG_TO_RAD(sweepAngle
/ slices
);
696 radius
= innerRadius
;
697 for (loop
=0; loop
<loops
; loop
++) {
698 angle
= DEG_TO_RAD(startAngle
);
699 glBegin( GL_LINE_STRIP
);
700 for (slice
=0; slice
<=slices
; slice
++) {
701 glVertex2d( radius
* sin(angle
), radius
* cos(angle
) );
702 angle
+= delta_angle
;
705 radius
+= delta_radius
;
708 angle
= DEG_TO_RAD(startAngle
);
709 for (slice
=0; slice
<slices
; slice
++) {
710 radius
= innerRadius
;
711 glBegin( GL_LINE_STRIP
);
712 for (loop
=0; loop
<loops
; loop
++) {
713 glVertex2d( radius
* sin(angle
), radius
* cos(angle
) );
714 radius
+= delta_radius
;
717 angle
+= delta_angle
;
720 else if (qobj
->DrawStyle
==GLU_SILHOUETTE
) {
722 GLdouble angle
, delta_angle
;
723 delta_angle
= DEG_TO_RAD(sweepAngle
/ slices
);
724 /* draw outer ring */
725 glBegin( GL_LINE_STRIP
);
726 angle
= DEG_TO_RAD(startAngle
);
727 for (slice
=0; slice
<=slices
; slice
++) {
728 glVertex2d( outerRadius
* sin(angle
), outerRadius
* cos(angle
) );
729 angle
+= delta_angle
;
732 /* draw inner ring */
733 if (innerRadius
>0.0) {
734 glBegin( GL_LINE_STRIP
);
735 angle
= DEG_TO_RAD(startAngle
);
736 for (slice
=0; slice
<slices
; slice
++) {
737 glVertex2d( innerRadius
* sin(angle
), innerRadius
* cos(angle
) );
738 angle
+= delta_angle
;
743 if (sweepAngle
<360.0) {
744 GLdouble stopAngle
= startAngle
+ sweepAngle
;
746 glVertex2d( innerRadius
*SIND(startAngle
), innerRadius
*COSD(startAngle
) );
747 glVertex2d( outerRadius
*SIND(startAngle
), outerRadius
*COSD(startAngle
) );
748 glVertex2d( innerRadius
*SIND(stopAngle
), innerRadius
*COSD(stopAngle
) );
749 glVertex2d( outerRadius
*SIND(stopAngle
), outerRadius
*COSD(stopAngle
) );
753 else if (qobj
->DrawStyle
==GLU_FILL
) {
755 GLdouble radius
, delta_radius
;
756 GLdouble angle
, delta_angle
;
757 delta_radius
= (outerRadius
- innerRadius
) / loops
;
758 delta_angle
= DEG_TO_RAD(sweepAngle
/ slices
);
759 radius
= innerRadius
;
760 for (loop
=0; loop
<loops
; loop
++) {
761 glBegin( GL_QUAD_STRIP
);
762 angle
= DEG_TO_RAD(startAngle
);
763 for (slice
=0; slice
<=slices
; slice
++) {
764 if (qobj
->Orientation
==GLU_OUTSIDE
) {
765 glVertex2d( (radius
+delta_radius
)*sin(angle
),
766 (radius
+delta_radius
)*cos(angle
) );
767 glVertex2d( radius
* sin(angle
), radius
* cos(angle
) );
770 glVertex2d( radius
* sin(angle
), radius
* cos(angle
) );
771 glVertex2d( (radius
+delta_radius
)*sin(angle
),
772 (radius
+delta_radius
)*cos(angle
) );
774 angle
+= delta_angle
;
777 radius
+= delta_radius
;