/* -*-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 #include #include #include #include #include namespace osgUtil { /** Traverses scene graph to improve efficiency. See OptimizationOptions. * For example of usage see examples/osgimpostor or osgviewer. */ 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, OPTIMIZE_TEXTURE_SETTINGS = 0x400, DEFAULT_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS | REMOVE_REDUNDANT_NODES | COMBINE_ADJACENT_LODS | SHARE_DUPLICATE_STATE | MERGE_GEOMETRY | CHECK_GEOMETRY | OPTIMIZE_TEXTURE_SETTINGS, 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 | OPTIMIZE_TEXTURE_SETTINGS }; /** Reset internal data to initial state - the getPermissibleOptionsMap is cleared.*/ void reset(); /** Traverse the node and its subgraph with a series of optimization * visitors, specified by the OptimizationOptions.*/ void optimize(osg::Node* node); /** Traverse the node and its subgraph with a series of optimization * visitors, specified by the OptimizationOptions.*/ virtual void optimize(osg::Node* node, unsigned int options); inline void setPermissibleOptimizationsForObject(const osg::Object* object, unsigned int options) { _permissibleOptimizationsMap[object] = options; } inline unsigned int getPermissibleOptimizationsForObject(const osg::Object* object) const { PermissibleOptimizationsMap::const_iterator itr = _permissibleOptimizationsMap.find(object); if (itr!=_permissibleOptimizationsMap.end()) return itr->second; else return 0xffffffff; } inline bool isOperationPermissibleForObject(const osg::Object* object,unsigned int option) const { return (option & getPermissibleOptimizationsForObject(object))!=0; } typedef std::map PermissibleOptimizationsMap; PermissibleOptimizationsMap& getPermissibleOptionsMap() { return _permissibleOptimizationsMap; } const PermissibleOptimizationsMap& getPermissibleOptionsMap() const { return _permissibleOptimizationsMap; } protected: PermissibleOptimizationsMap _permissibleOptimizationsMap; public: /** Flatten Static Transform 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::Node& geode); 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 isOperationPermissibleForObject(const osg::Object* object) const { return _optimizer ? _optimizer->isOperationPermissibleForObject(object,FLATTEN_STATIC_TRANSFORMS) : true; } protected: typedef std::vector TransformStack; typedef std::set DrawableSet; typedef std::set BillboardSet; typedef std::set NodeSet; typedef std::set TransformSet; Optimizer* _optimizer; TransformStack _transformStack; NodeSet _excludedNodeSet; DrawableSet _drawableSet; BillboardSet _billboardSet; TransformSet _transformSet; }; /** Combine Static Transform nodes that sit above one 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 isOperationPermissibleForObject(const osg::Object* object) const { return _optimizer ? _optimizer->isOperationPermissibleForObject(object,FLATTEN_STATIC_TRANSFORMS) : true; } protected: typedef std::set 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 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 isOperationPermissibleForObject(const osg::Object* object) const { return _optimizer ? _optimizer->isOperationPermissibleForObject(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 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 isOperationPermissibleForObject(const osg::Object* object) const { return _optimizer ? _optimizer->isOperationPermissibleForObject(object,REMOVE_REDUNDANT_NODES) : true; } Optimizer* _optimizer; }; /** Tesselate all geodes, to remove POLYGONS.*/ class OSGUTIL_EXPORT TesselateVisitor : public osg::NodeVisitor { public: typedef std::set 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 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 isOperationPermissibleForObject(const osg::Object* object) const { return _optimizer ? _optimizer->isOperationPermissibleForObject(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 isOperationPermissibleForObject(const osg::Object* object) const { return _optimizer ? _optimizer->isOperationPermissibleForObject(object,SHARE_DUPLICATE_STATE) : true; } protected: void addStateSet(osg::StateSet* stateset,osg::Object* obj); typedef std::set ObjectSet; typedef std::map 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 isOperationPermissibleForObject(const osg::Object* object) const { return _optimizer ? _optimizer->isOperationPermissibleForObject(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 isOperationPermissibleForObject(const osg::Object* object) const { return _optimizer ? _optimizer->isOperationPermissibleForObject(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 GroupsToDivideList; GroupsToDivideList _groupsToDivideList; inline bool isOperationPermissibleForObject(const osg::Object* object) const { return _optimizer ? _optimizer->isOperationPermissibleForObject(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 SharedNodeList; SharedNodeList _sharedNodeList; inline bool isOperationPermissibleForObject(const osg::Object* object) const { return _optimizer ? _optimizer->isOperationPermissibleForObject(object,COPY_SHARED_NODES) : true; } Optimizer* _optimizer; }; /** For all textures apply settings.*/ class OSGUTIL_EXPORT TextureVisitor : public osg::NodeVisitor { public: TextureVisitor(bool changeAutoUnRef, bool valueAutoUnRef, bool changeClientImageStorage, bool valueClientImageStorage, bool changeAnisotropy, float valueAnisotropy, Optimizer* optimizer=0): osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), _optimizer(optimizer), _changeAutoUnRef(changeAutoUnRef), _valueAutoUnRef(valueAutoUnRef), _changeClientImageStorage(changeClientImageStorage), _valueClientImageStorage(valueClientImageStorage), _changeAnisotropy(changeAnisotropy), _valueAnisotropy(valueAnisotropy) {} virtual void apply(osg::Geode& node); virtual void apply(osg::Node& node); void apply(osg::StateSet& stateset); void apply(osg::Texture& texture); inline bool isOperationPermissibleForObject(const osg::Object* object) const { return _optimizer ? _optimizer->isOperationPermissibleForObject(object,OPTIMIZE_TEXTURE_SETTINGS) : true; } Optimizer* _optimizer; bool _changeAutoUnRef, _valueAutoUnRef; bool _changeClientImageStorage, _valueClientImageStorage; bool _changeAnisotropy; float _valueAnisotropy; }; }; } #endif