416 lines
16 KiB
C++
416 lines
16 KiB
C++
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
|
|
*
|
|
* This library is open source and may be redistributed and/or modified under
|
|
* the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
|
|
* (at your option) any later version. The full license is in LICENSE file
|
|
* included with this distribution, and on the openscenegraph.org website.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* OpenSceneGraph Public License for more details.
|
|
*/
|
|
|
|
#ifndef OSGUTIL_OPTIMIZER
|
|
#define OSGUTIL_OPTIMIZER
|
|
|
|
#include <osg/NodeVisitor>
|
|
#include <osg/Matrix>
|
|
#include <osg/Geometry>
|
|
#include <osg/Transform>
|
|
|
|
#include <osgUtil/Export>
|
|
|
|
#include <set>
|
|
|
|
namespace osgUtil {
|
|
|
|
/** Insert impostor nodes into scene graph.
|
|
* For example of usage see src/Demos/osgimpostor.
|
|
*/
|
|
|
|
class OSGUTIL_EXPORT Optimizer
|
|
{
|
|
|
|
public:
|
|
|
|
Optimizer() {}
|
|
virtual ~Optimizer() {}
|
|
|
|
enum OptimizationOptions
|
|
{
|
|
FLATTEN_STATIC_TRANSFORMS = 0x001,
|
|
REMOVE_REDUNDANT_NODES = 0x002,
|
|
COMBINE_ADJACENT_LODS = 0x004,
|
|
SHARE_DUPLICATE_STATE = 0x008,
|
|
MERGE_GEOMETRY = 0x010,
|
|
CHECK_GEOMETRY = 0x020,
|
|
SPATIALIZE_GROUPS = 0x040,
|
|
COPY_SHARED_NODES = 0x080,
|
|
TRISTRIP_GEOMETRY = 0x100,
|
|
TESSELATE_GEOMETRY = 0x200,
|
|
DEFAULT_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS |
|
|
REMOVE_REDUNDANT_NODES |
|
|
COMBINE_ADJACENT_LODS |
|
|
SHARE_DUPLICATE_STATE |
|
|
MERGE_GEOMETRY |
|
|
CHECK_GEOMETRY,
|
|
ALL_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS |
|
|
REMOVE_REDUNDANT_NODES |
|
|
COMBINE_ADJACENT_LODS |
|
|
SHARE_DUPLICATE_STATE |
|
|
MERGE_GEOMETRY |
|
|
CHECK_GEOMETRY |
|
|
SPATIALIZE_GROUPS |
|
|
COPY_SHARED_NODES |
|
|
TRISTRIP_GEOMETRY
|
|
};
|
|
|
|
/** reset internal data to initial state - the getPrimissableOptionsMap is cleared.*/
|
|
void reset();
|
|
|
|
/** traverse the node and its subgraph with a series of optimization
|
|
* visitors, specificied by the OptizationOptions.*/
|
|
void optimize(osg::Node* node);
|
|
|
|
/** traverse the node and its subgraph with a series of optimization
|
|
* visitors, specificied by the OptizationOptions.*/
|
|
virtual void optimize(osg::Node* node, unsigned int options);
|
|
|
|
|
|
inline void setPermissableOptimizationsForObject(const osg::Object* object, unsigned int options)
|
|
{
|
|
_permissableOptimizationsMap[object] = options;
|
|
}
|
|
|
|
inline unsigned int getPermissableOptimizationsForObject(const osg::Object* object) const
|
|
{
|
|
PermissableOptimizationsMap::const_iterator itr = _permissableOptimizationsMap.find(object);
|
|
if (itr!=_permissableOptimizationsMap.end()) return itr->second;
|
|
else return 0xffffffff;
|
|
}
|
|
|
|
inline bool isOperationPermissableForObject(const osg::Object* object,unsigned int option) const
|
|
{
|
|
return (option & getPermissableOptimizationsForObject(object))!=0;
|
|
}
|
|
|
|
typedef std::map<const osg::Object*,unsigned int> PermissableOptimizationsMap;
|
|
|
|
PermissableOptimizationsMap& getPrimissableOptionsMap() { return _permissableOptimizationsMap; }
|
|
const PermissableOptimizationsMap& getPrimissableOptionsMap() const { return _permissableOptimizationsMap; }
|
|
|
|
|
|
protected:
|
|
|
|
PermissableOptimizationsMap _permissableOptimizationsMap;
|
|
|
|
|
|
public:
|
|
|
|
|
|
/** Flatten Static Trasform nodes by applying their transform to the
|
|
* geometry on the leaves of the scene graph, then removing the
|
|
* now redundant transforms.*/
|
|
class OSGUTIL_EXPORT FlattenStaticTransformsVisitor : public osg::NodeVisitor
|
|
{
|
|
public:
|
|
|
|
|
|
|
|
FlattenStaticTransformsVisitor(Optimizer* optimizer=0):
|
|
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
|
_optimizer(optimizer) {}
|
|
|
|
virtual void apply(osg::Geode& geode);
|
|
virtual void apply(osg::Billboard& geode);
|
|
virtual void apply(osg::Transform& transform);
|
|
|
|
bool removeTransforms(osg::Node* nodeWeCannotRemove);
|
|
|
|
inline bool isOperationPermissableForObject(const osg::Object* object) const
|
|
{
|
|
return _optimizer ? _optimizer->isOperationPermissableForObject(object,FLATTEN_STATIC_TRANSFORMS) : true;
|
|
}
|
|
|
|
|
|
protected:
|
|
|
|
typedef std::vector<osg::Transform*> TransformStack;
|
|
typedef std::set<osg::Drawable*> DrawableSet;
|
|
typedef std::set<osg::Billboard*> BillboardSet;
|
|
typedef std::set<osg::Transform*> TransformSet;
|
|
|
|
Optimizer* _optimizer;
|
|
TransformStack _transformStack;
|
|
DrawableSet _drawableSet;
|
|
BillboardSet _billboardSet;
|
|
TransformSet _transformSet;
|
|
};
|
|
|
|
|
|
/** Combine Static Trasform nodes that sit above on another.*/
|
|
class OSGUTIL_EXPORT CombineStaticTransformsVisitor : public osg::NodeVisitor
|
|
{
|
|
public:
|
|
|
|
CombineStaticTransformsVisitor(Optimizer* optimizer=0):
|
|
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
|
_optimizer(optimizer) {}
|
|
|
|
virtual void apply(osg::MatrixTransform& transform);
|
|
|
|
bool removeTransforms(osg::Node* nodeWeCannotRemove);
|
|
|
|
inline bool isOperationPermissableForObject(const osg::Object* object) const
|
|
{
|
|
return _optimizer ? _optimizer->isOperationPermissableForObject(object,FLATTEN_STATIC_TRANSFORMS) : true;
|
|
}
|
|
|
|
protected:
|
|
|
|
typedef std::set<osg::MatrixTransform*> TransformSet;
|
|
Optimizer* _optimizer;
|
|
TransformSet _transformSet;
|
|
};
|
|
|
|
/** Remove rendundant nodes, such as groups with one single child.*/
|
|
class OSGUTIL_EXPORT RemoveEmptyNodesVisitor : public osg::NodeVisitor
|
|
{
|
|
public:
|
|
|
|
|
|
typedef std::set<osg::Node*> NodeList;
|
|
NodeList _redundantNodeList;
|
|
|
|
RemoveEmptyNodesVisitor(Optimizer* optimizer=0):
|
|
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
|
_optimizer(optimizer) {}
|
|
|
|
virtual void apply(osg::Geode& geode);
|
|
virtual void apply(osg::Group& group);
|
|
|
|
void removeEmptyNodes();
|
|
|
|
inline bool isOperationPermissableForObject(const osg::Object* object) const
|
|
{
|
|
return _optimizer ? _optimizer->isOperationPermissableForObject(object,REMOVE_REDUNDANT_NODES) : true;
|
|
}
|
|
|
|
Optimizer* _optimizer;
|
|
};
|
|
|
|
/** Remove rendundant nodes, such as groups with one single child.*/
|
|
class OSGUTIL_EXPORT RemoveRedundantNodesVisitor : public osg::NodeVisitor
|
|
{
|
|
public:
|
|
|
|
typedef std::set<osg::Node*> NodeList;
|
|
NodeList _redundantNodeList;
|
|
|
|
RemoveRedundantNodesVisitor(Optimizer* optimizer=0):
|
|
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
|
_optimizer(optimizer) {}
|
|
|
|
virtual void apply(osg::Group& group);
|
|
virtual void apply(osg::Transform& transform);
|
|
|
|
void removeRedundantNodes();
|
|
|
|
inline bool isOperationPermissableForObject(const osg::Object* object) const
|
|
{
|
|
return _optimizer ? _optimizer->isOperationPermissableForObject(object,REMOVE_REDUNDANT_NODES) : true;
|
|
}
|
|
|
|
Optimizer* _optimizer;
|
|
};
|
|
|
|
/** Tesselate all geodes, to remove POLYGONS
|
|
* complementary ranges.*/
|
|
class OSGUTIL_EXPORT TesselateVisitor : public osg::NodeVisitor
|
|
{
|
|
public:
|
|
|
|
typedef std::set<osg::Group*> GroupList;
|
|
GroupList _groupList;
|
|
|
|
TesselateVisitor():osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) {}
|
|
|
|
virtual void apply(osg::Geode& geode);
|
|
|
|
};
|
|
|
|
/** Optimize the LOD groups, by combining adjacent LOD's which have
|
|
* complementary ranges.*/
|
|
class OSGUTIL_EXPORT CombineLODsVisitor : public osg::NodeVisitor
|
|
{
|
|
public:
|
|
|
|
typedef std::set<osg::Group*> GroupList;
|
|
GroupList _groupList;
|
|
|
|
CombineLODsVisitor(Optimizer* optimizer=0):
|
|
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
|
_optimizer(optimizer) {}
|
|
|
|
virtual void apply(osg::LOD& lod);
|
|
|
|
void combineLODs();
|
|
|
|
inline bool isOperationPermissableForObject(const osg::Object* object) const
|
|
{
|
|
return _optimizer ? _optimizer->isOperationPermissableForObject(object,COMBINE_ADJACENT_LODS) : true;
|
|
}
|
|
|
|
Optimizer* _optimizer;
|
|
};
|
|
|
|
/** Optimize State in the scene graph by removing duplicate state,
|
|
* replacing it with shared instances, both for StateAttributes,
|
|
* and whole StateSets.*/
|
|
class OSGUTIL_EXPORT StateVisitor : public osg::NodeVisitor
|
|
{
|
|
public:
|
|
|
|
/// default to traversing all children.
|
|
StateVisitor(Optimizer* optimizer=0):
|
|
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
|
_optimizer(optimizer) {}
|
|
|
|
/** empty visitor, make it ready for next traversal.*/
|
|
virtual void reset();
|
|
|
|
virtual void apply(osg::Node& node);
|
|
|
|
virtual void apply(osg::Geode& geode);
|
|
|
|
void optimize();
|
|
|
|
inline bool isOperationPermissableForObject(const osg::Object* object) const
|
|
{
|
|
return _optimizer ? _optimizer->isOperationPermissableForObject(object,SHARE_DUPLICATE_STATE) : true;
|
|
}
|
|
|
|
protected:
|
|
|
|
void addStateSet(osg::StateSet* stateset,osg::Object* obj);
|
|
|
|
typedef std::set<osg::Object*> ObjectSet;
|
|
typedef std::map<osg::StateSet*,ObjectSet> StateSetMap;
|
|
|
|
Optimizer* _optimizer;
|
|
StateSetMap _statesets;
|
|
|
|
};
|
|
|
|
class OSGUTIL_EXPORT CheckGeometryVisitor : public osg::NodeVisitor
|
|
{
|
|
public:
|
|
|
|
/// default to traversing all children.
|
|
CheckGeometryVisitor(Optimizer* optimizer=0):
|
|
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
|
_optimizer(optimizer) {}
|
|
|
|
virtual void apply(osg::Geode& geode) { checkGeode(geode); }
|
|
|
|
void checkGeode(osg::Geode& geode);
|
|
|
|
inline bool isOperationPermissableForObject(const osg::Object* object) const
|
|
{
|
|
return _optimizer ? _optimizer->isOperationPermissableForObject(object,CHECK_GEOMETRY) : true;
|
|
}
|
|
|
|
Optimizer* _optimizer;
|
|
|
|
};
|
|
|
|
class OSGUTIL_EXPORT MergeGeometryVisitor : public osg::NodeVisitor
|
|
{
|
|
public:
|
|
|
|
/// default to traversing all children.
|
|
MergeGeometryVisitor(Optimizer* optimizer=0) :
|
|
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
|
_optimizer(optimizer) {}
|
|
|
|
virtual void apply(osg::Geode& geode) { mergeGeode(geode); }
|
|
virtual void apply(osg::Billboard&) { /* don't do anything*/ }
|
|
|
|
bool mergeGeode(osg::Geode& geode);
|
|
|
|
static bool geometryContainsSharedArrays(osg::Geometry& geom);
|
|
|
|
static bool mergeGeometry(osg::Geometry& lhs,osg::Geometry& rhs);
|
|
|
|
static bool mergePrimitive(osg::DrawArrays& lhs,osg::DrawArrays& rhs);
|
|
static bool mergePrimitive(osg::DrawArrayLengths& lhs,osg::DrawArrayLengths& rhs);
|
|
static bool mergePrimitive(osg::DrawElementsUByte& lhs,osg::DrawElementsUByte& rhs);
|
|
static bool mergePrimitive(osg::DrawElementsUShort& lhs,osg::DrawElementsUShort& rhs);
|
|
static bool mergePrimitive(osg::DrawElementsUInt& lhs,osg::DrawElementsUInt& rhs);
|
|
|
|
inline bool isOperationPermissableForObject(const osg::Object* object) const
|
|
{
|
|
return _optimizer ? _optimizer->isOperationPermissableForObject(object,MERGE_GEOMETRY) : true;
|
|
}
|
|
|
|
Optimizer* _optimizer;
|
|
};
|
|
|
|
/** Spatialize scene into a balanced quad/oct tree.*/
|
|
class OSGUTIL_EXPORT SpatializeGroupsVisitor : public osg::NodeVisitor
|
|
{
|
|
public:
|
|
|
|
SpatializeGroupsVisitor(Optimizer* optimizer=0):
|
|
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
|
_optimizer(optimizer) {}
|
|
|
|
virtual void apply(osg::Group& group);
|
|
|
|
bool divide(unsigned int maxNumTreesPerCell=8);
|
|
|
|
bool divide(osg::Group* group, unsigned int maxNumTreesPerCell);
|
|
|
|
typedef std::set<osg::Group*> GroupsToDivideList;
|
|
GroupsToDivideList _groupsToDivideList;
|
|
|
|
inline bool isOperationPermissableForObject(const osg::Object* object) const
|
|
{
|
|
return _optimizer ? _optimizer->isOperationPermissableForObject(object,SPATIALIZE_GROUPS) : true;
|
|
}
|
|
|
|
Optimizer* _optimizer;
|
|
|
|
};
|
|
|
|
/** Copy any shared subgraphs, enabling flattening of static transforms.*/
|
|
class OSGUTIL_EXPORT CopySharedSubgraphsVisitor : public osg::NodeVisitor
|
|
{
|
|
public:
|
|
|
|
CopySharedSubgraphsVisitor(Optimizer* optimizer=0):
|
|
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
|
_optimizer(optimizer) {}
|
|
|
|
virtual void apply(osg::Node& node);
|
|
|
|
void copySharedNodes();
|
|
|
|
typedef std::set<osg::Node*> SharedNodeList;
|
|
SharedNodeList _sharedNodeList;
|
|
|
|
inline bool isOperationPermissableForObject(const osg::Object* object) const
|
|
{
|
|
return _optimizer ? _optimizer->isOperationPermissableForObject(object,COPY_SHARED_NODES) : true;
|
|
}
|
|
|
|
Optimizer* _optimizer;
|
|
|
|
};
|
|
};
|
|
|
|
}
|
|
|
|
#endif
|