From Jan Perciva with changes from Robert Osfield, "I am submitting improved osgGA camera manipulators.
Changes: - new mouse wheel zoom/movement/center functionality - ability to fix vertical axis (important for CAD) - possibility to specify values as absolute values or relative to model size - kind of backward compatibility by flags passed to constructor - and much more - restructuring classes to use kind of hierarchy and standard way of event processing (handle methods). This way, there is much more code reusability and it is more easy to develop new kinds of manipulators. Briefly, the new architecture keeps MatrixManipulator as base abstract class. StandardManipulator is the feature-rich standard manipulator with two main descendant classes: OrbitManipulator and FirstPersonManipulator. OrbitManipulator is base class for all trackball style manipulators, based on center, rotation and distance from center. FirstPersonManipulator is base for walk or fly style manipulators, using position and rotation for camera manipulation. " Changes by Robert: Replaced osg::Vec3 by osg::Vec3d, introduced DEFAULT_SETTINGS enum and usage. Added frame time member variables in prep for improving throw animation when vysync is off.
This commit is contained in:
@@ -1,241 +1,145 @@
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
|
||||
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 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
|
||||
* 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
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* OpenSceneGraph Public License for more details.
|
||||
*/
|
||||
|
||||
#include <osgGA/FlightManipulator>
|
||||
#include <osg/Notify>
|
||||
|
||||
using namespace osg;
|
||||
using namespace osgGA;
|
||||
|
||||
FlightManipulator::FlightManipulator()
|
||||
{
|
||||
_modelScale = 0.01f;
|
||||
_acceleration = 100.0f;
|
||||
_velocity = 0.0f;
|
||||
_yawMode = YAW_AUTOMATICALLY_WHEN_BANKED;
|
||||
|
||||
_distance = 1.0f;
|
||||
}
|
||||
|
||||
|
||||
FlightManipulator::~FlightManipulator()
|
||||
/// Constructor.
|
||||
FlightManipulator::FlightManipulator( int flags )
|
||||
: inherited( flags ),
|
||||
_yawMode( YAW_AUTOMATICALLY_WHEN_BANKED )
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void FlightManipulator::setNode(osg::Node* node)
|
||||
/// Constructor.
|
||||
FlightManipulator::FlightManipulator( const FlightManipulator& fm, const CopyOp& copyOp )
|
||||
: inherited( fm, copyOp ),
|
||||
_yawMode( fm._yawMode )
|
||||
{
|
||||
_node = node;
|
||||
if (_node.get())
|
||||
{
|
||||
const osg::BoundingSphere& boundingSphere=_node->getBound();
|
||||
_modelScale = boundingSphere._radius;
|
||||
}
|
||||
|
||||
if (getAutoComputeHomePosition()) computeHomePosition();
|
||||
}
|
||||
|
||||
|
||||
const osg::Node* FlightManipulator::getNode() const
|
||||
void FlightManipulator::init( const GUIEventAdapter& ea, GUIActionAdapter& us )
|
||||
{
|
||||
return _node.get();
|
||||
inherited::init( ea, us );
|
||||
|
||||
// center mouse pointer
|
||||
centerMousePointer( ea, us );
|
||||
}
|
||||
|
||||
|
||||
|
||||
osg::Node* FlightManipulator::getNode()
|
||||
void FlightManipulator::home( const GUIEventAdapter& ea, GUIActionAdapter& us )
|
||||
{
|
||||
return _node.get();
|
||||
}
|
||||
inherited::home( ea, us );
|
||||
|
||||
void FlightManipulator::home(const GUIEventAdapter& ea,GUIActionAdapter& us)
|
||||
{
|
||||
if (getAutoComputeHomePosition()) computeHomePosition();
|
||||
|
||||
computePosition(_homeEye, _homeCenter, _homeUp);
|
||||
|
||||
_velocity = 0.0;
|
||||
|
||||
us.requestRedraw();
|
||||
us.requestContinuousUpdate(false);
|
||||
us.requestWarpPointer((ea.getXmin()+ea.getXmax())/2.0f,(ea.getYmin()+ea.getYmax())/2.0f);
|
||||
|
||||
flushMouseEventStack();
|
||||
// center mouse pointer
|
||||
centerMousePointer( ea, us );
|
||||
}
|
||||
|
||||
|
||||
void FlightManipulator::init(const GUIEventAdapter& ea,GUIActionAdapter& us)
|
||||
// doc in parent
|
||||
bool FlightManipulator::handleFrame( const GUIEventAdapter& ea, GUIActionAdapter& us )
|
||||
{
|
||||
flushMouseEventStack();
|
||||
addMouseEvent( ea );
|
||||
if( performMovement() )
|
||||
us.requestRedraw();
|
||||
|
||||
us.requestContinuousUpdate(false);
|
||||
|
||||
_velocity = 0.0f;
|
||||
|
||||
if (ea.getEventType()!=GUIEventAdapter::RESIZE)
|
||||
{
|
||||
us.requestWarpPointer((ea.getXmin()+ea.getXmax())/2.0f,(ea.getYmin()+ea.getYmax())/2.0f);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool FlightManipulator::handle(const GUIEventAdapter& ea,GUIActionAdapter& us)
|
||||
// doc in parent
|
||||
bool FlightManipulator::handleMouseMove( const GUIEventAdapter& ea, GUIActionAdapter& us )
|
||||
{
|
||||
switch(ea.getEventType())
|
||||
{
|
||||
case(GUIEventAdapter::FRAME):
|
||||
addMouseEvent(ea);
|
||||
if (calcMovement()) us.requestRedraw();
|
||||
return false;
|
||||
|
||||
case(GUIEventAdapter::RESIZE):
|
||||
init(ea,us);
|
||||
us.requestRedraw();
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (ea.getHandled()) return false;
|
||||
|
||||
switch(ea.getEventType())
|
||||
{
|
||||
case(GUIEventAdapter::PUSH):
|
||||
{
|
||||
|
||||
addMouseEvent(ea);
|
||||
us.requestContinuousUpdate(true);
|
||||
if (calcMovement()) us.requestRedraw();
|
||||
return true;
|
||||
}
|
||||
|
||||
case(GUIEventAdapter::RELEASE):
|
||||
{
|
||||
|
||||
addMouseEvent(ea);
|
||||
us.requestContinuousUpdate(true);
|
||||
if (calcMovement()) us.requestRedraw();
|
||||
return true;
|
||||
}
|
||||
|
||||
case(GUIEventAdapter::DRAG):
|
||||
{
|
||||
|
||||
addMouseEvent(ea);
|
||||
us.requestContinuousUpdate(true);
|
||||
if (calcMovement()) us.requestRedraw();
|
||||
return true;
|
||||
}
|
||||
|
||||
case(GUIEventAdapter::MOVE):
|
||||
{
|
||||
|
||||
addMouseEvent(ea);
|
||||
us.requestContinuousUpdate(true);
|
||||
if (calcMovement()) us.requestRedraw();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
case(GUIEventAdapter::KEYDOWN):
|
||||
{
|
||||
if (ea.getKey()==GUIEventAdapter::KEY_Space)
|
||||
{
|
||||
flushMouseEventStack();
|
||||
home(ea,us);
|
||||
us.requestRedraw();
|
||||
us.requestContinuousUpdate(false);
|
||||
return true;
|
||||
}
|
||||
else if (ea.getKey()=='q')
|
||||
{
|
||||
_yawMode = YAW_AUTOMATICALLY_WHEN_BANKED;
|
||||
return true;
|
||||
}
|
||||
else if (ea.getKey()=='a')
|
||||
{
|
||||
_yawMode = NO_AUTOMATIC_YAW;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void FlightManipulator::getUsage(osg::ApplicationUsage& usage) const
|
||||
{
|
||||
usage.addKeyboardMouseBinding("Flight: Space","Reset the viewing position to home");
|
||||
usage.addKeyboardMouseBinding("Flight: q","Automatically yaw when banked (default)");
|
||||
usage.addKeyboardMouseBinding("Flight: a","No yaw when banked");
|
||||
}
|
||||
|
||||
void FlightManipulator::flushMouseEventStack()
|
||||
{
|
||||
_ga_t1 = NULL;
|
||||
_ga_t0 = NULL;
|
||||
return flightHandleEvent( ea, us );
|
||||
}
|
||||
|
||||
|
||||
void FlightManipulator::addMouseEvent(const GUIEventAdapter& ea)
|
||||
// doc in parent
|
||||
bool FlightManipulator::handleMouseDrag( const GUIEventAdapter& ea, GUIActionAdapter& us )
|
||||
{
|
||||
_ga_t1 = _ga_t0;
|
||||
_ga_t0 = &ea;
|
||||
return flightHandleEvent( ea, us );
|
||||
}
|
||||
|
||||
|
||||
void FlightManipulator::setByMatrix(const osg::Matrixd& matrix)
|
||||
// doc in parent
|
||||
bool FlightManipulator::handleMousePush( const GUIEventAdapter& ea, GUIActionAdapter& us )
|
||||
{
|
||||
_eye = matrix.getTrans();
|
||||
_rotation = matrix.getRotate();
|
||||
_distance = 1.0f;
|
||||
}
|
||||
|
||||
osg::Matrixd FlightManipulator::getMatrix() const
|
||||
{
|
||||
return osg::Matrixd::rotate(_rotation)*osg::Matrixd::translate(_eye);
|
||||
}
|
||||
|
||||
osg::Matrixd FlightManipulator::getInverseMatrix() const
|
||||
{
|
||||
return osg::Matrixd::translate(-_eye)*osg::Matrixd::rotate(_rotation.inverse());
|
||||
}
|
||||
|
||||
void FlightManipulator::computePosition(const osg::Vec3& eye,const osg::Vec3& center,const osg::Vec3& up)
|
||||
{
|
||||
osg::Vec3d lv = center-eye;
|
||||
|
||||
osg::Vec3 f(lv);
|
||||
f.normalize();
|
||||
osg::Vec3 s(f^up);
|
||||
s.normalize();
|
||||
osg::Vec3 u(s^f);
|
||||
u.normalize();
|
||||
|
||||
osg::Matrixd rotation_matrix(s[0], u[0], -f[0], 0.0f,
|
||||
s[1], u[1], -f[1], 0.0f,
|
||||
s[2], u[2], -f[2], 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
_eye = eye;
|
||||
_distance = lv.length();
|
||||
_rotation = rotation_matrix.getRotate().inverse();
|
||||
return flightHandleEvent( ea, us );
|
||||
}
|
||||
|
||||
|
||||
bool FlightManipulator::calcMovement()
|
||||
// doc in parent
|
||||
bool FlightManipulator::handleMouseRelease( const GUIEventAdapter& ea, GUIActionAdapter& us )
|
||||
{
|
||||
return flightHandleEvent( ea, us );
|
||||
}
|
||||
|
||||
|
||||
bool FlightManipulator::handleKeyDown( const GUIEventAdapter& ea, GUIActionAdapter& us )
|
||||
{
|
||||
if( inherited::handleKeyDown( ea, us ) )
|
||||
return true;
|
||||
|
||||
if( ea.getKey() == 'q' ) {
|
||||
|
||||
_yawMode = YAW_AUTOMATICALLY_WHEN_BANKED;
|
||||
return true;
|
||||
|
||||
}
|
||||
else if (ea.getKey()=='a') {
|
||||
|
||||
_yawMode = NO_AUTOMATIC_YAW;
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
bool FlightManipulator::flightHandleEvent( const GUIEventAdapter& ea, GUIActionAdapter& us )
|
||||
{
|
||||
addMouseEvent( ea );
|
||||
us.requestContinuousUpdate( true );
|
||||
if( performMovement() )
|
||||
us.requestRedraw();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void FlightManipulator::getUsage( ApplicationUsage& usage ) const
|
||||
{
|
||||
inherited::getUsage( usage );
|
||||
usage.addKeyboardMouseBinding( getManipulatorName() + ": q", "Automatically yaw when banked (default)" );
|
||||
usage.addKeyboardMouseBinding( getManipulatorName() + ": a", "No yaw when banked" );
|
||||
}
|
||||
|
||||
|
||||
/** Configure the Yaw control for the flight model. */
|
||||
void FlightManipulator::setYawControlMode( YawControlMode ycm )
|
||||
{
|
||||
_yawMode = ycm;
|
||||
}
|
||||
|
||||
|
||||
bool FlightManipulator::performMovement()
|
||||
{
|
||||
// return if less then two events have been added.
|
||||
if (_ga_t0.get()==NULL || _ga_t1.get()==NULL) return false;
|
||||
@@ -245,53 +149,46 @@ bool FlightManipulator::calcMovement()
|
||||
|
||||
if (dt<0.0f)
|
||||
{
|
||||
notify(INFO) << "warning dt = "<<dt<< std::endl;
|
||||
notify(WARN) << "Manipulator warning dt = " << dt << std::endl;
|
||||
dt = 0.0f;
|
||||
}
|
||||
|
||||
unsigned int buttonMask = _ga_t1->getButtonMask();
|
||||
if (buttonMask==GUIEventAdapter::LEFT_MOUSE_BUTTON)
|
||||
{
|
||||
// pan model.
|
||||
|
||||
_velocity += dt*(_acceleration+_velocity);
|
||||
|
||||
return performMovementLeftMouseButton(dt, 0., 0.);
|
||||
}
|
||||
else if (buttonMask==GUIEventAdapter::MIDDLE_MOUSE_BUTTON ||
|
||||
buttonMask==(GUIEventAdapter::LEFT_MOUSE_BUTTON|GUIEventAdapter::RIGHT_MOUSE_BUTTON))
|
||||
{
|
||||
|
||||
_velocity = 0.0f;
|
||||
|
||||
return performMovementMiddleMouseButton(dt, 0., 0.);
|
||||
}
|
||||
else if (buttonMask==GUIEventAdapter::RIGHT_MOUSE_BUTTON)
|
||||
{
|
||||
|
||||
_velocity -= dt*(_acceleration+_velocity);
|
||||
|
||||
return performMovementRightMouseButton(dt, 0., 0.);
|
||||
}
|
||||
|
||||
float dx = _ga_t0->getXnormalized();
|
||||
float dy = _ga_t0->getYnormalized();
|
||||
|
||||
osg::CoordinateFrame cf=getCoordinateFrame(_eye);
|
||||
CoordinateFrame cf=getCoordinateFrame(_eye);
|
||||
|
||||
osg::Matrixd rotation_matrix;
|
||||
Matrixd rotation_matrix;
|
||||
rotation_matrix.makeRotate(_rotation);
|
||||
|
||||
osg::Vec3d up = osg::Vec3(0.0,1.0,0.0) * rotation_matrix;
|
||||
osg::Vec3d lv = osg::Vec3(0.0,0.0,-1.0) * rotation_matrix;
|
||||
|
||||
osg::Vec3d sv = lv^up;
|
||||
Vec3d up = Vec3d(0.0,1.0,0.0) * rotation_matrix;
|
||||
Vec3d lv = Vec3d(0.0,0.0,-1.0) * rotation_matrix;
|
||||
|
||||
Vec3d sv = lv^up;
|
||||
sv.normalize();
|
||||
|
||||
double pitch = -inDegrees(dy*50.0f*dt);
|
||||
double roll = inDegrees(dx*50.0f*dt);
|
||||
|
||||
osg::Quat delta_rotate;
|
||||
Quat delta_rotate;
|
||||
|
||||
osg::Quat roll_rotate;
|
||||
osg::Quat pitch_rotate;
|
||||
Quat roll_rotate;
|
||||
Quat pitch_rotate;
|
||||
|
||||
pitch_rotate.makeRotate(pitch,sv.x(),sv.y(),sv.z());
|
||||
roll_rotate.makeRotate(roll,lv.x(),lv.y(),lv.z());
|
||||
@@ -303,8 +200,8 @@ bool FlightManipulator::calcMovement()
|
||||
//float bank = asinf(sv.z());
|
||||
double bank = asinf(sv *getUpVector(cf));
|
||||
double yaw = inRadians(bank)*dt;
|
||||
|
||||
osg::Quat yaw_rotate;
|
||||
|
||||
Quat yaw_rotate;
|
||||
//yaw_rotate.makeRotate(yaw,0.0f,0.0f,1.0f);
|
||||
|
||||
yaw_rotate.makeRotate(yaw,getUpVector(cf));
|
||||
@@ -320,3 +217,25 @@ bool FlightManipulator::calcMovement()
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool FlightManipulator::performMovementLeftMouseButton( const double dt, const double dx, const double dy )
|
||||
{
|
||||
// pan model
|
||||
_velocity += dt * (_acceleration + _velocity);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool FlightManipulator::performMovementMiddleMouseButton( const double dt, const double dx, const double dy )
|
||||
{
|
||||
_velocity = 0.0f;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool FlightManipulator::performMovementRightMouseButton( const double dt, const double dx, const double dy )
|
||||
{
|
||||
_velocity -= dt * (_acceleration + _velocity);
|
||||
return true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user