root/OpenSceneGraph/trunk/include/osgUtil/Optimizer @ 9245

Revision 9245, 33.6 kB (checked in by robert, 6 years ago)

From Joakim Simmonsson, fix for handling of billboards in FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
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.
7 *
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.
12*/
13
14#ifndef OSGUTIL_OPTIMIZER
15#define OSGUTIL_OPTIMIZER
16
17#include <osg/NodeVisitor>
18#include <osg/Matrix>
19#include <osg/Geometry>
20#include <osg/Transform>
21#include <osg/Texture2D>
22
23#include <osgUtil/Export>
24
25#include <set>
26
27namespace osgUtil {
28
29// forward declare
30class Optimizer;
31
32/** Helper base class for implementing Optimizer techniques.*/
33class OSGUTIL_EXPORT BaseOptimizerVisitor : public osg::NodeVisitor
34{
35    public:
36
37        BaseOptimizerVisitor(Optimizer* optimizer, unsigned int operation):
38            osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
39            _optimizer(optimizer),
40            _operationType(operation)
41        {
42            setNodeMaskOverride(0xffffffff);
43        }
44
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;
49
50    protected:
51
52        Optimizer*      _optimizer;
53        unsigned int _operationType;
54};
55
56/** Traverses scene graph to improve efficiency. See OptimizationOptions.
57  * For example of usage see examples/osgimpostor or osgviewer.
58  */
59 
60class OSGUTIL_EXPORT Optimizer
61{
62
63    public:
64
65        Optimizer() {}
66        virtual ~Optimizer() {}
67
68        enum OptimizationOptions
69        {
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),
77            SPATIALIZE_GROUPS =         (1 << 7),
78            COPY_SHARED_NODES =         (1 << 8),
79            TRISTRIP_GEOMETRY =         (1 << 9),
80            TESSELLATE_GEOMETRY =       (1 << 10),
81            OPTIMIZE_TEXTURE_SETTINGS = (1 << 11),
82            MERGE_GEODES =              (1 << 12),
83            FLATTEN_BILLBOARDS =        (1 << 13),
84            TEXTURE_ATLAS_BUILDER =     (1 << 14),
85            STATIC_OBJECT_DETECTION =   (1 << 15),
86            FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS = (1 << 16),
87            DEFAULT_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS |
88                                REMOVE_REDUNDANT_NODES |
89                                REMOVE_LOADED_PROXY_NODES |
90                                COMBINE_ADJACENT_LODS |
91                                SHARE_DUPLICATE_STATE |
92                                MERGE_GEOMETRY |
93                                CHECK_GEOMETRY |
94                                OPTIMIZE_TEXTURE_SETTINGS |
95                                STATIC_OBJECT_DETECTION,
96            ALL_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS |
97                                REMOVE_REDUNDANT_NODES |
98                                REMOVE_LOADED_PROXY_NODES |
99                                COMBINE_ADJACENT_LODS |
100                                SHARE_DUPLICATE_STATE |
101                                MERGE_GEODES |
102                                MERGE_GEOMETRY |
103                                CHECK_GEOMETRY |
104                                SPATIALIZE_GROUPS |
105                                COPY_SHARED_NODES |
106                                TRISTRIP_GEOMETRY |
107                                OPTIMIZE_TEXTURE_SETTINGS |
108                                TEXTURE_ATLAS_BUILDER |
109                                STATIC_OBJECT_DETECTION
110        };
111
112        /** Reset internal data to initial state - the getPermissibleOptionsMap is cleared.*/
113        void reset();
114       
115        /** Traverse the node and its subgraph with a series of optimization
116          * visitors, specified by the OptimizationOptions.*/
117        void optimize(osg::Node* node);
118
119        /** Traverse the node and its subgraph with a series of optimization
120          * visitors, specified by the OptimizationOptions.*/
121        virtual void optimize(osg::Node* node, unsigned int options);
122
123
124        /** Callback for customizing what operations are permitted on objects in the scene graph.*/       
125        struct IsOperationPermissibleForObjectCallback : public osg::Referenced
126        {
127            virtual bool isOperationPermissibleForObjectImplementation(const Optimizer* optimizer, const osg::StateSet* stateset,unsigned int option) const
128            {
129                return optimizer->isOperationPermissibleForObjectImplementation(stateset,option);
130            }
131           
132            virtual bool isOperationPermissibleForObjectImplementation(const Optimizer* optimizer, const osg::StateAttribute* attribute,unsigned int option) const
133            {
134                return optimizer->isOperationPermissibleForObjectImplementation(attribute,option);
135            }
136           
137            virtual bool isOperationPermissibleForObjectImplementation(const Optimizer* optimizer, const osg::Drawable* drawable,unsigned int option) const
138            {
139                return optimizer->isOperationPermissibleForObjectImplementation(drawable,option);
140            }
141           
142            virtual bool isOperationPermissibleForObjectImplementation(const Optimizer* optimizer, const osg::Node* node,unsigned int option) const
143            {
144                return optimizer->isOperationPermissibleForObjectImplementation(node,option);
145            }
146           
147        };
148       
149        /** Set the callback for customizing what operations are permitted on objects in the scene graph.*/       
150        void setIsOperationPermissibleForObjectCallback(IsOperationPermissibleForObjectCallback* callback) { _isOperationPermissibleForObjectCallback=callback; }
151
152        /** Get the callback for customizing what operations are permitted on objects in the scene graph.*/       
153        IsOperationPermissibleForObjectCallback* getIsOperationPermissibleForObjectCallback() { return _isOperationPermissibleForObjectCallback.get(); }
154
155        /** Get the callback for customizing what operations are permitted on objects in the scene graph.*/       
156        const IsOperationPermissibleForObjectCallback* getIsOperationPermissibleForObjectCallback() const { return _isOperationPermissibleForObjectCallback.get(); }
157
158
159        inline void setPermissibleOptimizationsForObject(const osg::Object* object, unsigned int options)
160        {
161            _permissibleOptimizationsMap[object] = options;
162        }
163       
164        inline unsigned int getPermissibleOptimizationsForObject(const osg::Object* object) const
165        {
166            PermissibleOptimizationsMap::const_iterator itr = _permissibleOptimizationsMap.find(object);
167            if (itr!=_permissibleOptimizationsMap.end()) return itr->second;
168            else return 0xffffffff;
169        }
170
171
172        inline bool isOperationPermissibleForObject(const osg::StateSet* object, unsigned int option) const
173        {
174            if (_isOperationPermissibleForObjectCallback.valid())
175                return _isOperationPermissibleForObjectCallback->isOperationPermissibleForObjectImplementation(this,object,option);
176            else
177                return isOperationPermissibleForObjectImplementation(object,option);
178        }
179
180        inline bool isOperationPermissibleForObject(const osg::StateAttribute* object, unsigned int option) const
181        {
182            if (_isOperationPermissibleForObjectCallback.valid())
183                return _isOperationPermissibleForObjectCallback->isOperationPermissibleForObjectImplementation(this,object,option);
184            else
185                return isOperationPermissibleForObjectImplementation(object,option);
186        }
187
188        inline bool isOperationPermissibleForObject(const osg::Drawable* object, unsigned int option) const
189        {
190            if (_isOperationPermissibleForObjectCallback.valid())
191                return _isOperationPermissibleForObjectCallback->isOperationPermissibleForObjectImplementation(this,object,option);
192            else
193                return isOperationPermissibleForObjectImplementation(object,option);
194        }
195
196        inline bool isOperationPermissibleForObject(const osg::Node* object, unsigned int option) const
197        {
198            if (_isOperationPermissibleForObjectCallback.valid())
199                return _isOperationPermissibleForObjectCallback->isOperationPermissibleForObjectImplementation(this,object,option);
200            else
201                return isOperationPermissibleForObjectImplementation(object,option);
202        }
203
204        bool isOperationPermissibleForObjectImplementation(const osg::StateSet* stateset, unsigned int option) const
205        {
206            return (option & getPermissibleOptimizationsForObject(stateset))!=0;
207        }
208       
209        bool isOperationPermissibleForObjectImplementation(const osg::StateAttribute* attribute, unsigned int option) const
210        {
211            return (option & getPermissibleOptimizationsForObject(attribute))!=0;
212        }
213
214        bool isOperationPermissibleForObjectImplementation(const osg::Drawable* drawable, unsigned int option) const
215        {
216            if (option & (REMOVE_REDUNDANT_NODES|MERGE_GEOMETRY))
217            {
218                if (drawable->getUserData()) return false;
219                if (drawable->getUpdateCallback()) return false;
220                if (drawable->getEventCallback()) return false;
221                if (drawable->getCullCallback()) return false;
222            }
223            return (option & getPermissibleOptimizationsForObject(drawable))!=0;
224        }
225
226        bool isOperationPermissibleForObjectImplementation(const osg::Node* node, unsigned int option) const
227        {
228            if (option & (REMOVE_REDUNDANT_NODES|COMBINE_ADJACENT_LODS|FLATTEN_STATIC_TRANSFORMS))
229            {
230                if (node->getUserData()) return false;
231                if (node->getUpdateCallback()) return false;
232                if (node->getEventCallback()) return false;
233                if (node->getCullCallback()) return false;
234                if (node->getNumDescriptions()>0) return false;
235                if (node->getStateSet()) return false;
236                if (node->getNodeMask()!=0xffffffff) return false;
237                // if (!node->getName().empty()) return false;
238            }
239
240            return (option & getPermissibleOptimizationsForObject(node))!=0;
241        }
242       
243    protected:
244
245        osg::ref_ptr<IsOperationPermissibleForObjectCallback> _isOperationPermissibleForObjectCallback;
246
247        typedef std::map<const osg::Object*,unsigned int> PermissibleOptimizationsMap;
248        PermissibleOptimizationsMap _permissibleOptimizationsMap;   
249   
250    public:
251
252        /** Flatten Static Transform nodes by applying their transform to the
253          * geometry on the leaves of the scene graph, then removing the
254          * now redundant transforms.  Static transformed Subgraphs that have multiple
255          * parental paths above them are not flattened, if you require this then
256          * the subgraphs have to be duplicated - for this use the
257          * FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor. */
258        class OSGUTIL_EXPORT FlattenStaticTransformsVisitor : public BaseOptimizerVisitor
259        {
260            public:
261
262                FlattenStaticTransformsVisitor(Optimizer* optimizer=0):
263                    BaseOptimizerVisitor(optimizer, FLATTEN_STATIC_TRANSFORMS) {}
264
265                virtual void apply(osg::Node& geode);
266                virtual void apply(osg::Geode& geode);
267                virtual void apply(osg::Billboard& geode);
268                virtual void apply(osg::ProxyNode& node);
269                virtual void apply(osg::PagedLOD& node);
270                virtual void apply(osg::Transform& transform);
271
272                bool removeTransforms(osg::Node* nodeWeCannotRemove);
273
274            protected:
275
276                typedef std::vector<osg::Transform*>                TransformStack;
277                typedef std::set<osg::Drawable*>                    DrawableSet;
278                typedef std::set<osg::Billboard*>                   BillboardSet;
279                typedef std::set<osg::Node* >                       NodeSet;
280                typedef std::set<osg::Transform*>                   TransformSet;
281               
282                TransformStack  _transformStack;
283                NodeSet         _excludedNodeSet;
284                DrawableSet     _drawableSet;
285                BillboardSet    _billboardSet;
286                TransformSet    _transformSet;
287        };
288
289        /** FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor is similar to
290          * to FlattenStaticTransformsVisitor in that is desgined to remove static transforms
291          * from the scene graph, pushing down the transforms to the geometry leaves of the scene graph,
292          * but with the difference that any subgraphs that are shared between different transforms
293          * of duplicated and flatten individually.  This results in more static transforms
294          * being removed, but also means that more data is generated, and as a result may
295          * not always be the most appropriate flatten visitor to use.*/ 
296        class OSGUTIL_EXPORT FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor : public BaseOptimizerVisitor
297        {
298            public:
299
300                FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor(Optimizer* optimizer=0):
301                    BaseOptimizerVisitor(optimizer, FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS) {}
302
303                virtual void reset();
304
305                virtual void apply(osg::Group& group);
306                virtual void apply(osg::Transform& transform);
307                virtual void apply(osg::LOD& lod);
308                virtual void apply(osg::Geode& geode);
309                virtual void apply(osg::Billboard& billboard);
310
311            protected:
312
313                void transformGeode(osg::Geode& geode);
314                void transformDrawable(osg::Drawable& drawable);
315                void transformBillboard(osg::Billboard& billboard);
316
317                std::vector<osg::Matrix> _matrixStack;
318
319        };
320
321        /** Combine Static Transform nodes that sit above one another.*/       
322        class OSGUTIL_EXPORT CombineStaticTransformsVisitor : public BaseOptimizerVisitor
323        {
324            public:
325
326                CombineStaticTransformsVisitor(Optimizer* optimizer=0):
327                    BaseOptimizerVisitor(optimizer, FLATTEN_STATIC_TRANSFORMS) {}
328
329                virtual void apply(osg::MatrixTransform& transform);
330
331                bool removeTransforms(osg::Node* nodeWeCannotRemove);
332
333            protected:
334
335                typedef std::set<osg::MatrixTransform*> TransformSet;
336                TransformSet  _transformSet;
337        };
338
339        /** Remove rendundant nodes, such as groups with one single child.*/
340        class OSGUTIL_EXPORT RemoveEmptyNodesVisitor : public BaseOptimizerVisitor
341        {
342            public:
343
344
345                typedef std::set<osg::Node*> NodeList;
346                NodeList                     _redundantNodeList;
347
348                RemoveEmptyNodesVisitor(Optimizer* optimizer=0):
349                    BaseOptimizerVisitor(optimizer, REMOVE_REDUNDANT_NODES) {}
350
351                virtual void apply(osg::Geode& geode);
352                virtual void apply(osg::Group& group);
353               
354                void removeEmptyNodes();
355
356        };
357
358        /** Remove redundant nodes, such as groups with one single child.*/
359        class OSGUTIL_EXPORT RemoveRedundantNodesVisitor : public BaseOptimizerVisitor
360        {
361            public:
362
363                typedef std::set<osg::Node*> NodeList;
364                NodeList                     _redundantNodeList;
365
366                RemoveRedundantNodesVisitor(Optimizer* optimizer=0):
367                    BaseOptimizerVisitor(optimizer, REMOVE_REDUNDANT_NODES) {}
368               
369                virtual void apply(osg::Group& group);
370                virtual void apply(osg::Transform& transform);
371               
372                bool isOperationPermissible(osg::Node& node);
373               
374                void removeRedundantNodes();
375
376        };
377
378        /** Remove loaded proxy nodes.*/
379        class OSGUTIL_EXPORT RemoveLoadedProxyNodesVisitor : public BaseOptimizerVisitor
380        {
381            public:
382
383                typedef std::set<osg::Node*> NodeList;
384                NodeList                     _redundantNodeList;
385
386                RemoveLoadedProxyNodesVisitor(Optimizer* optimizer=0):
387                    BaseOptimizerVisitor(optimizer, REMOVE_LOADED_PROXY_NODES) {}
388               
389                virtual void apply(osg::ProxyNode& group);
390               
391                void removeRedundantNodes();
392
393        };
394
395        /** Tessellate all geodes, to remove POLYGONS.*/
396        class OSGUTIL_EXPORT TessellateVisitor : public BaseOptimizerVisitor
397        {
398            public:
399
400                typedef std::set<osg::Group*>  GroupList;
401                GroupList                      _groupList;
402
403                TessellateVisitor(Optimizer* optimizer=0):
404                    BaseOptimizerVisitor(optimizer, TESSELLATE_GEOMETRY) {}
405
406                virtual void apply(osg::Geode& geode);
407
408        };
409
410        /** Optimize the LOD groups, by combining adjacent LOD's which have
411          * complementary ranges.*/
412        class OSGUTIL_EXPORT CombineLODsVisitor : public BaseOptimizerVisitor
413        {
414            public:
415
416                typedef std::set<osg::Group*>  GroupList;
417                GroupList                      _groupList;
418
419                CombineLODsVisitor(Optimizer* optimizer=0):
420                    BaseOptimizerVisitor(optimizer, COMBINE_ADJACENT_LODS) {}
421
422                virtual void apply(osg::LOD& lod);
423
424                void combineLODs();
425
426        };
427 
428        /** Optimize State in the scene graph by removing duplicate state,
429          * replacing it with shared instances, both for StateAttributes,
430          * and whole StateSets.*/
431        class OSGUTIL_EXPORT StateVisitor : public BaseOptimizerVisitor
432        {
433            public:
434
435                /// default to traversing all children.
436                StateVisitor(bool combineDynamicState,
437                             bool combineStaticState,
438                             bool combineUnspecifiedState,
439                             Optimizer* optimizer=0):
440                    BaseOptimizerVisitor(optimizer, SHARE_DUPLICATE_STATE)
441                {
442                    _optimize[osg::Object::DYNAMIC] = combineDynamicState;
443                    _optimize[osg::Object::STATIC] = combineStaticState;
444                    _optimize[osg::Object::UNSPECIFIED] = combineUnspecifiedState;
445                }
446
447                /** empty visitor, make it ready for next traversal.*/       
448                virtual void reset();
449
450                virtual void apply(osg::Node& node);
451
452                virtual void apply(osg::Geode& geode);
453
454                void optimize();
455
456            protected:
457
458                void addStateSet(osg::StateSet* stateset,osg::Object* obj);
459               
460                inline bool optimize(osg::Object::DataVariance variance)
461                {
462                    return _optimize[variance];
463                }
464
465                typedef std::set<osg::Object*>              ObjectSet;
466                typedef std::map<osg::StateSet*,ObjectSet>  StateSetMap;
467
468                // note, one element for DYNAMIC, STATIC and UNSPECIFIED
469                bool _optimize[3];
470               
471                StateSetMap _statesets;
472
473        };
474
475        /** Combine geodes
476          */
477        class OSGUTIL_EXPORT MergeGeodesVisitor : public BaseOptimizerVisitor
478        {
479            public:
480
481                /// default to traversing all children.
482                MergeGeodesVisitor(Optimizer* optimizer=0):
483                    BaseOptimizerVisitor(optimizer, MERGE_GEODES) {}
484
485                virtual void apply(osg::Group& group);
486
487                bool mergeGeodes(osg::Group& group);
488
489            protected:
490
491                bool mergeGeode(osg::Geode& lhs, osg::Geode& rhs);
492
493        };
494
495        class OSGUTIL_EXPORT CheckGeometryVisitor : public BaseOptimizerVisitor
496        {
497            public:
498
499                /// default to traversing all children.
500                CheckGeometryVisitor(Optimizer* optimizer=0):
501                    BaseOptimizerVisitor(optimizer, CHECK_GEOMETRY) {}
502
503                virtual void apply(osg::Geode& geode) { checkGeode(geode); }
504
505                void checkGeode(osg::Geode& geode);
506               
507        };
508       
509        class OSGUTIL_EXPORT MergeGeometryVisitor : public BaseOptimizerVisitor
510        {
511            public:
512
513                /// default to traversing all children.
514                MergeGeometryVisitor(Optimizer* optimizer=0) :
515                    BaseOptimizerVisitor(optimizer, MERGE_GEOMETRY),
516                    _targetMaximumNumberOfVertices(10000) {}
517
518                void setTargetMaximumNumberOfVertices(unsigned int num)
519                {
520                    _targetMaximumNumberOfVertices = num;
521                }
522               
523                unsigned int getTargetMaximumNumberOfVertices() const
524                {
525                    return _targetMaximumNumberOfVertices;
526                }
527
528                virtual void apply(osg::Geode& geode) { mergeGeode(geode); }
529                virtual void apply(osg::Billboard&) { /* don't do anything*/ }
530
531                bool mergeGeode(osg::Geode& geode);
532
533                static bool geometryContainsSharedArrays(osg::Geometry& geom);
534
535                static bool mergeGeometry(osg::Geometry& lhs,osg::Geometry& rhs);
536
537                static bool mergePrimitive(osg::DrawArrays& lhs,osg::DrawArrays& rhs);
538                static bool mergePrimitive(osg::DrawArrayLengths& lhs,osg::DrawArrayLengths& rhs);
539                static bool mergePrimitive(osg::DrawElementsUByte& lhs,osg::DrawElementsUByte& rhs);
540                static bool mergePrimitive(osg::DrawElementsUShort& lhs,osg::DrawElementsUShort& rhs);
541                static bool mergePrimitive(osg::DrawElementsUInt& lhs,osg::DrawElementsUInt& rhs);
542
543            protected:
544
545                unsigned int _targetMaximumNumberOfVertices;
546
547        };
548
549        /** Spatialize scene into a balanced quad/oct tree.*/
550        class OSGUTIL_EXPORT SpatializeGroupsVisitor : public BaseOptimizerVisitor
551        {
552            public:
553
554                SpatializeGroupsVisitor(Optimizer* optimizer=0):
555                    BaseOptimizerVisitor(optimizer, SPATIALIZE_GROUPS) {}
556               
557                virtual void apply(osg::Group& group);
558                virtual void apply(osg::Geode& geode);
559               
560                bool divide(unsigned int maxNumTreesPerCell=8);
561               
562                bool divide(osg::Group* group, unsigned int maxNumTreesPerCell);
563                bool divide(osg::Geode* geode, unsigned int maxNumTreesPerCell);
564               
565                typedef std::set<osg::Group*> GroupsToDivideList;
566                GroupsToDivideList _groupsToDivideList;
567
568                typedef std::set<osg::Geode*> GeodesToDivideList;
569                GeodesToDivideList _geodesToDivideList;
570        };
571
572        /** Copy any shared subgraphs, enabling flattening of static transforms.*/
573        class OSGUTIL_EXPORT CopySharedSubgraphsVisitor : public BaseOptimizerVisitor
574        {
575            public:
576
577                CopySharedSubgraphsVisitor(Optimizer* optimizer=0):
578                    BaseOptimizerVisitor(optimizer, COPY_SHARED_NODES) {}
579               
580                virtual void apply(osg::Node& node);
581
582                void copySharedNodes();
583               
584                typedef std::set<osg::Node*> SharedNodeList;
585                SharedNodeList _sharedNodeList;
586               
587        };
588
589
590        /** For all textures apply settings.*/
591        class OSGUTIL_EXPORT TextureVisitor : public BaseOptimizerVisitor
592        {
593            public:
594
595                TextureVisitor(bool changeAutoUnRef, bool valueAutoUnRef,
596                               bool changeClientImageStorage, bool valueClientImageStorage,
597                               bool changeAnisotropy, float valueAnisotropy,
598                               Optimizer* optimizer=0):
599                        BaseOptimizerVisitor(optimizer, OPTIMIZE_TEXTURE_SETTINGS),
600                        _changeAutoUnRef(changeAutoUnRef), _valueAutoUnRef(valueAutoUnRef),
601                        _changeClientImageStorage(changeClientImageStorage), _valueClientImageStorage(valueClientImageStorage),
602                        _changeAnisotropy(changeAnisotropy), _valueAnisotropy(valueAnisotropy) {}
603               
604                virtual void apply(osg::Geode& node);
605                virtual void apply(osg::Node& node);
606
607                void apply(osg::StateSet& stateset);
608                void apply(osg::Texture& texture);
609
610                bool            _changeAutoUnRef, _valueAutoUnRef;
611                bool            _changeClientImageStorage, _valueClientImageStorage;
612                bool            _changeAnisotropy;
613                float           _valueAnisotropy;
614
615        };
616       
617        /** Flatten MatrixTransform/Billboard pairs.*/
618        class OSGUTIL_EXPORT FlattenBillboardVisitor : public BaseOptimizerVisitor
619        {
620            public:
621                FlattenBillboardVisitor(Optimizer* optimizer=0):
622                        BaseOptimizerVisitor(optimizer, FLATTEN_BILLBOARDS) {}
623
624                typedef std::vector<osg::NodePath> NodePathList;
625                typedef std::map<osg::Billboard*, NodePathList > BillboardNodePathMap;
626
627                virtual void reset();
628
629                virtual void apply(osg::Billboard& billboard);
630
631                void process();   
632
633                BillboardNodePathMap _billboards;
634
635        };
636       
637        /** Texture Atlas Builder creates a set of textures/images which each contain multiple images.
638          * Texture Atlas' are used to make it possible to use much wider batching of data. */
639        class OSGUTIL_EXPORT TextureAtlasBuilder
640        {
641        public:
642            TextureAtlasBuilder();
643           
644            void reset();
645           
646            void setMaximumAtlasSize(unsigned int width, unsigned int height);
647
648            unsigned int getMaximumAtlasWidth() const { return _maximumAtlasWidth; }
649            unsigned int getMaximumAtlasHeight() const { return _maximumAtlasHeight; }
650           
651            void setMargin(unsigned int margin);
652            unsigned int getMargin() const { return _margin; }
653
654            void addSource(const osg::Image* image);
655            void addSource(const osg::Texture2D* texture);
656           
657            unsigned int getNumSources() const { return _sourceList.size(); }
658            const osg::Image* getSourceImage(unsigned int i) { return _sourceList[i]->_image.get(); }
659            const osg::Texture2D* getSourceTexture(unsigned int i) { return _sourceList[i]->_texture.get(); }
660           
661            void buildAtlas();
662           
663            osg::Image* getImageAtlas(unsigned int i);
664            osg::Texture2D* getTextureAtlas(unsigned int i);
665            osg::Matrix getTextureMatrix(unsigned int i);
666           
667            osg::Image* getImageAtlas(const osg::Image* image);
668            osg::Texture2D* getTextureAtlas(const osg::Image* image);
669            osg::Matrix getTextureMatrix(const osg::Image* image);
670           
671            osg::Image* getImageAtlas(const osg::Texture2D* textue);
672            osg::Texture2D* getTextureAtlas(const osg::Texture2D* texture);
673            osg::Matrix getTextureMatrix(const osg::Texture2D* texture);
674           
675        protected:
676       
677            unsigned int _maximumAtlasWidth;
678            unsigned int _maximumAtlasHeight;
679            unsigned int _margin;
680           
681
682            // forward declare
683            class Atlas;
684           
685            class Source : public osg::Referenced
686            {
687            public:
688                Source():
689                    _x(0),_y(0),_atlas(0) {}
690
691                Source(const osg::Image* image):
692                    _x(0),_y(0),_atlas(0),_image(image) {}
693
694                Source(const osg::Texture2D* texture):
695                    _x(0),_y(0),_atlas(0),_texture(texture) { if (texture) _image = texture->getImage(); }
696           
697                unsigned int _x;
698                unsigned int _y;
699                Atlas* _atlas;
700
701                osg::ref_ptr<const osg::Image> _image;
702                osg::ref_ptr<const osg::Texture2D> _texture;
703               
704                bool suitableForAtlas(unsigned int maximumAtlasWidth, unsigned int maximumAtlasHeight, unsigned int margin);
705                osg::Matrix computeTextureMatrix() const;
706               
707               
708            protected:
709           
710                virtual ~Source() {}
711            };
712           
713            typedef std::vector< osg::ref_ptr<Source> > SourceList;
714
715            class Atlas : public osg::Referenced
716            {
717            public:
718                Atlas(unsigned int width, unsigned height, unsigned margin):
719                    _maximumAtlasWidth(width),
720                    _maximumAtlasHeight(height),
721                    _margin(margin),
722                    _x(0),
723                    _y(0),
724                    _width(0),
725                    _height(0){}
726       
727                unsigned int _maximumAtlasWidth;
728                unsigned int _maximumAtlasHeight;
729                unsigned int _margin;
730
731                osg::ref_ptr<osg::Texture2D> _texture;
732                osg::ref_ptr<osg::Image> _image;
733           
734                SourceList _sourceList;
735               
736                unsigned int _x;
737                unsigned int _y;
738                unsigned int _width;
739                unsigned int _height;
740               
741                bool doesSourceFit(Source* source);
742                bool addSource(Source* source);
743                void clampToNearestPowerOfTwoSize();
744                void copySources();
745               
746            protected:
747           
748                virtual ~Atlas() {}
749            };
750           
751            typedef std::vector< osg::ref_ptr<Atlas> > AtlasList;
752           
753            Source* getSource(const osg::Image* image);
754            Source* getSource(const osg::Texture2D* texture);
755
756            SourceList _sourceList;
757            AtlasList _atlasList;   
758        };
759
760 
761        /** Optimize texture usage in the scene graph by combining textures into texture atlas
762          * Use of texture atlas cuts down on the number of seperate states in the scene, reducing
763          * state changes and improving the chances of use larger batches of geomertry.*/
764        class OSGUTIL_EXPORT TextureAtlasVisitor : public BaseOptimizerVisitor
765        {
766            public:
767
768                /// default to traversing all children.
769                TextureAtlasVisitor(Optimizer* optimizer=0):
770                    BaseOptimizerVisitor(optimizer, TEXTURE_ATLAS_BUILDER) {}
771
772
773                TextureAtlasBuilder& getTextureAtlasBuilder() { return _builder; }
774
775                /** empty visitor, make it ready for next traversal.*/       
776                virtual void reset();
777
778                virtual void apply(osg::Node& node);
779
780                virtual void apply(osg::Geode& geode);
781
782                void optimize();
783
784            protected:
785
786                bool pushStateSet(osg::StateSet* stateset);
787                void popStateSet();
788
789                typedef std::set<osg::Drawable*>  Drawables;
790                typedef std::map<osg::StateSet*, Drawables>  StateSetMap;
791                typedef std::set<osg::Texture2D*>  Textures;
792                typedef std::vector<osg::StateSet*>  StateSetStack;
793
794                TextureAtlasBuilder _builder;
795
796                StateSetMap     _statesetMap;
797                StateSetStack   _statesetStack;
798                Textures        _textures;
799
800        };
801
802        /** Optimize the setting of StateSet and Geometry objects in scene so that they have a STATIC DataVariance
803          * when they don't have any callbacks associated with them. */
804        class OSGUTIL_EXPORT StaticObjectDetectionVisitor : public BaseOptimizerVisitor
805        {
806            public:
807
808                /// default to traversing all children.
809                StaticObjectDetectionVisitor(Optimizer* optimizer=0):
810                    BaseOptimizerVisitor(optimizer, STATIC_OBJECT_DETECTION) {}
811
812                virtual void apply(osg::Node& node);
813
814                virtual void apply(osg::Geode& geode);
815
816            protected:
817
818                void applyStateSet(osg::StateSet& stateset);
819               
820                void applyDrawable(osg::Drawable& drawable);
821
822        };
823};
824
825inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::StateSet* object) const
826{
827    return _optimizer ? _optimizer->isOperationPermissibleForObject(object,_operationType) :  true;
828}
829
830inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::StateAttribute* object) const
831{
832    return _optimizer ? _optimizer->isOperationPermissibleForObject(object,_operationType) :  true;
833}
834
835inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::Drawable* object) const
836{
837    return _optimizer ? _optimizer->isOperationPermissibleForObject(object,_operationType) :  true;
838}
839
840inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::Node* object) const
841{
842    return _optimizer ? _optimizer->isOperationPermissibleForObject(object,_operationType) :  true;
843}
844
845}
846
847#endif
Note: See TracBrowser for help on using the browser.