mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-02-18 02:49:03 -06:00
Interaction Updates (#353)
* Interaction speed is not dependent on framerate * Split up interaction code in files and perform smooth interpolation when changing focus * Abstract interaction code in to functions. * Interpolation time is dependent on angle to focus node. * Use correct delta time when interpolating * Fix bug regarding decomposition of camera rotation. * Make orbital interaction mode behave as globe browsing and no longer use interactiondepth below ellipsoid. * Do not always rotate with object. Depending on distance * Remove interaction depth below ellipsoid. Now able to interact without renderable * Remove specification of interactionDepthBelowEllipsoid and cameraMinHeight * Remove GlobeBrowsingInteractionMode * Rename OrbitalInteractionMode to OrbitalNavigator and no longer extend interactionmode. * Move properties from interaction handler to orbital navigator * Use smooth step for follow rotation interpolator * Rename KeyframeInteractionMode to KeyframeNavigator * Rename files * Clean up. * Separate mousestate from orbitalnavigator * Clean up * Split keybindingmanager from interactionhandler interactionhandler * Rename interactionhandler to navigationhandler * Rename files * Clean up * Take back usage of gotochunk and gotogeo * Rename lua library navigation * Move functionality from navigationhandler to keyframenavigator * Update scripts for navigation * Comment code * Clean up * Solve but that caused NaN values for camera position when being in center of globe and setting focus to the globe. * Update jenkins file to remove build folder before building. * Fix error in jenkins script * Update jenkins file * Update jenkins file * Revert jenkins file * I hope this makes Jenkins happy. * Line endings God damnit * Line endings * Clean up * Fix compilation issue * Take back default scene. * Fix indentation * Move functions goToGeo and goToChunk to GlobeBrowsingModule. * Include algorithm for std::find * Remove auto and other clean up
This commit is contained in:
@@ -78,7 +78,7 @@ function postInitialization()
|
||||
openspace.setPropertyValue("Earth.RenderableGlobe.Debug.levelByProjectedAreaElseDistance", false)
|
||||
openspace.setPropertyValue("Earth.RenderableGlobe.Layers.ColorLayers.blendTileLevels", true)
|
||||
|
||||
openspace.resetCameraDirection()
|
||||
openspace.globebrowsing.goToGeo(0, 0, 20000000)
|
||||
|
||||
openspace.printInfo("Done setting default values")
|
||||
end
|
||||
@@ -89,7 +89,7 @@ return {
|
||||
CommonFolder = "common",
|
||||
Camera = {
|
||||
Focus = "Earth",
|
||||
Position = {30000000, 0, 0},
|
||||
Position = {0, 0, 0},
|
||||
Rotation = {0.758797, 0.221490, -0.605693, -0.091135},
|
||||
},
|
||||
|
||||
|
||||
@@ -63,8 +63,6 @@ return {
|
||||
Renderable = {
|
||||
Type = "RenderableGlobe",
|
||||
Radii = earthEllipsoid,
|
||||
CameraMinHeight = 300,
|
||||
InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values
|
||||
SegmentsPerPatch = 64,
|
||||
Layers = {
|
||||
ColorLayers = {
|
||||
|
||||
@@ -23,8 +23,6 @@ return {
|
||||
Renderable = {
|
||||
Type = "RenderableGlobe",
|
||||
Radii = {2631000, 2631000, 2631000},
|
||||
CameraMinHeight = 300,
|
||||
InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values
|
||||
SegmentsPerPatch = 64,
|
||||
Layers = {
|
||||
ColorLayers = {
|
||||
|
||||
@@ -23,8 +23,6 @@ return {
|
||||
Renderable = {
|
||||
Type = "RenderableGlobe",
|
||||
Radii = {1561000, 1561000, 1561000},
|
||||
CameraMinHeight = 300,
|
||||
InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values
|
||||
SegmentsPerPatch = 64,
|
||||
Layers = {
|
||||
ColorLayers = {
|
||||
|
||||
@@ -23,8 +23,6 @@ return {
|
||||
Renderable = {
|
||||
Type = "RenderableGlobe",
|
||||
Radii = {2631000, 2631000, 2631000},
|
||||
CameraMinHeight = 300,
|
||||
InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values
|
||||
SegmentsPerPatch = 64,
|
||||
Layers = {
|
||||
ColorLayers = {
|
||||
|
||||
@@ -23,8 +23,6 @@ return {
|
||||
Renderable = {
|
||||
Type = "RenderableGlobe",
|
||||
Radii = {1821300, 1821300, 1821300},
|
||||
CameraMinHeight = 300,
|
||||
InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values
|
||||
SegmentsPerPatch = 64,
|
||||
Layers = {
|
||||
ColorLayers = {
|
||||
|
||||
@@ -34,8 +34,6 @@ return {
|
||||
Renderable = {
|
||||
Type = "RenderableGlobe",
|
||||
Radii = {71492000, 71492000, 66854000},
|
||||
CameraMinHeight = 300,
|
||||
InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values
|
||||
SegmentsPerPatch = 64,
|
||||
Layers = {
|
||||
ColorLayers = {
|
||||
|
||||
@@ -32,11 +32,7 @@ return {
|
||||
Renderable = {
|
||||
Type = "RenderableGlobe",
|
||||
Radii = marsEllipsoid,
|
||||
CameraMinHeight = 10,
|
||||
SegmentsPerPatch = 90,
|
||||
-- Allows camera to go down 10000 meters below the reference ellipsoid
|
||||
-- Useful when having negative height map values
|
||||
InteractionDepthBelowEllipsoid = 10000,
|
||||
Layers = {
|
||||
ColorLayers = {
|
||||
{
|
||||
|
||||
@@ -19,10 +19,7 @@ return {
|
||||
Renderable = {
|
||||
Type = "RenderableGlobe",
|
||||
Radii = {1738140, 1738140, 1735970}, -- Moons's radius
|
||||
CameraMinHeight = 300,
|
||||
SegmentsPerPatch = 64,
|
||||
-- Allows camera to go down 10000 meters below the reference ellipsoid
|
||||
InteractionDepthBelowEllipsoid = 10000, -- Useful when having negative height map values
|
||||
Layers = {
|
||||
ColorLayers = {
|
||||
{
|
||||
|
||||
@@ -31,8 +31,6 @@ return {
|
||||
Renderable = {
|
||||
Type = "RenderableGlobe",
|
||||
Radii = {24764000, 24764000, 24314000},
|
||||
CameraMinHeight = 300,
|
||||
InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values
|
||||
SegmentsPerPatch = 64,
|
||||
Layers = {
|
||||
ColorLayers = {
|
||||
|
||||
@@ -31,8 +31,6 @@ return {
|
||||
Renderable = {
|
||||
Type = "RenderableGlobe",
|
||||
Radii = {60268000, 60268000, 54364000},
|
||||
CameraMinHeight = 300,
|
||||
InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values
|
||||
SegmentsPerPatch = 64,
|
||||
Layers = {
|
||||
ColorLayers = {
|
||||
|
||||
@@ -31,8 +31,6 @@ return {
|
||||
Renderable = {
|
||||
Type = "RenderableGlobe",
|
||||
Radii = {25559000, 25559000, 24973000},
|
||||
CameraMinHeight = 300,
|
||||
InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values
|
||||
SegmentsPerPatch = 64,
|
||||
Layers = {
|
||||
ColorLayers = {
|
||||
|
||||
@@ -36,8 +36,6 @@ return {
|
||||
Renderable = {
|
||||
Type = "RenderableGlobe",
|
||||
Radii = {6051900, 6051900, 6051800},
|
||||
CameraMinHeight = 300,
|
||||
InteractionDepthBelowEllipsoid = 0, -- Useful when having negative height map values
|
||||
SegmentsPerPatch = 64,
|
||||
Layers = {
|
||||
ColorLayers = {
|
||||
|
||||
@@ -62,7 +62,10 @@ class SyncEngine;
|
||||
class TimeManager;
|
||||
class WindowWrapper;
|
||||
|
||||
namespace interaction { class InteractionHandler; }
|
||||
namespace interaction {
|
||||
class NavigationHandler;
|
||||
class KeyBindingManager;
|
||||
}
|
||||
namespace gui { class GUI; }
|
||||
namespace properties { class PropertyOwner; }
|
||||
namespace scripting {
|
||||
@@ -123,7 +126,8 @@ public:
|
||||
TimeManager& timeManager();
|
||||
WindowWrapper& windowWrapper();
|
||||
ghoul::fontrendering::FontManager& fontManager();
|
||||
interaction::InteractionHandler& interactionHandler();
|
||||
interaction::NavigationHandler& navigationHandler();
|
||||
interaction::KeyBindingManager& keyBindingManager();
|
||||
properties::PropertyOwner& globalPropertyOwner();
|
||||
scripting::ScriptEngine& scriptEngine();
|
||||
scripting::ScriptScheduler& scriptScheduler();
|
||||
@@ -197,7 +201,8 @@ private:
|
||||
std::unique_ptr<WindowWrapper> _windowWrapper;
|
||||
std::unique_ptr<ghoul::cmdparser::CommandlineParser> _commandlineParser;
|
||||
std::unique_ptr<ghoul::fontrendering::FontManager> _fontManager;
|
||||
std::unique_ptr<interaction::InteractionHandler> _interactionHandler;
|
||||
std::unique_ptr<interaction::NavigationHandler> _navigationHandler;
|
||||
std::unique_ptr<interaction::KeyBindingManager> _keyBindingManager;
|
||||
std::unique_ptr<scripting::ScriptEngine> _scriptEngine;
|
||||
std::unique_ptr<scripting::ScriptScheduler> _scriptScheduler;
|
||||
std::unique_ptr<VirtualPropertyManager> _virtualPropertyManager;
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
namespace openspace {
|
||||
namespace interaction {
|
||||
|
||||
class InteractionHandler;
|
||||
class NavigationHandler;
|
||||
|
||||
class Controller {
|
||||
public:
|
||||
@@ -41,10 +41,10 @@ public:
|
||||
_handler(nullptr)
|
||||
{}
|
||||
|
||||
void setHandler(InteractionHandler* handler);
|
||||
void setHandler(NavigationHandler* handler);
|
||||
|
||||
protected:
|
||||
InteractionHandler* _handler;
|
||||
NavigationHandler* _handler;
|
||||
};
|
||||
|
||||
} // namespace interaction
|
||||
|
||||
59
include/openspace/interaction/delayedvariable.h
Normal file
59
include/openspace/interaction/delayedvariable.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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___DELAYEDVARIABLE___H__
|
||||
#define __OPENSPACE_CORE___DELAYEDVARIABLE___H__
|
||||
|
||||
namespace openspace {
|
||||
namespace interaction {
|
||||
|
||||
/**
|
||||
* 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 updated as soon as it is set to a value (calling the set() function).
|
||||
*/
|
||||
template <typename T, typename ScaleType>
|
||||
class DelayedVariable {
|
||||
public:
|
||||
DelayedVariable(ScaleType scaleFactor, ScaleType friction);
|
||||
void set(T value, double dt);
|
||||
void decelerate(double dt);
|
||||
void setHard(T value);
|
||||
void setFriction(ScaleType friction);
|
||||
void setScaleFactor(ScaleType scaleFactor);
|
||||
T get() const;
|
||||
|
||||
private:
|
||||
ScaleType _scaleFactor;
|
||||
ScaleType _friction;
|
||||
T _targetValue;
|
||||
T _currentValue;
|
||||
};
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
|
||||
#include "delayedvariable.inl"
|
||||
|
||||
#endif // __OPENSPACE_CORE___DELAYEDVARIABLE___H__
|
||||
76
include/openspace/interaction/delayedvariable.inl
Normal file
76
include/openspace/interaction/delayedvariable.inl
Normal file
@@ -0,0 +1,76 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <ghoul/misc/assert.h>
|
||||
#include <ghoul/glm.h>
|
||||
|
||||
namespace openspace {
|
||||
namespace interaction {
|
||||
|
||||
template <typename T, typename ScaleType>
|
||||
DelayedVariable<T, ScaleType>::DelayedVariable(ScaleType scaleFactor, ScaleType friction)
|
||||
: _scaleFactor(std::move(scaleFactor))
|
||||
, _friction(friction)
|
||||
{
|
||||
ghoul_assert(_friction >= ScaleType(0.0), "Friction must be positive");
|
||||
}
|
||||
|
||||
template <typename T, typename ScaleType>
|
||||
void DelayedVariable<T, ScaleType>::set(T value, double dt) {
|
||||
_targetValue = value;
|
||||
_currentValue = _currentValue + (_targetValue - _currentValue) *
|
||||
glm::min(_scaleFactor * dt, 1.0); // less or equal to 1.0 keeps it stable
|
||||
}
|
||||
|
||||
template <typename T, typename ScaleType>
|
||||
void DelayedVariable<T, ScaleType>::decelerate(double dt) {
|
||||
_currentValue = _currentValue + (- _currentValue) *
|
||||
glm::min(_scaleFactor * _friction * dt, 1.0);
|
||||
// less or equal to 1.0 keeps it stable
|
||||
}
|
||||
|
||||
template <typename T, typename ScaleType>
|
||||
void DelayedVariable<T, ScaleType>::setHard(T value) {
|
||||
_targetValue = value;
|
||||
_currentValue = value;
|
||||
}
|
||||
|
||||
template <typename T, typename ScaleType>
|
||||
void DelayedVariable<T, ScaleType>::setFriction(ScaleType friction) {
|
||||
_friction = friction;
|
||||
ghoul_assert(_friction >= ScaleType(0.0), "Friction must be positive");
|
||||
}
|
||||
|
||||
template <typename T, typename ScaleType>
|
||||
void DelayedVariable<T, ScaleType>::setScaleFactor(ScaleType scaleFactor) {
|
||||
_scaleFactor = scaleFactor;
|
||||
}
|
||||
|
||||
template <typename T, typename ScaleType>
|
||||
T DelayedVariable<T, ScaleType>::get() const {
|
||||
return _currentValue;
|
||||
}
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
70
include/openspace/interaction/inputstate.h
Normal file
70
include/openspace/interaction/inputstate.h
Normal file
@@ -0,0 +1,70 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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___INPUTSTATE___H__
|
||||
#define __OPENSPACE_CORE___INPUTSTATE___H__
|
||||
|
||||
#include <openspace/util/keys.h>
|
||||
#include <openspace/util/mouse.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace openspace {
|
||||
namespace interaction {
|
||||
|
||||
class InputState {
|
||||
public:
|
||||
InputState() = default;
|
||||
~InputState() = default;
|
||||
|
||||
// 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);
|
||||
|
||||
// Accessors
|
||||
const std::list<std::pair<Key, KeyModifier>>& getPressedKeys() const;
|
||||
const std::list<MouseButton>& getPressedMouseButtons() const;
|
||||
glm::dvec2 getMousePosition() const;
|
||||
double getMouseScrollDelta() const;
|
||||
|
||||
bool isKeyPressed(std::pair<Key, KeyModifier> keyModPair) const;
|
||||
bool isKeyPressed(Key key) const;
|
||||
bool isMouseButtonPressed(MouseButton mouseButton) const;
|
||||
|
||||
private:
|
||||
// Input from keyboard and mouse
|
||||
std::list<std::pair<Key, KeyModifier>> _keysDown;
|
||||
std::list<MouseButton> _mouseButtonsDown;
|
||||
glm::dvec2 _mousePosition;
|
||||
double _mouseScrollDelta;
|
||||
};
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_CORE___INPUTSTATE___H__
|
||||
@@ -1,286 +0,0 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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 <openspace/network/parallelconnection.h>
|
||||
#include <openspace/util/mouse.h>
|
||||
#include <openspace/util/keys.h>
|
||||
#include <openspace/util/timeline.h>
|
||||
|
||||
#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/geometry/geodetic3.h>
|
||||
#endif
|
||||
|
||||
#include <list>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class Camera;
|
||||
class SceneGraphNode;
|
||||
|
||||
namespace globebrowsing {
|
||||
class RenderableGlobe;
|
||||
}
|
||||
|
||||
namespace interaction {
|
||||
|
||||
template <typename T>
|
||||
class Interpolator
|
||||
{
|
||||
public:
|
||||
Interpolator(std::function<T(double)> 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<T(double)> _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);
|
||||
|
||||
// Accessors
|
||||
const std::list<std::pair<Key, KeyModifier> >& getPressedKeys() const;
|
||||
const std::list<MouseButton>& getPressedMouseButtons() const;
|
||||
glm::dvec2 getMousePosition() const;
|
||||
double getMouseScrollDelta() const;
|
||||
const std::vector<datamessagestructures::CameraKeyframe>& keyframes() const;
|
||||
|
||||
bool isKeyPressed(std::pair<Key, KeyModifier> keyModPair) const;
|
||||
bool isKeyPressed(Key key) const;
|
||||
bool isMouseButtonPressed(MouseButton mouseButton) const;
|
||||
private:
|
||||
// Input from keyboard and mouse
|
||||
std::list<std::pair<Key, KeyModifier> > _keysDown;
|
||||
std::list<MouseButton> _mouseButtonsDown;
|
||||
glm::dvec2 _mousePosition;
|
||||
double _mouseScrollDelta;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class InteractionMode {
|
||||
public:
|
||||
InteractionMode();
|
||||
virtual ~InteractionMode();
|
||||
|
||||
// Mutators
|
||||
virtual void setFocusNode(SceneGraphNode* focusNode);
|
||||
|
||||
// Accessors
|
||||
SceneGraphNode* focusNode();
|
||||
Interpolator<double>& rotateToFocusNodeInterpolator();
|
||||
virtual bool followingNodeRotation() const = 0;
|
||||
|
||||
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 <typename T, typename ScaleType>
|
||||
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<glm::dvec2, double> velocity;
|
||||
};
|
||||
|
||||
SceneGraphNode* _focusNode = nullptr;
|
||||
glm::dvec3 _previousFocusNodePosition;
|
||||
glm::dquat _previousFocusNodeRotation;
|
||||
|
||||
|
||||
Interpolator<double> _rotateToFocusNodeInterpolator;
|
||||
};
|
||||
|
||||
class KeyframeInteractionMode : public InteractionMode
|
||||
{
|
||||
public:
|
||||
struct CameraPose {
|
||||
glm::dvec3 position;
|
||||
glm::quat rotation;
|
||||
std::string focusNode;
|
||||
bool followFocusNodeRotation;
|
||||
};
|
||||
|
||||
KeyframeInteractionMode();
|
||||
~KeyframeInteractionMode();
|
||||
|
||||
virtual void updateMouseStatesFromInput(const InputState& inputState, double deltaTime);
|
||||
virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime);
|
||||
bool followingNodeRotation() const override;
|
||||
Timeline<CameraPose>& timeline();
|
||||
|
||||
private:
|
||||
Timeline<CameraPose> _cameraPoseTimeline;
|
||||
};
|
||||
|
||||
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> 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);
|
||||
bool followingNodeRotation() const override;
|
||||
|
||||
protected:
|
||||
//void updateCameraStateFromMouseStates(Camera& camera, double deltaTime);
|
||||
std::shared_ptr<MouseStates> _mouseStates;
|
||||
};
|
||||
|
||||
class GlobeBrowsingInteractionMode : public OrbitalInteractionMode
|
||||
{
|
||||
public:
|
||||
GlobeBrowsingInteractionMode(std::shared_ptr<MouseStates> mouseStates);
|
||||
~GlobeBrowsingInteractionMode();
|
||||
|
||||
virtual void setFocusNode(SceneGraphNode* focusNode);
|
||||
//virtual void update(Camera& camera, const InputState& inputState, double deltaTime);
|
||||
virtual void updateCameraStateFromMouseStates(Camera& camera, double deltaTime);
|
||||
bool followingNodeRotation() const override;
|
||||
#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__
|
||||
65
include/openspace/interaction/interpolator.h
Normal file
65
include/openspace/interaction/interpolator.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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___INTERPOLATOR___H__
|
||||
#define __OPENSPACE_CORE___INTERPOLATOR___H__
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace openspace {
|
||||
namespace interaction {
|
||||
|
||||
/*
|
||||
* Interpolates a typename T using a transfer function.
|
||||
*/
|
||||
template <typename T>
|
||||
class Interpolator {
|
||||
public:
|
||||
Interpolator();
|
||||
~Interpolator() = default;
|
||||
|
||||
void start();
|
||||
void end();
|
||||
void setDeltaTime(float deltaTime);
|
||||
void setTransferFunction(std::function<T(float)> transferFunction);
|
||||
void setInterpolationTime(float interpolationTime);
|
||||
void step();
|
||||
|
||||
float deltaTimeScaled() const;
|
||||
T value() const;
|
||||
bool isInterpolating() const;
|
||||
|
||||
private:
|
||||
std::function<T(float)> _transferFunction;
|
||||
float _t;
|
||||
float _interpolationTime;
|
||||
float _scaledDeltaTime;
|
||||
};
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
|
||||
#include "interpolator.inl"
|
||||
|
||||
#endif // __OPENSPACE_CORE___INTERPOLATOR___H__
|
||||
85
include/openspace/interaction/interpolator.inl
Normal file
85
include/openspace/interaction/interpolator.inl
Normal file
@@ -0,0 +1,85 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <ghoul/misc/assert.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
namespace openspace {
|
||||
namespace interaction {
|
||||
|
||||
template <typename T>
|
||||
Interpolator<T>::Interpolator()
|
||||
: _transferFunction([](float t){ return t; })
|
||||
, _t(0.0)
|
||||
, _interpolationTime(1.0) {};
|
||||
|
||||
template <typename T>
|
||||
void Interpolator<T>::start() {
|
||||
_t = 0.0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
void Interpolator<T>::end() {
|
||||
_t = 1.0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Interpolator<T>::setDeltaTime(float deltaTime) {
|
||||
_scaledDeltaTime = deltaTime / _interpolationTime;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Interpolator<T>::setTransferFunction(std::function<T(float)> transferFunction) {
|
||||
_transferFunction = transferFunction;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Interpolator<T>::setInterpolationTime(float interpolationTime) {
|
||||
_interpolationTime = interpolationTime;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void Interpolator<T>::step() {
|
||||
_t += _scaledDeltaTime;
|
||||
_t = glm::clamp(_t, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
float Interpolator<T>::deltaTimeScaled() const {
|
||||
return _scaledDeltaTime;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T Interpolator<T>::value() const {
|
||||
return _transferFunction(_t);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool Interpolator<T>::isInterpolating() const {
|
||||
return _t < 1.0 && _t >= 0.0;
|
||||
}
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
87
include/openspace/interaction/keybindingmanager.h
Normal file
87
include/openspace/interaction/keybindingmanager.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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___KEYBINDINGMANAGER___H__
|
||||
#define __OPENSPACE_CORE___KEYBINDINGMANAGER___H__
|
||||
|
||||
#include <openspace/documentation/documentationgenerator.h>
|
||||
#include <openspace/scripting/lualibrary.h>
|
||||
#include <openspace/util/keys.h>
|
||||
|
||||
#include <ghoul/misc/boolean.h>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class Camera;
|
||||
class SceneGraphNode;
|
||||
|
||||
namespace interaction {
|
||||
|
||||
class KeyBindingManager : public DocumentationGenerator
|
||||
{
|
||||
public:
|
||||
KeyBindingManager();
|
||||
~KeyBindingManager() = default;
|
||||
|
||||
void resetKeyBindings();
|
||||
|
||||
void bindKeyLocal(
|
||||
Key key,
|
||||
KeyModifier modifier,
|
||||
std::string luaCommand,
|
||||
std::string documentation = ""
|
||||
);
|
||||
|
||||
void bindKey(
|
||||
Key key,
|
||||
KeyModifier modifier,
|
||||
std::string luaCommand,
|
||||
std::string documentation = ""
|
||||
);
|
||||
|
||||
static scripting::LuaLibrary luaLibrary();
|
||||
|
||||
// Callback functions
|
||||
void keyboardCallback(Key key, KeyModifier modifier, KeyAction action);
|
||||
|
||||
private:
|
||||
using Synchronized = ghoul::Boolean;
|
||||
|
||||
struct KeyInformation {
|
||||
std::string command;
|
||||
Synchronized synchronization;
|
||||
std::string documentation;
|
||||
};
|
||||
|
||||
std::string generateJson() const override;
|
||||
|
||||
bool _cameraUpdatedFromScript = false;
|
||||
|
||||
std::multimap<KeyWithModifier, KeyInformation> _keyLua;
|
||||
};
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_CORE___KEYBINDINGMANAGER___H__
|
||||
69
include/openspace/interaction/keyframenavigator.h
Normal file
69
include/openspace/interaction/keyframenavigator.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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___KEYFRAMENAVIGATOR___H__
|
||||
#define __OPENSPACE_CORE___KEYFRAMENAVIGATOR___H__
|
||||
|
||||
#include <openspace/util/timeline.h>
|
||||
#include <openspace/network/parallelconnection.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class Camera;
|
||||
|
||||
namespace interaction {
|
||||
|
||||
class KeyframeNavigator
|
||||
{
|
||||
public:
|
||||
struct CameraPose {
|
||||
glm::dvec3 position;
|
||||
glm::quat rotation;
|
||||
std::string focusNode;
|
||||
bool followFocusNodeRotation;
|
||||
};
|
||||
|
||||
KeyframeNavigator() = default;
|
||||
~KeyframeNavigator() = default;
|
||||
|
||||
void updateCamera(Camera& camera);
|
||||
Timeline<CameraPose>& timeline();
|
||||
|
||||
void addKeyframe(double timestamp, KeyframeNavigator::CameraPose pose);
|
||||
void removeKeyframesAfter(double timestamp);
|
||||
void clearKeyframes();
|
||||
size_t nKeyframes() const;
|
||||
const std::vector<datamessagestructures::CameraKeyframe>& keyframes() const;
|
||||
|
||||
private:
|
||||
Timeline<CameraPose> _cameraPoseTimeline;
|
||||
};
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_CORE___KEYFRAMENAVIGATOR___H__
|
||||
80
include/openspace/interaction/mousestate.h
Normal file
80
include/openspace/interaction/mousestate.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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___MOUSESTATE___H__
|
||||
#define __OPENSPACE_CORE___MOUSESTATE___H__
|
||||
|
||||
#include <openspace/interaction/delayedvariable.h>
|
||||
#include <openspace/interaction/inputstate.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
namespace openspace {
|
||||
namespace interaction {
|
||||
|
||||
struct MouseState {
|
||||
MouseState(double scaleFactor);
|
||||
void setFriction(double friction);
|
||||
void setVelocityScaleFactor(double scaleFactor);
|
||||
|
||||
glm::dvec2 previousPosition;
|
||||
DelayedVariable<glm::dvec2, double> velocity;
|
||||
};
|
||||
|
||||
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 globalRotationMouseVelocity() const;
|
||||
glm::dvec2 localRotationMouseVelocity() const;
|
||||
glm::dvec2 truckMovementMouseVelocity() const;
|
||||
glm::dvec2 localRollMouseVelocity() const;
|
||||
glm::dvec2 globalRollMouseVelocity() const;
|
||||
|
||||
private:
|
||||
double _sensitivity;
|
||||
|
||||
MouseState _globalRotationMouseState;
|
||||
MouseState _localRotationMouseState;
|
||||
MouseState _truckMovementMouseState;
|
||||
MouseState _localRollMouseState;
|
||||
MouseState _globalRollMouseState;
|
||||
};
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_CORE___MOUSESTATE___H__
|
||||
@@ -22,14 +22,13 @@
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_CORE___INTERACTIONHANDLER___H__
|
||||
#define __OPENSPACE_CORE___INTERACTIONHANDLER___H__
|
||||
#ifndef __OPENSPACE_CORE___NAVIGATIONHANDLER___H__
|
||||
#define __OPENSPACE_CORE___NAVIGATIONHANDLER___H__
|
||||
|
||||
#include <openspace/documentation/documentationgenerator.h>
|
||||
#include <openspace/properties/propertyowner.h>
|
||||
|
||||
#include <openspace/interaction/interactionmode.h>
|
||||
#include <openspace/network/parallelconnection.h>
|
||||
#include <openspace/interaction/orbitalnavigator.h>
|
||||
#include <openspace/interaction/keyframenavigator.h>
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
@@ -38,10 +37,6 @@
|
||||
|
||||
#include <ghoul/misc/boolean.h>
|
||||
|
||||
#include <list>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class Camera;
|
||||
@@ -49,11 +44,10 @@ class SceneGraphNode;
|
||||
|
||||
namespace interaction {
|
||||
|
||||
class InteractionHandler : public properties::PropertyOwner, public DocumentationGenerator
|
||||
{
|
||||
class NavigationHandler : public properties::PropertyOwner {
|
||||
public:
|
||||
InteractionHandler();
|
||||
~InteractionHandler();
|
||||
NavigationHandler();
|
||||
~NavigationHandler();
|
||||
|
||||
void initialize();
|
||||
void deinitialize();
|
||||
@@ -63,39 +57,9 @@ public:
|
||||
void setCamera(Camera* camera);
|
||||
void resetCameraDirection();
|
||||
|
||||
// Interaction mode setters
|
||||
void setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict);
|
||||
InteractionMode* interactionMode();
|
||||
void setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict);
|
||||
|
||||
void goToChunk(int x, int y, int level);
|
||||
void goToGeo(double latitude, double longitude);
|
||||
|
||||
void resetKeyBindings();
|
||||
|
||||
void addKeyframe(double timestamp, KeyframeInteractionMode::CameraPose pose);
|
||||
void removeKeyframesAfter(double timestamp);
|
||||
void clearKeyframes();
|
||||
size_t nKeyframes() const;
|
||||
const std::vector<datamessagestructures::CameraKeyframe>& keyframes() const;
|
||||
|
||||
void bindKeyLocal(
|
||||
Key key,
|
||||
KeyModifier modifier,
|
||||
std::string luaCommand,
|
||||
std::string documentation = ""
|
||||
);
|
||||
void bindKey(
|
||||
Key key,
|
||||
KeyModifier modifier,
|
||||
std::string luaCommand,
|
||||
std::string documentation = ""
|
||||
);
|
||||
void lockControls();
|
||||
void unlockControls();
|
||||
|
||||
//void update(double deltaTime);
|
||||
void updateCamera(double deltaTime);
|
||||
void updateInputStates(double timeSinceLastUpdate);
|
||||
|
||||
// Accessors
|
||||
ghoul::Dictionary getCameraStateDictionary();
|
||||
@@ -104,15 +68,8 @@ public:
|
||||
glm::quat focusNodeToCameraRotation() const;
|
||||
Camera* camera() const;
|
||||
const InputState& inputState() const;
|
||||
|
||||
/**
|
||||
* Returns the Lua library that contains all Lua functions available to affect the
|
||||
* interaction. The functions contained are
|
||||
* - openspace::luascriptfunctions::setOrigin
|
||||
* \return The Lua library that contains all Lua functions available to affect the
|
||||
* interaction
|
||||
*/
|
||||
static scripting::LuaLibrary luaLibrary();
|
||||
const OrbitalNavigator& orbitalNavigator() const;
|
||||
KeyframeNavigator& keyframeNavigator() const;
|
||||
|
||||
// Callback functions
|
||||
void keyboardCallback(Key key, KeyModifier modifier, KeyAction action);
|
||||
@@ -123,47 +80,26 @@ public:
|
||||
void saveCameraStateToFile(const std::string& filepath);
|
||||
void restoreCameraStateFromFile(const std::string& filepath);
|
||||
|
||||
/**
|
||||
* \return The Lua library that contains all Lua functions available to affect the
|
||||
* interaction
|
||||
*/
|
||||
static scripting::LuaLibrary luaLibrary();
|
||||
private:
|
||||
using Synchronized = ghoul::Boolean;
|
||||
|
||||
struct KeyInformation {
|
||||
std::string command;
|
||||
Synchronized synchronization;
|
||||
std::string documentation;
|
||||
};
|
||||
|
||||
std::string generateJson() const override;
|
||||
|
||||
void setInteractionMode(InteractionMode* interactionMode);
|
||||
|
||||
bool _cameraUpdatedFromScript = false;
|
||||
|
||||
std::multimap<KeyWithModifier, KeyInformation> _keyLua;
|
||||
|
||||
std::unique_ptr<InputState> _inputState;
|
||||
Camera* _camera;
|
||||
|
||||
InteractionMode* _currentInteractionMode;
|
||||
|
||||
std::shared_ptr<OrbitalInteractionMode::MouseStates> _mouseStates;
|
||||
|
||||
std::unique_ptr<OrbitalInteractionMode> _orbitalInteractionMode;
|
||||
std::unique_ptr<GlobeBrowsingInteractionMode> _globeBrowsingInteractionMode;
|
||||
std::unique_ptr<KeyframeInteractionMode> _keyframeInteractionMode;
|
||||
std::unique_ptr<OrbitalNavigator> _orbitalNavigator;
|
||||
std::unique_ptr<KeyframeNavigator> _keyframeNavigator;
|
||||
|
||||
// Properties
|
||||
properties::StringProperty _origin;
|
||||
properties::OptionProperty _interactionModeOption;
|
||||
|
||||
properties::BoolProperty _rotationalFriction;
|
||||
properties::BoolProperty _horizontalFriction;
|
||||
properties::BoolProperty _verticalFriction;
|
||||
|
||||
properties::FloatProperty _sensitivity;
|
||||
properties::FloatProperty _rapidness;
|
||||
properties::BoolProperty _useKeyFrameInteraction;
|
||||
};
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_CORE___INTERACTIONHANDLER___H__
|
||||
#endif // __OPENSPACE_CORE___NAVIGATIONHANDLER___H__
|
||||
197
include/openspace/interaction/orbitalnavigator.h
Normal file
197
include/openspace/interaction/orbitalnavigator.h
Normal file
@@ -0,0 +1,197 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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___ORBITALNAVIGATOR___H__
|
||||
#define __OPENSPACE_CORE___ORBITALNAVIGATOR___H__
|
||||
|
||||
#include <openspace/interaction/delayedvariable.h>
|
||||
#include <openspace/interaction/inputstate.h>
|
||||
#include <openspace/interaction/interpolator.h>
|
||||
#include <openspace/interaction/mousestate.h>
|
||||
|
||||
#include <openspace/properties/propertyowner.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class SceneGraphNode;
|
||||
class Camera;
|
||||
class SurfacePositionHandle;
|
||||
|
||||
namespace interaction {
|
||||
|
||||
class OrbitalNavigator : public properties::PropertyOwner {
|
||||
public:
|
||||
OrbitalNavigator();
|
||||
~OrbitalNavigator();
|
||||
|
||||
void updateMouseStatesFromInput(const InputState& inputState, double deltaTime);
|
||||
void updateCameraStateFromMouseStates(Camera& camera, double deltaTime);
|
||||
void setFocusNode(SceneGraphNode* focusNode);
|
||||
void startInterpolateCameraDirection(const Camera& camera);
|
||||
|
||||
bool followingNodeRotation() const;
|
||||
SceneGraphNode* focusNode() const;
|
||||
|
||||
private:
|
||||
struct CameraRotationDecomposition {
|
||||
glm::dquat localRotation;
|
||||
glm::dquat globalRotation;
|
||||
};
|
||||
|
||||
// Properties
|
||||
properties::BoolProperty _rotationalFriction;
|
||||
properties::BoolProperty _horizontalFriction;
|
||||
properties::BoolProperty _verticalFriction;
|
||||
properties::FloatProperty _followFocusNodeRotationDistance;
|
||||
properties::FloatProperty _minimumAllowedDistance;
|
||||
properties::FloatProperty _sensitivity;
|
||||
properties::FloatProperty _motionLag;
|
||||
|
||||
MouseStates _mouseStates;
|
||||
|
||||
SceneGraphNode* _focusNode = nullptr;
|
||||
glm::dvec3 _previousFocusNodePosition;
|
||||
glm::dquat _previousFocusNodeRotation;
|
||||
|
||||
Interpolator<double> _rotateToFocusNodeInterpolator;
|
||||
Interpolator<double> _followRotationInterpolator;
|
||||
|
||||
/**
|
||||
* Decomposes the cameras rotation in to a global and a local rotation defined by
|
||||
* CameraRotationDecomposition. The global rotation defines the rotation so that the
|
||||
* camera points towards the focus node in the direction opposite to the direction
|
||||
* out from the surface of the object. The local rotation defines the differential
|
||||
* from the global to the current total rotation so that
|
||||
* <code>cameraRotation = globalRotation * localRotation</code>.
|
||||
*/
|
||||
CameraRotationDecomposition decomposeCameraRotation(
|
||||
const glm::dvec3& cameraPosition,
|
||||
const glm::dquat& cameraRotation,
|
||||
const glm::dvec3& cameraLookUp,
|
||||
const glm::dvec3& cameraViewDirection);
|
||||
|
||||
/*
|
||||
* Perform a camera roll on the local camera rotation
|
||||
* \returns a local camera rotation modified with a roll.
|
||||
*/
|
||||
glm::dquat roll(double deltaTime, const glm::dquat& localCameraRotation) const;
|
||||
|
||||
/**
|
||||
* Performs rotation around the cameras x and y axes.
|
||||
* \returns a local camera rotation modified with two degrees of freedom.
|
||||
*/
|
||||
glm::dquat rotateLocally(double deltaTime,
|
||||
const glm::dquat& localCameraRotation) const;
|
||||
|
||||
/**
|
||||
* Interpolates the local rotation towards a 0 rotation.
|
||||
* \returns a modified local rotation interpolated towards 0.
|
||||
*/
|
||||
glm::dquat interpolateLocalRotation(double deltaTime,
|
||||
const glm::dquat& localCameraRotation);
|
||||
|
||||
/**
|
||||
* Translates the horizontal direction. If far from the focus object, this will
|
||||
* result in an orbital rotation around the object. This function does not affect the
|
||||
* rotation but only the position.
|
||||
* \returns a position vector adjusted in the horizontal direction.
|
||||
*/
|
||||
glm::dvec3 translateHorizontally(double deltaTime, const glm::dvec3& cameraPosition,
|
||||
const glm::dvec3& objectPosition,
|
||||
const glm::dquat& focusNodeRotationDiff,
|
||||
const glm::dquat& globalCameraRotation,
|
||||
const SurfacePositionHandle& positionHandle) const;
|
||||
|
||||
/*
|
||||
* Adds rotation to the camera position so that it follows the rotation of the focus
|
||||
* node defined by the differential focusNodeRotationDiff.
|
||||
* \returns a position updated with the rotation defined by focusNodeRotationDiff
|
||||
*/
|
||||
glm::dvec3 followFocusNodeRotation(const glm::dvec3& cameraPosition,
|
||||
const glm::dvec3& objectPosition,
|
||||
const glm::dquat& focusNodeRotationDiff) const;
|
||||
|
||||
/**
|
||||
* Updates the global rotation so that it points towards the focus node.
|
||||
* \returns a global rotation quaternion defining a rotation towards the focus node.
|
||||
*/
|
||||
glm::dquat rotateGlobally(const glm::dquat& globalCameraRotation,
|
||||
const glm::dvec3& objectPosition,
|
||||
const glm::dquat& focusNodeRotationDiff,
|
||||
const glm::dvec3& cameraPosition,
|
||||
const SurfacePositionHandle& positionHandle) const;
|
||||
|
||||
/**
|
||||
* Translates the camera position towards or away from the focus node.
|
||||
* \returns a position vector adjusted in the vertical direction.
|
||||
*/
|
||||
glm::dvec3 translateVertically(double deltaTime, const glm::dvec3& cameraPosition,
|
||||
const glm::dvec3& objectPosition,
|
||||
const SurfacePositionHandle& positionHandle) const;
|
||||
|
||||
/**
|
||||
* Rotates the camera around the out vector of the surface.
|
||||
* \returns a quaternion adjusted to rotate around the out vector of the surface.
|
||||
*/
|
||||
glm::dquat rotateHorizontally(double deltaTime,
|
||||
const glm::dquat& globalCameraRotation,
|
||||
const glm::dvec3& cameraPosition,
|
||||
const SurfacePositionHandle& positionHandle) const;
|
||||
|
||||
/**
|
||||
* Push the camera out to the surface of the object.
|
||||
* \returns a position vector adjusted to be at least minHeightAboveGround meters
|
||||
* above the actual surface of the object
|
||||
*/
|
||||
glm::dvec3 pushToSurface(double minHeightAboveGround,
|
||||
const glm::dvec3& cameraPosition,
|
||||
const glm::dvec3& objectPosition,
|
||||
const SurfacePositionHandle& positionHandle) const;
|
||||
|
||||
/**
|
||||
* Interpolates between rotationDiff and a 0 rotation.
|
||||
*/
|
||||
glm::dquat interpolateRotationDifferential(
|
||||
double deltaTime, double interpolationTime,
|
||||
const glm::dquat& rotationDiff,
|
||||
const glm::dvec3& objectPosition,
|
||||
const glm::dvec3& cameraPosition,
|
||||
const SurfacePositionHandle& positionHandle);
|
||||
|
||||
/**
|
||||
* Calculates a SurfacePositionHandle given a camera position in world space.
|
||||
*/
|
||||
SurfacePositionHandle calculateSurfacePositionHandle(
|
||||
const glm::dvec3 cameraPositionWorldSpace);
|
||||
};
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_CORE___ORBITALNAVIGATOR___H__
|
||||
@@ -42,6 +42,7 @@ namespace openspace {
|
||||
struct RenderData;
|
||||
struct UpdateData;
|
||||
struct RendererTasks;
|
||||
struct SurfacePositionHandle;
|
||||
|
||||
namespace documentation { struct Documentation; }
|
||||
|
||||
@@ -78,6 +79,8 @@ public:
|
||||
virtual void render(const RenderData& data);
|
||||
virtual void render(const RenderData& data, RendererTasks& rendererTask);
|
||||
virtual void update(const UpdateData& data);
|
||||
virtual SurfacePositionHandle calculateSurfacePositionHandle(
|
||||
const glm::dvec3& targetModelSpace);
|
||||
|
||||
RenderBin renderBin() const;
|
||||
void setRenderBin(RenderBin bin);
|
||||
|
||||
@@ -48,6 +48,7 @@ class Translation;
|
||||
class Scale;
|
||||
class Scene;
|
||||
struct UpdateData;
|
||||
struct SurfacePositionHandle;
|
||||
|
||||
namespace documentation { struct Documentation; }
|
||||
|
||||
@@ -91,6 +92,8 @@ public:
|
||||
void removeDependency(SceneGraphNode& dependency, UpdateScene updateScene = UpdateScene::Yes);
|
||||
void clearDependencies(UpdateScene updateScene = UpdateScene::Yes);
|
||||
void setDependencies(const std::vector<SceneGraphNode*>& dependencies, UpdateScene updateScene = UpdateScene::Yes);
|
||||
SurfacePositionHandle calculateSurfacePositionHandle(
|
||||
const glm::dvec3& targetModelSpace);
|
||||
|
||||
const std::vector<SceneGraphNode*>& dependencies() const;
|
||||
const std::vector<SceneGraphNode*>& dependentNodes() const;
|
||||
|
||||
@@ -75,6 +75,21 @@ struct RaycastData {
|
||||
std::string namespaceName;
|
||||
};
|
||||
|
||||
/**
|
||||
* Defines the position of an object relative to a surface. The surface is defined as
|
||||
* a reference surface together with a height offset from that reference surface.
|
||||
*/
|
||||
struct SurfacePositionHandle {
|
||||
/// Vector from the center of the object to the reference surface of the object
|
||||
glm::dvec3 centerToReferenceSurface;
|
||||
/// Direction out from the reference. Can conincide with the surface normal but does
|
||||
/// not have to.
|
||||
glm::dvec3 referenceSurfaceOutDirection;
|
||||
/// Height from the reference surface out to the actual surface in the direction of
|
||||
/// the surface normal. Can be positive or negative.
|
||||
double heightToSurface;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_CORE___UPDATESTRUCTURES___H__
|
||||
|
||||
@@ -102,7 +102,7 @@ Chunk::BoundingHeights Chunk::getBoundingHeights() const {
|
||||
// a single raster image. If it is not we will just use the first raster
|
||||
// (that is channel 0).
|
||||
const size_t HeightChannel = 0;
|
||||
const LayerGroup& heightmaps = layerManager->layerGroup(layergroupid::HeightLayers);
|
||||
const LayerGroup& heightmaps = layerManager->layerGroup(layergroupid::GroupID::HeightLayers);
|
||||
std::vector<ChunkTileSettingsPair> chunkTileSettingPairs =
|
||||
tileselector::getTilesAndSettingsUnsorted(
|
||||
heightmaps, _tileIndex);
|
||||
|
||||
@@ -27,11 +27,10 @@
|
||||
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/tile/quad.h>
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
|
||||
namespace openspace {
|
||||
namespace globebrowsing {
|
||||
|
||||
struct TileIndex;
|
||||
|
||||
class GeodeticPatch {
|
||||
public:
|
||||
|
||||
@@ -25,8 +25,11 @@
|
||||
#include <modules/globebrowsing/globebrowsingmodule.h>
|
||||
|
||||
#include <modules/globebrowsing/cache/memoryawaretilecache.h>
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#include <modules/globebrowsing/geometry/geodeticpatch.h>
|
||||
#include <modules/globebrowsing/globes/renderableglobe.h>
|
||||
#include <modules/globebrowsing/other/distanceswitch.h>
|
||||
#include <modules/globebrowsing/tile/tileindex.h>
|
||||
#include <modules/globebrowsing/tile/rawtiledatareader/gdalwrapper.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/defaulttileprovider.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/singleimageprovider.h>
|
||||
@@ -37,11 +40,11 @@
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileprovider.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileproviderbylevel.h>
|
||||
#include <modules/globebrowsing/tile/tileprovider/tileproviderbyindex.h>
|
||||
|
||||
#include <modules/globebrowsing/rendering/layer/layermanager.h>
|
||||
#include <modules/globebrowsing/rendering/layer/layer.h>
|
||||
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/util/factorymanager.h>
|
||||
|
||||
#include <ghoul/misc/templatefactory.h>
|
||||
@@ -51,6 +54,10 @@
|
||||
|
||||
#include "globebrowsingmodule_lua.inl"
|
||||
|
||||
namespace {
|
||||
const char* _loggerCat = "GlobeBrowsingModule";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
|
||||
GlobeBrowsingModule::GlobeBrowsingModule() : OpenSpaceModule(Name) {}
|
||||
@@ -146,6 +153,18 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const {
|
||||
"any of " + listLayerGroups + ". The third argument is the dictionary"
|
||||
"defining the layer."
|
||||
},
|
||||
{
|
||||
"goToChunk",
|
||||
&globebrowsing::luascriptfunctions::goToChunk,
|
||||
"void",
|
||||
"Go to chunk with given index x, y, level"
|
||||
},
|
||||
{
|
||||
"goToGeo",
|
||||
&globebrowsing::luascriptfunctions::goToGeo,
|
||||
"void",
|
||||
"Go to geographic coordinates latitude and longitude"
|
||||
}
|
||||
},
|
||||
{
|
||||
"${MODULE_GLOBEBROWSING}/scripts/layer_support.lua"
|
||||
@@ -156,6 +175,163 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const {
|
||||
};
|
||||
}
|
||||
|
||||
void GlobeBrowsingModule::goToChunk(int x, int y, int level) {
|
||||
using namespace globebrowsing;
|
||||
Camera* cam = OsEng.navigationHandler().camera();
|
||||
goToChunk(*cam, TileIndex(x,y,level), glm::vec2(0.5, 0.5), true);
|
||||
}
|
||||
|
||||
void GlobeBrowsingModule::goToGeo(double latitude, double longitude) {
|
||||
using namespace globebrowsing;
|
||||
Camera* cam = OsEng.navigationHandler().camera();
|
||||
goToGeodetic2(*cam, Geodetic2(latitude, longitude) / 180 * glm::pi<double>(), true);
|
||||
}
|
||||
|
||||
void GlobeBrowsingModule::goToGeo(double latitude, double longitude,
|
||||
double altitude)
|
||||
{
|
||||
using namespace globebrowsing;
|
||||
|
||||
Camera* cam = OsEng.navigationHandler().camera();
|
||||
goToGeodetic3(
|
||||
*cam,
|
||||
{
|
||||
Geodetic2(latitude, longitude) / 180 * glm::pi<double>(),
|
||||
altitude
|
||||
},
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
void GlobeBrowsingModule::goToChunk(Camera& camera, globebrowsing::TileIndex ti,
|
||||
glm::vec2 uv, bool resetCameraDirection)
|
||||
{
|
||||
using namespace globebrowsing;
|
||||
|
||||
RenderableGlobe* globe = castFocusNodeRenderableToGlobe();
|
||||
if (!globe) {
|
||||
LERROR("Focus node must have a RenderableGlobe renderable.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Camera position in model space
|
||||
glm::dvec3 camPos = camera.positionVec3();
|
||||
glm::dmat4 inverseModelTransform = globe->inverseModelTransform();
|
||||
glm::dvec3 cameraPositionModelSpace =
|
||||
glm::dvec3(inverseModelTransform * glm::dvec4(camPos, 1));
|
||||
|
||||
GeodeticPatch patch(ti);
|
||||
Geodetic2 corner = patch.getCorner(SOUTH_WEST);
|
||||
Geodetic2 positionOnPatch = patch.getSize();
|
||||
positionOnPatch.lat *= uv.y;
|
||||
positionOnPatch.lon *= uv.x;
|
||||
Geodetic2 pointPosition = corner + positionOnPatch;
|
||||
|
||||
glm::dvec3 positionOnEllipsoid =
|
||||
globe->ellipsoid().geodeticSurfaceProjection(cameraPositionModelSpace);
|
||||
double altitude = glm::length(cameraPositionModelSpace - positionOnEllipsoid);
|
||||
|
||||
goToGeodetic3(camera, {pointPosition, altitude}, resetCameraDirection);
|
||||
}
|
||||
|
||||
void GlobeBrowsingModule::goToGeodetic2(Camera& camera,
|
||||
globebrowsing::Geodetic2 geo2,
|
||||
bool resetCameraDirection)
|
||||
{
|
||||
using namespace globebrowsing;
|
||||
|
||||
RenderableGlobe* globe = castFocusNodeRenderableToGlobe();
|
||||
if (!globe) {
|
||||
LERROR("Focus node must have a RenderableGlobe renderable.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Camera position in model space
|
||||
glm::dvec3 camPos = camera.positionVec3();
|
||||
glm::dmat4 inverseModelTransform = globe->inverseModelTransform();
|
||||
glm::dvec3 cameraPositionModelSpace =
|
||||
glm::dvec3(inverseModelTransform * glm::dvec4(camPos, 1));
|
||||
|
||||
glm::dvec3 positionOnEllipsoid =
|
||||
globe->ellipsoid().geodeticSurfaceProjection(cameraPositionModelSpace);
|
||||
double altitude = glm::length(cameraPositionModelSpace - positionOnEllipsoid);
|
||||
|
||||
goToGeodetic3(camera, {geo2, altitude}, resetCameraDirection);
|
||||
}
|
||||
|
||||
void GlobeBrowsingModule::goToGeodetic3(Camera& camera, globebrowsing::Geodetic3 geo3,
|
||||
bool resetCameraDirection)
|
||||
{
|
||||
using namespace globebrowsing;
|
||||
|
||||
RenderableGlobe* globe = castFocusNodeRenderableToGlobe();
|
||||
if (!globe) {
|
||||
LERROR("Focus node must have a RenderableGlobe renderable.");
|
||||
return;
|
||||
}
|
||||
|
||||
glm::dvec3 positionModelSpace = globe->ellipsoid().cartesianPosition(geo3);
|
||||
glm::dmat4 modelTransform = globe->modelTransform();
|
||||
glm::dvec3 positionWorldSpace = modelTransform * glm::dvec4(positionModelSpace, 1.0);
|
||||
camera.setPositionVec3(positionWorldSpace);
|
||||
|
||||
if (resetCameraDirection) {
|
||||
this->resetCameraDirection(camera, geo3.geodetic2);
|
||||
}
|
||||
}
|
||||
|
||||
void GlobeBrowsingModule::resetCameraDirection(Camera& camera, globebrowsing::Geodetic2 geo2)
|
||||
{
|
||||
using namespace globebrowsing;
|
||||
|
||||
RenderableGlobe* globe = castFocusNodeRenderableToGlobe();
|
||||
if (!globe) {
|
||||
LERROR("Focus node must have a RenderableGlobe renderable.");
|
||||
return;
|
||||
}
|
||||
|
||||
// Camera is described in world space
|
||||
glm::dmat4 modelTransform = globe->modelTransform();
|
||||
|
||||
// Lookup vector
|
||||
glm::dvec3 positionModelSpace = globe->ellipsoid().cartesianSurfacePosition(geo2);
|
||||
glm::dvec3 slightlyNorth = globe->ellipsoid().cartesianSurfacePosition(
|
||||
Geodetic2(geo2.lat + 0.001, geo2.lon));
|
||||
glm::dvec3 lookUpModelSpace = glm::normalize(slightlyNorth - positionModelSpace);
|
||||
glm::dvec3 lookUpWorldSpace = glm::dmat3(modelTransform) * lookUpModelSpace;
|
||||
|
||||
// Lookat vector
|
||||
glm::dvec3 lookAtWorldSpace = modelTransform * glm::dvec4(positionModelSpace, 1.0);
|
||||
|
||||
// Eye position
|
||||
glm::dvec3 eye = camera.positionVec3();
|
||||
|
||||
// Matrix
|
||||
glm::dmat4 lookAtMatrix = glm::lookAt(
|
||||
eye, lookAtWorldSpace, lookUpWorldSpace);
|
||||
|
||||
// Set rotation
|
||||
glm::dquat rotation = glm::quat_cast(inverse(lookAtMatrix));
|
||||
camera.setRotation(rotation);
|
||||
}
|
||||
|
||||
globebrowsing::RenderableGlobe* GlobeBrowsingModule::castFocusNodeRenderableToGlobe() {
|
||||
using namespace globebrowsing;
|
||||
|
||||
Renderable* baseRenderable = OsEng.navigationHandler().focusNode()->renderable();
|
||||
if (!baseRenderable) {
|
||||
return nullptr;
|
||||
}
|
||||
if (globebrowsing::RenderableGlobe* globe =
|
||||
dynamic_cast<RenderableGlobe*>(baseRenderable))
|
||||
{
|
||||
return globe;
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string GlobeBrowsingModule::layerGroupNamesList() {
|
||||
std::string listLayerGroups("");
|
||||
for (int i = 0; i < globebrowsing::layergroupid::NUM_LAYER_GROUPS - 1; ++i) {
|
||||
|
||||
@@ -26,11 +26,17 @@
|
||||
#define __OPENSPACE_MODULE_GLOBEBROWSING___GLOBEBROWSING_MODULE___H__
|
||||
|
||||
#include <openspace/util/openspacemodule.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <memory>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class Camera;
|
||||
namespace globebrowsing {
|
||||
class RenderableGlobe;
|
||||
class TileIndex;
|
||||
class Geodetic2;
|
||||
class Geodetic3;
|
||||
|
||||
namespace cache {
|
||||
class MemoryAwareTileCache;
|
||||
}
|
||||
@@ -42,14 +48,26 @@ public:
|
||||
|
||||
GlobeBrowsingModule();
|
||||
|
||||
globebrowsing::cache::MemoryAwareTileCache* tileCache();
|
||||
|
||||
void goToChunk(int x, int y, int level);
|
||||
void goToGeo(double latitude, double longitude);
|
||||
void goToGeo(double latitude, double longitude, double altitude);
|
||||
|
||||
globebrowsing::cache::MemoryAwareTileCache* tileCache();
|
||||
scripting::LuaLibrary luaLibrary() const override;
|
||||
protected:
|
||||
void internalInitialize() override;
|
||||
|
||||
private:
|
||||
|
||||
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,
|
||||
bool resetCameraDirection);
|
||||
void resetCameraDirection(Camera& camera, globebrowsing::Geodetic2 geo2);
|
||||
globebrowsing::RenderableGlobe* castFocusNodeRenderableToGlobe();
|
||||
|
||||
/**
|
||||
\return a comma separated list of layer group names.
|
||||
*/
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <modules/globebrowsing/rendering/layer/layer.h>
|
||||
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/engine/moduleengine.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/rendering/renderable.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
@@ -135,6 +136,47 @@ int deleteLayer(lua_State* L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int goToChunk(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
// Check arguments
|
||||
int nArguments = lua_gettop(L);
|
||||
if (nArguments != 3) {
|
||||
return luaL_error(L, "Expected %i arguments, got %i", 3, nArguments);
|
||||
}
|
||||
|
||||
int x = static_cast<int>(lua_tonumber(L, 1));
|
||||
int y = static_cast<int>(lua_tonumber(L, 2));
|
||||
int level = static_cast<int>(lua_tonumber(L, 3));
|
||||
|
||||
OsEng.moduleEngine().module<GlobeBrowsingModule>()->goToChunk(x, y, level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int goToGeo(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
int nArguments = lua_gettop(L);
|
||||
if (nArguments != 2 && nArguments != 3) {
|
||||
return luaL_error(L, "Expected 2 or 3 arguments.");
|
||||
}
|
||||
|
||||
double latitude = static_cast<int>(lua_tonumber(L, 1));
|
||||
double longitude = static_cast<int>(lua_tonumber(L, 2));
|
||||
|
||||
if (nArguments == 2) {
|
||||
OsEng.moduleEngine().module<GlobeBrowsingModule>()->goToGeo(latitude, longitude);
|
||||
}
|
||||
else if (nArguments == 3) {
|
||||
double altitude = static_cast<int>(lua_tonumber(L, 3));
|
||||
OsEng.moduleEngine().module<GlobeBrowsingModule>()->goToGeo(latitude, longitude,
|
||||
altitude);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
} // namespace luascriptfunctions
|
||||
} // nameapace globebrowsing
|
||||
|
||||
@@ -174,7 +174,7 @@ float ChunkedLodGlobe::getHeight(glm::dvec3 position) const {
|
||||
|
||||
// Get the tile providers for the height maps
|
||||
const std::vector<std::shared_ptr<Layer>>& heightMapLayers =
|
||||
_layerManager->layerGroup(layergroupid::HeightLayers).activeLayers();
|
||||
_layerManager->layerGroup(layergroupid::GroupID::HeightLayers).activeLayers();
|
||||
|
||||
for (const std::shared_ptr<Layer>& layer : heightMapLayers) {
|
||||
tileprovider::TileProvider* tileProvider = layer->tileProvider();
|
||||
|
||||
@@ -32,8 +32,6 @@
|
||||
namespace {
|
||||
const char* keyFrame = "Frame";
|
||||
const char* keyRadii = "Radii";
|
||||
const char* keyInteractionDepthBelowEllipsoid = "InteractionDepthBelowEllipsoid";
|
||||
const char* keyCameraMinHeight = "CameraMinHeight";
|
||||
const char* keySegmentsPerPatch = "SegmentsPerPatch";
|
||||
const char* keyLayers = "Layers";
|
||||
}
|
||||
@@ -86,15 +84,6 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary)
|
||||
double patchSegmentsd;
|
||||
dictionary.getValue(keySegmentsPerPatch, patchSegmentsd);
|
||||
int patchSegments = patchSegmentsd;
|
||||
|
||||
if (!dictionary.getValue(keyInteractionDepthBelowEllipsoid,
|
||||
_interactionDepthBelowEllipsoid)) {
|
||||
_interactionDepthBelowEllipsoid = 0;
|
||||
}
|
||||
|
||||
float cameraMinHeight;
|
||||
dictionary.getValue(keyCameraMinHeight, cameraMinHeight);
|
||||
_generalProperties.cameraMinHeight.set(cameraMinHeight);
|
||||
|
||||
// Init layer manager
|
||||
ghoul::Dictionary layersDictionary;
|
||||
@@ -262,8 +251,33 @@ const std::shared_ptr<const Camera> RenderableGlobe::savedCamera() const {
|
||||
return _savedCamera;
|
||||
}
|
||||
|
||||
double RenderableGlobe::interactionDepthBelowEllipsoid() {
|
||||
return _interactionDepthBelowEllipsoid;
|
||||
SurfacePositionHandle RenderableGlobe::calculateSurfacePositionHandle(
|
||||
const glm::dvec3& targetModelSpace)
|
||||
{
|
||||
glm::dvec3 centerToEllipsoidSurface =
|
||||
_ellipsoid.geodeticSurfaceProjection(targetModelSpace);
|
||||
glm::dvec3 ellipsoidSurfaceToTarget = targetModelSpace - centerToEllipsoidSurface;
|
||||
// ellipsoidSurfaceOutDirection will point towards the target, we want the outward
|
||||
// direction. Therefore it must be flipped in case the target is under the reference
|
||||
// ellipsoid so that it always points outwards
|
||||
glm::dvec3 ellipsoidSurfaceOutDirection = glm::normalize(ellipsoidSurfaceToTarget);
|
||||
if (glm::dot(ellipsoidSurfaceOutDirection, centerToEllipsoidSurface) < 0) {
|
||||
ellipsoidSurfaceOutDirection *= -1.0;
|
||||
}
|
||||
|
||||
double heightToSurface = getHeight(targetModelSpace);
|
||||
heightToSurface = glm::isnan(heightToSurface) ? 0.0 : heightToSurface;
|
||||
centerToEllipsoidSurface = glm::isnan(glm::length(centerToEllipsoidSurface)) ?
|
||||
(glm::dvec3(0.0, 1.0, 0.0) * static_cast<double>(boundingSphere())) :
|
||||
centerToEllipsoidSurface;
|
||||
ellipsoidSurfaceOutDirection = glm::isnan(glm::length(ellipsoidSurfaceOutDirection)) ?
|
||||
glm::dvec3(0.0, 1.0, 0.0) : ellipsoidSurfaceOutDirection;
|
||||
|
||||
return {
|
||||
centerToEllipsoidSurface,
|
||||
ellipsoidSurfaceOutDirection,
|
||||
heightToSurface
|
||||
};
|
||||
}
|
||||
|
||||
void RenderableGlobe::setSaveCamera(std::shared_ptr<Camera> camera) {
|
||||
|
||||
@@ -107,7 +107,11 @@ public:
|
||||
double interactionDepthBelowEllipsoid();
|
||||
|
||||
// Setters
|
||||
void setSaveCamera(std::shared_ptr<Camera> camera);
|
||||
void setSaveCamera(std::shared_ptr<Camera> camera);
|
||||
|
||||
virtual SurfacePositionHandle calculateSurfacePositionHandle(
|
||||
const glm::dvec3& targetModelSpace) override;
|
||||
|
||||
private:
|
||||
// Globes. These are renderables inserted in a distance switch so that the heavier
|
||||
// <code>ChunkedLodGlobe</code> does not have to be rendered at far distances.
|
||||
@@ -119,7 +123,6 @@ private:
|
||||
DistanceSwitch _distanceSwitch;
|
||||
std::shared_ptr<Camera> _savedCamera;
|
||||
|
||||
double _interactionDepthBelowEllipsoid;
|
||||
std::string _frame;
|
||||
double _time;
|
||||
|
||||
|
||||
@@ -228,9 +228,9 @@ void ChunkRenderer::renderChunkGlobally(const Chunk& chunk, const RenderData& da
|
||||
programObject->setUniform("radiiSquared", glm::vec3(ellipsoid.radiiSquared()));
|
||||
|
||||
if (_layerManager->layerGroup(
|
||||
layergroupid::NightLayers).activeLayers().size() > 0 ||
|
||||
layergroupid::GroupID::NightLayers).activeLayers().size() > 0 ||
|
||||
_layerManager->layerGroup(
|
||||
layergroupid::WaterMasks).activeLayers().size() > 0 ||
|
||||
layergroupid::GroupID::WaterMasks).activeLayers().size() > 0 ||
|
||||
chunk.owner().generalProperties().atmosphereEnabled ||
|
||||
chunk.owner().generalProperties().performShading)
|
||||
{
|
||||
|
||||
@@ -58,7 +58,7 @@ void GPULayerGroup::bind(ghoul::opengl::ProgramObject* programObject,
|
||||
int pileSize = layerGroup.pileSize();
|
||||
for (size_t i = 0; i < _gpuActiveLayers.size(); ++i) {
|
||||
// should maybe a proper GPULayer factory
|
||||
_gpuActiveLayers[i] = (category == layergroupid::HeightLayers) ?
|
||||
_gpuActiveLayers[i] = (category == layergroupid::GroupID::HeightLayers) ?
|
||||
std::make_unique<GPUHeightLayer>() :
|
||||
std::make_unique<GPULayer>();
|
||||
std::string nameExtension = "[" + std::to_string(i) + "].";
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
#include <openspace/engine/settingsengine.h>
|
||||
#include <openspace/engine/virtualpropertymanager.h>
|
||||
#include <openspace/engine/wrapper/windowwrapper.h>
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/interaction/luaconsole.h>
|
||||
#include <openspace/network/parallelconnection.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
@@ -70,7 +70,7 @@ OnScreenGUIModule::OnScreenGUIModule()
|
||||
std::vector<properties::PropertyOwner*> res = {
|
||||
&(OsEng.windowWrapper()),
|
||||
&(OsEng.settingsEngine()),
|
||||
&(OsEng.interactionHandler()),
|
||||
&(OsEng.navigationHandler()),
|
||||
&(OsEng.renderEngine()),
|
||||
&(OsEng.parallelConnection()),
|
||||
&(OsEng.console())
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <modules/onscreengui/include/guiorigincomponent.h>
|
||||
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
@@ -42,7 +42,7 @@ GuiOriginComponent::GuiOriginComponent()
|
||||
{}
|
||||
|
||||
void GuiOriginComponent::render() {
|
||||
SceneGraphNode* currentFocus = OsEng.interactionHandler().focusNode();
|
||||
SceneGraphNode* currentFocus = OsEng.navigationHandler().focusNode();
|
||||
|
||||
std::vector<SceneGraphNode*> nodes =
|
||||
OsEng.renderEngine().scene()->allSceneGraphNodes();
|
||||
@@ -70,7 +70,7 @@ void GuiOriginComponent::render() {
|
||||
bool hasChanged = ImGui::Combo("Origin", ¤tPosition, nodeNames.c_str());
|
||||
if (hasChanged) {
|
||||
OsEng.scriptEngine().queueScript(
|
||||
"openspace.setPropertyValue('Interaction.origin', '" +
|
||||
"openspace.setPropertyValue('NavigationHandler.origin', '" +
|
||||
nodes[currentPosition]->name() + "');",
|
||||
scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/util/timemanager.h>
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/network/parallelconnection.h>
|
||||
#include <openspace/network/messagestructures.h>
|
||||
|
||||
@@ -83,7 +83,7 @@ void GuiParallelComponent::renderClientWithHost() {
|
||||
renderClientCommon();
|
||||
|
||||
const size_t nTimeKeyframes = OsEng.timeManager().nKeyframes();
|
||||
const size_t nCameraKeyframes = OsEng.interactionHandler().nKeyframes();
|
||||
const size_t nCameraKeyframes = OsEng.navigationHandler().keyframeNavigator().nKeyframes();
|
||||
|
||||
std::string timeKeyframeInfo = "TimeKeyframes : " + std::to_string(nTimeKeyframes);
|
||||
std::string cameraKeyframeInfo = "CameraKeyframes : " + std::to_string(nCameraKeyframes);
|
||||
|
||||
@@ -31,8 +31,8 @@
|
||||
#include <openspace/util/camera.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/engine/wrapper/windowwrapper.h>
|
||||
#include <openspace/interaction/interactionmode.h>
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
#include <openspace/interaction/orbitalnavigator.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/properties/propertyowner.h>
|
||||
#include <openspace/properties/vectorproperty.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
#include <modules/touch/include/TouchInteraction.h>
|
||||
#include <modules/onscreengui/onscreenguimodule.h>
|
||||
|
||||
#include <openspace/interaction/interactionmode.h>
|
||||
#include <openspace/interaction/orbitalnavigator.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/query/query.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
@@ -530,7 +530,7 @@ void TouchInteraction::computeVelocities(const std::vector<TuioCursor>& list, co
|
||||
case PICK: { // pick something in the scene as focus node
|
||||
if (_selected.size() == 1 && _selected.at(0).node) {
|
||||
setFocusNode(_selected.at(0).node);
|
||||
OsEng.interactionHandler().setFocusNode(_focusNode); // cant do setFocusNode() since TouchInteraction is not subclass of InteractionMode
|
||||
OsEng.navigationHandler().setFocusNode(_focusNode); // cant do setFocusNode() since TouchInteraction is not subclass of InteractionMode
|
||||
|
||||
// rotate camera to look at new focus, using slerp quat
|
||||
glm::dvec3 camToFocus = _focusNode->worldPosition() - _camera->positionVec3();
|
||||
@@ -556,7 +556,7 @@ void TouchInteraction::computeVelocities(const std::vector<TuioCursor>& list, co
|
||||
void TouchInteraction::step(double dt) {
|
||||
using namespace glm;
|
||||
|
||||
setFocusNode(OsEng.interactionHandler().focusNode()); // since functions cant be called directly (TouchInteraction not a subclass of InteractionMode)
|
||||
setFocusNode(OsEng.navigationHandler().focusNode()); // since functions cant be called directly (TouchInteraction not a subclass of InteractionMode)
|
||||
if (_focusNode && _camera) {
|
||||
// Create variables from current state
|
||||
dvec3 camPos = _camera->positionVec3();
|
||||
@@ -776,4 +776,4 @@ void TouchInteraction::setFocusNode(SceneGraphNode* focusNode) {
|
||||
_focusNode = focusNode;
|
||||
}
|
||||
|
||||
} // openspace namespace
|
||||
} // openspace namespace
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/engine/settingsengine.h>
|
||||
#include <openspace/engine/wrapper/windowwrapper.h>
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/rendering/screenspacerenderable.h>
|
||||
|
||||
@@ -156,4 +156,4 @@ TuioEar::TuioEar() {
|
||||
_tuioClient = new TuioClient(_oscReceiver);
|
||||
_tuioClient->addTuioListener(this);
|
||||
_tuioClient->connect();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/engine/settingsengine.h>
|
||||
#include <openspace/engine/wrapper/windowwrapper.h>
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/rendering/screenspacerenderable.h>
|
||||
|
||||
@@ -119,8 +119,8 @@ TouchModule::TouchModule()
|
||||
OsEng.registerModuleCallback(
|
||||
OpenSpaceEngine::CallbackOption::PreSync,
|
||||
[&]() {
|
||||
touch.setCamera(OsEng.interactionHandler().camera());
|
||||
touch.setFocusNode(OsEng.interactionHandler().focusNode());
|
||||
touch.setCamera(OsEng.navigationHandler().camera());
|
||||
touch.setFocusNode(OsEng.navigationHandler().focusNode());
|
||||
|
||||
if (hasNewInput() && OsEng.windowWrapper().isMaster()) {
|
||||
touch.updateStateFromInput(listOfContactPoints, lastProcessed);
|
||||
|
||||
@@ -52,18 +52,18 @@ helper.setCommonKeys = function()
|
||||
|
||||
openspace.bindKey(
|
||||
"f",
|
||||
helper.property.invert('Interaction.horizontalFriction'),
|
||||
helper.property.invert('NavigationHandler.OrbitalNavigator.horizontalFriction'),
|
||||
"Toggles the horizontal friction of the camera. If it is disabled, the camera rotates around the focus object indefinitely."
|
||||
)
|
||||
|
||||
openspace.bindKey(
|
||||
"Shift+f",
|
||||
helper.property.invert('Interaction.verticalFriction'),
|
||||
helper.property.invert('NavigationHandler.OrbitalNavigator.verticalFriction'),
|
||||
"Toggles the vertical friction of the camera. If it is disabled, the camera rises up from or closes in towards the focus object indefinitely."
|
||||
)
|
||||
openspace.bindKey(
|
||||
"Ctrl+f",
|
||||
helper.property.invert('Interaction.rotationalFriction'),
|
||||
helper.property.invert('NavigationHandler.OrbitalNavigator.rotationalFriction'),
|
||||
"Toggles the rotational friction of the camera. If it is disabled, the camera rotates around its own axis indefinitely."
|
||||
)
|
||||
|
||||
|
||||
@@ -42,10 +42,15 @@ set(OPENSPACE_SOURCE
|
||||
${OPENSPACE_BASE_DIR}/src/engine/wrapper/sgctwindowwrapper.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/engine/wrapper/windowwrapper.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/controller.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/interactionhandler.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/interactionmode.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/interactionhandler_lua.inl
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/inputstate.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/keybindingmanager.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/keybindingmanager_lua.inl
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/keyframenavigator.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/luaconsole.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/navigationhandler.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/navigationhandler_lua.inl
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/mousestate.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/orbitalnavigator.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/mission/mission.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/mission/missionmanager.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/mission/missionmanager_lua.inl
|
||||
@@ -181,9 +186,17 @@ set(OPENSPACE_HEADER
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/engine/wrapper/sgctwindowwrapper.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/engine/wrapper/windowwrapper.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/controller.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/interactionhandler.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/interactionmode.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/delayedvariable.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/delayedvariable.inl
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/inputstate.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/interpolator.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/interpolator.inl
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/keybindingmanager.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/keyframenavigator.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/luaconsole.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/mousestate.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/navigationhandler.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/orbitalnavigator.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/mission/mission.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/mission/missionmanager.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/network/networkengine.h
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
#include <openspace/engine/moduleengine.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/engine/wrapper/windowwrapper.h>
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/interaction/keybindingmanager.h>
|
||||
#include <openspace/mission/mission.h>
|
||||
#include <openspace/mission/missionmanager.h>
|
||||
#include <openspace/rendering/renderable.h>
|
||||
@@ -69,7 +70,8 @@ void registerCoreClasses(scripting::ScriptEngine& engine) {
|
||||
engine.addLibrary(RenderEngine::luaLibrary());
|
||||
engine.addLibrary(Scene::luaLibrary());
|
||||
engine.addLibrary(Time::luaLibrary());
|
||||
engine.addLibrary(interaction::InteractionHandler::luaLibrary());
|
||||
engine.addLibrary(interaction::KeyBindingManager::luaLibrary());
|
||||
engine.addLibrary(interaction::NavigationHandler::luaLibrary());
|
||||
engine.addLibrary(ParallelConnection::luaLibrary());
|
||||
engine.addLibrary(ModuleEngine::luaLibrary());
|
||||
engine.addLibrary(scripting::ScriptScheduler::luaLibrary());
|
||||
|
||||
@@ -36,7 +36,8 @@
|
||||
#include <openspace/engine/syncengine.h>
|
||||
#include <openspace/engine/virtualpropertymanager.h>
|
||||
#include <openspace/engine/wrapper/windowwrapper.h>
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/interaction/keybindingmanager.h>
|
||||
#include <openspace/interaction/luaconsole.h>
|
||||
#include <openspace/network/networkengine.h>
|
||||
#include <openspace/network/parallelconnection.h>
|
||||
@@ -140,7 +141,8 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName,
|
||||
, _commandlineParser(new ghoul::cmdparser::CommandlineParser(
|
||||
programName, ghoul::cmdparser::CommandlineParser::AllowUnknownCommands::Yes
|
||||
))
|
||||
, _interactionHandler(new interaction::InteractionHandler)
|
||||
, _navigationHandler(new interaction::NavigationHandler)
|
||||
, _keyBindingManager(new interaction::KeyBindingManager)
|
||||
, _scriptEngine(new scripting::ScriptEngine)
|
||||
, _scriptScheduler(new scripting::ScriptScheduler)
|
||||
, _virtualPropertyManager(new VirtualPropertyManager)
|
||||
@@ -151,10 +153,10 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName,
|
||||
, _shutdown({false, 0.f, 0.f})
|
||||
, _isFirstRenderingFirstFrame(true)
|
||||
{
|
||||
_interactionHandler->setPropertyOwner(_globalPropertyNamespace.get());
|
||||
_navigationHandler->setPropertyOwner(_globalPropertyNamespace.get());
|
||||
|
||||
// New property subowners also have to be added to the OnScreenGuiModule callback!
|
||||
_globalPropertyNamespace->addPropertySubOwner(_interactionHandler.get());
|
||||
_globalPropertyNamespace->addPropertySubOwner(_navigationHandler.get());
|
||||
_globalPropertyNamespace->addPropertySubOwner(_settingsEngine.get());
|
||||
_globalPropertyNamespace->addPropertySubOwner(_renderEngine.get());
|
||||
_globalPropertyNamespace->addPropertySubOwner(_windowWrapper.get());
|
||||
@@ -206,6 +208,7 @@ void OpenSpaceEngine::create(int argc, char** argv,
|
||||
requestClose = false;
|
||||
|
||||
LDEBUG("Initialize FileSystem");
|
||||
|
||||
ghoul::initialize();
|
||||
|
||||
// Initialize the LogManager and add the console log as this will be used every time
|
||||
@@ -219,7 +222,6 @@ void OpenSpaceEngine::create(int argc, char** argv,
|
||||
);
|
||||
LogMgr.addLog(std::make_unique<ConsoleLog>());
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
ghoul::filesystem::File app(argv[0]);
|
||||
std::string dirName = app.directoryName();
|
||||
@@ -515,9 +517,9 @@ void OpenSpaceEngine::initialize() {
|
||||
_settingsEngine->initialize();
|
||||
_settingsEngine->setModules(_moduleEngine->modules());
|
||||
|
||||
// Initialize the InteractionHandler
|
||||
_interactionHandler->initialize();
|
||||
|
||||
// Initialize the NavigationHandler
|
||||
_navigationHandler->initialize();
|
||||
|
||||
// Load a light and a monospaced font
|
||||
loadFonts();
|
||||
|
||||
@@ -601,7 +603,11 @@ void OpenSpaceEngine::loadScene(const std::string& scenePath) {
|
||||
_renderEngine->startFading(1, 3.0);
|
||||
|
||||
scene->initialize();
|
||||
_interactionHandler->setCamera(scene->camera());
|
||||
// Update the scene so that position of objects are set in case they are used in
|
||||
// post sync scripts
|
||||
_renderEngine->updateScene();
|
||||
_navigationHandler->setCamera(scene->camera());
|
||||
_navigationHandler->setFocusNode(scene->camera()->parent());
|
||||
|
||||
try {
|
||||
runPostInitializationScripts(scenePath);
|
||||
@@ -612,7 +618,7 @@ void OpenSpaceEngine::loadScene(const std::string& scenePath) {
|
||||
|
||||
// Write keyboard documentation.
|
||||
if (configurationManager().hasKey(ConfigurationManager::KeyKeyboardShortcuts)) {
|
||||
interactionHandler().writeDocumentation(
|
||||
keyBindingManager().writeDocumentation(
|
||||
absPath(configurationManager().value<std::string>(
|
||||
ConfigurationManager::KeyKeyboardShortcuts
|
||||
))
|
||||
@@ -638,7 +644,7 @@ void OpenSpaceEngine::loadScene(const std::string& scenePath) {
|
||||
void OpenSpaceEngine::deinitialize() {
|
||||
LTRACE("OpenSpaceEngine::deinitialize(begin)");
|
||||
|
||||
_interactionHandler->deinitialize();
|
||||
_navigationHandler->deinitialize();
|
||||
_renderEngine->deinitialize();
|
||||
|
||||
LTRACE("OpenSpaceEngine::deinitialize(end)");
|
||||
@@ -1120,10 +1126,8 @@ void OpenSpaceEngine::preSynchronization() {
|
||||
);
|
||||
}
|
||||
|
||||
_interactionHandler->updateInputStates(dt);
|
||||
|
||||
_renderEngine->updateScene();
|
||||
_interactionHandler->updateCamera(dt);
|
||||
_navigationHandler->updateCamera(dt);
|
||||
_renderEngine->camera()->invalidateCache();
|
||||
|
||||
_parallelConnection->preSynchronization();
|
||||
@@ -1158,9 +1162,6 @@ void OpenSpaceEngine::postSynchronizationPreDraw() {
|
||||
_renderEngine->camera()->invalidateCache();
|
||||
}
|
||||
|
||||
// Step the camera using the current mouse velocities which are synced
|
||||
//_interactionHandler->updateCamera();
|
||||
|
||||
for (const auto& func : _moduleCallbacks.postSyncPreDraw) {
|
||||
func();
|
||||
}
|
||||
@@ -1250,7 +1251,8 @@ void OpenSpaceEngine::keyboardCallback(Key key, KeyModifier mod, KeyAction actio
|
||||
return;
|
||||
}
|
||||
|
||||
_interactionHandler->keyboardCallback(key, mod, action);
|
||||
_navigationHandler->keyboardCallback(key, mod, action);
|
||||
_keyBindingManager->keyboardCallback(key, mod, action);
|
||||
}
|
||||
|
||||
void OpenSpaceEngine::charCallback(unsigned int codepoint, KeyModifier modifier) {
|
||||
@@ -1272,7 +1274,7 @@ void OpenSpaceEngine::mouseButtonCallback(MouseButton button, MouseAction action
|
||||
}
|
||||
}
|
||||
|
||||
_interactionHandler->mouseButtonCallback(button, action);
|
||||
_navigationHandler->mouseButtonCallback(button, action);
|
||||
}
|
||||
|
||||
void OpenSpaceEngine::mousePositionCallback(double x, double y) {
|
||||
@@ -1280,7 +1282,7 @@ void OpenSpaceEngine::mousePositionCallback(double x, double y) {
|
||||
func(x, y);
|
||||
}
|
||||
|
||||
_interactionHandler->mousePositionCallback(x, y);
|
||||
_navigationHandler->mousePositionCallback(x, y);
|
||||
}
|
||||
|
||||
void OpenSpaceEngine::mouseScrollWheelCallback(double posX, double posY) {
|
||||
@@ -1291,7 +1293,7 @@ void OpenSpaceEngine::mouseScrollWheelCallback(double posX, double posY) {
|
||||
}
|
||||
}
|
||||
|
||||
_interactionHandler->mouseScrollWheelCallback(posY);
|
||||
_navigationHandler->mouseScrollWheelCallback(posY);
|
||||
}
|
||||
|
||||
void OpenSpaceEngine::encode() {
|
||||
@@ -1501,9 +1503,14 @@ ghoul::fontrendering::FontManager& OpenSpaceEngine::fontManager() {
|
||||
return *_fontManager;
|
||||
}
|
||||
|
||||
interaction::InteractionHandler& OpenSpaceEngine::interactionHandler() {
|
||||
ghoul_assert(_interactionHandler, "InteractionHandler must not be nullptr");
|
||||
return *_interactionHandler;
|
||||
interaction::NavigationHandler& OpenSpaceEngine::navigationHandler() {
|
||||
ghoul_assert(_navigationHandler, "NavigationHandler must not be nullptr");
|
||||
return *_navigationHandler;
|
||||
}
|
||||
|
||||
interaction::KeyBindingManager& OpenSpaceEngine::keyBindingManager() {
|
||||
ghoul_assert(_keyBindingManager, "KeyBindingManager must not be nullptr");
|
||||
return *_keyBindingManager;
|
||||
}
|
||||
|
||||
properties::PropertyOwner& OpenSpaceEngine::globalPropertyOwner() {
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
|
||||
#include <openspace/interaction/controller.h>
|
||||
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
|
||||
namespace openspace {
|
||||
namespace interaction {
|
||||
|
||||
void Controller::setHandler(InteractionHandler* handler)
|
||||
void Controller::setHandler(NavigationHandler* handler)
|
||||
{
|
||||
_handler = handler;
|
||||
}
|
||||
|
||||
97
src/interaction/inputstate.cpp
Normal file
97
src/interaction/inputstate.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/interaction/inputstate.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace openspace {
|
||||
namespace interaction {
|
||||
|
||||
void InputState::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) {
|
||||
if (action == KeyAction::Press) {
|
||||
_keysDown.emplace_back(key, modifier);
|
||||
}
|
||||
else if (action == KeyAction::Release) {
|
||||
// Remove all key pressings for 'key'
|
||||
_keysDown.remove_if([key](std::pair<Key, KeyModifier> keyModPair)
|
||||
{ return keyModPair.first == key; });
|
||||
}
|
||||
}
|
||||
|
||||
void InputState::mouseButtonCallback(MouseButton button, MouseAction action) {
|
||||
if (action == MouseAction::Press) {
|
||||
_mouseButtonsDown.push_back(button);
|
||||
}
|
||||
else if (action == MouseAction::Release) {
|
||||
// Remove all key pressings for 'button'
|
||||
_mouseButtonsDown.remove_if([button](MouseButton buttonInList)
|
||||
{ return button == buttonInList; });
|
||||
}
|
||||
}
|
||||
|
||||
void InputState::mousePositionCallback(double mouseX, double mouseY) {
|
||||
_mousePosition = glm::dvec2(mouseX, mouseY);
|
||||
}
|
||||
|
||||
void InputState::mouseScrollWheelCallback(double mouseScrollDelta) {
|
||||
_mouseScrollDelta = mouseScrollDelta;
|
||||
}
|
||||
|
||||
const std::list<std::pair<Key, KeyModifier> >& InputState::getPressedKeys() const {
|
||||
return _keysDown;
|
||||
}
|
||||
|
||||
const std::list<MouseButton>& InputState::getPressedMouseButtons() const {
|
||||
return _mouseButtonsDown;
|
||||
}
|
||||
|
||||
glm::dvec2 InputState::getMousePosition() const {
|
||||
return _mousePosition;
|
||||
}
|
||||
|
||||
double InputState::getMouseScrollDelta() const {
|
||||
return _mouseScrollDelta;
|
||||
}
|
||||
|
||||
bool InputState::isKeyPressed(std::pair<Key, KeyModifier> keyModPair) const {
|
||||
return std::find(_keysDown.begin(), _keysDown.end(), keyModPair) != _keysDown.end();
|
||||
}
|
||||
|
||||
bool InputState::isKeyPressed(Key key) const {
|
||||
return std::find_if(_keysDown.begin(), _keysDown.end(),
|
||||
[key](const std::pair<Key, KeyModifier>& keyModPair) {
|
||||
return key == keyModPair.first;
|
||||
}) != _keysDown.end();
|
||||
}
|
||||
|
||||
bool InputState::isMouseButtonPressed(MouseButton mouseButton) const {
|
||||
return std::find(_mouseButtonsDown.begin(), _mouseButtonsDown.end(),
|
||||
mouseButton) != _mouseButtonsDown.end();
|
||||
}
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
@@ -1,563 +0,0 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
#include <openspace/network/parallelconnection.h>
|
||||
|
||||
#include <openspace/openspace.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
#include <openspace/interaction/interactionmode.h>
|
||||
#include <openspace/query/query.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/util/time.h>
|
||||
#include <openspace/util/keys.h>
|
||||
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/misc/interpolator.h>
|
||||
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <glm/gtx/string_cast.hpp>
|
||||
|
||||
#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#endif
|
||||
|
||||
#include <ghoul/glm.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace {
|
||||
const char* _loggerCat = "InteractionHandler";
|
||||
|
||||
const char* KeyFocus = "Focus";
|
||||
const char* KeyPosition = "Position";
|
||||
const char* KeyRotation = "Rotation";
|
||||
|
||||
const char* MainTemplateFilename = "${OPENSPACE_DATA}/web/keybindings/main.hbs";
|
||||
const char* KeybindingTemplateFilename = "${OPENSPACE_DATA}/web/keybindings/keybinding.hbs";
|
||||
const char* JsFilename = "${OPENSPACE_DATA}/web/keybindings/script.js";
|
||||
|
||||
const int IdOrbitalInteractionMode = 0;
|
||||
const char* KeyOrbitalInteractionMode = "Orbital";
|
||||
|
||||
const int IdGlobeBrowsingInteractionMode = 1;
|
||||
const char* KeyGlobeBrowsingInteractionMode = "GlobeBrowsing";
|
||||
|
||||
const int IdKeyframeInteractionMode = 2;
|
||||
const char* KeyKeyframeInteractionMode = "Keyframe";
|
||||
} // namespace
|
||||
|
||||
#include "interactionhandler_lua.inl"
|
||||
|
||||
namespace openspace {
|
||||
namespace interaction {
|
||||
|
||||
// InteractionHandler
|
||||
InteractionHandler::InteractionHandler()
|
||||
: properties::PropertyOwner("Interaction")
|
||||
, DocumentationGenerator(
|
||||
"Documentation",
|
||||
"keybindings",
|
||||
{
|
||||
{ "keybindingTemplate", KeybindingTemplateFilename },
|
||||
{ "mainTemplate", MainTemplateFilename }
|
||||
},
|
||||
JsFilename
|
||||
)
|
||||
, _origin("origin", "Origin", "")
|
||||
, _rotationalFriction("rotationalFriction", "Rotational Friction", true)
|
||||
, _horizontalFriction("horizontalFriction", "Horizontal Friction", true)
|
||||
, _verticalFriction("verticalFriction", "Vertical Friction", true)
|
||||
, _sensitivity("sensitivity", "Sensitivity", 0.5f, 0.001f, 1.f)
|
||||
, _rapidness("rapidness", "Rapidness", 1.f, 0.1f, 60.f)
|
||||
, _interactionModeOption(
|
||||
"interactionMode",
|
||||
"Interaction Mode",
|
||||
properties::OptionProperty::DisplayType::Dropdown
|
||||
)
|
||||
{
|
||||
_origin.onChange([this]() {
|
||||
SceneGraphNode* node = sceneGraphNode(_origin.value());
|
||||
if (!node) {
|
||||
LWARNING("Could not find a node in scenegraph called '" << _origin.value() << "'");
|
||||
return;
|
||||
}
|
||||
setFocusNode(node);
|
||||
resetCameraDirection();
|
||||
});
|
||||
|
||||
// Create the interactionModes
|
||||
_inputState = std::make_unique<InputState>();
|
||||
// Inject the same mouse states to both orbital and global interaction mode
|
||||
_mouseStates = std::make_unique<OrbitalInteractionMode::MouseStates>(_sensitivity * pow(10.0,-4), 1);
|
||||
|
||||
_orbitalInteractionMode = std::make_unique<OrbitalInteractionMode>(_mouseStates);
|
||||
_globeBrowsingInteractionMode = std::make_unique<GlobeBrowsingInteractionMode>(_mouseStates);
|
||||
_keyframeInteractionMode = std::make_unique<KeyframeInteractionMode>();
|
||||
|
||||
_interactionModeOption.addOption(IdOrbitalInteractionMode, KeyOrbitalInteractionMode);
|
||||
_interactionModeOption.addOption(IdGlobeBrowsingInteractionMode, KeyGlobeBrowsingInteractionMode);
|
||||
_interactionModeOption.addOption(IdKeyframeInteractionMode, KeyKeyframeInteractionMode);
|
||||
|
||||
// Set the interactionMode
|
||||
_currentInteractionMode = _orbitalInteractionMode.get();
|
||||
|
||||
// Define lambda functions for changed properties
|
||||
_rotationalFriction.onChange([&]() {
|
||||
_mouseStates->setRotationalFriction(_rotationalFriction);
|
||||
});
|
||||
_horizontalFriction.onChange([&]() {
|
||||
_mouseStates->setHorizontalFriction(_horizontalFriction);
|
||||
});
|
||||
_verticalFriction.onChange([&]() {
|
||||
_mouseStates->setVerticalFriction(_verticalFriction);
|
||||
});
|
||||
_sensitivity.onChange([&]() {
|
||||
_mouseStates->setSensitivity(_sensitivity * pow(10.0,-4));
|
||||
});
|
||||
_rapidness.onChange([&]() {
|
||||
_mouseStates->setVelocityScaleFactor(_rapidness);
|
||||
});
|
||||
|
||||
_interactionModeOption.onChange([this]() {
|
||||
switch(_interactionModeOption.value()) {
|
||||
case IdGlobeBrowsingInteractionMode:
|
||||
setInteractionMode(_globeBrowsingInteractionMode.get());
|
||||
break;
|
||||
case IdKeyframeInteractionMode:
|
||||
setInteractionMode(_keyframeInteractionMode.get());
|
||||
break;
|
||||
case IdOrbitalInteractionMode:
|
||||
default:
|
||||
setInteractionMode(_orbitalInteractionMode.get());
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Add the properties
|
||||
addProperty(_origin);
|
||||
addProperty(_interactionModeOption);
|
||||
|
||||
addProperty(_rotationalFriction);
|
||||
addProperty(_horizontalFriction);
|
||||
addProperty(_verticalFriction);
|
||||
addProperty(_sensitivity);
|
||||
addProperty(_rapidness);
|
||||
}
|
||||
|
||||
InteractionHandler::~InteractionHandler() {
|
||||
|
||||
}
|
||||
|
||||
void InteractionHandler::initialize() {
|
||||
OsEng.parallelConnection().connectionEvent()->subscribe("interactionHandler", "statusChanged", [this]() {
|
||||
if (OsEng.parallelConnection().status() == ParallelConnection::Status::ClientWithHost) {
|
||||
setInteractionMode(_keyframeInteractionMode.get());
|
||||
} else if (_currentInteractionMode == _keyframeInteractionMode.get()) {
|
||||
setInteractionMode(_orbitalInteractionMode.get());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void InteractionHandler::deinitialize() {
|
||||
OsEng.parallelConnection().connectionEvent()->unsubscribe("interactionHandler");
|
||||
}
|
||||
|
||||
void InteractionHandler::setFocusNode(SceneGraphNode* node) {
|
||||
_currentInteractionMode->setFocusNode(node);
|
||||
}
|
||||
|
||||
void InteractionHandler::setCamera(Camera* camera) {
|
||||
_camera = camera;
|
||||
setFocusNode(_camera->parent());
|
||||
}
|
||||
|
||||
void InteractionHandler::resetCameraDirection() {
|
||||
LINFO("Setting camera direction to point at focus node.");
|
||||
_currentInteractionMode->rotateToFocusNodeInterpolator().start();
|
||||
}
|
||||
|
||||
void InteractionHandler::setInteractionMode(InteractionMode* interactionMode) {
|
||||
// Focus node is passed over from the previous interaction mode
|
||||
SceneGraphNode* focusNode = _currentInteractionMode->focusNode();
|
||||
|
||||
// Set the interaction mode
|
||||
_currentInteractionMode = interactionMode;
|
||||
|
||||
// Update the focusnode for the new interaction mode
|
||||
_currentInteractionMode->setFocusNode(focusNode);
|
||||
}
|
||||
|
||||
InteractionMode * InteractionHandler::interactionMode() {
|
||||
return _currentInteractionMode;
|
||||
}
|
||||
|
||||
void InteractionHandler::goToChunk(int x, int y, int level) {
|
||||
if (_currentInteractionMode == _globeBrowsingInteractionMode.get()) {
|
||||
#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
|
||||
_globeBrowsingInteractionMode->goToChunk(*_camera, globebrowsing::TileIndex(x,y,level), glm::vec2(0.5,0.5), true);
|
||||
#endif
|
||||
} else {
|
||||
LWARNING("Interaction mode must be set to 'GlobeBrowsing'");
|
||||
}
|
||||
}
|
||||
|
||||
void InteractionHandler::goToGeo(double latitude, double longitude) {
|
||||
if (_currentInteractionMode == _globeBrowsingInteractionMode.get()) {
|
||||
#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
|
||||
_globeBrowsingInteractionMode->goToGeodetic2(
|
||||
*_camera,
|
||||
globebrowsing::Geodetic2(latitude, longitude) / 180 * glm::pi<double>(), true
|
||||
);
|
||||
#endif
|
||||
} else {
|
||||
LWARNING("Interaction mode must be set to 'GlobeBrowsing'");
|
||||
}
|
||||
}
|
||||
|
||||
void InteractionHandler::lockControls() {
|
||||
|
||||
}
|
||||
|
||||
void InteractionHandler::unlockControls() {
|
||||
|
||||
}
|
||||
|
||||
void InteractionHandler::updateInputStates(double timeSinceLastUpdate) {
|
||||
ghoul_assert(_inputState != nullptr, "InputState cannot be null!");
|
||||
ghoul_assert(_camera != nullptr, "Camera cannot be null!");
|
||||
_currentInteractionMode->updateMouseStatesFromInput(*_inputState, timeSinceLastUpdate);
|
||||
}
|
||||
|
||||
void InteractionHandler::updateCamera(double deltaTime) {
|
||||
ghoul_assert(_inputState != nullptr, "InputState cannot be null!");
|
||||
ghoul_assert(_camera != nullptr, "Camera cannot be null!");
|
||||
|
||||
if (_cameraUpdatedFromScript) {
|
||||
_cameraUpdatedFromScript = false;
|
||||
}
|
||||
else {
|
||||
if (_camera && focusNode()) {
|
||||
_currentInteractionMode->updateCameraStateFromMouseStates(*_camera, deltaTime);
|
||||
_camera->setFocusPositionVec3(focusNode()->worldPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SceneGraphNode* InteractionHandler::focusNode() const {
|
||||
return _currentInteractionMode->focusNode();
|
||||
}
|
||||
|
||||
glm::dvec3 InteractionHandler::focusNodeToCameraVector() const {
|
||||
return _camera->positionVec3() - focusNode()->worldPosition();
|
||||
}
|
||||
|
||||
glm::quat InteractionHandler::focusNodeToCameraRotation() const {
|
||||
glm::dmat4 invWorldRotation = glm::inverse(focusNode()->worldRotationMatrix());
|
||||
return glm::quat(invWorldRotation) * glm::quat(_camera->rotationQuaternion());
|
||||
}
|
||||
|
||||
Camera* InteractionHandler::camera() const {
|
||||
return _camera;
|
||||
}
|
||||
|
||||
const InputState& InteractionHandler::inputState() const {
|
||||
return *_inputState;
|
||||
}
|
||||
|
||||
|
||||
void InteractionHandler::mouseButtonCallback(MouseButton button, MouseAction action) {
|
||||
_inputState->mouseButtonCallback(button, action);
|
||||
}
|
||||
|
||||
void InteractionHandler::mousePositionCallback(double x, double y) {
|
||||
_inputState->mousePositionCallback(x, y);
|
||||
}
|
||||
|
||||
void InteractionHandler::mouseScrollWheelCallback(double pos) {
|
||||
_inputState->mouseScrollWheelCallback(pos);
|
||||
}
|
||||
|
||||
void InteractionHandler::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) {
|
||||
_inputState->keyboardCallback(key, modifier, action);
|
||||
|
||||
if (action == KeyAction::Press || action == KeyAction::Repeat) {
|
||||
// iterate over key bindings
|
||||
auto ret = _keyLua.equal_range({ key, modifier });
|
||||
for (auto it = ret.first; it != ret.second; ++it) {
|
||||
auto remote = it->second.synchronization ?
|
||||
scripting::ScriptEngine::RemoteScripting::Yes :
|
||||
scripting::ScriptEngine::RemoteScripting::No;
|
||||
|
||||
OsEng.scriptEngine().queueScript(it->second.command, remote);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InteractionHandler::setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict) {
|
||||
bool readSuccessful = true;
|
||||
|
||||
std::string focus;
|
||||
glm::dvec3 cameraPosition;
|
||||
glm::dvec4 cameraRotation; // Need to read the quaternion as a vector first.
|
||||
|
||||
readSuccessful &= cameraDict.getValue(KeyFocus, focus);
|
||||
readSuccessful &= cameraDict.getValue(KeyPosition, cameraPosition);
|
||||
readSuccessful &= cameraDict.getValue(KeyRotation, cameraRotation);
|
||||
|
||||
if (!readSuccessful) {
|
||||
throw ghoul::RuntimeError(
|
||||
"Position, Rotation and Focus need to be defined for camera dictionary.");
|
||||
}
|
||||
|
||||
SceneGraphNode* node = sceneGraphNode(focus);
|
||||
if (!node) {
|
||||
throw ghoul::RuntimeError(
|
||||
"Could not find a node in scenegraph called '" + focus + "'");
|
||||
}
|
||||
|
||||
// Set state
|
||||
setFocusNode(node);
|
||||
_camera->setPositionVec3(cameraPosition);
|
||||
_camera->setRotation(glm::dquat(
|
||||
cameraRotation.x, cameraRotation.y, cameraRotation.z, cameraRotation.w));
|
||||
}
|
||||
|
||||
ghoul::Dictionary InteractionHandler::getCameraStateDictionary() {
|
||||
glm::dvec3 cameraPosition;
|
||||
glm::dquat quat;
|
||||
glm::dvec4 cameraRotation;
|
||||
|
||||
cameraPosition = _camera->positionVec3();
|
||||
quat = _camera->rotationQuaternion();
|
||||
cameraRotation = glm::dvec4(quat.w, quat.x, quat.y, quat.z);
|
||||
|
||||
ghoul::Dictionary cameraDict;
|
||||
cameraDict.setValue(KeyPosition, cameraPosition);
|
||||
cameraDict.setValue(KeyRotation, cameraRotation);
|
||||
cameraDict.setValue(KeyFocus, focusNode()->name());
|
||||
|
||||
return cameraDict;
|
||||
}
|
||||
|
||||
void InteractionHandler::saveCameraStateToFile(const std::string& filepath) {
|
||||
if (!filepath.empty()) {
|
||||
auto fullpath = absPath(filepath);
|
||||
LINFO("Saving camera position: " << filepath);
|
||||
|
||||
ghoul::Dictionary cameraDict = getCameraStateDictionary();
|
||||
|
||||
// TODO : Should get the camera state as a dictionary and save the dictionary to
|
||||
// a file in form of a lua state and not use ofstreams here.
|
||||
|
||||
std::ofstream ofs(fullpath.c_str());
|
||||
|
||||
glm::dvec3 p = _camera->positionVec3();
|
||||
glm::dquat q = _camera->rotationQuaternion();
|
||||
|
||||
ofs << "return {" << std::endl;
|
||||
ofs << " " << KeyFocus << " = " << "\"" << focusNode()->name() << "\"" << "," << std::endl;
|
||||
ofs << " " << KeyPosition << " = {"
|
||||
<< std::to_string(p.x) << ", "
|
||||
<< std::to_string(p.y) << ", "
|
||||
<< std::to_string(p.z) << "}," << std::endl;
|
||||
ofs << " " << KeyRotation << " = {"
|
||||
<< std::to_string(q.w) << ", "
|
||||
<< std::to_string(q.x) << ", "
|
||||
<< std::to_string(q.y) << ", "
|
||||
<< std::to_string(q.z) << "}," << std::endl;
|
||||
ofs << "}"<< std::endl;
|
||||
|
||||
ofs.close();
|
||||
}
|
||||
}
|
||||
|
||||
void InteractionHandler::restoreCameraStateFromFile(const std::string& filepath) {
|
||||
LINFO("Reading camera state from file: " << filepath);
|
||||
if (!FileSys.fileExists(filepath))
|
||||
throw ghoul::FileNotFoundError(filepath, "CameraFilePath");
|
||||
|
||||
ghoul::Dictionary cameraDict;
|
||||
try {
|
||||
ghoul::lua::loadDictionaryFromFile(filepath, cameraDict);
|
||||
setCameraStateFromDictionary(cameraDict);
|
||||
_cameraUpdatedFromScript = true;
|
||||
}
|
||||
catch (ghoul::RuntimeError& e) {
|
||||
LWARNING("Unable to set camera position");
|
||||
LWARNING(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
void InteractionHandler::resetKeyBindings() {
|
||||
_keyLua.clear();
|
||||
}
|
||||
|
||||
void InteractionHandler::bindKeyLocal(Key key, KeyModifier modifier,
|
||||
std::string luaCommand, std::string documentation)
|
||||
{
|
||||
_keyLua.insert({
|
||||
{ key, modifier },
|
||||
{ std::move(luaCommand), Synchronized::No, std::move(documentation) }
|
||||
});
|
||||
}
|
||||
|
||||
void InteractionHandler::bindKey(Key key, KeyModifier modifier,
|
||||
std::string luaCommand, std::string documentation)
|
||||
{
|
||||
_keyLua.insert({
|
||||
{ key, modifier },
|
||||
{ std::move(luaCommand), Synchronized::Yes, std::move(documentation) }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
std::string InteractionHandler::generateJson() const {
|
||||
std::stringstream json;
|
||||
json << "[";
|
||||
bool first = true;
|
||||
for (const auto& p : _keyLua) {
|
||||
if (!first) {
|
||||
json << ",";
|
||||
}
|
||||
first = false;
|
||||
json << "{";
|
||||
json << "\"key\": \"" << std::to_string(p.first) << "\",";
|
||||
json << "\"script\": \"" << p.second.command << "\",";
|
||||
json << "\"remoteScripting\": " << (p.second.synchronization ? "true," : "false,");
|
||||
json << "\"documentation\": \"" << p.second.documentation << "\"";
|
||||
json << "}";
|
||||
}
|
||||
json << "]";
|
||||
|
||||
std::string jsonString = "";
|
||||
for (const char& c : json.str()) {
|
||||
if (c == '\'') {
|
||||
jsonString += "\\'";
|
||||
} else {
|
||||
jsonString += c;
|
||||
}
|
||||
}
|
||||
|
||||
return jsonString;
|
||||
}
|
||||
|
||||
|
||||
scripting::LuaLibrary InteractionHandler::luaLibrary() {
|
||||
return{
|
||||
"",
|
||||
{
|
||||
{
|
||||
"clearKeys",
|
||||
&luascriptfunctions::clearKeys,
|
||||
"",
|
||||
"Clear all key bindings"
|
||||
},
|
||||
{
|
||||
"bindKey",
|
||||
&luascriptfunctions::bindKey,
|
||||
"string, string [,string]",
|
||||
"Binds a key by name to a lua string command to execute both locally "
|
||||
"and to broadcast to clients if this is the host of a parallel session. "
|
||||
"The first argument is the key, the second argument is the Lua command "
|
||||
"that is to be executed, and the optional third argument is a human "
|
||||
"readable description of the command for documentation purposes."
|
||||
},
|
||||
{
|
||||
"bindKeyLocal",
|
||||
&luascriptfunctions::bindKeyLocal,
|
||||
"string, string [,string]",
|
||||
"Binds a key by name to a lua string command to execute only locally. "
|
||||
"The first argument is the key, the second argument is the Lua command "
|
||||
"that is to be executed, and the optional third argument is a human "
|
||||
"readable description of the command for documentation purposes."
|
||||
},
|
||||
{
|
||||
"saveCameraStateToFile",
|
||||
&luascriptfunctions::saveCameraStateToFile,
|
||||
"string",
|
||||
"Save the current camera state to file"
|
||||
},
|
||||
{
|
||||
"restoreCameraStateFromFile",
|
||||
&luascriptfunctions::restoreCameraStateFromFile,
|
||||
"string",
|
||||
"Restore the camera state from file"
|
||||
},
|
||||
{
|
||||
"resetCameraDirection",
|
||||
&luascriptfunctions::resetCameraDirection,
|
||||
"void",
|
||||
"Reset the camera direction to point at the focus node"
|
||||
},
|
||||
{
|
||||
"goToChunk",
|
||||
&luascriptfunctions::goToChunk,
|
||||
"void",
|
||||
"Go to chunk with given index x, y, level"
|
||||
},
|
||||
{
|
||||
"goToGeo",
|
||||
&luascriptfunctions::goToGeo,
|
||||
"void",
|
||||
"Go to geographic coordinates latitude and longitude"
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void InteractionHandler::addKeyframe(double timestamp, KeyframeInteractionMode::CameraPose pose) {
|
||||
if (!_keyframeInteractionMode) {
|
||||
return;
|
||||
}
|
||||
_keyframeInteractionMode->timeline().addKeyframe(timestamp, pose);
|
||||
}
|
||||
|
||||
void InteractionHandler::removeKeyframesAfter(double timestamp) {
|
||||
if (!_keyframeInteractionMode) {
|
||||
return;
|
||||
}
|
||||
_keyframeInteractionMode->timeline().removeKeyframesAfter(timestamp);
|
||||
}
|
||||
|
||||
void InteractionHandler::clearKeyframes() {
|
||||
if (!_keyframeInteractionMode) {
|
||||
return;
|
||||
}
|
||||
_keyframeInteractionMode->timeline().clearKeyframes();
|
||||
}
|
||||
|
||||
size_t InteractionHandler::nKeyframes() const {
|
||||
if (!_keyframeInteractionMode) {
|
||||
return 0;
|
||||
}
|
||||
return _keyframeInteractionMode->timeline().keyframes().size();
|
||||
}
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
@@ -1,800 +0,0 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/interaction/interactionmode.h>
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/query/query.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
#include <openspace/util/time.h>
|
||||
#include <openspace/util/keys.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
|
||||
#include <modules/globebrowsing/globes/renderableglobe.h>
|
||||
#include <modules/globebrowsing/globes/chunkedlodglobe.h>
|
||||
#include <modules/globebrowsing/geometry/geodetic2.h>
|
||||
#endif
|
||||
|
||||
#include <glm/gtx/string_cast.hpp>
|
||||
|
||||
namespace {
|
||||
const std::string _loggerCat = "InteractionMode";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace interaction {
|
||||
|
||||
// InputState
|
||||
InputState::InputState() {
|
||||
|
||||
}
|
||||
|
||||
InputState::~InputState() {
|
||||
|
||||
}
|
||||
|
||||
void InputState::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) {
|
||||
if (action == KeyAction::Press) {
|
||||
_keysDown.push_back(std::pair<Key, KeyModifier>(key, modifier));
|
||||
}
|
||||
else if (action == KeyAction::Release) {
|
||||
// Remove all key pressings for 'key'
|
||||
_keysDown.remove_if([key](std::pair<Key, KeyModifier> keyModPair)
|
||||
{ return keyModPair.first == key; });
|
||||
}
|
||||
}
|
||||
|
||||
void InputState::mouseButtonCallback(MouseButton button, MouseAction action) {
|
||||
if (action == MouseAction::Press) {
|
||||
_mouseButtonsDown.push_back(button);
|
||||
}
|
||||
else if (action == MouseAction::Release) {
|
||||
// Remove all key pressings for 'button'
|
||||
_mouseButtonsDown.remove_if([button](MouseButton buttonInList)
|
||||
{ return button == buttonInList; });
|
||||
}
|
||||
}
|
||||
|
||||
void InputState::mousePositionCallback(double mouseX, double mouseY) {
|
||||
_mousePosition = glm::dvec2(mouseX, mouseY);
|
||||
}
|
||||
|
||||
void InputState::mouseScrollWheelCallback(double mouseScrollDelta) {
|
||||
_mouseScrollDelta = mouseScrollDelta;
|
||||
}
|
||||
|
||||
const std::list<std::pair<Key, KeyModifier> >& InputState::getPressedKeys() const {
|
||||
return _keysDown;
|
||||
}
|
||||
|
||||
const std::list<MouseButton>& InputState::getPressedMouseButtons() const {
|
||||
return _mouseButtonsDown;
|
||||
}
|
||||
|
||||
glm::dvec2 InputState::getMousePosition() const {
|
||||
return _mousePosition;
|
||||
}
|
||||
|
||||
double InputState::getMouseScrollDelta() const {
|
||||
return _mouseScrollDelta;
|
||||
}
|
||||
|
||||
bool InputState::isKeyPressed(std::pair<Key, KeyModifier> keyModPair) const {
|
||||
for (auto it = _keysDown.begin(); it != _keysDown.end(); it++) {
|
||||
if (*it == keyModPair) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InputState::isKeyPressed(Key key) const {
|
||||
for (auto it = _keysDown.begin(); it != _keysDown.end(); it++) {
|
||||
if ((*it).first == key) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool InputState::isMouseButtonPressed(MouseButton mouseButton) const {
|
||||
for (auto it = _mouseButtonsDown.begin(); it != _mouseButtonsDown.end(); it++) {
|
||||
if (*it == mouseButton) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
InteractionMode::InteractionMode()
|
||||
: _rotateToFocusNodeInterpolator(Interpolator<double>([](double t){
|
||||
return pow(t, 2);
|
||||
})) {
|
||||
}
|
||||
|
||||
|
||||
InteractionMode::~InteractionMode() {
|
||||
|
||||
}
|
||||
|
||||
void InteractionMode::setFocusNode(SceneGraphNode* focusNode) {
|
||||
_focusNode = focusNode;
|
||||
|
||||
if (_focusNode != nullptr) {
|
||||
_previousFocusNodePosition = _focusNode->worldPosition();
|
||||
_previousFocusNodeRotation = glm::quat_cast(_focusNode->worldRotationMatrix());
|
||||
}
|
||||
}
|
||||
|
||||
SceneGraphNode* InteractionMode::focusNode() {
|
||||
return _focusNode;
|
||||
}
|
||||
|
||||
Interpolator<double>& InteractionMode::rotateToFocusNodeInterpolator() {
|
||||
return _rotateToFocusNodeInterpolator;
|
||||
};
|
||||
|
||||
|
||||
// KeyframeInteractionMode
|
||||
KeyframeInteractionMode::KeyframeInteractionMode()
|
||||
{
|
||||
}
|
||||
|
||||
KeyframeInteractionMode::~KeyframeInteractionMode() {
|
||||
}
|
||||
|
||||
|
||||
void KeyframeInteractionMode::updateMouseStatesFromInput(const InputState&, double) {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
void KeyframeInteractionMode::updateCameraStateFromMouseStates(Camera& camera, double) {
|
||||
double now = OsEng.runTime();
|
||||
|
||||
if (_cameraPoseTimeline.nKeyframes() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Keyframe<CameraPose>* nextKeyframe = _cameraPoseTimeline.firstKeyframeAfter(now);
|
||||
const Keyframe<CameraPose>* prevKeyframe = _cameraPoseTimeline.lastKeyframeBefore(now);
|
||||
double nextTime = 0;
|
||||
double prevTime = 0;
|
||||
double t = 0;
|
||||
|
||||
if (nextKeyframe) {
|
||||
nextTime = nextKeyframe->timestamp;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (prevKeyframe) {
|
||||
prevTime = prevKeyframe->timestamp;
|
||||
t = (now - prevTime) / (nextTime - prevTime);
|
||||
} else {
|
||||
// If there is no keyframe before: Only use the next keyframe.
|
||||
prevTime = nextTime;
|
||||
prevKeyframe = nextKeyframe;
|
||||
t = 1;
|
||||
}
|
||||
|
||||
_cameraPoseTimeline.removeKeyframesBefore(prevTime);
|
||||
|
||||
const CameraPose& prevPose = prevKeyframe->data;
|
||||
const CameraPose& nextPose = nextKeyframe->data;
|
||||
|
||||
Scene* scene = camera.parent()->scene();
|
||||
SceneGraphNode* prevFocusNode = scene->sceneGraphNode(prevPose.focusNode);
|
||||
SceneGraphNode* nextFocusNode = scene->sceneGraphNode(nextPose.focusNode);
|
||||
|
||||
if (!prevFocusNode || !nextFocusNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
glm::dvec3 prevKeyframeCameraPosition = prevPose.position;
|
||||
glm::dvec3 nextKeyframeCameraPosition = nextPose.position;
|
||||
glm::dquat prevKeyframeCameraRotation = prevPose.rotation;
|
||||
glm::dquat nextKeyframeCameraRotation = nextPose.rotation;
|
||||
|
||||
// Transform position and rotation based on focus node rotation (if following rotation)
|
||||
if (prevPose.followFocusNodeRotation) {
|
||||
prevKeyframeCameraRotation = prevFocusNode->worldRotationMatrix() * glm::dmat3(glm::dquat(prevPose.rotation));
|
||||
prevKeyframeCameraPosition = prevFocusNode->worldRotationMatrix() * prevPose.position;
|
||||
}
|
||||
if (nextPose.followFocusNodeRotation) {
|
||||
nextKeyframeCameraRotation = nextFocusNode->worldRotationMatrix() * glm::dmat3(glm::dquat(nextPose.rotation));
|
||||
nextKeyframeCameraPosition = nextFocusNode->worldRotationMatrix() * nextPose.position;
|
||||
}
|
||||
|
||||
// Transform position based on focus node position
|
||||
prevKeyframeCameraPosition += prevFocusNode->worldPosition();
|
||||
nextKeyframeCameraPosition += nextFocusNode->worldPosition();
|
||||
|
||||
// Linear interpolation
|
||||
camera.setPositionVec3(prevKeyframeCameraPosition * (1 - t) + nextKeyframeCameraPosition * t);
|
||||
camera.setRotation(glm::slerp(prevKeyframeCameraRotation, nextKeyframeCameraRotation, t));
|
||||
}
|
||||
|
||||
bool KeyframeInteractionMode::followingNodeRotation() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
Timeline<KeyframeInteractionMode::CameraPose>& KeyframeInteractionMode::timeline() {
|
||||
return _cameraPoseTimeline;
|
||||
}
|
||||
|
||||
// OrbitalInteractionMode
|
||||
OrbitalInteractionMode::MouseStates::MouseStates(double sensitivity, double velocityScaleFactor)
|
||||
: _sensitivity(sensitivity)
|
||||
, _globalRotationMouseState(velocityScaleFactor)
|
||||
, _localRotationMouseState(velocityScaleFactor)
|
||||
, _truckMovementMouseState(velocityScaleFactor)
|
||||
, _localRollMouseState(velocityScaleFactor)
|
||||
, _globalRollMouseState(velocityScaleFactor)
|
||||
{}
|
||||
|
||||
void OrbitalInteractionMode::MouseStates::updateMouseStatesFromInput(const InputState& inputState, double deltaTime) {
|
||||
#ifdef OPENSPACE_MODULE_TOUCH_ENABLED
|
||||
ghoul::any t = property("Global Properties.Touch.TouchInteraction.TouchEvents")->get();
|
||||
if (!*(ghoul::any_cast<bool>(&t))) {
|
||||
#endif // OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
|
||||
glm::dvec2 mousePosition = inputState.getMousePosition();
|
||||
|
||||
bool button1Pressed = inputState.isMouseButtonPressed(MouseButton::Button1);
|
||||
bool button2Pressed = inputState.isMouseButtonPressed(MouseButton::Button2);
|
||||
bool button3Pressed = inputState.isMouseButtonPressed(MouseButton::Button3);
|
||||
bool keyCtrlPressed = inputState.isKeyPressed(Key::LeftControl);
|
||||
bool keyShiftPressed = inputState.isKeyPressed(Key::LeftShift);
|
||||
|
||||
// Update the mouse states
|
||||
if (button1Pressed && !keyShiftPressed) {
|
||||
if (keyCtrlPressed) {
|
||||
glm::dvec2 mousePositionDelta =
|
||||
_localRotationMouseState.previousPosition - mousePosition;
|
||||
_localRotationMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime);
|
||||
|
||||
_globalRotationMouseState.previousPosition = mousePosition;
|
||||
_globalRotationMouseState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
else {
|
||||
glm::dvec2 mousePositionDelta =
|
||||
_globalRotationMouseState.previousPosition - mousePosition;
|
||||
_globalRotationMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime);
|
||||
|
||||
_localRotationMouseState.previousPosition = mousePosition;
|
||||
_localRotationMouseState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
}
|
||||
else { // !button1Pressed
|
||||
_localRotationMouseState.previousPosition = mousePosition;
|
||||
_localRotationMouseState.velocity.decelerate(deltaTime);
|
||||
|
||||
_globalRotationMouseState.previousPosition = mousePosition;
|
||||
_globalRotationMouseState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
if (button2Pressed) {
|
||||
glm::dvec2 mousePositionDelta =
|
||||
_truckMovementMouseState.previousPosition - mousePosition;
|
||||
_truckMovementMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime);
|
||||
}
|
||||
else { // !button2Pressed
|
||||
_truckMovementMouseState.previousPosition = mousePosition;
|
||||
_truckMovementMouseState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
if (button3Pressed || (keyShiftPressed && button1Pressed)) {
|
||||
if (keyCtrlPressed) {
|
||||
glm::dvec2 mousePositionDelta =
|
||||
_localRollMouseState.previousPosition - mousePosition;
|
||||
_localRollMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime);
|
||||
|
||||
_globalRollMouseState.previousPosition = mousePosition;
|
||||
_globalRollMouseState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
else {
|
||||
glm::dvec2 mousePositionDelta =
|
||||
_globalRollMouseState.previousPosition - mousePosition;
|
||||
_globalRollMouseState.velocity.set(mousePositionDelta * _sensitivity, deltaTime);
|
||||
|
||||
_localRollMouseState.previousPosition = mousePosition;
|
||||
_localRollMouseState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
}
|
||||
else { // !button3Pressed
|
||||
_globalRollMouseState.previousPosition = mousePosition;
|
||||
_globalRollMouseState.velocity.decelerate(deltaTime);
|
||||
|
||||
_localRollMouseState.previousPosition = mousePosition;
|
||||
_localRollMouseState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
#ifdef OPENSPACE_MODULE_TOUCH_ENABLED
|
||||
}
|
||||
#endif // OPENSPACE_MODULE_TOUCH_ENABLED
|
||||
|
||||
}
|
||||
|
||||
void OrbitalInteractionMode::MouseStates::setRotationalFriction(double friction) {
|
||||
_localRotationMouseState.setFriction(friction);
|
||||
_localRollMouseState.setFriction(friction);
|
||||
_globalRollMouseState.setFriction(friction);
|
||||
}
|
||||
|
||||
void OrbitalInteractionMode::MouseStates::setHorizontalFriction(double friction) {
|
||||
_globalRotationMouseState.setFriction(friction);
|
||||
}
|
||||
|
||||
void OrbitalInteractionMode::MouseStates::setVerticalFriction(double friction) {
|
||||
_truckMovementMouseState.setFriction(friction);
|
||||
}
|
||||
|
||||
void OrbitalInteractionMode::MouseStates::setSensitivity(double sensitivity) {
|
||||
_sensitivity = sensitivity;
|
||||
}
|
||||
|
||||
void OrbitalInteractionMode::MouseStates::setVelocityScaleFactor(double scaleFactor) {
|
||||
_globalRotationMouseState.setVelocityScaleFactor(scaleFactor);
|
||||
_localRotationMouseState.setVelocityScaleFactor(scaleFactor);
|
||||
_truckMovementMouseState.setVelocityScaleFactor(scaleFactor);
|
||||
_localRollMouseState.setVelocityScaleFactor(scaleFactor);
|
||||
_globalRollMouseState.setVelocityScaleFactor(scaleFactor);
|
||||
}
|
||||
|
||||
glm::dvec2 OrbitalInteractionMode::MouseStates::synchedGlobalRotationMouseVelocity() {
|
||||
return _globalRotationMouseState.velocity.get();
|
||||
}
|
||||
|
||||
glm::dvec2 OrbitalInteractionMode::MouseStates::synchedLocalRotationMouseVelocity() {
|
||||
return _localRotationMouseState.velocity.get();
|
||||
}
|
||||
|
||||
glm::dvec2 OrbitalInteractionMode::MouseStates::synchedTruckMovementMouseVelocity() {
|
||||
return _truckMovementMouseState.velocity.get();
|
||||
}
|
||||
|
||||
glm::dvec2 OrbitalInteractionMode::MouseStates::synchedLocalRollMouseVelocity() {
|
||||
return _localRollMouseState.velocity.get();
|
||||
}
|
||||
|
||||
glm::dvec2 OrbitalInteractionMode::MouseStates::synchedGlobalRollMouseVelocity() {
|
||||
return _globalRollMouseState.velocity.get();
|
||||
}
|
||||
|
||||
OrbitalInteractionMode::OrbitalInteractionMode(
|
||||
std::shared_ptr<MouseStates> mouseStates)
|
||||
: InteractionMode()
|
||||
, _mouseStates(mouseStates) {
|
||||
|
||||
}
|
||||
|
||||
OrbitalInteractionMode::~OrbitalInteractionMode() {
|
||||
|
||||
}
|
||||
|
||||
void OrbitalInteractionMode::updateCameraStateFromMouseStates(Camera& camera, double deltaTime) {
|
||||
// Update synched data
|
||||
|
||||
using namespace glm;
|
||||
if (_focusNode) {
|
||||
// Read the current state of the camera and focus node
|
||||
dvec3 camPos = camera.positionVec3();
|
||||
|
||||
// Follow focus nodes movement
|
||||
dvec3 centerPos = _focusNode->worldPosition();
|
||||
dvec3 focusNodeDiff = centerPos - _previousFocusNodePosition;
|
||||
_previousFocusNodePosition = centerPos;
|
||||
camPos += focusNodeDiff;
|
||||
|
||||
dquat totalRotation = camera.rotationQuaternion();
|
||||
dvec3 directionToCenter = normalize(centerPos - camPos);
|
||||
dvec3 lookUp = camera.lookUpVectorWorldSpace();
|
||||
double boundingSphere = _focusNode->boundingSphere();
|
||||
dvec3 camDirection = camera.viewDirectionWorldSpace();
|
||||
|
||||
// Declare other variables used in interaction calculations
|
||||
double minHeightAboveBoundingSphere = 1;
|
||||
dvec3 centerToCamera = camPos - centerPos;
|
||||
dvec3 centerToBoundingSphere;
|
||||
|
||||
// Create the internal representation of the local and global camera rotations
|
||||
dmat4 lookAtMat = lookAt(
|
||||
dvec3(0, 0, 0),
|
||||
directionToCenter,
|
||||
normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction
|
||||
dquat globalCameraRotation = normalize(quat_cast(inverse(lookAtMat)));
|
||||
dquat localCameraRotation = inverse(globalCameraRotation) * totalRotation;
|
||||
|
||||
{ // Do local roll
|
||||
glm::dquat cameraRollRotation =
|
||||
glm::angleAxis(_mouseStates->synchedLocalRollMouseVelocity().x, dvec3(0, 0, 1));
|
||||
localCameraRotation = localCameraRotation * cameraRollRotation;
|
||||
}
|
||||
if (!_rotateToFocusNodeInterpolator.isInterpolating())
|
||||
{ // Do local rotation
|
||||
dvec3 eulerAngles(_mouseStates->synchedLocalRotationMouseVelocity().y, _mouseStates->synchedLocalRotationMouseVelocity().x, 0);
|
||||
dquat rotationDiff = dquat(eulerAngles);
|
||||
|
||||
localCameraRotation = localCameraRotation * rotationDiff;
|
||||
}
|
||||
else
|
||||
{ // Interpolate local rotation to focus node
|
||||
double t = _rotateToFocusNodeInterpolator.value();
|
||||
localCameraRotation = slerp(localCameraRotation, dquat(dvec3(0.0)), t);
|
||||
_rotateToFocusNodeInterpolator.step(deltaTime * 0.1); // Should probably depend on dt
|
||||
// This is a fast but ugly solution to slow regaining of control...
|
||||
if (t > 0.18) {
|
||||
_rotateToFocusNodeInterpolator.end();
|
||||
}
|
||||
}
|
||||
{ // Do global rotation
|
||||
dvec2 smoothMouseVelocity = _mouseStates->synchedGlobalRotationMouseVelocity();
|
||||
dvec3 eulerAngles(-smoothMouseVelocity.y, -smoothMouseVelocity.x, 0);
|
||||
dquat rotationDiffCamSpace = dquat(eulerAngles);
|
||||
|
||||
dquat newRotationCamspace = globalCameraRotation * rotationDiffCamSpace;
|
||||
dquat rotationDiffWorldSpace = newRotationCamspace * inverse(globalCameraRotation);
|
||||
dvec3 rotationDiffVec3 = centerToCamera * rotationDiffWorldSpace - centerToCamera;
|
||||
|
||||
camPos += rotationDiffVec3;
|
||||
dvec3 centerToCamera = camPos - centerPos;
|
||||
directionToCenter = normalize(-centerToCamera);
|
||||
|
||||
dvec3 lookUpWhenFacingCenter =
|
||||
globalCameraRotation * dvec3(camera.lookUpVectorCameraSpace());
|
||||
dmat4 lookAtMat = lookAt(
|
||||
dvec3(0, 0, 0),
|
||||
directionToCenter,
|
||||
lookUpWhenFacingCenter);
|
||||
globalCameraRotation = normalize(quat_cast(inverse(lookAtMat)));
|
||||
}
|
||||
{ // Move position towards or away from focus node
|
||||
centerToBoundingSphere =
|
||||
-directionToCenter *
|
||||
boundingSphere;
|
||||
camPos += -(centerToCamera - centerToBoundingSphere) *
|
||||
_mouseStates->synchedTruckMovementMouseVelocity().y;
|
||||
}
|
||||
{ // Roll around sphere normal
|
||||
dquat cameraRollRotation =
|
||||
angleAxis(_mouseStates->synchedGlobalRollMouseVelocity().x, -directionToCenter);
|
||||
globalCameraRotation = cameraRollRotation * globalCameraRotation;
|
||||
}
|
||||
{ // Push up to surface
|
||||
dvec3 sphereSurfaceToCamera = camPos - (centerPos + centerToBoundingSphere);
|
||||
|
||||
double distFromSphereSurfaceToCamera = length(sphereSurfaceToCamera);
|
||||
camPos += -directionToCenter *
|
||||
max(minHeightAboveBoundingSphere - distFromSphereSurfaceToCamera, 0.0);
|
||||
}
|
||||
|
||||
// Update the camera state
|
||||
camera.setPositionVec3(camPos);
|
||||
camera.setRotation(globalCameraRotation * localCameraRotation);
|
||||
}
|
||||
}
|
||||
|
||||
bool OrbitalInteractionMode::followingNodeRotation() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void OrbitalInteractionMode::updateMouseStatesFromInput(const InputState& inputState, double deltaTime) {
|
||||
_mouseStates->updateMouseStatesFromInput(inputState, deltaTime);
|
||||
}
|
||||
|
||||
GlobeBrowsingInteractionMode::GlobeBrowsingInteractionMode(std::shared_ptr<MouseStates> mouseStates)
|
||||
: OrbitalInteractionMode(mouseStates)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
GlobeBrowsingInteractionMode::~GlobeBrowsingInteractionMode() {
|
||||
|
||||
}
|
||||
|
||||
void GlobeBrowsingInteractionMode::setFocusNode(SceneGraphNode* focusNode) {
|
||||
InteractionMode::setFocusNode(focusNode);
|
||||
|
||||
#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
|
||||
Renderable* baseRenderable = _focusNode->renderable();
|
||||
if (globebrowsing::RenderableGlobe* globe = dynamic_cast<globebrowsing::RenderableGlobe*>(baseRenderable)) {
|
||||
_globe = globe;
|
||||
}
|
||||
else {
|
||||
LWARNING("Focus node is not a renderable globe. GlobeBrowsingInteraction is not possible");
|
||||
_globe = nullptr;
|
||||
}
|
||||
#endif // OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
|
||||
}
|
||||
|
||||
void GlobeBrowsingInteractionMode::updateCameraStateFromMouseStates(Camera& camera, double deltaTime) {
|
||||
|
||||
#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
|
||||
using namespace glm;
|
||||
if (_focusNode && _globe) {
|
||||
// Declare variables to use in interaction calculations
|
||||
// Shrink interaction ellipsoid to enable interaction below height = 0
|
||||
double ellipsoidShrinkTerm = _globe->interactionDepthBelowEllipsoid();
|
||||
double minHeightAboveGround = _globe->generalProperties().cameraMinHeight;
|
||||
|
||||
// Read the current state of the camera and focusnode
|
||||
dvec3 camPos = camera.positionVec3();
|
||||
dvec3 centerPos = _focusNode->worldPosition();
|
||||
|
||||
// Follow focus nodes movement
|
||||
dvec3 focusNodeDiff = centerPos - _previousFocusNodePosition;
|
||||
_previousFocusNodePosition = centerPos;
|
||||
camPos += focusNodeDiff;
|
||||
|
||||
dquat totalRotation = camera.rotationQuaternion();
|
||||
dvec3 lookUp = camera.lookUpVectorWorldSpace();
|
||||
dvec3 camDirection = camera.viewDirectionWorldSpace();
|
||||
|
||||
// Sampling of height is done in the reference frame of the globe.
|
||||
// Hence, the camera position needs to be transformed with the inverse model matrix
|
||||
glm::dmat4 inverseModelTransform = _globe->inverseModelTransform();
|
||||
glm::dmat4 modelTransform = _globe->modelTransform();
|
||||
glm::dvec3 cameraPositionModelSpace =
|
||||
glm::dvec3(inverseModelTransform * glm::dvec4(camPos, 1));
|
||||
|
||||
dvec3 posDiff = camPos - centerPos;
|
||||
|
||||
dvec3 directionFromSurfaceToCameraModelSpace =
|
||||
_globe->ellipsoid().geodeticSurfaceNormal(
|
||||
_globe->ellipsoid().cartesianToGeodetic2(cameraPositionModelSpace));
|
||||
dvec3 directionFromSurfaceToCamera =
|
||||
normalize(dmat3(modelTransform) * directionFromSurfaceToCameraModelSpace);
|
||||
dvec3 centerToEllipsoidSurface = dmat3(modelTransform) * (_globe->projectOnEllipsoid(cameraPositionModelSpace) -
|
||||
directionFromSurfaceToCameraModelSpace * ellipsoidShrinkTerm);
|
||||
dvec3 ellipsoidSurfaceToCamera = camPos - (centerPos + centerToEllipsoidSurface);
|
||||
|
||||
double heightToSurface =
|
||||
_globe->getHeight(cameraPositionModelSpace) + ellipsoidShrinkTerm;
|
||||
|
||||
double distFromCenterToSurface =
|
||||
length(centerToEllipsoidSurface);
|
||||
double distFromEllipsoidSurfaceToCamera = length(ellipsoidSurfaceToCamera);
|
||||
double distFromCenterToCamera = length(posDiff);
|
||||
double distFromSurfaceToCamera =
|
||||
distFromEllipsoidSurfaceToCamera - heightToSurface;
|
||||
|
||||
// Create the internal representation of the local and global camera rotations
|
||||
dmat4 lookAtMat = lookAt(
|
||||
dvec3(0.0, 0.0, 0.0),
|
||||
-directionFromSurfaceToCamera,
|
||||
normalize(camDirection + lookUp)); // To avoid problem with lookup in up direction
|
||||
dquat globalCameraRotation = normalize(quat_cast(inverse(lookAtMat)));
|
||||
dquat localCameraRotation = inverse(globalCameraRotation) * totalRotation;
|
||||
|
||||
// Rotate with the globe
|
||||
dmat3 globeStateMatrix = _focusNode->worldRotationMatrix();
|
||||
dquat globeRotation = quat_cast(globeStateMatrix);
|
||||
dquat focusNodeRotationDiff = _previousFocusNodeRotation * inverse(globeRotation);
|
||||
_previousFocusNodeRotation = globeRotation;
|
||||
|
||||
{ // Do local roll
|
||||
glm::dquat cameraRollRotation =
|
||||
glm::angleAxis(_mouseStates->synchedLocalRollMouseVelocity().x, dvec3(0, 0, 1));
|
||||
localCameraRotation = localCameraRotation * cameraRollRotation;
|
||||
}
|
||||
if(!_rotateToFocusNodeInterpolator.isInterpolating())
|
||||
{ // Do local rotation
|
||||
glm::dvec3 eulerAngles(_mouseStates->synchedLocalRotationMouseVelocity().y, _mouseStates->synchedLocalRotationMouseVelocity().x, 0);
|
||||
glm::dquat rotationDiff = glm::dquat(eulerAngles);
|
||||
|
||||
localCameraRotation = localCameraRotation * rotationDiff;
|
||||
}
|
||||
else
|
||||
{ // Interpolate local rotation to focus node
|
||||
double t = _rotateToFocusNodeInterpolator.value();
|
||||
localCameraRotation = slerp(localCameraRotation, dquat(dvec3(0.0)), t);
|
||||
_rotateToFocusNodeInterpolator.step(0.002); // Should probably depend on dt
|
||||
// This is a fast but ugly solution to slow regaining of control...
|
||||
if (t > 0.2) {
|
||||
_rotateToFocusNodeInterpolator.end();
|
||||
}
|
||||
}
|
||||
{ // Do global rotation (horizontal movement)
|
||||
glm::dvec3 eulerAngles = glm::dvec3(
|
||||
-_mouseStates->synchedGlobalRotationMouseVelocity().y,
|
||||
-_mouseStates->synchedGlobalRotationMouseVelocity().x,
|
||||
0) * glm::clamp(distFromSurfaceToCamera / distFromCenterToSurface, 0.0, 1.0);
|
||||
glm::dquat rotationDiffCamSpace = glm::dquat(eulerAngles);
|
||||
|
||||
glm::dquat rotationDiffWorldSpace =
|
||||
globalCameraRotation *
|
||||
rotationDiffCamSpace *
|
||||
glm::inverse(globalCameraRotation);
|
||||
|
||||
glm::dvec3 rotationDiffVec3 =
|
||||
(distFromCenterToCamera * directionFromSurfaceToCamera)
|
||||
* rotationDiffWorldSpace
|
||||
- (distFromCenterToCamera * directionFromSurfaceToCamera);
|
||||
|
||||
camPos += rotationDiffVec3;
|
||||
|
||||
posDiff = camPos - centerPos;
|
||||
glm::dvec3 rotationDiffVec3AroundCenter =
|
||||
posDiff
|
||||
* focusNodeRotationDiff
|
||||
- (posDiff);
|
||||
camPos += rotationDiffVec3AroundCenter;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
cameraPositionModelSpace =
|
||||
glm::dvec3(inverseModelTransform * glm::dvec4(camPos, 1));
|
||||
|
||||
directionFromSurfaceToCameraModelSpace =
|
||||
_globe->ellipsoid().geodeticSurfaceNormal(
|
||||
_globe->ellipsoid().cartesianToGeodetic2(cameraPositionModelSpace));
|
||||
directionFromSurfaceToCamera =
|
||||
normalize(dmat3(modelTransform) * directionFromSurfaceToCameraModelSpace);
|
||||
centerToEllipsoidSurface = dmat3(modelTransform) * (_globe->projectOnEllipsoid(cameraPositionModelSpace) -
|
||||
directionFromSurfaceToCameraModelSpace * ellipsoidShrinkTerm);
|
||||
ellipsoidSurfaceToCamera = camPos - (centerPos + centerToEllipsoidSurface);
|
||||
|
||||
|
||||
glm::dvec3 lookUpWhenFacingSurface =
|
||||
inverse(focusNodeRotationDiff) * globalCameraRotation * glm::dvec3(camera.lookUpVectorCameraSpace());
|
||||
glm::dmat4 lookAtMat = glm::lookAt(
|
||||
glm::dvec3(0, 0, 0),
|
||||
-directionFromSurfaceToCamera,
|
||||
lookUpWhenFacingSurface);
|
||||
globalCameraRotation =
|
||||
glm::normalize(glm::quat_cast(glm::inverse(lookAtMat)));
|
||||
}
|
||||
{ // Move position towards or away from focus node
|
||||
camPos += -directionFromSurfaceToCamera * distFromSurfaceToCamera *
|
||||
_mouseStates->synchedTruckMovementMouseVelocity().y;
|
||||
}
|
||||
{ // Roll around ellipsoid normal
|
||||
glm::dquat cameraRollRotation =
|
||||
glm::angleAxis(_mouseStates->synchedGlobalRollMouseVelocity().x, directionFromSurfaceToCamera);
|
||||
globalCameraRotation = cameraRollRotation * globalCameraRotation;
|
||||
}
|
||||
{ // Push up to surface
|
||||
ellipsoidSurfaceToCamera = camPos - (centerPos + centerToEllipsoidSurface);
|
||||
|
||||
// Sampling of height is done in the reference frame of the globe.
|
||||
// Hence, the camera position needs to be transformed with the inverse model matrix
|
||||
glm::dmat4 inverseModelTransform = _globe->inverseModelTransform();
|
||||
glm::dvec3 cameraPositionModelSpace =
|
||||
glm::dvec3(inverseModelTransform * glm::dvec4(camPos, 1));
|
||||
|
||||
distFromEllipsoidSurfaceToCamera = glm::length(ellipsoidSurfaceToCamera);
|
||||
double heightToSurface =
|
||||
_globe->getHeight(cameraPositionModelSpace) + ellipsoidShrinkTerm;
|
||||
double heightToSurfaceAndPadding = heightToSurface + minHeightAboveGround;
|
||||
camPos += directionFromSurfaceToCamera *
|
||||
glm::max(heightToSurfaceAndPadding - distFromEllipsoidSurfaceToCamera, 0.0);
|
||||
}
|
||||
|
||||
// Update the camera state
|
||||
camera.setPositionVec3(camPos);
|
||||
camera.setRotation(globalCameraRotation * localCameraRotation);
|
||||
}
|
||||
#endif // OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
|
||||
}
|
||||
|
||||
bool GlobeBrowsingInteractionMode::followingNodeRotation() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
|
||||
void GlobeBrowsingInteractionMode::goToChunk(Camera& camera,
|
||||
globebrowsing::TileIndex ti, glm::vec2 uv, bool resetCameraDirection) {
|
||||
using namespace globebrowsing;
|
||||
|
||||
// Camera position in model space
|
||||
glm::dvec3 camPos = camera.positionVec3();
|
||||
glm::dmat4 inverseModelTransform = _globe->inverseModelTransform();
|
||||
glm::dvec3 cameraPositionModelSpace =
|
||||
glm::dvec3(inverseModelTransform * glm::dvec4(camPos, 1));
|
||||
|
||||
GeodeticPatch patch(ti);
|
||||
Geodetic2 corner = patch.getCorner(SOUTH_WEST);
|
||||
Geodetic2 positionOnPatch = patch.getSize();
|
||||
positionOnPatch.lat *= uv.y;
|
||||
positionOnPatch.lon *= uv.x;
|
||||
Geodetic2 pointPosition = corner + positionOnPatch;
|
||||
|
||||
glm::dvec3 positionOnEllipsoid =
|
||||
_globe->ellipsoid().geodeticSurfaceProjection(cameraPositionModelSpace);
|
||||
double altitude = glm::length(cameraPositionModelSpace - positionOnEllipsoid);
|
||||
|
||||
goToGeodetic3(camera, {pointPosition, altitude});
|
||||
|
||||
if (resetCameraDirection) {
|
||||
this->resetCameraDirection(camera, pointPosition);
|
||||
}
|
||||
}
|
||||
|
||||
void GlobeBrowsingInteractionMode::goToGeodetic2(Camera& camera,
|
||||
globebrowsing::Geodetic2 geo2, bool resetCameraDirection) {
|
||||
using namespace globebrowsing;
|
||||
|
||||
// Camera position in model space
|
||||
glm::dvec3 camPos = camera.positionVec3();
|
||||
glm::dmat4 inverseModelTransform = _globe->inverseModelTransform();
|
||||
glm::dvec3 cameraPositionModelSpace =
|
||||
glm::dvec3(inverseModelTransform * glm::dvec4(camPos, 1));
|
||||
|
||||
glm::dvec3 positionOnEllipsoid =
|
||||
_globe->ellipsoid().geodeticSurfaceProjection(cameraPositionModelSpace);
|
||||
double altitude = glm::length(cameraPositionModelSpace - positionOnEllipsoid);
|
||||
|
||||
goToGeodetic3(camera, {geo2, altitude});
|
||||
|
||||
if (resetCameraDirection) {
|
||||
this->resetCameraDirection(camera, geo2);
|
||||
}
|
||||
}
|
||||
|
||||
void GlobeBrowsingInteractionMode::goToGeodetic3(Camera& camera, globebrowsing::Geodetic3 geo3) {
|
||||
glm::dvec3 positionModelSpace = _globe->ellipsoid().cartesianPosition(geo3);
|
||||
glm::dmat4 modelTransform = _globe->modelTransform();
|
||||
glm::dvec3 positionWorldSpace = modelTransform * glm::dvec4(positionModelSpace, 1.0);
|
||||
camera.setPositionVec3(positionWorldSpace);
|
||||
}
|
||||
|
||||
void GlobeBrowsingInteractionMode::resetCameraDirection(Camera& camera, globebrowsing::Geodetic2 geo2) {
|
||||
using namespace globebrowsing;
|
||||
|
||||
// Camera is described in world space
|
||||
glm::dmat4 modelTransform = _globe->modelTransform();
|
||||
|
||||
// Lookup vector
|
||||
glm::dvec3 positionModelSpace = _globe->ellipsoid().cartesianSurfacePosition(geo2);
|
||||
glm::dvec3 slightlyNorth = _globe->ellipsoid().cartesianSurfacePosition(
|
||||
Geodetic2(geo2.lat + 0.001, geo2.lon));
|
||||
glm::dvec3 lookUpModelSpace = glm::normalize(slightlyNorth - positionModelSpace);
|
||||
glm::dvec3 lookUpWorldSpace = glm::dmat3(modelTransform) * lookUpModelSpace;
|
||||
|
||||
// Lookat vector
|
||||
glm::dvec3 lookAtWorldSpace = modelTransform * glm::dvec4(positionModelSpace, 1.0);
|
||||
|
||||
// Eye position
|
||||
glm::dvec3 eye = camera.positionVec3();
|
||||
|
||||
// Matrix
|
||||
glm::dmat4 lookAtMatrix = glm::lookAt(
|
||||
eye, lookAtWorldSpace, lookUpWorldSpace);
|
||||
|
||||
// Set rotation
|
||||
glm::dquat rotation = glm::quat_cast(inverse(lookAtMatrix));
|
||||
camera.setRotation(rotation);
|
||||
}
|
||||
|
||||
#endif // OPENSPACE_MODULE_GLOBEBROWSING_ENABLED
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
178
src/interaction/keybindingmanager.cpp
Normal file
178
src/interaction/keybindingmanager.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/interaction/keybindingmanager.h>
|
||||
|
||||
#include <openspace/openspace.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
#include <openspace/query/query.h>
|
||||
#include <openspace/util/keys.h>
|
||||
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
#include <glm/gtx/string_cast.hpp>
|
||||
#include <ghoul/glm.h>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace {
|
||||
const char* MainTemplateFilename = "${OPENSPACE_DATA}/web/keybindings/main.hbs";
|
||||
const char* KeybindingTemplateFilename = "${OPENSPACE_DATA}/web/keybindings/keybinding.hbs";
|
||||
const char* JsFilename = "${OPENSPACE_DATA}/web/keybindings/script.js";
|
||||
} // namespace
|
||||
|
||||
#include "keybindingmanager_lua.inl"
|
||||
|
||||
namespace openspace {
|
||||
namespace interaction {
|
||||
|
||||
KeyBindingManager::KeyBindingManager()
|
||||
: DocumentationGenerator(
|
||||
"Documentation",
|
||||
"keybindings",
|
||||
{
|
||||
{ "keybindingTemplate", KeybindingTemplateFilename },
|
||||
{ "mainTemplate", MainTemplateFilename }
|
||||
},
|
||||
JsFilename
|
||||
)
|
||||
{ }
|
||||
|
||||
void KeyBindingManager::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) {
|
||||
if (action == KeyAction::Press || action == KeyAction::Repeat) {
|
||||
// iterate over key bindings
|
||||
std::pair<std::multimap<KeyWithModifier, KeyInformation>::iterator,
|
||||
std::multimap<KeyWithModifier, KeyInformation>::iterator> ret =
|
||||
_keyLua.equal_range({ key, modifier });
|
||||
for (std::multimap<KeyWithModifier, KeyInformation>::iterator it = ret.first;
|
||||
it != ret.second;
|
||||
++it)
|
||||
{
|
||||
scripting::ScriptEngine::RemoteScripting remote =
|
||||
it->second.synchronization ?
|
||||
scripting::ScriptEngine::RemoteScripting::Yes :
|
||||
scripting::ScriptEngine::RemoteScripting::No;
|
||||
|
||||
OsEng.scriptEngine().queueScript(it->second.command, remote);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyBindingManager::resetKeyBindings() {
|
||||
_keyLua.clear();
|
||||
}
|
||||
|
||||
void KeyBindingManager::bindKeyLocal(Key key, KeyModifier modifier,
|
||||
std::string luaCommand, std::string documentation)
|
||||
{
|
||||
_keyLua.insert({
|
||||
{ key, modifier },
|
||||
{
|
||||
std::move(luaCommand),
|
||||
Synchronized::No,
|
||||
std::move(documentation)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void KeyBindingManager::bindKey(Key key, KeyModifier modifier,
|
||||
std::string luaCommand, std::string documentation)
|
||||
{
|
||||
_keyLua.insert({
|
||||
{ key, modifier },
|
||||
{
|
||||
std::move(luaCommand),
|
||||
Synchronized::Yes,
|
||||
std::move(documentation)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
std::string KeyBindingManager::generateJson() const {
|
||||
std::stringstream json;
|
||||
json << "[";
|
||||
bool first = true;
|
||||
for (const std::pair<KeyWithModifier, KeyInformation>& p : _keyLua) {
|
||||
if (!first) {
|
||||
json << ",";
|
||||
}
|
||||
first = false;
|
||||
json << "{";
|
||||
json << "\"key\": \"" << std::to_string(p.first) << "\",";
|
||||
json << "\"script\": \"" << p.second.command << "\",";
|
||||
json << "\"remoteScripting\": " << (p.second.synchronization ? "true," : "false,");
|
||||
json << "\"documentation\": \"" << p.second.documentation << "\"";
|
||||
json << "}";
|
||||
}
|
||||
json << "]";
|
||||
|
||||
std::string jsonString = "";
|
||||
for (const char& c : json.str()) {
|
||||
if (c == '\'') {
|
||||
jsonString += "\\'";
|
||||
} else {
|
||||
jsonString += c;
|
||||
}
|
||||
}
|
||||
|
||||
return jsonString;
|
||||
}
|
||||
|
||||
scripting::LuaLibrary KeyBindingManager::luaLibrary() {
|
||||
return {
|
||||
"",
|
||||
{
|
||||
{
|
||||
"clearKeys",
|
||||
&luascriptfunctions::clearKeys,
|
||||
"",
|
||||
"Clear all key bindings"
|
||||
},
|
||||
{
|
||||
"bindKey",
|
||||
&luascriptfunctions::bindKey,
|
||||
"string, string [,string]",
|
||||
"Binds a key by name to a lua string command to execute both locally "
|
||||
"and to broadcast to clients if this is the host of a parallel session. "
|
||||
"The first argument is the key, the second argument is the Lua command "
|
||||
"that is to be executed, and the optional third argument is a human "
|
||||
"readable description of the command for documentation purposes."
|
||||
},
|
||||
{
|
||||
"bindKeyLocal",
|
||||
&luascriptfunctions::bindKeyLocal,
|
||||
"string, string [,string]",
|
||||
"Binds a key by name to a lua string command to execute only locally. "
|
||||
"The first argument is the key, the second argument is the Lua command "
|
||||
"that is to be executed, and the optional third argument is a human "
|
||||
"readable description of the command for documentation purposes."
|
||||
},
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
@@ -25,38 +25,6 @@
|
||||
namespace openspace {
|
||||
|
||||
namespace luascriptfunctions {
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* setOrigin():
|
||||
* Set the origin of the camera
|
||||
*/
|
||||
int setOrigin(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
int nArguments = lua_gettop(L);
|
||||
if (nArguments != 1)
|
||||
return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments);
|
||||
|
||||
const int type = lua_type(L, -1);
|
||||
if (type != LUA_TSTRING)
|
||||
return luaL_error(L, "Expected string, got %i", type);
|
||||
|
||||
std::string s = luaL_checkstring(L, -1);
|
||||
|
||||
SceneGraphNode* node = sceneGraphNode(s);
|
||||
if (!node) {
|
||||
LWARNINGC(
|
||||
"lua.setOrigin",
|
||||
"Could not find a node in scenegraph called '" << s << "'"
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
OsEng.interactionHandler().setFocusNode(node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* bindKey():
|
||||
@@ -95,7 +63,7 @@ int bindKey(lua_State* L) {
|
||||
documentation = luaL_checkstring(L, DocumentationLocation);
|
||||
}
|
||||
|
||||
OsEng.interactionHandler().bindKey(
|
||||
OsEng.keyBindingManager().bindKey(
|
||||
iKey.key,
|
||||
iKey.modifier,
|
||||
std::move(command),
|
||||
@@ -141,7 +109,7 @@ int bindKeyLocal(lua_State* L) {
|
||||
documentation = luaL_checkstring(L, DocumentationLocation);
|
||||
}
|
||||
|
||||
OsEng.interactionHandler().bindKeyLocal(
|
||||
OsEng.keyBindingManager().bindKeyLocal(
|
||||
iKey.key,
|
||||
iKey.modifier,
|
||||
std::move(command),
|
||||
@@ -151,7 +119,6 @@ int bindKeyLocal(lua_State* L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* clearKeys():
|
||||
@@ -164,89 +131,11 @@ int clearKeys(lua_State* L) {
|
||||
if (nArguments != 0)
|
||||
return luaL_error(L, "Expected %i arguments, got %i", 0, nArguments);
|
||||
|
||||
OsEng.interactionHandler().resetKeyBindings();
|
||||
OsEng.keyBindingManager().resetKeyBindings();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int goToChunk(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
int nArguments = lua_gettop(L);
|
||||
if (nArguments != 3)
|
||||
return luaL_error(L, "Expected %i arguments, got %i", 3, nArguments);
|
||||
|
||||
int x = static_cast<int>(lua_tonumber(L, 1));
|
||||
int y = static_cast<int>(lua_tonumber(L, 2));
|
||||
int level = static_cast<int>(lua_tonumber(L, 3));
|
||||
|
||||
OsEng.interactionHandler().goToChunk(x, y, level);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int goToGeo(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
int nArguments = lua_gettop(L);
|
||||
if (nArguments != 2)
|
||||
return luaL_error(L, "Expected %i arguments, got %i", 2, nArguments);
|
||||
|
||||
double latitude = static_cast<int>(lua_tonumber(L, 1));
|
||||
double longitude = static_cast<int>(lua_tonumber(L, 2));
|
||||
|
||||
OsEng.interactionHandler().goToGeo(latitude, longitude);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int restoreCameraStateFromFile(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
int nArguments = lua_gettop(L);
|
||||
if (nArguments != 1)
|
||||
return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments);
|
||||
|
||||
std::string cameraStateFilePath = luaL_checkstring(L, -1);
|
||||
|
||||
if (cameraStateFilePath.empty()) {
|
||||
return luaL_error(L, "filepath string is empty");
|
||||
}
|
||||
|
||||
OsEng.interactionHandler().restoreCameraStateFromFile(cameraStateFilePath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int saveCameraStateToFile(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
int nArguments = lua_gettop(L);
|
||||
if (nArguments != 1)
|
||||
return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments);
|
||||
|
||||
std::string cameraStateFilePath = luaL_checkstring(L, -1);
|
||||
|
||||
if (cameraStateFilePath.empty()) {
|
||||
return luaL_error(L, "filepath string is empty");
|
||||
}
|
||||
|
||||
OsEng.interactionHandler().saveCameraStateToFile(cameraStateFilePath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int resetCameraDirection(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
int nArguments = lua_gettop(L);
|
||||
if (nArguments != 0) {
|
||||
return luaL_error(L, "Expected %i arguments, got %i", 0, nArguments);
|
||||
}
|
||||
|
||||
OsEng.interactionHandler().resetCameraDirection();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
} // namespace luascriptfunctions
|
||||
|
||||
} // namespace openspace
|
||||
127
src/interaction/keyframenavigator.cpp
Normal file
127
src/interaction/keyframenavigator.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/interaction/keyframenavigator.h>
|
||||
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
#include <openspace/util/camera.h>
|
||||
#include <openspace/util/time.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
namespace openspace {
|
||||
namespace interaction {
|
||||
|
||||
void KeyframeNavigator::updateCamera(Camera& camera) {
|
||||
double now = OsEng.runTime();
|
||||
|
||||
if (_cameraPoseTimeline.nKeyframes() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const Keyframe<CameraPose>* nextKeyframe = _cameraPoseTimeline.firstKeyframeAfter(now);
|
||||
const Keyframe<CameraPose>* prevKeyframe = _cameraPoseTimeline.lastKeyframeBefore(now);
|
||||
double nextTime = 0;
|
||||
double prevTime = 0;
|
||||
double t = 0;
|
||||
|
||||
if (nextKeyframe) {
|
||||
nextTime = nextKeyframe->timestamp;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
if (prevKeyframe) {
|
||||
prevTime = prevKeyframe->timestamp;
|
||||
t = (now - prevTime) / (nextTime - prevTime);
|
||||
} else {
|
||||
// If there is no keyframe before: Only use the next keyframe.
|
||||
prevTime = nextTime;
|
||||
prevKeyframe = nextKeyframe;
|
||||
t = 1;
|
||||
}
|
||||
|
||||
_cameraPoseTimeline.removeKeyframesBefore(prevTime);
|
||||
|
||||
const CameraPose& prevPose = prevKeyframe->data;
|
||||
const CameraPose& nextPose = nextKeyframe->data;
|
||||
|
||||
Scene* scene = camera.parent()->scene();
|
||||
SceneGraphNode* prevFocusNode = scene->sceneGraphNode(prevPose.focusNode);
|
||||
SceneGraphNode* nextFocusNode = scene->sceneGraphNode(nextPose.focusNode);
|
||||
|
||||
if (!prevFocusNode || !nextFocusNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
glm::dvec3 prevKeyframeCameraPosition = prevPose.position;
|
||||
glm::dvec3 nextKeyframeCameraPosition = nextPose.position;
|
||||
glm::dquat prevKeyframeCameraRotation = prevPose.rotation;
|
||||
glm::dquat nextKeyframeCameraRotation = nextPose.rotation;
|
||||
|
||||
// Transform position and rotation based on focus node rotation (if following rotation)
|
||||
if (prevPose.followFocusNodeRotation) {
|
||||
prevKeyframeCameraRotation = prevFocusNode->worldRotationMatrix() * glm::dmat3(glm::dquat(prevPose.rotation));
|
||||
prevKeyframeCameraPosition = prevFocusNode->worldRotationMatrix() * prevPose.position;
|
||||
}
|
||||
if (nextPose.followFocusNodeRotation) {
|
||||
nextKeyframeCameraRotation = nextFocusNode->worldRotationMatrix() * glm::dmat3(glm::dquat(nextPose.rotation));
|
||||
nextKeyframeCameraPosition = nextFocusNode->worldRotationMatrix() * nextPose.position;
|
||||
}
|
||||
|
||||
// Transform position based on focus node position
|
||||
prevKeyframeCameraPosition += prevFocusNode->worldPosition();
|
||||
nextKeyframeCameraPosition += nextFocusNode->worldPosition();
|
||||
|
||||
// Linear interpolation
|
||||
camera.setPositionVec3(prevKeyframeCameraPosition * (1 - t) + nextKeyframeCameraPosition * t);
|
||||
camera.setRotation(glm::slerp(prevKeyframeCameraRotation, nextKeyframeCameraRotation, t));
|
||||
}
|
||||
|
||||
Timeline<KeyframeNavigator::CameraPose>& KeyframeNavigator::timeline() {
|
||||
return _cameraPoseTimeline;
|
||||
}
|
||||
|
||||
void KeyframeNavigator::addKeyframe(double timestamp, KeyframeNavigator::CameraPose pose) {
|
||||
timeline().addKeyframe(timestamp, pose);
|
||||
}
|
||||
|
||||
void KeyframeNavigator::removeKeyframesAfter(double timestamp) {
|
||||
timeline().removeKeyframesAfter(timestamp);
|
||||
}
|
||||
|
||||
void KeyframeNavigator::clearKeyframes() {
|
||||
timeline().clearKeyframes();
|
||||
}
|
||||
|
||||
size_t KeyframeNavigator::nKeyframes() const {
|
||||
return _cameraPoseTimeline.nKeyframes();
|
||||
}
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
177
src/interaction/mousestate.cpp
Normal file
177
src/interaction/mousestate.cpp
Normal file
@@ -0,0 +1,177 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/interaction/mousestate.h>
|
||||
|
||||
namespace openspace {
|
||||
namespace interaction {
|
||||
|
||||
MouseState::MouseState(double scaleFactor)
|
||||
: velocity(scaleFactor, 1)
|
||||
, previousPosition(0.0, 0.0)
|
||||
{ }
|
||||
|
||||
void MouseState::setFriction(double friction) {
|
||||
velocity.setFriction(friction);
|
||||
}
|
||||
|
||||
void MouseState::setVelocityScaleFactor(double scaleFactor) {
|
||||
velocity.setScaleFactor(scaleFactor);
|
||||
}
|
||||
|
||||
MouseStates::MouseStates(double sensitivity, double velocityScaleFactor)
|
||||
: _sensitivity(sensitivity)
|
||||
, _globalRotationMouseState(velocityScaleFactor)
|
||||
, _localRotationMouseState(velocityScaleFactor)
|
||||
, _truckMovementMouseState(velocityScaleFactor)
|
||||
, _localRollMouseState(velocityScaleFactor)
|
||||
, _globalRollMouseState(velocityScaleFactor)
|
||||
{ }
|
||||
|
||||
void MouseStates::updateMouseStatesFromInput(const InputState& inputState,
|
||||
double deltaTime)
|
||||
{
|
||||
glm::dvec2 mousePosition = inputState.getMousePosition();
|
||||
|
||||
bool button1Pressed = inputState.isMouseButtonPressed(MouseButton::Button1);
|
||||
bool button2Pressed = inputState.isMouseButtonPressed(MouseButton::Button2);
|
||||
bool button3Pressed = inputState.isMouseButtonPressed(MouseButton::Button3);
|
||||
bool keyCtrlPressed = inputState.isKeyPressed(Key::LeftControl);
|
||||
bool keyShiftPressed = inputState.isKeyPressed(Key::LeftShift);
|
||||
|
||||
// Update the mouse states
|
||||
if (button1Pressed && !keyShiftPressed) {
|
||||
if (keyCtrlPressed) {
|
||||
glm::dvec2 mousePositionDelta =
|
||||
_localRotationMouseState.previousPosition - mousePosition;
|
||||
_localRotationMouseState.velocity.set(
|
||||
mousePositionDelta * _sensitivity, deltaTime);
|
||||
|
||||
_globalRotationMouseState.previousPosition = mousePosition;
|
||||
_globalRotationMouseState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
else {
|
||||
glm::dvec2 mousePositionDelta =
|
||||
_globalRotationMouseState.previousPosition - mousePosition;
|
||||
_globalRotationMouseState.velocity.set(
|
||||
mousePositionDelta * _sensitivity, deltaTime);
|
||||
|
||||
_localRotationMouseState.previousPosition = mousePosition;
|
||||
_localRotationMouseState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
}
|
||||
else { // !button1Pressed
|
||||
_localRotationMouseState.previousPosition = mousePosition;
|
||||
_localRotationMouseState.velocity.decelerate(deltaTime);
|
||||
|
||||
_globalRotationMouseState.previousPosition = mousePosition;
|
||||
_globalRotationMouseState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
if (button2Pressed) {
|
||||
glm::dvec2 mousePositionDelta =
|
||||
_truckMovementMouseState.previousPosition - mousePosition;
|
||||
_truckMovementMouseState.velocity.set(
|
||||
mousePositionDelta * _sensitivity, deltaTime);
|
||||
}
|
||||
else { // !button2Pressed
|
||||
_truckMovementMouseState.previousPosition = mousePosition;
|
||||
_truckMovementMouseState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
if (button3Pressed || (keyShiftPressed && button1Pressed)) {
|
||||
if (keyCtrlPressed) {
|
||||
glm::dvec2 mousePositionDelta =
|
||||
_localRollMouseState.previousPosition - mousePosition;
|
||||
_localRollMouseState.velocity.set(
|
||||
mousePositionDelta * _sensitivity, deltaTime);
|
||||
|
||||
_globalRollMouseState.previousPosition = mousePosition;
|
||||
_globalRollMouseState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
else {
|
||||
glm::dvec2 mousePositionDelta =
|
||||
_globalRollMouseState.previousPosition - mousePosition;
|
||||
_globalRollMouseState.velocity.set(
|
||||
mousePositionDelta * _sensitivity, deltaTime);
|
||||
|
||||
_localRollMouseState.previousPosition = mousePosition;
|
||||
_localRollMouseState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
}
|
||||
else { // !button3Pressed
|
||||
_globalRollMouseState.previousPosition = mousePosition;
|
||||
_globalRollMouseState.velocity.decelerate(deltaTime);
|
||||
|
||||
_localRollMouseState.previousPosition = mousePosition;
|
||||
_localRollMouseState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
void MouseStates::setRotationalFriction(double friction) {
|
||||
_localRotationMouseState.setFriction(friction);
|
||||
_localRollMouseState.setFriction(friction);
|
||||
_globalRollMouseState.setFriction(friction);
|
||||
}
|
||||
|
||||
void MouseStates::setHorizontalFriction(double friction) {
|
||||
_globalRotationMouseState.setFriction(friction);
|
||||
}
|
||||
|
||||
void MouseStates::setVerticalFriction(double friction) {
|
||||
_truckMovementMouseState.setFriction(friction);
|
||||
}
|
||||
|
||||
void MouseStates::setSensitivity(double sensitivity) {
|
||||
_sensitivity = sensitivity;
|
||||
}
|
||||
|
||||
void MouseStates::setVelocityScaleFactor(double scaleFactor) {
|
||||
_globalRotationMouseState.setVelocityScaleFactor(scaleFactor);
|
||||
_localRotationMouseState.setVelocityScaleFactor(scaleFactor);
|
||||
_truckMovementMouseState.setVelocityScaleFactor(scaleFactor);
|
||||
_localRollMouseState.setVelocityScaleFactor(scaleFactor);
|
||||
_globalRollMouseState.setVelocityScaleFactor(scaleFactor);
|
||||
}
|
||||
|
||||
glm::dvec2 MouseStates::globalRotationMouseVelocity() const{
|
||||
return _globalRotationMouseState.velocity.get();
|
||||
}
|
||||
|
||||
glm::dvec2 MouseStates::localRotationMouseVelocity() const{
|
||||
return _localRotationMouseState.velocity.get();
|
||||
}
|
||||
|
||||
glm::dvec2 MouseStates::truckMovementMouseVelocity() const{
|
||||
return _truckMovementMouseState.velocity.get();
|
||||
}
|
||||
|
||||
glm::dvec2 MouseStates::localRollMouseVelocity() const{
|
||||
return _localRollMouseState.velocity.get();
|
||||
}
|
||||
|
||||
glm::dvec2 MouseStates::globalRollMouseVelocity() const{
|
||||
return _globalRollMouseState.velocity.get();
|
||||
}
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
299
src/interaction/navigationhandler.cpp
Normal file
299
src/interaction/navigationhandler.cpp
Normal file
@@ -0,0 +1,299 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
|
||||
#include <openspace/openspace.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/query/query.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/util/time.h>
|
||||
#include <openspace/util/keys.h>
|
||||
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
#include <ghoul/glm.h>
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace {
|
||||
const char* _loggerCat = "NavigationHandler";
|
||||
|
||||
const char* KeyFocus = "Focus";
|
||||
const char* KeyPosition = "Position";
|
||||
const char* KeyRotation = "Rotation";
|
||||
} // namespace
|
||||
|
||||
#include "navigationhandler_lua.inl"
|
||||
|
||||
namespace openspace {
|
||||
namespace interaction {
|
||||
|
||||
NavigationHandler::NavigationHandler()
|
||||
: properties::PropertyOwner("NavigationHandler")
|
||||
, _origin("origin", "Origin", "")
|
||||
, _useKeyFrameInteraction("useKeyFrameInteraction", "Use keyframe interaction", false)
|
||||
{
|
||||
_origin.onChange([this]() {
|
||||
SceneGraphNode* node = sceneGraphNode(_origin.value());
|
||||
if (!node) {
|
||||
LWARNING("Could not find a node in scenegraph called '" << _origin.value() << "'");
|
||||
return;
|
||||
}
|
||||
setFocusNode(node);
|
||||
resetCameraDirection();
|
||||
});
|
||||
|
||||
_inputState = std::make_unique<InputState>();
|
||||
_orbitalNavigator = std::make_unique<OrbitalNavigator>();
|
||||
_keyframeNavigator = std::make_unique<KeyframeNavigator>();
|
||||
|
||||
// Add the properties
|
||||
addProperty(_origin);
|
||||
addProperty(_useKeyFrameInteraction);
|
||||
addPropertySubOwner(*_orbitalNavigator);
|
||||
}
|
||||
|
||||
NavigationHandler::~NavigationHandler()
|
||||
{ }
|
||||
|
||||
void NavigationHandler::initialize() {
|
||||
OsEng.parallelConnection().connectionEvent()->subscribe("NavigationHandler", "statusChanged", [this]() {
|
||||
if (OsEng.parallelConnection().status() == ParallelConnection::Status::ClientWithHost) {
|
||||
_useKeyFrameInteraction = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void NavigationHandler::deinitialize() {
|
||||
OsEng.parallelConnection().connectionEvent()->unsubscribe("NavigationHandler");
|
||||
}
|
||||
|
||||
void NavigationHandler::setFocusNode(SceneGraphNode* node) {
|
||||
_orbitalNavigator->setFocusNode(node);
|
||||
_camera->setFocusPositionVec3(focusNode()->worldPosition());
|
||||
}
|
||||
|
||||
void NavigationHandler::setCamera(Camera* camera) {
|
||||
_camera = camera;
|
||||
//setFocusNode(_camera->parent());
|
||||
}
|
||||
|
||||
void NavigationHandler::resetCameraDirection() {
|
||||
LINFO("Setting camera direction to point at focus node.");
|
||||
_orbitalNavigator->startInterpolateCameraDirection(*_camera);
|
||||
}
|
||||
|
||||
const OrbitalNavigator& NavigationHandler::orbitalNavigator() const {
|
||||
return *_orbitalNavigator;
|
||||
}
|
||||
|
||||
KeyframeNavigator& NavigationHandler::keyframeNavigator() const {
|
||||
return *_keyframeNavigator;
|
||||
}
|
||||
|
||||
void NavigationHandler::updateCamera(double deltaTime) {
|
||||
ghoul_assert(_inputState != nullptr, "InputState cannot be null!");
|
||||
ghoul_assert(_camera != nullptr, "Camera cannot be null!");
|
||||
|
||||
if (_cameraUpdatedFromScript) {
|
||||
_cameraUpdatedFromScript = false;
|
||||
}
|
||||
else {
|
||||
if (_camera && focusNode()) {
|
||||
if (_useKeyFrameInteraction) {
|
||||
_keyframeNavigator->updateCamera(*_camera);
|
||||
}
|
||||
else {
|
||||
_orbitalNavigator->updateMouseStatesFromInput(*_inputState, deltaTime);
|
||||
_orbitalNavigator->updateCameraStateFromMouseStates(*_camera, deltaTime);
|
||||
}
|
||||
_camera->setFocusPositionVec3(focusNode()->worldPosition());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SceneGraphNode* NavigationHandler::focusNode() const {
|
||||
return _orbitalNavigator->focusNode();
|
||||
}
|
||||
|
||||
glm::dvec3 NavigationHandler::focusNodeToCameraVector() const {
|
||||
return _camera->positionVec3() - focusNode()->worldPosition();
|
||||
}
|
||||
|
||||
glm::quat NavigationHandler::focusNodeToCameraRotation() const {
|
||||
glm::dmat4 invWorldRotation = glm::inverse(focusNode()->worldRotationMatrix());
|
||||
return glm::quat(invWorldRotation) * glm::quat(_camera->rotationQuaternion());
|
||||
}
|
||||
|
||||
Camera* NavigationHandler::camera() const {
|
||||
return _camera;
|
||||
}
|
||||
|
||||
const InputState& NavigationHandler::inputState() const {
|
||||
return *_inputState;
|
||||
}
|
||||
|
||||
void NavigationHandler::mouseButtonCallback(MouseButton button, MouseAction action) {
|
||||
_inputState->mouseButtonCallback(button, action);
|
||||
}
|
||||
|
||||
void NavigationHandler::mousePositionCallback(double x, double y) {
|
||||
_inputState->mousePositionCallback(x, y);
|
||||
}
|
||||
|
||||
void NavigationHandler::mouseScrollWheelCallback(double pos) {
|
||||
_inputState->mouseScrollWheelCallback(pos);
|
||||
}
|
||||
|
||||
void NavigationHandler::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) {
|
||||
_inputState->keyboardCallback(key, modifier, action);
|
||||
}
|
||||
|
||||
void NavigationHandler::setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict) {
|
||||
bool readSuccessful = true;
|
||||
|
||||
std::string focus;
|
||||
glm::dvec3 cameraPosition;
|
||||
glm::dvec4 cameraRotation; // Need to read the quaternion as a vector first.
|
||||
|
||||
readSuccessful &= cameraDict.getValue(KeyFocus, focus);
|
||||
readSuccessful &= cameraDict.getValue(KeyPosition, cameraPosition);
|
||||
readSuccessful &= cameraDict.getValue(KeyRotation, cameraRotation);
|
||||
|
||||
if (!readSuccessful) {
|
||||
throw ghoul::RuntimeError(
|
||||
"Position, Rotation and Focus need to be defined for camera dictionary.");
|
||||
}
|
||||
|
||||
SceneGraphNode* node = sceneGraphNode(focus);
|
||||
if (!node) {
|
||||
throw ghoul::RuntimeError(
|
||||
"Could not find a node in scenegraph called '" + focus + "'");
|
||||
}
|
||||
|
||||
// Set state
|
||||
setFocusNode(node);
|
||||
_camera->setPositionVec3(cameraPosition);
|
||||
_camera->setRotation(glm::dquat(
|
||||
cameraRotation.x, cameraRotation.y, cameraRotation.z, cameraRotation.w));
|
||||
}
|
||||
|
||||
ghoul::Dictionary NavigationHandler::getCameraStateDictionary() {
|
||||
glm::dvec3 cameraPosition;
|
||||
glm::dquat quat;
|
||||
glm::dvec4 cameraRotation;
|
||||
|
||||
cameraPosition = _camera->positionVec3();
|
||||
quat = _camera->rotationQuaternion();
|
||||
cameraRotation = glm::dvec4(quat.w, quat.x, quat.y, quat.z);
|
||||
|
||||
ghoul::Dictionary cameraDict;
|
||||
cameraDict.setValue(KeyPosition, cameraPosition);
|
||||
cameraDict.setValue(KeyRotation, cameraRotation);
|
||||
cameraDict.setValue(KeyFocus, focusNode()->name());
|
||||
|
||||
return cameraDict;
|
||||
}
|
||||
|
||||
void NavigationHandler::saveCameraStateToFile(const std::string& filepath) {
|
||||
if (!filepath.empty()) {
|
||||
std::string fullpath = absPath(filepath);
|
||||
LINFO("Saving camera position: " << filepath);
|
||||
|
||||
ghoul::Dictionary cameraDict = getCameraStateDictionary();
|
||||
|
||||
// TODO : Should get the camera state as a dictionary and save the dictionary to
|
||||
// a file in form of a lua state and not use ofstreams here.
|
||||
|
||||
std::ofstream ofs(fullpath.c_str());
|
||||
|
||||
glm::dvec3 p = _camera->positionVec3();
|
||||
glm::dquat q = _camera->rotationQuaternion();
|
||||
|
||||
ofs << "return {" << std::endl;
|
||||
ofs << " " << KeyFocus << " = " << "\"" << focusNode()->name() << "\"" << "," << std::endl;
|
||||
ofs << " " << KeyPosition << " = {"
|
||||
<< std::to_string(p.x) << ", "
|
||||
<< std::to_string(p.y) << ", "
|
||||
<< std::to_string(p.z) << "}," << std::endl;
|
||||
ofs << " " << KeyRotation << " = {"
|
||||
<< std::to_string(q.w) << ", "
|
||||
<< std::to_string(q.x) << ", "
|
||||
<< std::to_string(q.y) << ", "
|
||||
<< std::to_string(q.z) << "}," << std::endl;
|
||||
ofs << "}"<< std::endl;
|
||||
|
||||
ofs.close();
|
||||
}
|
||||
}
|
||||
|
||||
void NavigationHandler::restoreCameraStateFromFile(const std::string& filepath) {
|
||||
LINFO("Reading camera state from file: " << filepath);
|
||||
if (!FileSys.fileExists(filepath))
|
||||
throw ghoul::FileNotFoundError(filepath, "CameraFilePath");
|
||||
|
||||
ghoul::Dictionary cameraDict;
|
||||
try {
|
||||
ghoul::lua::loadDictionaryFromFile(filepath, cameraDict);
|
||||
setCameraStateFromDictionary(cameraDict);
|
||||
_cameraUpdatedFromScript = true;
|
||||
}
|
||||
catch (ghoul::RuntimeError& e) {
|
||||
LWARNING("Unable to set camera position");
|
||||
LWARNING(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
scripting::LuaLibrary NavigationHandler::luaLibrary() {
|
||||
return {
|
||||
"navigation",
|
||||
{
|
||||
{
|
||||
"saveCameraStateToFile",
|
||||
&luascriptfunctions::saveCameraStateToFile,
|
||||
"string",
|
||||
"Save the current camera state to file"
|
||||
},
|
||||
{
|
||||
"restoreCameraStateFromFile",
|
||||
&luascriptfunctions::restoreCameraStateFromFile,
|
||||
"string",
|
||||
"Restore the camera state from file"
|
||||
},
|
||||
{
|
||||
"resetCameraDirection",
|
||||
&luascriptfunctions::resetCameraDirection,
|
||||
"void",
|
||||
"Reset the camera direction to point at the focus node"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
113
src/interaction/navigationhandler_lua.inl
Normal file
113
src/interaction/navigationhandler_lua.inl
Normal file
@@ -0,0 +1,113 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
namespace openspace {
|
||||
|
||||
namespace luascriptfunctions {
|
||||
/**
|
||||
* \ingroup LuaScripts
|
||||
* setOrigin():
|
||||
* Set the origin of the camera
|
||||
*/
|
||||
int setOrigin(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
int nArguments = lua_gettop(L);
|
||||
if (nArguments != 1) {
|
||||
return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments);
|
||||
}
|
||||
|
||||
const int type = lua_type(L, -1);
|
||||
if (type != LUA_TSTRING) {
|
||||
return luaL_error(L, "Expected string, got %i", type);
|
||||
}
|
||||
|
||||
std::string s = luaL_checkstring(L, -1);
|
||||
|
||||
SceneGraphNode* node = sceneGraphNode(s);
|
||||
if (!node) {
|
||||
LWARNINGC(
|
||||
"lua.setOrigin",
|
||||
"Could not find a node in scenegraph called '" << s << "'"
|
||||
);
|
||||
return 0;
|
||||
}
|
||||
|
||||
OsEng.navigationHandler().setFocusNode(node);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int restoreCameraStateFromFile(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
int nArguments = lua_gettop(L);
|
||||
if (nArguments != 1) {
|
||||
return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments);
|
||||
}
|
||||
|
||||
std::string cameraStateFilePath = luaL_checkstring(L, -1);
|
||||
|
||||
if (cameraStateFilePath.empty()) {
|
||||
return luaL_error(L, "filepath string is empty");
|
||||
}
|
||||
|
||||
OsEng.navigationHandler().restoreCameraStateFromFile(cameraStateFilePath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int saveCameraStateToFile(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
int nArguments = lua_gettop(L);
|
||||
if (nArguments != 1) {
|
||||
return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments);
|
||||
}
|
||||
|
||||
std::string cameraStateFilePath = luaL_checkstring(L, -1);
|
||||
|
||||
if (cameraStateFilePath.empty()) {
|
||||
return luaL_error(L, "filepath string is empty");
|
||||
}
|
||||
|
||||
OsEng.navigationHandler().saveCameraStateToFile(cameraStateFilePath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int resetCameraDirection(lua_State* L) {
|
||||
using ghoul::lua::luaTypeToString;
|
||||
|
||||
int nArguments = lua_gettop(L);
|
||||
if (nArguments != 0) {
|
||||
return luaL_error(L, "Expected %i arguments, got %i", 0, nArguments);
|
||||
}
|
||||
|
||||
OsEng.navigationHandler().resetCameraDirection();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
} // namespace luascriptfunctions
|
||||
|
||||
} // namespace openspace
|
||||
532
src/interaction/orbitalnavigator.cpp
Normal file
532
src/interaction/orbitalnavigator.cpp
Normal file
@@ -0,0 +1,532 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2017 *
|
||||
* *
|
||||
* 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. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/interaction/orbitalnavigator.h>
|
||||
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <openspace/rendering/renderable.h>
|
||||
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
#include <glm/gtx/vector_angle.hpp>
|
||||
|
||||
namespace {
|
||||
const char* _loggerCat = "OrbitalNavigator";
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
namespace interaction {
|
||||
|
||||
OrbitalNavigator::OrbitalNavigator()
|
||||
: properties::PropertyOwner("OrbitalNavigator")
|
||||
, _rotationalFriction("rotationalFriction", "Rotational friction", true)
|
||||
, _horizontalFriction("horizontalFriction", "Horizontal friction", true)
|
||||
, _verticalFriction("verticalFriction", "Vertical friction", true)
|
||||
, _followFocusNodeRotationDistance("followFocusNodeRotationDistance",
|
||||
"Follow focus node rotation distance", 2.0f, 0.0f, 10.f)
|
||||
, _minimumAllowedDistance("minimumAllowedDistance",
|
||||
"Minimum allowed distance", 10.0f, 0.0f, 10000.f)
|
||||
, _sensitivity("sensitivity", "Sensitivity", 20.0f, 1.0f, 50.f)
|
||||
, _motionLag("motionLag", "Motion lag", 0.5f, 0.f, 1.f)
|
||||
, _mouseStates(_sensitivity * pow(10.0,-4), 1 / (_motionLag + 0.0000001))
|
||||
{
|
||||
auto smoothStep =
|
||||
[](double t) {
|
||||
double res = 3.0 * t*t - 2.0 * t*t*t;
|
||||
return glm::clamp(res, 0.0, 1.0);
|
||||
};
|
||||
_followRotationInterpolator.setTransferFunction(smoothStep);
|
||||
|
||||
// The transfer function is used here to get a different interpolation than the one
|
||||
// obtained from newValue = lerp(0, currentValue, dt). That one will result in an
|
||||
// exponentially decreasing value but we want to be able to control it. Either as
|
||||
// a linear interpolation or a smooth step interpolation. Therefore we use
|
||||
// newValue = lerp(0, currentValue * f(t) * dt) where f(t) is the transfer function
|
||||
// and lerp is a linear iterpolation
|
||||
// lerp(endValue, startValue, interpolationParameter).
|
||||
//
|
||||
// The transfer functions are derived from:
|
||||
// f(t) = d/dt ( ln(1 / f_orig(t)) ) where f_orig is the transfer function that would
|
||||
// be used if the interpolation was sinply linear between a start value and an end
|
||||
// value instead of current value and end value (0) as we use it when inerpoláting.
|
||||
// As an example f_orig(t) = 1 - t yields f(t) = 1 / (1 - t) which results in a linear
|
||||
// interpolation from 1 to 0.
|
||||
|
||||
auto smoothStepDerivedTranferFunction =
|
||||
[](double t) {
|
||||
return (6 * (t + t*t) / (1 - 3 * t*t + 2 * t*t*t));
|
||||
};
|
||||
_rotateToFocusNodeInterpolator.setTransferFunction(smoothStepDerivedTranferFunction);
|
||||
|
||||
// Define callback functions for changed properties
|
||||
_rotationalFriction.onChange([&]() {
|
||||
_mouseStates.setRotationalFriction(_rotationalFriction);
|
||||
});
|
||||
_horizontalFriction.onChange([&]() {
|
||||
_mouseStates.setHorizontalFriction(_horizontalFriction);
|
||||
});
|
||||
_verticalFriction.onChange([&]() {
|
||||
_mouseStates.setVerticalFriction(_verticalFriction);
|
||||
});
|
||||
_sensitivity.onChange([&]() {
|
||||
_mouseStates.setSensitivity(_sensitivity * pow(10.0,-4));
|
||||
});
|
||||
_motionLag.onChange([&]() {
|
||||
_mouseStates.setVelocityScaleFactor(1 / (_motionLag + 0.0000001));
|
||||
});
|
||||
|
||||
// Add the properties
|
||||
addProperty(_rotationalFriction);
|
||||
addProperty(_horizontalFriction);
|
||||
addProperty(_verticalFriction);
|
||||
addProperty(_followFocusNodeRotationDistance);
|
||||
addProperty(_minimumAllowedDistance);
|
||||
addProperty(_sensitivity);
|
||||
addProperty(_motionLag);
|
||||
}
|
||||
|
||||
OrbitalNavigator::~OrbitalNavigator()
|
||||
{ }
|
||||
|
||||
void OrbitalNavigator::updateMouseStatesFromInput(const InputState& inputState,
|
||||
double deltaTime)
|
||||
{
|
||||
_mouseStates.updateMouseStatesFromInput(inputState, deltaTime);
|
||||
}
|
||||
|
||||
void OrbitalNavigator::updateCameraStateFromMouseStates(Camera& camera,
|
||||
double deltaTime)
|
||||
{
|
||||
if (_focusNode) {
|
||||
// Read the current state of the camera
|
||||
glm::dvec3 camPos = camera.positionVec3();
|
||||
glm::dvec3 centerPos = _focusNode->worldPosition();
|
||||
|
||||
// Follow focus nodes movement
|
||||
glm::dvec3 focusNodeDiff = centerPos - _previousFocusNodePosition;
|
||||
_previousFocusNodePosition = centerPos;
|
||||
camPos += focusNodeDiff;
|
||||
|
||||
// Calculate a position handle based on the camera position in world space
|
||||
SurfacePositionHandle posHandle = calculateSurfacePositionHandle(camPos);
|
||||
|
||||
// Decompose camera rotation so that we can handle global and local rotation
|
||||
// individually. Then we combine them again when finished.
|
||||
CameraRotationDecomposition camRot = decomposeCameraRotation(
|
||||
camPos,
|
||||
camera.rotationQuaternion(),
|
||||
camera.lookUpVectorWorldSpace(),
|
||||
camera.viewDirectionWorldSpace()
|
||||
);
|
||||
|
||||
// Rotate with the object by finding a differential rotation from the previous
|
||||
// to the current rotation
|
||||
glm::dmat3 objectStateMatrix = _focusNode->worldRotationMatrix();
|
||||
glm::dquat objectRotation = glm::quat_cast(objectStateMatrix);
|
||||
glm::dquat focusNodeRotationDiff =
|
||||
_previousFocusNodeRotation * glm::inverse(objectRotation);
|
||||
_previousFocusNodeRotation = objectRotation;
|
||||
|
||||
// Interpolate rotation differential so that the camera rotates with the object
|
||||
// only if close enough
|
||||
focusNodeRotationDiff = interpolateRotationDifferential(
|
||||
deltaTime,
|
||||
1.0,
|
||||
focusNodeRotationDiff,
|
||||
centerPos,
|
||||
camPos,
|
||||
posHandle
|
||||
);
|
||||
|
||||
// Update local rotation
|
||||
camRot.localRotation = roll(deltaTime, camRot.localRotation);
|
||||
camRot.localRotation = interpolateLocalRotation(deltaTime, camRot.localRotation);
|
||||
camRot.localRotation = rotateLocally(deltaTime, camRot.localRotation);
|
||||
|
||||
// Horizontal translation
|
||||
camPos = translateHorizontally(
|
||||
deltaTime,
|
||||
camPos,
|
||||
centerPos,
|
||||
focusNodeRotationDiff,
|
||||
camRot.globalRotation,
|
||||
posHandle
|
||||
);
|
||||
|
||||
// Horizontal translation by focus node rotation
|
||||
camPos = followFocusNodeRotation(
|
||||
camPos,
|
||||
centerPos,
|
||||
focusNodeRotationDiff
|
||||
);
|
||||
|
||||
// Recalculate posHandle since horizontal position changed
|
||||
posHandle = calculateSurfacePositionHandle(camPos);
|
||||
|
||||
camRot.globalRotation = rotateGlobally(
|
||||
camRot.globalRotation,
|
||||
centerPos,
|
||||
focusNodeRotationDiff,
|
||||
camPos,
|
||||
posHandle
|
||||
);
|
||||
|
||||
// Rotate around the surface out direction
|
||||
camRot.globalRotation = rotateHorizontally(
|
||||
deltaTime,
|
||||
camRot.globalRotation,
|
||||
camPos,
|
||||
posHandle
|
||||
);
|
||||
|
||||
// Perform the vertical movements
|
||||
camPos = translateVertically(deltaTime, camPos, centerPos, posHandle);
|
||||
camPos = pushToSurface(
|
||||
_minimumAllowedDistance,
|
||||
camPos,
|
||||
centerPos,
|
||||
posHandle
|
||||
);
|
||||
|
||||
// Update the camera state
|
||||
camera.setPositionVec3(camPos);
|
||||
camera.setRotation(camRot.globalRotation * camRot.localRotation);
|
||||
}
|
||||
}
|
||||
|
||||
void OrbitalNavigator::setFocusNode(SceneGraphNode* focusNode) {
|
||||
_focusNode = focusNode;
|
||||
|
||||
if (_focusNode != nullptr) {
|
||||
_previousFocusNodePosition = _focusNode->worldPosition();
|
||||
_previousFocusNodeRotation = glm::quat_cast(_focusNode->worldRotationMatrix());
|
||||
}
|
||||
}
|
||||
|
||||
void OrbitalNavigator::startInterpolateCameraDirection(const Camera& camera) {
|
||||
glm::dvec3 camPos = camera.positionVec3();
|
||||
glm::dvec3 camDir = glm::normalize(
|
||||
camera.rotationQuaternion() * glm::dvec3(0.0, 0.0, -1.0)
|
||||
);
|
||||
glm::dvec3 centerPos = _focusNode->worldPosition();
|
||||
glm::dvec3 directionToCenter = glm::normalize(centerPos - camPos);
|
||||
|
||||
double angle = glm::angle(camDir, directionToCenter);
|
||||
|
||||
// Minimum is two second. Otherwise proportional to angle
|
||||
_rotateToFocusNodeInterpolator.setInterpolationTime(glm::max(angle * 2.0, 2.0));
|
||||
_rotateToFocusNodeInterpolator.start();
|
||||
}
|
||||
|
||||
bool OrbitalNavigator::followingNodeRotation() const {
|
||||
return _followRotationInterpolator.value() >= 1.0;
|
||||
}
|
||||
|
||||
SceneGraphNode* OrbitalNavigator::focusNode() const {
|
||||
return _focusNode;
|
||||
}
|
||||
|
||||
OrbitalNavigator::CameraRotationDecomposition
|
||||
OrbitalNavigator::decomposeCameraRotation(
|
||||
const glm::dvec3& cameraPosition,
|
||||
const glm::dquat& cameraRotation,
|
||||
const glm::dvec3& cameraLookUp,
|
||||
const glm::dvec3& cameraViewDirection)
|
||||
{
|
||||
glm::dmat4 inverseModelTransform = _focusNode->inverseModelTransform();
|
||||
glm::dmat4 modelTransform = _focusNode->modelTransform();
|
||||
glm::dvec3 cameraPositionModelSpace =
|
||||
glm::dvec3(inverseModelTransform * glm::dvec4(cameraPosition, 1));
|
||||
|
||||
SurfacePositionHandle posHandle =
|
||||
_focusNode->calculateSurfacePositionHandle(cameraPositionModelSpace);
|
||||
|
||||
glm::dvec3 directionFromSurfaceToCameraModelSpace =
|
||||
posHandle.referenceSurfaceOutDirection;
|
||||
glm::dvec3 directionFromSurfaceToCamera =
|
||||
glm::normalize(glm::dmat3(modelTransform) *
|
||||
directionFromSurfaceToCameraModelSpace);
|
||||
|
||||
// To avoid problem with lookup in up direction we adjust is with the view direction
|
||||
glm::dmat4 lookAtMat = glm::lookAt(
|
||||
glm::dvec3(0.0, 0.0, 0.0),
|
||||
-directionFromSurfaceToCamera,
|
||||
normalize(cameraViewDirection + cameraLookUp));
|
||||
glm::dquat globalCameraRotation = glm::normalize(glm::quat_cast(inverse(lookAtMat)));
|
||||
glm::dquat localCameraRotation = glm::inverse(globalCameraRotation) * cameraRotation;
|
||||
|
||||
return { localCameraRotation, globalCameraRotation };
|
||||
}
|
||||
|
||||
glm::dquat OrbitalNavigator::roll(double deltaTime,
|
||||
const glm::dquat& localCameraRotation) const
|
||||
{
|
||||
glm::dquat rollQuat = glm::angleAxis(
|
||||
_mouseStates.localRollMouseVelocity().x * deltaTime,
|
||||
glm::dvec3(0.0, 0.0, 1.0)
|
||||
);
|
||||
return localCameraRotation * rollQuat;
|
||||
}
|
||||
|
||||
glm::dquat OrbitalNavigator::rotateLocally(double deltaTime,
|
||||
const glm::dquat& localCameraRotation) const
|
||||
{
|
||||
glm::dvec3 eulerAngles(
|
||||
_mouseStates.localRotationMouseVelocity().y,
|
||||
_mouseStates.localRotationMouseVelocity().x,
|
||||
0.0
|
||||
);
|
||||
glm::dquat rotationDiff = glm::dquat(eulerAngles * deltaTime);
|
||||
return localCameraRotation * rotationDiff;
|
||||
}
|
||||
|
||||
glm::dquat OrbitalNavigator::interpolateLocalRotation(
|
||||
double deltaTime,
|
||||
const glm::dquat& localCameraRotation)
|
||||
{
|
||||
if (_rotateToFocusNodeInterpolator.isInterpolating()) {
|
||||
double t = _rotateToFocusNodeInterpolator.value();
|
||||
_rotateToFocusNodeInterpolator.setDeltaTime(deltaTime);
|
||||
_rotateToFocusNodeInterpolator.step();
|
||||
glm::dquat result = glm::slerp(
|
||||
localCameraRotation,
|
||||
glm::dquat(glm::dvec3(0.0)),
|
||||
glm::min(t * _rotateToFocusNodeInterpolator.deltaTimeScaled(), 1.0));
|
||||
if (angle(result) < 0.01) {
|
||||
_rotateToFocusNodeInterpolator.end();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
return localCameraRotation;
|
||||
}
|
||||
}
|
||||
|
||||
glm::dvec3 OrbitalNavigator::translateHorizontally(
|
||||
double deltaTime,
|
||||
const glm::dvec3& cameraPosition,
|
||||
const glm::dvec3& objectPosition,
|
||||
const glm::dquat& focusNodeRotationDiff,
|
||||
const glm::dquat& globalCameraRotation,
|
||||
const SurfacePositionHandle& positionHandle) const
|
||||
{
|
||||
glm::dmat4 modelTransform = _focusNode->modelTransform();
|
||||
|
||||
glm::dvec3 outDirection =
|
||||
glm::normalize(glm::dmat3(modelTransform) *
|
||||
positionHandle.referenceSurfaceOutDirection);
|
||||
|
||||
// Vector logic
|
||||
glm::dvec3 posDiff = cameraPosition - objectPosition;
|
||||
glm::dvec3 centerToReferenceSurface = glm::dmat3(modelTransform) *
|
||||
positionHandle.centerToReferenceSurface;
|
||||
glm::dvec3 centerToActualSurfaceModelSpace = positionHandle.centerToReferenceSurface +
|
||||
positionHandle.referenceSurfaceOutDirection * positionHandle.heightToSurface;
|
||||
glm::dvec3 centerToActualSurface = glm::dmat3(modelTransform) *
|
||||
centerToActualSurfaceModelSpace;
|
||||
glm::dvec3 actualSurfaceToCamera = posDiff - centerToActualSurface;
|
||||
double distFromSurfaceToCamera = glm::length(actualSurfaceToCamera);
|
||||
|
||||
// Final values to be used
|
||||
double distFromCenterToSurface = length(centerToActualSurface);
|
||||
double distFromCenterToCamera = length(posDiff);
|
||||
|
||||
double speedScale =
|
||||
distFromCenterToSurface > 0.0 ?
|
||||
glm::clamp(distFromSurfaceToCamera / distFromCenterToSurface, 0.0, 1.0) :
|
||||
1.0;
|
||||
|
||||
// Get rotation in camera space
|
||||
glm::dvec3 eulerAngles = glm::dvec3(
|
||||
-_mouseStates.globalRotationMouseVelocity().y * deltaTime,
|
||||
-_mouseStates.globalRotationMouseVelocity().x * deltaTime,
|
||||
0) * speedScale;
|
||||
glm::dquat rotationDiffCamSpace = glm::dquat(eulerAngles);
|
||||
|
||||
// Transform to world space
|
||||
glm::dquat rotationDiffWorldSpace =
|
||||
globalCameraRotation *
|
||||
rotationDiffCamSpace *
|
||||
glm::inverse(globalCameraRotation);
|
||||
|
||||
// Rotate and find the difference vector
|
||||
glm::dvec3 rotationDiffVec3 =
|
||||
(distFromCenterToCamera * outDirection)
|
||||
* rotationDiffWorldSpace
|
||||
- (distFromCenterToCamera * outDirection);
|
||||
|
||||
// Add difference to position
|
||||
return cameraPosition + rotationDiffVec3;
|
||||
}
|
||||
|
||||
glm::dvec3 OrbitalNavigator::followFocusNodeRotation(
|
||||
const glm::dvec3& cameraPosition,
|
||||
const glm::dvec3& objectPosition,
|
||||
const glm::dquat& focusNodeRotationDiff) const
|
||||
{
|
||||
glm::dvec3 posDiff = cameraPosition - objectPosition;
|
||||
glm::dvec3 rotationDiffVec3AroundCenter =
|
||||
posDiff
|
||||
* focusNodeRotationDiff
|
||||
- (posDiff);
|
||||
return cameraPosition + rotationDiffVec3AroundCenter;
|
||||
}
|
||||
|
||||
glm::dquat OrbitalNavigator::rotateGlobally(
|
||||
const glm::dquat& globalCameraRotation,
|
||||
const glm::dvec3& objectPosition,
|
||||
const glm::dquat& focusNodeRotationDiff,
|
||||
const glm::dvec3& cameraPosition,
|
||||
const SurfacePositionHandle& positionHandle) const
|
||||
{
|
||||
glm::dmat4 modelTransform = _focusNode->modelTransform();
|
||||
|
||||
glm::dvec3 directionFromSurfaceToCamera =
|
||||
glm::dmat3(modelTransform) * positionHandle.referenceSurfaceOutDirection;
|
||||
|
||||
glm::dvec3 lookUpWhenFacingSurface =
|
||||
glm::inverse(focusNodeRotationDiff) *
|
||||
globalCameraRotation * glm::dvec3(0.0, 1.0, 0.0);
|
||||
glm::dmat4 lookAtMat = glm::lookAt(
|
||||
glm::dvec3(0.0, 0.0, 0.0),
|
||||
-directionFromSurfaceToCamera,
|
||||
lookUpWhenFacingSurface);
|
||||
return glm::normalize(glm::quat_cast(glm::inverse(lookAtMat)));
|
||||
}
|
||||
|
||||
glm::dvec3 OrbitalNavigator::translateVertically(
|
||||
double deltaTime,
|
||||
const glm::dvec3& cameraPosition,
|
||||
const glm::dvec3& objectPosition,
|
||||
const SurfacePositionHandle& positionHandle) const
|
||||
{
|
||||
glm::dmat4 modelTransform = _focusNode->modelTransform();
|
||||
|
||||
glm::dvec3 posDiff = cameraPosition - objectPosition;
|
||||
|
||||
glm::dvec3 centerToReferenceSurface =
|
||||
glm::dmat3(modelTransform) * positionHandle.centerToReferenceSurface;
|
||||
glm::dvec3 centerToActualSurfaceModelSpace =
|
||||
positionHandle.centerToReferenceSurface +
|
||||
positionHandle.referenceSurfaceOutDirection * positionHandle.heightToSurface;
|
||||
glm::dvec3 centerToActualSurface =
|
||||
glm::dmat3(modelTransform) * centerToActualSurfaceModelSpace;
|
||||
glm::dvec3 actualSurfaceToCamera = posDiff - centerToActualSurface;
|
||||
|
||||
return cameraPosition -
|
||||
actualSurfaceToCamera * _mouseStates.truckMovementMouseVelocity().y * deltaTime;
|
||||
}
|
||||
|
||||
glm::dquat OrbitalNavigator::rotateHorizontally(
|
||||
double deltaTime,
|
||||
const glm::dquat& globalCameraRotation,
|
||||
const glm::dvec3& cameraPosition,
|
||||
const SurfacePositionHandle& positionHandle) const
|
||||
{
|
||||
glm::dmat4 modelTransform = _focusNode->modelTransform();
|
||||
|
||||
glm::dvec3 directionFromSurfaceToCameraModelSpace =
|
||||
positionHandle.referenceSurfaceOutDirection;
|
||||
glm::dvec3 directionFromSurfaceToCamera =
|
||||
glm::normalize(glm::dmat3(modelTransform) * directionFromSurfaceToCameraModelSpace);
|
||||
|
||||
glm::dquat cameraRollRotation =
|
||||
glm::angleAxis(
|
||||
_mouseStates.globalRollMouseVelocity().x *
|
||||
deltaTime, directionFromSurfaceToCamera
|
||||
);
|
||||
return cameraRollRotation * globalCameraRotation;
|
||||
}
|
||||
|
||||
glm::dvec3 OrbitalNavigator::pushToSurface(
|
||||
double minHeightAboveGround,
|
||||
const glm::dvec3& cameraPosition,
|
||||
const glm::dvec3& objectPosition,
|
||||
const SurfacePositionHandle& positionHandle) const
|
||||
{
|
||||
glm::dmat4 modelTransform = _focusNode->modelTransform();
|
||||
|
||||
glm::dvec3 posDiff = cameraPosition - objectPosition;
|
||||
glm::dvec3 referenceSurfaceOutDirection =
|
||||
glm::dmat3(modelTransform) * positionHandle.referenceSurfaceOutDirection;
|
||||
glm::dvec3 centerToReferenceSurface =
|
||||
glm::dmat3(modelTransform) * positionHandle.centerToReferenceSurface;
|
||||
glm::dvec3 centerToActualSurfaceModelSpace =
|
||||
positionHandle.centerToReferenceSurface +
|
||||
positionHandle.referenceSurfaceOutDirection * positionHandle.heightToSurface;
|
||||
glm::dvec3 centerToActualSurface =
|
||||
glm::dmat3(modelTransform) * centerToActualSurfaceModelSpace;
|
||||
glm::dvec3 actualSurfaceToCamera = posDiff - centerToActualSurface;
|
||||
double surfaceToCameraSigned =
|
||||
glm::length(actualSurfaceToCamera) *
|
||||
glm::sign(dot(actualSurfaceToCamera, referenceSurfaceOutDirection));
|
||||
|
||||
return cameraPosition + referenceSurfaceOutDirection *
|
||||
glm::max(minHeightAboveGround - surfaceToCameraSigned, 0.0);
|
||||
}
|
||||
|
||||
glm::dquat OrbitalNavigator::interpolateRotationDifferential(
|
||||
double deltaTime,
|
||||
double interpolationTime,
|
||||
const glm::dquat& rotationDiff,
|
||||
const glm::dvec3& objectPosition,
|
||||
const glm::dvec3& cameraPosition,
|
||||
const SurfacePositionHandle& positionHandle)
|
||||
{
|
||||
glm::dmat4 modelTransform = _focusNode->modelTransform();
|
||||
|
||||
double maximumDistanceForRotation = glm::length(
|
||||
glm::dmat3(modelTransform) * positionHandle.centerToReferenceSurface
|
||||
) * _followFocusNodeRotationDistance;
|
||||
double distanceToCamera = glm::length(cameraPosition - objectPosition);
|
||||
|
||||
// Interpolate with a negative delta time if distance is too large to follow
|
||||
double interpolationSign = glm::sign(maximumDistanceForRotation - distanceToCamera);
|
||||
|
||||
_followRotationInterpolator.setInterpolationTime(interpolationTime);
|
||||
_followRotationInterpolator.setDeltaTime(interpolationSign * deltaTime);
|
||||
_followRotationInterpolator.step();
|
||||
|
||||
return glm::slerp(
|
||||
glm::dquat(glm::dvec3(0.0)),
|
||||
rotationDiff,
|
||||
_followRotationInterpolator.value()
|
||||
);
|
||||
}
|
||||
|
||||
SurfacePositionHandle OrbitalNavigator::calculateSurfacePositionHandle(
|
||||
const glm::dvec3 cameraPositionWorldSpace)
|
||||
{
|
||||
glm::dmat4 inverseModelTransform = _focusNode->inverseModelTransform();
|
||||
glm::dvec3 cameraPositionModelSpace =
|
||||
glm::dvec3(inverseModelTransform * glm::dvec4(cameraPositionWorldSpace, 1));
|
||||
SurfacePositionHandle posHandle =
|
||||
_focusNode->calculateSurfacePositionHandle(cameraPositionModelSpace);
|
||||
return posHandle;
|
||||
}
|
||||
|
||||
} // namespace interaction
|
||||
} // namespace openspace
|
||||
@@ -66,8 +66,8 @@
|
||||
#include <openspace/openspace.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/engine/wrapper/windowwrapper.h>
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
#include <openspace/interaction/interactionmode.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/interaction/keyframenavigator.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/scripting/script_helper.h>
|
||||
#include <openspace/util/time.h>
|
||||
@@ -580,14 +580,16 @@ void ParallelConnection::dataMessageReceived(const std::vector<char>& messageCon
|
||||
datamessagestructures::CameraKeyframe kf(buffer);
|
||||
kf._timestamp = calculateBufferedKeyframeTime(kf._timestamp);
|
||||
|
||||
OsEng.interactionHandler().removeKeyframesAfter(kf._timestamp);
|
||||
interaction::KeyframeInteractionMode::CameraPose pose;
|
||||
OsEng.navigationHandler().keyframeNavigator().removeKeyframesAfter(
|
||||
kf._timestamp);
|
||||
interaction::KeyframeNavigator::CameraPose pose;
|
||||
pose.focusNode = kf._focusNode;
|
||||
pose.position = kf._position;
|
||||
pose.rotation = kf._rotation;
|
||||
pose.followFocusNodeRotation = kf._followNodeRotation;
|
||||
|
||||
OsEng.interactionHandler().addKeyframe(kf._timestamp, pose);
|
||||
OsEng.navigationHandler().keyframeNavigator().addKeyframe(
|
||||
kf._timestamp, pose);
|
||||
break;
|
||||
}
|
||||
case datamessagestructures::Type::TimeData: {
|
||||
@@ -755,7 +757,7 @@ void ParallelConnection::connectionStatusMessageReceived(const std::vector<char>
|
||||
|
||||
setStatus(status);
|
||||
|
||||
OsEng.interactionHandler().clearKeyframes();
|
||||
OsEng.navigationHandler().keyframeNavigator().clearKeyframes();
|
||||
OsEng.timeManager().clearKeyframes();
|
||||
|
||||
}
|
||||
@@ -1012,7 +1014,7 @@ void ParallelConnection::sendScript(std::string script) {
|
||||
}
|
||||
|
||||
void ParallelConnection::resetTimeOffset() {
|
||||
OsEng.interactionHandler().clearKeyframes();
|
||||
OsEng.navigationHandler().keyframeNavigator().clearKeyframes();
|
||||
OsEng.timeManager().clearKeyframes();
|
||||
std::lock_guard<std::mutex> latencyLock(_latencyMutex);
|
||||
_latencyDiffs.clear();
|
||||
@@ -1082,21 +1084,21 @@ const std::string& ParallelConnection::hostName() {
|
||||
}
|
||||
|
||||
void ParallelConnection::sendCameraKeyframe() {
|
||||
SceneGraphNode* focusNode = OsEng.interactionHandler().focusNode();
|
||||
SceneGraphNode* focusNode = OsEng.navigationHandler().focusNode();
|
||||
if (!focusNode) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a keyframe with current position and orientation of camera
|
||||
datamessagestructures::CameraKeyframe kf;
|
||||
kf._position = OsEng.interactionHandler().focusNodeToCameraVector();
|
||||
kf._position = OsEng.navigationHandler().focusNodeToCameraVector();
|
||||
|
||||
kf._followNodeRotation = OsEng.interactionHandler().interactionMode()->followingNodeRotation();
|
||||
kf._followNodeRotation = OsEng.navigationHandler().orbitalNavigator().followingNodeRotation();
|
||||
if (kf._followNodeRotation) {
|
||||
kf._position = glm::inverse(focusNode->worldRotationMatrix()) * kf._position;
|
||||
kf._rotation = OsEng.interactionHandler().focusNodeToCameraRotation();
|
||||
kf._rotation = OsEng.navigationHandler().focusNodeToCameraRotation();
|
||||
} else {
|
||||
kf._rotation = OsEng.interactionHandler().camera()->rotationQuaternion();
|
||||
kf._rotation = OsEng.navigationHandler().camera()->rotationQuaternion();
|
||||
}
|
||||
|
||||
kf._focusNode = focusNode->name();
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/engine/virtualpropertymanager.h>
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/rendering/renderable.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
|
||||
@@ -158,6 +158,17 @@ void Renderable::render(const RenderData& data, RendererTasks&) {
|
||||
|
||||
void Renderable::render(const RenderData&) {}
|
||||
|
||||
SurfacePositionHandle Renderable::calculateSurfacePositionHandle(
|
||||
const glm::dvec3& targetModelSpace)
|
||||
{
|
||||
glm::dvec3 directionFromCenterToTarget = glm::normalize(targetModelSpace);
|
||||
return {
|
||||
directionFromCenterToTarget * static_cast<double>(boundingSphere()),
|
||||
directionFromCenterToTarget,
|
||||
0.0
|
||||
};
|
||||
}
|
||||
|
||||
void Renderable::setPscUniforms(ghoul::opengl::ProgramObject& program,
|
||||
const Camera& camera,
|
||||
const PowerScaledCoordinate& position)
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#include <openspace/engine/configurationmanager.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/engine/wrapper/windowwrapper.h>
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/interaction/luaconsole.h>
|
||||
#include <openspace/mission/missionmanager.h>
|
||||
#include <openspace/performance/performancemanager.h>
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
#include <openspace/engine/configurationmanager.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/engine/wrapper/windowwrapper.h>
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/query/query.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
|
||||
@@ -477,6 +477,21 @@ void SceneGraphNode::setDependencies(const std::vector<SceneGraphNode*>& depende
|
||||
}
|
||||
}
|
||||
|
||||
SurfacePositionHandle SceneGraphNode::calculateSurfacePositionHandle(
|
||||
const glm::dvec3& targetModelSpace)
|
||||
{
|
||||
if (_renderable) {
|
||||
return _renderable->calculateSurfacePositionHandle(targetModelSpace);
|
||||
}
|
||||
else {
|
||||
return {
|
||||
glm::dvec3(0.0, 0.0, 0.0),
|
||||
glm::normalize(targetModelSpace),
|
||||
0.0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<SceneGraphNode*>& SceneGraphNode::dependencies() const {
|
||||
return _dependencies;
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include <openspace/util/syncbuffer.h>
|
||||
#include <openspace/query/query.h>
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/interaction/interactionhandler.h>
|
||||
|
||||
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
Reference in New Issue
Block a user