From 0f61af08bd1559b76c9efb6a8d3b5825a0a5d800 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 25 Feb 2005 14:02:48 +0000 Subject: [PATCH] Added support for new event visitor type into osgGA and osgProducer::Viewer, and event callback into Drawable. --- examples/osgstereoimage/osgstereoimage.cpp | 2 +- include/osg/Drawable | 23 ++++ include/osgGA/EventVisitor | 131 +++++++++++++++++++++ include/osgGA/GUIEventHandler | 12 +- include/osgProducer/Viewer | 13 ++ src/osg/Drawable.cpp | 21 ++++ src/osg/Geode.cpp | 31 ++++- src/osgGA/EventVisitor.cpp | 44 +++++++ src/osgGA/GNUmakefile | 1 + src/osgGA/GUIEventHandler.cpp | 31 +++++ src/osgProducer/Viewer.cpp | 20 +++- 11 files changed, 319 insertions(+), 10 deletions(-) create mode 100644 include/osgGA/EventVisitor create mode 100644 src/osgGA/EventVisitor.cpp diff --git a/examples/osgstereoimage/osgstereoimage.cpp b/examples/osgstereoimage/osgstereoimage.cpp index 42e4ad655..f4683ad1c 100644 --- a/examples/osgstereoimage/osgstereoimage.cpp +++ b/examples/osgstereoimage/osgstereoimage.cpp @@ -25,7 +25,7 @@ typedef std::vector FileList; -class SlideEventHandler : public osgGA::GUIEventHandler, public osg::NodeCallback +class SlideEventHandler : public osgGA::GUIEventHandler { public: diff --git a/include/osg/Drawable b/include/osg/Drawable index 80e8853c0..75ede503e 100644 --- a/include/osg/Drawable +++ b/include/osg/Drawable @@ -265,6 +265,28 @@ class SG_EXPORT Drawable : public Object const UpdateCallback* getUpdateCallback() const { return _updateCallback.get(); } + struct EventCallback : public virtual osg::Object + { + EventCallback() {} + + EventCallback(const EventCallback&,const CopyOp&) {} + + META_Object(osg,EventCallback); + + /** do customized Event code.*/ + virtual void event(osg::NodeVisitor*, osg::Drawable*) {} + }; + + /** Set the EventCallback which allows users to attach customize the updating of an object during the Event traversal.*/ + virtual void setEventCallback(EventCallback* ac); + + /** Get the non const EventCallback.*/ + EventCallback* getEventCallback() { return _eventCallback.get(); } + + /** Get the const EventCallback.*/ + const EventCallback* getEventCallback() const { return _eventCallback.get(); } + + struct CullCallback : public virtual osg::Object { CullCallback() {} @@ -697,6 +719,7 @@ class SG_EXPORT Drawable : public Object mutable GLObjectList _vboList; ref_ptr _updateCallback; + ref_ptr _eventCallback; ref_ptr _cullCallback; ref_ptr _drawCallback; }; diff --git a/include/osgGA/EventVisitor b/include/osgGA/EventVisitor new file mode 100644 index 000000000..bc6dbb928 --- /dev/null +++ b/include/osgGA/EventVisitor @@ -0,0 +1,131 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 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 OSGGA_EVENTVISITOR +#define OSGGA_EVENTVISITOR 1 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +namespace osgGA { + +/** + * Basic EventVisitor implementation for animating a scene. + * This visitor traverses the scene graph, calling each nodes appCallback if + * it exists. + */ +class OSGGA_EXPORT EventVisitor : public osg::NodeVisitor +{ + public: + + EventVisitor(); + virtual ~EventVisitor(); + + + void setActionAdapter(osgGA::GUIActionAdapter* actionAdapter) { _actionAdapter=actionAdapter; } + + osgGA::GUIActionAdapter* getActionAdapter() { return _actionAdapter; } + + const osgGA::GUIActionAdapter* getActionAdapter() const { return _actionAdapter; } + + + typedef std::list< osg::ref_ptr > EventList; + + void setEventList(const EventList& events) { _events = events; } + + EventList& getEventList() { return _events; } + + const EventList& getEventList() const { return _events; } + + void addEvent(GUIEventAdapter* event); + + void removeEvent(GUIEventAdapter* event); + + + virtual void reset(); + + /** During traversal each type of node calls its callbacks and its children traversed. */ + virtual void apply(osg::Node& 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); } + virtual void apply(osg::Transform& node) { handle_callbacks_and_traverse(node); } + virtual void apply(osg::Projection& node) { handle_callbacks_and_traverse(node); } + virtual void apply(osg::Switch& node) { handle_callbacks_and_traverse(node); } + virtual void apply(osg::LOD& node) { handle_callbacks_and_traverse(node); } + virtual void apply(osg::Impostor& node) { handle_callbacks_and_traverse(node); } + virtual void apply(osg::OccluderNode& node) { handle_callbacks_and_traverse(node); } + + + protected: + +// /** Prevent unwanted copy construction.*/ +// EventVisitor(const EventVisitor&):osg::NodeVisitor() {} + + /** Prevent unwanted copy operator.*/ + EventVisitor& operator = (const EventVisitor&) { return *this; } + + inline void handle_callbacks_and_traverse(osg::Node& node) + { + osg::NodeCallback* callback = node.getEventCallback(); + if (callback) (*callback)(&node,this); + else if (node.getNumChildrenRequiringEventTraversal()>0) traverse(node); + } + + inline void handle_geode_callbacks(osg::Geode& node) + { + osg::NodeCallback* callback = node.getEventCallback(); + if (callback) (*callback)(&node,this); + /*else if (node.getNumChildrenRequiringEventTraversal()>0)*/ + traverseGeode(node); + } + + inline void traverseGeode(osg::Geode& geode) + { + traverse((osg::Node&)geode); + + // Call the app callbacks on the drawables. + for(unsigned int i=0;igetEventCallback(); + if (callback) callback->event(this,geode.getDrawable(i)); + } + } + + osgGA::GUIActionAdapter* _actionAdapter; + EventList _events; + +}; + +} + +#endif + diff --git a/include/osgGA/GUIEventHandler b/include/osgGA/GUIEventHandler index aa6ebaa7b..12958e4c0 100644 --- a/include/osgGA/GUIEventHandler +++ b/include/osgGA/GUIEventHandler @@ -16,8 +16,8 @@ #include -#include -#include +#include +#include #include #include @@ -49,7 +49,7 @@ This request is made via the GUIActionAdapter class. */ -class OSGGA_EXPORT GUIEventHandler : public virtual osg::Object +class OSGGA_EXPORT GUIEventHandler : public osg::NodeCallback, public osg::Drawable::EventCallback { public: @@ -58,6 +58,12 @@ public: META_Object(osgGA,GUIEventHandler); + /** Event traversal node callback method.*/ + virtual void operator()(osg::Node* node, osg::NodeVisitor* nv); + + /** Event traversal drawable callback method.*/ + virtual void event(osg::NodeVisitor* nv, osg::Drawable* drawable); + /** Returns 0 if this GUIEventHandler is not a CompositeGUIEventHandler. */ virtual const CompositeGUIEventHandler* getComposite() const { return 0; } diff --git a/include/osgProducer/Viewer b/include/osgProducer/Viewer index ff807ec69..f70d81139 100644 --- a/include/osgProducer/Viewer +++ b/include/osgProducer/Viewer @@ -24,6 +24,7 @@ #include #include +#include #include #include @@ -205,6 +206,17 @@ class OSGPRODUCER_EXPORT Viewer : public OsgCameraGroup, public osgGA::GUIAction /** Get the const update visitor.*/ const osg::NodeVisitor* getUpdateVisitor() const { return _updateVisitor.get(); } + + /** Set the update visitor which does the event traversal of the scene graph. Automatically called by the update() method.*/ + void setEventVisitor(osgGA::EventVisitor* nv) { _eventVisitor = nv; } + + /** Get the update visitor.*/ + osgGA::EventVisitor* getEventVisitor() { return _eventVisitor.get(); } + + /** Get the const update visitor.*/ + const osgGA::EventVisitor* getEventVisitor() const { return _eventVisitor.get(); } + + void computeActiveCoordindateSystemNodePath(); void setCoordindateSystemNodePath(const osg::RefNodePath& nodePath) { _coordinateSystemNodePath = nodePath; } @@ -299,6 +311,7 @@ class OSGPRODUCER_EXPORT Viewer : public OsgCameraGroup, public osgGA::GUIAction osg::ref_ptr _keyswitchManipulator; osg::ref_ptr _updateVisitor; + osg::ref_ptr _eventVisitor; osg::RefNodePath _coordinateSystemNodePath; diff --git a/src/osg/Drawable.cpp b/src/osg/Drawable.cpp index 16503751f..76d5668a8 100644 --- a/src/osg/Drawable.cpp +++ b/src/osg/Drawable.cpp @@ -497,6 +497,27 @@ void Drawable::setUpdateCallback(UpdateCallback* ac) } } +void Drawable::setEventCallback(EventCallback* ac) +{ + if (_eventCallback==ac) return; + + int delta = 0; + if (_eventCallback.valid()) --delta; + if (ac) ++delta; + + _eventCallback = ac; + + if (delta!=0) + { + for(ParentList::iterator itr=_parents.begin(); + itr!=_parents.end(); + ++itr) + { + (*itr)->setNumChildrenRequiringEventTraversal((*itr)->getNumChildrenRequiringEventTraversal()+delta); + } + } +} + struct ComputeBound : public PrimitiveFunctor { ComputeBound():_vertices(0) {} diff --git a/src/osg/Geode.cpp b/src/osg/Geode.cpp index ab6db1935..13c253399 100644 --- a/src/osg/Geode.cpp +++ b/src/osg/Geode.cpp @@ -62,6 +62,11 @@ bool Geode::addDrawable( Drawable *drawable ) setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()+1); } + if (drawable->getEventCallback()) + { + setNumChildrenRequiringEventTraversal(getNumChildrenRequiringEventTraversal()+1); + } + dirtyBound(); return true; @@ -88,12 +93,14 @@ bool Geode::removeDrawable(unsigned int pos,unsigned int numDrawablesToRemove) } unsigned int updateCallbackRemoved = 0; + unsigned int eventCallbackRemoved = 0; for(unsigned i=pos;iremoveParent(this); // update the number of app calbacks removed if (_drawables[i]->getUpdateCallback()) ++updateCallbackRemoved; + if (_drawables[i]->getEventCallback()) ++eventCallbackRemoved; } _drawables.erase(_drawables.begin()+pos,_drawables.begin()+endOfRemoveRange); @@ -103,6 +110,11 @@ bool Geode::removeDrawable(unsigned int pos,unsigned int numDrawablesToRemove) setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()-updateCallbackRemoved); } + if (eventCallbackRemoved) + { + setNumChildrenRequiringEventTraversal(getNumChildrenRequiringEventTraversal()-eventCallbackRemoved); + } + dirtyBound(); return true; @@ -129,14 +141,23 @@ bool Geode::setDrawable( unsigned int i, Drawable* newDrawable ) Drawable* origDrawable = _drawables[i].get(); - int delta = 0; - if (origDrawable->getUpdateCallback()) --delta; - if (newDrawable->getUpdateCallback()) ++delta; - if (delta!=0) + int deltaUpdate = 0; + if (origDrawable->getUpdateCallback()) --deltaUpdate; + if (newDrawable->getUpdateCallback()) ++deltaUpdate; + if (deltaUpdate!=0) { - setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()+delta); + setNumChildrenRequiringUpdateTraversal(getNumChildrenRequiringUpdateTraversal()+deltaUpdate); } + int deltaEvent = 0; + if (origDrawable->getEventCallback()) --deltaEvent; + if (newDrawable->getEventCallback()) ++deltaEvent; + if (deltaEvent!=0) + { + setNumChildrenRequiringEventTraversal(getNumChildrenRequiringEventTraversal()+deltaEvent); + } + + // remove from origDrawable's parent list. origDrawable->removeParent(this); diff --git a/src/osgGA/EventVisitor.cpp b/src/osgGA/EventVisitor.cpp new file mode 100644 index 000000000..940e0095f --- /dev/null +++ b/src/osgGA/EventVisitor.cpp @@ -0,0 +1,44 @@ +/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 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. +*/ +#include + +#include + +using namespace osg; +using namespace osgGA; + +EventVisitor::EventVisitor():NodeVisitor(UPDATE_VISITOR,TRAVERSE_ALL_CHILDREN) +{ +} + + +EventVisitor::~EventVisitor() +{ +} + +void EventVisitor::addEvent(GUIEventAdapter* event) +{ + _events.push_back(event); +} + +void EventVisitor::removeEvent(GUIEventAdapter* event) +{ + EventList::iterator itr = std::find(_events.begin(),_events.end(),event); + if (itr!=_events.end()) _events.erase(itr); +} + + +void EventVisitor::reset() +{ + _events.clear(); +} diff --git a/src/osgGA/GNUmakefile b/src/osgGA/GNUmakefile index 5e29a5787..beafb537f 100644 --- a/src/osgGA/GNUmakefile +++ b/src/osgGA/GNUmakefile @@ -6,6 +6,7 @@ CXXFILES = \ AnimationPathManipulator.cpp\ MatrixManipulator.cpp\ DriveManipulator.cpp\ + EventVisitor.cpp\ FlightManipulator.cpp\ GUIEventAdapter.cpp\ GUIEventHandler.cpp\ diff --git a/src/osgGA/GUIEventHandler.cpp b/src/osgGA/GUIEventHandler.cpp index 9df41adae..1d2475e64 100644 --- a/src/osgGA/GUIEventHandler.cpp +++ b/src/osgGA/GUIEventHandler.cpp @@ -12,9 +12,40 @@ */ #include +#include using namespace osgGA; + +void GUIEventHandler::operator()(osg::Node* node, osg::NodeVisitor* nv) +{ + osgGA::EventVisitor* ev = dynamic_cast(nv); + if (ev && ev->getActionAdapter() && !ev->getEventList().empty()) + { + for(osgGA::EventVisitor::EventList::iterator itr = ev->getEventList().begin(); + itr != ev->getEventList().end(); + ++itr) + { + handle(*(*itr), *(ev->getActionAdapter())); + } + } + traverse(node,nv); +} + +void GUIEventHandler::event(osg::NodeVisitor* nv, osg::Drawable* /*drawable*/) +{ + osgGA::EventVisitor* ev = dynamic_cast(nv); + if (ev && ev->getActionAdapter() && !ev->getEventList().empty()) + { + for(osgGA::EventVisitor::EventList::iterator itr = ev->getEventList().begin(); + itr != ev->getEventList().end(); + ++itr) + { + handle(*(*itr), *(ev->getActionAdapter())); + } + } +} + void CompositeGUIEventHandler::getUsage(osg::ApplicationUsage& usage) const { for (ChildList::const_iterator itr=_children.begin(); diff --git a/src/osgProducer/Viewer.cpp b/src/osgProducer/Viewer.cpp index 8a4be8c0f..3d6310cfb 100644 --- a/src/osgProducer/Viewer.cpp +++ b/src/osgProducer/Viewer.cpp @@ -5,6 +5,7 @@ #include +#include #include #include #include @@ -482,6 +483,10 @@ void Viewer::setUpViewer(unsigned int options) _updateVisitor->setFrameStamp(_frameStamp.get()); + if (!_eventVisitor) _eventVisitor = new osgGA::EventVisitor; + _eventVisitor->setActionAdapter(this); + + if (options&TRACKBALL_MANIPULATOR) addCameraManipulator(new osgGA::TrackballManipulator); if (options&FLIGHT_MANIPULATOR) addCameraManipulator(new osgGA::FlightManipulator); if (options&DRIVE_MANIPULATOR) addCameraManipulator(new osgGA::DriveManipulator); @@ -632,6 +637,11 @@ void Viewer::update() frame_event->adaptFrame(_frameStamp->getReferenceTime()); queue.push_back(frame_event); + if (_eventVisitor.valid()) + { + _eventVisitor->setTraversalNumber(_frameStamp->getFrameNumber()); + } + // dispatch the events in order of arrival. for(osgProducer::KeyboardMouseCallback::EventQueue::iterator event_itr=queue.begin(); event_itr!=queue.end(); @@ -644,8 +654,15 @@ void Viewer::update() { handled = (*handler_itr)->handle(*(*event_itr),*this); } + if (!handled && _eventVisitor.valid()) + { + _eventVisitor->reset(); + _eventVisitor->addEvent(event_itr->get()); + getTopMostSceneData()->accept(*_eventVisitor); + } + } - + if (osgDB::Registry::instance()->getDatabasePager()) { // update the scene graph by remove expired subgraphs and merge newly loaded subgraphs @@ -661,6 +678,7 @@ void Viewer::update() getTopMostSceneData()->accept(*_updateVisitor); } + // update the main producer camera if (_keyswitchManipulator.valid() && _keyswitchManipulator->getCurrentMatrixManipulator()) {