// MeshX.cpp // NKU CSC 480/580 - Kirby // --------------------------------------------------------- // An simple immutable class for representing a mesh, // using the .X format with Mesh {... MeshNormals{...}}. // --------------------------------------------------------- #include "MeshX.h" #include #include void scanpast( ifstream& in, char delim ) // A little I/O helper: seek past next occurence of delimiter. { char ch ; do { ch= in.get() ; } while ( in && ch != delim ) ; if ( ! in ) throw runtime_error( "EOF in scanpast()" ) ; } Mesh::Mesh( ifstream& meshx ) // Load mesh object from X file Mesh {... MeshNormals{...}}. { try { // Read vertices, keeping track of greatest distance from origin (radius of bounding sphere). int numVertices ; scanpast( meshx, '{' ) ; meshx >> numVertices ; scanpast( meshx, ';' ) ; _vertices.resize( numVertices ) ; _radius= 0 ; for ( int i=0 ; i < numVertices ; ++i ) { // Read and store vertex coordinates. double x,y,z ; meshx >> x ; scanpast( meshx, ';' ) ; meshx >> y ; scanpast( meshx, ';' ) ; meshx >> z ; scanpast( meshx, ';' ) ; Point3 point( x, y, z ) ; _vertices[i]= point ; // Keep track of largest radius. double r= point.asVector().norm() ; if ( r > _radius ) _radius= r ; scanpast( meshx, ( i < numVertices-1 ) ? ',' : ';' ) ; } // Read face -> vertex-sequence map. int numFaces ; meshx >> numFaces ; scanpast( meshx, ';' ) ; vector face ; _facesToVertices.resize( numFaces ) ; for ( int j=0 ; j < numFaces ; ++j ) { int numVertsThisFace ; meshx >> numVertsThisFace ; scanpast( meshx, ';' ) ; assert( numVertsThisFace > 2 ) ; face.resize( numVertsThisFace ) ; // Read indices into face. int i, k ; for ( k=0 ; k < numVertsThisFace-1 ; ++k ) { meshx >> i ; scanpast( meshx, ',' ) ; face[k]= i ; } meshx >> i ; scanpast( meshx, ';' ) ; scanpast( meshx, ( j < numFaces-1 ? ',' : ';' ) ) ; face[k]= i ; // Add this face into the vector of faces. _facesToVertices[j]= face ; } // Read normals. int numNormals ; scanpast( meshx, '{' ) ; meshx >> numNormals ; scanpast( meshx, ';' ) ; _normals.resize( numNormals ) ; for ( int i=0 ; i < numNormals ; ++i ) { double x,y,z ; meshx >> x ; scanpast( meshx, ';' ) ; meshx >> y ; scanpast( meshx, ';' ) ; meshx >> z ; scanpast( meshx, ';' ) ; scanpast( meshx, ( i < numNormals-1 ) ? ',' : ';' ) ; _normals[i]= Vector3( x, y, z ) ; } // Read face -> vertex-sequence map. meshx >> numFaces ; scanpast( meshx, ';' ) ; _facesToNormals.resize( numFaces ) ; for ( int j=0 ; j < numFaces ; ++j ) { int numVertsThisFace ; meshx >> numVertsThisFace ; scanpast( meshx, ';' ) ; assert( numVertsThisFace > 2 ) ; face.resize( numVertsThisFace ) ; // Read indices into face. int i, k ; for ( k=0 ; k < numVertsThisFace-1 ; ++k ) { meshx >> i ; scanpast( meshx, ',' ) ; face[k]= i ; } meshx >> i ; scanpast( meshx, ';' ) ; scanpast( meshx, ( j < numFaces-1 ? ',' : ';' ) ) ; face[k]= i ; // Add this face into the vector of faces. _facesToNormals[j]= face ; } } catch ( runtime_error& ex ) { // Would be thrown by scanpast(). cerr << ex.what() << " -- possibly incorrect X file format." << endl ; exit( 1 ) ; } } void Mesh::dump( ostream& out ) const // Print the contents of this mesh in an easily inspectable form. { // Print out all the vertices out << "Vertices" << endl ; int numVertices= getNumVertices() ; for ( int i=0 ; i < numVertices ; ++i ) out << i << "\t" << _vertices[i] << endl ; out << "Radius of bounding sphere: " << _radius << endl ; // Print out all the normals out << "Normals" << endl ; int numNormals= getNumNormals() ; for ( int i=0 ; i < numNormals ; ++i ) out << i << "\t" << _normals[i] << endl ; // Print out all the faces out << "Faces" << endl ; int numFaces= getNumFaces() ; for ( int j=0 ; j < numFaces ; ++j ) { out << "Face " << setw(4) << j << " " ; // Print out the vertex indices for face j cout << "\tvertex indices: " ; const vector& faceV= _facesToVertices[j] ; for ( int kv=0 ; kv < (int) faceV.size() ; ++kv ) out << setw(4) << faceV[kv] << " " ; out << "\tface indices: " ; // Print out the normal indices for face j const vector& faceN= _facesToNormals[j] ; for ( int kn=0 ; kn < (int) faceN.size() ; ++kn ) out << setw(4) << faceN[kn] << " " ; out << endl ; } } int Mesh::makeDisplayList() const // Create an OpenGL display list from this mesh. { int id= glGenLists(1) ; glNewList( id, GL_COMPILE ) ; { int numFaces= getNumFaces() ; for ( int j=0 ; j < numFaces ; ++j ) { const vector& faceV= getFaceV(j) ; // indices into the vertices of face j const vector& faceN= getFaceN(j) ; // indices into the normals of face j int numVertsThisFace= (int) faceV.size() ; assert( numVertsThisFace == (int) faceN.size() ) ; glBegin( GL_POLYGON ) ; for ( int jj=0 ; jj < numVertsThisFace ; ++jj ) { glNormal3dv( getNormal( faceN[jj] ).asArray() ) ; glVertex3dv( getVertex( faceV[jj] ).asArray() ) ; } glEnd() ; } } glEndList() ; return id ; }