diff --git a/examples/osgviewerQt/osgviewerQt.cpp b/examples/osgviewerQt/osgviewerQt.cpp index 5e3917df9..ee30256a9 100644 --- a/examples/osgviewerQt/osgviewerQt.cpp +++ b/examples/osgviewerQt/osgviewerQt.cpp @@ -5,7 +5,7 @@ #include #include -#include +#include #include @@ -57,8 +57,8 @@ public: view->setSceneData( scene ); view->addEventHandler( new osgViewer::StatsHandler ); - view->setCameraManipulator( new osgGA::TrackballManipulator ); - + view->setCameraManipulator( new osgGA::MultiTouchTrackballManipulator ); + gw->setTouchEventsEnabled( true ); return gw->getGLWidget(); } diff --git a/include/osgGA/GUIEventAdapter b/include/osgGA/GUIEventAdapter index af5c3f353..8de2fea42 100644 --- a/include/osgGA/GUIEventAdapter +++ b/include/osgGA/GUIEventAdapter @@ -602,6 +602,9 @@ public: /// get mouse-Y orientation (mouse-Y increases upwards or downwards). MouseYOrientation getMouseYOrientation() const { return _mouseYOrientation; } + /// set mouse-Y orientation (mouse-Y increases upwards or downwards) and recompute variables + void setMouseYOrientationAndUpdateCoords(MouseYOrientation myo); + /// set current mouse button state. void setButtonMask(int mask) { _buttonMask = mask; } diff --git a/include/osgQt/GraphicsWindowQt b/include/osgQt/GraphicsWindowQt index b6adef265..30924675c 100644 --- a/include/osgQt/GraphicsWindowQt +++ b/include/osgQt/GraphicsWindowQt @@ -23,8 +23,10 @@ #include #include #include +#include class QInputEvent; +class QGestureEvent; namespace osgViewer { class ViewerBase; @@ -66,6 +68,9 @@ public: inline bool getForwardKeyEvents() const { return _forwardKeyEvents; } virtual void setForwardKeyEvents( bool f ) { _forwardKeyEvents = f; } + + inline bool getTouchEventsEnabled() const { return _touchEventsEnabled; } + void setTouchEventsEnabled( bool e ); void setKeyboardModifiers( QInputEvent* event ); @@ -76,6 +81,7 @@ public: virtual void mouseDoubleClickEvent( QMouseEvent* event ); virtual void mouseMoveEvent( QMouseEvent* event ); virtual void wheelEvent( QWheelEvent* event ); + virtual bool gestureEvent( QGestureEvent* event ); protected: @@ -109,6 +115,8 @@ protected: QQueue _deferredEventQueue; QSet _eventCompressor; + bool _touchEventsEnabled; + bool _forwardKeyEvents; qreal _devicePixelRatio; @@ -157,6 +165,9 @@ public: virtual std::string getWindowName(); virtual void useCursor( bool cursorOn ); virtual void setCursor( MouseCursor cursor ); + inline bool getTouchEventsEnabled() const { return _widget->getTouchEventsEnabled(); } + virtual void setTouchEventsEnabled( bool e ) { _widget->setTouchEventsEnabled(e); } + virtual bool valid() const; virtual bool realizeImplementation(); diff --git a/src/osgGA/GUIEventAdapter.cpp b/src/osgGA/GUIEventAdapter.cpp index 80c50d7fa..0f37689b3 100644 --- a/src/osgGA/GUIEventAdapter.cpp +++ b/src/osgGA/GUIEventAdapter.cpp @@ -132,3 +132,20 @@ void GUIEventAdapter::copyPointerDataFrom(const osgGA::GUIEventAdapter& sourceEv setMouseYOrientation(sourceEvent.getMouseYOrientation()); setPointerDataList(sourceEvent.getPointerDataList()); } + + + +void GUIEventAdapter::setMouseYOrientationAndUpdateCoords(osgGA::GUIEventAdapter::MouseYOrientation myo) +{ + if ( myo==_mouseYOrientation ) + return; + + setMouseYOrientation( myo ); + + _my = _Ymax - _my + _Ymin; + if( isMultiTouchEvent() ) + { + for( TouchData::iterator itr = getTouchData()->begin(); itr != getTouchData()->end(); itr++ ) + itr->y = _Ymax - itr->y + _Ymin; + } +} diff --git a/src/osgGA/MultiTouchTrackballManipulator.cpp b/src/osgGA/MultiTouchTrackballManipulator.cpp index 5d224008d..14e808536 100644 --- a/src/osgGA/MultiTouchTrackballManipulator.cpp +++ b/src/osgGA/MultiTouchTrackballManipulator.cpp @@ -37,29 +37,28 @@ MultiTouchTrackballManipulator::MultiTouchTrackballManipulator( const MultiTouch void MultiTouchTrackballManipulator::handleMultiTouchDrag(const GUIEventAdapter* now, const GUIEventAdapter* last, const double eventTimeDelta) { - osg::Vec2 pt_1_now(now->getTouchPointNormalizedX(0),now->getTouchPointNormalizedY(0)); - osg::Vec2 pt_2_now(now->getTouchPointNormalizedX(1),now->getTouchPointNormalizedY(1)); - osg::Vec2 pt_1_last(last->getTouchPointNormalizedX(0),last->getTouchPointNormalizedY(0)); - osg::Vec2 pt_2_last(last->getTouchPointNormalizedX(1),last->getTouchPointNormalizedY(1)); + const osg::Vec2 pt_1_now( now->getTouchData()->get(0).x, now->getTouchData()->get(0).y); + const osg::Vec2 pt_2_now( now->getTouchData()->get(1).x, now->getTouchData()->get(1).y); + const osg::Vec2 pt_1_last( last->getTouchData()->get(0).x, last->getTouchData()->get(0).y); + const osg::Vec2 pt_2_last( last->getTouchData()->get(1).x, last->getTouchData()->get(1).y); - - - float gap_now((pt_1_now - pt_2_now).length()); - float gap_last((pt_1_last - pt_2_last).length()); + const float gap_now((pt_1_now - pt_2_now).length()); + const float gap_last((pt_1_last - pt_2_last).length()); // osg::notify(osg::ALWAYS) << gap_now << " " << gap_last << std::endl; + const float relativeChange = (gap_last - gap_now)/gap_last; + // zoom gesture - if (fabs(gap_last - gap_now) > 0.02) - zoomModel( (gap_last - gap_now) , true ); + if (fabs(relativeChange) > 0.02) + zoomModel( relativeChange , true ); // drag gesture - osg::Vec2 delta = ((pt_1_last - pt_1_now) + (pt_2_last - pt_2_now)) / 2.0f; + const osg::Vec2 delta = ((pt_1_last - pt_1_now) + (pt_2_last - pt_2_now)) / 2.0f; - float scale = _distance / 3.0f; - - // osg::notify(osg::ALWAYS) << "drag: " << delta << " scale: " << scale << std::endl; + const float scale = -0.3f * _distance * getThrowScale( eventTimeDelta ); + //osg::notify(osg::ALWAYS) << "drag: " << delta << " scale: " << scale << std::endl; panModel( delta.x() * scale, delta.y() * scale); } diff --git a/src/osgQt/GraphicsWindowQt.cpp b/src/osgQt/GraphicsWindowQt.cpp index 55ba43a48..817f02e5b 100644 --- a/src/osgQt/GraphicsWindowQt.cpp +++ b/src/osgQt/GraphicsWindowQt.cpp @@ -11,12 +11,17 @@ * OpenSceneGraph Public License for more details. */ -#include - #include +#include #include #include +#if (QT_VERSION>=QT_VERSION_CHECK(4, 6, 0)) +# define USE_GESTURES +# include +# include +#endif + using namespace osgQt; @@ -136,7 +141,8 @@ static HeartBeat heartBeat; GLWidget::GLWidget( QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f, bool forwardKeyEvents ) : QGLWidget(parent, shareWidget, f), _gw( NULL ), -_forwardKeyEvents( forwardKeyEvents ) +_forwardKeyEvents( forwardKeyEvents ), +_touchEventsEnabled( false ) { _devicePixelRatio = GETDEVICEPIXELRATIO(); } @@ -145,7 +151,8 @@ GLWidget::GLWidget( QGLContext* context, QWidget* parent, const QGLWidget* share bool forwardKeyEvents ) : QGLWidget(context, parent, shareWidget, f), _gw( NULL ), -_forwardKeyEvents( forwardKeyEvents ) +_forwardKeyEvents( forwardKeyEvents ), +_touchEventsEnabled( false ) { _devicePixelRatio = GETDEVICEPIXELRATIO(); } @@ -154,7 +161,8 @@ GLWidget::GLWidget( const QGLFormat& format, QWidget* parent, const QGLWidget* s bool forwardKeyEvents ) : QGLWidget(format, parent, shareWidget, f), _gw( NULL ), -_forwardKeyEvents( forwardKeyEvents ) +_forwardKeyEvents( forwardKeyEvents ), +_touchEventsEnabled( false ) { _devicePixelRatio = GETDEVICEPIXELRATIO(); } @@ -170,6 +178,25 @@ GLWidget::~GLWidget() } } +void GLWidget::setTouchEventsEnabled(bool e) +{ +#ifdef USE_GESTURES + if (e==_touchEventsEnabled) + return; + + _touchEventsEnabled = e; + + if (_touchEventsEnabled) + { + grabGesture(Qt::PinchGesture); + } + else + { + ungrabGesture(Qt::PinchGesture); + } +#endif +} + void GLWidget::processDeferredEvents() { QQueue deferredEventQueueCopy; @@ -189,6 +216,10 @@ void GLWidget::processDeferredEvents() bool GLWidget::event( QEvent* event ) { +#ifdef USE_GESTURES + if ( event->type()==QEvent::Gesture ) + return gestureEvent(static_cast(event)); +#endif // QEvent::Hide // @@ -361,6 +392,85 @@ void GLWidget::wheelEvent( QWheelEvent* event ) (event->delta()>0 ? osgGA::GUIEventAdapter::SCROLL_LEFT : osgGA::GUIEventAdapter::SCROLL_RIGHT) ); } +#ifdef USE_GESTURES +static osgGA::GUIEventAdapter::TouchPhase translateQtGestureState( Qt::GestureState state ) +{ + osgGA::GUIEventAdapter::TouchPhase touchPhase; + switch ( state ) + { + case Qt::GestureStarted: + touchPhase = osgGA::GUIEventAdapter::TOUCH_BEGAN; + break; + case Qt::GestureUpdated: + touchPhase = osgGA::GUIEventAdapter::TOUCH_MOVED; + break; + case Qt::GestureFinished: + case Qt::GestureCanceled: + touchPhase = osgGA::GUIEventAdapter::TOUCH_ENDED; + break; + default: + touchPhase = osgGA::GUIEventAdapter::TOUCH_UNKNOWN; + }; + + return touchPhase; +} +#endif + + +bool GLWidget::gestureEvent( QGestureEvent* qevent ) +{ +#ifndef USE_GESTURES + return false; +#else + + bool accept = false; + + if ( QPinchGesture* pinch = static_cast(qevent->gesture(Qt::PinchGesture) ) ) + { + const QPointF qcenterf = pinch->centerPoint(); + const float angle = pinch->totalRotationAngle(); + const float scale = pinch->totalScaleFactor(); + + const QPoint pinchCenterQt = mapFromGlobal(qcenterf.toPoint()); + const osg::Vec2 pinchCenter( pinchCenterQt.x(), pinchCenterQt.y() ); + + //We don't have absolute positions of the two touches, only a scale and rotation + //Hence we create pseudo-coordinates which are reasonable, and centered around the + //real position + const float radius = (width()+height())/4; + const osg::Vec2 vector( scale*cos(angle)*radius, scale*sin(angle)*radius); + const osg::Vec2 p0 = pinchCenter+vector; + const osg::Vec2 p1 = pinchCenter-vector; + + osg::ref_ptr event = 0; + const osgGA::GUIEventAdapter::TouchPhase touchPhase = translateQtGestureState( pinch->state() ); + if ( touchPhase==osgGA::GUIEventAdapter::TOUCH_BEGAN ) + { + event = _gw->getEventQueue()->touchBegan(0 , touchPhase, p0[0], p0[1] ); + } + else if ( touchPhase==osgGA::GUIEventAdapter::TOUCH_MOVED ) + { + event = _gw->getEventQueue()->touchMoved( 0, touchPhase, p0[0], p0[1] ); + } + else + { + event = _gw->getEventQueue()->touchEnded( 0, touchPhase, p0[0], p0[1], 1 ); + } + + if ( event ) + { + event->addTouchPoint( 1, touchPhase, p1[0], p1[1] ); + accept = true; + } + } + + if ( accept ) + qevent->accept(); + + return accept; +#endif +} + GraphicsWindowQt::GraphicsWindowQt( osg::GraphicsContext::Traits* traits, QWidget* parent, const QGLWidget* shareWidget, Qt::WindowFlags f ) diff --git a/src/osgViewer/CompositeViewer.cpp b/src/osgViewer/CompositeViewer.cpp index 1afdcf9ed..5bb9eff22 100644 --- a/src/osgViewer/CompositeViewer.cpp +++ b/src/osgViewer/CompositeViewer.cpp @@ -1008,11 +1008,7 @@ void CompositeViewer::eventTraversal() event->setInputRange(pd->xMin, pd->yMin, pd->xMax, pd->yMax); event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); #else - if (event->getMouseYOrientation()!=osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS) - { - event->setY((event->getYmax()-event->getY())+event->getYmin()); - event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); - } + event->setMouseYOrientationAndUpdateCoords(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); #endif _previousEvent = event; diff --git a/src/osgViewer/Viewer.cpp b/src/osgViewer/Viewer.cpp index 3b86fcb51..3ab9f63b0 100644 --- a/src/osgViewer/Viewer.cpp +++ b/src/osgViewer/Viewer.cpp @@ -929,16 +929,7 @@ void Viewer::eventTraversal() event->setInputRange(pd->xMin, pd->yMin, pd->xMax, pd->yMax); event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); #else - if (event->getMouseYOrientation()!=osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS) - { - event->setY((event->getYmax()-event->getY())+event->getYmin()); - event->setMouseYOrientation(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); - if(event->isMultiTouchEvent()) { - for(osgGA::GUIEventAdapter::TouchData::iterator itr = event->getTouchData()->begin(); itr != event->getTouchData()->end(); itr++) { - itr->y = event->getYmax() - itr->y + event->getYmin(); - } - } - } + event->setMouseYOrientationAndUpdateCoords(osgGA::GUIEventAdapter::Y_INCREASING_UPWARDS); #endif eventState->copyPointerDataFrom(*event);