Equalizer  1.4.1
eqPly/vertexBufferRoot.cpp
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 }
Generated on Mon Nov 26 2012 14:41:50 for Equalizer 1.4.1 by  doxygen 1.7.6.1