Equalizer  1.2.1
eqPly/vertexBufferRoot.cpp
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 }
Generated on Fri Jun 8 2012 15:44:33 for Equalizer 1.2.1 by  doxygen 1.8.0