From ccc3d3fd8a512db41f855ae2c47ca0a912d3722d Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 19 Oct 2001 14:22:02 +0000 Subject: [PATCH] Added osgUtil::Optimizer which contains four visitor each designed for doing different types of optimization on the scene graph - state optimization, flattening static transforms, combining LOD's and removing redundent groups. The new Optimizer replaces the once seperate OptimizerStateVisitor. --- VisualStudio/osgUtil/osgUtil.dsp | 4 +- include/osgUtil/OptimizeStateVisitor | 47 --- include/osgUtil/Optimizer | 135 +++++++ src/Demos/sgv/sgv.cpp | 338 +---------------- src/osgUtil/Makefile | 4 +- src/osgUtil/OptimizeStateVisitor.cpp | 195 ---------- src/osgUtil/Optimizer.cpp | 530 +++++++++++++++++++++++++++ 7 files changed, 673 insertions(+), 580 deletions(-) delete mode 100644 include/osgUtil/OptimizeStateVisitor create mode 100644 include/osgUtil/Optimizer delete mode 100644 src/osgUtil/OptimizeStateVisitor.cpp create mode 100644 src/osgUtil/Optimizer.cpp diff --git a/VisualStudio/osgUtil/osgUtil.dsp b/VisualStudio/osgUtil/osgUtil.dsp index eecfe9762..1e483969b 100755 --- a/VisualStudio/osgUtil/osgUtil.dsp +++ b/VisualStudio/osgUtil/osgUtil.dsp @@ -137,7 +137,7 @@ SOURCE=..\..\src\osgUtil\NvTriStripObjects.cpp # End Source File # Begin Source File -SOURCE=..\..\src\osgUtil\OptimizeStateVisitor.cpp +SOURCE=..\..\src\osgUtil\Optimizer.cpp # End Source File # Begin Source File @@ -265,7 +265,7 @@ SOURCE=..\..\src\osgUtil\NvTriStripObjects.h # End Source File # Begin Source File -SOURCE=..\..\include\osgUtil\OptimizeStateVisitor +SOURCE=..\..\include\osgUtil\Optimizer # End Source File # Begin Source File diff --git a/include/osgUtil/OptimizeStateVisitor b/include/osgUtil/OptimizeStateVisitor deleted file mode 100644 index 3ac62e9e6..000000000 --- a/include/osgUtil/OptimizeStateVisitor +++ /dev/null @@ -1,47 +0,0 @@ -//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield -//Distributed under the terms of the GNU Library General Public License (LGPL) -//as published by the Free Software Foundation. - -#ifndef OSGUTIL_OPTIMIZESTATEVISITOR -#define OSGUTIL_OPTIMIZESTATEVISITOR - -#include - -#include - -namespace osgUtil { - -/** Insert impostor nodes into scene graph. - * For example of usage see src/Demos/osgimpostor. - */ -class OSGUTIL_EXPORT OptimizeStateVisitor : public osg::NodeVisitor -{ - public: - - /// default to traversing all children. - OptimizeStateVisitor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) {} - - /** empty visitor, make it ready for next traversal.*/ - virtual void reset(); - - - virtual void apply(osg::Node& node); - - virtual void apply(osg::Geode& geode); - - void optimize(); - - protected: - - void addStateSet(osg::StateSet* stateset,osg::Object* obj); - - typedef std::set ObjectSet; - typedef std::map StateSetMap; - - StateSetMap _statesets; - -}; - -}; - -#endif diff --git a/include/osgUtil/Optimizer b/include/osgUtil/Optimizer new file mode 100644 index 000000000..becc14cd9 --- /dev/null +++ b/include/osgUtil/Optimizer @@ -0,0 +1,135 @@ +//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield +//Distributed under the terms of the GNU Library General Public License (LGPL) +//as published by the Free Software Foundation. + +#ifndef OSGUTIL_OPTIMIZER +#define OSGUTIL_OPTIMIZER + +#include +#include + +#include + +namespace osgUtil { + +/** Insert impostor nodes into scene graph. + * For example of usage see src/Demos/osgimpostor. + */ + +class OSGUTIL_EXPORT Optimizer +{ + + public: + + Optimizer() {} + + enum OptimizationOptions + { + FLATTEN_STATIC_TRANSFORMS = 0x1, + REMOVE_REDUNDENT_NODES = 0x2, + COMBINE_ADJACENT_LODS = 0x4, + SHARE_DUPLICATE_STATE = 0x8, + ALL_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS | + REMOVE_REDUNDENT_NODES | + COMBINE_ADJACENT_LODS | + SHARE_DUPLICATE_STATE + }; + + /** traverse the node and its subgraph with a series of optimization + * visitors, specificied by the OptizationOptions.*/ + virtual void optimize(osg::Node* node, unsigned int options = ALL_OPTIMIZATIONS); + + + + /** Flatten Static Trasform nodes by applying their transform to the + * geometry on the leaves of the scene graph, then removing the + * now redundent transforms.*/ + class FlattenStaticTransformsVisitor : public osg::NodeVisitor + { + public: + + typedef std::vector MatrixStack; + MatrixStack _matrixStack; + + typedef std::set TransformList; + TransformList _transformList; + + FlattenStaticTransformsVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} + + virtual void apply(osg::Geode& geode); + virtual void apply(osg::Billboard& billboard); + virtual void apply(osg::LOD& lod); + virtual void apply(osg::Transform& transform); + + void removeTransforms(); + + }; + + /** Remove rendundent nodes, such as groups with one single child.*/ + class RemoveRedundentNodesVisitor : public osg::NodeVisitor + { + public: + + typedef std::set NodeList; + NodeList _redundentNodeList; + + RemoveRedundentNodesVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} + + virtual void apply(osg::Group& group); + + void removeRedundentNodes(); + + }; + + /** Optimize the LOD groups, by combining adjacent LOD's which have + * complementary ranges.*/ + class CombineLODsVisitor : public osg::NodeVisitor + { + public: + + typedef std::set GroupList; + GroupList _groupList; + + CombineLODsVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} + + virtual void apply(osg::LOD& lod); + + void combineLODs(); + + }; + + /** Optimize State in the scene graph by removing duplicate state, + * replacing it with shared instances, both for StateAttributes, + * and whole StateSets.*/ + class StateVisitor : public osg::NodeVisitor + { + public: + + /// default to traversing all children. + StateVisitor() : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN) {} + + /** empty visitor, make it ready for next traversal.*/ + virtual void reset(); + + virtual void apply(osg::Node& node); + + virtual void apply(osg::Geode& geode); + + void optimize(); + + protected: + + void addStateSet(osg::StateSet* stateset,osg::Object* obj); + + typedef std::set ObjectSet; + typedef std::map StateSetMap; + + StateSetMap _statesets; + + }; + +}; + +}; + +#endif diff --git a/src/Demos/sgv/sgv.cpp b/src/Demos/sgv/sgv.cpp index a99c772c4..d2c627832 100644 --- a/src/Demos/sgv/sgv.cpp +++ b/src/Demos/sgv/sgv.cpp @@ -18,319 +18,7 @@ #include #include -#include - - - -class TransformFunctor : public osg::Drawable::AttributeFunctor -{ - public: - - osg::Matrix _m; - osg::Matrix _im; - - TransformFunctor(const osg::Matrix& m): - osg::Drawable::AttributeFunctor(osg::Drawable::COORDS|osg::Drawable::NORMALS) - { - _m = m; - _im.invert(_m); - } - - virtual ~TransformFunctor() {} - - virtual bool apply(osg::Drawable::AttributeBitMask abm,osg::Vec3* begin,osg::Vec3* end) - { - if (abm == osg::Drawable::COORDS) - { - for (osg::Vec3* itr=begin;itr MatrixStack; - MatrixStack _matrixStack; - - typedef std::set TransformList; - TransformList _transformList; - - FlattenStaticTransformsVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} - - virtual void apply(osg::Geode& geode) - { - if (!_matrixStack.empty()) - { - TransformFunctor tf(_matrixStack.back()); - for(int i=0;iapplyAttributeOperation(tf); - } - } - } - - virtual void apply(osg::Billboard& billboard) - { - if (!_matrixStack.empty()) - { - osg::Matrix& matrix = _matrixStack.back(); - TransformFunctor tf(matrix); - - osg::Vec3 axis = osg::Matrix::transform3x3(tf._im,billboard.getAxis()); - billboard.setAxis(axis); - - for(int i=0;iapplyAttributeOperation(tf); - } - } - } - - virtual void apply(osg::LOD& lod) - { - if (!_matrixStack.empty()) - { - lod.setCenter(lod.getCenter()*_matrixStack.back()); - } - traverse(lod); - } - - virtual void apply(osg::Transform& transform) - { - if (_matrixStack.empty()) - { - _matrixStack.push_back(transform.getMatrix()); - } - else - { - _matrixStack.push_back(transform.getMatrix()*_matrixStack.back()); - } - - traverse(transform); - - _transformList.insert(&transform); - - // reset the matrix to identity. - transform.getMatrix().makeIdent(); - - _matrixStack.pop_back(); - } - - void removeTransforms() - { - for(TransformList::iterator itr=_transformList.begin(); - itr!=_transformList.end(); - ++itr) - { - osg::ref_ptr transform = *itr; - osg::ref_ptr group = new osg::Group; - - int i; - for(i=0;igetNumChildren();++i) - { - for(int j=0;jgetNumParents();++j) - { - group->addChild(transform->getChild(i)); - } - } - - for(i=transform->getNumParents()-1;i>=0;--i) - { - transform->getParent(i)->replaceChild(transform.get(),group.get()); - } - - } - _transformList.clear(); - } - -}; - - -class RemoveRedundentNodesVisitor : public osg::NodeVisitor -{ - public: - - typedef std::set NodeList; - NodeList _redundentNodeList; - - RemoveRedundentNodesVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} - - virtual void apply(osg::Group& group) - { - if (typeid(group)==typeid(osg::Group)) - { - if (group.getNumParents()>0 && group.getNumChildren()<=1) - { - _redundentNodeList.insert(&group); - } - } - traverse(group); - } - - - void removeRedundentNodes() - { - for(NodeList::iterator itr=_redundentNodeList.begin(); - itr!=_redundentNodeList.end(); - ++itr) - { - osg::ref_ptr group = dynamic_cast(*itr); - if (group.valid()) - { - - for(int j=group->getNumParents()-1;j>=0;--j) - { - for(int i=0;igetNumChildren();++i) - { - group->getParent(j)->addChild(group->getChild(i)); - } - group->getParent(j)->removeChild(group.get()); - } - } - } - _redundentNodeList.clear(); - } - -}; - -class CombineLODsVisitor : public osg::NodeVisitor -{ - public: - - typedef std::set GroupList; - GroupList _groupList; - - CombineLODsVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {} - - virtual void apply(osg::LOD& lod) - { - for(int i=0;i LODSet; - - LODSet lodChildren; - - for(int i=0;igetNumChildren();++i) - { - osg::Node* child = group->getChild(i); - osg::LOD* lod = dynamic_cast(child); - if (lod) - { - if (lod->getNumRanges()-1==lod->getNumChildren()) - { - lodChildren.insert(lod); - } - else - { - // wonky LOD, numRanges should = numChildren+1 - } - } - } - - if (lodChildren.size()>=2) - { - osg::BoundingBox bb; - LODSet::iterator lod_itr; - for(lod_itr=lodChildren.begin(); - lod_itr!=lodChildren.end(); - ++lod_itr) - { - - bb.expandBy((*lod_itr)->getCenter()); - } - if (bb.radius()<1e-2) - { - typedef std::pair RangePair; - typedef std::multimap RangeMap; - RangeMap rangeMap; - float maxRange = 0.0f; - for(lod_itr=lodChildren.begin(); - lod_itr!=lodChildren.end(); - ++lod_itr) - { - - osg::LOD* lod = *lod_itr; - for(int i=0;igetNumRanges()-1;++i) - { - if (maxRangegetRange(i+1)) maxRange = lod->getRange(i+1); - rangeMap.insert(RangeMap::value_type(RangePair(lod->getRange(i),lod->getRange(i+1)),lod->getChild(i))); - } - - } - - // create new LOD containing all other LOD's children. - osg::LOD* newLOD = new osg::LOD; - newLOD->setName("newLOD"); - newLOD->setCenter(bb.center()); - - int i=0; - for(RangeMap::iterator c_itr=rangeMap.begin(); - c_itr!=rangeMap.end(); - ++c_itr,++i) - { - newLOD->setRange(i,c_itr->first.first); - newLOD->addChild(c_itr->second); - } - newLOD->setRange(i,maxRange); - - // add LOD into parent. - group->addChild(newLOD); - - // remove all the old LOD's from group. - for(lod_itr=lodChildren.begin(); - lod_itr!=lodChildren.end(); - ++lod_itr) - { - group->removeChild(*lod_itr); - } - - } - - } - } - _groupList.clear(); - } - -}; - +#include /* @@ -452,28 +140,10 @@ int main( int argc, char **argv ) osg::Timer_t after_load = timer.tick(); cout << "Time for load = "<accept(osv); - osv.optimize(); - #endif - - CombineLODsVisitor clv; - rootnode->accept(clv); - clv.combineLODs(); - - FlattenStaticTransformsVisitor fstv; - rootnode->accept(fstv); - fstv.removeTransforms(); - - RemoveRedundentNodesVisitor rrnv; - rootnode->accept(rrnv); - rrnv.removeRedundentNodes(); + // run optimization over the scene graph + osgUtil::Optimizer optimzer; + optimzer.optimize(rootnode); // initialize the viewer. osgGLUT::Viewer viewer; diff --git a/src/osgUtil/Makefile b/src/osgUtil/Makefile index ec4863148..ca0edd40c 100644 --- a/src/osgUtil/Makefile +++ b/src/osgUtil/Makefile @@ -13,7 +13,7 @@ C++FILES = \ IntersectVisitor.cpp\ InsertImpostorsVisitor.cpp\ NvTriStripObjects.cpp\ - OptimizeStateVisitor.cpp\ + Optimizer.cpp\ RenderBin.cpp\ RenderGraph.cpp\ RenderLeaf.cpp\ @@ -55,7 +55,7 @@ TARGET_INCLUDE_FILES = \ osgUtil/GUIEventHandler\ osgUtil/IntersectVisitor\ osgUtil/InsertImpostorsVisitor\ - osgUtil/OptimizeStateVisitor\ + osgUtil/Optimizer\ osgUtil/RenderBin\ osgUtil/RenderGraph\ osgUtil/RenderLeaf\ diff --git a/src/osgUtil/OptimizeStateVisitor.cpp b/src/osgUtil/OptimizeStateVisitor.cpp deleted file mode 100644 index 55483e4d4..000000000 --- a/src/osgUtil/OptimizeStateVisitor.cpp +++ /dev/null @@ -1,195 +0,0 @@ -#include -#include - -#include - -#include -#include - -using namespace osgUtil; - - -struct LessAttributeFunctor -{ - bool operator () (const osg::StateAttribute* lhs,const osg::StateAttribute* rhs) const - { - return (*lhs<*rhs); - } -}; - -struct LessStateSetFunctor -{ - bool operator () (const osg::StateSet* lhs,const osg::StateSet* rhs) const - { - return (*lhs<*rhs); - } -}; - -void OptimizeStateVisitor::reset() -{ - _statesets.clear(); -} - -void OptimizeStateVisitor::addStateSet(osg::StateSet* stateset,osg::Object* obj) -{ - _statesets[stateset].insert(obj); -} - -void OptimizeStateVisitor::apply(osg::Node& node) -{ - osg::StateSet* ss = node.getStateSet(); - if (ss) addStateSet(ss,&node); - - traverse(node); -} - -void OptimizeStateVisitor::apply(osg::Geode& geode) -{ - osg::StateSet* ss = geode.getStateSet(); - if (ss) addStateSet(ss,&geode); - for(int i=0;igetStateSet(); - if (ss) addStateSet(ss,drawable); - } - } -} - -void OptimizeStateVisitor::optimize() -{ - osg::notify(osg::INFO) << "Num of StateSet="<<_statesets.size()< StateSetList; - typedef std::map AttributeToStateSetMap; - - AttributeToStateSetMap _attributeToStateSetMap; - - // NOTE will need to track state attribute override value too. - - for(StateSetMap::iterator sitr=_statesets.begin(); - sitr!=_statesets.end(); - ++sitr) - { - osg::StateSet::AttributeList& attributes = sitr->first->getAttributeList(); - for(osg::StateSet::AttributeList::iterator aitr= attributes.begin(); - aitr!=attributes.end(); - ++aitr) - { - _attributeToStateSetMap[aitr->second.first.get()].insert(sitr->first); - } - } - - if (_attributeToStateSetMap.size()<2) - { - osg::notify(osg::INFO) << "Too few state attributes to optimize."< AttributeList; - AttributeList _attributeList; - - for(AttributeToStateSetMap::iterator aitr=_attributeToStateSetMap.begin(); - aitr!=_attributeToStateSetMap.end(); - ++aitr) - { - _attributeList.push_back(aitr->first); - } - - // sort the attributes so that equal attributes sit along side each - // other. - std::sort(_attributeList.begin(),_attributeList.end(),LessAttributeFunctor()); - - - osg::notify(osg::INFO) << "state attribute list"<className()<className()<<" first="<<*first_unique<<" current="<<*current<setAttribute(*first_unique); - } - } - else first_unique = current; - } - - } - // duplicate state attributes removed. - // now need to look at duplicate state sets. - - { - // create the list of stateset's. - typedef std::vector StateSetSortList; - StateSetSortList _statesetSortList; - for(StateSetMap::iterator ssitr=_statesets.begin(); - ssitr!=_statesets.end(); - ++ssitr) - { - _statesetSortList.push_back(ssitr->first); - } - - - // sort the StateSet's so that equal StateSet's sit along side each - // other. - std::sort(_statesetSortList.begin(),_statesetSortList.end(),LessStateSetFunctor()); - - osg::notify(osg::INFO) << "searching for duplicate attributes"<className()<<" first="<<*first_unique<<" current="<<*current<(obj); - if (drawable) - { - drawable->setStateSet(*first_unique); - } - else - { - osg::Node* node = dynamic_cast(obj); - if (node) - { - node->setStateSet(*first_unique); - } - } - } - } - else first_unique = current; - } - } - -} diff --git a/src/osgUtil/Optimizer.cpp b/src/osgUtil/Optimizer.cpp new file mode 100644 index 000000000..c96d196a7 --- /dev/null +++ b/src/osgUtil/Optimizer.cpp @@ -0,0 +1,530 @@ +#include + +#include +#include +#include +#include +#include + +#include +#include + +using namespace osgUtil; + +//////////////////////////////////////////////////////////////////////////// +// Overall Optimizetion function. +//////////////////////////////////////////////////////////////////////////// + +void Optimizer::optimize(osg::Node* node, unsigned int options) +{ + + if (options & FLATTEN_STATIC_TRANSFORMS) + { + FlattenStaticTransformsVisitor fstv; + node->accept(fstv); + fstv.removeTransforms(); + } + + if (options & REMOVE_REDUNDENT_NODES) + { + RemoveRedundentNodesVisitor rrnv; + node->accept(rrnv); + rrnv.removeRedundentNodes(); + } + + if (options & COMBINE_ADJACENT_LODS) + { + CombineLODsVisitor clv; + node->accept(clv); + clv.combineLODs(); + } + + if (options & SHARE_DUPLICATE_STATE) + { + #ifndef WIN32 + // optimize the state in scene graph, removing duplicate state. + #endif + StateVisitor osv; + node->accept(osv); + osv.optimize(); + } + +} + +class TransformFunctor : public osg::Drawable::AttributeFunctor +{ + public: + + osg::Matrix _m; + osg::Matrix _im; + + TransformFunctor(const osg::Matrix& m): + osg::Drawable::AttributeFunctor(osg::Drawable::COORDS|osg::Drawable::NORMALS) + { + _m = m; + _im.invert(_m); + } + + virtual ~TransformFunctor() {} + + virtual bool apply(osg::Drawable::AttributeBitMask abm,osg::Vec3* begin,osg::Vec3* end) + { + if (abm == osg::Drawable::COORDS) + { + for (osg::Vec3* itr=begin;itrgetStateSet(); + if (ss) addStateSet(ss,drawable); + } + } +} + +void Optimizer::StateVisitor::optimize() +{ + osg::notify(osg::INFO) << "Num of StateSet="<<_statesets.size()< StateSetList; + typedef std::map AttributeToStateSetMap; + + AttributeToStateSetMap _attributeToStateSetMap; + + // NOTE will need to track state attribute override value too. + + for(StateSetMap::iterator sitr=_statesets.begin(); + sitr!=_statesets.end(); + ++sitr) + { + osg::StateSet::AttributeList& attributes = sitr->first->getAttributeList(); + for(osg::StateSet::AttributeList::iterator aitr= attributes.begin(); + aitr!=attributes.end(); + ++aitr) + { + _attributeToStateSetMap[aitr->second.first.get()].insert(sitr->first); + } + } + + if (_attributeToStateSetMap.size()<2) + { + osg::notify(osg::INFO) << "Too few state attributes to optimize."< AttributeList; + AttributeList _attributeList; + + for(AttributeToStateSetMap::iterator aitr=_attributeToStateSetMap.begin(); + aitr!=_attributeToStateSetMap.end(); + ++aitr) + { + _attributeList.push_back(aitr->first); + } + + // sort the attributes so that equal attributes sit along side each + // other. + std::sort(_attributeList.begin(),_attributeList.end(),LessAttributeFunctor()); + + + osg::notify(osg::INFO) << "state attribute list"<className()<className()<<" first="<<*first_unique<<" current="<<*current<setAttribute(*first_unique); + } + } + else first_unique = current; + } + + } + // duplicate state attributes removed. + // now need to look at duplicate state sets. + + { + // create the list of stateset's. + typedef std::vector StateSetSortList; + StateSetSortList _statesetSortList; + for(StateSetMap::iterator ssitr=_statesets.begin(); + ssitr!=_statesets.end(); + ++ssitr) + { + _statesetSortList.push_back(ssitr->first); + } + + + // sort the StateSet's so that equal StateSet's sit along side each + // other. + std::sort(_statesetSortList.begin(),_statesetSortList.end(),LessStateSetFunctor()); + + osg::notify(osg::INFO) << "searching for duplicate attributes"<className()<<" first="<<*first_unique<<" current="<<*current<(obj); + if (drawable) + { + drawable->setStateSet(*first_unique); + } + else + { + osg::Node* node = dynamic_cast(obj); + if (node) + { + node->setStateSet(*first_unique); + } + } + } + } + else first_unique = current; + } + } + +} + +//////////////////////////////////////////////////////////////////////////// +// Flatten static transforms +//////////////////////////////////////////////////////////////////////////// + +void Optimizer::FlattenStaticTransformsVisitor::apply(osg::Geode& geode) +{ + if (!_matrixStack.empty()) + { + TransformFunctor tf(_matrixStack.back()); + for(int i=0;iapplyAttributeOperation(tf); + } + } +} + +void Optimizer::FlattenStaticTransformsVisitor::apply(osg::Billboard& billboard) +{ + if (!_matrixStack.empty()) + { + osg::Matrix& matrix = _matrixStack.back(); + TransformFunctor tf(matrix); + + osg::Vec3 axis = osg::Matrix::transform3x3(tf._im,billboard.getAxis()); + billboard.setAxis(axis); + + for(int i=0;iapplyAttributeOperation(tf); + } + } +} + +void Optimizer::FlattenStaticTransformsVisitor::apply(osg::LOD& lod) +{ + if (!_matrixStack.empty()) + { + lod.setCenter(lod.getCenter()*_matrixStack.back()); + } + traverse(lod); +} + +void Optimizer::FlattenStaticTransformsVisitor::apply(osg::Transform& transform) +{ + if (_matrixStack.empty()) + { + _matrixStack.push_back(transform.getMatrix()); + } + else + { + _matrixStack.push_back(transform.getMatrix()*_matrixStack.back()); + } + + traverse(transform); + + _transformList.insert(&transform); + + // reset the matrix to identity. + transform.getMatrix().makeIdent(); + + _matrixStack.pop_back(); +} + +void Optimizer::FlattenStaticTransformsVisitor::removeTransforms() +{ + for(TransformList::iterator itr=_transformList.begin(); + itr!=_transformList.end(); + ++itr) + { + osg::ref_ptr transform = *itr; + osg::ref_ptr group = new osg::Group; + + int i; + for(i=0;igetNumChildren();++i) + { + for(int j=0;jgetNumParents();++j) + { + group->addChild(transform->getChild(i)); + } + } + + for(i=transform->getNumParents()-1;i>=0;--i) + { + transform->getParent(i)->replaceChild(transform.get(),group.get()); + } + + } + _transformList.clear(); +} + + +//////////////////////////////////////////////////////////////////////////// +// RemoveRedundentNodes. +//////////////////////////////////////////////////////////////////////////// + +void Optimizer::RemoveRedundentNodesVisitor::apply(osg::Group& group) +{ + if (typeid(group)==typeid(osg::Group)) + { + if (group.getNumParents()>0 && group.getNumChildren()<=1) + { + _redundentNodeList.insert(&group); + } + } + traverse(group); +} + + +void Optimizer::RemoveRedundentNodesVisitor::removeRedundentNodes() +{ + for(NodeList::iterator itr=_redundentNodeList.begin(); + itr!=_redundentNodeList.end(); + ++itr) + { + osg::ref_ptr group = dynamic_cast(*itr); + if (group.valid()) + { + + for(int j=group->getNumParents()-1;j>=0;--j) + { + for(int i=0;igetNumChildren();++i) + { + group->getParent(j)->addChild(group->getChild(i)); + } + group->getParent(j)->removeChild(group.get()); + } + } + } + _redundentNodeList.clear(); +} + + + + +//////////////////////////////////////////////////////////////////////////// +// combine LOD's. +//////////////////////////////////////////////////////////////////////////// +void Optimizer::CombineLODsVisitor::apply(osg::LOD& lod) +{ + for(int i=0;i LODSet; + + LODSet lodChildren; + + for(int i=0;igetNumChildren();++i) + { + osg::Node* child = group->getChild(i); + osg::LOD* lod = dynamic_cast(child); + if (lod) + { + if (lod->getNumRanges()-1==lod->getNumChildren()) + { + lodChildren.insert(lod); + } + else + { + // wonky LOD, numRanges should = numChildren+1 + } + } + } + + if (lodChildren.size()>=2) + { + osg::BoundingBox bb; + LODSet::iterator lod_itr; + for(lod_itr=lodChildren.begin(); + lod_itr!=lodChildren.end(); + ++lod_itr) + { + + bb.expandBy((*lod_itr)->getCenter()); + } + if (bb.radius()<1e-2) + { + typedef std::pair RangePair; + typedef std::multimap RangeMap; + RangeMap rangeMap; + float maxRange = 0.0f; + for(lod_itr=lodChildren.begin(); + lod_itr!=lodChildren.end(); + ++lod_itr) + { + + osg::LOD* lod = *lod_itr; + for(int i=0;igetNumRanges()-1;++i) + { + if (maxRangegetRange(i+1)) maxRange = lod->getRange(i+1); + rangeMap.insert(RangeMap::value_type(RangePair(lod->getRange(i),lod->getRange(i+1)),lod->getChild(i))); + } + + } + + // create new LOD containing all other LOD's children. + osg::LOD* newLOD = new osg::LOD; + newLOD->setName("newLOD"); + newLOD->setCenter(bb.center()); + + int i=0; + for(RangeMap::iterator c_itr=rangeMap.begin(); + c_itr!=rangeMap.end(); + ++c_itr,++i) + { + newLOD->setRange(i,c_itr->first.first); + newLOD->addChild(c_itr->second); + } + newLOD->setRange(i,maxRange); + + // add LOD into parent. + group->addChild(newLOD); + + // remove all the old LOD's from group. + for(lod_itr=lodChildren.begin(); + lod_itr!=lodChildren.end(); + ++lod_itr) + { + group->removeChild(*lod_itr); + } + + } + + } + } + _groupList.clear(); +} +