/***************************************************************************************** * * * OpenSpace * * * * Copyright (c) 2014-2016 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * * without restriction, including without limitation the rights to use, copy, modify, * * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * * permit persons to whom the Software is furnished to do so, subject to the following * * conditions: * * * * The above copyright notice and this permission notice shall be included in all copies * * or substantial portions of the Software. * * * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ #ifndef __OPENSPACE_CORE___INTERACTIONMODE___H__ #define __OPENSPACE_CORE___INTERACTIONMODE___H__ #include #include #include #include #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED #include #include #endif #include namespace openspace { class Camera; class SceneGraphNode; namespace globebrowsing { class RenderableGlobe; } namespace interaction { template class Interpolator { public: Interpolator(std::function transferFunction) : _t(0.0) , _transferFunction(transferFunction) {}; ~Interpolator() {}; void start() { _t = 0.0; }; void end() { _t = 1.0; }; void step(double delta) { _t += delta; }; T value() { return _transferFunction(_t); }; bool isInterpolating() { return _t < 1.0; }; private: std::function _transferFunction; double _t; }; class InputState { public: InputState(); ~InputState(); // Callback functions void keyboardCallback(Key key, KeyModifier modifier, KeyAction action); void mouseButtonCallback(MouseButton button, MouseAction action); void mousePositionCallback(double mouseX, double mouseY); void mouseScrollWheelCallback(double mouseScrollDelta); // Mutators void addKeyframe(const datamessagestructures::CameraKeyframe &kf); void clearKeyframes(); void clearOldKeyframes(); // Accessors const std::list >& getPressedKeys() const; const std::list& getPressedMouseButtons() const; glm::dvec2 getMousePosition() const; double getMouseScrollDelta() const; const std::vector& keyframes() const; bool isKeyPressed(std::pair keyModPair) const; bool isKeyPressed(Key key) const; bool isMouseButtonPressed(MouseButton mouseButton) const; private: // Input from keyboard and mouse std::list > _keysDown; std::list _mouseButtonsDown; glm::dvec2 _mousePosition; double _mouseScrollDelta; // Remote input via keyframes std::vector _keyframes; }; class InteractionMode { public: InteractionMode(); ~InteractionMode(); // Mutators virtual void setFocusNode(SceneGraphNode* focusNode); // Accessors SceneGraphNode* focusNode(); Interpolator& rotateToFocusNodeInterpolator(); virtual void updateMouseStatesFromInput(const InputState& inputState, double deltaTime) = 0; virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime) = 0; protected: /** Inner class that acts as a smoothing filter to a variable. The filter has a step response on a form that resembles the function y = 1-e^(-t/scale). The variable will be updates as soon as it is set to a value (calling the set() function). */ template class DelayedVariable { public: DelayedVariable(ScaleType scaleFactor, ScaleType friction) { _scaleFactor = scaleFactor; _friction = glm::max(friction, ScaleType(0.0)); } void set(T value, double dt) { _targetValue = value; _currentValue = _currentValue + (_targetValue - _currentValue) * std::min(_scaleFactor * dt, 1.0); // less or equal to 1.0 keeps it stable } void decelerate(double dt) { _currentValue = _currentValue + (- _currentValue) * std::min(_scaleFactor * _friction * dt, 1.0); // less or equal to 1.0 keeps it stable } void setHard(T value) { _targetValue = value; _currentValue = value; } void setFriction(ScaleType friction) { _friction = glm::max(friction, ScaleType(0.0)); } void setScaleFactor(ScaleType scaleFactor) { _scaleFactor = scaleFactor; } T get() { return _currentValue; } private: ScaleType _scaleFactor; ScaleType _friction; T _targetValue; T _currentValue; }; struct MouseState { MouseState(double scaleFactor) : velocity(scaleFactor, 1) , previousPosition(0.0, 0.0) {} void setFriction(double friction) { velocity.setFriction(friction); } void setVelocityScaleFactor(double scaleFactor) { velocity.setScaleFactor(scaleFactor); } glm::dvec2 previousPosition; DelayedVariable velocity; }; SceneGraphNode* _focusNode = nullptr; glm::dvec3 _previousFocusNodePosition; glm::dquat _previousFocusNodeRotation; Interpolator _rotateToFocusNodeInterpolator; }; class KeyframeInteractionMode : public InteractionMode { public: KeyframeInteractionMode(); ~KeyframeInteractionMode(); virtual void updateMouseStatesFromInput(const InputState& inputState, double deltaTime); virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); private: std::vector _keyframes; double _currentKeyframeTime; }; class GlobeBrowsingInteractionMode; class OrbitalInteractionMode : public InteractionMode { public: class MouseStates { public: /** \param sensitivity \param velocityScaleFactor can be set to 60 to remove the inertia of the interaction. Lower value will make it harder to move the camera. */ MouseStates(double sensitivity, double velocityScaleFactor); void updateMouseStatesFromInput(const InputState& inputState, double deltaTime); void setRotationalFriction(double friction); void setHorizontalFriction(double friction); void setVerticalFriction(double friction); void setSensitivity(double sensitivity); void setVelocityScaleFactor(double scaleFactor); glm::dvec2 synchedGlobalRotationMouseVelocity(); glm::dvec2 synchedLocalRotationMouseVelocity(); glm::dvec2 synchedTruckMovementMouseVelocity(); glm::dvec2 synchedLocalRollMouseVelocity(); glm::dvec2 synchedGlobalRollMouseVelocity(); private: double _sensitivity; MouseState _globalRotationMouseState; MouseState _localRotationMouseState; MouseState _truckMovementMouseState; MouseState _localRollMouseState; MouseState _globalRollMouseState; }; OrbitalInteractionMode(std::shared_ptr mouseStates); ~OrbitalInteractionMode(); //virtual void update(Camera& camera, const InputState& inputState, double deltaTime); virtual void updateMouseStatesFromInput(const InputState& inputState, double deltaTime); virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); protected: //void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); std::shared_ptr _mouseStates; }; class GlobeBrowsingInteractionMode : public OrbitalInteractionMode { public: GlobeBrowsingInteractionMode(std::shared_ptr mouseStates); ~GlobeBrowsingInteractionMode(); virtual void setFocusNode(SceneGraphNode* focusNode); //virtual void update(Camera& camera, const InputState& inputState, double deltaTime); virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED void goToChunk(Camera& camera, globebrowsing::TileIndex ti, glm::vec2 uv, bool resetCameraDirection); void goToGeodetic2(Camera& camera, globebrowsing::Geodetic2 geo2, bool resetCameraDirection); void goToGeodetic3(Camera& camera, globebrowsing::Geodetic3 geo3); void resetCameraDirection(Camera& camera, globebrowsing::Geodetic2 geo2); #endif private: //void updateCameraStateFromMouseStates(Camera& camera, double deltaTime); #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED globebrowsing::RenderableGlobe* _globe; #endif }; } // namespace interaction } // namespace openspace #endif // __OPENSPACE_CORE___INTERACTIONMODE___H__