From b2786607999074cbdb33b0893cf31af9180b3562 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 2 Dec 2009 14:21:13 +0000 Subject: [PATCH] From Nico Kruithof, "Attached is a patch that makes the spherical manipulator frame rate independent. This is similar to what Lee did for the trackball manipulator a couple of months ago." --- include/osgGA/SphericalManipulator | 11 +++++++++++ src/osgGA/SphericalManipulator.cpp | 26 ++++++++++++++++++-------- 2 files changed, 29 insertions(+), 8 deletions(-) diff --git a/include/osgGA/SphericalManipulator b/include/osgGA/SphericalManipulator index a9e50abea..fc07c44d6 100644 --- a/include/osgGA/SphericalManipulator +++ b/include/osgGA/SphericalManipulator @@ -143,6 +143,17 @@ class OSGGA_EXPORT SphericalManipulator : public MatrixManipulator bool _thrown; bool _allowThrow; + /** The approximate amount of time it is currently taking to draw a frame. + * This is used to compute the delta in translation/rotation during a thrown display update. + * It allows us to match an delta in position/rotation independent of the rendering frame rate. + */ + double _delta_frame_time; + + /** The time the last frame started. + * Used when _rate_sensitive is true so that we can match display update rate to rotation/translation rate. + */ + double _last_frame_time; + RotationMode _rotationMode; osg::Vec3d _center; double _distance; diff --git a/src/osgGA/SphericalManipulator.cpp b/src/osgGA/SphericalManipulator.cpp index 96363f217..392b57f57 100644 --- a/src/osgGA/SphericalManipulator.cpp +++ b/src/osgGA/SphericalManipulator.cpp @@ -115,11 +115,18 @@ bool SphericalManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us switch(ea.getEventType()) { case(GUIEventAdapter::FRAME): - if (_thrown) { - if (calcMovement()) us.requestRedraw(); + double current_frame_time = ea.getTime(); + + _delta_frame_time = current_frame_time - _last_frame_time; + _last_frame_time = current_frame_time; + + if (_thrown) + { + if (calcMovement()) us.requestRedraw(); + } + return false; } - return false; default: break; } @@ -304,6 +311,9 @@ bool SphericalManipulator::calcMovement() buttonMask = _ga_t1->getButtonMask(); } + double throwScale = (_thrown && _ga_t0.valid() && _ga_t1.valid()) ? + _delta_frame_time / (_ga_t0->getTime() - _ga_t1->getTime()) : 1.0; + if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON) { // rotate camera. @@ -321,7 +331,7 @@ bool SphericalManipulator::calcMovement() float angle=atan2(py1-pyc,px1-pxc)-atan2(py0-pyc,px0-pxc); - _heading+=angle; + _heading+=throwScale*angle; if(_heading < -PI) _heading+=2*PI; else if(_heading > PI) @@ -331,7 +341,7 @@ bool SphericalManipulator::calcMovement() { if((_rotationMode != ELEVATION) && ((_ga_t1->getModKeyMask() & GUIEventAdapter::MODKEY_SHIFT) == 0)) { - _heading-=dx*PI_2; + _heading-=throwScale*dx*PI_2; if(_heading < 0) _heading+=2*PI; @@ -341,7 +351,7 @@ bool SphericalManipulator::calcMovement() if((_rotationMode != HEADING) && ((_ga_t1->getModKeyMask() & GUIEventAdapter::MODKEY_ALT) == 0)) { - _elevation-=dy*osg::PI_4; + _elevation-=throwScale*dy*osg::PI_4; // Only allows vertical rotation of 180deg if(_elevation < -osg::PI_2) @@ -363,7 +373,7 @@ bool SphericalManipulator::calcMovement() osg::Matrix rotation_matrix; rotation_matrix=osg::Matrixd::rotate(_elevation,-1,0,0)*osg::Matrixd::rotate(PI_2+_heading,0,0,1); - osg::Vec3 dv(dx*scale,0,dy*scale); + osg::Vec3 dv(throwScale*dx*scale,0,throwScale*dy*scale); _center += dv*rotation_matrix; return true; @@ -375,7 +385,7 @@ bool SphericalManipulator::calcMovement() // zoom model. double fd = _distance; - double scale = 1.0+dy; + double scale = 1.0+throwScale*dy; if(fd*scale > _modelScale*_minimumZoomScale) { _distance *= scale;