/* * freeglut_geometry.c * * Freeglut geometry rendering methods. * * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. * Written by Pawel W. Olszta, * Creation date: Fri Dec 3 1999 * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include #include "freeglut_internal.h" /* * TODO BEFORE THE STABLE RELEASE: * * Following functions have been contributed by Andreas Umbach. * * glutWireCube() -- looks OK * glutSolidCube() -- OK * * Those functions have been implemented by John Fay. * * glutWireTorus() -- looks OK * glutSolidTorus() -- looks OK * glutWireDodecahedron() -- looks OK * glutSolidDodecahedron() -- looks OK * glutWireOctahedron() -- looks OK * glutSolidOctahedron() -- looks OK * glutWireTetrahedron() -- looks OK * glutSolidTetrahedron() -- looks OK * glutWireIcosahedron() -- looks OK * glutSolidIcosahedron() -- looks OK * * The Following functions have been updated by Nigel Stewart, based * on FreeGLUT 2.0.0 implementations: * * glutWireSphere() -- looks OK * glutSolidSphere() -- looks OK * glutWireCone() -- looks OK * glutSolidCone() -- looks OK */ /* -- INTERFACE FUNCTIONS -------------------------------------------------- */ /* * Draws a wireframed cube. Code contributed by Andreas Umbach */ void FGAPIENTRY glutWireCube( GLdouble dSize ) { double size = dSize * 0.5; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCube" ); # define V(a,b,c) glVertex3d( a size, b size, c size ); # define N(a,b,c) glNormal3d( a, b, c ); /* PWO: I dared to convert the code to use macros... */ glBegin( GL_LINE_LOOP ); N( 1.0, 0.0, 0.0); V(+,-,+); V(+,-,-); V(+,+,-); V(+,+,+); glEnd(); glBegin( GL_LINE_LOOP ); N( 0.0, 1.0, 0.0); V(+,+,+); V(+,+,-); V(-,+,-); V(-,+,+); glEnd(); glBegin( GL_LINE_LOOP ); N( 0.0, 0.0, 1.0); V(+,+,+); V(-,+,+); V(-,-,+); V(+,-,+); glEnd(); glBegin( GL_LINE_LOOP ); N(-1.0, 0.0, 0.0); V(-,-,+); V(-,+,+); V(-,+,-); V(-,-,-); glEnd(); glBegin( GL_LINE_LOOP ); N( 0.0,-1.0, 0.0); V(-,-,+); V(-,-,-); V(+,-,-); V(+,-,+); glEnd(); glBegin( GL_LINE_LOOP ); N( 0.0, 0.0,-1.0); V(-,-,-); V(-,+,-); V(+,+,-); V(+,-,-); glEnd(); # undef V # undef N } /* * Draws a solid cube. Code contributed by Andreas Umbach */ void FGAPIENTRY glutSolidCube( GLdouble dSize ) { double size = dSize * 0.5; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCube" ); # define V(a,b,c) glVertex3d( a size, b size, c size ); # define N(a,b,c) glNormal3d( a, b, c ); /* PWO: Again, I dared to convert the code to use macros... */ glBegin( GL_QUADS ); N( 1.0, 0.0, 0.0); V(+,-,+); V(+,-,-); V(+,+,-); V(+,+,+); N( 0.0, 1.0, 0.0); V(+,+,+); V(+,+,-); V(-,+,-); V(-,+,+); N( 0.0, 0.0, 1.0); V(+,+,+); V(-,+,+); V(-,-,+); V(+,-,+); N(-1.0, 0.0, 0.0); V(-,-,+); V(-,+,+); V(-,+,-); V(-,-,-); N( 0.0,-1.0, 0.0); V(-,-,+); V(-,-,-); V(+,-,-); V(+,-,+); N( 0.0, 0.0,-1.0); V(-,-,-); V(-,+,-); V(+,+,-); V(+,-,-); glEnd(); # undef V # undef N } /* * Compute lookup table of cos and sin values forming a cirle * * Notes: * It is the responsibility of the caller to free these tables * The size of the table is (n+1) to form a connected loop * The last entry is exactly the same as the first * The sign of n can be flipped to get the reverse loop */ static void fghCircleTable(double **sint,double **cost,const int n) { int i; /* Table size, the sign of n flips the circle direction */ const int size = abs(n); /* Determine the angle between samples */ const double angle = 2*M_PI/(double)( ( n == 0 ) ? 1 : n ); /* Allocate memory for n samples, plus duplicate of first entry at the end */ *sint = (double *) calloc(sizeof(double), size+1); *cost = (double *) calloc(sizeof(double), size+1); /* Bail out if memory allocation fails, fgError never returns */ if (!(*sint) || !(*cost)) { free(*sint); free(*cost); fgError("Failed to allocate memory in fghCircleTable"); } /* Compute cos and sin around the circle */ (*sint)[0] = 0.0; (*cost)[0] = 1.0; for (i=1; i0)?1:0]; r0 = 0.0; r1 = sint2[(stacks>0)?1:0]; glBegin(GL_TRIANGLE_FAN); glNormal3d(0,0,1); glVertex3d(0,0,radius); for (j=slices; j>=0; j--) { glNormal3d(cost1[j]*r1, sint1[j]*r1, z1 ); glVertex3d(cost1[j]*r1*radius, sint1[j]*r1*radius, z1*radius); } glEnd(); /* Cover each stack with a quad strip, except the top and bottom stacks */ for( i=1; i 0 ) ? stacks : 1 ); const double rStep = base / ( ( stacks > 0 ) ? stacks : 1 ); /* Scaling factors for vertex normals */ const double cosn = ( height / sqrt ( height * height + base * base )); const double sinn = ( base / sqrt ( height * height + base * base )); /* Pre-computed circle */ double *sint,*cost; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCone" ); fghCircleTable(&sint,&cost,-slices); /* Cover the circular base with a triangle fan... */ z0 = 0.0; z1 = zStep; r0 = base; r1 = r0 - rStep; glBegin(GL_TRIANGLE_FAN); glNormal3d(0.0,0.0,-1.0); glVertex3d(0.0,0.0, z0 ); for (j=0; j<=slices; j++) glVertex3d(cost[j]*r0, sint[j]*r0, z0); glEnd(); /* Cover each stack with a quad strip, except the top stack */ for( i=0; i 0 ) ? stacks : 1 ); const double rStep = base / ( ( stacks > 0 ) ? stacks : 1 ); /* Scaling factors for vertex normals */ const double cosn = ( height / sqrt ( height * height + base * base )); const double sinn = ( base / sqrt ( height * height + base * base )); /* Pre-computed circle */ double *sint,*cost; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCone" ); fghCircleTable(&sint,&cost,-slices); /* Draw the stacks... */ for (i=0; i 0 ) ? stacks : 1 ); /* Pre-computed circle */ double *sint,*cost; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidCylinder" ); fghCircleTable(&sint,&cost,-slices); /* Cover the base and top */ glBegin(GL_TRIANGLE_FAN); glNormal3d(0.0, 0.0, -1.0 ); glVertex3d(0.0, 0.0, 0.0 ); for (j=0; j<=slices; j++) glVertex3d(cost[j]*radius, sint[j]*radius, 0.0); glEnd(); glBegin(GL_TRIANGLE_FAN); glNormal3d(0.0, 0.0, 1.0 ); glVertex3d(0.0, 0.0, height); for (j=slices; j>=0; j--) glVertex3d(cost[j]*radius, sint[j]*radius, height); glEnd(); /* Do the stacks */ z0 = 0.0; z1 = zStep; for (i=1; i<=stacks; i++) { if (i==stacks) z1 = height; glBegin(GL_QUAD_STRIP); for (j=0; j<=slices; j++ ) { glNormal3d(cost[j], sint[j], 0.0 ); glVertex3d(cost[j]*radius, sint[j]*radius, z0 ); glVertex3d(cost[j]*radius, sint[j]*radius, z1 ); } glEnd(); z0 = z1; z1 += zStep; } /* Release sin and cos tables */ free(sint); free(cost); } /* * Draws a wire cylinder */ void FGAPIENTRY glutWireCylinder(GLdouble radius, GLdouble height, GLint slices, GLint stacks) { int i,j; /* Step in z and radius as stacks are drawn. */ double z = 0.0; const double zStep = height / ( ( stacks > 0 ) ? stacks : 1 ); /* Pre-computed circle */ double *sint,*cost; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutWireCylinder" ); fghCircleTable(&sint,&cost,-slices); /* Draw the stacks... */ for (i=0; i<=stacks; i++) { if (i==stacks) z = height; glBegin(GL_LINE_LOOP); for( j=0; j 0 ) { GLdouble local_offset[3] ; /* Use a local variable to avoid buildup of roundoff errors */ num_levels -- ; scale /= 2.0 ; for ( i = 0 ; i < NUM_TETR_FACES ; i++ ) { local_offset[0] = offset[0] + scale * tet_r[i][0] ; local_offset[1] = offset[1] + scale * tet_r[i][1] ; local_offset[2] = offset[2] + scale * tet_r[i][2] ; glutWireSierpinskiSponge ( num_levels, local_offset, scale ) ; } } } void FGAPIENTRY glutSolidSierpinskiSponge ( int num_levels, GLdouble offset[3], GLdouble scale ) { int i, j ; FREEGLUT_EXIT_IF_NOT_INITIALISED ( "glutSolidSierpinskiSponge" ); if ( num_levels == 0 ) { glBegin ( GL_TRIANGLES ) ; for ( i = 0 ; i < NUM_TETR_FACES ; i++ ) { glNormal3d ( -tet_r[i][0], -tet_r[i][1], -tet_r[i][2] ) ; for ( j = 0; j < 3; j++ ) { double x = offset[0] + scale * tet_r[tet_i[i][j]][0] ; double y = offset[1] + scale * tet_r[tet_i[i][j]][1] ; double z = offset[2] + scale * tet_r[tet_i[i][j]][2] ; glVertex3d ( x, y, z ) ; } } glEnd () ; } else if ( num_levels > 0 ) { GLdouble local_offset[3] ; /* Use a local variable to avoid buildup of roundoff errors */ num_levels -- ; scale /= 2.0 ; for ( i = 0 ; i < NUM_TETR_FACES ; i++ ) { local_offset[0] = offset[0] + scale * tet_r[i][0] ; local_offset[1] = offset[1] + scale * tet_r[i][1] ; local_offset[2] = offset[2] + scale * tet_r[i][2] ; glutSolidSierpinskiSponge ( num_levels, local_offset, scale ) ; } } } /*** END OF FILE ***/