From 70e1c608191925403761e80799414c46a04d3720 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 3 Nov 2008 15:08:04 +0000 Subject: [PATCH] Added sendPointerEvent and sendKeyEvent virtual methods to osg::Image to facilitate the subclassing of Image providing interactive behaviours so as used in the vnc interactive VncImage class. osgViewer::InteractiveImageHandler provides an event handler that convertes osgGA mouse and keyboard events into the coordinate frame of an image based on ray intersection with geometry in the associated subgraph. Changed the ordering of events processing in Viewer and CompositeViewer to allow scene graph event handlers to take precidence over viewer event handlers and camera manipulators --- include/osg/Image | 8 +++ include/osgViewer/ViewerEventHandlers | 22 ++++++ src/osgViewer/CompositeViewer.cpp | 70 +++++++++++-------- src/osgViewer/Viewer.cpp | 47 +++++++------ src/osgViewer/ViewerEventHandlers.cpp | 99 +++++++++++++++++++++++++++ 5 files changed, 199 insertions(+), 47 deletions(-) diff --git a/include/osg/Image b/include/osg/Image index 46662f926..b6f3547a1 100644 --- a/include/osg/Image +++ b/include/osg/Image @@ -309,6 +309,14 @@ class OSG_EXPORT Image : public Object virtual void update(NodeVisitor* nv) {} + + /** method for sending pointer events to images that are acting as front ends to interactive surfaces such as a vnc or browser window.*/ + virtual void sendPointerEvent(int x, int y, int buttonMask) {}; + + /** method for sending key events to images that are acting as front ends to interactive surfaces such as a vnc or browser window.*/ + virtual void sendKeyEvent(int key, bool keyDown) {}; + + protected : virtual ~Image(); diff --git a/include/osgViewer/ViewerEventHandlers b/include/osgViewer/ViewerEventHandlers index fb31952e2..606d65cec 100644 --- a/include/osgViewer/ViewerEventHandlers +++ b/include/osgViewer/ViewerEventHandlers @@ -362,6 +362,28 @@ class OSGVIEWER_EXPORT ScreenCaptureHandler : public osgGA::GUIEventHandler void addCallbackToViewer(osgViewer::ViewerBase& viewer); }; +/** InteractiveImage is an event handler that computes the mouse coordinates in an images coordinate frame + * and then passes keyboard and mouse events to it. This event handler is useful for vnc or browser + * surfaces in the 3D scene.*/ +class OSGVIEWER_EXPORT InteractiveImageHandler : public osgGA::GUIEventHandler +{ +public: + + InteractiveImageHandler(osg::Image* image): + _image(image) {} + + virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa, osg::Object*, osg::NodeVisitor* nv); + +protected: + + virtual ~InteractiveImageHandler() {} + + bool mousePosition(osgViewer::View* view, osg::NodeVisitor* nv, const osgGA::GUIEventAdapter& ea, int& x, int &y) const; + + osg::observer_ptr _image; + +}; + } #endif diff --git a/src/osgViewer/CompositeViewer.cpp b/src/osgViewer/CompositeViewer.cpp index bcdc51d81..569b11f90 100644 --- a/src/osgViewer/CompositeViewer.cpp +++ b/src/osgViewer/CompositeViewer.cpp @@ -828,33 +828,6 @@ void CompositeViewer::eventTraversal() if (_done) return; - for(ViewEventsMap::iterator veitr = viewEventsMap.begin(); - veitr != viewEventsMap.end(); - ++veitr) - { - View* view = veitr->first; - _eventVisitor->setActionAdapter(view); - - for(osgGA::EventQueue::Events::iterator itr = veitr->second.begin(); - itr != veitr->second.end(); - ++itr) - { - osgGA::GUIEventAdapter* event = itr->get(); - - for(View::EventHandlers::iterator hitr = view->getEventHandlers().begin(); - hitr != view->getEventHandlers().end(); - ++hitr) - { - (*hitr)->handleWithCheckAgainstIgnoreHandledEventsMask( *event, *view, 0, 0); - } - - if (view->getCameraManipulator()) - { - view->getCameraManipulator()->handleWithCheckAgainstIgnoreHandledEventsMask( *event, *view); - } - } - } - if (_eventVisitor.valid()) { _eventVisitor->setFrameStamp(getFrameStamp()); @@ -898,6 +871,49 @@ void CompositeViewer::eventTraversal() } } + + for(ViewEventsMap::iterator veitr = viewEventsMap.begin(); + veitr != viewEventsMap.end(); + ++veitr) + { + View* view = veitr->first; + _eventVisitor->setActionAdapter(view); + + for(osgGA::EventQueue::Events::iterator itr = veitr->second.begin(); + itr != veitr->second.end(); + ++itr) + { + osgGA::GUIEventAdapter* event = itr->get(); + + for(View::EventHandlers::iterator hitr = view->getEventHandlers().begin(); + hitr != view->getEventHandlers().end(); + ++hitr) + { + (*hitr)->handleWithCheckAgainstIgnoreHandledEventsMask( *event, *view, 0, 0); + } + } + } + + for(ViewEventsMap::iterator veitr = viewEventsMap.begin(); + veitr != viewEventsMap.end(); + ++veitr) + { + View* view = veitr->first; + _eventVisitor->setActionAdapter(view); + + for(osgGA::EventQueue::Events::iterator itr = veitr->second.begin(); + itr != veitr->second.end(); + ++itr) + { + osgGA::GUIEventAdapter* event = itr->get(); + + if (view->getCameraManipulator()) + { + view->getCameraManipulator()->handleWithCheckAgainstIgnoreHandledEventsMask( *event, *view); + } + } + } + if (getStats() && getStats()->collectStats("event")) diff --git a/src/osgViewer/Viewer.cpp b/src/osgViewer/Viewer.cpp index f0179f5f7..30655250c 100644 --- a/src/osgViewer/Viewer.cpp +++ b/src/osgViewer/Viewer.cpp @@ -804,26 +804,6 @@ void Viewer::eventTraversal() if (_done) return; - for(osgGA::EventQueue::Events::iterator itr = events.begin(); - itr != events.end(); - ++itr) - { - osgGA::GUIEventAdapter* event = itr->get(); - - for(EventHandlers::iterator hitr = _eventHandlers.begin(); - hitr != _eventHandlers.end(); - ++hitr) - { - (*hitr)->handleWithCheckAgainstIgnoreHandledEventsMask( *event, *this, 0, 0); - } - - if (_cameraManipulator.valid()) - { - _cameraManipulator->handleWithCheckAgainstIgnoreHandledEventsMask( *event, *this); - } - - } - if (_eventVisitor.valid() && getSceneData()) { _eventVisitor->setFrameStamp(getFrameStamp()); @@ -858,6 +838,33 @@ void Viewer::eventTraversal() } } + + for(osgGA::EventQueue::Events::iterator itr = events.begin(); + itr != events.end(); + ++itr) + { + osgGA::GUIEventAdapter* event = itr->get(); + + for(EventHandlers::iterator hitr = _eventHandlers.begin(); + hitr != _eventHandlers.end(); + ++hitr) + { + (*hitr)->handleWithCheckAgainstIgnoreHandledEventsMask( *event, *this, 0, 0); + } + + } + + for(osgGA::EventQueue::Events::iterator itr = events.begin(); + itr != events.end(); + ++itr) + { + osgGA::GUIEventAdapter* event = itr->get(); + if (_cameraManipulator.valid()) + { + _cameraManipulator->handleWithCheckAgainstIgnoreHandledEventsMask( *event, *this); + } + } + if (getStats() && getStats()->collectStats("event")) { double endEventTraversal = osg::Timer::instance()->delta_s(_startTick, osg::Timer::instance()->tick()); diff --git a/src/osgViewer/ViewerEventHandlers.cpp b/src/osgViewer/ViewerEventHandlers.cpp index a3de7da79..46123ef8a 100644 --- a/src/osgViewer/ViewerEventHandlers.cpp +++ b/src/osgViewer/ViewerEventHandlers.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -602,4 +603,102 @@ void LODScaleHandler::getUsage(osg::ApplicationUsage& usage) const } +bool InteractiveImageHandler::mousePosition(osgViewer::View* view, osg::NodeVisitor* nv, const osgGA::GUIEventAdapter& ea, int& x, int &y) const +{ + osgUtil::LineSegmentIntersector::Intersections intersections; + bool foundIntersection = view==0 ? false : + (nv==0 ? view->computeIntersections(ea.getX(), ea.getY(), intersections) : + view->computeIntersections(ea.getX(), ea.getY(), nv->getNodePath(), intersections)); + + if (foundIntersection) + { + + osg::Vec2 tc(0.5f,0.5f); + + // use the nearest intersection + const osgUtil::LineSegmentIntersector::Intersection& intersection = *(intersections.begin()); + osg::Drawable* drawable = intersection.drawable.get(); + osg::Geometry* geometry = drawable ? drawable->asGeometry() : 0; + osg::Vec3Array* vertices = geometry ? dynamic_cast(geometry->getVertexArray()) : 0; + if (vertices) + { + // get the vertex indices. + const osgUtil::LineSegmentIntersector::Intersection::IndexList& indices = intersection.indexList; + const osgUtil::LineSegmentIntersector::Intersection::RatioList& ratios = intersection.ratioList; + + if (indices.size()==3 && ratios.size()==3) + { + unsigned int i1 = indices[0]; + unsigned int i2 = indices[1]; + unsigned int i3 = indices[2]; + + float r1 = ratios[0]; + float r2 = ratios[1]; + float r3 = ratios[2]; + + osg::Array* texcoords = (geometry->getNumTexCoordArrays()>0) ? geometry->getTexCoordArray(0) : 0; + osg::Vec2Array* texcoords_Vec2Array = dynamic_cast(texcoords); + if (texcoords_Vec2Array) + { + // we have tex coord array so now we can compute the final tex coord at the point of intersection. + osg::Vec2 tc1 = (*texcoords_Vec2Array)[i1]; + osg::Vec2 tc2 = (*texcoords_Vec2Array)[i2]; + osg::Vec2 tc3 = (*texcoords_Vec2Array)[i3]; + tc = tc1*r1 + tc2*r2 + tc3*r3; + } + } + + } + + x = int( float(_image->s()) * tc.x() ); + y = int( float(_image->t()) * tc.y() ); + + return true; + } + + return false; +} + + +bool InteractiveImageHandler::handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& aa, osg::Object*, osg::NodeVisitor* nv) +{ + if (ea.getHandled()) return false; + + switch(ea.getEventType()) + { + case(osgGA::GUIEventAdapter::MOVE): + case(osgGA::GUIEventAdapter::DRAG): + case(osgGA::GUIEventAdapter::PUSH): + case(osgGA::GUIEventAdapter::RELEASE): + { + osgViewer::View* view = dynamic_cast(&aa); + int x,y; + if (mousePosition(view, nv, ea, x, y)) + { + _image->sendPointerEvent(x, y, ea.getButtonMask()); + return true; + } + break; + } + case(osgGA::GUIEventAdapter::KEYDOWN): + case(osgGA::GUIEventAdapter::KEYUP): + { + osgViewer::View* view = dynamic_cast(&aa); + int x,y; + bool sendKeyEvent = mousePosition(view, nv, ea, x, y); + + if (sendKeyEvent) + { + _image->sendKeyEvent(ea.getKey(), ea.getEventType()==osgGA::GUIEventAdapter::KEYDOWN); + + return true; + } + } + + default: + return false; + } + return false; +} + }