1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version. The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * OpenSceneGraph Public License for more details.
14#ifndef OSGUTIL_OPTIMIZER
15#define OSGUTIL_OPTIMIZER
17#include <osg/NodeVisitor>
19#include <osg/Geometry>
20#include <osg/Transform>
21#include <osg/Texture2D>
23#include <osgUtil/Export>
32/** Helper base class for implementing Optimizer techniques.*/
33class OSGUTIL_EXPORT BaseOptimizerVisitor : public osg::NodeVisitor
37 BaseOptimizerVisitor(Optimizer* optimizer, unsigned int operation):
38 osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
39 _optimizer(optimizer),
40 _operationType(operation)
42 setNodeMaskOverride(0xffffffff);
45 inline bool isOperationPermissibleForObject(const osg::StateSet* object) const;
46 inline bool isOperationPermissibleForObject(const osg::StateAttribute* object) const;
47 inline bool isOperationPermissibleForObject(const osg::Drawable* object) const;
48 inline bool isOperationPermissibleForObject(const osg::Node* object) const;
52 Optimizer* _optimizer;
53 unsigned int _operationType;
56/** Traverses scene graph to improve efficiency. See OptimizationOptions.
57 * For example of usage see examples/osgimpostor or osgviewer.
60class OSGUTIL_EXPORT Optimizer
66 virtual ~Optimizer() {}
68 enum OptimizationOptions
70 FLATTEN_STATIC_TRANSFORMS = (1 << 0),
71 REMOVE_REDUNDANT_NODES = (1 << 1),
72 REMOVE_LOADED_PROXY_NODES = (1 << 2),
73 COMBINE_ADJACENT_LODS = (1 << 3),
74 SHARE_DUPLICATE_STATE = (1 << 4),
75 MERGE_GEOMETRY = (1 << 5),
76 CHECK_GEOMETRY = (1 << 6), // deprecated, currently no-op
77 MAKE_FAST_GEOMETRY = (1 << 7),
78 SPATIALIZE_GROUPS = (1 << 8),
79 COPY_SHARED_NODES = (1 << 9),
80 TRISTRIP_GEOMETRY = (1 << 10),
81 TESSELLATE_GEOMETRY = (1 << 11),
82 OPTIMIZE_TEXTURE_SETTINGS = (1 << 12),
83 MERGE_GEODES = (1 << 13),
84 FLATTEN_BILLBOARDS = (1 << 14),
85 TEXTURE_ATLAS_BUILDER = (1 << 15),
86 STATIC_OBJECT_DETECTION = (1 << 16),
87 FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS = (1 << 17),
88 INDEX_MESH = (1 << 18),
89 VERTEX_POSTTRANSFORM = (1 << 19),
90 VERTEX_PRETRANSFORM = (1 << 20),
91 BUFFER_OBJECT_SETTINGS = (1 << 21),
92 DEFAULT_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS |
93 REMOVE_REDUNDANT_NODES |
94 REMOVE_LOADED_PROXY_NODES |
95 COMBINE_ADJACENT_LODS |
96 SHARE_DUPLICATE_STATE |
100 OPTIMIZE_TEXTURE_SETTINGS |
101 STATIC_OBJECT_DETECTION,
102 ALL_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS |
103 REMOVE_REDUNDANT_NODES |
104 REMOVE_LOADED_PROXY_NODES |
105 COMBINE_ADJACENT_LODS |
106 SHARE_DUPLICATE_STATE |
114 OPTIMIZE_TEXTURE_SETTINGS |
115 TEXTURE_ATLAS_BUILDER |
116 STATIC_OBJECT_DETECTION |
117 BUFFER_OBJECT_SETTINGS
120 /** Reset internal data to initial state - the getPermissibleOptionsMap is cleared.*/
123 /** Traverse the node and its subgraph with a series of optimization
124 * visitors, specified by the OptimizationOptions.*/
125 void optimize(osg::Node* node);
127 template<class T> void optimize(const osg::ref_ptr<T>& node) { optimize(node.get()); }
129 /** Traverse the node and its subgraph with a series of optimization
130 * visitors, specified by the OptimizationOptions.*/
131 virtual void optimize(osg::Node* node, unsigned int options);
133 template<class T> void optimize(const osg::ref_ptr<T>& node, unsigned int options) { optimize(node.get(), options); }
136 /** Callback for customizing what operations are permitted on objects in the scene graph.*/
137 struct IsOperationPermissibleForObjectCallback : public osg::Referenced
139 virtual bool isOperationPermissibleForObjectImplementation(const Optimizer* optimizer, const osg::StateSet* stateset,unsigned int option) const
141 return optimizer->isOperationPermissibleForObjectImplementation(stateset,option);
144 virtual bool isOperationPermissibleForObjectImplementation(const Optimizer* optimizer, const osg::StateAttribute* attribute,unsigned int option) const
146 return optimizer->isOperationPermissibleForObjectImplementation(attribute,option);
149 virtual bool isOperationPermissibleForObjectImplementation(const Optimizer* optimizer, const osg::Drawable* drawable,unsigned int option) const
151 return optimizer->isOperationPermissibleForObjectImplementation(drawable,option);
154 virtual bool isOperationPermissibleForObjectImplementation(const Optimizer* optimizer, const osg::Node* node,unsigned int option) const
156 return optimizer->isOperationPermissibleForObjectImplementation(node,option);
161 /** Set the callback for customizing what operations are permitted on objects in the scene graph.*/
162 void setIsOperationPermissibleForObjectCallback(IsOperationPermissibleForObjectCallback* callback) { _isOperationPermissibleForObjectCallback=callback; }
164 /** Get the callback for customizing what operations are permitted on objects in the scene graph.*/
165 IsOperationPermissibleForObjectCallback* getIsOperationPermissibleForObjectCallback() { return _isOperationPermissibleForObjectCallback.get(); }
167 /** Get the callback for customizing what operations are permitted on objects in the scene graph.*/
168 const IsOperationPermissibleForObjectCallback* getIsOperationPermissibleForObjectCallback() const { return _isOperationPermissibleForObjectCallback.get(); }
171 inline void setPermissibleOptimizationsForObject(const osg::Object* object, unsigned int options)
173 _permissibleOptimizationsMap[object] = options;
176 inline unsigned int getPermissibleOptimizationsForObject(const osg::Object* object) const
178 PermissibleOptimizationsMap::const_iterator itr = _permissibleOptimizationsMap.find(object);
179 if (itr!=_permissibleOptimizationsMap.end()) return itr->second;
180 else return 0xffffffff;
184 inline bool isOperationPermissibleForObject(const osg::StateSet* object, unsigned int option) const
186 if (_isOperationPermissibleForObjectCallback.valid())
187 return _isOperationPermissibleForObjectCallback->isOperationPermissibleForObjectImplementation(this,object,option);
189 return isOperationPermissibleForObjectImplementation(object,option);
192 inline bool isOperationPermissibleForObject(const osg::StateAttribute* object, unsigned int option) const
194 if (_isOperationPermissibleForObjectCallback.valid())
195 return _isOperationPermissibleForObjectCallback->isOperationPermissibleForObjectImplementation(this,object,option);
197 return isOperationPermissibleForObjectImplementation(object,option);
200 inline bool isOperationPermissibleForObject(const osg::Drawable* object, unsigned int option) const
202 if (_isOperationPermissibleForObjectCallback.valid())
203 return _isOperationPermissibleForObjectCallback->isOperationPermissibleForObjectImplementation(this,object,option);
205 return isOperationPermissibleForObjectImplementation(object,option);
208 inline bool isOperationPermissibleForObject(const osg::Node* object, unsigned int option) const
210 if (_isOperationPermissibleForObjectCallback.valid())
211 return _isOperationPermissibleForObjectCallback->isOperationPermissibleForObjectImplementation(this,object,option);
213 return isOperationPermissibleForObjectImplementation(object,option);
216 bool isOperationPermissibleForObjectImplementation(const osg::StateSet* stateset, unsigned int option) const
218 return (option & getPermissibleOptimizationsForObject(stateset))!=0;
221 bool isOperationPermissibleForObjectImplementation(const osg::StateAttribute* attribute, unsigned int option) const
223 return (option & getPermissibleOptimizationsForObject(attribute))!=0;
226 bool isOperationPermissibleForObjectImplementation(const osg::Drawable* drawable, unsigned int option) const
228 if (option & (REMOVE_REDUNDANT_NODES|MERGE_GEOMETRY))
230 if (drawable->getUserData()) return false;
231 if (drawable->getUpdateCallback()) return false;
232 if (drawable->getEventCallback()) return false;
233 if (drawable->getCullCallback()) return false;
235 return (option & getPermissibleOptimizationsForObject(drawable))!=0;
238 bool isOperationPermissibleForObjectImplementation(const osg::Node* node, unsigned int option) const
240 if (option & (REMOVE_REDUNDANT_NODES|COMBINE_ADJACENT_LODS|FLATTEN_STATIC_TRANSFORMS))
242 if (node->getUserData()) return false;
243 if (node->getUpdateCallback()) return false;
244 if (node->getEventCallback()) return false;
245 if (node->getCullCallback()) return false;
246 if (node->getNumDescriptions()>0) return false;
247 if (node->getStateSet()) return false;
248 if (node->getNodeMask()!=0xffffffff) return false;
249 // if (!node->getName().empty()) return false;
252 return (option & getPermissibleOptimizationsForObject(node))!=0;
257 osg::ref_ptr<IsOperationPermissibleForObjectCallback> _isOperationPermissibleForObjectCallback;
259 typedef std::map<const osg::Object*,unsigned int> PermissibleOptimizationsMap;
260 PermissibleOptimizationsMap _permissibleOptimizationsMap;
264 /** Flatten Static Transform nodes by applying their transform to the
265 * geometry on the leaves of the scene graph, then removing the
266 * now redundant transforms. Static transformed subgraphs that have multiple
267 * parental paths above them are not flattened, if you require this then
268 * the subgraphs have to be duplicated - for this use the
269 * FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor. */
270 class OSGUTIL_EXPORT FlattenStaticTransformsVisitor : public BaseOptimizerVisitor
274 FlattenStaticTransformsVisitor(Optimizer* optimizer=0):
275 BaseOptimizerVisitor(optimizer, FLATTEN_STATIC_TRANSFORMS) {}
277 virtual void apply(osg::Node& geode);
278 virtual void apply(osg::Drawable& drawable);
279 virtual void apply(osg::Billboard& geode);
280 virtual void apply(osg::ProxyNode& node);
281 virtual void apply(osg::PagedLOD& node);
282 virtual void apply(osg::Transform& transform);
284 bool removeTransforms(osg::Node* nodeWeCannotRemove);
288 typedef std::vector<osg::Transform*> TransformStack;
289 typedef std::set<osg::Drawable*> DrawableSet;
290 typedef std::set<osg::Billboard*> BillboardSet;
291 typedef std::set<osg::Node* > NodeSet;
292 typedef std::set<osg::Transform*> TransformSet;
294 TransformStack _transformStack;
295 NodeSet _excludedNodeSet;
296 DrawableSet _drawableSet;
297 BillboardSet _billboardSet;
298 TransformSet _transformSet;
301 /** FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor is similar
302 * to FlattenStaticTransformsVisitor in that it is designed to remove static transforms
303 * from the scene graph, pushing down the transforms to the geometry leaves of the scene graph,
304 * but with the difference that any subgraphs that are shared between different transforms
305 * are duplicated and flattened individually. This results in more static transforms
306 * being removed, but also means that more data is generated, and as a result may
307 * not always be the most appropriate flatten visitor to use.*/
308 class OSGUTIL_EXPORT FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor : public BaseOptimizerVisitor
312 FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor(Optimizer* optimizer=0):
313 BaseOptimizerVisitor(optimizer, FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS) {}
315 virtual void reset();
317 virtual void apply(osg::Group& group);
318 virtual void apply(osg::Transform& transform);
319 virtual void apply(osg::LOD& lod);
320 virtual void apply(osg::Geode& geode);
321 virtual void apply(osg::Billboard& billboard);
325 void transformGeode(osg::Geode& geode);
326 void transformDrawable(osg::Drawable& drawable);
327 void transformBillboard(osg::Billboard& billboard);
329 std::vector<osg::Matrix> _matrixStack;
333 /** Combine Static Transform nodes that sit above one another.*/
334 class OSGUTIL_EXPORT CombineStaticTransformsVisitor : public BaseOptimizerVisitor
338 CombineStaticTransformsVisitor(Optimizer* optimizer=0):
339 BaseOptimizerVisitor(optimizer, FLATTEN_STATIC_TRANSFORMS) {}
341 virtual void apply(osg::MatrixTransform& transform);
343 bool removeTransforms(osg::Node* nodeWeCannotRemove);
347 typedef std::set<osg::MatrixTransform*> TransformSet;
348 TransformSet _transformSet;
351 /** Remove rendundant nodes, such as groups with one single child.*/
352 class OSGUTIL_EXPORT RemoveEmptyNodesVisitor : public BaseOptimizerVisitor
357 typedef std::set<osg::Node*> NodeList;
358 NodeList _redundantNodeList;
360 RemoveEmptyNodesVisitor(Optimizer* optimizer=0):
361 BaseOptimizerVisitor(optimizer, REMOVE_REDUNDANT_NODES) {}
363 virtual void apply(osg::Group& group);
365 void removeEmptyNodes();
369 /** Remove redundant nodes, such as groups with one single child.*/
370 class OSGUTIL_EXPORT RemoveRedundantNodesVisitor : public BaseOptimizerVisitor
374 typedef std::set<osg::Node*> NodeList;
375 NodeList _redundantNodeList;
377 RemoveRedundantNodesVisitor(Optimizer* optimizer=0):
378 BaseOptimizerVisitor(optimizer, REMOVE_REDUNDANT_NODES) {}
380 virtual void apply(osg::Group& group);
381 virtual void apply(osg::Transform& transform);
383 bool isOperationPermissible(osg::Node& node);
385 void removeRedundantNodes();
389 /** Remove loaded proxy nodes.*/
390 class OSGUTIL_EXPORT RemoveLoadedProxyNodesVisitor : public BaseOptimizerVisitor
394 typedef std::set<osg::Node*> NodeList;
395 NodeList _redundantNodeList;
397 RemoveLoadedProxyNodesVisitor(Optimizer* optimizer=0):
398 BaseOptimizerVisitor(optimizer, REMOVE_LOADED_PROXY_NODES) {}
400 virtual void apply(osg::ProxyNode& group);
402 void removeRedundantNodes();
406 /** Tessellate all Geometries, to remove POLYGONS.*/
407 class OSGUTIL_EXPORT TessellateVisitor : public BaseOptimizerVisitor
411 typedef std::set<osg::Group*> GroupList;
412 GroupList _groupList;
414 TessellateVisitor(Optimizer* optimizer=0):
415 BaseOptimizerVisitor(optimizer, TESSELLATE_GEOMETRY) {}
417 virtual void apply(osg::Geometry& geom);
421 /** Optimize the LOD groups, by combining adjacent LOD's which have
422 * complementary ranges.*/
423 class OSGUTIL_EXPORT CombineLODsVisitor : public BaseOptimizerVisitor
427 typedef std::set<osg::Group*> GroupList;
428 GroupList _groupList;
430 CombineLODsVisitor(Optimizer* optimizer=0):
431 BaseOptimizerVisitor(optimizer, COMBINE_ADJACENT_LODS) {}
433 virtual void apply(osg::LOD& lod);
439 /** Optimize State in the scene graph by removing duplicate state,
440 * replacing it with shared instances, both for StateAttributes,
441 * and whole StateSets.*/
442 class OSGUTIL_EXPORT StateVisitor : public BaseOptimizerVisitor
446 /// default to traversing all children.
447 StateVisitor(bool combineDynamicState,
448 bool combineStaticState,
449 bool combineUnspecifiedState,
450 Optimizer* optimizer=0):
451 BaseOptimizerVisitor(optimizer, SHARE_DUPLICATE_STATE)
453 _optimize[osg::Object::DYNAMIC] = combineDynamicState;
454 _optimize[osg::Object::STATIC] = combineStaticState;
455 _optimize[osg::Object::UNSPECIFIED] = combineUnspecifiedState;
458 /** empty visitor, make it ready for next traversal.*/
459 virtual void reset();
461 virtual void apply(osg::Node& node);
467 void addStateSet(osg::StateSet* stateset, osg::Node* node);
469 inline bool optimize(osg::Object::DataVariance variance)
471 return _optimize[variance];
474 typedef std::set<osg::Node*> NodeSet;
475 typedef std::map<osg::StateSet*, NodeSet> StateSetMap;
477 // note, one element for DYNAMIC, STATIC and UNSPECIFIED
480 StateSetMap _statesets;
486 class OSGUTIL_EXPORT MergeGeodesVisitor : public BaseOptimizerVisitor
490 /// default to traversing all children.
491 MergeGeodesVisitor(Optimizer* optimizer=0):
492 BaseOptimizerVisitor(optimizer, MERGE_GEODES) {}
494 virtual void apply(osg::Group& group);
496 bool mergeGeodes(osg::Group& group);
500 bool mergeGeode(osg::Geode& lhs, osg::Geode& rhs);
504 class OSGUTIL_EXPORT MakeFastGeometryVisitor : public BaseOptimizerVisitor
508 /// default to traversing all children.
509 MakeFastGeometryVisitor(Optimizer* optimizer=0):
510 BaseOptimizerVisitor(optimizer, MAKE_FAST_GEOMETRY) {}
512 virtual void apply(osg::Geometry& geom);
516 class OSGUTIL_EXPORT MergeGeometryVisitor : public BaseOptimizerVisitor
520 /// default to traversing all children.
521 MergeGeometryVisitor(Optimizer* optimizer=0) :
522 BaseOptimizerVisitor(optimizer, MERGE_GEOMETRY),
523 _targetMaximumNumberOfVertices(10000) {}
525 void setTargetMaximumNumberOfVertices(unsigned int num)
527 _targetMaximumNumberOfVertices = num;
530 unsigned int getTargetMaximumNumberOfVertices() const
532 return _targetMaximumNumberOfVertices;
535 virtual void apply(osg::Group& group) { mergeGroup(group); traverse(group); }
536 virtual void apply(osg::Billboard&) { /* don't do anything*/ }
538 bool mergeGroup(osg::Group& group);
540 static bool geometryContainsSharedArrays(osg::Geometry& geom);
542 static bool mergeGeometry(osg::Geometry& lhs,osg::Geometry& rhs);
544 static bool mergePrimitive(osg::DrawArrays& lhs,osg::DrawArrays& rhs);
545 static bool mergePrimitive(osg::DrawArrayLengths& lhs,osg::DrawArrayLengths& rhs);
546 static bool mergePrimitive(osg::DrawElementsUByte& lhs,osg::DrawElementsUByte& rhs);
547 static bool mergePrimitive(osg::DrawElementsUShort& lhs,osg::DrawElementsUShort& rhs);
548 static bool mergePrimitive(osg::DrawElementsUInt& lhs,osg::DrawElementsUInt& rhs);
552 unsigned int _targetMaximumNumberOfVertices;
556 /** Spatialize scene into a balanced quad/oct tree.*/
557 class OSGUTIL_EXPORT SpatializeGroupsVisitor : public BaseOptimizerVisitor
561 SpatializeGroupsVisitor(Optimizer* optimizer=0):
562 BaseOptimizerVisitor(optimizer, SPATIALIZE_GROUPS) {}
564 virtual void apply(osg::Group& group);
565 virtual void apply(osg::Geode& geode);
567 bool divide(unsigned int maxNumTreesPerCell=8);
569 bool divide(osg::Group* group, unsigned int maxNumTreesPerCell);
570 bool divide(osg::Geode* geode, unsigned int maxNumTreesPerCell);
572 typedef std::set<osg::Group*> GroupsToDivideList;
573 GroupsToDivideList _groupsToDivideList;
575 typedef std::set<osg::Geode*> GeodesToDivideList;
576 GeodesToDivideList _geodesToDivideList;
579 /** Copy any shared subgraphs, enabling flattening of static transforms.*/
580 class OSGUTIL_EXPORT CopySharedSubgraphsVisitor : public BaseOptimizerVisitor
584 CopySharedSubgraphsVisitor(Optimizer* optimizer=0):
585 BaseOptimizerVisitor(optimizer, COPY_SHARED_NODES) {}
587 virtual void apply(osg::Node& node);
589 void copySharedNodes();
591 typedef std::set<osg::Node*> SharedNodeList;
592 SharedNodeList _sharedNodeList;
597 /** For all textures apply settings.*/
598 class OSGUTIL_EXPORT TextureVisitor : public BaseOptimizerVisitor
602 TextureVisitor(bool changeAutoUnRef, bool valueAutoUnRef,
603 bool changeClientImageStorage, bool valueClientImageStorage,
604 bool changeAnisotropy, float valueAnisotropy,
605 Optimizer* optimizer=0):
606 BaseOptimizerVisitor(optimizer, OPTIMIZE_TEXTURE_SETTINGS),
607 _changeAutoUnRef(changeAutoUnRef), _valueAutoUnRef(valueAutoUnRef),
608 _changeClientImageStorage(changeClientImageStorage), _valueClientImageStorage(valueClientImageStorage),
609 _changeAnisotropy(changeAnisotropy), _valueAnisotropy(valueAnisotropy) {}
611 virtual void apply(osg::Node& node);
613 void apply(osg::StateSet& stateset);
614 void apply(osg::Texture& texture);
616 bool _changeAutoUnRef, _valueAutoUnRef;
617 bool _changeClientImageStorage, _valueClientImageStorage;
618 bool _changeAnisotropy;
619 float _valueAnisotropy;
623 /** Flatten MatrixTransform/Billboard pairs.*/
624 class OSGUTIL_EXPORT FlattenBillboardVisitor : public BaseOptimizerVisitor
627 FlattenBillboardVisitor(Optimizer* optimizer=0):
628 BaseOptimizerVisitor(optimizer, FLATTEN_BILLBOARDS) {}
630 typedef std::vector<osg::NodePath> NodePathList;
631 typedef std::map<osg::Billboard*, NodePathList > BillboardNodePathMap;
633 virtual void reset();
635 virtual void apply(osg::Billboard& billboard);
639 BillboardNodePathMap _billboards;
643 /** Texture Atlas Builder creates a set of textures/images which each contain multiple images.
644 * Texture Atlas' are used to make it possible to use much wider batching of data. */
645 class OSGUTIL_EXPORT TextureAtlasBuilder
648 TextureAtlasBuilder();
652 void setMaximumAtlasSize(int width, int height);
654 int getMaximumAtlasWidth() const { return _maximumAtlasWidth; }
655 int getMaximumAtlasHeight() const { return _maximumAtlasHeight; }
657 void setMargin(int margin);
658 int getMargin() const { return _margin; }
660 void addSource(const osg::Image* image);
661 void addSource(const osg::Texture2D* texture);
663 unsigned int getNumSources() const { return _sourceList.size(); }
664 const osg::Image* getSourceImage(unsigned int i) { return _sourceList[i]->_image.get(); }
665 const osg::Texture2D* getSourceTexture(unsigned int i) { return _sourceList[i]->_texture.get(); }
668 osg::Image* getImageAtlas(unsigned int i);
669 osg::Texture2D* getTextureAtlas(unsigned int i);
670 osg::Matrix getTextureMatrix(unsigned int i);
672 osg::Image* getImageAtlas(const osg::Image* image);
673 osg::Texture2D* getTextureAtlas(const osg::Image* image);
674 osg::Matrix getTextureMatrix(const osg::Image* image);
676 osg::Image* getImageAtlas(const osg::Texture2D* textue);
677 osg::Texture2D* getTextureAtlas(const osg::Texture2D* texture);
678 osg::Matrix getTextureMatrix(const osg::Texture2D* texture);
682 int _maximumAtlasWidth;
683 int _maximumAtlasHeight;
690 class Source : public osg::Referenced
694 _x(0),_y(0),_atlas(0) {}
696 Source(const osg::Image* image):
697 _x(0),_y(0),_atlas(0),_image(image) {}
699 Source(const osg::Texture2D* texture):
700 _x(0),_y(0),_atlas(0),_texture(texture) { if (texture) _image = texture->getImage(); }
706 osg::ref_ptr<const osg::Image> _image;
707 osg::ref_ptr<const osg::Texture2D> _texture;
709 bool suitableForAtlas(int maximumAtlasWidth, int maximumAtlasHeight, int margin);
710 osg::Matrix computeTextureMatrix() const;
718 typedef std::vector< osg::ref_ptr<Source> > SourceList;
720 class Atlas : public osg::Referenced
723 Atlas(int width, int height, int margin):
724 _maximumAtlasWidth(width),
725 _maximumAtlasHeight(height),
731 _indexFirstOfRow(0){}
733 int _maximumAtlasWidth;
734 int _maximumAtlasHeight;
737 osg::ref_ptr<osg::Texture2D> _texture;
738 osg::ref_ptr<osg::Image> _image;
740 SourceList _sourceList;
746 unsigned int _indexFirstOfRow; ///< Contain the index of the first element of the last row.
749 DOES_NOT_FIT_IN_ANY_ROW,
753 FitsIn doesSourceFit(Source* source);
754 bool addSource(Source* source);
755 void clampToNearestPowerOfTwoSize();
762 typedef std::vector< osg::ref_ptr<Atlas> > AtlasList;
764 Source* getSource(const osg::Image* image);
765 Source* getSource(const osg::Texture2D* texture);
767 SourceList _sourceList;
768 AtlasList _atlasList;
772 bool operator()(osg::ref_ptr<Source> src1, osg::ref_ptr<Source> src2) const
774 return src1->_image->t() > src2->_image->t();
777 void completeRow(unsigned int indexAtlas);
781 /** Optimize texture usage in the scene graph by combining textures into texture atlas
782 * Use of texture atlas cuts down on the number of separate states in the scene, reducing
783 * state changes and improving the chances of using larger batches of geometry.*/
784 class OSGUTIL_EXPORT TextureAtlasVisitor : public BaseOptimizerVisitor
788 /// default to traversing all children.
789 TextureAtlasVisitor(Optimizer* optimizer=0):
790 BaseOptimizerVisitor(optimizer, TEXTURE_ATLAS_BUILDER) {}
793 TextureAtlasBuilder& getTextureAtlasBuilder() { return _builder; }
795 /** empty visitor, make it ready for next traversal.*/
796 virtual void reset();
798 virtual void apply(osg::Node& node);
799 virtual void apply(osg::Drawable& node);
805 bool pushStateSet(osg::StateSet* stateset);
808 typedef std::set<osg::Drawable*> Drawables;
809 typedef std::map<osg::StateSet*, Drawables> StateSetMap;
810 typedef std::set<osg::Texture2D*> Textures;
811 typedef std::vector<osg::StateSet*> StateSetStack;
813 TextureAtlasBuilder _builder;
815 StateSetMap _statesetMap;
816 StateSetStack _statesetStack;
821 /** Optimize the setting of StateSet and Geometry objects in scene so that they have a STATIC DataVariance
822 * when they don't have any callbacks associated with them. */
823 class OSGUTIL_EXPORT StaticObjectDetectionVisitor : public BaseOptimizerVisitor
827 /// default to traversing all children.
828 StaticObjectDetectionVisitor(Optimizer* optimizer=0):
829 BaseOptimizerVisitor(optimizer, STATIC_OBJECT_DETECTION) {}
831 virtual void apply(osg::Node& node);
832 virtual void apply(osg::Drawable& drawable);
836 void applyStateSet(osg::StateSet& stateset);
840 /** For all geometry apply settings.*/
841 class OSGUTIL_EXPORT BufferObjectVisitor : public BaseOptimizerVisitor
845 BufferObjectVisitor(bool changeVBO, bool valueVBO,
846 bool changeVertexArrayObject, bool valueVertexArrayObject,
847 bool changeDisplayList, bool valueDisplayList,
848 Optimizer* optimizer=0):
849 BaseOptimizerVisitor(optimizer, BUFFER_OBJECT_SETTINGS),
850 _changeVertexBufferObject(changeVBO), _valueVertexBufferObject(valueVBO),
851 _changeVertexArrayObject(changeVertexArrayObject), _valueVertexArrayObject(valueVertexArrayObject),
852 _changeDisplayList(changeDisplayList), _valueDisplayList(valueDisplayList) {}
854 virtual void apply(osg::Geometry& geometry);
856 bool _changeVertexBufferObject, _valueVertexBufferObject;
857 bool _changeVertexArrayObject, _valueVertexArrayObject;
858 bool _changeDisplayList, _valueDisplayList;
863inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::StateSet* object) const
865 return _optimizer ? _optimizer->isOperationPermissibleForObject(object,_operationType) : true;
868inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::StateAttribute* object) const
870 return _optimizer ? _optimizer->isOperationPermissibleForObject(object,_operationType) : true;
873inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::Drawable* object) const
875 return _optimizer ? _optimizer->isOperationPermissibleForObject(object,_operationType) : true;
878inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::Node* object) const
880 return _optimizer ? _optimizer->isOperationPermissibleForObject(object,_operationType) : true;