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