0484890ef69ff96f0c1fcc462bce62c18048036e
3 * Mesa 3-D graphics library
5 * Copyright (C) 1999-2000 Brian Paul
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the Free
19 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * texture coordinate support
25 * flip normals according to orientation
26 * there's still some inside/outside orientation bugs in possibly all
27 * but the sphere function
43 # define M_PI (3.1415926)
48 * Convert degrees to radians:
50 #define DEG_TO_RAD(A) ((A)*(M_PI/180.0))
54 * Sin and Cos for degree angles:
56 #define SIND( A ) sin( (A)*(M_PI/180.0) )
57 #define COSD( A) cos( (A)*(M_PI/180.0) )
61 * Texture coordinates if texture flag is set
63 #define TXTR_COORD(x,y) if (qobj->TextureFlag) glTexCoord2f(x,y);
69 GLenum DrawStyle
; /* GLU_FILL, LINE, SILHOUETTE, or POINT */
70 GLenum Orientation
; /* GLU_INSIDE or GLU_OUTSIDE */
71 GLboolean TextureFlag
; /* Generate texture coords? */
72 GLenum Normals
; /* GLU_NONE, GLU_FLAT, or GLU_SMOOTH */
73 void (GLCALLBACK
* ErrorFunc
) (GLenum err
); /* Error handler callback function */
79 * Process a GLU error.
82 quadric_error(GLUquadricObj
* qobj
, GLenum error
, const char *msg
)
84 /* Call the error call back function if any */
85 if (qobj
->ErrorFunc
) {
86 (*qobj
->ErrorFunc
) (error
);
88 /* Print a message to stdout if MESA_DEBUG variable is defined */
89 if (getenv("MESA_DEBUG")) {
90 fprintf(stderr
, "GLUError: %s: %s\n", (char *) gluErrorString(error
),
98 GLUquadricObj
*GLAPIENTRY
103 q
= (GLUquadricObj
*) malloc(sizeof(struct GLUquadric
));
105 q
->DrawStyle
= GLU_FILL
;
106 q
->Orientation
= GLU_OUTSIDE
;
107 q
->TextureFlag
= GL_FALSE
;
108 q
->Normals
= GLU_SMOOTH
;
117 gluDeleteQuadric(GLUquadricObj
* state
)
120 free((void *) state
);
127 * Set the drawing style to be GLU_FILL, GLU_LINE, GLU_SILHOUETTE,
131 gluQuadricDrawStyle(GLUquadricObj
* quadObject
, GLenum drawStyle
)
133 if (quadObject
&& (drawStyle
== GLU_FILL
|| drawStyle
== GLU_LINE
134 || drawStyle
== GLU_SILHOUETTE
135 || drawStyle
== GLU_POINT
)) {
136 quadObject
->DrawStyle
= drawStyle
;
139 quadric_error(quadObject
, GLU_INVALID_ENUM
, "qluQuadricDrawStyle");
146 * Set the orientation to GLU_INSIDE or GLU_OUTSIDE.
149 gluQuadricOrientation(GLUquadricObj
* quadObject
, GLenum orientation
)
152 && (orientation
== GLU_INSIDE
|| orientation
== GLU_OUTSIDE
)) {
153 quadObject
->Orientation
= orientation
;
156 quadric_error(quadObject
, GLU_INVALID_ENUM
, "qluQuadricOrientation");
163 * Set the error handler callback function.
166 gluQuadricCallback(GLUquadricObj
* qobj
,
167 GLenum which
, void (GLCALLBACK
* fn
) ())
170 * UGH, this is a mess! I thought ANSI was a standard.
172 if (qobj
&& which
== GLU_ERROR
) {
174 qobj
->ErrorFunc
= (void (GLCALLBACKPCAST
) (GLenum
)) fn
;
175 #elif defined(OPENSTEP)
176 qobj
->ErrorFunc
= (void (*)(GLenum
)) fn
;
177 #elif defined(_WIN32)
178 qobj
->ErrorFunc
= (void (GLCALLBACK
*) (int)) fn
;
179 #elif defined(__STORM__)
180 qobj
->ErrorFunc
= (void (GLCALLBACK
*) (GLenum
)) fn
;
181 #elif defined(__BEOS__)
182 qobj
->ErrorFunc
= (void (*)(GLenum
)) fn
;
184 qobj
->ErrorFunc
= (void (GLCALLBACK
*) ()) fn
;
191 gluQuadricNormals(GLUquadricObj
* quadObject
, GLenum normals
)
194 && (normals
== GLU_NONE
|| normals
== GLU_FLAT
195 || normals
== GLU_SMOOTH
)) {
196 quadObject
->Normals
= normals
;
202 gluQuadricTexture(GLUquadricObj
* quadObject
, GLboolean textureCoords
)
205 quadObject
->TextureFlag
= textureCoords
;
213 * Call glNormal3f after scaling normal to unit length.
216 normal3f(GLfloat x
, GLfloat y
, GLfloat z
)
223 gluCylinder(GLUquadricObj
* qobj
,
224 GLdouble baseRadius
, GLdouble topRadius
,
225 GLdouble height
, GLint slices
, GLint stacks
)
227 GLdouble da
, r
, dr
, dz
;
228 GLfloat x
, y
, z
, nz
, nsign
;
231 if (qobj
->Orientation
== GLU_INSIDE
) {
238 da
= 2.0 * M_PI
/ slices
;
239 dr
= (topRadius
- baseRadius
) / stacks
;
240 dz
= height
/ stacks
;
241 nz
= (baseRadius
- topRadius
) / height
; /* Z component of normal vectors */
243 if (qobj
->DrawStyle
== GLU_POINT
) {
245 for (i
= 0; i
< slices
; i
++) {
248 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
252 for (j
= 0; j
<= stacks
; j
++) {
253 glVertex3f(x
* r
, y
* r
, z
);
260 else if (qobj
->DrawStyle
== GLU_LINE
|| qobj
->DrawStyle
== GLU_SILHOUETTE
) {
262 if (qobj
->DrawStyle
== GLU_LINE
) {
265 for (j
= 0; j
<= stacks
; j
++) {
266 glBegin(GL_LINE_LOOP
);
267 for (i
= 0; i
< slices
; i
++) {
270 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
271 glVertex3f(x
* r
, y
* r
, z
);
279 /* draw one ring at each end */
280 if (baseRadius
!= 0.0) {
281 glBegin(GL_LINE_LOOP
);
282 for (i
= 0; i
< slices
; i
++) {
285 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
286 glVertex3f(x
* baseRadius
, y
* baseRadius
, 0.0);
289 glBegin(GL_LINE_LOOP
);
290 for (i
= 0; i
< slices
; i
++) {
293 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
294 glVertex3f(x
* topRadius
, y
* topRadius
, height
);
299 /* draw length lines */
301 for (i
= 0; i
< slices
; i
++) {
304 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
305 glVertex3f(x
* baseRadius
, y
* baseRadius
, 0.0);
306 glVertex3f(x
* topRadius
, y
* topRadius
, height
);
310 else if (qobj
->DrawStyle
== GLU_FILL
) {
311 GLfloat ds
= 1.0 / slices
;
312 GLfloat dt
= 1.0 / stacks
;
316 for (j
= 0; j
< stacks
; j
++) {
318 glBegin(GL_QUAD_STRIP
);
319 for (i
= 0; i
<= slices
; i
++) {
330 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
332 glVertex3f(x
* r
, y
* r
, z
);
333 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
334 TXTR_COORD(s
, t
+ dt
);
335 glVertex3f(x
* (r
+ dr
), y
* (r
+ dr
), z
+ dz
);
338 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
340 glVertex3f(x
* r
, y
* r
, z
);
341 normal3f(x
* nsign
, y
* nsign
, nz
* nsign
);
342 TXTR_COORD(s
, t
+ dt
);
343 glVertex3f(x
* (r
+ dr
), y
* (r
+ dr
), z
+ dz
);
360 gluSphere(GLUquadricObj
* qobj
, GLdouble radius
, GLint slices
, GLint stacks
)
362 GLfloat rho
, drho
, theta
, dtheta
;
364 GLfloat s
, t
, ds
, dt
;
365 GLint i
, j
, imin
, imax
;
369 if (qobj
->Normals
== GLU_NONE
) {
375 if (qobj
->Orientation
== GLU_INSIDE
) {
382 drho
= M_PI
/ (GLfloat
) stacks
;
383 dtheta
= 2.0 * M_PI
/ (GLfloat
) slices
;
385 /* texturing: s goes from 0.0/0.25/0.5/0.75/1.0 at +y/+x/-y/-x/+y axis */
386 /* t goes from -1.0/+1.0 at z = -radius/+radius (linear along longitudes) */
387 /* cannot use triangle fan on texturing (s coord. at top/bottom tip varies) */
389 if (qobj
->DrawStyle
== GLU_FILL
) {
390 if (!qobj
->TextureFlag
) {
391 /* draw +Z end as a triangle fan */
392 glBegin(GL_TRIANGLE_FAN
);
393 /* glNormal3f(0.0, 0.0, 1.0); */
394 glVertex3f(0.0, 0.0, nsign
* radius
);
395 for (j
= 0; j
<= slices
; j
++) {
396 theta
= (j
== slices
) ? 0.0 : j
* dtheta
;
397 x
= -sin(theta
) * sin(drho
);
398 y
= cos(theta
) * sin(drho
);
399 z
= nsign
* cos(drho
);
400 glVertex3f(x
* radius
, y
* radius
, z
* radius
);
407 t
= 1.0; /* because loop now runs from 0 */
408 if (qobj
->TextureFlag
) {
417 /* draw intermediate stacks as quad strips */
418 for (i
= imin
; i
< imax
; i
++) {
420 glBegin(GL_QUAD_STRIP
);
422 for (j
= 0; j
<= slices
; j
++) {
423 theta
= (j
== slices
) ? 0.0 : j
* dtheta
;
424 x
= -sin(theta
) * sin(rho
);
425 y
= cos(theta
) * sin(rho
);
426 z
= nsign
* cos(rho
);
428 glVertex3f(x
* radius
, y
* radius
, z
* radius
);
429 x
= -sin(theta
) * sin(rho
+ drho
);
430 y
= cos(theta
) * sin(rho
+ drho
);
431 z
= nsign
* cos(rho
+ drho
);
432 TXTR_COORD(s
, t
- dt
);
434 glVertex3f(x
* radius
, y
* radius
, z
* radius
);
440 if (!qobj
->TextureFlag
) {
441 /* draw -Z end as a triangle fan */
442 glBegin(GL_TRIANGLE_FAN
);
443 glVertex3f(0.0, 0.0, -radius
* nsign
);
447 for (j
= slices
; j
>= 0; j
--) {
448 theta
= (j
== slices
) ? 0.0 : j
* dtheta
;
449 x
= -sin(theta
) * sin(rho
);
450 y
= cos(theta
) * sin(rho
);
451 z
= nsign
* cos(rho
);
453 glVertex3f(x
* radius
, y
* radius
, z
* radius
);
458 else if (qobj
->DrawStyle
== GLU_LINE
|| qobj
->DrawStyle
== GLU_SILHOUETTE
) {
459 /* draw stack lines */
460 for (i
= 1; i
< stacks
; i
++) { /* stack line at i==stacks-1 was missing here */
462 glBegin(GL_LINE_LOOP
);
463 for (j
= 0; j
< slices
; j
++) {
465 x
= cos(theta
) * sin(rho
);
466 y
= sin(theta
) * sin(rho
);
468 glVertex3f(x
* radius
, y
* radius
, z
* radius
);
472 /* draw slice lines */
473 for (j
= 0; j
< slices
; j
++) {
475 glBegin(GL_LINE_STRIP
);
476 for (i
= 0; i
<= stacks
; i
++) {
478 x
= cos(theta
) * sin(rho
);
479 y
= sin(theta
) * sin(rho
);
481 glVertex3f(x
* radius
, y
* radius
, z
* radius
);
486 else if (qobj
->DrawStyle
== GLU_POINT
) {
487 /* top and bottom-most points */
489 glVertex3f(0.0, 0.0, radius
);
490 glVertex3f(0.0, 0.0, -radius
);
492 /* loop over stacks */
493 for (i
= 1; i
< stacks
- 1; i
++) {
495 for (j
= 0; j
< slices
; j
++) {
497 x
= cos(theta
) * sin(rho
);
498 y
= sin(theta
) * sin(rho
);
500 glVertex3f(x
* radius
, y
* radius
, z
* radius
);
511 gluDisk(GLUquadricObj
* qobj
,
512 GLdouble innerRadius
, GLdouble outerRadius
, GLint slices
, GLint loops
)
524 da
= 2.0 * M_PI
/ slices
;
525 dr
= (outerRadius
- innerRadius
) / (GLfloat
) loops
;
527 switch (qobj
->DrawStyle
) {
530 /* texture of a gluDisk is a cut out of the texture unit square
531 * x, y in [-outerRadius, +outerRadius]; s, t in [0, 1]
534 GLfloat dtc
= 2.0f
* outerRadius
;
536 GLfloat r1
= innerRadius
;
538 for (l
= 0; l
< loops
; l
++) {
539 GLfloat r2
= r1
+ dr
;
540 if (qobj
->Orientation
== GLU_OUTSIDE
) {
542 glBegin(GL_QUAD_STRIP
);
543 for (s
= 0; s
<= slices
; s
++) {
551 TXTR_COORD(0.5 + sa
* r2
/ dtc
, 0.5 + ca
* r2
/ dtc
);
552 glVertex2f(r2
* sa
, r2
* ca
);
553 TXTR_COORD(0.5 + sa
* r1
/ dtc
, 0.5 + ca
* r1
/ dtc
);
554 glVertex2f(r1
* sa
, r1
* ca
);
560 glBegin(GL_QUAD_STRIP
);
561 for (s
= slices
; s
>= 0; s
--) {
569 TXTR_COORD(0.5 - sa
* r2
/ dtc
, 0.5 + ca
* r2
/ dtc
);
570 glVertex2f(r2
* sa
, r2
* ca
);
571 TXTR_COORD(0.5 - sa
* r1
/ dtc
, 0.5 + ca
* r1
/ dtc
);
572 glVertex2f(r1
* sa
, r1
* ca
);
584 for (l
= 0; l
<= loops
; l
++) {
585 GLfloat r
= innerRadius
+ l
* dr
;
586 glBegin(GL_LINE_LOOP
);
587 for (s
= 0; s
< slices
; s
++) {
589 glVertex2f(r
* sin(a
), r
* cos(a
));
594 for (s
= 0; s
< slices
; s
++) {
598 glBegin(GL_LINE_STRIP
);
599 for (l
= 0; l
<= loops
; l
++) {
600 GLfloat r
= innerRadius
+ l
* dr
;
601 glVertex2f(r
* x
, r
* y
);
611 for (s
= 0; s
< slices
; s
++) {
616 for (l
= 0; l
<= loops
; l
++) {
617 GLfloat r
= innerRadius
* l
* dr
;
618 glVertex2f(r
* x
, r
* y
);
626 if (innerRadius
!= 0.0) {
628 glBegin(GL_LINE_LOOP
);
629 for (a
= 0.0; a
< 2.0 * M_PI
; a
+= da
) {
630 GLfloat x
= innerRadius
* sin(a
);
631 GLfloat y
= innerRadius
* cos(a
);
638 glBegin(GL_LINE_LOOP
);
639 for (a
= 0; a
< 2.0 * M_PI
; a
+= da
) {
640 GLfloat x
= outerRadius
* sin(a
);
641 GLfloat y
= outerRadius
* cos(a
);
656 gluPartialDisk(GLUquadricObj
* qobj
, GLdouble innerRadius
,
657 GLdouble outerRadius
, GLint slices
, GLint loops
,
658 GLdouble startAngle
, GLdouble sweepAngle
)
660 if (qobj
->DrawStyle
== GLU_POINT
) {
662 GLdouble radius
, delta_radius
;
663 GLdouble angle
, delta_angle
;
664 delta_radius
= (outerRadius
- innerRadius
) / (loops
- 1);
665 delta_angle
= DEG_TO_RAD((sweepAngle
) / (slices
- 1));
667 radius
= innerRadius
;
668 for (loop
= 0; loop
< loops
; loop
++) {
669 angle
= DEG_TO_RAD(startAngle
);
670 for (slice
= 0; slice
< slices
; slice
++) {
671 glVertex2f(radius
* sin(angle
), radius
* cos(angle
));
672 angle
+= delta_angle
;
674 radius
+= delta_radius
;
678 else if (qobj
->DrawStyle
== GLU_LINE
) {
680 GLdouble radius
, delta_radius
;
681 GLdouble angle
, delta_angle
;
682 delta_radius
= (outerRadius
- innerRadius
) / loops
;
683 delta_angle
= DEG_TO_RAD(sweepAngle
/ slices
);
685 radius
= innerRadius
;
686 for (loop
= 0; loop
< loops
; loop
++) {
687 angle
= DEG_TO_RAD(startAngle
);
688 glBegin(GL_LINE_STRIP
);
689 for (slice
= 0; slice
<= slices
; slice
++) {
690 glVertex2f(radius
* sin(angle
), radius
* cos(angle
));
691 angle
+= delta_angle
;
694 radius
+= delta_radius
;
697 angle
= DEG_TO_RAD(startAngle
);
698 for (slice
= 0; slice
<= slices
; slice
++) {
699 radius
= innerRadius
;
700 glBegin(GL_LINE_STRIP
);
701 for (loop
= 0; loop
< loops
; loop
++) {
702 glVertex2f(radius
* sin(angle
), radius
* cos(angle
));
703 radius
+= delta_radius
;
706 angle
+= delta_angle
;
709 else if (qobj
->DrawStyle
== GLU_SILHOUETTE
) {
711 GLdouble angle
, delta_angle
;
712 delta_angle
= DEG_TO_RAD(sweepAngle
/ slices
);
713 /* draw outer ring */
714 glBegin(GL_LINE_STRIP
);
715 angle
= DEG_TO_RAD(startAngle
);
716 for (slice
= 0; slice
<= slices
; slice
++) {
717 glVertex2f(outerRadius
* sin(angle
), outerRadius
* cos(angle
));
718 angle
+= delta_angle
;
721 /* draw inner ring */
722 if (innerRadius
> 0.0) {
723 glBegin(GL_LINE_STRIP
);
724 angle
= DEG_TO_RAD(startAngle
);
725 for (slice
= 0; slice
< slices
; slice
++) {
726 glVertex2f(innerRadius
* sin(angle
), innerRadius
* cos(angle
));
727 angle
+= delta_angle
;
732 if (sweepAngle
< 360.0) {
733 GLdouble stopAngle
= startAngle
+ sweepAngle
;
735 glVertex2f(innerRadius
* SIND(startAngle
),
736 innerRadius
* COSD(startAngle
));
737 glVertex2f(outerRadius
* SIND(startAngle
),
738 outerRadius
* COSD(startAngle
));
739 glVertex2f(innerRadius
* SIND(stopAngle
),
740 innerRadius
* COSD(stopAngle
));
741 glVertex2f(outerRadius
* SIND(stopAngle
),
742 outerRadius
* COSD(stopAngle
));
746 else if (qobj
->DrawStyle
== GLU_FILL
) {
748 GLdouble radius
, delta_radius
;
749 GLdouble angle
, delta_angle
;
750 delta_radius
= (outerRadius
- innerRadius
) / loops
;
751 delta_angle
= DEG_TO_RAD(sweepAngle
/ slices
);
752 radius
= innerRadius
;
753 for (loop
= 0; loop
< loops
; loop
++) {
754 glBegin(GL_QUAD_STRIP
);
755 angle
= DEG_TO_RAD(startAngle
);
756 for (slice
= 0; slice
<= slices
; slice
++) {
757 if (qobj
->Orientation
== GLU_OUTSIDE
) {
758 glVertex2f((radius
+ delta_radius
) * sin(angle
),
759 (radius
+ delta_radius
) * cos(angle
));
760 glVertex2f(radius
* sin(angle
), radius
* cos(angle
));
763 glVertex2f(radius
* sin(angle
), radius
* cos(angle
));
764 glVertex2f((radius
+ delta_radius
) * sin(angle
),
765 (radius
+ delta_radius
) * cos(angle
));
767 angle
+= delta_angle
;
770 radius
+= delta_radius
;