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; +} + }