OpenSceneGraph/include/osgUtil/RenderGraph
2002-05-18 08:39:42 +00:00

211 lines
6.5 KiB
Plaintext

//C++ header - Open Scene Graph - Copyright (C) 1998-2001 Robert Osfield
//Distributed under the terms of the GNU Library General Public License (LGPL)
//as published by the Free Software Foundation.
#ifndef OSGUTIL_RENDERGRAPH
#define OSGUTIL_RENDERGRAPH 1
#include <osg/Matrix>
#include <osg/Drawable>
#include <osg/StateSet>
#include <osg/State>
#include <osg/Light>
#include <osgUtil/RenderLeaf>
#include <set>
#include <vector>
namespace osgUtil {
class OSGUTIL_EXPORT RenderGraph : public osg::Referenced
{
public:
typedef std::map< const osg::StateSet*, osg::ref_ptr<RenderGraph> > ChildList;
typedef std::vector< osg::ref_ptr<RenderLeaf> > LeafList;
RenderGraph* _parent;
osg::ref_ptr<const osg::StateSet> _stateset;
int _depth;
ChildList _children;
LeafList _leaves;
osg::ref_ptr<osg::Referenced> _userData;
RenderGraph():
_parent(NULL),
_stateset(NULL),
_depth(0)
{
}
RenderGraph(RenderGraph* parent,const osg::StateSet* stateset):
_parent(parent),
_stateset(stateset)
{
if (_parent) _depth = _parent->_depth + 1;
else _depth = 0;
}
~RenderGraph() {}
RenderGraph* cloneType() const { return new RenderGraph; }
void setUserData(osg::Referenced* obj) { _userData = obj; }
osg::Referenced* getUserData() { return _userData.get(); }
const osg::Referenced* getUserData() const { return _userData.get(); }
/** return true if all of drawables, lights and children are empty.*/
inline const bool empty() const
{
return _leaves.empty() && _children.empty();
}
inline const bool leaves_empty() const
{
return _leaves.empty();
}
/** reset the internal contents of a RenderGraph, including deleting all children.*/
void reset();
/** recursively clean the RenderGraph of all its drawables, lights and depths.
* Leaves children intact, and ready to be populated again.*/
void clean();
/** recursively prune the RenderGraph of empty children.*/
void prune();
inline RenderGraph* 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.
RenderGraph* sg = new RenderGraph(this,stateset);
_children[stateset] = sg;
return sg;
}
/** add a render leaf.*/
inline void addLeaf(RenderLeaf* leaf)
{
if (leaf)
{
_leaves.push_back(leaf);
leaf->_parent = this;
}
}
static inline void moveRenderGraph(osg::State& state,RenderGraph* sg_curr,RenderGraph* 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<RenderGraph*> return_path;
// 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<RenderGraph*>::reverse_iterator itr=return_path.rbegin();
itr!=return_path.rend();
++itr)
{
RenderGraph* rg = (*itr);
if (rg->_stateset.valid()) state.pushStateSet(rg->_stateset.get());
}
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.valid()) state.popStateSet();
// and push new state.
if (sg_new->_stateset.valid()) state.pushStateSet(sg_new->_stateset.get());
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->_stateset.valid()) state.popStateSet();
sg_curr = sg_curr->_parent;
}
// use return path to trace back steps to sg_new.
std::vector<RenderGraph*> return_path;
// 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.
while (sg_curr->_parent!=sg_new->_parent)
{
if (sg_curr->_stateset.valid()) state.popStateSet();
sg_curr = sg_curr->_parent;
return_path.push_back(sg_new);
sg_new = sg_new->_parent;
}
for(std::vector<RenderGraph*>::reverse_iterator itr=return_path.rbegin();
itr!=return_path.rend();
++itr)
{
RenderGraph* rg = (*itr);
if (rg->_stateset.valid()) state.pushStateSet(rg->_stateset.get());
}
}
inline static void moveToRootRenderGraph(osg::State& state,RenderGraph* sg_curr)
{
// need to pop back all statesets and matrices.
while (sg_curr)
{
if (sg_curr->_stateset.valid()) state.popStateSet();
sg_curr = sg_curr->_parent;
}
}
private:
/// disallow copy construction.
RenderGraph(const RenderGraph&):osg::Referenced() {}
/// disallow copy operator.
RenderGraph& operator = (const RenderGraph&) { return *this; }
};
}
#endif