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_STATEGRAPH
15#define OSGUTIL_STATEGRAPH 1
18#include <osg/Drawable>
19#include <osg/StateSet>
23#include <osgUtil/RenderLeaf>
31struct LessDepthSortFunctor
33 bool operator() (const osg::ref_ptr<RenderLeaf>& lhs,const osg::ref_ptr<RenderLeaf>& rhs)
35 return (lhs->_depth < rhs->_depth);
39/** StateGraph - contained in a renderBin, defines the scene to be drawn.
41class OSGUTIL_EXPORT StateGraph : public osg::Object
46 typedef std::map< const osg::StateSet*, osg::ref_ptr<StateGraph> > ChildList;
47 typedef std::vector< osg::ref_ptr<RenderLeaf> > LeafList;
51#ifdef OSGUTIL_RENDERBACKEND_USE_REF_PTR
52 osg::ref_ptr<const osg::StateSet> _stateset;
54 const osg::StateSet* _stateset;
61 mutable float _averageDistance;
62 mutable float _minimumDistance;
64 osg::ref_ptr<osg::Referenced> _userData;
79 StateGraph(StateGraph* parent,const osg::StateSet* stateset):
88 if (_parent) _depth = _parent->_depth + 1;
90 if (_parent && _parent->_dynamic) _dynamic = true;
91 else _dynamic = stateset->getDataVariance()==osg::Object::DYNAMIC;
97 virtual osg::Object* cloneType() const { return new StateGraph(); }
98 virtual StateGraph* cloneStateGraph() const { return new StateGraph(); }
99 virtual osg::Object* clone(const osg::CopyOp&) const { return new StateGraph(); }
100 virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const StateGraph*>(obj)!=0L; }
101 virtual const char* libraryName() const { return "osgUtil"; }
102 virtual const char* className() const { return "StateGraph"; }
104 void setUserData(osg::Referenced* obj) { _userData = obj; }
105 osg::Referenced* getUserData() { return _userData.get(); }
106 const osg::Referenced* getUserData() const { return _userData.get(); }
108 void setStateSet(const osg::StateSet* stateset) { _stateset = stateset; }
110#ifdef OSGUTIL_RENDERBACKEND_USE_REF_PTR
111 const osg::StateSet* getStateSet() const { return _stateset.get(); }
113 const osg::StateSet* getStateSet() const { return _stateset; }
116 /** return true if all of drawables, lights and children are empty.*/
117 inline bool empty() const
119 return _leaves.empty() && _children.empty();
122 inline bool leaves_empty() const
124 return _leaves.empty();
128 inline float getAverageDistance() const
130 if (_averageDistance==FLT_MAX && !_leaves.empty())
132 _averageDistance = 0.0f;
133 for(LeafList::const_iterator itr=_leaves.begin();
137 _averageDistance += (*itr)->_depth;
139 _averageDistance /= (float)_leaves.size();
142 return _averageDistance;
145 inline float getMinimumDistance() const
147 if (_minimumDistance==FLT_MAX && !_leaves.empty())
149 LeafList::const_iterator itr=_leaves.begin();
150 _minimumDistance = (*itr)->_depth;
156 if ((*itr)->_depth<_minimumDistance) _minimumDistance=(*itr)->_depth;
160 return _minimumDistance;
163 inline void sortFrontToBack()
165 std::sort(_leaves.begin(),_leaves.end(),LessDepthSortFunctor());
168 /** Reset the internal contents of a StateGraph, including deleting all children.*/
171 /** Recursively clean the StateGraph of all its drawables, lights and depths.
172 * Leaves children intact, and ready to be populated again.*/
175 /** Recursively prune the StateGraph of empty children.*/
179 void resizeGLObjectBuffers(unsigned int maxSize)
181 for(ChildList::iterator itr = _children.begin();
182 itr != _children.end();
185 (itr->second)->resizeGLObjectBuffers(maxSize);
188 for(LeafList::iterator itr = _leaves.begin();
189 itr != _leaves.end();
192 (*itr)->resizeGLObjectBuffers(maxSize);
196 void releaseGLObjects(osg::State* state=0) const
198 if (_stateset) _stateset->releaseGLObjects(state);
200 for(ChildList::const_iterator itr = _children.begin();
201 itr != _children.end();
204 (itr->second)->releaseGLObjects(state);
207 for(LeafList::const_iterator itr = _leaves.begin();
208 itr != _leaves.end();
211 (*itr)->releaseGLObjects(state);
215 inline StateGraph* find_or_insert(const osg::StateSet* stateset)
217 // search for the appropriate state group, return it if found.
218 ChildList::iterator itr = _children.find(stateset);
219 if (itr!=_children.end()) return itr->second.get();
221 // create a state group and insert it into the children list
222 // then return the state group.
223 StateGraph* sg = new StateGraph(this,stateset);
224 _children[stateset] = sg;
228 /** add a render leaf.*/
229 inline void addLeaf(RenderLeaf* leaf)
233 _averageDistance = FLT_MAX; // signify dirty.
234 _minimumDistance = FLT_MAX; // signify dirty.
235 _leaves.push_back(leaf);
236 leaf->_parent = this;
237 if (_dynamic) leaf->_dynamic = true;
241 static inline void moveStateGraph(osg::State& state,StateGraph* sg_curr,StateGraph* sg_new)
243 if (sg_new==sg_curr || sg_new==NULL) return;
248 // use return path to trace back steps to sg_new.
249 std::vector<StateGraph*> return_path;
250 return_path.reserve(sg_new->_depth+1);
252 // need to pop back root render graph.
255 return_path.push_back(sg_new);
256 sg_new = sg_new->_parent;
259 for(std::vector<StateGraph*>::reverse_iterator itr=return_path.rbegin();
260 itr!=return_path.rend();
263 StateGraph* rg = (*itr);
264 if (rg->getStateSet()) state.pushStateSet(rg->getStateSet());
270 // first handle the typical case which is two state groups
272 if (sg_curr->_parent==sg_new->_parent)
275 // state has changed so need to pop old state.
276 if (sg_curr->getStateSet()) state.popStateSet();
277 // and push new state.
278 if (sg_new->getStateSet()) state.pushStateSet(sg_new->getStateSet());
283 // need to pop back up to the same depth as the new state group.
284 while (sg_curr->_depth>sg_new->_depth)
286 if (sg_curr->getStateSet()) state.popStateSet();
287 sg_curr = sg_curr->_parent;
290 // use return path to trace back steps to sg_new.
291 std::vector<StateGraph*> return_path;
292 return_path.reserve(sg_new->_depth+1);
294 // need to pop back up to the same depth as the curr state group.
295 while (sg_new->_depth>sg_curr->_depth)
297 return_path.push_back(sg_new);
298 sg_new = sg_new->_parent;
301 // now pop back up both parent paths until they agree.
304 // should be this to conform with above case where two StateGraph
305 // nodes have the same parent
306 while (sg_curr != sg_new)
308 if (sg_curr->getStateSet()) state.popStateSet();
309 sg_curr = sg_curr->_parent;
311 return_path.push_back(sg_new);
312 sg_new = sg_new->_parent;
315 for(std::vector<StateGraph*>::reverse_iterator itr=return_path.rbegin();
316 itr!=return_path.rend();
319 StateGraph* rg = (*itr);
320 if (rg->getStateSet()) state.pushStateSet(rg->getStateSet());
325 inline static void moveToRootStateGraph(osg::State& state,StateGraph* sg_curr)
327 // need to pop back all statesets and matrices.
330 if (sg_curr->getStateSet()) state.popStateSet();
331 sg_curr = sg_curr->_parent;
336 inline static int numToPop(StateGraph* sg_curr)
339 // need to pop back all statesets and matrices.
342 if (sg_curr->getStateSet()) ++numToPop;
343 sg_curr = sg_curr->_parent;
351 /// disallow copy construction.
352 StateGraph(const StateGraph&) : osg::Object() {}
353 /// disallow copy operator.
354 StateGraph& operator = (const StateGraph&) { return *this; }