mirror of
				https://github.com/OpenMW/openmw.git
				synced 2025-11-04 07:26:39 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			802 lines
		
	
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			802 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;
 | 
						|
    }
 | 
						|
}
 |