osgEarth 2.1.1

/home/cube/sources/osgearth/src/osgEarthSymbology/MeshConsolidator.cpp

Go to the documentation of this file.
00001 /* -*-c++-*- */
00002 /* osgEarth - Dynamic map generation toolkit for OpenSceneGraph
00003  * Copyright 2008-2010 Pelican Mapping
00004  * http://osgearth.org
00005  *
00006  * osgEarth is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU Lesser General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>
00018  */
00019 #include <osgEarthSymbology/MeshConsolidator>
00020 #include <osgEarthSymbology/LineFunctor>
00021 #include <osg/TriangleFunctor>
00022 #include <osg/TriangleIndexFunctor>
00023 #include <limits>
00024 #include <map>
00025 #include <iterator>
00026 
00027 #define LC "[MeshConsolidator] "
00028 
00029 using namespace osgEarth;
00030 using namespace osgEarth::Symbology;
00031 
00032 //------------------------------------------------------------------------
00033 
00034 namespace
00035 {
00036     template<typename T>
00037     struct Collector
00038     {
00039         osg::Geometry::PrimitiveSetList* _newPrimSets;
00040         unsigned _maxSize;
00041         T* _current;
00042 
00043         Collector() : _current(0L) { }
00044 
00045         void operator()( unsigned i0, unsigned i1, unsigned i2 )
00046         {
00047             if ( _current == 0L || _current->size() > _maxSize-3 )
00048             {
00049                 _current = new T (GL_TRIANGLES);
00050                 _newPrimSets->push_back( _current );
00051             }
00052 
00053             _current->push_back( i0 );
00054             _current->push_back( i1 );
00055             _current->push_back( i2 );
00056         }
00057     };
00058 
00059     template<typename FROM, typename TO>
00060     osg::PrimitiveSet* copy( FROM* src, unsigned offset )
00061     {
00062         TO* newDE = new TO( src->getMode() );
00063         newDE->reserve( src->size() );
00064         for( typename FROM::const_iterator i = src->begin(); i != src->end(); ++i )
00065             newDE->push_back( (*i) + offset );
00066         return newDE;
00067     }
00068 
00069     template<typename FROM>
00070     osg::PrimitiveSet* remake( FROM* src, unsigned numVerts, unsigned offset )
00071     {
00072         if ( numVerts < 0x100 )
00073             return copy<FROM,osg::DrawElementsUByte>( src, offset );
00074         else if ( numVerts < 0x10000 )
00075             return copy<FROM,osg::DrawElementsUShort>( src, offset );
00076         else
00077             return copy<FROM,osg::DrawElementsUInt>( src, offset );
00078     }
00079 
00080     bool canOptimize( osg::Geometry& geom )
00081     {
00082         osg::Array* vertexArray = geom.getVertexArray();
00083         if ( !vertexArray )
00084             return false;
00085 
00086         // check that everything is bound per-vertex
00087 
00088         if ( geom.getColorArray() != 0L && geom.getColorBinding() != osg::Geometry::BIND_PER_VERTEX )
00089             return false;
00090 
00091         if ( geom.getNormalArray() != 0L && geom.getNormalBinding() != osg::Geometry::BIND_PER_VERTEX )
00092             return false;
00093 
00094         if ( geom.getSecondaryColorArray() != 0L && geom.getSecondaryColorBinding() != osg::Geometry::BIND_PER_VERTEX )
00095             return false;
00096 
00097         if ( geom.getVertexAttribArrayList().size() > 0 )
00098         {
00099             unsigned n = geom.getVertexAttribArrayList().size();
00100             for( unsigned i=0; i<n; ++i ) 
00101             {
00102                 if ( geom.getVertexAttribBinding( i ) != osg::Geometry::BIND_PER_VERTEX )
00103                     return false;
00104             }
00105         }
00106 
00107         return true;
00108     }
00109 }
00110 
00111 //------------------------------------------------------------------------
00112 
00113 void
00114 MeshConsolidator::run( osg::Geometry& geom )
00115 {
00116     if ( !canOptimize(geom) )
00117         return;
00118 
00119     osg::Geometry::PrimitiveSetList& primSets = geom.getPrimitiveSetList();
00120     osg::Geometry::PrimitiveSetList  triSets, nonTriSets;
00121 
00122     for( osg::Geometry::PrimitiveSetList::iterator i = primSets.begin(); i != primSets.end(); ++i )
00123     {
00124         osg::PrimitiveSet* pset = i->get();
00125         switch( pset->getMode() )
00126         {
00127         case osg::PrimitiveSet::TRIANGLES:
00128         case osg::PrimitiveSet::TRIANGLE_STRIP:
00129         case osg::PrimitiveSet::TRIANGLE_FAN:
00130         case osg::PrimitiveSet::QUADS:
00131         case osg::PrimitiveSet::QUAD_STRIP:
00132         case osg::PrimitiveSet::POLYGON:
00133             triSets.push_back( pset );
00134             break;
00135 
00136         default:
00137             nonTriSets.push_back( pset );
00138         }
00139     }
00140 
00141     if ( triSets.size() > 0 )
00142     {
00143         osg::Array* vertexArray = geom.getVertexArray();
00144         unsigned numVerts = vertexArray->getNumElements();
00145         osg::Geometry::PrimitiveSetList newPrimSets;
00146 
00147         if ( numVerts < 0x100 )
00148         {
00149             osg::TriangleIndexFunctor< Collector<osg::DrawElementsUByte> > collector;
00150             collector._newPrimSets = &newPrimSets;
00151             collector._maxSize = 0xFF;
00152             geom.accept( collector );
00153         }
00154         else if ( numVerts < 0x10000 )
00155         {
00156             osg::TriangleIndexFunctor< Collector<osg::DrawElementsUShort> > collector;
00157             collector._newPrimSets = &newPrimSets;
00158             collector._maxSize = 0xFFFF;
00159             geom.accept( collector );
00160         }
00161         else
00162         {
00163             osg::TriangleIndexFunctor< Collector<osg::DrawElementsUInt> > collector;
00164             collector._newPrimSets = &newPrimSets;
00165             collector._maxSize = 0xFFFFFFFF;
00166             geom.accept( collector );
00167         }
00168 
00169         for( osg::Geometry::PrimitiveSetList::iterator i = newPrimSets.begin(); i != newPrimSets.end(); ++i )
00170             nonTriSets.push_back( i->get() );
00171     }
00172 
00173     geom.setPrimitiveSetList( nonTriSets );
00174 }
00175 
00176 void
00177 MeshConsolidator::run( osg::Geode& geode )
00178 {
00179     unsigned numVerts = 0;
00180     unsigned numColors = 0;
00181     unsigned numNormals = 0;
00182     unsigned numTexCoordArrays = 0;
00183     unsigned numVertAttribArrays = 0;
00184     std::vector<unsigned> texCoordArrayUnits;
00185 
00186     osg::Geometry::AttributeBinding newColorsBinding;
00187     osg::Geometry::AttributeBinding newNormalsBinding;
00188 
00189     // first, triangulate all the geometries and count all the components:
00190     for( unsigned i=0; i<geode.getNumDrawables(); ++i )
00191     {
00192         osg::Geometry* geom = geode.getDrawable(i)->asGeometry();
00193         if ( geom )
00194         {
00195             if ( !canOptimize(*geom) )
00196                 continue;
00197 
00198             // optimize it into triangles first:
00199             run( *geom );
00200 
00201             osg::Array* verts = geom->getVertexArray();
00202             if ( verts )
00203                 numVerts += verts->getNumElements();
00204 
00205             osg::Array* colors = geom->getColorArray();
00206             if ( colors )
00207                 numColors += colors->getNumElements();
00208 
00209             osg::Array* normals = geom->getNormalArray();
00210             if ( normals )
00211                 numNormals += normals->getNumElements();
00212 
00213             // NOTE!! tex/attrib array counts much already be equal.
00214             if ( texCoordArrayUnits.size() == 0 )
00215             {
00216                 for( unsigned u=0; u<32; ++u ) {
00217                     if ( geom->getTexCoordArray(u) != 0L )
00218                         texCoordArrayUnits.push_back( u );
00219                 }
00220             }
00221 
00222             numVertAttribArrays += geom->getNumVertexAttribArrays();
00223         }
00224     }
00225 
00226     // bail if there are unsupported items in there.
00227     if (geode.getNumDrawables() < 2 ||
00228         //numTexCoordArrays       > 0 ||
00229         numVertAttribArrays     > 0 )
00230     {
00231         return;
00232     }
00233 
00234 
00235     osg::Vec3Array* newVerts = new osg::Vec3Array();
00236     newVerts->reserve( numVerts );
00237 
00238     osg::Vec4Array* newColors =0L;
00239     if ( numColors > 0 )
00240     {
00241         newColors = new osg::Vec4Array();
00242         newColors->reserve( numVerts );
00243         newColorsBinding = osg::Geometry::BIND_PER_VERTEX;
00244         //newColors->reserve( numColors==numVerts? numColors : 1 );
00245         //newColorsBinding = numColors==numVerts? osg::Geometry::BIND_PER_VERTEX : osg::Geometry::BIND_OVERALL;
00246     }
00247 
00248     osg::Vec3Array* newNormals =0L;
00249     if ( numNormals > 0 )
00250     {
00251         newNormals = new osg::Vec3Array();
00252         newNormals->reserve( numVerts );
00253         newNormalsBinding = osg::Geometry::BIND_PER_VERTEX;
00254         //newNormals->reserve( numNormals==numVerts? numNormals : 1 );
00255         //newNormalsBinding = numNormals==numVerts? osg::Geometry::BIND_PER_VERTEX : osg::Geometry::BIND_OVERALL;
00256     }
00257 
00258     std::vector<osg::Vec2Array*> newTexCoordsArrays;
00259     for( unsigned i=0; i<texCoordArrayUnits.size(); ++i )
00260     {
00261         osg::Vec2Array* newTexCoords = new osg::Vec2Array();
00262         newTexCoords->reserve( numVerts );
00263         newTexCoordsArrays.push_back( newTexCoords );
00264     }
00265 
00266     unsigned offset = 0;
00267     osg::Geometry::PrimitiveSetList newPrimSets;
00268 
00269     std::vector<osg::ref_ptr<osg::Geometry> > nonOptimizedGeoms;
00270 
00271     osg::StateSet* unifiedStateSet = 0L;
00272 
00273     for( unsigned i=0; i<geode.getNumDrawables(); ++i )
00274     {
00275         osg::Geometry* geom = geode.getDrawable(i)->asGeometry();
00276         if ( geom )
00277         {
00278             if ( !canOptimize(*geom) )
00279             {
00280                 nonOptimizedGeoms.push_back(geom);
00281                 continue;
00282             }
00283 
00284             // merge in the stateset:
00285             if ( unifiedStateSet == 0L )
00286                 unifiedStateSet = geom->getStateSet();
00287             else if ( geom->getStateSet() )
00288                 unifiedStateSet->merge( *geom->getStateSet() );                
00289 
00290             // copy over the verts:
00291             osg::Vec3Array* geomVerts = dynamic_cast<osg::Vec3Array*>( geom->getVertexArray() );
00292             if ( geomVerts )
00293             {
00294                 std::copy( geomVerts->begin(), geomVerts->end(), std::back_inserter(*newVerts) );
00295 
00296                 if ( newColors )
00297                 {
00298                     osg::Vec4Array* colors = dynamic_cast<osg::Vec4Array*>( geom->getColorArray() );
00299                     if ( colors )
00300                     {
00301                         if ( newColorsBinding == osg::Geometry::BIND_PER_VERTEX )
00302                         {
00303                             std::copy( colors->begin(), colors->end(), std::back_inserter(*newColors) );
00304                         }
00305                         else if ( i == 0 ) // overall
00306                         {
00307                             newColors->push_back( (*colors)[0] );
00308                         }
00309                     }
00310                 }
00311 
00312                 if ( newNormals )
00313                 {
00314                     osg::Vec3Array* normals = dynamic_cast<osg::Vec3Array*>( geom->getNormalArray() );
00315                     if ( normals )
00316                     {
00317                         if ( newNormalsBinding == osg::Geometry::BIND_PER_VERTEX )
00318                         {
00319                             std::copy( normals->begin(), normals->end(), std::back_inserter(*newNormals) );
00320                         }
00321                         else if ( i == 0 ) // overall
00322                         {
00323                             newNormals->push_back( (*normals)[0] );
00324                         }
00325                     }
00326                 }
00327 
00328                 if ( newTexCoordsArrays.size() > 0 )
00329                 {
00330                     for( unsigned a=0; a<texCoordArrayUnits.size(); ++a )
00331                     {
00332                         unsigned unit = texCoordArrayUnits[a];
00333                         osg::Vec2Array* texCoords = dynamic_cast<osg::Vec2Array*>( geom->getTexCoordArray(unit) );
00334                         if ( texCoords )
00335                         {
00336                             osg::Vec2Array* newTexCoords = newTexCoordsArrays[a];
00337                             std::copy( texCoords->begin(), texCoords->end(), std::back_inserter(*newTexCoords) );
00338                         }
00339                     }
00340                 }
00341 
00342                 for( unsigned j=0; j < geom->getNumPrimitiveSets(); ++j )
00343                 {
00344                     osg::PrimitiveSet* pset = geom->getPrimitiveSet(j);
00345                     osg::PrimitiveSet* newpset = 0L;
00346                     
00347                     if ( dynamic_cast<osg::DrawElementsUByte*>(pset) )
00348                         newpset = remake( static_cast<osg::DrawElementsUByte*>(pset), numVerts, offset );
00349                     else if ( dynamic_cast<osg::DrawElementsUShort*>(pset) )
00350                         newpset = remake( static_cast<osg::DrawElementsUShort*>(pset), numVerts, offset );
00351                     else if ( dynamic_cast<osg::DrawElementsUInt*>(pset) )
00352                         newpset = remake( static_cast<osg::DrawElementsUInt*>(pset), numVerts, offset );
00353                     else if ( dynamic_cast<osg::DrawArrays*>(pset) )
00354                         newpset = new osg::DrawArrays( pset->getMode(), offset, geomVerts->size() );
00355 
00356                     if ( newpset )
00357                         newPrimSets.push_back( newpset );
00358                 }
00359 
00360                 offset += geomVerts->size();
00361             }
00362         }
00363     }
00364 
00365     // assemble the new geometry.
00366     osg::Geometry* newGeom = new osg::Geometry();
00367 
00368     newGeom->setVertexArray( newVerts );
00369     
00370     if ( newColors )
00371     {
00372         newGeom->setColorArray( newColors );
00373         newGeom->setColorBinding( newColorsBinding );
00374     }
00375 
00376     if ( newNormals )
00377     {
00378         newGeom->setNormalArray( newNormals );
00379         newGeom->setNormalBinding( newNormalsBinding );
00380     }
00381 
00382     if ( newTexCoordsArrays.size() > 0 )
00383     {
00384         for( unsigned a=0; a<texCoordArrayUnits.size(); ++a )
00385         {
00386             unsigned unit = texCoordArrayUnits[a];
00387             newGeom->setTexCoordArray( unit, newTexCoordsArrays[a] );
00388         }
00389     }
00390 
00391     newGeom->setPrimitiveSetList( newPrimSets );
00392     newGeom->setStateSet( unifiedStateSet );
00393 
00394     // replace the geode's drawables
00395     geode.removeDrawables( 0, geode.getNumDrawables() );
00396     geode.addDrawable( newGeom );
00397     for( std::vector<osg::ref_ptr<osg::Geometry> >::iterator i = nonOptimizedGeoms.begin(); i != nonOptimizedGeoms.end(); ++i )
00398         geode.addDrawable( i->get() );
00399 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines