Equalizer
1.2.1
|
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 00031 #include "vertexBufferRoot.h" 00032 #include "vertexBufferState.h" 00033 #include "vertexData.h" 00034 #include <string> 00035 #include <sstream> 00036 #include <fcntl.h> 00037 #include <sys/types.h> 00038 #include <sys/stat.h> 00039 #ifndef _WIN32 00040 # include <sys/mman.h> 00041 #endif 00042 00043 namespace mesh 00044 { 00045 00046 typedef vmml::frustum_culler< float > FrustumCuller; 00047 00048 /* Determine number of bits used by the current architecture. */ 00049 size_t getArchitectureBits(); 00050 /* Determine whether the current architecture is little endian or not. */ 00051 bool isArchitectureLittleEndian(); 00052 /* Construct architecture dependent file name. */ 00053 std::string getArchitectureFilename( const std::string& filename ); 00054 00055 /* Begin kd-tree setup, go through full range starting with x axis. */ 00056 void VertexBufferRoot::setupTree( VertexData& data ) 00057 { 00058 // data is VertexData, _data is VertexBufferData 00059 _data.clear(); 00060 00061 const Axis axis = data.getLongestAxis( 0, data.triangles.size() ); 00062 00063 VertexBufferNode::setupTree( data, 0, data.triangles.size(), 00064 axis, 0, _data ); 00065 VertexBufferNode::updateBoundingSphere(); 00066 VertexBufferNode::updateRange(); 00067 00068 #if 0 00069 // re-test all points to be in the bounding sphere 00070 Vertex center( _boundingSphere.array ); 00071 float radius = _boundingSphere.w(); 00072 float radiusSquared = radius * radius; 00073 for( size_t offset = 0; offset < _data.vertices.size(); ++offset ) 00074 { 00075 const Vertex& vertex = _data.vertices[ offset ]; 00076 00077 const Vertex centerToPoint = vertex - center; 00078 const float distanceSquared = centerToPoint.squared_length(); 00079 EQASSERTINFO( distanceSquared <= radiusSquared, 00080 distanceSquared << " > " << radiusSquared ); 00081 } 00082 #endif 00083 } 00084 00085 // #define LOGCULL 00086 void VertexBufferRoot::cullDraw( VertexBufferState& state ) const 00087 { 00088 _beginRendering( state ); 00089 00090 #ifdef LOGCULL 00091 size_t verticesRendered = 0; 00092 size_t verticesOverlap = 0; 00093 #endif 00094 00095 FrustumCuller culler; 00096 culler.setup( state.getProjectionModelViewMatrix( )); 00097 00098 const Range& range = state.getRange(); 00099 00100 // start with root node 00101 std::vector< const mesh::VertexBufferBase* > candidates; 00102 candidates.push_back( this ); 00103 00104 while( !candidates.empty() ) 00105 { 00106 if( state.stopRendering( )) 00107 return; 00108 00109 const mesh::VertexBufferBase* treeNode = candidates.back(); 00110 candidates.pop_back(); 00111 00112 // completely out of range check 00113 if( treeNode->getRange()[0] >= range[1] || 00114 treeNode->getRange()[1] < range[0] ) 00115 continue; 00116 00117 // bounding sphere view frustum culling 00118 const vmml::Visibility visibility = 00119 culler.test_sphere( treeNode->getBoundingSphere( )); 00120 00121 switch( visibility ) 00122 { 00123 case vmml::VISIBILITY_FULL: 00124 // if fully visible and fully in range, render it 00125 if( treeNode->getRange()[0] >= range[0] && 00126 treeNode->getRange()[1] < range[1] ) 00127 { 00128 treeNode->draw( state ); 00129 //treeNode->drawBoundingSphere( state ); 00130 #ifdef LOGCULL 00131 verticesRendered += treeNode->getNumberOfVertices(); 00132 #endif 00133 break; 00134 } 00135 // partial range, fall through to partial visibility 00136 00137 case vmml::VISIBILITY_PARTIAL: 00138 { 00139 const mesh::VertexBufferBase* left = treeNode->getLeft(); 00140 const mesh::VertexBufferBase* right = treeNode->getRight(); 00141 00142 if( !left && !right ) 00143 { 00144 if( treeNode->getRange()[0] >= range[0] ) 00145 { 00146 treeNode->draw( state ); 00147 //treeNode->drawBoundingSphere( state ); 00148 #ifdef LOGCULL 00149 verticesRendered += treeNode->getNumberOfVertices(); 00150 if( visibility == vmml::VISIBILITY_PARTIAL ) 00151 verticesOverlap += treeNode->getNumberOfVertices(); 00152 #endif 00153 } 00154 // else drop, to be drawn by 'previous' channel 00155 } 00156 else 00157 { 00158 if( left ) 00159 candidates.push_back( left ); 00160 if( right ) 00161 candidates.push_back( right ); 00162 } 00163 break; 00164 } 00165 case vmml::VISIBILITY_NONE: 00166 // do nothing 00167 break; 00168 } 00169 } 00170 00171 _endRendering( state ); 00172 00173 #ifdef LOGCULL 00174 const size_t verticesTotal = model->getNumberOfVertices(); 00175 MESHINFO 00176 << getName() << " rendered " << verticesRendered * 100 / verticesTotal 00177 << "% of model, overlap <= " << verticesOverlap * 100 / verticesTotal 00178 << "%" << std::endl; 00179 #endif 00180 } 00181 00182 00183 /* Set up the common OpenGL state for rendering of all nodes. */ 00184 void VertexBufferRoot::_beginRendering( VertexBufferState& state ) const 00185 { 00186 switch( state.getRenderMode() ) 00187 { 00188 #ifdef GL_ARB_vertex_buffer_object 00189 case RENDER_MODE_BUFFER_OBJECT: 00190 glPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT ); 00191 glEnableClientState( GL_VERTEX_ARRAY ); 00192 glEnableClientState( GL_NORMAL_ARRAY ); 00193 if( state.useColors() ) 00194 glEnableClientState( GL_COLOR_ARRAY ); 00195 #endif 00196 case RENDER_MODE_DISPLAY_LIST: 00197 case RENDER_MODE_IMMEDIATE: 00198 default: 00199 ; 00200 } 00201 } 00202 00203 00204 /* Delegate rendering to node routine. */ 00205 void VertexBufferRoot::draw( VertexBufferState& state ) const 00206 { 00207 VertexBufferNode::draw( state ); 00208 } 00209 00210 00211 /* Tear down the common OpenGL state for rendering of all nodes. */ 00212 void VertexBufferRoot::_endRendering( VertexBufferState& state ) const 00213 { 00214 switch( state.getRenderMode() ) 00215 { 00216 #ifdef GL_ARB_vertex_buffer_object 00217 case RENDER_MODE_BUFFER_OBJECT: 00218 { 00219 // deactivate VBO and EBO use 00220 #define glewGetContext state.glewGetContext 00221 glBindBuffer( GL_ARRAY_BUFFER_ARB, 0); 00222 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER_ARB, 0); 00223 glPopClientAttrib(); 00224 } 00225 #endif 00226 case RENDER_MODE_DISPLAY_LIST: 00227 case RENDER_MODE_IMMEDIATE: 00228 default: 00229 ; 00230 } 00231 } 00232 00233 00234 /* Determine number of bits used by the current architecture. */ 00235 size_t getArchitectureBits() 00236 { 00237 return ( sizeof( void* ) * 8 ); 00238 } 00239 00240 00241 /* Determine whether the current architecture is little endian or not. */ 00242 bool isArchitectureLittleEndian() 00243 { 00244 unsigned char test[2] = { 1, 0 }; 00245 short* x = reinterpret_cast< short* >( test ); 00246 return ( *x == 1 ); 00247 } 00248 00249 00250 /* Construct architecture dependent file name. */ 00251 std::string getArchitectureFilename( const std::string& filename ) 00252 { 00253 std::ostringstream oss; 00254 oss << filename << ( isArchitectureLittleEndian() ? ".le" : ".be" ); 00255 oss << getArchitectureBits() << ".bin"; 00256 return oss.str(); 00257 } 00258 00259 00260 /* Functions extracted out of readFromFile to enhance readability. */ 00261 bool VertexBufferRoot::_constructFromPly( const std::string& filename ) 00262 { 00263 MESHINFO << "Constructing new from PLY file." << std::endl; 00264 00265 VertexData data; 00266 if( _invertFaces ) 00267 data.useInvertedFaces(); 00268 if( !data.readPlyFile( filename ) ) 00269 { 00270 MESHERROR << "Unable to load PLY file." << std::endl; 00271 return false; 00272 } 00273 00274 data.calculateNormals(); 00275 data.scale( 2.0f ); 00276 setupTree( data ); 00277 if( !writeToFile( filename )) 00278 MESHWARN << "Unable to write binary representation." << std::endl; 00279 00280 return true; 00281 } 00282 00283 bool VertexBufferRoot::_readBinary( std::string filename ) 00284 { 00285 #ifdef WIN32 00286 00287 // replace dir delimiters since '\' is often used as escape char 00288 for( size_t i=0; i<filename.length(); ++i ) 00289 if( filename[i] == '\\' ) 00290 filename[i] = '/'; 00291 00292 // try to open binary file 00293 HANDLE file = CreateFile( filename.c_str(), GENERIC_READ, FILE_SHARE_READ, 00294 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 ); 00295 if( file == INVALID_HANDLE_VALUE ) 00296 return false; 00297 00298 MESHINFO << "Reading cached binary representation." << std::endl; 00299 00300 // create a file mapping 00301 HANDLE map = CreateFileMapping( file, 0, PAGE_READONLY, 0, 0, 00302 filename.c_str( )); 00303 CloseHandle( file ); 00304 if( !map ) 00305 { 00306 MESHERROR << "Unable to read binary file, file mapping failed." 00307 << std::endl; 00308 return false; 00309 } 00310 00311 // get a view of the mapping 00312 char* addr = static_cast< char* >( MapViewOfFile( map, FILE_MAP_READ, 0, 00313 0, 0 ) ); 00314 bool result = false; 00315 00316 if( addr ) 00317 { 00318 try 00319 { 00320 fromMemory( addr ); 00321 result = true; 00322 } 00323 catch( const std::exception& e ) 00324 { 00325 MESHERROR << "Unable to read binary file, an exception occured: " 00326 << e.what() << std::endl; 00327 } 00328 UnmapViewOfFile( addr ); 00329 } 00330 else 00331 { 00332 MESHERROR << "Unable to read binary file, memory mapping failed." 00333 << std::endl; 00334 return false; 00335 } 00336 00337 CloseHandle( map ); 00338 return result; 00339 00340 #else 00341 // try to open binary file 00342 int fd = open( filename.c_str(), O_RDONLY ); 00343 if( fd < 0 ) 00344 return false; 00345 00346 // retrieving file information 00347 struct stat status; 00348 fstat( fd, &status ); 00349 00350 // create memory mapped file 00351 char* addr = static_cast< char* >( mmap( 0, status.st_size, PROT_READ, 00352 MAP_SHARED, fd, 0 ) ); 00353 bool result = false; 00354 if( addr != MAP_FAILED ) 00355 { 00356 try 00357 { 00358 fromMemory( addr ); 00359 result = true; 00360 } 00361 catch( const std::exception& e ) 00362 { 00363 MESHERROR << "Unable to read binary file, an exception occured: " 00364 << e.what() << std::endl; 00365 } 00366 munmap( addr, status.st_size ); 00367 } 00368 else 00369 { 00370 MESHERROR << "Unable to read binary file, memory mapping failed." 00371 << std::endl; 00372 } 00373 00374 close( fd ); 00375 return result; 00376 #endif 00377 } 00378 00379 00380 /* Read binary kd-tree representation, construct from ply if unavailable. */ 00381 bool VertexBufferRoot::readFromFile( const std::string& filename ) 00382 { 00383 if( _readBinary( getArchitectureFilename( filename ))) 00384 { 00385 _name = filename; 00386 return true; 00387 } 00388 if( _constructFromPly( filename )) 00389 { 00390 _name = filename; 00391 return true; 00392 } 00393 return false; 00394 } 00395 00396 /* Write binary representation of the kd-tree to file. */ 00397 bool VertexBufferRoot::writeToFile( const std::string& filename ) 00398 { 00399 bool result = false; 00400 00401 std::ofstream output( getArchitectureFilename( filename ).c_str(), 00402 std::ios::out | std::ios::binary ); 00403 if( output ) 00404 { 00405 // enable exceptions on stream errors 00406 output.exceptions( std::ofstream::failbit | std::ofstream::badbit ); 00407 try 00408 { 00409 toStream( output ); 00410 result = true; 00411 } 00412 catch( const std::exception& e ) 00413 { 00414 MESHERROR << "Unable to write binary file, an exception " 00415 << "occured: " << e.what() << std::endl; 00416 } 00417 output.close(); 00418 } 00419 else 00420 { 00421 MESHERROR << "Unable to create binary file." << std::endl; 00422 } 00423 00424 return result; 00425 } 00426 00427 00428 /* Read root node from memory and continue with other nodes. */ 00429 void VertexBufferRoot::fromMemory( char* start ) 00430 { 00431 char** addr = &start; 00432 size_t version; 00433 memRead( reinterpret_cast< char* >( &version ), addr, sizeof( size_t ) ); 00434 if( version != FILE_VERSION ) 00435 throw MeshException( "Error reading binary file. Version in file " 00436 "does not match the expected version." ); 00437 size_t nodeType; 00438 memRead( reinterpret_cast< char* >( &nodeType ), addr, sizeof( size_t ) ); 00439 if( nodeType != ROOT_TYPE ) 00440 throw MeshException( "Error reading binary file. Expected the root " 00441 "node, but found something else instead." ); 00442 _data.fromMemory( addr ); 00443 VertexBufferNode::fromMemory( addr, _data ); 00444 memRead( reinterpret_cast< char* >( &nodeType ), addr, sizeof( size_t ) ); 00445 if( nodeType != ROOT_TYPE ) 00446 throw MeshException( "Error reading binary file. Expected a custom " 00447 "EOF marker, but found something else instead." ); 00448 } 00449 00450 00451 /* Write root node to output stream and continue with other nodes. */ 00452 void VertexBufferRoot::toStream( std:: ostream& os ) 00453 { 00454 size_t version = FILE_VERSION; 00455 os.write( reinterpret_cast< char* >( &version ), sizeof( size_t ) ); 00456 size_t nodeType = ROOT_TYPE; 00457 os.write( reinterpret_cast< char* >( &nodeType ), sizeof( size_t ) ); 00458 _data.toStream( os ); 00459 VertexBufferNode::toStream( os ); 00460 os.write( reinterpret_cast< char* >( &nodeType ), sizeof( size_t ) ); 00461 } 00462 00463 }