123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361 |
- /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 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_STATEGRAPH
- #define OSGUTIL_STATEGRAPH 1
- #include <osg/Matrix>
- #include <osg/Drawable>
- #include <osg/StateSet>
- #include <osg/State>
- #include <osg/Light>
- #include <osgUtil/RenderLeaf>
- #include <set>
- #include <vector>
- #include <algorithm>
- namespace osgUtil {
- struct LessDepthSortFunctor
- {
- bool operator() (const osg::ref_ptr<RenderLeaf>& lhs,const osg::ref_ptr<RenderLeaf>& rhs)
- {
- return (lhs->_depth < rhs->_depth);
- }
- };
- /** StateGraph - contained in a renderBin, defines the scene to be drawn.
- */
- class OSGUTIL_EXPORT StateGraph : public osg::Object
- {
- public:
- typedef std::map< const osg::StateSet*, osg::ref_ptr<StateGraph> > ChildList;
- typedef std::vector< osg::ref_ptr<RenderLeaf> > LeafList;
- StateGraph* _parent;
- #ifdef OSGUTIL_RENDERBACKEND_USE_REF_PTR
- osg::ref_ptr<const osg::StateSet> _stateset;
- #else
- const osg::StateSet* _stateset;
- #endif
- int _depth;
- ChildList _children;
- LeafList _leaves;
- mutable float _averageDistance;
- mutable float _minimumDistance;
- osg::ref_ptr<osg::Referenced> _userData;
- bool _dynamic;
- StateGraph():
- _parent(NULL),
- _stateset(NULL),
- _depth(0),
- _averageDistance(0),
- _minimumDistance(0),
- _userData(NULL),
- _dynamic(false)
- {
- }
- StateGraph(StateGraph* parent,const osg::StateSet* stateset):
- _parent(parent),
- _stateset(stateset),
- _depth(0),
- _averageDistance(0),
- _minimumDistance(0),
- _userData(NULL),
- _dynamic(false)
- {
- if (_parent) _depth = _parent->_depth + 1;
- if (_parent && _parent->_dynamic) _dynamic = true;
- else _dynamic = stateset->getDataVariance()==osg::Object::DYNAMIC;
- }
- ~StateGraph() {}
- virtual osg::Object* cloneType() const { return new StateGraph(); }
- virtual StateGraph* cloneStateGraph() const { return new StateGraph(); }
- virtual osg::Object* clone(const osg::CopyOp&) const { return new StateGraph(); }
- virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const StateGraph*>(obj)!=0L; }
- virtual const char* libraryName() const { return "osgUtil"; }
- virtual const char* className() const { return "StateGraph"; }
- void setUserData(osg::Referenced* obj) { _userData = obj; }
- osg::Referenced* getUserData() { return _userData.get(); }
- const osg::Referenced* getUserData() const { return _userData.get(); }
- void setStateSet(const osg::StateSet* stateset) { _stateset = stateset; }
- #ifdef OSGUTIL_RENDERBACKEND_USE_REF_PTR
- const osg::StateSet* getStateSet() const { return _stateset.get(); }
- #else
- const osg::StateSet* getStateSet() const { return _stateset; }
- #endif
- /** return true if all of drawables, lights and children are empty.*/
- inline bool empty() const
- {
- return _leaves.empty() && _children.empty();
- }
- inline bool leaves_empty() const
- {
- return _leaves.empty();
- }
- inline float getAverageDistance() const
- {
- if (_averageDistance==FLT_MAX && !_leaves.empty())
- {
- _averageDistance = 0.0f;
- for(LeafList::const_iterator itr=_leaves.begin();
- itr!=_leaves.end();
- ++itr)
- {
- _averageDistance += (*itr)->_depth;
- }
- _averageDistance /= (float)_leaves.size();
- }
- return _averageDistance;
- }
- inline float getMinimumDistance() const
- {
- if (_minimumDistance==FLT_MAX && !_leaves.empty())
- {
- LeafList::const_iterator itr=_leaves.begin();
- _minimumDistance = (*itr)->_depth;
- ++itr;
- for(;
- itr!=_leaves.end();
- ++itr)
- {
- if ((*itr)->_depth<_minimumDistance) _minimumDistance=(*itr)->_depth;
- }
- }
- return _minimumDistance;
- }
- inline void sortFrontToBack()
- {
- std::sort(_leaves.begin(),_leaves.end(),LessDepthSortFunctor());
- }
- /** Reset the internal contents of a StateGraph, including deleting all children.*/
- void reset();
- /** Recursively clean the StateGraph of all its drawables, lights and depths.
- * Leaves children intact, and ready to be populated again.*/
- void clean();
- /** Recursively prune the StateGraph of empty children.*/
- void prune();
- void resizeGLObjectBuffers(unsigned int maxSize)
- {
- for(ChildList::iterator itr = _children.begin();
- itr != _children.end();
- ++itr)
- {
- (itr->second)->resizeGLObjectBuffers(maxSize);
- }
- for(LeafList::iterator itr = _leaves.begin();
- itr != _leaves.end();
- ++itr)
- {
- (*itr)->resizeGLObjectBuffers(maxSize);
- }
- }
- void releaseGLObjects(osg::State* state=0) const
- {
- if (_stateset) _stateset->releaseGLObjects(state);
- for(ChildList::const_iterator itr = _children.begin();
- itr != _children.end();
- ++itr)
- {
- (itr->second)->releaseGLObjects(state);
- }
- for(LeafList::const_iterator itr = _leaves.begin();
- itr != _leaves.end();
- ++itr)
- {
- (*itr)->releaseGLObjects(state);
- }
- }
- inline StateGraph* find_or_insert(const osg::StateSet* stateset)
- {
- // search for the appropriate state group, return it if found.
- ChildList::iterator itr = _children.find(stateset);
- if (itr!=_children.end()) return itr->second.get();
- // create a state group and insert it into the children list
- // then return the state group.
- StateGraph* sg = new StateGraph(this,stateset);
- _children[stateset] = sg;
- return sg;
- }
- /** add a render leaf.*/
- inline void addLeaf(RenderLeaf* leaf)
- {
- if (leaf)
- {
- _averageDistance = FLT_MAX; // signify dirty.
- _minimumDistance = FLT_MAX; // signify dirty.
- _leaves.push_back(leaf);
- leaf->_parent = this;
- if (_dynamic) leaf->_dynamic = true;
- }
- }
- static inline void moveStateGraph(osg::State& state,StateGraph* sg_curr,StateGraph* sg_new)
- {
- if (sg_new==sg_curr || sg_new==NULL) return;
- if (sg_curr==NULL)
- {
- // use return path to trace back steps to sg_new.
- std::vector<StateGraph*> return_path;
- return_path.reserve(sg_new->_depth+1);
- // need to pop back root render graph.
- do
- {
- return_path.push_back(sg_new);
- sg_new = sg_new->_parent;
- } while (sg_new);
- for(std::vector<StateGraph*>::reverse_iterator itr=return_path.rbegin();
- itr!=return_path.rend();
- ++itr)
- {
- StateGraph* rg = (*itr);
- if (rg->getStateSet()) state.pushStateSet(rg->getStateSet());
- }
- return;
- }
- // first handle the typical case which is two state groups
- // are neighbours.
- if (sg_curr->_parent==sg_new->_parent)
- {
- // state has changed so need to pop old state.
- if (sg_curr->getStateSet()) state.popStateSet();
- // and push new state.
- if (sg_new->getStateSet()) state.pushStateSet(sg_new->getStateSet());
- return;
- }
- // need to pop back up to the same depth as the new state group.
- while (sg_curr->_depth>sg_new->_depth)
- {
- if (sg_curr->getStateSet()) state.popStateSet();
- sg_curr = sg_curr->_parent;
- }
- // use return path to trace back steps to sg_new.
- std::vector<StateGraph*> return_path;
- return_path.reserve(sg_new->_depth+1);
- // need to pop back up to the same depth as the curr state group.
- while (sg_new->_depth>sg_curr->_depth)
- {
- return_path.push_back(sg_new);
- sg_new = sg_new->_parent;
- }
- // now pop back up both parent paths until they agree.
- // DRT - 10/22/02
- // should be this to conform with above case where two StateGraph
- // nodes have the same parent
- while (sg_curr != sg_new)
- {
- if (sg_curr->getStateSet()) state.popStateSet();
- sg_curr = sg_curr->_parent;
- return_path.push_back(sg_new);
- sg_new = sg_new->_parent;
- }
- for(std::vector<StateGraph*>::reverse_iterator itr=return_path.rbegin();
- itr!=return_path.rend();
- ++itr)
- {
- StateGraph* rg = (*itr);
- if (rg->getStateSet()) state.pushStateSet(rg->getStateSet());
- }
- }
- inline static void moveToRootStateGraph(osg::State& state,StateGraph* sg_curr)
- {
- // need to pop back all statesets and matrices.
- while (sg_curr)
- {
- if (sg_curr->getStateSet()) state.popStateSet();
- sg_curr = sg_curr->_parent;
- }
- }
- inline static int numToPop(StateGraph* sg_curr)
- {
- int numToPop = 0;
- // need to pop back all statesets and matrices.
- while (sg_curr)
- {
- if (sg_curr->getStateSet()) ++numToPop;
- sg_curr = sg_curr->_parent;
- }
- return numToPop;
- }
- private:
- /// disallow copy construction.
- StateGraph(const StateGraph&) : osg::Object() {}
- /// disallow copy operator.
- StateGraph& operator = (const StateGraph&) { return *this; }
- };
- }
- #endif
|