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