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.
This commit is contained in:
parent
0d0b33f4b0
commit
fc1fa57275
@ -28,6 +28,13 @@ class SG_EXPORT StateSet : public Object
|
||||
virtual bool isSameKindAs(const Object* obj) const { return dynamic_cast<const StateSet*>(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();
|
||||
|
@ -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<osg::StateSet*> StateSetList;
|
||||
StateSetList _statesets;
|
||||
void addStateSet(osg::StateSet* stateset,osg::Object* obj);
|
||||
|
||||
typedef std::set<osg::Object*> ObjectSet;
|
||||
typedef std::map<osg::StateSet*,ObjectSet> StateSetMap;
|
||||
|
||||
StateSetMap _statesets;
|
||||
|
||||
};
|
||||
|
||||
|
@ -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->first<rhs_mode_itr->first) return -1;
|
||||
else if (rhs_mode_itr->first<lhs_mode_itr->first) return 1;
|
||||
if (lhs_mode_itr->second<rhs_mode_itr->second) return -1;
|
||||
else if (rhs_mode_itr->second<lhs_mode_itr->second) 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->first<rhs_attr_itr->first) return -1;
|
||||
else if (rhs_attr_itr->first<lhs_attr_itr->first) return 1;
|
||||
if (lhs_attr_itr->second.first<rhs_attr_itr->second.first) return -1;
|
||||
else if (rhs_attr_itr->second.first<lhs_attr_itr->second.first) return 1;
|
||||
if (lhs_attr_itr->second.second<rhs_attr_itr->second.second) return -1;
|
||||
else if (rhs_attr_itr->second.second<lhs_attr_itr->second.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()
|
||||
{
|
||||
|
@ -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;i<geode.getNumDrawables();++i)
|
||||
{
|
||||
ss = geode.getDrawable(i)->getStateSet();
|
||||
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()<<endl;
|
||||
|
||||
// create map from state attributes to stateset which contain them.
|
||||
typedef std::map<osg::StateAttribute*,StateSetList> 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<osg::StateSet*> StateSetList;
|
||||
typedef std::map<osg::StateAttribute*,StateSetList> 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."<<endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// create unique set of state attribute pointers.
|
||||
typedef std::vector<osg::StateAttribute*> 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"<<endl;
|
||||
for(AttributeList::iterator aaitr = _attributeList.begin();
|
||||
aaitr!=_attributeList.end();
|
||||
++aaitr)
|
||||
{
|
||||
osg::notify(osg::INFO) << " "<<*aaitr << " "<<(*aaitr)->className()<<endl;
|
||||
}
|
||||
|
||||
osg::notify(osg::INFO) << "searching for duplicates"<<endl;
|
||||
// find the duplicates.
|
||||
AttributeList::iterator first_unique = _attributeList.begin();
|
||||
AttributeList::iterator current = first_unique; ++current;
|
||||
for(; current!=_attributeList.end();++current)
|
||||
{
|
||||
if (**current==**first_unique)
|
||||
{
|
||||
osg::notify(osg::INFO) << " found duplicate "<<(*current)->className()<<" first="<<*first_unique<<" current="<<*current<<endl;
|
||||
StateSetList& statesetlist = _attributeToStateSetMap[*current];
|
||||
for(StateSetList::iterator sitr=statesetlist.begin();
|
||||
sitr!=statesetlist.end();
|
||||
++sitr)
|
||||
osg::StateSet::AttributeList& attributes = sitr->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."<<endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// create unique set of state attribute pointers.
|
||||
typedef std::vector<osg::StateAttribute*> 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"<<endl;
|
||||
for(AttributeList::iterator aaitr = _attributeList.begin();
|
||||
aaitr!=_attributeList.end();
|
||||
++aaitr)
|
||||
{
|
||||
osg::notify(osg::INFO) << " "<<*aaitr << " "<<(*aaitr)->className()<<endl;
|
||||
}
|
||||
|
||||
osg::notify(osg::INFO) << "searching for duplicate attributes"<<endl;
|
||||
// find the duplicates.
|
||||
AttributeList::iterator first_unique = _attributeList.begin();
|
||||
AttributeList::iterator current = first_unique; ++current;
|
||||
for(; current!=_attributeList.end();++current)
|
||||
{
|
||||
if (**current==**first_unique)
|
||||
{
|
||||
osg::notify(osg::INFO) << " found duplicate "<<(*current)->className()<<" first="<<*first_unique<<" current="<<*current<<endl;
|
||||
StateSetList& statesetlist = _attributeToStateSetMap[*current];
|
||||
for(StateSetList::iterator sitr=statesetlist.begin();
|
||||
sitr!=statesetlist.end();
|
||||
++sitr)
|
||||
{
|
||||
osg::notify(osg::INFO) << " replace duplicate "<<*current<<" with "<<*first_unique<< endl;
|
||||
osg::StateSet* stateset = *sitr;
|
||||
stateset->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<osg::StateSet*> 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"<<endl;
|
||||
// find the duplicates.
|
||||
StateSetSortList::iterator first_unique = _statesetSortList.begin();
|
||||
StateSetSortList::iterator current = first_unique; ++current;
|
||||
for(; current!=_statesetSortList.end();++current)
|
||||
{
|
||||
if (**current==**first_unique)
|
||||
{
|
||||
osg::notify(osg::INFO) << " found duplicate "<<(*current)->className()<<" first="<<*first_unique<<" current="<<*current<<endl;
|
||||
ObjectSet& objSet = _statesets[*current];
|
||||
for(ObjectSet::iterator sitr=objSet.begin();
|
||||
sitr!=objSet.end();
|
||||
++sitr)
|
||||
{
|
||||
osg::notify(osg::INFO) << " replace duplicate "<<*current<<" with "<<*first_unique<< endl;
|
||||
osg::Object* obj = *sitr;
|
||||
osg::Drawable* drawable = dynamic_cast<osg::Drawable*>(obj);
|
||||
if (drawable)
|
||||
{
|
||||
drawable->setStateSet(*first_unique);
|
||||
}
|
||||
else
|
||||
{
|
||||
osg::Node* node = dynamic_cast<osg::Node*>(obj);
|
||||
if (node)
|
||||
{
|
||||
node->setStateSet(*first_unique);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else first_unique = current;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user