diff --git a/include/osg/Drawable b/include/osg/Drawable index 6a55e8113..a9b1a470f 100644 --- a/include/osg/Drawable +++ b/include/osg/Drawable @@ -161,6 +161,38 @@ class SG_EXPORT Drawable : public Object void compile(State& state); + struct AppCallback : public osg::Referenced + { + /** do customized app code.*/ + virtual void app(osg::NodeVisitor *visitor, osg::Drawable* drawable) const = 0; + }; + + /** Set the AppCallback which allows users to attach customize the undating of an object during the app traversal.*/ + void setAppCallback(AppCallback* ac); + + /** Get the non const AppCallback.*/ + AppCallback* getAppCallback() { return _appCallback.get(); } + + /** Get the const AppCallback.*/ + const AppCallback* getAppCallback() const { return _appCallback.get(); } + + + struct CullCallback : public osg::Referenced + { + /** do customized cull code.*/ + virtual bool cull(osg::NodeVisitor *visitor, osg::Drawable* drawable, osg::State *state=NULL) const = 0; + }; + + /** Set the CullCallback which allows users to attach customize the culling of Drawable during the cull traversal.*/ + void setCullCallback(CullCallback* cc) { _cullCallback=cc; } + + /** Get the non const CullCallback.*/ + CullCallback* getCullCallback() { return _cullCallback.get(); } + + /** Get the const CullCallback.*/ + const CullCallback* getCullCallback() const { return _cullCallback.get(); } + + /** Callback attached to an Drawable which allows the users to customize the drawing of an exist Drawable object. * The draw callback is implement as a replacement to the Drawable's own drawImmediateMode() method, if the * the user intends to decorate the exist draw code then simple call the drawable->drawImmediateMode() from @@ -181,21 +213,6 @@ class SG_EXPORT Drawable : public Object /** Get the const DrawCallback.*/ const DrawCallback* getDrawCallback() const { return _drawCallback.get(); } - struct CullCallback : public osg::Referenced - { - /** do customized cull code.*/ - virtual bool cull(osg::NodeVisitor *visitor, osg::Drawable* drawable, osg::State *state=NULL) const = 0; - }; - - /** Set the CullCallback which allows users to attach customize the drawing of existing Drawable object.*/ - void setCullCallback(CullCallback* cc) { _cullCallback=cc; } - - /** Get the non const CullCallback.*/ - CullCallback* getCullCallback() { return _cullCallback.get(); } - - /** Get the const CullCallback.*/ - const CullCallback* getCullCallback() const { return _cullCallback.get(); } - /** draw directly ignoring an OpenGL display list which could be attached. * This is the internal draw method which does the drawing itself, @@ -310,6 +327,7 @@ class SG_EXPORT Drawable : public Object mutable BoundingBox _bbox; mutable bool _bbox_computed; + ref_ptr _appCallback; ref_ptr _drawCallback; ref_ptr _cullCallback; diff --git a/include/osg/Node b/include/osg/Node index 643f711fc..881aa482c 100644 --- a/include/osg/Node +++ b/include/osg/Node @@ -243,6 +243,7 @@ class SG_EXPORT Node : public Object ParentList _parents; friend class osg::Group; + friend class osg::Drawable; ref_ptr _appCallback; int _numChildrenRequiringAppTraversal; diff --git a/include/osgUtil/AppVisitor b/include/osgUtil/AppVisitor index a26b025a8..8edcea808 100644 --- a/include/osgUtil/AppVisitor +++ b/include/osgUtil/AppVisitor @@ -37,8 +37,9 @@ class OSGUTIL_EXPORT AppVisitor : public osg::NodeVisitor virtual void apply(osg::Node& node) { handle_callbacks_and_traverse(node); } - virtual void apply(osg::Geode& node) { handle_callbacks_and_traverse(node); } - virtual void apply(osg::Billboard& node) { handle_callbacks_and_traverse(node); } + virtual void apply(osg::Geode& node) { handle_geode_callbacks(node); } + virtual void apply(osg::Billboard& node) { handle_geode_callbacks(node); } + virtual void apply(osg::LightSource& node) { handle_callbacks_and_traverse(node); } virtual void apply(osg::Group& node) { handle_callbacks_and_traverse(node); } @@ -65,6 +66,20 @@ class OSGUTIL_EXPORT AppVisitor : public osg::NodeVisitor else if (node.getNumChildrenRequiringAppTraversal()>0) traverse(node); } + inline void handle_geode_callbacks(osg::Geode& node) + { + osg::NodeCallback* callback = node.getAppCallback(); + if (callback) (*callback)(&node,this); + else if (node.getNumChildrenRequiringAppTraversal()>0) traverse(node); + + // call the app callbacks on the drawables. + for(int i=0;igetAppCallback(); + if (callback) callback->app(this,node.getDrawable(i)); + } + + } }; diff --git a/src/osg/Drawable.cpp b/src/osg/Drawable.cpp index e8f80703f..050036361 100644 --- a/src/osg/Drawable.cpp +++ b/src/osg/Drawable.cpp @@ -206,3 +206,22 @@ void Drawable::flushDeletedDisplayLists(uint contextID) s_deletedDisplayListCache.erase(citr); } } + +void Drawable::setAppCallback(AppCallback* ac) +{ + if (_appCallback==ac) return; + + int delta = 0; + if (_appCallback.valid()) --delta; + if (ac) ++delta; + + if (delta!=0) + { + for(ParentList::iterator itr=_parents.begin(); + itr!=_parents.end(); + ++itr) + { + (*itr)->setNumChildrenRequiringAppTraversal((*itr)->getNumChildrenRequiringAppTraversal()+delta); + } + } +} diff --git a/src/osg/Geode.cpp b/src/osg/Geode.cpp index 6ebd557e5..b246df6e6 100644 --- a/src/osg/Geode.cpp +++ b/src/osg/Geode.cpp @@ -43,6 +43,11 @@ const bool Geode::addDrawable( Drawable *drawable ) // register as parent of drawable. drawable->addParent(this); + if (drawable->getAppCallback()) + { + setNumChildrenRequiringAppTraversal(getNumChildrenRequiringAppTraversal()+1); + } + dirtyBound(); return true; @@ -59,6 +64,11 @@ const bool Geode::removeDrawable( Drawable *drawable ) // remove this Geode from the child parent list. drawable->removeParent(this); + if (drawable->getAppCallback()) + { + setNumChildrenRequiringAppTraversal(getNumChildrenRequiringAppTraversal()-1); + } + // note ref_ptr<> automatically handles decrementing drawable's reference count. _drawables.erase(itr); @@ -77,7 +87,14 @@ const bool Geode::replaceDrawable( Drawable *origDrawable, Drawable *newDrawable DrawableList::iterator itr = findDrawable(origDrawable); if (itr!=_drawables.end()) { - + int delta = 0; + if (origDrawable->getAppCallback()) --delta; + if (newDrawable->getAppCallback()) ++delta; + if (delta!=0) + { + setNumChildrenRequiringAppTraversal(getNumChildrenRequiringAppTraversal()+delta); + } + // remove from origDrawable's parent list. origDrawable->removeParent(this); @@ -88,6 +105,7 @@ const bool Geode::replaceDrawable( Drawable *origDrawable, Drawable *newDrawable // register as parent of child. newDrawable->addParent(this); + dirtyBound(); return true;