root/OpenSceneGraph/trunk/include/osgUtil/StateGraph @ 13041

Revision 13041, 9.7 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • 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_STATEGRAPH
15#define OSGUTIL_STATEGRAPH 1
16
17#include <osg/Matrix>
18#include <osg/Drawable>
19#include <osg/StateSet>
20#include <osg/State>
21#include <osg/Light>
22
23#include <osgUtil/RenderLeaf>
24
25#include <set>
26#include <vector>
27#include <algorithm>
28
29namespace osgUtil {
30
31struct LessDepthSortFunctor
32{
33    bool operator() (const osg::ref_ptr<RenderLeaf>& lhs,const osg::ref_ptr<RenderLeaf>& rhs)
34    {
35        return (lhs->_depth < rhs->_depth);
36    }
37};
38
39/** StateGraph - contained in a renderBin, defines the scene to be drawn.
40  */
41class OSGUTIL_EXPORT StateGraph : public osg::Referenced
42{
43    public:
44
45
46        typedef std::map< const osg::StateSet*, osg::ref_ptr<StateGraph> >   ChildList;
47        typedef std::vector< osg::ref_ptr<RenderLeaf> >                 LeafList;
48
49        StateGraph*                         _parent;
50
51#ifdef OSGUTIL_RENDERBACKEND_USE_REF_PTR
52        osg::ref_ptr<const osg::StateSet> _stateset;
53#else
54        const osg::StateSet* _stateset;
55#endif
56
57        int                                 _depth;
58        ChildList                           _children;
59        LeafList                            _leaves;
60
61        mutable float                       _averageDistance;
62        mutable float                       _minimumDistance;
63
64        osg::ref_ptr<osg::Referenced>       _userData;
65
66        bool                                _dynamic;
67
68        StateGraph():
69            osg::Referenced(false),
70            _parent(NULL),
71            _stateset(NULL),
72            _depth(0),
73            _averageDistance(0),
74            _minimumDistance(0),
75            _userData(NULL),
76            _dynamic(false)
77        {
78        }
79
80        StateGraph(StateGraph* parent,const osg::StateSet* stateset):
81            osg::Referenced(false),
82            _parent(parent),
83            _stateset(stateset),
84            _depth(0),
85            _averageDistance(0),
86            _minimumDistance(0),
87            _userData(NULL),
88            _dynamic(false)
89        {
90            if (_parent) _depth = _parent->_depth + 1;
91
92            if (_parent && _parent->_dynamic) _dynamic = true;
93            else _dynamic = stateset->getDataVariance()==osg::Object::DYNAMIC;
94        }
95
96        ~StateGraph() {}
97
98        StateGraph* cloneType() const { return new StateGraph; }
99
100        void setUserData(osg::Referenced* obj) { _userData = obj; }
101        osg::Referenced* getUserData() { return _userData.get(); }
102        const osg::Referenced* getUserData() const { return _userData.get(); }
103
104        void setStateSet(const osg::StateSet* stateset) { _stateset = stateset; }
105
106#ifdef OSGUTIL_RENDERBACKEND_USE_REF_PTR
107        const osg::StateSet* getStateSet() const { return _stateset.get(); }
108#else
109        const osg::StateSet* getStateSet() const { return _stateset; }
110#endif
111
112        /** return true if all of drawables, lights and children are empty.*/
113        inline bool empty() const
114        {
115            return _leaves.empty() && _children.empty();
116        }
117
118        inline bool leaves_empty() const
119        {
120            return _leaves.empty();
121        }
122
123
124        inline float getAverageDistance() const
125        {
126            if (_averageDistance==FLT_MAX && !_leaves.empty())
127            {
128                _averageDistance = 0.0f;
129                for(LeafList::const_iterator itr=_leaves.begin();
130                    itr!=_leaves.end();
131                    ++itr)
132                {
133                   _averageDistance += (*itr)->_depth;
134                }
135                _averageDistance /= (float)_leaves.size();
136
137            }
138            return _averageDistance;
139        }
140
141        inline float getMinimumDistance() const
142        {
143            if (_minimumDistance==FLT_MAX && !_leaves.empty())
144            {
145                LeafList::const_iterator itr=_leaves.begin();
146                _minimumDistance = (*itr)->_depth;
147                ++itr;
148                for(;
149                    itr!=_leaves.end();
150                    ++itr)
151                {
152                   if ((*itr)->_depth<_minimumDistance) _minimumDistance=(*itr)->_depth;
153                }
154
155            }
156            return _minimumDistance;
157        }
158
159        inline void sortFrontToBack()
160        {
161            std::sort(_leaves.begin(),_leaves.end(),LessDepthSortFunctor());
162        }
163
164        /** Reset the internal contents of a StateGraph, including deleting all children.*/
165        void reset();
166
167        /** Recursively clean the StateGraph of all its drawables, lights and depths.
168          * Leaves children intact, and ready to be populated again.*/
169        void clean();
170
171        /** Recursively prune the StateGraph of empty children.*/
172        void prune();
173
174
175        inline StateGraph* find_or_insert(const osg::StateSet* stateset)
176        {
177            // search for the appropriate state group, return it if found.
178            ChildList::iterator itr = _children.find(stateset);
179            if (itr!=_children.end()) return itr->second.get();
180
181            // create a state group and insert it into the children list
182            // then return the state group.
183            StateGraph* sg = new StateGraph(this,stateset);
184            _children[stateset] = sg;
185            return sg;
186        }
187
188        /** add a render leaf.*/
189        inline void addLeaf(RenderLeaf* leaf)
190        {
191            if (leaf)
192            {
193                _averageDistance = FLT_MAX; // signify dirty.
194                _minimumDistance = FLT_MAX; // signify dirty.
195                _leaves.push_back(leaf);
196                leaf->_parent = this;
197                if (_dynamic) leaf->_dynamic = true;
198            }
199        }
200
201        static inline void moveStateGraph(osg::State& state,StateGraph* sg_curr,StateGraph* sg_new)
202        {
203            if (sg_new==sg_curr || sg_new==NULL) return;
204
205            if (sg_curr==NULL)
206            {
207
208                // use return path to trace back steps to sg_new.
209                std::vector<StateGraph*> return_path;
210
211                // need to pop back root render graph.
212                do
213                {
214                    return_path.push_back(sg_new);
215                    sg_new = sg_new->_parent;
216                } while (sg_new);
217
218                for(std::vector<StateGraph*>::reverse_iterator itr=return_path.rbegin();
219                    itr!=return_path.rend();
220                    ++itr)
221                {
222                    StateGraph* rg = (*itr);
223                    if (rg->getStateSet()) state.pushStateSet(rg->getStateSet());
224                }
225                return;
226            }
227
228
229            // first handle the typical case which is two state groups
230            // are neighbours.
231            if (sg_curr->_parent==sg_new->_parent)
232            {
233
234                // state has changed so need to pop old state.
235                if (sg_curr->getStateSet()) state.popStateSet();
236                // and push new state.
237                if (sg_new->getStateSet()) state.pushStateSet(sg_new->getStateSet());
238                return;
239            }
240
241
242            // need to pop back up to the same depth as the new state group.
243            while (sg_curr->_depth>sg_new->_depth)
244            {
245                if (sg_curr->getStateSet()) state.popStateSet();
246                sg_curr = sg_curr->_parent;
247            }
248
249            // use return path to trace back steps to sg_new.
250            std::vector<StateGraph*> return_path;
251
252            // need to pop back up to the same depth as the curr state group.
253            while (sg_new->_depth>sg_curr->_depth)
254            {
255                return_path.push_back(sg_new);
256                sg_new = sg_new->_parent;
257            }
258
259            // now pop back up both parent paths until they agree.
260
261            // DRT - 10/22/02
262            // should be this to conform with above case where two StateGraph
263            // nodes have the same parent
264            while (sg_curr != sg_new)
265            {
266                if (sg_curr->getStateSet()) state.popStateSet();
267                sg_curr = sg_curr->_parent;
268
269                return_path.push_back(sg_new);
270                sg_new = sg_new->_parent;
271            }
272
273            for(std::vector<StateGraph*>::reverse_iterator itr=return_path.rbegin();
274                itr!=return_path.rend();
275                ++itr)
276            {
277                StateGraph* rg = (*itr);
278                if (rg->getStateSet()) state.pushStateSet(rg->getStateSet());
279            }
280
281        }
282
283        inline static void moveToRootStateGraph(osg::State& state,StateGraph* sg_curr)
284        {
285            // need to pop back all statesets and matrices.
286            while (sg_curr)
287            {
288                if (sg_curr->getStateSet()) state.popStateSet();
289                sg_curr = sg_curr->_parent;
290            }
291
292        }
293
294        inline static int numToPop(StateGraph* sg_curr)
295        {
296            int numToPop = 0;
297            // need to pop back all statesets and matrices.
298            while (sg_curr)
299            {
300                if (sg_curr->getStateSet()) ++numToPop;
301                sg_curr = sg_curr->_parent;
302            }
303
304            return numToPop;
305        }
306
307    private:
308
309        /// disallow copy construction.
310        StateGraph(const StateGraph&):osg::Referenced() {}
311        /// disallow copy operator.
312        StateGraph& operator = (const StateGraph&) { return *this; }
313
314};
315
316}
317
318#endif
319
Note: See TracBrowser for help on using the browser.