Equalizer 1.0
|
00001 00002 /* Copyright (c) 2007, Tobias Wolf <twolf@access.unizh.ch> 00003 * 2009-2011, Stefan Eilemann <eile@equalizergraphics.com> 00004 * 00005 * Redistribution and use in source and binary forms, with or without 00006 * modification, are permitted provided that the following conditions are met: 00007 * 00008 * - Redistributions of source code must retain the above copyright notice, this 00009 * list of conditions and the following disclaimer. 00010 * - Redistributions in binary form must reproduce the above copyright notice, 00011 * this list of conditions and the following disclaimer in the documentation 00012 * and/or other materials provided with the distribution. 00013 * - Neither the name of Eyescale Software GmbH nor the names of its 00014 * contributors may be used to endorse or promote products derived from this 00015 * software without specific prior written permission. 00016 * 00017 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 00018 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00019 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00020 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 00021 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00022 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 00023 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00024 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00025 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 00026 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00027 * POSSIBILITY OF SUCH DAMAGE. 00028 00029 00030 Implementation of the VertexBufferRoot class. 00031 */ 00032 00033 00034 #include "vertexBufferRoot.h" 00035 #include "vertexBufferState.h" 00036 #include "vertexData.h" 00037 #include <string> 00038 #include <sstream> 00039 #include <fcntl.h> 00040 #include <sys/types.h> 00041 #include <sys/stat.h> 00042 #ifndef _WIN32 00043 # include <sys/mman.h> 00044 #endif 00045 00046 using namespace std; 00047 00048 namespace mesh 00049 { 00050 00051 00052 /* Determine number of bits used by the current architecture. */ 00053 size_t getArchitectureBits(); 00054 /* Determine whether the current architecture is little endian or not. */ 00055 bool isArchitectureLittleEndian(); 00056 /* Construct architecture dependent file name. */ 00057 string getArchitectureFilename( const std::string& filename ); 00058 00059 /* Begin kd-tree setup, go through full range starting with x axis. */ 00060 void VertexBufferRoot::setupTree( VertexData& data ) 00061 { 00062 // data is VertexData, _data is VertexBufferData 00063 _data.clear(); 00064 00065 const Axis axis = data.getLongestAxis( 0, data.triangles.size() ); 00066 00067 VertexBufferNode::setupTree( data, 0, data.triangles.size(), 00068 axis, 0, _data ); 00069 VertexBufferNode::updateBoundingSphere(); 00070 VertexBufferNode::updateRange(); 00071 00072 #if 0 00073 // re-test all points to be in the bounding sphere 00074 Vertex center( _boundingSphere.array ); 00075 float radius = _boundingSphere.w(); 00076 float radiusSquared = radius * radius; 00077 for( size_t offset = 0; offset < _data.vertices.size(); ++offset ) 00078 { 00079 const Vertex& vertex = _data.vertices[ offset ]; 00080 00081 const Vertex centerToPoint = vertex - center; 00082 const float distanceSquared = centerToPoint.squared_length(); 00083 EQASSERTINFO( distanceSquared <= radiusSquared, 00084 distanceSquared << " > " << radiusSquared ); 00085 } 00086 #endif 00087 } 00088 00089 00090 /* Set up the common OpenGL state for rendering of all nodes. */ 00091 void VertexBufferRoot::beginRendering( VertexBufferState& state ) const 00092 { 00093 switch( state.getRenderMode() ) 00094 { 00095 #ifdef GL_ARB_vertex_buffer_object 00096 case RENDER_MODE_BUFFER_OBJECT: 00097 glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT ); 00098 glEnableClientState( GL_VERTEX_ARRAY ); 00099 glEnableClientState( GL_NORMAL_ARRAY ); 00100 if( state.useColors() ) 00101 glEnableClientState( GL_COLOR_ARRAY ); 00102 #endif 00103 case RENDER_MODE_DISPLAY_LIST: 00104 case RENDER_MODE_IMMEDIATE: 00105 default: 00106 ; 00107 } 00108 } 00109 00110 00111 /* Delegate rendering to node routine. */ 00112 void VertexBufferRoot::render( VertexBufferState& state ) const 00113 { 00114 VertexBufferNode::render( state ); 00115 } 00116 00117 00118 /* Tear down the common OpenGL state for rendering of all nodes. */ 00119 void VertexBufferRoot::endRendering( VertexBufferState& state ) const 00120 { 00121 switch( state.getRenderMode() ) 00122 { 00123 #ifdef GL_ARB_vertex_buffer_object 00124 case RENDER_MODE_BUFFER_OBJECT: 00125 { 00126 // deactivate VBO and EBO use 00127 #define glewGetContext state.glewGetContext 00128 glBindBuffer( GL_ARRAY_BUFFER_ARB, 0); 00129 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER_ARB, 0); 00130 glPopClientAttrib(); 00131 } 00132 #endif 00133 case RENDER_MODE_DISPLAY_LIST: 00134 case RENDER_MODE_IMMEDIATE: 00135 default: 00136 ; 00137 } 00138 } 00139 00140 00141 /* Determine number of bits used by the current architecture. */ 00142 size_t getArchitectureBits() 00143 { 00144 return ( sizeof( void* ) * 8 ); 00145 } 00146 00147 00148 /* Determine whether the current architecture is little endian or not. */ 00149 bool isArchitectureLittleEndian() 00150 { 00151 unsigned char test[2] = { 1, 0 }; 00152 short* x = reinterpret_cast< short* >( test ); 00153 return ( *x == 1 ); 00154 } 00155 00156 00157 /* Construct architecture dependent file name. */ 00158 string getArchitectureFilename( const std::string& filename ) 00159 { 00160 ostringstream oss; 00161 oss << filename << ( isArchitectureLittleEndian() ? ".le" : ".be" ); 00162 oss << getArchitectureBits() << ".bin"; 00163 return oss.str(); 00164 } 00165 00166 00167 /* Functions extracted out of readFromFile to enhance readability. */ 00168 bool VertexBufferRoot::_constructFromPly( const std::string& filename ) 00169 { 00170 MESHINFO << "Constructing new from PLY file." << endl; 00171 00172 VertexData data; 00173 if( _invertFaces ) 00174 data.useInvertedFaces(); 00175 if( !data.readPlyFile( filename ) ) 00176 { 00177 MESHERROR << "Unable to load PLY file." << endl; 00178 return false; 00179 } 00180 00181 data.calculateNormals(); 00182 data.scale( 2.0f ); 00183 setupTree( data ); 00184 if( !writeToFile( filename )) 00185 MESHWARN << "Unable to write binary representation." << endl; 00186 00187 return true; 00188 } 00189 00190 bool VertexBufferRoot::_readBinary( std::string filename ) 00191 { 00192 #ifdef WIN32 00193 00194 // replace dir delimiters since '\' is often used as escape char 00195 for( size_t i=0; i<filename.length(); ++i ) 00196 if( filename[i] == '\\' ) 00197 filename[i] = '/'; 00198 00199 // try to open binary file 00200 HANDLE file = CreateFile( filename.c_str(), GENERIC_READ, FILE_SHARE_READ, 00201 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ); 00202 if( file == INVALID_HANDLE_VALUE ) 00203 return false; 00204 00205 MESHINFO << "Reading cached binary representation." << endl; 00206 00207 // create a file mapping 00208 HANDLE map = CreateFileMapping( file, 0, PAGE_READONLY, 0, 0, 00209 filename.c_str( )); 00210 CloseHandle( file ); 00211 if( !map ) 00212 { 00213 MESHERROR << "Unable to read binary file, file mapping failed." 00214 << endl; 00215 return false; 00216 } 00217 00218 // get a view of the mapping 00219 char* addr = static_cast< char* >( MapViewOfFile( map, FILE_MAP_READ, 0, 00220 0, 0 ) ); 00221 bool result = false; 00222 00223 if( addr ) 00224 { 00225 try 00226 { 00227 fromMemory( addr ); 00228 result = true; 00229 } 00230 catch( exception& e ) 00231 { 00232 MESHERROR << "Unable to read binary file, an exception occured: " 00233 << e.what() << endl; 00234 } 00235 UnmapViewOfFile( addr ); 00236 } 00237 else 00238 { 00239 MESHERROR << "Unable to read binary file, memory mapping failed." 00240 << endl; 00241 return false; 00242 } 00243 00244 CloseHandle( map ); 00245 return result; 00246 00247 #else 00248 // try to open binary file 00249 int fd = open( filename.c_str(), O_RDONLY ); 00250 if( fd < 0 ) 00251 return false; 00252 00253 // retrieving file information 00254 struct stat status; 00255 fstat( fd, &status ); 00256 00257 // create memory mapped file 00258 char* addr = static_cast< char* >( mmap( 0, status.st_size, PROT_READ, 00259 MAP_SHARED, fd, 0 ) ); 00260 bool result = false; 00261 if( addr != MAP_FAILED ) 00262 { 00263 try 00264 { 00265 fromMemory( addr ); 00266 result = true; 00267 } 00268 catch( exception& e ) 00269 { 00270 MESHERROR << "Unable to read binary file, an exception occured: " 00271 << e.what() << endl; 00272 } 00273 munmap( addr, status.st_size ); 00274 } 00275 else 00276 { 00277 MESHERROR << "Unable to read binary file, memory mapping failed." 00278 << endl; 00279 } 00280 00281 close( fd ); 00282 return result; 00283 #endif 00284 } 00285 00286 00287 /* Read binary kd-tree representation, construct from ply if unavailable. */ 00288 bool VertexBufferRoot::readFromFile( const std::string& filename ) 00289 { 00290 if( _readBinary( getArchitectureFilename( filename ))) 00291 { 00292 _name = filename; 00293 return true; 00294 } 00295 if( _constructFromPly( filename )) 00296 { 00297 _name = filename; 00298 return true; 00299 } 00300 return false; 00301 } 00302 00303 /* Write binary representation of the kd-tree to file. */ 00304 bool VertexBufferRoot::writeToFile( const std::string& filename ) 00305 { 00306 bool result = false; 00307 00308 ofstream output( getArchitectureFilename( filename ).c_str(), 00309 ios::out | ios::binary ); 00310 if( output ) 00311 { 00312 // enable exceptions on stream errors 00313 output.exceptions( ofstream::failbit | ofstream::badbit ); 00314 try 00315 { 00316 toStream( output ); 00317 result = true; 00318 } 00319 catch( exception& e ) 00320 { 00321 MESHERROR << "Unable to write binary file, an exception " 00322 << "occured: " << e.what() << endl; 00323 } 00324 output.close(); 00325 } 00326 else 00327 { 00328 MESHERROR << "Unable to create binary file." << endl; 00329 } 00330 00331 return result; 00332 } 00333 00334 00335 /* Read root node from memory and continue with other nodes. */ 00336 void VertexBufferRoot::fromMemory( char* start ) 00337 { 00338 char** addr = &start; 00339 size_t version; 00340 memRead( reinterpret_cast< char* >( &version ), addr, sizeof( size_t ) ); 00341 if( version != FILE_VERSION ) 00342 throw MeshException( "Error reading binary file. Version in file " 00343 "does not match the expected version." ); 00344 size_t nodeType; 00345 memRead( reinterpret_cast< char* >( &nodeType ), addr, sizeof( size_t ) ); 00346 if( nodeType != ROOT_TYPE ) 00347 throw MeshException( "Error reading binary file. Expected the root " 00348 "node, but found something else instead." ); 00349 _data.fromMemory( addr ); 00350 VertexBufferNode::fromMemory( addr, _data ); 00351 memRead( reinterpret_cast< char* >( &nodeType ), addr, sizeof( size_t ) ); 00352 if( nodeType != ROOT_TYPE ) 00353 throw MeshException( "Error reading binary file. Expected a custom " 00354 "EOF marker, but found something else instead." ); 00355 } 00356 00357 00358 /* Write root node to output stream and continue with other nodes. */ 00359 void VertexBufferRoot::toStream( std:: ostream& os ) 00360 { 00361 size_t version = FILE_VERSION; 00362 os.write( reinterpret_cast< char* >( &version ), sizeof( size_t ) ); 00363 size_t nodeType = ROOT_TYPE; 00364 os.write( reinterpret_cast< char* >( &nodeType ), sizeof( size_t ) ); 00365 _data.toStream( os ); 00366 VertexBufferNode::toStream( os ); 00367 os.write( reinterpret_cast< char* >( &nodeType ), sizeof( size_t ) ); 00368 } 00369 00370 }