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-19 06:03:28 +08:00
|
|
|
#if (defined(_MSC_VER) && _MSC_VER<1300 && !defined(_STLPORT_VERSION))
|
2002-03-01 17:29:56 +08:00
|
|
|
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();
|
Added DataVariance enum and set/get fields to osg::Object to help identify
which objects have values that vary over the lifetime of the object (DYNAMIC)
and ones that do not vary (STATIC). Removed the equivalent code in
osg::Transform, StateSet and StateAttribute, as these are now encompassed
by the new DataVariance field.
Removed MatrixMode enum from Matrix, and associated fields/parameters from
osg::Transfrom and osg::NodeVisitor, since MatrixMode was not providing
any useful functionality, but made the interface more complex (MatrixMode
was an experimental API)
Added ReferenceFrame field to osg::Transform which allows users to specify
transforms that are relative to their parents (the default, and previous behavior)
or absolute reference frame, which can be used for HUD's, camera relative
light sources etc etc. Note, the view frustum culling for absolute Transform
are disabled, and all their parents up to the root are also automatically
have view frustum culling disabled. However, once passed an absolute Transform
node culling will return to its default state of on, so you can still cull
underneath an absolute transform, its only the culling above which is disabled.
2002-04-12 07:20:23 +08:00
|
|
|
if (ss && ss->getDataVariance()==osg::Object::STATIC) addStateSet(ss,&node);
|
2001-10-19 22:22:02 +08:00
|
|
|
|
|
|
|
traverse(node);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Optimizer::StateVisitor::apply(osg::Geode& geode)
|
|
|
|
{
|
|
|
|
osg::StateSet* ss = geode.getStateSet();
|
Added DataVariance enum and set/get fields to osg::Object to help identify
which objects have values that vary over the lifetime of the object (DYNAMIC)
and ones that do not vary (STATIC). Removed the equivalent code in
osg::Transform, StateSet and StateAttribute, as these are now encompassed
by the new DataVariance field.
Removed MatrixMode enum from Matrix, and associated fields/parameters from
osg::Transfrom and osg::NodeVisitor, since MatrixMode was not providing
any useful functionality, but made the interface more complex (MatrixMode
was an experimental API)
Added ReferenceFrame field to osg::Transform which allows users to specify
transforms that are relative to their parents (the default, and previous behavior)
or absolute reference frame, which can be used for HUD's, camera relative
light sources etc etc. Note, the view frustum culling for absolute Transform
are disabled, and all their parents up to the root are also automatically
have view frustum culling disabled. However, once passed an absolute Transform
node culling will return to its default state of on, so you can still cull
underneath an absolute transform, its only the culling above which is disabled.
2002-04-12 07:20:23 +08:00
|
|
|
if (ss && ss->getDataVariance()==osg::Object::STATIC) addStateSet(ss,&geode);
|
2001-10-19 22:22:02 +08:00
|
|
|
for(int i=0;i<geode.getNumDrawables();++i)
|
|
|
|
{
|
|
|
|
osg::Drawable* drawable = geode.getDrawable(i);
|
|
|
|
if (drawable)
|
|
|
|
{
|
|
|
|
ss = drawable->getStateSet();
|
Added DataVariance enum and set/get fields to osg::Object to help identify
which objects have values that vary over the lifetime of the object (DYNAMIC)
and ones that do not vary (STATIC). Removed the equivalent code in
osg::Transform, StateSet and StateAttribute, as these are now encompassed
by the new DataVariance field.
Removed MatrixMode enum from Matrix, and associated fields/parameters from
osg::Transfrom and osg::NodeVisitor, since MatrixMode was not providing
any useful functionality, but made the interface more complex (MatrixMode
was an experimental API)
Added ReferenceFrame field to osg::Transform which allows users to specify
transforms that are relative to their parents (the default, and previous behavior)
or absolute reference frame, which can be used for HUD's, camera relative
light sources etc etc. Note, the view frustum culling for absolute Transform
are disabled, and all their parents up to the root are also automatically
have view frustum culling disabled. However, once passed an absolute Transform
node culling will return to its default state of on, so you can still cull
underneath an absolute transform, its only the culling above which is disabled.
2002-04-12 07:20:23 +08:00
|
|
|
if (ss && ss->getDataVariance()==osg::Object::STATIC) addStateSet(ss,drawable);
|
2001-10-19 22:22:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
Added DataVariance enum and set/get fields to osg::Object to help identify
which objects have values that vary over the lifetime of the object (DYNAMIC)
and ones that do not vary (STATIC). Removed the equivalent code in
osg::Transform, StateSet and StateAttribute, as these are now encompassed
by the new DataVariance field.
Removed MatrixMode enum from Matrix, and associated fields/parameters from
osg::Transfrom and osg::NodeVisitor, since MatrixMode was not providing
any useful functionality, but made the interface more complex (MatrixMode
was an experimental API)
Added ReferenceFrame field to osg::Transform which allows users to specify
transforms that are relative to their parents (the default, and previous behavior)
or absolute reference frame, which can be used for HUD's, camera relative
light sources etc etc. Note, the view frustum culling for absolute Transform
are disabled, and all their parents up to the root are also automatically
have view frustum culling disabled. However, once passed an absolute Transform
node culling will return to its default state of on, so you can still cull
underneath an absolute transform, its only the culling above which is disabled.
2002-04-12 07:20:23 +08:00
|
|
|
if (aitr->second.first->getDataVariance()==osg::Object::STATIC)
|
2002-03-15 01:34:08 +08:00
|
|
|
{
|
|
|
|
_attributeToStateSetMap[aitr->second.first.get()].insert(sitr->first);
|
|
|
|
}
|
2001-10-19 22:22:02 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
Added DataVariance enum and set/get fields to osg::Object to help identify
which objects have values that vary over the lifetime of the object (DYNAMIC)
and ones that do not vary (STATIC). Removed the equivalent code in
osg::Transform, StateSet and StateAttribute, as these are now encompassed
by the new DataVariance field.
Removed MatrixMode enum from Matrix, and associated fields/parameters from
osg::Transfrom and osg::NodeVisitor, since MatrixMode was not providing
any useful functionality, but made the interface more complex (MatrixMode
was an experimental API)
Added ReferenceFrame field to osg::Transform which allows users to specify
transforms that are relative to their parents (the default, and previous behavior)
or absolute reference frame, which can be used for HUD's, camera relative
light sources etc etc. Note, the view frustum culling for absolute Transform
are disabled, and all their parents up to the root are also automatically
have view frustum culling disabled. However, once passed an absolute Transform
node culling will return to its default state of on, so you can still cull
underneath an absolute transform, its only the culling above which is disabled.
2002-04-12 07:20:23 +08:00
|
|
|
if (_ignoreDynamicTransforms && transform.getDataVariance()==osg::Object::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-03-27 07:52:52 +08:00
|
|
|
osg::ref_ptr<osg::Matrix> matrix = osgNew osg::Matrix;
|
2002-02-06 16:57:06 +08:00
|
|
|
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.
|
2002-04-26 16:16:14 +08:00
|
|
|
for(unsigned int i=0;i<lod->getNumRanges();++i)
|
2002-01-23 03:30:51 +08:00
|
|
|
{
|
|
|
|
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;
|
2002-03-27 07:52:52 +08:00
|
|
|
osg::ref_ptr<osg::Group> group = osgNew osg::Group;
|
2002-05-23 23:35:12 +08:00
|
|
|
group->setDataVariance(osg::Object::STATIC);
|
2002-04-26 16:16:14 +08:00
|
|
|
for(unsigned int i=0;i<transform->getNumChildren();++i)
|
2002-01-23 03:30:51 +08:00
|
|
|
{
|
2002-04-26 16:16:14 +08:00
|
|
|
for(unsigned int j=0;j<transform->getNumParents();++j)
|
2002-01-23 03:30:51 +08:00
|
|
|
{
|
|
|
|
group->addChild(transform->getChild(i));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2002-04-26 20:06:19 +08:00
|
|
|
for(int i2=transform->getNumParents()-1;i2>=0;--i2)
|
2002-01-23 03:30:51 +08:00
|
|
|
{
|
2002-04-26 20:06:19 +08:00
|
|
|
transform->getParent(i2)->replaceChild(transform.get(),group.get());
|
2002-01-23 03:30:51 +08:00
|
|
|
}
|
|
|
|
}
|
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() &&
|
2002-03-15 01:34:08 +08:00
|
|
|
!group.getStateSet() &&
|
2002-05-23 23:35:12 +08:00
|
|
|
group.getNodeMask()==0xffffffff)
|
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
|
|
|
{
|
|
|
|
_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)
|
|
|
|
{
|
2002-04-26 16:16:14 +08:00
|
|
|
for(unsigned int i=0;i<lod.getNumParents();++i)
|
2001-10-19 22:22:02 +08:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
|
2002-04-26 16:16:14 +08:00
|
|
|
for(unsigned int i=0;i<group->getNumChildren();++i)
|
2001-10-19 22:22:02 +08:00
|
|
|
{
|
|
|
|
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;
|
2002-04-26 16:16:14 +08:00
|
|
|
for(unsigned int i=0;i<lod->getNumRanges()-1;++i)
|
2001-10-19 22:22:02 +08:00
|
|
|
{
|
|
|
|
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.
|
2002-03-27 07:52:52 +08:00
|
|
|
osg::LOD* newLOD = osgNew osg::LOD;
|
2001-10-19 22:22:02 +08:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|