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:
Robert Osfield 2001-10-01 23:02:14 +00:00
parent 0d0b33f4b0
commit fc1fa57275
4 changed files with 192 additions and 75 deletions

View File

@ -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();

View File

@ -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;
};

View File

@ -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()
{

View File

@ -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;
}
}
}