2001-10-19 22:22:02 +08:00
|
|
|
#include <osgUtil/Optimizer>
|
|
|
|
|
|
|
|
#include <osg/Transform>
|
|
|
|
#include <osg/LOD>
|
|
|
|
#include <osg/Impostor>
|
|
|
|
#include <osg/Billboard>
|
|
|
|
#include <osg/Notify>
|
|
|
|
|
|
|
|
#include <typeinfo>
|
|
|
|
#include <algorithm>
|
|
|
|
|
|
|
|
using namespace osgUtil;
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Overall Optimizetion function.
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void Optimizer::optimize(osg::Node* node, unsigned int options)
|
|
|
|
{
|
2002-02-10 06:29:40 +08:00
|
|
|
|
2001-12-14 22:25:38 +08:00
|
|
|
if (options & COMBINE_ADJACENT_LODS)
|
|
|
|
{
|
|
|
|
CombineLODsVisitor clv;
|
|
|
|
node->accept(clv);
|
|
|
|
clv.combineLODs();
|
|
|
|
}
|
2002-01-23 03:30:51 +08:00
|
|
|
|
2001-10-19 22:22:02 +08:00
|
|
|
if (options & FLATTEN_STATIC_TRANSFORMS)
|
|
|
|
{
|
|
|
|
FlattenStaticTransformsVisitor fstv;
|
|
|
|
node->accept(fstv);
|
|
|
|
fstv.removeTransforms();
|
|
|
|
}
|
2002-01-23 03:30:51 +08:00
|
|
|
|
2001-10-19 22:22:02 +08:00
|
|
|
if (options & REMOVE_REDUNDENT_NODES)
|
|
|
|
{
|
|
|
|
RemoveRedundentNodesVisitor rrnv;
|
|
|
|
node->accept(rrnv);
|
|
|
|
rrnv.removeRedundentNodes();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (options & SHARE_DUPLICATE_STATE)
|
|
|
|
{
|
2002-03-01 17:29:56 +08:00
|
|
|
#if (defined(_MSC_VER) && _MSC_VER<13 && !defined(_STLPORT_VERSION))
|
|
|
|
osg::notify(osg::INFO)<<"Warning: VisualStudio 6.0 build, unable to run state optimizer"<<std::endl;
|
|
|
|
#else
|
2001-10-19 22:22:02 +08:00
|
|
|
StateVisitor osv;
|
|
|
|
node->accept(osv);
|
|
|
|
osv.optimize();
|
2001-10-19 23:30:54 +08:00
|
|
|
#endif
|
2001-10-19 22:22:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
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<end;++itr)
|
|
|
|
{
|
|
|
|
(*itr) = (*itr)*_m;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
else if (abm == osg::Drawable::NORMALS)
|
|
|
|
{
|
|
|
|
for (osg::Vec3* itr=begin;itr<end;++itr)
|
|
|
|
{
|
|
|
|
// note post mult by inverse for normals.
|
|
|
|
(*itr) = osg::Matrix::transform3x3(_im,(*itr));
|
|
|
|
(*itr).normalize();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Optimize State Visitor
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
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 Optimizer::StateVisitor::reset()
|
|
|
|
{
|
|
|
|
_statesets.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Optimizer::StateVisitor::addStateSet(osg::StateSet* stateset,osg::Object* obj)
|
|
|
|
{
|
|
|
|
_statesets[stateset].insert(obj);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Optimizer::StateVisitor::apply(osg::Node& node)
|
|
|
|
{
|
|
|
|
osg::StateSet* ss = node.getStateSet();
|
|
|
|
if (ss) addStateSet(ss,&node);
|
|
|
|
|
|
|
|
traverse(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Optimizer::StateVisitor::apply(osg::Geode& geode)
|
|
|
|
{
|
|
|
|
osg::StateSet* ss = geode.getStateSet();
|
|
|
|
if (ss) addStateSet(ss,&geode);
|
|
|
|
for(int i=0;i<geode.getNumDrawables();++i)
|
|
|
|
{
|
|
|
|
osg::Drawable* drawable = geode.getDrawable(i);
|
|
|
|
if (drawable)
|
|
|
|
{
|
|
|
|
ss = drawable->getStateSet();
|
|
|
|
if (ss) addStateSet(ss,drawable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Optimizer::StateVisitor::optimize()
|
|
|
|
{
|
2001-12-15 18:00:43 +08:00
|
|
|
osg::notify(osg::INFO) << "Num of StateSet="<<_statesets.size()<< std::endl;
|
2001-10-19 22:22:02 +08:00
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
// 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)
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
2001-12-15 18:00:43 +08:00
|
|
|
osg::notify(osg::INFO) << "Too few state attributes to optimize."<< std::endl;
|
2001-10-19 22:22:02 +08:00
|
|
|
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());
|
|
|
|
|
|
|
|
|
2001-12-15 18:00:43 +08:00
|
|
|
osg::notify(osg::INFO) << "state attribute list"<< std::endl;
|
2001-10-19 22:22:02 +08:00
|
|
|
for(AttributeList::iterator aaitr = _attributeList.begin();
|
|
|
|
aaitr!=_attributeList.end();
|
|
|
|
++aaitr)
|
|
|
|
{
|
2001-12-15 18:00:43 +08:00
|
|
|
osg::notify(osg::INFO) << " "<<*aaitr << " "<<(*aaitr)->className()<< std::endl;
|
2001-10-19 22:22:02 +08:00
|
|
|
}
|
|
|
|
|
2001-12-15 18:00:43 +08:00
|
|
|
osg::notify(osg::INFO) << "searching for duplicate attributes"<< std::endl;
|
2001-10-19 22:22:02 +08:00
|
|
|
// find the duplicates.
|
|
|
|
AttributeList::iterator first_unique = _attributeList.begin();
|
|
|
|
AttributeList::iterator current = first_unique; ++current;
|
|
|
|
for(; current!=_attributeList.end();++current)
|
|
|
|
{
|
|
|
|
if (**current==**first_unique)
|
|
|
|
{
|
2001-12-15 18:00:43 +08:00
|
|
|
osg::notify(osg::INFO) << " found duplicate "<<(*current)->className()<<" first="<<*first_unique<<" current="<<*current<< std::endl;
|
2001-10-19 22:22:02 +08:00
|
|
|
StateSetList& statesetlist = _attributeToStateSetMap[*current];
|
|
|
|
for(StateSetList::iterator sitr=statesetlist.begin();
|
|
|
|
sitr!=statesetlist.end();
|
|
|
|
++sitr)
|
|
|
|
{
|
2001-12-15 18:00:43 +08:00
|
|
|
osg::notify(osg::INFO) << " replace duplicate "<<*current<<" with "<<*first_unique<< std::endl;
|
2001-10-19 22:22:02 +08:00
|
|
|
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());
|
|
|
|
|
2001-12-15 18:00:43 +08:00
|
|
|
osg::notify(osg::INFO) << "searching for duplicate attributes"<< std::endl;
|
2001-10-19 22:22:02 +08:00
|
|
|
// find the duplicates.
|
|
|
|
StateSetSortList::iterator first_unique = _statesetSortList.begin();
|
|
|
|
StateSetSortList::iterator current = first_unique; ++current;
|
|
|
|
for(; current!=_statesetSortList.end();++current)
|
|
|
|
{
|
|
|
|
if (**current==**first_unique)
|
|
|
|
{
|
2001-12-15 18:00:43 +08:00
|
|
|
osg::notify(osg::INFO) << " found duplicate "<<(*current)->className()<<" first="<<*first_unique<<" current="<<*current<< std::endl;
|
2001-10-19 22:22:02 +08:00
|
|
|
ObjectSet& objSet = _statesets[*current];
|
|
|
|
for(ObjectSet::iterator sitr=objSet.begin();
|
|
|
|
sitr!=objSet.end();
|
|
|
|
++sitr)
|
|
|
|
{
|
2001-12-15 18:00:43 +08:00
|
|
|
osg::notify(osg::INFO) << " replace duplicate "<<*current<<" with "<<*first_unique<< std::endl;
|
2001-10-19 22:22:02 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Flatten static transforms
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void Optimizer::FlattenStaticTransformsVisitor::apply(osg::Geode& geode)
|
|
|
|
{
|
2002-02-10 06:29:40 +08:00
|
|
|
|
|
|
|
osg::Matrix matrix;
|
|
|
|
if (!_matrixStack.empty()) matrix = _matrixStack.back();
|
|
|
|
|
|
|
|
for(int i=0;i<geode.getNumDrawables();++i)
|
2001-10-19 22:22:02 +08:00
|
|
|
{
|
2002-02-10 06:29:40 +08:00
|
|
|
// register each drawable with the objectMap.
|
|
|
|
_objectMap[geode.getDrawable(i)].add(_transformStack,matrix);
|
2001-10-19 22:22:02 +08:00
|
|
|
}
|
2002-02-10 06:29:40 +08:00
|
|
|
|
2001-10-19 22:22:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void Optimizer::FlattenStaticTransformsVisitor::apply(osg::Billboard& billboard)
|
|
|
|
{
|
|
|
|
if (!_matrixStack.empty())
|
|
|
|
{
|
2002-01-23 03:30:51 +08:00
|
|
|
// register ourselves with the objectMap.
|
|
|
|
_objectMap[&billboard].add(_transformStack,_matrixStack.back());
|
2001-10-19 22:22:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Optimizer::FlattenStaticTransformsVisitor::apply(osg::LOD& lod)
|
|
|
|
{
|
|
|
|
if (!_matrixStack.empty())
|
|
|
|
{
|
2002-01-23 03:30:51 +08:00
|
|
|
// register ourselves with the objectMap.
|
|
|
|
_objectMap[&lod].add(_transformStack,_matrixStack.back());
|
2001-10-19 22:22:02 +08:00
|
|
|
}
|
2002-01-23 03:30:51 +08:00
|
|
|
|
2001-10-19 22:22:02 +08:00
|
|
|
traverse(lod);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Optimizer::FlattenStaticTransformsVisitor::apply(osg::Transform& transform)
|
|
|
|
{
|
2001-12-17 23:05:06 +08:00
|
|
|
if (_ignoreDynamicTransforms && transform.getType()==osg::Transform::DYNAMIC)
|
2001-10-19 22:22:02 +08:00
|
|
|
{
|
2001-12-17 23:05:06 +08:00
|
|
|
// simple traverse the children as if this Transform didn't exist.
|
|
|
|
traverse(transform);
|
2001-10-19 22:22:02 +08:00
|
|
|
}
|
|
|
|
else
|
2001-12-17 23:05:06 +08:00
|
|
|
{
|
2002-02-06 16:57:06 +08:00
|
|
|
osg::ref_ptr<osg::Matrix> matrix = new osg::Matrix;
|
|
|
|
transform.getLocalToWorldMatrix(*matrix,this);
|
|
|
|
|
|
|
|
if (!_matrixStack.empty())
|
2001-12-17 23:05:06 +08:00
|
|
|
{
|
2002-02-06 16:57:06 +08:00
|
|
|
matrix->postMult(_matrixStack.back());
|
2001-12-17 23:05:06 +08:00
|
|
|
}
|
2002-02-06 16:57:06 +08:00
|
|
|
_matrixStack.push_back(*matrix);
|
2001-10-19 22:22:02 +08:00
|
|
|
|
2002-01-23 03:30:51 +08:00
|
|
|
_transformStack.push_back(&transform);
|
2001-10-19 22:22:02 +08:00
|
|
|
|
2001-12-17 23:05:06 +08:00
|
|
|
// simple traverse the children as if this Transform didn't exist.
|
|
|
|
traverse(transform);
|
2001-10-19 22:22:02 +08:00
|
|
|
|
2002-01-23 03:30:51 +08:00
|
|
|
_transformStack.pop_back();
|
|
|
|
|
2001-12-17 23:05:06 +08:00
|
|
|
_matrixStack.pop_back();
|
|
|
|
}
|
2001-10-19 22:22:02 +08:00
|
|
|
}
|
|
|
|
|
2002-01-23 03:30:51 +08:00
|
|
|
void Optimizer::FlattenStaticTransformsVisitor::doTransform(osg::Object* obj,osg::Matrix& matrix)
|
|
|
|
{
|
|
|
|
osg::Drawable* drawable = dynamic_cast<osg::Drawable*>(obj);
|
|
|
|
if (drawable)
|
|
|
|
{
|
|
|
|
TransformFunctor tf(matrix);
|
|
|
|
drawable->applyAttributeOperation(tf);
|
|
|
|
drawable->dirtyBound();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
osg::LOD* lod = dynamic_cast<osg::LOD*>(obj);
|
|
|
|
if (lod)
|
|
|
|
{
|
|
|
|
osg::Matrix matrix_no_trans = matrix;
|
|
|
|
matrix_no_trans.setTrans(0.0f,0.0f,0.0f);
|
|
|
|
|
|
|
|
osg::Vec3 v111(1.0f,1.0f,1.0f);
|
|
|
|
osg::Vec3 new_v111 = v111*matrix_no_trans;
|
|
|
|
float ratio = new_v111.length()/v111.length();
|
|
|
|
|
|
|
|
// move center point.
|
|
|
|
lod->setCenter(lod->getCenter()*matrix);
|
|
|
|
|
|
|
|
// adjust ranges to new scale.
|
|
|
|
for(int i=0;i<lod->getNumRanges();++i)
|
|
|
|
{
|
|
|
|
lod->setRange(i,lod->getRange(i)*ratio);
|
|
|
|
}
|
|
|
|
|
|
|
|
lod->dirtyBound();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
osg::Billboard* billboard = dynamic_cast<osg::Billboard*>(obj);
|
|
|
|
if (billboard)
|
|
|
|
{
|
|
|
|
osg::Matrix matrix_no_trans = matrix;
|
|
|
|
matrix_no_trans.setTrans(0.0f,0.0f,0.0f);
|
|
|
|
|
|
|
|
TransformFunctor tf(matrix_no_trans);
|
|
|
|
|
|
|
|
osg::Vec3 axis = osg::Matrix::transform3x3(tf._im,billboard->getAxis());
|
|
|
|
axis.normalize();
|
|
|
|
billboard->setAxis(axis);
|
|
|
|
|
|
|
|
for(int i=0;i<billboard->getNumDrawables();++i)
|
|
|
|
{
|
|
|
|
billboard->setPos(i,billboard->getPos(i)*matrix);
|
|
|
|
billboard->getDrawable(i)->applyAttributeOperation(tf);
|
|
|
|
}
|
|
|
|
|
|
|
|
billboard->dirtyBound();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Optimizer::FlattenStaticTransformsVisitor::disableObject(ObjectMap::iterator itr)
|
|
|
|
{
|
2002-02-03 03:49:47 +08:00
|
|
|
if (itr==_objectMap.end())
|
2002-01-23 03:30:51 +08:00
|
|
|
{
|
|
|
|
// Euston we have a problem..
|
|
|
|
osg::notify(osg::WARN)<<"Warning: internal error Optimizer::FlattenStaticTransformsVisitor::disableObject()"<<std::endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (itr->second._canBeApplied)
|
|
|
|
{
|
|
|
|
// we havn't been disabled yet so we need to disable,
|
|
|
|
itr->second._canBeApplied = false;
|
|
|
|
|
|
|
|
// and then inform everybody we have been disabled.
|
|
|
|
for(ObjectStruct::TransformSet::iterator titr = itr->second._transformSet.begin();
|
|
|
|
titr != itr->second._transformSet.end();
|
|
|
|
++titr)
|
|
|
|
{
|
|
|
|
disableTransform(*titr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Optimizer::FlattenStaticTransformsVisitor::disableTransform(osg::Transform* transform)
|
|
|
|
{
|
|
|
|
TransformMap::iterator itr=_transformMap.find(transform);
|
|
|
|
if (itr==_transformMap.end())
|
|
|
|
{
|
|
|
|
// Euston we have a problem..
|
|
|
|
osg::notify(osg::WARN)<<"Warning: internal error Optimizer::FlattenStaticTransformsVisitor::disableTransform()"<<std::endl;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (itr->second._canBeApplied)
|
|
|
|
{
|
|
|
|
|
|
|
|
// we havn't been disabled yet so we need to disable,
|
|
|
|
itr->second._canBeApplied = false;
|
|
|
|
// and then inform everybody we have been disabled.
|
|
|
|
for(TransformStruct::ObjectSet::iterator oitr = itr->second._objectSet.begin();
|
|
|
|
oitr != itr->second._objectSet.end();
|
|
|
|
++oitr)
|
|
|
|
{
|
|
|
|
disableObject(*oitr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-10-19 22:22:02 +08:00
|
|
|
void Optimizer::FlattenStaticTransformsVisitor::removeTransforms()
|
|
|
|
{
|
2002-01-23 03:30:51 +08:00
|
|
|
|
|
|
|
// create the TransformMap from the ObjectMap
|
|
|
|
ObjectMap::iterator oitr;
|
|
|
|
for(oitr=_objectMap.begin();
|
|
|
|
oitr!=_objectMap.end();
|
|
|
|
++oitr)
|
2001-10-19 22:22:02 +08:00
|
|
|
{
|
2002-01-23 03:30:51 +08:00
|
|
|
osg::Object* object = oitr->first;
|
|
|
|
ObjectStruct& os = oitr->second;
|
|
|
|
|
|
|
|
for(ObjectStruct::TransformSet::iterator titr = os._transformSet.begin();
|
|
|
|
titr != os._transformSet.end();
|
|
|
|
++titr)
|
|
|
|
{
|
|
|
|
_transformMap[*titr].add(object);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-10-19 22:22:02 +08:00
|
|
|
|
2002-01-23 03:30:51 +08:00
|
|
|
// disable all the objects which have more than one matrix associated
|
|
|
|
// with them, and then disable all transforms which have an object associated
|
|
|
|
// them that can't be applied, and then disable all objects which have
|
|
|
|
// disabled transforms associated, recursing until all disabled
|
|
|
|
// associativity.
|
|
|
|
for(oitr=_objectMap.begin();
|
|
|
|
oitr!=_objectMap.end();
|
|
|
|
++oitr)
|
|
|
|
{
|
|
|
|
ObjectStruct& os = oitr->second;
|
|
|
|
if (os._canBeApplied)
|
2001-10-19 22:22:02 +08:00
|
|
|
{
|
2002-01-23 03:30:51 +08:00
|
|
|
if (os._moreThanOneMatrixRequired)
|
2001-10-19 22:22:02 +08:00
|
|
|
{
|
2002-01-23 03:30:51 +08:00
|
|
|
disableObject(oitr);
|
2001-10-19 22:22:02 +08:00
|
|
|
}
|
|
|
|
}
|
2002-01-23 03:30:51 +08:00
|
|
|
}
|
2001-10-19 22:22:02 +08:00
|
|
|
|
2002-01-23 03:30:51 +08:00
|
|
|
// transform the objects that can be applied.
|
|
|
|
for(oitr=_objectMap.begin();
|
|
|
|
oitr!=_objectMap.end();
|
|
|
|
++oitr)
|
|
|
|
{
|
|
|
|
osg::Object* object = oitr->first;
|
|
|
|
ObjectStruct& os = oitr->second;
|
|
|
|
if (os._canBeApplied)
|
2001-10-19 22:22:02 +08:00
|
|
|
{
|
2002-01-23 03:30:51 +08:00
|
|
|
doTransform(object,os._matrix);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-10-19 22:22:02 +08:00
|
|
|
|
2002-01-23 03:30:51 +08:00
|
|
|
// clean up the transforms.
|
|
|
|
for(TransformMap::iterator titr=_transformMap.begin();
|
|
|
|
titr!=_transformMap.end();
|
|
|
|
++titr)
|
|
|
|
{
|
|
|
|
if (titr->second._canBeApplied)
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
osg::ref_ptr<osg::Transform> transform = titr->first;
|
|
|
|
osg::ref_ptr<osg::Group> group = new osg::Group;
|
|
|
|
|
|
|
|
int i;
|
|
|
|
for(i=0;i<transform->getNumChildren();++i)
|
|
|
|
{
|
|
|
|
for(int j=0;j<transform->getNumParents();++j)
|
|
|
|
{
|
|
|
|
group->addChild(transform->getChild(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i=transform->getNumParents()-1;i>=0;--i)
|
|
|
|
{
|
|
|
|
transform->getParent(i)->replaceChild(transform.get(),group.get());
|
|
|
|
}
|
|
|
|
}
|
2001-10-19 22:22:02 +08:00
|
|
|
}
|
2002-01-23 03:30:51 +08:00
|
|
|
_objectMap.clear();
|
|
|
|
_transformMap.clear();
|
|
|
|
_transformStack.clear();
|
|
|
|
_matrixStack.clear();
|
2001-10-19 22:22:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// RemoveRedundentNodes.
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
void Optimizer::RemoveRedundentNodesVisitor::apply(osg::Group& group)
|
|
|
|
{
|
|
|
|
if (typeid(group)==typeid(osg::Group))
|
|
|
|
{
|
|
|
|
if (group.getNumParents()>0 && group.getNumChildren()<=1)
|
|
|
|
{
|
Added support for shallow and deep copy of nodes, drawables and state, via a
copy constructor which takes an optional Cloner object, and the old
osg::Object::clone() has changed so that it now requires a Cloner as paramter.
This is passed on to the copy constructor to help control the shallow vs
deep copying. The old functionality of clone() which was clone of type has
been renamed to cloneType().
Updated all of the OSG to work with these new conventions, implemention all
the required copy constructors etc. A couple of areas will do shallow
copies by design, a couple of other still need to be updated to do either
shallow or deep.
Neither of the shallow or deep copy operations have been tested yet, only
the old functionality of the OSG has been checked so far, such running the
viewer on various demo datasets.
Also fixed a problem in osg::Optimize::RemoveRendundentNodesVisitor which
was not checking that Group didn't have have any attached StateSet's, Callbacks
or UserData. These checks have now been added, which fixes a bug which was
revealled by the new osgscribe demo, this related to removal of group acting
as state decorator.
method
2002-01-29 05:17:01 +08:00
|
|
|
if (!group.getUserData() &&
|
|
|
|
!group.getAppCallback() &&
|
|
|
|
!group.getStateSet())
|
|
|
|
{
|
|
|
|
_redundentNodeList.insert(&group);
|
|
|
|
}
|
2001-10-19 22:22:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
traverse(group);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Optimizer::RemoveRedundentNodesVisitor::removeRedundentNodes()
|
|
|
|
{
|
|
|
|
for(NodeList::iterator itr=_redundentNodeList.begin();
|
|
|
|
itr!=_redundentNodeList.end();
|
|
|
|
++itr)
|
|
|
|
{
|
|
|
|
osg::ref_ptr<osg::Group> group = dynamic_cast<osg::Group*>(*itr);
|
|
|
|
if (group.valid())
|
|
|
|
{
|
2002-01-23 23:28:31 +08:00
|
|
|
// take a copy of parents list since subsequent removes will modify the original one.
|
|
|
|
osg::Node::ParentList parents = group->getParents();
|
|
|
|
|
|
|
|
if (group->getNumChildren()==0)
|
|
|
|
{
|
|
|
|
for(osg::Node::ParentList::iterator pitr=parents.begin();
|
|
|
|
pitr!=parents.end();
|
|
|
|
++pitr)
|
|
|
|
{
|
|
|
|
(*pitr)->removeChild(group.get());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (group->getNumChildren()==1)
|
2001-10-19 22:22:02 +08:00
|
|
|
{
|
2002-01-23 23:28:31 +08:00
|
|
|
osg::Node* child = group->getChild(0);
|
|
|
|
for(osg::Node::ParentList::iterator pitr=parents.begin();
|
|
|
|
pitr!=parents.end();
|
|
|
|
++pitr)
|
2001-10-19 22:22:02 +08:00
|
|
|
{
|
2002-01-23 23:28:31 +08:00
|
|
|
(*pitr)->replaceChild(group.get(),child);
|
2001-10-19 22:22:02 +08:00
|
|
|
}
|
2002-01-23 23:28:31 +08:00
|
|
|
|
2001-10-19 22:22:02 +08:00
|
|
|
}
|
2002-01-23 23:28:31 +08:00
|
|
|
else // (group->getNumChildren()>1)
|
|
|
|
{
|
|
|
|
osg::notify(osg::WARN)<<"Warning: Optimizer::RemoveRedundentNodesVisitor has incorrectly assigned Group to remove."<<std::endl;
|
|
|
|
osg::notify(osg::WARN)<<" Safely ignoring remove operation for this group."<<std::endl;
|
|
|
|
}
|
|
|
|
|
2001-10-19 22:22:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_redundentNodeList.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
// combine LOD's.
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void Optimizer::CombineLODsVisitor::apply(osg::LOD& lod)
|
|
|
|
{
|
|
|
|
for(int i=0;i<lod.getNumParents();++i)
|
|
|
|
{
|
|
|
|
if (typeid(*lod.getParent(i))==typeid(osg::Group))
|
|
|
|
{
|
|
|
|
_groupList.insert(lod.getParent(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
traverse(lod);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Optimizer::CombineLODsVisitor::combineLODs()
|
|
|
|
{
|
|
|
|
for(GroupList::iterator itr=_groupList.begin();
|
|
|
|
itr!=_groupList.end();
|
|
|
|
++itr)
|
|
|
|
{
|
|
|
|
osg::Group* group = *itr;
|
|
|
|
|
|
|
|
typedef std::set<osg::LOD*> LODSet;
|
|
|
|
|
|
|
|
LODSet lodChildren;
|
|
|
|
|
|
|
|
for(int i=0;i<group->getNumChildren();++i)
|
|
|
|
{
|
|
|
|
osg::Node* child = group->getChild(i);
|
|
|
|
osg::LOD* lod = dynamic_cast<osg::LOD*>(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<float,float> RangePair;
|
|
|
|
typedef std::multimap<RangePair,osg::Node*> 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;i<lod->getNumRanges()-1;++i)
|
|
|
|
{
|
|
|
|
if (maxRange<lod->getRange(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();
|
|
|
|
}
|
|
|
|
|