vertexBufferLeaf.cpp

00001 /*  
00002     vertexBufferLeaf.cpp
00003     Copyright (c) 2007, Tobias Wolf <twolf@access.unizh.ch>
00004     Copyright (c) 2008-2009, Stefan Eilemann <eile@equalizergraphics.com>
00005   *
00006  * This library is free software; you can redistribute it and/or modify it under
00007  * the terms of the GNU Lesser General Public License version 2.1 as published
00008  * by the Free Software Foundation.
00009  *  
00010  * This library is distributed in the hope that it will be useful, but WITHOUT
00011  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
00012  * FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
00013  * details.
00014  * 
00015  * You should have received a copy of the GNU Lesser General Public License
00016  * along with this library; if not, write to the Free Software Foundation, Inc.,
00017  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00018   
00019     
00020     Implementation of the VertexBufferLeaf class.
00021 */
00022 
00023 
00024 #include "vertexBufferLeaf.h"
00025 #include "vertexBufferData.h"
00026 #include "vertexBufferState.h"
00027 #include "vertexData.h"
00028 #include <map>
00029 
00030 using namespace std;
00031 
00032 namespace mesh
00033 {
00034 
00035 /*  Finish partial setup - sort, reindex and merge into global data.  */
00036 void VertexBufferLeaf::setupTree( VertexData& data, const Index start,
00037                                   const Index length, const Axis axis,
00038                                   const size_t depth,
00039                                   VertexBufferData& globalData )
00040 {
00041     #ifndef NDEBUG
00042     MESHINFO << "Entering VertexBufferLeaf::setupTree"
00043              << "( " << start << ", " << length << ", " << axis << ", " 
00044              << depth << " )." << endl;
00045     #endif
00046     
00047     data.sort( start, length, axis );
00048     _vertexStart = globalData.vertices.size();
00049     _vertexLength = 0;
00050     _indexStart = globalData.indices.size();
00051     _indexLength = 0;
00052     
00053     const bool hasColors = ( data.colors.size() > 0 ); 
00054     
00055     // stores the new indices (relative to _start)
00056     map< Index, ShortIndex > newIndex;
00057     
00058     for( Index t = 0; t < length; ++t )
00059     {
00060         for( Index v = 0; v < 3; ++v )
00061         {
00062             Index i = data.triangles[start + t][v];
00063             if( newIndex.find( i ) == newIndex.end() )
00064             {
00065                 newIndex[i] = _vertexLength++;
00066                 // assert number of vertices does not exceed SmallIndex range
00067                 MESHASSERT( _vertexLength );
00068                 globalData.vertices.push_back( data.vertices[i] );
00069                 if( hasColors )
00070                     globalData.colors.push_back( data.colors[i] );
00071                 globalData.normals.push_back( data.normals[i] );
00072             }
00073             globalData.indices.push_back( newIndex[i] );
00074             ++_indexLength; 
00075         }
00076     }
00077     
00078     #ifndef NDEBUG
00079     MESHINFO << "Exiting VertexBufferLeaf::setupTree"
00080              << "( " << _indexStart << ", " << _indexLength << "; " 
00081              << _vertexStart << ", " << _vertexLength << " )." << endl;
00082     #else
00083     MESHINFO << "Leaf " << this << " contains " << _vertexLength << " vertices"
00084              << " and " << _indexLength / 3 << " triangles." << endl;
00085     #endif
00086 }
00087 
00088 
00089 /*  Compute the bounding sphere of the leaf's indexed vertices.  */
00090 const BoundingSphere& VertexBufferLeaf::updateBoundingSphere()
00091 {
00092     // We determine a bounding sphere by:
00093     // 1) Using the inner sphere of the dominant axis of the bounding box as an
00094     //    estimate
00095     // 2) Test all points to be in that sphere
00096     // 3) Expand the sphere to contain all points outside.
00097 
00098 
00099     // 1a) initialize and compute a bounding box
00100     BoundingBox boundingBox;
00101     boundingBox[0] = 
00102         _globalData.vertices[ _vertexStart + _globalData.indices[_indexStart] ];
00103     boundingBox[1] = 
00104         _globalData.vertices[ _vertexStart + _globalData.indices[_indexStart] ];
00105 
00106     for( Index offset = 1; offset < _indexLength; ++offset )
00107     {
00108         const Vertex& vertex = 
00109             _globalData.vertices[ _vertexStart + 
00110                                   _globalData.indices[_indexStart + offset] ];
00111 
00112         boundingBox[0][0] = min( boundingBox[0][0], vertex[0] );
00113         boundingBox[1][0] = max( boundingBox[1][0], vertex[0] );
00114         boundingBox[0][1] = min( boundingBox[0][1], vertex[1] );
00115         boundingBox[1][1] = max( boundingBox[1][1], vertex[1] );
00116         boundingBox[0][2] = min( boundingBox[0][2], vertex[2] );
00117         boundingBox[1][2] = max( boundingBox[1][2], vertex[2] );
00118     }
00119     
00120     // 1b) get inner sphere of bounding box as an initial estimate
00121     _boundingSphere.x() = 
00122                              ( boundingBox[0].x() + boundingBox[1].x() ) * 0.5f;
00123     _boundingSphere.y() = 
00124                              ( boundingBox[0].y() + boundingBox[1].y() ) * 0.5f;
00125     _boundingSphere.z() = 
00126                              ( boundingBox[0].z() + boundingBox[1].z() ) * 0.5f;
00127 
00128     _boundingSphere.w()  = EQ_MAX( boundingBox[1].x() - boundingBox[0].x(),
00129                                       boundingBox[1].y() - boundingBox[0].y() );
00130     _boundingSphere.w()  = EQ_MAX( boundingBox[1].z() - boundingBox[0].z(),
00131                                       _boundingSphere.w() );
00132     _boundingSphere.w() *= .5f;
00133 
00134     float  radius        = _boundingSphere.w();
00135     float  radiusSquared =  radius * radius;
00136     Vertex center( _boundingSphere.array );
00137 
00138     // 2) test all points to be in the estimated bounding sphere
00139     for( Index offset = 0; offset < _indexLength; ++offset )
00140     {
00141         const Vertex& vertex = 
00142             _globalData.vertices[ _vertexStart + 
00143                                   _globalData.indices[_indexStart + offset] ];
00144         
00145         const Vertex centerToPoint   = vertex - center;
00146         const float  distanceSquared = centerToPoint.squared_length();
00147         if( distanceSquared <= radiusSquared ) // point is inside existing BS
00148             continue;
00149 
00150         // 3) expand sphere to contain 'outside' points
00151         const float distance = sqrtf( distanceSquared );
00152         const float delta    = distance - radius;
00153 
00154         radius        = ( radius + distance ) * .5f;
00155         radiusSquared = radius * radius;
00156         const Vertex normdelta = normalize( centerToPoint ) * ( 0.5f * delta );
00157   
00158         center       += normdelta;
00159 
00160         EQASSERTINFO( Vertex( vertex-center ).squared_length() <= 
00161                       ( radiusSquared + 2.f* numeric_limits<float>::epsilon( )),
00162                       vertex << " c " << center << " r " << radius << " (" 
00163                              << Vertex( vertex-center ).length() << ")" );
00164     }
00165 
00166     // store optimal bounding sphere 
00167     _boundingSphere.x() = center.x();
00168     _boundingSphere.y() = center.y();
00169     _boundingSphere.z() = center.z();
00170     _boundingSphere.w() = radius;
00171 
00172 #ifndef NDEBUG
00173     MESHINFO << "Exiting VertexBufferLeaf::updateBoundingSphere" 
00174              << "( " << _boundingSphere << " )." << endl;
00175 #endif
00176     
00177     return _boundingSphere;
00178 }
00179 
00180 
00181 /*  Compute the range of this child.  */
00182 void VertexBufferLeaf::updateRange()
00183 {
00184     _range[0] = 1.0f * _indexStart / _globalData.indices.size();
00185     _range[1] = _range[0] + 1.0f * _indexLength / _globalData.indices.size();
00186     
00187     #ifndef NDEBUG
00188     MESHINFO << "Exiting VertexBufferLeaf::updateRange" 
00189              << "( " << _range[0] << ", " << _range[1] << " )." << endl;
00190     #endif
00191 }
00192 
00193 #define glewGetContext state.glewGetContext
00194 
00195 /*  Set up rendering of the leaf nodes.  */
00196 void VertexBufferLeaf::setupRendering( VertexBufferState& state,
00197                                        GLuint* data ) const
00198 {
00199     switch( state.getRenderMode() )
00200     {
00201     case RENDER_MODE_IMMEDIATE:
00202         break;
00203 
00204     case RENDER_MODE_BUFFER_OBJECT:
00205     {
00206         const char* charThis = reinterpret_cast< const char* >( this );
00207         
00208         if( data[VERTEX_OBJECT] == state.INVALID )
00209             data[VERTEX_OBJECT] = state.newBufferObject( charThis + 0 );
00210         glBindBuffer( GL_ARRAY_BUFFER, data[VERTEX_OBJECT] );
00211         glBufferData( GL_ARRAY_BUFFER, _vertexLength * sizeof( Vertex ),
00212                         &_globalData.vertices[_vertexStart], GL_STATIC_DRAW );
00213         
00214         if( data[NORMAL_OBJECT] == state.INVALID )
00215             data[NORMAL_OBJECT] = state.newBufferObject( charThis + 1 );
00216         glBindBuffer( GL_ARRAY_BUFFER, data[NORMAL_OBJECT] );
00217         glBufferData( GL_ARRAY_BUFFER, _vertexLength * sizeof( Normal ),
00218                         &_globalData.normals[_vertexStart], GL_STATIC_DRAW );
00219         
00220         if( data[COLOR_OBJECT] == state.INVALID )
00221             data[COLOR_OBJECT] = state.newBufferObject( charThis + 2 );
00222         if( state.useColors() )
00223         {
00224             glBindBuffer( GL_ARRAY_BUFFER, data[COLOR_OBJECT] );
00225             glBufferData( GL_ARRAY_BUFFER, _vertexLength * sizeof( Color ),
00226                             &_globalData.colors[_vertexStart], GL_STATIC_DRAW );
00227         }
00228         
00229         if( data[INDEX_OBJECT] == state.INVALID )
00230             data[INDEX_OBJECT] = state.newBufferObject( charThis + 3 );
00231         glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, data[INDEX_OBJECT] );
00232         glBufferData( GL_ELEMENT_ARRAY_BUFFER, 
00233                         _indexLength * sizeof( ShortIndex ),
00234                         &_globalData.indices[_indexStart], GL_STATIC_DRAW );
00235         
00236         break;
00237     }        
00238     case RENDER_MODE_DISPLAY_LIST:
00239     default:
00240     {
00241         if( data[0] == state.INVALID )
00242         {
00243             char* key = (char*)( this );
00244             if( state.useColors( ))
00245                 ++key;
00246             data[0] = state.newDisplayList( key );
00247         }
00248         glNewList( data[0], GL_COMPILE );
00249         renderImmediate( state );
00250         glEndList();
00251         break;
00252     }
00253     }
00254 }
00255 
00256 
00257 /*  Render the leaf.  */
00258 void VertexBufferLeaf::render( VertexBufferState& state ) const
00259 {
00260     switch( state.getRenderMode() )
00261     {
00262     case RENDER_MODE_IMMEDIATE:
00263         renderImmediate( state );
00264         return;
00265     case RENDER_MODE_BUFFER_OBJECT:
00266         renderBufferObject( state );
00267         return;
00268     case RENDER_MODE_DISPLAY_LIST:
00269     default:
00270         renderDisplayList( state );
00271         return;
00272     }
00273 }
00274 
00275 
00276 /*  Render the leaf with buffer objects.  */
00277 void VertexBufferLeaf::renderBufferObject( VertexBufferState& state ) const
00278 {
00279     GLuint buffers[4];
00280     for( int i = 0; i < 4; ++i )
00281         buffers[i] = 
00282             state.getBufferObject( reinterpret_cast< const char* >(this) + i );
00283     if( buffers[VERTEX_OBJECT] == state.INVALID || 
00284         buffers[NORMAL_OBJECT] == state.INVALID || 
00285         buffers[COLOR_OBJECT] == state.INVALID || 
00286         buffers[INDEX_OBJECT] == state.INVALID )
00287 
00288         setupRendering( state, buffers );
00289     
00290     if( state.useColors() )
00291     {
00292         glBindBuffer( GL_ARRAY_BUFFER, buffers[COLOR_OBJECT] );
00293         glColorPointer( 4, GL_UNSIGNED_BYTE, 0, 0 );
00294     }
00295     glBindBuffer( GL_ARRAY_BUFFER, buffers[NORMAL_OBJECT] );
00296     glNormalPointer( GL_FLOAT, 0, 0 );
00297     glBindBuffer( GL_ARRAY_BUFFER, buffers[VERTEX_OBJECT] );
00298     glVertexPointer( 3, GL_FLOAT, 0, 0 );
00299     glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, buffers[INDEX_OBJECT] );
00300     glDrawElements( GL_TRIANGLES, _indexLength, GL_UNSIGNED_SHORT, 0 );
00301 }
00302 
00303 
00304 /*  Render the leaf with a display list.  */
00305 inline
00306 void VertexBufferLeaf::renderDisplayList( VertexBufferState& state ) const
00307 {
00308     char* key = (char*)( this );
00309     if( state.useColors( ))
00310         ++key;
00311 
00312     GLuint displayList = state.getDisplayList( key );
00313 
00314     if( displayList == state.INVALID )
00315         setupRendering( state, &displayList );
00316     
00317     glCallList( displayList );
00318 }
00319 
00320 
00321 /*  Render the leaf with immediate mode primitives or vertex arrays.  */
00322 inline
00323 void VertexBufferLeaf::renderImmediate( VertexBufferState& state ) const
00324 {
00325     glBegin( GL_TRIANGLES );  
00326     for( Index offset = 0; offset < _indexLength; ++offset )
00327     {
00328         const Index i =_vertexStart + _globalData.indices[_indexStart + offset];
00329         if( state.useColors() )
00330             glColor4ubv( &_globalData.colors[i][0] );
00331         glNormal3fv( &_globalData.normals[i][0] );
00332         glVertex3fv( &_globalData.vertices[i][0] );
00333     }
00334     glEnd();
00335     
00336 //    if( state.useColors() )
00337 //        glColorPointer( 4, GL_UNSIGNED_BYTE, 0, 
00338 //                        &_globalData.colors[_vertexStart] );
00339 //    glNormalPointer( GL_FLOAT, 0, &_globalData.normals[_vertexStart] );
00340 //    glVertexPointer( 3, GL_FLOAT, 0, &_globalData.vertices[_vertexStart] );
00341 //    glDrawElements( GL_TRIANGLES, _indexLength, GL_UNSIGNED_SHORT, 
00342 //                    &_globalData.indices[_indexStart] );
00343 }
00344 
00345 
00346 /*  Read leaf node from memory.  */
00347 void VertexBufferLeaf::fromMemory( char** addr, VertexBufferData& globalData )
00348 {
00349     size_t nodeType;
00350     memRead( reinterpret_cast< char* >( &nodeType ), addr, sizeof( size_t ) );
00351     if( nodeType != LEAF_TYPE )
00352         throw MeshException( "Error reading binary file. Expected a leaf "
00353                              "node, but found something else instead." );
00354     VertexBufferBase::fromMemory( addr, globalData );
00355     memRead( reinterpret_cast< char* >( &_vertexStart ), addr, 
00356              sizeof( Index ) );
00357     memRead( reinterpret_cast< char* >( &_vertexLength ), addr, 
00358              sizeof( ShortIndex ) );
00359     memRead( reinterpret_cast< char* >( &_indexStart ), addr, 
00360              sizeof( Index ) );
00361     memRead( reinterpret_cast< char* >( &_indexLength ), addr, 
00362              sizeof( Index ) );
00363 }
00364 
00365 
00366 /*  Write leaf node to output stream.  */
00367 void VertexBufferLeaf::toStream( std::ostream& os )
00368 {
00369     size_t nodeType = LEAF_TYPE;
00370     os.write( reinterpret_cast< char* >( &nodeType ), sizeof( size_t ) );
00371     VertexBufferBase::toStream( os );
00372     os.write( reinterpret_cast< char* >( &_vertexStart ), sizeof( Index ) );
00373     os.write( reinterpret_cast< char* >( &_vertexLength ), sizeof( ShortIndex ) );
00374     os.write( reinterpret_cast< char* >( &_indexStart ), sizeof( Index ) );
00375     os.write( reinterpret_cast< char* >( &_indexLength ), sizeof( Index ) );
00376 }
00377 
00378 }
Generated on Mon Aug 10 18:58:41 2009 for Equalizer 0.9 by  doxygen 1.5.8