diff --git a/include/osg/Node b/include/osg/Node index 5aec15c7b..fa1fd282d 100644 --- a/include/osg/Node +++ b/include/osg/Node @@ -105,6 +105,20 @@ class SG_EXPORT Node : public Object * since they have an AppCallback attached to them or their children.*/ inline const int getNumChildrenRequiringAppTraversal() const { return _numChildrenRequiringAppTraversal; } + + /** Set the view frustum/small feature culling of this node to be active or inactive. + * The default value to true for _cullingActive. Used a guide + * to the cull traversal.*/ + void setCullingActive(const bool active); + + /** Get the view frustum/small feature _cullingActive flag. Used a guide + * to the cull traversal.*/ + inline const bool getCullingActive() const { return _cullingActive; } + + /** Get the number of Children of this node which have culling disabled.*/ + inline const int getNumChildrenWithCullingDisabled() const { return _numChildrenWithCullingDisabled; } + + /** * Set user data. See MemoryAdapter documentation for details * of how to specify memory management of _userData. @@ -201,11 +215,14 @@ class SG_EXPORT Node : public Object ParentList _parents; friend Group; - ref_ptr _appCallback; - int _numChildrenRequiringAppTraversal; - + ref_ptr _appCallback; + int _numChildrenRequiringAppTraversal; void setNumChildrenRequiringAppTraversal(const int num); + bool _cullingActive; + int _numChildrenWithCullingDisabled; + void setNumChildrenWithCullingDisabled(const int num); + void* _userData; ref_ptr _memoryAdapter; diff --git a/src/osg/Group.cpp b/src/osg/Group.cpp index 85f1169c9..7a7f57120 100644 --- a/src/osg/Group.cpp +++ b/src/osg/Group.cpp @@ -62,6 +62,16 @@ bool Group::addChild( Node *child ) ); } + // could now require disabling of culling thanks to the new subgraph, + // so need to check and update if required. + if (child->getNumChildrenWithCullingDisabled()>0 || + !child->getCullingActive()) + { + setNumChildrenWithCullingDisabled( + getNumChildrenWithCullingDisabled()+1 + ); + } + return true; } else return false; @@ -89,6 +99,14 @@ bool Group::removeChild( Node *child ) ); } + if (child->getNumChildrenWithCullingDisabled()>0 || + !child->getCullingActive()) + { + setNumChildrenWithCullingDisabled( + getNumChildrenWithCullingDisabled()-1 + ); + } + // note ref_ptr<> automatically handles decrementing child's reference count. _children.erase(itr); dirtyBound(); @@ -118,6 +136,50 @@ bool Group::replaceChild( Node *origNode, Node *newNode ) newNode->_parents.push_back(this); dirtyBound(); + + + // could now require app traversal thanks to the new subgraph, + // so need to check and update if required. + int delta_numChildrenRequiringAppTraversal = 0; + if (origNode->getNumChildrenRequiringAppTraversal()>0 || + origNode->getAppCallback()) + { + --delta_numChildrenRequiringAppTraversal; + } + if (newNode->getNumChildrenRequiringAppTraversal()>0 || + newNode->getAppCallback()) + { + ++delta_numChildrenRequiringAppTraversal; + } + + if (delta_numChildrenRequiringAppTraversal!=0) + { + setNumChildrenRequiringAppTraversal( + getNumChildrenRequiringAppTraversal()+delta_numChildrenRequiringAppTraversal + ); + } + + // could now require disabling of culling thanks to the new subgraph, + // so need to check and update if required. + int delta_numChildrenWithCullingDisabled = 0; + if (origNode->getNumChildrenWithCullingDisabled()>0 || + !origNode->getCullingActive()) + { + --delta_numChildrenWithCullingDisabled; + } + if (newNode->getNumChildrenWithCullingDisabled()>0 || + !newNode->getCullingActive()) + { + ++delta_numChildrenWithCullingDisabled; + } + + if (delta_numChildrenWithCullingDisabled!=0) + { + setNumChildrenWithCullingDisabled( + getNumChildrenWithCullingDisabled()-1 + ); + } + return true; } else return false; diff --git a/src/osg/Node.cpp b/src/osg/Node.cpp index c65470c13..36258db1f 100644 --- a/src/osg/Node.cpp +++ b/src/osg/Node.cpp @@ -15,6 +15,10 @@ Node::Node() _nodeMask = 0xffffffff; _numChildrenRequiringAppTraversal = 0; + + _cullingActive = true; + _numChildrenWithCullingDisabled = 0; + } @@ -112,6 +116,81 @@ void Node::setNumChildrenRequiringAppTraversal(const int num) } +void Node::setCullingActive(const bool active) +{ + // if no changes just return. + if (_cullingActive == active) return; + + // culling active has been changed, will need to update + // both _cullActive and possibly the parents numChildrenWithCullingDisabled + // if culling disabled changes. + + // update the parents _numChildrenWithCullingDisabled + // note, if _numChildrenWithCullingDisabled!=0 then the + // parents won't be affected by any app callback change, + // so no need to inform them. + if (_numChildrenWithCullingDisabled==0 && !_parents.empty()) + { + int delta = 0; + if (!_cullingActive) --delta; + if (!active) ++delta; + if (delta!=0) + { + // the number of callbacks has changed, need to pass this + // on to parents so they know whether app traversal is + // reqired on this subgraph. + for(ParentList::iterator itr =_parents.begin(); + itr != _parents.end(); + ++itr) + { + (*itr)->setNumChildrenWithCullingDisabled( + (*itr)->getNumChildrenWithCullingDisabled()+delta ); + } + + } + } + + // set the cullingActive itself. + _cullingActive = active; +} + +void Node::setNumChildrenWithCullingDisabled(const int num) +{ + // if no changes just return. + if (_numChildrenWithCullingDisabled==num) return; + + // note, if _cullingActive is false then the + // parents won't be affected by any changes to + // _numChildrenWithCullingDisabled so no need to inform them. + if (_cullingActive && !_parents.empty()) + { + + // need to pass on changes to parents. + int delta = 0; + if (_numChildrenWithCullingDisabled>0) --delta; + if (num>0) ++delta; + if (delta!=0) + { + // the number of callbacks has changed, need to pass this + // on to parents so they know whether app traversal is + // reqired on this subgraph. + for(ParentList::iterator itr =_parents.begin(); + itr != _parents.end(); + ++itr) + { + (*itr)->setNumChildrenWithCullingDisabled( + (*itr)->getNumChildrenWithCullingDisabled()+delta + ); + } + + } + } + + // finally update this objects value. + _numChildrenWithCullingDisabled=num; +} + + const bool Node::computeBound() const { _bsphere.init(); diff --git a/src/osgPlugins/osg/Node.cpp b/src/osgPlugins/osg/Node.cpp index e8e832e8c..91491302e 100644 --- a/src/osgPlugins/osg/Node.cpp +++ b/src/osgPlugins/osg/Node.cpp @@ -34,6 +34,22 @@ bool Node_readLocalData(Object& obj, Input& fr) iteratorAdvanced = true; } + if (fr[0].matchWord("cullingActive")) + { + if (fr[1].matchWord("FALSE")) + { + node.setCullingActive(false); + iteratorAdvanced = true; + fr+=2; + } + else if (fr[1].matchWord("TRUE")) + { + node.setCullingActive(true); + iteratorAdvanced = true; + fr+=2; + } + } + // if (fr.matchSequence("user_data {")) // { // notify(DEBUG) << "Matched user_data {"<(_userData); diff --git a/src/osgUtil/CullVisitor.cpp b/src/osgUtil/CullVisitor.cpp index c99a7e75c..80138fada 100644 --- a/src/osgUtil/CullVisitor.cpp +++ b/src/osgUtil/CullVisitor.cpp @@ -367,7 +367,10 @@ CullViewState::CullingMode CullVisitor::getCullingMode() const void CullVisitor::apply(Node& node) { CullViewState::CullingMode mode = _cullingModeStack.back(); - if (isCulled(node.getBound(),mode)) return; + + if (!node.getCullingActive()) mode = 0; + else if (node.getNumChildrenWithCullingDisabled()==0 && + isCulled(node.getBound(),mode)) return; // push the culling mode. _cullingModeStack.push_back(mode); @@ -391,7 +394,10 @@ void CullVisitor::apply(Geode& node) // return if object's bounding sphere is culled. CullViewState::CullingMode mode = _cullingModeStack.back(); - if (isCulled(node.getBound(),mode)) return; + + if (!node.getCullingActive()) mode = 0; + else if (node.getNumChildrenWithCullingDisabled()==0 && + isCulled(node.getBound(),mode)) return; // push the node's state. StateSet* node_state = node.getStateSet(); @@ -465,7 +471,10 @@ void CullVisitor::apply(Billboard& node) { // return if object's bounding sphere is culled. CullViewState::CullingMode mode = _cullingModeStack.back(); - if (isCulled(node.getBound(),mode)) return; + + if (!node.getCullingActive()) mode = 0; + else if (node.getNumChildrenWithCullingDisabled()==0 && + isCulled(node.getBound(),mode)) return; // push the node's state. StateSet* node_state = node.getStateSet(); @@ -566,7 +575,10 @@ void CullVisitor::apply(Group& node) { // return if object's bounding sphere is culled. CullViewState::CullingMode mode = _cullingModeStack.back(); - if (isCulled(node.getBound(),mode)) return; + + if (!node.getCullingActive()) mode = 0; + else if (node.getNumChildrenWithCullingDisabled()==0 && + isCulled(node.getBound(),mode)) return; // push the culling mode. _cullingModeStack.push_back(mode); @@ -589,7 +601,10 @@ void CullVisitor::apply(Transform& node) { // return if object's bounding sphere is culled. CullViewState::CullingMode mode = _cullingModeStack.back(); - if (isCulled(node.getBound(),mode)) return; + + if (!node.getCullingActive()) mode = 0; + else if (node.getNumChildrenWithCullingDisabled()==0 && + isCulled(node.getBound(),mode)) return; // push the culling mode. _cullingModeStack.push_back(mode); @@ -622,7 +637,10 @@ void CullVisitor::apply(LOD& node) { // return if object's bounding sphere is culled. CullViewState::CullingMode mode = _cullingModeStack.back(); - if (isCulled(node.getBound(),mode)) return; + + if (!node.getCullingActive()) mode = 0; + else if (node.getNumChildrenWithCullingDisabled()==0 && + isCulled(node.getBound(),mode)) return; int eval = node.evaluate(getEyeLocal(),_LODBias); if (eval<0) return; @@ -667,7 +685,10 @@ void CullVisitor::apply(Impostor& node) // return if object's bounding sphere is culled. CullViewState::CullingMode mode = _cullingModeStack.back(); - if (isCulled(bs,mode)) return; + + if (!node.getCullingActive()) mode = 0; + else if (node.getNumChildrenWithCullingDisabled()==0 && + isCulled(node.getBound(),mode)) return; osg::Vec3 eyeLocal = getEyeLocal();