mirror of https://github.com/OpenMW/openmw.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
803 lines
22 KiB
C++
803 lines
22 KiB
C++
#include "cameracontroller.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <cmath>
|
|
#include <set>
|
|
|
|
#include <QWidget>
|
|
|
|
#include <osg/BoundingBox>
|
|
#include <osg/Camera>
|
|
#include <osg/ComputeBoundsVisitor>
|
|
#include <osg/Group>
|
|
#include <osg/Math>
|
|
#include <osg/Matrixd>
|
|
#include <osg/Quat>
|
|
#include <osg/Vec3>
|
|
#include <osg/ref_ptr>
|
|
|
|
#include <osgUtil/IntersectionVisitor>
|
|
#include <osgUtil/LineSegmentIntersector>
|
|
|
|
#include "../../model/prefs/shortcut.hpp"
|
|
|
|
namespace CSVRender
|
|
{
|
|
|
|
/*
|
|
Camera Controller
|
|
*/
|
|
|
|
const osg::Vec3d CameraController::WorldUp = osg::Vec3d(0, 0, 1);
|
|
|
|
const osg::Vec3d CameraController::LocalUp = osg::Vec3d(0, 1, 0);
|
|
const osg::Vec3d CameraController::LocalLeft = osg::Vec3d(1, 0, 0);
|
|
const osg::Vec3d CameraController::LocalForward = osg::Vec3d(0, 0, 1);
|
|
|
|
CameraController::CameraController(QObject* parent)
|
|
: QObject(parent)
|
|
, mActive(false)
|
|
, mInverted(false)
|
|
, mCameraSensitivity(1 / 650.f)
|
|
, mSecondaryMoveMult(50)
|
|
, mWheelMoveMult(8)
|
|
, mCamera(nullptr)
|
|
{
|
|
}
|
|
|
|
bool CameraController::isActive() const
|
|
{
|
|
return mActive;
|
|
}
|
|
|
|
osg::Camera* CameraController::getCamera() const
|
|
{
|
|
return mCamera;
|
|
}
|
|
|
|
double CameraController::getCameraSensitivity() const
|
|
{
|
|
return mCameraSensitivity;
|
|
}
|
|
|
|
bool CameraController::getInverted() const
|
|
{
|
|
return mInverted;
|
|
}
|
|
|
|
double CameraController::getSecondaryMovementMultiplier() const
|
|
{
|
|
return mSecondaryMoveMult;
|
|
}
|
|
|
|
double CameraController::getWheelMovementMultiplier() const
|
|
{
|
|
return mWheelMoveMult;
|
|
}
|
|
|
|
void CameraController::setCamera(osg::Camera* camera)
|
|
{
|
|
bool wasActive = mActive;
|
|
|
|
mCamera = camera;
|
|
mActive = (mCamera != nullptr);
|
|
|
|
if (mActive != wasActive)
|
|
{
|
|
for (std::vector<CSMPrefs::Shortcut*>::iterator it = mShortcuts.begin(); it != mShortcuts.end(); ++it)
|
|
{
|
|
CSMPrefs::Shortcut* shortcut = *it;
|
|
shortcut->enable(mActive);
|
|
}
|
|
}
|
|
}
|
|
|
|
void CameraController::setCameraSensitivity(double value)
|
|
{
|
|
mCameraSensitivity = value;
|
|
}
|
|
|
|
void CameraController::setInverted(bool value)
|
|
{
|
|
mInverted = value;
|
|
}
|
|
|
|
void CameraController::setSecondaryMovementMultiplier(double value)
|
|
{
|
|
mSecondaryMoveMult = value;
|
|
}
|
|
|
|
void CameraController::setWheelMovementMultiplier(double value)
|
|
{
|
|
mWheelMoveMult = value;
|
|
}
|
|
|
|
void CameraController::setup(osg::Group* root, unsigned int mask, const osg::Vec3d& up)
|
|
{
|
|
// Find World bounds
|
|
osg::ComputeBoundsVisitor boundsVisitor;
|
|
osg::BoundingBox& boundingBox = boundsVisitor.getBoundingBox();
|
|
|
|
boundsVisitor.setTraversalMask(mask);
|
|
root->accept(boundsVisitor);
|
|
|
|
if (!boundingBox.valid())
|
|
{
|
|
// Try again without any mask
|
|
boundsVisitor.reset();
|
|
boundsVisitor.setTraversalMask(~0u);
|
|
root->accept(boundsVisitor);
|
|
|
|
// Last resort, set a default
|
|
if (!boundingBox.valid())
|
|
{
|
|
boundingBox.set(-1, -1, -1, 1, 1, 1);
|
|
}
|
|
}
|
|
|
|
// Calculate a good starting position
|
|
osg::Vec3d minBounds = boundingBox.corner(0) - boundingBox.center();
|
|
osg::Vec3d maxBounds = boundingBox.corner(7) - boundingBox.center();
|
|
|
|
osg::Vec3d camOffset = up * maxBounds > 0 ? maxBounds : minBounds;
|
|
camOffset *= 2;
|
|
|
|
osg::Vec3d eye = camOffset + boundingBox.center();
|
|
osg::Vec3d center = boundingBox.center();
|
|
|
|
getCamera()->setViewMatrixAsLookAt(eye, center, up);
|
|
}
|
|
|
|
void CameraController::addShortcut(CSMPrefs::Shortcut* shortcut)
|
|
{
|
|
mShortcuts.push_back(shortcut);
|
|
}
|
|
|
|
/*
|
|
Free Camera Controller
|
|
*/
|
|
|
|
FreeCameraController::FreeCameraController(QWidget* widget)
|
|
: CameraController(widget)
|
|
, mLockUpright(false)
|
|
, mModified(false)
|
|
, mNaviPrimary(false)
|
|
, mNaviSecondary(false)
|
|
, mFast(false)
|
|
, mFastAlternate(false)
|
|
, mLeft(false)
|
|
, mRight(false)
|
|
, mForward(false)
|
|
, mBackward(false)
|
|
, mRollLeft(false)
|
|
, mRollRight(false)
|
|
, mUp(LocalUp)
|
|
, mLinSpeed(1000)
|
|
, mRotSpeed(osg::PI / 2)
|
|
, mSpeedMult(8)
|
|
{
|
|
CSMPrefs::Shortcut* naviPrimaryShortcut = new CSMPrefs::Shortcut("scene-navi-primary", widget);
|
|
naviPrimaryShortcut->enable(false);
|
|
connect(naviPrimaryShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this,
|
|
&FreeCameraController::naviPrimary);
|
|
|
|
addShortcut(naviPrimaryShortcut);
|
|
|
|
CSMPrefs::Shortcut* naviSecondaryShortcut = new CSMPrefs::Shortcut("scene-navi-secondary", widget);
|
|
naviSecondaryShortcut->enable(false);
|
|
connect(naviSecondaryShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this,
|
|
&FreeCameraController::naviSecondary);
|
|
|
|
addShortcut(naviSecondaryShortcut);
|
|
|
|
CSMPrefs::Shortcut* forwardShortcut
|
|
= new CSMPrefs::Shortcut("free-forward", "scene-speed-modifier", CSMPrefs::Shortcut::SM_Detach, widget);
|
|
forwardShortcut->enable(false);
|
|
connect(forwardShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this, &FreeCameraController::forward);
|
|
connect(forwardShortcut, qOverload<bool>(&CSMPrefs::Shortcut::secondary), this,
|
|
&FreeCameraController::alternateFast);
|
|
|
|
addShortcut(forwardShortcut);
|
|
|
|
CSMPrefs::Shortcut* leftShortcut = new CSMPrefs::Shortcut("free-left", widget);
|
|
leftShortcut->enable(false);
|
|
connect(leftShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this, &FreeCameraController::left);
|
|
|
|
addShortcut(leftShortcut);
|
|
|
|
CSMPrefs::Shortcut* backShortcut = new CSMPrefs::Shortcut("free-backward", widget);
|
|
backShortcut->enable(false);
|
|
connect(backShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this, &FreeCameraController::backward);
|
|
|
|
addShortcut(backShortcut);
|
|
|
|
CSMPrefs::Shortcut* rightShortcut = new CSMPrefs::Shortcut("free-right", widget);
|
|
rightShortcut->enable(false);
|
|
connect(rightShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this, &FreeCameraController::right);
|
|
|
|
addShortcut(rightShortcut);
|
|
|
|
CSMPrefs::Shortcut* rollLeftShortcut = new CSMPrefs::Shortcut("free-roll-left", widget);
|
|
rollLeftShortcut->enable(false);
|
|
connect(
|
|
rollLeftShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this, &FreeCameraController::rollLeft);
|
|
|
|
addShortcut(rollLeftShortcut);
|
|
|
|
CSMPrefs::Shortcut* rollRightShortcut = new CSMPrefs::Shortcut("free-roll-right", widget);
|
|
rollRightShortcut->enable(false);
|
|
connect(
|
|
rollRightShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this, &FreeCameraController::rollRight);
|
|
|
|
addShortcut(rollRightShortcut);
|
|
|
|
CSMPrefs::Shortcut* speedModeShortcut = new CSMPrefs::Shortcut("free-speed-mode", widget);
|
|
speedModeShortcut->enable(false);
|
|
connect(
|
|
speedModeShortcut, qOverload<>(&CSMPrefs::Shortcut::activated), this, &FreeCameraController::swapSpeedMode);
|
|
|
|
addShortcut(speedModeShortcut);
|
|
}
|
|
|
|
double FreeCameraController::getLinearSpeed() const
|
|
{
|
|
return mLinSpeed;
|
|
}
|
|
|
|
double FreeCameraController::getRotationalSpeed() const
|
|
{
|
|
return mRotSpeed;
|
|
}
|
|
|
|
double FreeCameraController::getSpeedMultiplier() const
|
|
{
|
|
return mSpeedMult;
|
|
}
|
|
|
|
void FreeCameraController::setLinearSpeed(double value)
|
|
{
|
|
mLinSpeed = value;
|
|
}
|
|
|
|
void FreeCameraController::setRotationalSpeed(double value)
|
|
{
|
|
mRotSpeed = value;
|
|
}
|
|
|
|
void FreeCameraController::setSpeedMultiplier(double value)
|
|
{
|
|
mSpeedMult = value;
|
|
}
|
|
|
|
void FreeCameraController::fixUpAxis(const osg::Vec3d& up)
|
|
{
|
|
mLockUpright = true;
|
|
mUp = up;
|
|
mModified = true;
|
|
}
|
|
|
|
void FreeCameraController::unfixUpAxis()
|
|
{
|
|
mLockUpright = false;
|
|
}
|
|
|
|
void FreeCameraController::handleMouseMoveEvent(int x, int y)
|
|
{
|
|
if (!isActive())
|
|
return;
|
|
|
|
if (mNaviPrimary)
|
|
{
|
|
double scalar = getCameraSensitivity() * (getInverted() ? -1.0 : 1.0);
|
|
yaw(x * scalar);
|
|
pitch(y * scalar);
|
|
}
|
|
else if (mNaviSecondary)
|
|
{
|
|
osg::Vec3d movement;
|
|
movement += LocalLeft * -x * getSecondaryMovementMultiplier();
|
|
movement += LocalUp * y * getSecondaryMovementMultiplier();
|
|
|
|
translate(movement);
|
|
}
|
|
}
|
|
|
|
void FreeCameraController::handleMouseScrollEvent(int x)
|
|
{
|
|
if (!isActive())
|
|
return;
|
|
|
|
translate(LocalForward * x * ((mFast ^ mFastAlternate) ? getWheelMovementMultiplier() : 1));
|
|
}
|
|
|
|
void FreeCameraController::update(double dt)
|
|
{
|
|
if (!isActive())
|
|
return;
|
|
|
|
double linDist = mLinSpeed * dt;
|
|
double rotDist = mRotSpeed * dt;
|
|
|
|
if (mFast ^ mFastAlternate)
|
|
linDist *= mSpeedMult;
|
|
|
|
if (mLeft)
|
|
translate(LocalLeft * linDist);
|
|
if (mRight)
|
|
translate(LocalLeft * -linDist);
|
|
if (mForward)
|
|
translate(LocalForward * linDist);
|
|
if (mBackward)
|
|
translate(LocalForward * -linDist);
|
|
|
|
if (!mLockUpright)
|
|
{
|
|
if (mRollLeft)
|
|
roll(-rotDist);
|
|
if (mRollRight)
|
|
roll(rotDist);
|
|
}
|
|
else if (mModified)
|
|
{
|
|
stabilize();
|
|
mModified = false;
|
|
}
|
|
|
|
// Normalize the matrix to counter drift
|
|
getCamera()->getViewMatrix().orthoNormal(getCamera()->getViewMatrix());
|
|
}
|
|
|
|
void FreeCameraController::yaw(double value)
|
|
{
|
|
getCamera()->getViewMatrix() *= osg::Matrixd::rotate(value, LocalUp);
|
|
mModified = true;
|
|
}
|
|
|
|
void FreeCameraController::pitch(double value)
|
|
{
|
|
const double Constraint = osg::PI / 2 - 0.1;
|
|
|
|
if (mLockUpright)
|
|
{
|
|
osg::Vec3d eye, center, up;
|
|
getCamera()->getViewMatrixAsLookAt(eye, center, up);
|
|
|
|
osg::Vec3d forward = center - eye;
|
|
osg::Vec3d left = up ^ forward;
|
|
|
|
double pitchAngle = std::acos(up * mUp);
|
|
if ((mUp ^ up) * left < 0)
|
|
pitchAngle *= -1;
|
|
|
|
if (std::abs(pitchAngle + value) > Constraint)
|
|
value = (pitchAngle > 0 ? 1 : -1) * Constraint - pitchAngle;
|
|
}
|
|
|
|
getCamera()->getViewMatrix() *= osg::Matrixd::rotate(value, LocalLeft);
|
|
mModified = true;
|
|
}
|
|
|
|
void FreeCameraController::roll(double value)
|
|
{
|
|
getCamera()->getViewMatrix() *= osg::Matrixd::rotate(value, LocalForward);
|
|
mModified = true;
|
|
}
|
|
|
|
void FreeCameraController::translate(const osg::Vec3d& offset)
|
|
{
|
|
getCamera()->getViewMatrix() *= osg::Matrixd::translate(offset);
|
|
mModified = true;
|
|
}
|
|
|
|
void FreeCameraController::stabilize()
|
|
{
|
|
osg::Vec3d eye, center, up;
|
|
getCamera()->getViewMatrixAsLookAt(eye, center, up);
|
|
getCamera()->setViewMatrixAsLookAt(eye, center, mUp);
|
|
}
|
|
|
|
void FreeCameraController::naviPrimary(bool active)
|
|
{
|
|
mNaviPrimary = active;
|
|
}
|
|
|
|
void FreeCameraController::naviSecondary(bool active)
|
|
{
|
|
mNaviSecondary = active;
|
|
}
|
|
|
|
void FreeCameraController::forward(bool active)
|
|
{
|
|
mForward = active;
|
|
}
|
|
|
|
void FreeCameraController::left(bool active)
|
|
{
|
|
mLeft = active;
|
|
}
|
|
|
|
void FreeCameraController::backward(bool active)
|
|
{
|
|
mBackward = active;
|
|
}
|
|
|
|
void FreeCameraController::right(bool active)
|
|
{
|
|
mRight = active;
|
|
}
|
|
|
|
void FreeCameraController::rollLeft(bool active)
|
|
{
|
|
mRollLeft = active;
|
|
}
|
|
|
|
void FreeCameraController::rollRight(bool active)
|
|
{
|
|
mRollRight = active;
|
|
}
|
|
|
|
void FreeCameraController::alternateFast(bool active)
|
|
{
|
|
mFastAlternate = active;
|
|
}
|
|
|
|
void FreeCameraController::swapSpeedMode()
|
|
{
|
|
mFast = !mFast;
|
|
}
|
|
|
|
/*
|
|
Orbit Camera Controller
|
|
*/
|
|
|
|
OrbitCameraController::OrbitCameraController(QWidget* widget)
|
|
: CameraController(widget)
|
|
, mInitialized(false)
|
|
, mNaviPrimary(false)
|
|
, mNaviSecondary(false)
|
|
, mFast(false)
|
|
, mFastAlternate(false)
|
|
, mLeft(false)
|
|
, mRight(false)
|
|
, mUp(false)
|
|
, mDown(false)
|
|
, mRollLeft(false)
|
|
, mRollRight(false)
|
|
, mPickingMask(~0u)
|
|
, mCenter(0, 0, 0)
|
|
, mDistance(0)
|
|
, mOrbitSpeed(osg::PI / 4)
|
|
, mOrbitSpeedMult(4)
|
|
, mConstRoll(false)
|
|
{
|
|
CSMPrefs::Shortcut* naviPrimaryShortcut = new CSMPrefs::Shortcut("scene-navi-primary", widget);
|
|
naviPrimaryShortcut->enable(false);
|
|
connect(naviPrimaryShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this,
|
|
&OrbitCameraController::naviPrimary);
|
|
|
|
addShortcut(naviPrimaryShortcut);
|
|
|
|
CSMPrefs::Shortcut* naviSecondaryShortcut = new CSMPrefs::Shortcut("scene-navi-secondary", widget);
|
|
naviSecondaryShortcut->enable(false);
|
|
connect(naviSecondaryShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this,
|
|
&OrbitCameraController::naviSecondary);
|
|
|
|
addShortcut(naviSecondaryShortcut);
|
|
|
|
CSMPrefs::Shortcut* upShortcut
|
|
= new CSMPrefs::Shortcut("orbit-up", "scene-speed-modifier", CSMPrefs::Shortcut::SM_Detach, widget);
|
|
upShortcut->enable(false);
|
|
connect(upShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this, &OrbitCameraController::up);
|
|
connect(
|
|
upShortcut, qOverload<bool>(&CSMPrefs::Shortcut::secondary), this, &OrbitCameraController::alternateFast);
|
|
|
|
addShortcut(upShortcut);
|
|
|
|
CSMPrefs::Shortcut* leftShortcut = new CSMPrefs::Shortcut("orbit-left", widget);
|
|
leftShortcut->enable(false);
|
|
connect(leftShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this, &OrbitCameraController::left);
|
|
|
|
addShortcut(leftShortcut);
|
|
|
|
CSMPrefs::Shortcut* downShortcut = new CSMPrefs::Shortcut("orbit-down", widget);
|
|
downShortcut->enable(false);
|
|
connect(downShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this, &OrbitCameraController::down);
|
|
|
|
addShortcut(downShortcut);
|
|
|
|
CSMPrefs::Shortcut* rightShortcut = new CSMPrefs::Shortcut("orbit-right", widget);
|
|
rightShortcut->enable(false);
|
|
connect(rightShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this, &OrbitCameraController::right);
|
|
|
|
addShortcut(rightShortcut);
|
|
|
|
CSMPrefs::Shortcut* rollLeftShortcut = new CSMPrefs::Shortcut("orbit-roll-left", widget);
|
|
rollLeftShortcut->enable(false);
|
|
connect(
|
|
rollLeftShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this, &OrbitCameraController::rollLeft);
|
|
|
|
addShortcut(rollLeftShortcut);
|
|
|
|
CSMPrefs::Shortcut* rollRightShortcut = new CSMPrefs::Shortcut("orbit-roll-right", widget);
|
|
rollRightShortcut->enable(false);
|
|
connect(rollRightShortcut, qOverload<bool>(&CSMPrefs::Shortcut::activated), this,
|
|
&OrbitCameraController::rollRight);
|
|
|
|
addShortcut(rollRightShortcut);
|
|
|
|
CSMPrefs::Shortcut* speedModeShortcut = new CSMPrefs::Shortcut("orbit-speed-mode", widget);
|
|
speedModeShortcut->enable(false);
|
|
connect(speedModeShortcut, qOverload<>(&CSMPrefs::Shortcut::activated), this,
|
|
&OrbitCameraController::swapSpeedMode);
|
|
|
|
addShortcut(speedModeShortcut);
|
|
}
|
|
|
|
osg::Vec3d OrbitCameraController::getCenter() const
|
|
{
|
|
return mCenter;
|
|
}
|
|
|
|
double OrbitCameraController::getOrbitSpeed() const
|
|
{
|
|
return mOrbitSpeed;
|
|
}
|
|
|
|
double OrbitCameraController::getOrbitSpeedMultiplier() const
|
|
{
|
|
return mOrbitSpeedMult;
|
|
}
|
|
|
|
unsigned int OrbitCameraController::getPickingMask() const
|
|
{
|
|
return mPickingMask;
|
|
}
|
|
|
|
void OrbitCameraController::setCenter(const osg::Vec3d& value)
|
|
{
|
|
osg::Vec3d eye, center, up;
|
|
getCamera()->getViewMatrixAsLookAt(eye, center, up);
|
|
|
|
mCenter = value;
|
|
mDistance = (eye - mCenter).length();
|
|
|
|
getCamera()->setViewMatrixAsLookAt(eye, mCenter, up);
|
|
|
|
mInitialized = true;
|
|
}
|
|
|
|
void OrbitCameraController::setOrbitSpeed(double value)
|
|
{
|
|
mOrbitSpeed = value;
|
|
}
|
|
|
|
void OrbitCameraController::setOrbitSpeedMultiplier(double value)
|
|
{
|
|
mOrbitSpeedMult = value;
|
|
}
|
|
|
|
void OrbitCameraController::setPickingMask(unsigned int value)
|
|
{
|
|
mPickingMask = value;
|
|
}
|
|
|
|
void OrbitCameraController::handleMouseMoveEvent(int x, int y)
|
|
{
|
|
if (!isActive())
|
|
return;
|
|
|
|
if (!mInitialized)
|
|
initialize();
|
|
|
|
if (mNaviPrimary)
|
|
{
|
|
double scalar = getCameraSensitivity() * (getInverted() ? -1.0 : 1.0);
|
|
rotateHorizontal(x * scalar);
|
|
rotateVertical(-y * scalar);
|
|
}
|
|
else if (mNaviSecondary)
|
|
{
|
|
osg::Vec3d movement;
|
|
movement += LocalLeft * x * getSecondaryMovementMultiplier();
|
|
movement += LocalUp * -y * getSecondaryMovementMultiplier();
|
|
|
|
translate(movement);
|
|
}
|
|
}
|
|
|
|
void OrbitCameraController::handleMouseScrollEvent(int x)
|
|
{
|
|
if (!isActive())
|
|
return;
|
|
|
|
zoom(-x * ((mFast ^ mFastAlternate) ? getWheelMovementMultiplier() : 1));
|
|
}
|
|
|
|
void OrbitCameraController::update(double dt)
|
|
{
|
|
if (!isActive())
|
|
return;
|
|
|
|
if (!mInitialized)
|
|
initialize();
|
|
|
|
double rotDist = mOrbitSpeed * dt;
|
|
|
|
if (mFast ^ mFastAlternate)
|
|
rotDist *= mOrbitSpeedMult;
|
|
|
|
if (mLeft)
|
|
rotateHorizontal(-rotDist);
|
|
if (mRight)
|
|
rotateHorizontal(rotDist);
|
|
if (mUp)
|
|
rotateVertical(rotDist);
|
|
if (mDown)
|
|
rotateVertical(-rotDist);
|
|
|
|
if (mRollLeft)
|
|
roll(-rotDist);
|
|
if (mRollRight)
|
|
roll(rotDist);
|
|
|
|
// Normalize the matrix to counter drift
|
|
getCamera()->getViewMatrix().orthoNormal(getCamera()->getViewMatrix());
|
|
}
|
|
|
|
void OrbitCameraController::reset()
|
|
{
|
|
mInitialized = false;
|
|
}
|
|
|
|
void OrbitCameraController::initialize()
|
|
{
|
|
static const int DefaultStartDistance = 10000.f;
|
|
|
|
// Try to intelligently pick focus object
|
|
osg::ref_ptr<osgUtil::LineSegmentIntersector> intersector(
|
|
new osgUtil::LineSegmentIntersector(osgUtil::Intersector::PROJECTION, osg::Vec3d(0, 0, 0), LocalForward));
|
|
|
|
intersector->setIntersectionLimit(osgUtil::LineSegmentIntersector::LIMIT_NEAREST);
|
|
osgUtil::IntersectionVisitor visitor(intersector);
|
|
|
|
visitor.setTraversalMask(mPickingMask);
|
|
|
|
getCamera()->accept(visitor);
|
|
|
|
osg::Vec3d eye, center, up;
|
|
getCamera()->getViewMatrixAsLookAt(eye, center, up, DefaultStartDistance);
|
|
|
|
if (intersector->getIntersections().begin() != intersector->getIntersections().end())
|
|
{
|
|
mCenter = intersector->getIntersections().begin()->getWorldIntersectPoint();
|
|
mDistance = (eye - mCenter).length();
|
|
}
|
|
else
|
|
{
|
|
mCenter = center;
|
|
mDistance = DefaultStartDistance;
|
|
}
|
|
|
|
mInitialized = true;
|
|
}
|
|
|
|
void OrbitCameraController::setConstRoll(bool enabled)
|
|
{
|
|
mConstRoll = enabled;
|
|
}
|
|
|
|
void OrbitCameraController::rotateHorizontal(double value)
|
|
{
|
|
osg::Vec3d eye, center, up;
|
|
getCamera()->getViewMatrixAsLookAt(eye, center, up);
|
|
osg::Vec3d absoluteUp = osg::Vec3(0, 0, 1);
|
|
|
|
osg::Quat rotation = osg::Quat(value, mConstRoll ? absoluteUp : up);
|
|
osg::Vec3d oldOffset = eye - mCenter;
|
|
osg::Vec3d newOffset = rotation * oldOffset;
|
|
|
|
if (mConstRoll)
|
|
up = rotation * up;
|
|
|
|
getCamera()->setViewMatrixAsLookAt(mCenter + newOffset, mCenter, up);
|
|
}
|
|
|
|
void OrbitCameraController::rotateVertical(double value)
|
|
{
|
|
osg::Vec3d eye, center, up;
|
|
getCamera()->getViewMatrixAsLookAt(eye, center, up);
|
|
|
|
osg::Vec3d forward = center - eye;
|
|
osg::Vec3d axis = up ^ forward;
|
|
|
|
osg::Quat rotation = osg::Quat(value, axis);
|
|
osg::Vec3d oldOffset = eye - mCenter;
|
|
osg::Vec3d newOffset = rotation * oldOffset;
|
|
|
|
if (mConstRoll)
|
|
up = rotation * up;
|
|
|
|
getCamera()->setViewMatrixAsLookAt(mCenter + newOffset, mCenter, up);
|
|
}
|
|
|
|
void OrbitCameraController::roll(double value)
|
|
{
|
|
getCamera()->getViewMatrix() *= osg::Matrixd::rotate(value, LocalForward);
|
|
}
|
|
|
|
void OrbitCameraController::translate(const osg::Vec3d& offset)
|
|
{
|
|
osg::Vec3d eye, center, up;
|
|
getCamera()->getViewMatrixAsLookAt(eye, center, up);
|
|
|
|
osg::Vec3d newOffset = getCamera()->getViewMatrix().getRotate().inverse() * offset;
|
|
mCenter += newOffset;
|
|
eye += newOffset;
|
|
|
|
getCamera()->setViewMatrixAsLookAt(eye, mCenter, up);
|
|
}
|
|
|
|
void OrbitCameraController::zoom(double value)
|
|
{
|
|
mDistance = std::max(10., mDistance + value);
|
|
|
|
osg::Vec3d eye, center, up;
|
|
getCamera()->getViewMatrixAsLookAt(eye, center, up, 1.f);
|
|
|
|
osg::Vec3d offset = (eye - center) * mDistance;
|
|
|
|
getCamera()->setViewMatrixAsLookAt(mCenter + offset, mCenter, up);
|
|
}
|
|
|
|
void OrbitCameraController::naviPrimary(bool active)
|
|
{
|
|
mNaviPrimary = active;
|
|
}
|
|
|
|
void OrbitCameraController::naviSecondary(bool active)
|
|
{
|
|
mNaviSecondary = active;
|
|
}
|
|
|
|
void OrbitCameraController::up(bool active)
|
|
{
|
|
mUp = active;
|
|
}
|
|
|
|
void OrbitCameraController::left(bool active)
|
|
{
|
|
mLeft = active;
|
|
}
|
|
|
|
void OrbitCameraController::down(bool active)
|
|
{
|
|
mDown = active;
|
|
}
|
|
|
|
void OrbitCameraController::right(bool active)
|
|
{
|
|
mRight = active;
|
|
}
|
|
|
|
void OrbitCameraController::rollLeft(bool active)
|
|
{
|
|
if (isActive())
|
|
mRollLeft = active;
|
|
}
|
|
|
|
void OrbitCameraController::rollRight(bool active)
|
|
{
|
|
mRollRight = active;
|
|
}
|
|
|
|
void OrbitCameraController::alternateFast(bool active)
|
|
{
|
|
mFastAlternate = active;
|
|
}
|
|
|
|
void OrbitCameraController::swapSpeedMode()
|
|
{
|
|
mFast = !mFast;
|
|
}
|
|
}
|