// Wormhole.cpp // NKU CSC 480 Spring 2006 Kirby Program 1 // -------------------------------------------------------------------------------- // Wormhole in wireframe. // The "standard wormhole", as the figure, is wormhole( 2.0, 1.0, 1.4, 0.2, 0.1 ). // -------------------------------------------------------------------------------- #include #include "Geometry.h" using namespace csc480 ; void wormholeOpening( double rInner, double rOuter, int nIntervalsPhi, int nIntervalsTheta ) // Draw a wormhole opening with given inner and outer radii. // Drawn as a surface of revolution of a quarter circle offset from the axis. // nIntervalsPhi= number of slices of quarter circle // nIntervalsTheta= number of divisions around surface of revolution. { assert( nIntervalsPhi > 2 ) ; assert( nIntervalsTheta > 2 ) ; assert( rOuter > rInner ) ; assert( rInner > 0 ) ; const double R= rOuter-rInner ; // radius of quarter circle to be revolved const double DPHI= (PI/2) / nIntervalsPhi ; // step size upward in angle of above circle const double DTHETA = 2*PI / nIntervalsTheta ; // step size around circle of revolution double phi= 0 ; double y=0 ; double dist= rInner ; // Loop through the slices. for ( int iPhi=0 ; iPhi <= nIntervalsPhi ; ++iPhi ) { double phiNext= phi + DPHI ; double yNext= R * sin( phiNext ) ; double distNext= rOuter - sqrt( R*R - yNext*yNext ) ; // Build a quadstrip using this slice and next. glBegin( GL_TRIANGLE_STRIP ) ; for ( int ia=0 ; ia <= nIntervalsTheta ; ++ia ) { // Update the angle as we move around the circle. double theta= -ia * DTHETA ; double c= cos( theta ) ; double s= sin( theta ) ; // Get the points on the circle here and at the next level. double x= dist * c ; double z= dist * s ; double xNext= distNext * c ; double zNext= distNext * s ; glVertex3d( x, y, z ) ; glVertex3d( xNext, yNext, zNext ) ; } glEnd() ; // Prepare for next pass phi= phiNext ; y= yNext ; dist= distNext ; } } void tile( double xLo, double zLo, double xLength, double zLength ) // Draw a rectangular tile (made up of 2 triangles) on xz plane of given dimensions. { glBegin( GL_TRIANGLE_STRIP ) ; glVertex3d( xLo, 0, zLo ) ; glVertex3d( xLo, 0, zLo+zLength ) ; glVertex3d( xLo+xLength, 0, zLo ) ; glVertex3d( xLo+xLength, 0, zLo+zLength ) ; glEnd() ; } void rect( double xMin, double xMax, int nTilesX, double zMin, double zMax, int nTilesZ ) // Draw a rectangle made up of tiles on the xz plane. { double dz= (zMax - zMin) / nTilesZ ; double dx= (xMax - xMin) / nTilesX ; for ( int ix=0 ; ix < nTilesX ; ix++ ) { for ( int iz=0 ; iz < nTilesZ ; iz++ ) { tile( xMin + ix*dx, zMin + iz*dz, dx, dz ) ; } } } void floor( double length, double width, double sep, double rOuter ) // Draw a the plane the wormhole opens onto, centered at the origin. { rect( -length/2, -sep/2-rOuter, 1, -width/2, width/2, 10 ) ; rect( -sep/2+rOuter, sep/2-rOuter, 10, -width/2, width/2, 10 ) ; rect( sep/2+rOuter, length/2, 1, -width/2, width/2, 10 ) ; rect( -sep/2-rOuter, -sep/2+rOuter, 4, -width/2, -rOuter, 3 ) ; rect( -sep/2-rOuter, -sep/2+rOuter, 4, rOuter, width/2, 3 ) ; rect( sep/2-rOuter, sep/2+rOuter, 4, -width/2, -rOuter, 3 ) ; rect( sep/2-rOuter, sep/2+rOuter, 4, rOuter, width/2, 3 ) ; } void torus( double rInt, double rExt, int nResInt, int nResExt, double thetaMax ) // Draw a torus with given internal and external radii, broken up into // intervals given by internal and external radius resolution. // Draws from theta=0 to theta=thetaMax. (thetaMax=180 draws a half-donut). { assert( rInt > 0 ) ; assert( rExt > rInt ) ; assert( nResInt > 2 ) ; assert( nResExt > 2 ) ; assert( thetaMax > 0 && thetaMax <= 360. ) ; int nSections= 1 + (int)( nResExt * thetaMax / 360.) ; int nSpokes= 1 + nResInt ; double dTheta= 360. / nResExt ; double dPhi= 360. / nResInt ; Point3 ptRim( rExt,0,0 ) ; Vector3 uvRadial( 1,0,0 ) ; Vector3 uvZ( 0,0,1 ) ; for ( int iSection=1 ; iSection < nSections ; ++iSection ) { double theta= iSection*dTheta ; double x0= rExt * cos( toRadians( theta ) ) ; double y0= rExt * sin( toRadians( theta ) ) ; Point3 ptRimNext( x0, y0, 0 ) ; Vector3 uvRadialNext= normalize( ptRimNext - Point3(0,0,0) ) ; glBegin( GL_TRIANGLE_STRIP ) ; for ( int iSpoke= 0 ; iSpoke < nSpokes ; ++iSpoke ) { double phi= iSpoke*dPhi ; Point3 vtx= ptRim + rInt*cos( toRadians( phi ) )*uvRadial + rInt*sin( toRadians( phi ) )*uvZ ; glVertex3dv( vtx.toArray() ) ; Point3 vtxNext= ptRimNext + rInt*cos( toRadians( phi ) )*uvRadialNext + rInt*sin( toRadians( phi ) )*uvZ ; glVertex3dv( vtxNext.toArray() ) ; } uvRadial= uvRadialNext ; ptRim= ptRimNext ; glEnd() ; } } void wormhole( double length, double width, double sep, double rOuter, double rInner ) // Draws a wormhole with caps emptying into a plane. See P1 handout for details. { assert( sep + 2*rOuter < length ) ; assert( sep > 0 ) ; assert( rOuter > rInner ) ; assert( rInner > 0 ) ; assert( 2*rOuter < width ) ; double rInt= rInner ; double rExt= sep/2 ; double capHeight= rOuter - rInner ; glPushMatrix() ; glScaled( 1, -1, 1 ) ; // turn upside down glTranslated( 0, capHeight, 0 ) ; // slide down to allow for cap torus( rInt, rExt, 16, 70, 180 ) ; glPopMatrix() ; glPushMatrix() ; glTranslated( rExt, -capHeight, 0 ) ; wormholeOpening( rInner, rOuter, 8, 16 ) ; glPopMatrix() ; glPushMatrix() ; glTranslated( -rExt, -capHeight, 0 ) ; wormholeOpening( rInner, rOuter, 8, 16 ) ; glPopMatrix() ; floor( length, width, sep, rOuter ) ; }