From fc1fa5727507b4e26f806f2259474c6e9c76cbf5 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 1 Oct 2001 23:02:14 +0000 Subject: [PATCH] Added support for osg::StateSet comparison operators and using this new feature added support in osgUtil::OptimizeStateVisitor for removing duplicate StateSet's from the scene graph, previously only duplicated StateAttributes we're removed. --- include/osg/StateSet | 7 + include/osgUtil/OptimizeStateVisitor | 9 +- src/osg/StateSet.cpp | 44 ++++++ src/osgUtil/OptimizeStateVisitor.cpp | 207 +++++++++++++++++---------- 4 files changed, 192 insertions(+), 75 deletions(-) diff --git a/include/osg/StateSet b/include/osg/StateSet index 945d366bf..9676b320c 100644 --- a/include/osg/StateSet +++ b/include/osg/StateSet @@ -28,6 +28,13 @@ class SG_EXPORT StateSet : public Object virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast(obj)!=NULL; } virtual const char* className() const { return "StateSet"; } + /** return -1 if *this < *rhs, 0 if *this==*rhs, 1 if *this>*rhs.*/ + int compare(const StateSet& rhs) const; + + bool operator < (const StateSet& rhs) const { return compare(rhs)<0; } + bool operator == (const StateSet& rhs) const { return compare(rhs)==0; } + bool operator != (const StateSet& rhs) const { return compare(rhs)!=0; } + /** set all the modes to on or off so that it defines a complete state, typically used for a default global state.*/ void setGlobalDefaults(); diff --git a/include/osgUtil/OptimizeStateVisitor b/include/osgUtil/OptimizeStateVisitor index 47639710c..7ca5ebfb2 100644 --- a/include/osgUtil/OptimizeStateVisitor +++ b/include/osgUtil/OptimizeStateVisitor @@ -20,7 +20,6 @@ class OSGUTIL_EXPORT OptimizeStateVisitor : public osg::NodeVisitor /** empty visitor, make it ready for next traversal.*/ virtual void reset(); - void addStateSet(osg::StateSet* stateset); virtual void apply(osg::Node& node); @@ -30,8 +29,12 @@ class OSGUTIL_EXPORT OptimizeStateVisitor : public osg::NodeVisitor protected: - typedef std::set StateSetList; - StateSetList _statesets; + void addStateSet(osg::StateSet* stateset,osg::Object* obj); + + typedef std::set ObjectSet; + typedef std::map StateSetMap; + + StateSetMap _statesets; }; diff --git a/src/osg/StateSet.cpp b/src/osg/StateSet.cpp index 4531cf998..3570f1a90 100644 --- a/src/osg/StateSet.cpp +++ b/src/osg/StateSet.cpp @@ -29,6 +29,50 @@ StateSet::~StateSet() // delete the memory manually. } +int StateSet::compare(const StateSet& rhs) const +{ + // check to see how the modes compare. + ModeList::const_iterator lhs_mode_itr = _modeList.begin(); + ModeList::const_iterator rhs_mode_itr = rhs._modeList.begin(); + while (lhs_mode_itr!=_modeList.end() && rhs_mode_itr!=rhs._modeList.end()) + { + if (lhs_mode_itr->firstfirst) return -1; + else if (rhs_mode_itr->firstfirst) return 1; + if (lhs_mode_itr->secondsecond) return -1; + else if (rhs_mode_itr->secondsecond) return 1; + ++lhs_mode_itr; + ++rhs_mode_itr; + } + if (lhs_mode_itr==_modeList.end()) + { + if (rhs_mode_itr!=rhs._modeList.end()) return -1; + } + else if (rhs_mode_itr == rhs._modeList.end()) return 1; + + // we've got here so modes must be equal... + + // now check to see how the attributes compare. + AttributeList::const_iterator lhs_attr_itr = _attributeList.begin(); + AttributeList::const_iterator rhs_attr_itr = rhs._attributeList.begin(); + while (lhs_attr_itr!=_attributeList.end() && rhs_attr_itr!=rhs._attributeList.end()) + { + if (lhs_attr_itr->firstfirst) return -1; + else if (rhs_attr_itr->firstfirst) return 1; + if (lhs_attr_itr->second.firstsecond.first) return -1; + else if (rhs_attr_itr->second.firstsecond.first) return 1; + if (lhs_attr_itr->second.secondsecond.second) return -1; + else if (rhs_attr_itr->second.secondsecond.second) return 1; + ++lhs_attr_itr; + ++rhs_attr_itr; + } + if (lhs_attr_itr==_attributeList.end()) + { + if (rhs_attr_itr!=rhs._attributeList.end()) return -1; + } + else if (rhs_attr_itr == rhs._attributeList.end()) return 1; + + return 0; +} void StateSet::setGlobalDefaults() { diff --git a/src/osgUtil/OptimizeStateVisitor.cpp b/src/osgUtil/OptimizeStateVisitor.cpp index 2e353e722..55483e4d4 100644 --- a/src/osgUtil/OptimizeStateVisitor.cpp +++ b/src/osgUtil/OptimizeStateVisitor.cpp @@ -16,7 +16,7 @@ struct LessAttributeFunctor return (*lhs<*rhs); } }; -/* + struct LessStateSetFunctor { bool operator () (const osg::StateSet* lhs,const osg::StateSet* rhs) const @@ -24,21 +24,21 @@ struct LessStateSetFunctor return (*lhs<*rhs); } }; -*/ + void OptimizeStateVisitor::reset() { _statesets.clear(); } -void OptimizeStateVisitor::addStateSet(osg::StateSet* stateset) +void OptimizeStateVisitor::addStateSet(osg::StateSet* stateset,osg::Object* obj) { - _statesets.insert(stateset); + _statesets[stateset].insert(obj); } void OptimizeStateVisitor::apply(osg::Node& node) { osg::StateSet* ss = node.getStateSet(); - if (ss) addStateSet(ss); + if (ss) addStateSet(ss,&node); traverse(node); } @@ -46,11 +46,15 @@ void OptimizeStateVisitor::apply(osg::Node& node) void OptimizeStateVisitor::apply(osg::Geode& geode) { osg::StateSet* ss = geode.getStateSet(); - if (ss) addStateSet(ss); + if (ss) addStateSet(ss,&geode); for(int i=0;igetStateSet(); - if (ss) addStateSet(ss); + osg::Drawable* drawable = geode.getDrawable(i); + if (drawable) + { + ss = drawable->getStateSet(); + if (ss) addStateSet(ss,drawable); + } } } @@ -58,75 +62,134 @@ void OptimizeStateVisitor::optimize() { osg::notify(osg::INFO) << "Num of StateSet="<<_statesets.size()< AttributeToStateSetMap; - AttributeToStateSetMap _attributeToStateSetMap; - // NOTE will need to track state attribute override value too. - - for(StateSetList::iterator sitr=_statesets.begin(); - sitr!=_statesets.end(); - ++sitr) { - osg::StateSet::AttributeList& attributes = (*sitr)->getAttributeList(); - for(osg::StateSet::AttributeList::iterator aitr= attributes.begin(); - aitr!=attributes.end(); - ++aitr) + // create map from state attributes to stateset which contain them. + typedef std::set 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) { - _attributeToStateSetMap[aitr->second.first.get()].insert(*sitr); - } - } - - 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<first->getAttributeList(); + for(osg::StateSet::AttributeList::iterator aitr= attributes.begin(); + aitr!=attributes.end(); + ++aitr) { - osg::notify(osg::INFO) << " replace duplicate "<<*current<<" with "<<*first_unique<< endl; - osg::StateSet* stateset = *sitr; - stateset->setAttribute(*first_unique); + _attributeToStateSetMap[aitr->second.first.get()].insert(sitr->first); } } - else first_unique = current; - } + 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; + } + } + }