OpenSceneGraph/include/osgUtil/StateGraph

288 lines
8.9 KiB
Plaintext
Raw Normal View History

2006-07-18 23:21:48 +08:00
/* -*-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
2001-09-20 05:19:47 +08:00
#include <osg/Matrix>
#include <osg/Drawable>
#include <osg/StateSet>
#include <osg/State>
#include <osg/Light>
#include <osgUtil/RenderLeaf>
#include <set>
#include <vector>
#include <algorithm>
2001-09-20 05:19:47 +08:00
namespace osgUtil {
struct LeafDepthSortFunctor
{
bool operator() (const osg::ref_ptr<RenderLeaf>& lhs,const osg::ref_ptr<RenderLeaf>& rhs)
{
return (lhs->_depth>rhs->_depth);
}
};
2001-09-20 05:19:47 +08:00
/** StateGraph - contained in a renderBin, defines the scene to be drawn.
*/
class OSGUTIL_EXPORT StateGraph : public osg::Referenced
2001-09-20 05:19:47 +08:00
{
public:
typedef std::map< const osg::StateSet*, osg::ref_ptr<StateGraph> > ChildList;
2001-09-20 05:19:47 +08:00
typedef std::vector< osg::ref_ptr<RenderLeaf> > LeafList;
StateGraph* _parent;
const osg::StateSet* _stateset;
2001-09-20 05:19:47 +08:00
int _depth;
ChildList _children;
LeafList _leaves;
mutable float _averageDistance;
mutable float _minimumDistance;
osg::ref_ptr<osg::Referenced> _userData;
2001-09-20 05:19:47 +08:00
StateGraph():
osg::Referenced(false),
2001-09-20 05:19:47 +08:00
_parent(NULL),
_stateset(NULL),
_depth(0),
_averageDistance(0),
_minimumDistance(0),
_userData(NULL)
2001-09-20 05:19:47 +08:00
{
}
StateGraph(StateGraph* parent,const osg::StateSet* stateset):
osg::Referenced(false),
2001-09-20 05:19:47 +08:00
_parent(parent),
_stateset(stateset),
_depth(0),
_averageDistance(0),
_minimumDistance(0),
_userData(NULL)
2001-09-20 05:19:47 +08:00
{
if (_parent) _depth = _parent->_depth + 1;
}
~StateGraph() {}
2001-09-20 05:19:47 +08:00
StateGraph* cloneType() const { return new StateGraph; }
2002-02-19 07:01:09 +08:00
void setUserData(osg::Referenced* obj) { _userData = obj; }
osg::Referenced* getUserData() { return _userData.get(); }
const osg::Referenced* getUserData() const { return _userData.get(); }
2001-09-20 05:19:47 +08:00
2001-09-28 20:36:40 +08:00
/** return true if all of drawables, lights and children are empty.*/
inline bool empty() const
2001-09-20 05:19:47 +08:00
{
return _leaves.empty() && _children.empty();
}
inline bool leaves_empty() const
2001-09-20 05:19:47 +08:00
{
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(),LeafDepthSortFunctor());
}
/** Reset the internal contents of a StateGraph, including deleting all children.*/
2001-09-20 05:19:47 +08:00
void reset();
/** Recursively clean the StateGraph of all its drawables, lights and depths.
2001-09-20 05:19:47 +08:00
* Leaves children intact, and ready to be populated again.*/
void clean();
/** Recursively prune the StateGraph of empty children.*/
2001-09-20 05:19:47 +08:00
void prune();
inline StateGraph* find_or_insert(const osg::StateSet* stateset)
2001-09-20 05:19:47 +08:00
{
// search for the appropriate state group, return it if found.
ChildList::iterator itr = _children.find(stateset);
if (itr!=_children.end()) return itr->second.get();
2001-09-28 20:36:40 +08:00
// create a state group and insert it into the children list
2001-09-20 05:19:47 +08:00
// then return the state group.
StateGraph* sg = new StateGraph(this,stateset);
2001-09-20 05:19:47 +08:00
_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.
2001-09-20 05:19:47 +08:00
_leaves.push_back(leaf);
leaf->_parent = this;
}
}
static inline void moveStateGraph(osg::State& state,StateGraph* sg_curr,StateGraph* sg_new)
2001-09-20 05:19:47 +08:00
{
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;
2001-09-20 05:19:47 +08:00
// 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();
2001-09-20 05:19:47 +08:00
itr!=return_path.rend();
++itr)
{
StateGraph* rg = (*itr);
if (rg->_stateset) state.pushStateSet(rg->_stateset);
2001-09-20 05:19:47 +08:00
}
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->_stateset) state.popStateSet();
2001-09-20 05:19:47 +08:00
// and push new state.
if (sg_new->_stateset) state.pushStateSet(sg_new->_stateset);
2001-09-20 05:19:47 +08:00
return;
}
2001-09-28 20:36:40 +08:00
// need to pop back up to the same depth as the new state group.
2001-09-20 05:19:47 +08:00
while (sg_curr->_depth>sg_new->_depth)
{
if (sg_curr->_stateset) state.popStateSet();
2001-09-20 05:19:47 +08:00
sg_curr = sg_curr->_parent;
}
// use return path to trace back steps to sg_new.
std::vector<StateGraph*> return_path;
2001-09-20 05:19:47 +08:00
2001-09-28 20:36:40 +08:00
// need to pop back up to the same depth as the curr state group.
2001-09-20 05:19:47 +08:00
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)
2001-09-20 05:19:47 +08:00
{
if (sg_curr->_stateset) state.popStateSet();
2001-09-20 05:19:47 +08:00
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();
2001-09-20 05:19:47 +08:00
itr!=return_path.rend();
++itr)
{
StateGraph* rg = (*itr);
if (rg->_stateset) state.pushStateSet(rg->_stateset);
2001-09-20 05:19:47 +08:00
}
}
inline static void moveToRootStateGraph(osg::State& state,StateGraph* sg_curr)
2001-09-20 05:19:47 +08:00
{
// need to pop back all statesets and matrices.
while (sg_curr)
{
if (sg_curr->_stateset) state.popStateSet();
2001-09-20 05:19:47 +08:00
sg_curr = sg_curr->_parent;
}
}
private:
/// disallow copy construction.
StateGraph(const StateGraph&):osg::Referenced() {}
2001-09-20 05:19:47 +08:00
/// disallow copy operator.
StateGraph& operator = (const StateGraph&) { return *this; }
2001-09-20 05:19:47 +08:00
};
}
2001-09-20 05:19:47 +08:00
#endif