1 /* $Id: quadric.c,v 1.2 2003/08/22 20:11:43 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
44 # define M_PI (3.1415926)
49 * Convert degrees to radians:
51 #define DEG_TO_RAD(A) ((A)*(M_PI/180.0))
55 * Sin and Cos for degree angles:
57 #define SIND( A ) sin( (A)*(M_PI/180.0) )
58 #define COSD( A) cos( (A)*(M_PI/180.0) )
62 * Texture coordinates if texture flag is set
64 #define TXTR_COORD(x,y) if (qobj->TextureFlag) glTexCoord2f(x,y);
70 GLenum DrawStyle
; /* GLU_FILL, LINE, SILHOUETTE, or POINT */
71 GLenum Orientation
; /* GLU_INSIDE or GLU_OUTSIDE */
72 GLboolean TextureFlag
; /* Generate texture coords? */
73 GLenum Normals
; /* GLU_NONE, GLU_FLAT, or GLU_SMOOTH */
74 void (GLCALLBACK
* ErrorFunc
) (GLenum err
); /* Error handler callback function */
80 * Process a GLU error.
83 quadric_error(GLUquadricObj
* qobj
, GLenum error
, const char *msg
)
85 /* Call the error call back function if any */
86 if (qobj
->ErrorFunc
) {
87 (*qobj
->ErrorFunc
) (error
);
89 /* Print a message to stdout if MESA_DEBUG variable is defined */
90 if (getenv("MESA_DEBUG")) {
91 fprintf(stderr
, "GLUError: %s: %s\n", (char *) gluErrorString(error
),
99 GLUquadricObj
*GLAPIENTRY
104 q
= (GLUquadricObj
*) malloc(sizeof(struct GLUquadric
));
106 q
->DrawStyle
= GLU_FILL
;
107 q
->Orientation
= GLU_OUTSIDE
;
108 q
->TextureFlag
= GL_FALSE
;
109 q
->Normals
= GLU_SMOOTH
;
118 gluDeleteQuadric(GLUquadricObj
* state
)
121 free((void *) state
);
128 * Set the drawing style to be GLU_FILL, GLU_LINE, GLU_SILHOUETTE,
132 gluQuadricDrawStyle(GLUquadricObj
* quadObject
, GLenum drawStyle
)
134 if (quadObject
&& (drawStyle
== GLU_FILL
|| drawStyle
== GLU_LINE
135 || drawStyle
== GLU_SILHOUETTE
136 || drawStyle
== GLU_POINT
)) {
137 quadObject
->DrawStyle
= drawStyle
;
140 quadric_error(quadObject
, GLU_INVALID_ENUM
, "qluQuadricDrawStyle");
147 * Set the orientation to GLU_INSIDE or GLU_OUTSIDE.
150 gluQuadricOrientation(GLUquadricObj
* quadObject
, GLenum orientation
)
153 && (orientation
== GLU_INSIDE
|| orientation
== GLU_OUTSIDE
)) {
154 quadObject
->Orientation
= orientation
;
157 quadric_error(quadObject
, GLU_INVALID_ENUM
, "qluQuadricOrientation");
164 * Set the error handler callback function.
167 gluQuadricCallback(GLUquadricObj
* qobj
,
168 GLenum which
, void (GLCALLBACK
* fn
) ())
171 * UGH, this is a mess! I thought ANSI was a standard.
173 if (qobj
&& which
== GLU_ERROR
) {
175 qobj
->ErrorFunc
= (void (GLCALLBACKPCAST
) (GLenum
)) fn
;
176 #elif defined(OPENSTEP)
177 qobj
->ErrorFunc
= (void (*)(GLenum
)) fn
;
178 #elif defined(_WIN32)
179 qobj
->ErrorFunc
= (void (GLCALLBACK
*) (int)) fn
;
180 #elif defined(__STORM__)
181 qobj
->ErrorFunc
= (void (GLCALLBACK
*) (GLenum
)) fn
;
182 #elif defined(__BEOS__)
183 qobj
->ErrorFunc
= (void (*)(GLenum
)) fn
;
185 qobj
->ErrorFunc
= (void (GLCALLBACK
*) ()) fn
;
192 gluQuadricNormals(GLUquadricObj
* quadObject
, GLenum normals
)
195 && (normals
== GLU_NONE
|| normals
== GLU_FLAT
196 || normals
== GLU_SMOOTH
)) {
197 quadObject
->Normals
= normals
;
203 gluQuadricTexture(GLUquadricObj
* quadObject
, GLboolean textureCoords
)
206 quadObject
->TextureFlag
= textureCoords
;
214 * Call glNormal3f after scaling normal to unit length.
217 normal3f(GLfloat x
, GLfloat y
, GLfloat z
)
224 gluCylinder(GLUquadricObj
* qobj
,
225 GLdouble baseRadius
, GLdouble topRadius
,
226 GLdouble height
, GLint slices
, GLint stacks
)
228 GLdouble da
, r
, dr
, dz
;
229 GLfloat x
, y
, z
, nz
, nsign
;
232 if (qobj
->Orientation
== GLU_INSIDE
) {
239 da
= 2.0 * M_PI
/ slices
;
240 dr
= (topRadius
- baseRadius
) / stacks
;
241 dz
= height
/ stacks
;
242 nz
= (baseRadius
- topRadius
) / height
; /* Z component of normal vectors */
244 if (qobj
->DrawStyle
== GLU_POINT
) {
246 for (i
= 0; i
< slices
; i
++) {
249 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
253 for (j
= 0; j
<= stacks
; j
++) {
254 glVertex3f(x
* r
, y
* r
, z
);
261 else if (qobj
->DrawStyle
== GLU_LINE
|| qobj
->DrawStyle
== GLU_SILHOUETTE
) {
263 if (qobj
->DrawStyle
== GLU_LINE
) {
266 for (j
= 0; j
<= stacks
; j
++) {
267 glBegin(GL_LINE_LOOP
);
268 for (i
= 0; i
< slices
; i
++) {
271 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
272 glVertex3f(x
* r
, y
* r
, z
);
280 /* draw one ring at each end */
281 if (baseRadius
!= 0.0) {
282 glBegin(GL_LINE_LOOP
);
283 for (i
= 0; i
< slices
; i
++) {
286 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
287 glVertex3f(x
* baseRadius
, y
* baseRadius
, 0.0);
290 glBegin(GL_LINE_LOOP
);
291 for (i
= 0; i
< slices
; i
++) {
294 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
295 glVertex3f(x
* topRadius
, y
* topRadius
, height
);
300 /* draw length lines */
302 for (i
= 0; i
< slices
; i
++) {
305 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
306 glVertex3f(x
* baseRadius
, y
* baseRadius
, 0.0);
307 glVertex3f(x
* topRadius
, y
* topRadius
, height
);
311 else if (qobj
->DrawStyle
== GLU_FILL
) {
312 GLfloat ds
= 1.0 / slices
;
313 GLfloat dt
= 1.0 / stacks
;
317 for (j
= 0; j
< stacks
; j
++) {
319 glBegin(GL_QUAD_STRIP
);
320 for (i
= 0; i
<= slices
; i
++) {
331 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
333 glVertex3f(x
* r
, y
* r
, z
);
334 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
335 TXTR_COORD(s
, t
+ dt
);
336 glVertex3f(x
* (r
+ dr
), y
* (r
+ dr
), z
+ dz
);
339 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
341 glVertex3f(x
* r
, y
* r
, z
);
342 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
343 TXTR_COORD(s
, t
+ dt
);
344 glVertex3f(x
* (r
+ dr
), y
* (r
+ dr
), z
+ dz
);
361 gluSphere(GLUquadricObj
* qobj
, GLdouble radius
, GLint slices
, GLint stacks
)
363 GLfloat rho
, drho
, theta
, dtheta
;
365 GLfloat s
, t
, ds
, dt
;
366 GLint i
, j
, imin
, imax
;
370 if (qobj
->Normals
== GLU_NONE
) {
376 if (qobj
->Orientation
== GLU_INSIDE
) {
383 drho
= M_PI
/ (GLfloat
) stacks
;
384 dtheta
= 2.0 * M_PI
/ (GLfloat
) slices
;
386 /* texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis */
387 /* t goes from -1.0/+1.0 at z = -radius/+radius (linear along longitudes) */
388 /* cannot use triangle fan on texturing (s coord. at top/bottom tip varies) */
390 if (qobj
->DrawStyle
== GLU_FILL
) {
391 if (!qobj
->TextureFlag
) {
392 /* draw +Z end as a triangle fan */
393 glBegin(GL_TRIANGLE_FAN
);
394 /* glNormal3f(0.0, 0.0, 1.0); */
395 glVertex3f(0.0, 0.0, nsign
* radius
);
396 for (j
= 0; j
<= slices
; j
++) {
397 theta
= (j
== slices
) ? 0.0 : j
* dtheta
;
398 x
= -sin(theta
) * sin(drho
);
399 y
= cos(theta
) * sin(drho
);
400 z
= nsign
* cos(drho
);
401 glVertex3f(x
* radius
, y
* radius
, z
* radius
);
408 t
= 1.0; /* because loop now runs from 0 */
409 if (qobj
->TextureFlag
) {
418 /* draw intermediate stacks as quad strips */
419 for (i
= imin
; i
< imax
; i
++) {
421 glBegin(GL_QUAD_STRIP
);
423 for (j
= 0; j
<= slices
; j
++) {
424 theta
= (j
== slices
) ? 0.0 : j
* dtheta
;
425 x
= -sin(theta
) * sin(rho
);
426 y
= cos(theta
) * sin(rho
);
427 z
= nsign
* cos(rho
);
429 glVertex3f(x
* radius
, y
* radius
, z
* radius
);
430 x
= -sin(theta
) * sin(rho
+ drho
);
431 y
= cos(theta
) * sin(rho
+ drho
);
432 z
= nsign
* cos(rho
+ drho
);
433 TXTR_COORD(s
, t
- dt
);
435 glVertex3f(x
* radius
, y
* radius
, z
* radius
);
441 if (!qobj
->TextureFlag
) {
442 /* draw -Z end as a triangle fan */
443 glBegin(GL_TRIANGLE_FAN
);
444 glVertex3f(0.0, 0.0, -radius
* nsign
);
448 for (j
= slices
; j
>= 0; j
--) {
449 theta
= (j
== slices
) ? 0.0 : j
* dtheta
;
450 x
= -sin(theta
) * sin(rho
);
451 y
= cos(theta
) * sin(rho
);
452 z
= nsign
* cos(rho
);
454 glVertex3f(x
* radius
, y
* radius
, z
* radius
);
459 else if (qobj
->DrawStyle
== GLU_LINE
|| qobj
->DrawStyle
== GLU_SILHOUETTE
) {
460 /* draw stack lines */
461 for (i
= 1; i
< stacks
; i
++) { /* stack line at i==stacks-1 was missing here */
463 glBegin(GL_LINE_LOOP
);
464 for (j
= 0; j
< slices
; j
++) {
466 x
= cos(theta
) * sin(rho
);
467 y
= sin(theta
) * sin(rho
);
469 glVertex3f(x
* radius
, y
* radius
, z
* radius
);
473 /* draw slice lines */
474 for (j
= 0; j
< slices
; j
++) {
476 glBegin(GL_LINE_STRIP
);
477 for (i
= 0; i
<= stacks
; i
++) {
479 x
= cos(theta
) * sin(rho
);
480 y
= sin(theta
) * sin(rho
);
482 glVertex3f(x
* radius
, y
* radius
, z
* radius
);
487 else if (qobj
->DrawStyle
== GLU_POINT
) {
488 /* top and bottom-most points */
490 glVertex3f(0.0, 0.0, radius
);
491 glVertex3f(0.0, 0.0, -radius
);
493 /* loop over stacks */
494 for (i
= 1; i
< stacks
- 1; i
++) {
496 for (j
= 0; j
< slices
; j
++) {
498 x
= cos(theta
) * sin(rho
);
499 y
= sin(theta
) * sin(rho
);
501 glVertex3f(x
* radius
, y
* radius
, z
* radius
);
512 gluDisk(GLUquadricObj
* qobj
,
513 GLdouble innerRadius
, GLdouble outerRadius
, GLint slices
, GLint loops
)
525 da
= 2.0 * M_PI
/ slices
;
526 dr
= (outerRadius
- innerRadius
) / (GLfloat
) loops
;
528 switch (qobj
->DrawStyle
) {
531 /* texture of a gluDisk is a cut out of the texture unit square
532 * x, y in [-outerRadius, +outerRadius]; s, t in [0, 1]
535 GLfloat dtc
= 2.0f
* outerRadius
;
537 GLfloat r1
= innerRadius
;
539 for (l
= 0; l
< loops
; l
++) {
540 GLfloat r2
= r1
+ dr
;
541 if (qobj
->Orientation
== GLU_OUTSIDE
) {
543 glBegin(GL_QUAD_STRIP
);
544 for (s
= 0; s
<= slices
; s
++) {
552 TXTR_COORD(0.5 + sa
* r2
/ dtc
, 0.5 + ca
* r2
/ dtc
);
553 glVertex2f(r2
* sa
, r2
* ca
);
554 TXTR_COORD(0.5 + sa
* r1
/ dtc
, 0.5 + ca
* r1
/ dtc
);
555 glVertex2f(r1
* sa
, r1
* ca
);
561 glBegin(GL_QUAD_STRIP
);
562 for (s
= slices
; s
>= 0; s
--) {
570 TXTR_COORD(0.5 - sa
* r2
/ dtc
, 0.5 + ca
* r2
/ dtc
);
571 glVertex2f(r2
* sa
, r2
* ca
);
572 TXTR_COORD(0.5 - sa
* r1
/ dtc
, 0.5 + ca
* r1
/ dtc
);
573 glVertex2f(r1
* sa
, r1
* ca
);
585 for (l
= 0; l
<= loops
; l
++) {
586 GLfloat r
= innerRadius
+ l
* dr
;
587 glBegin(GL_LINE_LOOP
);
588 for (s
= 0; s
< slices
; s
++) {
590 glVertex2f(r
* sin(a
), r
* cos(a
));
595 for (s
= 0; s
< slices
; s
++) {
599 glBegin(GL_LINE_STRIP
);
600 for (l
= 0; l
<= loops
; l
++) {
601 GLfloat r
= innerRadius
+ l
* dr
;
602 glVertex2f(r
* x
, r
* y
);
612 for (s
= 0; s
< slices
; s
++) {
617 for (l
= 0; l
<= loops
; l
++) {
618 GLfloat r
= innerRadius
* l
* dr
;
619 glVertex2f(r
* x
, r
* y
);
627 if (innerRadius
!= 0.0) {
629 glBegin(GL_LINE_LOOP
);
630 for (a
= 0.0; a
< 2.0 * M_PI
; a
+= da
) {
631 GLfloat x
= innerRadius
* sin(a
);
632 GLfloat y
= innerRadius
* cos(a
);
639 glBegin(GL_LINE_LOOP
);
640 for (a
= 0; a
< 2.0 * M_PI
; a
+= da
) {
641 GLfloat x
= outerRadius
* sin(a
);
642 GLfloat y
= outerRadius
* cos(a
);
657 gluPartialDisk(GLUquadricObj
* qobj
, GLdouble innerRadius
,
658 GLdouble outerRadius
, GLint slices
, GLint loops
,
659 GLdouble startAngle
, GLdouble sweepAngle
)
661 if (qobj
->DrawStyle
== GLU_POINT
) {
663 GLdouble radius
, delta_radius
;
664 GLdouble angle
, delta_angle
;
665 delta_radius
= (outerRadius
- innerRadius
) / (loops
- 1);
666 delta_angle
= DEG_TO_RAD((sweepAngle
) / (slices
- 1));
668 radius
= innerRadius
;
669 for (loop
= 0; loop
< loops
; loop
++) {
670 angle
= DEG_TO_RAD(startAngle
);
671 for (slice
= 0; slice
< slices
; slice
++) {
672 glVertex2f(radius
* sin(angle
), radius
* cos(angle
));
673 angle
+= delta_angle
;
675 radius
+= delta_radius
;
679 else if (qobj
->DrawStyle
== GLU_LINE
) {
681 GLdouble radius
, delta_radius
;
682 GLdouble angle
, delta_angle
;
683 delta_radius
= (outerRadius
- innerRadius
) / loops
;
684 delta_angle
= DEG_TO_RAD(sweepAngle
/ slices
);
686 radius
= innerRadius
;
687 for (loop
= 0; loop
< loops
; loop
++) {
688 angle
= DEG_TO_RAD(startAngle
);
689 glBegin(GL_LINE_STRIP
);
690 for (slice
= 0; slice
<= slices
; slice
++) {
691 glVertex2f(radius
* sin(angle
), radius
* cos(angle
));
692 angle
+= delta_angle
;
695 radius
+= delta_radius
;
698 angle
= DEG_TO_RAD(startAngle
);
699 for (slice
= 0; slice
<= slices
; slice
++) {
700 radius
= innerRadius
;
701 glBegin(GL_LINE_STRIP
);
702 for (loop
= 0; loop
< loops
; loop
++) {
703 glVertex2f(radius
* sin(angle
), radius
* cos(angle
));
704 radius
+= delta_radius
;
707 angle
+= delta_angle
;
710 else if (qobj
->DrawStyle
== GLU_SILHOUETTE
) {
712 GLdouble angle
, delta_angle
;
713 delta_angle
= DEG_TO_RAD(sweepAngle
/ slices
);
714 /* draw outer ring */
715 glBegin(GL_LINE_STRIP
);
716 angle
= DEG_TO_RAD(startAngle
);
717 for (slice
= 0; slice
<= slices
; slice
++) {
718 glVertex2f(outerRadius
* sin(angle
), outerRadius
* cos(angle
));
719 angle
+= delta_angle
;
722 /* draw inner ring */
723 if (innerRadius
> 0.0) {
724 glBegin(GL_LINE_STRIP
);
725 angle
= DEG_TO_RAD(startAngle
);
726 for (slice
= 0; slice
< slices
; slice
++) {
727 glVertex2f(innerRadius
* sin(angle
), innerRadius
* cos(angle
));
728 angle
+= delta_angle
;
733 if (sweepAngle
< 360.0) {
734 GLdouble stopAngle
= startAngle
+ sweepAngle
;
736 glVertex2f(innerRadius
* SIND(startAngle
),
737 innerRadius
* COSD(startAngle
));
738 glVertex2f(outerRadius
* SIND(startAngle
),
739 outerRadius
* COSD(startAngle
));
740 glVertex2f(innerRadius
* SIND(stopAngle
),
741 innerRadius
* COSD(stopAngle
));
742 glVertex2f(outerRadius
* SIND(stopAngle
),
743 outerRadius
* COSD(stopAngle
));
747 else if (qobj
->DrawStyle
== GLU_FILL
) {
749 GLdouble radius
, delta_radius
;
750 GLdouble angle
, delta_angle
;
751 delta_radius
= (outerRadius
- innerRadius
) / loops
;
752 delta_angle
= DEG_TO_RAD(sweepAngle
/ slices
);
753 radius
= innerRadius
;
754 for (loop
= 0; loop
< loops
; loop
++) {
755 glBegin(GL_QUAD_STRIP
);
756 angle
= DEG_TO_RAD(startAngle
);
757 for (slice
= 0; slice
<= slices
; slice
++) {
758 if (qobj
->Orientation
== GLU_OUTSIDE
) {
759 glVertex2f((radius
+ delta_radius
) * sin(angle
),
760 (radius
+ delta_radius
) * cos(angle
));
761 glVertex2f(radius
* sin(angle
), radius
* cos(angle
));
764 glVertex2f(radius
* sin(angle
), radius
* cos(angle
));
765 glVertex2f((radius
+ delta_radius
) * sin(angle
),
766 (radius
+ delta_radius
) * cos(angle
));
768 angle
+= delta_angle
;
771 radius
+= delta_radius
;