Merge branch 'feature/globebrowsing' of github.com:OpenSpace/OpenSpace-Development into feature/globebrowsing

This commit is contained in:
Kalle Bladin
2016-06-22 19:19:05 -04:00
15 changed files with 769 additions and 534 deletions

View File

@@ -27,14 +27,15 @@
#include <openspace/interaction/keyboardcontroller.h>
#include <openspace/interaction/mousecontroller.h>
#include <openspace/interaction/interactionmode.h>
#include <openspace/network/parallelconnection.h>
#include <openspace/properties/propertyowner.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/util/mouse.h>
#include <openspace/util/keys.h>
#include <list>
#include <modules/globebrowsing/globes/renderableglobe.h>
#include <mutex>
@@ -147,145 +148,6 @@ private:
#else // USE_OLD_INTERACTIONHANDLER
class InputState
{
public:
InputState();
~InputState();
// Callback functions
void keyboardCallback(Key key, KeyModifier modifier, KeyAction action);
void mouseButtonCallback(MouseButton button, MouseAction action);
void mousePositionCallback(double mouseX, double mouseY);
void mouseScrollWheelCallback(double mouseScrollDelta);
// Mutators
void addKeyframe(const network::datamessagestructures::PositionKeyframe &kf);
void clearKeyframes();
// Accessors
const std::list<std::pair<Key, KeyModifier> >& getPressedKeys() const;
const std::list<MouseButton>& getPressedMouseButtons() const;
glm::dvec2 getMousePosition() const;
double getMouseScrollDelta() const;
std::vector<network::datamessagestructures::PositionKeyframe>& getKeyFrames() const;
bool isKeyPressed(std::pair<Key, KeyModifier> keyModPair) 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;
// Remote input via keyframes
std::vector<network::datamessagestructures::PositionKeyframe> _keyframes;
std::mutex _keyframeMutex;
};
class InteractionMode
{
public:
InteractionMode();
~InteractionMode();
// Mutators
virtual void setFocusNode(SceneGraphNode* focusNode);
// Accessors
SceneGraphNode* focusNode();
virtual void update(Camera& camera, const InputState& inputState, 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 scale) {
_scale = scale;
}
void set(T value, double dt) {
_targetValue = value;
_currentValue = _currentValue + (_targetValue - _currentValue) *
min(_scale * dt, 1.0); // less or equal to 1.0 keeps it stable
}
T get() {
return _currentValue;
}
private:
ScaleType _scale;
T _targetValue;
T _currentValue;
};
struct MouseState {
MouseState(double scale)
: velocity(scale)
, previousPosition(0.0, 0.0) {}
glm::dvec2 previousPosition;
DelayedVariable<glm::dvec2, double> velocity;
};
SceneGraphNode* _focusNode = nullptr;
};
class KeyframeInteractionMode : public InteractionMode
{
public:
KeyframeInteractionMode();
~KeyframeInteractionMode();
virtual void update(double deltaTime);
private:
double _currentKeyframeTime;
};
class OrbitalInteractionMode : public InteractionMode
{
public:
/*!
\param inputState
\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.
*/
OrbitalInteractionMode(double sensitivity, double velocityScaleFactor);
~OrbitalInteractionMode();
virtual void update(Camera& camera, const InputState& inputState, double deltaTime);
protected:
void updateMouseStatesFromInput(const InputState& inputState, double deltaTime);
void updateCameraStateFromMouseStates(Camera& camera);
double _sensitivity;
MouseState _globalRotationMouseState;
MouseState _localRotationMouseState;
MouseState _truckMovementMouseState;
MouseState _rollMouseState;
glm::dquat _localCameraRotation;
glm::dquat _globalCameraRotation;
};
class GlobeBrowsingInteractionMode : public OrbitalInteractionMode
{
public:
GlobeBrowsingInteractionMode(double sensitivity, double velocityScaleFactor);
~GlobeBrowsingInteractionMode();
virtual void setFocusNode(SceneGraphNode* focusNode);
virtual void update(Camera& camera, const InputState& inputState, double deltaTime);
private:
void updateCameraStateFromMouseStates(Camera& camera);
RenderableGlobe* _globe;
};
class InteractionHandler : public properties::PropertyOwner
{
@@ -332,9 +194,14 @@ public:
void mousePositionCallback(double x, double y);
void mouseScrollWheelCallback(double pos);
void saveCameraPosition(const std::string& filepath = "");
void restoreCameraPosition(const std::string& filepath = "");
private:
void setInteractionMode(std::shared_ptr<InteractionMode> interactionMode);
bool _cameraUpdatedFromScript = false;
std::multimap<KeyWithModifier, std::string > _keyLua;
std::unique_ptr<InputState> _inputState;
@@ -348,7 +215,6 @@ private:
// Properties
properties::StringProperty _origin;
properties::StringProperty _coordinateSystem;
};
#endif // USE_OLD_INTERACTIONHANDLER

View File

@@ -0,0 +1,197 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __INTERACTION_MODE_H__
#define __INTERACTION_MODE_H__
#include <openspace/interaction/keyboardcontroller.h>
#include <openspace/interaction/mousecontroller.h>
#include <openspace/network/parallelconnection.h>
#include <openspace/util/mouse.h>
#include <openspace/util/keys.h>
#include <modules/globebrowsing/globes/renderableglobe.h>
namespace openspace {
class Camera;
class SceneGraphNode;
namespace interaction {
class InputState
{
public:
InputState();
~InputState();
// Callback functions
void keyboardCallback(Key key, KeyModifier modifier, KeyAction action);
void mouseButtonCallback(MouseButton button, MouseAction action);
void mousePositionCallback(double mouseX, double mouseY);
void mouseScrollWheelCallback(double mouseScrollDelta);
// Mutators
void addKeyframe(const network::datamessagestructures::PositionKeyframe &kf);
void clearKeyframes();
// Accessors
const std::list<std::pair<Key, KeyModifier> >& getPressedKeys() const;
const std::list<MouseButton>& getPressedMouseButtons() const;
glm::dvec2 getMousePosition() const;
double getMouseScrollDelta() const;
std::vector<network::datamessagestructures::PositionKeyframe>& getKeyFrames() const;
bool isKeyPressed(std::pair<Key, KeyModifier> keyModPair) 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;
// Remote input via keyframes
std::vector<network::datamessagestructures::PositionKeyframe> _keyframes;
std::mutex _keyframeMutex;
};
class InteractionMode
{
public:
InteractionMode();
~InteractionMode();
// Mutators
virtual void setFocusNode(SceneGraphNode* focusNode);
// Accessors
SceneGraphNode* focusNode();
virtual void update(Camera& camera, const InputState& inputState, double deltaTime) = 0;
virtual void initialize(const Camera& camera) = 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 scale) {
_scale = scale;
}
void set(T value, double dt) {
_targetValue = value;
_currentValue = _currentValue + (_targetValue - _currentValue) *
min(_scale * dt, 1.0); // less or equal to 1.0 keeps it stable
}
T get() {
return _currentValue;
}
private:
ScaleType _scale;
T _targetValue;
T _currentValue;
};
struct MouseState {
MouseState(double scale)
: velocity(scale)
, previousPosition(0.0, 0.0) {}
glm::dvec2 previousPosition;
DelayedVariable<glm::dvec2, double> velocity;
};
SceneGraphNode* _focusNode = nullptr;
};
class KeyframeInteractionMode : public InteractionMode
{
public:
KeyframeInteractionMode();
~KeyframeInteractionMode();
virtual void update(double deltaTime);
virtual void initialize(const Camera& camera);
private:
double _currentKeyframeTime;
};
class OrbitalInteractionMode : public InteractionMode
{
public:
/*!
\param inputState
\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.
*/
OrbitalInteractionMode(double sensitivity, double velocityScaleFactor);
~OrbitalInteractionMode();
virtual void update(Camera& camera, const InputState& inputState, double deltaTime);
virtual void initialize(const Camera& camera);
protected:
void updateMouseStatesFromInput(const InputState& inputState, double deltaTime);
void updateCameraStateFromMouseStates(Camera& camera);
double _sensitivity;
MouseState _globalRotationMouseState;
MouseState _localRotationMouseState;
MouseState _truckMovementMouseState;
MouseState _rollMouseState;
glm::dquat _localCameraRotation;
glm::dquat _globalCameraRotation;
};
class GlobeBrowsingInteractionMode : public OrbitalInteractionMode
{
public:
GlobeBrowsingInteractionMode(double sensitivity, double velocityScaleFactor);
~GlobeBrowsingInteractionMode();
virtual void setFocusNode(SceneGraphNode* focusNode);
virtual void update(Camera& camera, const InputState& inputState, double deltaTime);
private:
void updateCameraStateFromMouseStates(Camera& camera);
RenderableGlobe* _globe;
};
} // namespace interaction
} // namespace openspace
#endif // __INTERACTION_MODE_H__

View File

@@ -38,6 +38,8 @@
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/quaternion.hpp>
#include <iostream>
namespace openspace {
/**
This class still needs some more love. Suggested improvements:
@@ -122,6 +124,9 @@ namespace openspace {
void serialize(SyncBuffer* syncBuffer);
void deserialize(SyncBuffer* syncBuffer);
void serialize(std::ostream& os) const;
void deserialize(std::istream& is);
/**
Handles SGCT's internal matrices. Also caches a calculated viewProjection
matrix. This is the data that is different for different cameras within
@@ -171,6 +176,7 @@ namespace openspace {
const glm::mat4& projectionMatrix() const;
[[deprecated("Replaced by Camera::SgctInternal::viewProjectionMatrix()")]]
const glm::mat4& viewProjectionMatrix() const;
private:
/**
Class encapsulating data that needs to be synched between SGCT nodes.

View File

@@ -177,7 +177,7 @@ namespace openspace {
_chunkedLodGlobe->lodScaleFactor = lodScaleFactor.value();
_chunkedLodGlobe->atmosphereEnabled = atmosphereEnabled.value();
_tileProviderManager->prerender();
_tileProviderManager->update();
}
glm::dvec3 RenderableGlobe::projectOnEllipsoid(glm::dvec3 position) {

View File

@@ -138,11 +138,11 @@ namespace openspace {
return _layerCategories[category];
}
void TileProviderManager::prerender() {
void TileProviderManager::update() {
for each (auto layerCategory in _layerCategories) {
for each (auto tileProviderWithName in layerCategory) {
if (tileProviderWithName.isActive) {
tileProviderWithName.tileProvider->prerender();
tileProviderWithName.tileProvider->update();
}
}
}

View File

@@ -64,7 +64,7 @@ namespace openspace {
const std::vector<std::shared_ptr<TileProvider> >
getActivatedLayerCategory(LayeredTextures::TextureCategory);
void prerender();
void update();
private:
static void initTexures(std::vector<TileProviderWithName>& destination,

View File

@@ -109,8 +109,8 @@ namespace openspace {
TileDepthTransform TemporalTileProvider::depthTransform() {
if (_currentTileProvider == nullptr) {
LDEBUG("Warning: had to call prerender from depthTransform()");
prerender();
LDEBUG("Warning: had to call update from depthTransform()");
update();
}
return _currentTileProvider->depthTransform();
@@ -118,8 +118,8 @@ namespace openspace {
Tile::Status TemporalTileProvider::getTileStatus(const ChunkIndex& chunkIndex) {
if (_currentTileProvider == nullptr) {
LDEBUG("Warning: had to call prerender from getTileStatus()");
prerender();
LDEBUG("Warning: had to call update from getTileStatus()");
update();
}
return _currentTileProvider->getTileStatus(chunkIndex);
@@ -127,8 +127,8 @@ namespace openspace {
Tile TemporalTileProvider::getTile(const ChunkIndex& chunkIndex) {
if (_currentTileProvider == nullptr) {
LDEBUG("Warning: had to call prerender from getTile()");
prerender();
LDEBUG("Warning: had to call update from getTile()");
update();
}
return _currentTileProvider->getTile(chunkIndex);
@@ -136,15 +136,15 @@ namespace openspace {
void TemporalTileProvider::prerender() {
void TemporalTileProvider::update() {
_currentTileProvider = getTileProvider();
_currentTileProvider->prerender();
_currentTileProvider->update();
}
std::shared_ptr<AsyncTileDataProvider> TemporalTileProvider::getAsyncTileReader() {
if (_currentTileProvider == nullptr) {
LDEBUG("Warning: had to call prerender from getAsyncTileReader()");
prerender();
LDEBUG("Warning: had to call update from getAsyncTileReader()");
update();
}
return _currentTileProvider->getAsyncTileReader();

View File

@@ -123,7 +123,7 @@ namespace openspace {
virtual Tile getTile(const ChunkIndex& chunkIndex);
virtual Tile::Status getTileStatus(const ChunkIndex& chunkIndex);
virtual TileDepthTransform depthTransform();
virtual void prerender();
virtual void update();
virtual std::shared_ptr<AsyncTileDataProvider> getAsyncTileReader();

View File

@@ -68,7 +68,7 @@ namespace openspace {
}
void CachingTileProvider::prerender() {
void CachingTileProvider::update() {
initTexturesFromLoadedData();
if (_framesSinceLastRequestFlush++ > _framesUntilRequestFlush) {
clearRequestQueue();

View File

@@ -70,7 +70,7 @@ namespace openspace {
virtual Tile getTile(const ChunkIndex& chunkIndex) = 0;
virtual Tile::Status getTileStatus(const ChunkIndex& index) = 0;
virtual TileDepthTransform depthTransform() = 0;
virtual void prerender() = 0;
virtual void update() = 0;
virtual std::shared_ptr<AsyncTileDataProvider> getAsyncTileReader() = 0;
};
@@ -96,7 +96,7 @@ namespace openspace {
virtual Tile getTile(const ChunkIndex& chunkIndex);
virtual Tile::Status getTileStatus(const ChunkIndex& index);
virtual TileDepthTransform depthTransform();
virtual void prerender();
virtual void update();
virtual std::shared_ptr<AsyncTileDataProvider> getAsyncTileReader();

View File

@@ -35,6 +35,7 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/interaction/controller.cpp
${OPENSPACE_BASE_DIR}/src/interaction/deviceidentifier.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/keyboardcontroller.cpp
${OPENSPACE_BASE_DIR}/src/interaction/luaconsole.cpp
@@ -109,6 +110,7 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/interaction/controller.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/deviceidentifier.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/interactionhandler.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/interactionmode.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/keyboardcontroller.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/luaconsole.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/mousecontroller.h

View File

@@ -36,6 +36,8 @@
#include <glm/gtx/quaternion.hpp>
#include <fstream>
namespace {
const std::string _loggerCat = "InteractionHandler";
}
@@ -613,380 +615,6 @@ void InteractionHandler::clearKeyframes(){
#else // USE_OLD_INTERACTIONHANDLER
// InputState
InputState::InputState() {
}
InputState::~InputState() {
}
void InputState::addKeyframe(const network::datamessagestructures::PositionKeyframe &kf) {
_keyframeMutex.lock();
//save a maximum of 10 samples (1 seconds of buffer)
if (_keyframes.size() >= 10) {
_keyframes.erase(_keyframes.begin());
}
_keyframes.push_back(kf);
_keyframeMutex.unlock();
}
void InputState::clearKeyframes() {
_keyframeMutex.lock();
_keyframes.clear();
_keyframeMutex.unlock();
}
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::isMouseButtonPressed(MouseButton mouseButton) const {
for (auto it = _mouseButtonsDown.begin(); it != _mouseButtonsDown.end(); it++) {
if (*it == mouseButton) {
return true;
}
}
return false;
}
InteractionMode::InteractionMode() {
}
InteractionMode::~InteractionMode() {
}
void InteractionMode::setFocusNode(SceneGraphNode* focusNode) {
_focusNode = focusNode;
}
SceneGraphNode* InteractionMode::focusNode() {
return _focusNode;
}
// KeyframeInteractionMode
KeyframeInteractionMode::KeyframeInteractionMode(){
}
KeyframeInteractionMode::~KeyframeInteractionMode() {
}
void KeyframeInteractionMode::update(double deltaTime) {
// TODO : Get keyframes from input state and use them to position and rotate the camera
}
// OrbitalInteractionMode
OrbitalInteractionMode::OrbitalInteractionMode(double sensitivity, double velocityScaleFactor)
: _sensitivity(sensitivity)
, _globalRotationMouseState(velocityScaleFactor)
, _localRotationMouseState(velocityScaleFactor)
, _truckMovementMouseState(velocityScaleFactor)
, _rollMouseState(velocityScaleFactor) {
}
OrbitalInteractionMode::~OrbitalInteractionMode() {
}
void OrbitalInteractionMode::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(
std::pair<Key, KeyModifier>(Key::LeftControl, KeyModifier::Control));
// Update the mouse states
if (button1Pressed) {
if (keyCtrlPressed) {
glm::dvec2 mousePositionDelta =
_localRotationMouseState.previousPosition - mousePosition;
_localRotationMouseState.velocity.set(mousePositionDelta * deltaTime * _sensitivity, deltaTime);
_globalRotationMouseState.previousPosition = mousePosition;
_globalRotationMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
}
else {
glm::dvec2 mousePositionDelta =
_globalRotationMouseState.previousPosition - mousePosition;
_globalRotationMouseState.velocity.set(mousePositionDelta * deltaTime * _sensitivity, deltaTime);
_localRotationMouseState.previousPosition = mousePosition;
_localRotationMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
}
}
else { // !button1Pressed
_localRotationMouseState.previousPosition = mousePosition;
_localRotationMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
_globalRotationMouseState.previousPosition = mousePosition;
_globalRotationMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
}
if (button2Pressed) {
glm::dvec2 mousePositionDelta =
_truckMovementMouseState.previousPosition - mousePosition;
_truckMovementMouseState.velocity.set(mousePositionDelta * deltaTime * _sensitivity, deltaTime);
}
else { // !button2Pressed
_truckMovementMouseState.previousPosition = mousePosition;
_truckMovementMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
}
if (button3Pressed) {
glm::dvec2 mousePositionDelta =
_rollMouseState.previousPosition - mousePosition;
_rollMouseState.velocity.set(mousePositionDelta * deltaTime * _sensitivity, deltaTime);
}
else { // !button3Pressed
_rollMouseState.previousPosition = mousePosition;
_rollMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
}
}
void OrbitalInteractionMode::updateCameraStateFromMouseStates(Camera& camera) {
if (_focusNode) {
// Declare variables to use in interaction calculations
glm::dvec3 centerPos = _focusNode->worldPosition().dvec3();
glm::dvec3 camPos = camera.positionVec3();
glm::dvec3 posDiff = camPos - centerPos;
glm::dvec3 newPosition = camPos;
{ // Do local rotation
glm::dvec3 eulerAngles(_localRotationMouseState.velocity.get().y, 0, 0);
glm::dquat rotationDiff = glm::dquat(eulerAngles);
_localCameraRotation = _localCameraRotation * rotationDiff;
}
{ // Do global rotation
glm::dvec3 eulerAngles(
-_globalRotationMouseState.velocity.get().y,
-_globalRotationMouseState.velocity.get().x,
0);
glm::dquat rotationDiffCamSpace = glm::dquat(eulerAngles);
glm::dquat newRotationCamspace =
_globalCameraRotation * rotationDiffCamSpace;
glm::dquat rotationDiffWorldSpace =
newRotationCamspace * glm::inverse(_globalCameraRotation);
glm::dvec3 rotationDiffVec3 = posDiff * rotationDiffWorldSpace - posDiff;
newPosition = camPos + rotationDiffVec3;
glm::dvec3 directionToCenter = glm::normalize(centerPos - newPosition);
glm::dvec3 lookUpWhenFacingCenter =
_globalCameraRotation * glm::dvec3(camera.lookUpVectorCameraSpace());
glm::dmat4 lookAtMat = glm::lookAt(
glm::dvec3(0, 0, 0),
directionToCenter,
lookUpWhenFacingCenter);
_globalCameraRotation =
glm::normalize(glm::quat_cast(glm::inverse(lookAtMat)));
}
{ // Move position towards or away from focus node
double boundingSphere = _focusNode->boundingSphere().lengthf();
glm::dvec3 centerToBoundingSphere =
glm::normalize(posDiff) *
static_cast<double>(_focusNode->boundingSphere().lengthf());
newPosition += -(posDiff - centerToBoundingSphere) *
_truckMovementMouseState.velocity.get().y;
}
{ // Do roll
glm::dquat cameraRollRotation =
glm::angleAxis(_rollMouseState.velocity.get().x, glm::normalize(posDiff));
_globalCameraRotation = cameraRollRotation * _globalCameraRotation;
}
// Update the camera state
camera.setRotation(_globalCameraRotation * _localCameraRotation);
camera.setPositionVec3(newPosition);
}
}
void OrbitalInteractionMode::update(Camera& camera, const InputState& inputState, double deltaTime) {
updateMouseStatesFromInput(inputState, deltaTime);
updateCameraStateFromMouseStates(camera);
}
GlobeBrowsingInteractionMode::GlobeBrowsingInteractionMode(double sensitivity, double velocityScaleFactor)
: OrbitalInteractionMode(sensitivity, velocityScaleFactor)
{
}
GlobeBrowsingInteractionMode::~GlobeBrowsingInteractionMode() {
}
void GlobeBrowsingInteractionMode::setFocusNode(SceneGraphNode* focusNode) {
_focusNode = focusNode;
Renderable* baseRenderable = _focusNode->renderable();
if (RenderableGlobe* globe = dynamic_cast<RenderableGlobe*>(baseRenderable)) {
_globe = globe;
}
else {
LWARNING("Focus node is not a renderable globe. GlobeBrowsingInteraction is not possible");
_globe = nullptr;
}
}
void GlobeBrowsingInteractionMode::updateCameraStateFromMouseStates(Camera& camera) {
if (_focusNode && _globe) {
// Declare variables to use in interaction calculations
// Shrink interaction ellipsoid to enable interaction below height = 0
double ellipsoidShrinkTerm = 10000.0;
double minHeightAboveGround = 100.0;
glm::dvec3 centerPos = _focusNode->worldPosition().dvec3();
glm::dvec3 camPos = camera.positionVec3();
glm::dvec3 posDiff = camPos - centerPos;
glm::dvec3 directionFromSurfaceToCamera =
_globe->ellipsoid().geodeticSurfaceNormal(
_globe->ellipsoid().cartesianToGeodetic2(camPos));
glm::dvec3 centerToEllipsoidSurface = _globe->projectOnEllipsoid(camPos) -
directionFromSurfaceToCamera * ellipsoidShrinkTerm;
glm::dvec3 ellipsoidSurfaceToCamera = camPos - (centerPos + centerToEllipsoidSurface);
double distFromCenterToSurface =
glm::length(centerToEllipsoidSurface);
double distFromEllipsoidSurfaceToCamera = glm::length(ellipsoidSurfaceToCamera);
double distFromCenterToCamera = glm::length(posDiff);
{ // Do local rotation
glm::dvec3 eulerAngles(_localRotationMouseState.velocity.get().y, 0, 0);
glm::dquat rotationDiff = glm::dquat(eulerAngles);
_localCameraRotation = _localCameraRotation * rotationDiff;
}
{ // Do global rotation
glm::dvec3 eulerAngles = glm::dvec3(
-_globalRotationMouseState.velocity.get().y,
-_globalRotationMouseState.velocity.get().x,
0) * glm::clamp(distFromEllipsoidSurfaceToCamera / 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 = camPos + rotationDiffVec3;
directionFromSurfaceToCamera =
_globe->ellipsoid().geodeticSurfaceNormal(
_globe->ellipsoid().cartesianToGeodetic2(camPos));
centerToEllipsoidSurface = _globe->projectOnEllipsoid(camPos) -
directionFromSurfaceToCamera * ellipsoidShrinkTerm;
ellipsoidSurfaceToCamera = camPos - (centerPos + centerToEllipsoidSurface);
glm::dvec3 lookUpWhenFacingSurface =
_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
distFromEllipsoidSurfaceToCamera = glm::length(ellipsoidSurfaceToCamera);
camPos += -directionFromSurfaceToCamera * distFromEllipsoidSurfaceToCamera *
_truckMovementMouseState.velocity.get().y;
}
{ // Do roll
glm::dquat cameraRollRotation =
glm::angleAxis(_rollMouseState.velocity.get().x, directionFromSurfaceToCamera);
_globalCameraRotation = cameraRollRotation * _globalCameraRotation;
}
{ // Push up to surface
ellipsoidSurfaceToCamera = camPos - (centerPos + centerToEllipsoidSurface);
distFromEllipsoidSurfaceToCamera = glm::length(ellipsoidSurfaceToCamera);
double heightToSurface = _globe->getHeight(camPos) + ellipsoidShrinkTerm;
double heightToSurfaceAndPadding = heightToSurface + minHeightAboveGround;
camPos += directionFromSurfaceToCamera *
glm::max(heightToSurfaceAndPadding - distFromEllipsoidSurfaceToCamera, 0.0);
}
// Update the camera state
camera.setRotation(_globalCameraRotation * _localCameraRotation);
camera.setPositionVec3(camPos);
}
}
void GlobeBrowsingInteractionMode::update(Camera& camera, const InputState& inputState, double deltaTime) {
updateMouseStatesFromInput(inputState, deltaTime);
updateCameraStateFromMouseStates(camera);
}
// InteractionHandler
InteractionHandler::InteractionHandler()
@@ -1060,7 +688,13 @@ void InteractionHandler::unlockControls() {
void InteractionHandler::update(double deltaTime) {
ghoul_assert(_inputState != nullptr, "InputState cannot be null!");
ghoul_assert(_camera != nullptr, "Camera cannot be null!");
_currentInteractionMode->update(*_camera, *_inputState, deltaTime);
if (_cameraUpdatedFromScript) {
_cameraUpdatedFromScript = false;
}
else {
_currentInteractionMode->update(*_camera, *_inputState, deltaTime);
}
}
SceneGraphNode* const InteractionHandler::focusNode() const {
@@ -1101,6 +735,39 @@ void InteractionHandler::keyboardCallback(Key key, KeyModifier modifier, KeyActi
}
}
void InteractionHandler::saveCameraPosition(const std::string& filepath) {
if (!filepath.empty()) {
auto fullpath = absPath(filepath);
LDEBUG("Saving camera position: " << fullpath);
std::ofstream ofs(fullpath.c_str());
_camera->serialize(ofs);
ofs.close();
}
}
void InteractionHandler::restoreCameraPosition(const std::string& filepath) {
if (!filepath.empty()) {
auto fullpath = absPath(filepath);
LDEBUG("Reading camera position: " << fullpath);
std::ifstream ifs(fullpath.c_str());
Camera c;
c.deserialize(ifs);
ifs.close();
// uff, need to do this ...
c.preSynchronization();
c.postSynchronizationPreDraw();
auto p = c.positionVec3();
auto r = c.rotationQuaternion();
_camera->setPositionVec3(p);
_camera->setRotation(r);
_currentInteractionMode->initialize(*_camera);
_cameraUpdatedFromScript = true;
}
}
void InteractionHandler::resetKeyBindings() {
_keyLua.clear();
}
@@ -1133,6 +800,18 @@ scripting::ScriptEngine::LuaLibrary InteractionHandler::luaLibrary() {
&luascriptfunctions::setInteractionMode,
"string",
"Set the interaction mode for the camera"
},
{
"saveCameraPosition",
&luascriptfunctions::saveCameraPosition,
"string",
"Save the current camera position to file"
},
{
"restoreCameraPosition",
&luascriptfunctions::restoreCameraPosition,
"string",
"Restore the camera position from file"
}
}
};

View File

@@ -143,6 +143,39 @@ int setInteractionMode(lua_State* L) {
return 0;
}
int restoreCameraPosition(lua_State* L) {
using ghoul::lua::luaTypeToString;
const std::string _loggerCat = "lua.setCameraPosition";
int nArguments = lua_gettop(L);
if (nArguments != 1)
return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments);
std::string cameraPosFilePath = luaL_checkstring(L, -1);
if (cameraPosFilePath.empty())
return luaL_error(L, "filepath string is empty");
OsEng.interactionHandler().restoreCameraPosition(cameraPosFilePath);
return 0;
}
int saveCameraPosition(lua_State* L) {
using ghoul::lua::luaTypeToString;
const std::string _loggerCat = "lua.setCameraPosition";
int nArguments = lua_gettop(L);
if (nArguments != 1)
return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments);
std::string cameraPosFilePath = luaL_checkstring(L, -1);
if (cameraPosFilePath.empty())
return luaL_error(L, "filepath string is empty");
OsEng.interactionHandler().saveCameraPosition(cameraPosFilePath);
}
#ifdef USE_OLD_INTERACTIONHANDLER
/**

View File

@@ -0,0 +1,436 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2016 *
* *
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
* software and associated documentation files (the "Software"), to deal in the Software *
* without restriction, including without limitation the rights to use, copy, modify, *
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
* permit persons to whom the Software is furnished to do so, subject to the following *
* conditions: *
* *
* The above copyright notice and this permission notice shall be included in all copies *
* or substantial portions of the Software. *
* *
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#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/util/time.h>
#include <openspace/util/keys.h>
#include <ghoul/logging/logmanager.h>
#include <glm/gtx/quaternion.hpp>
namespace {
const std::string _loggerCat = "InteractionMode";
}
namespace openspace {
namespace interaction {
// InputState
InputState::InputState() {
}
InputState::~InputState() {
}
void InputState::addKeyframe(const network::datamessagestructures::PositionKeyframe &kf) {
_keyframeMutex.lock();
//save a maximum of 10 samples (1 seconds of buffer)
if (_keyframes.size() >= 10) {
_keyframes.erase(_keyframes.begin());
}
_keyframes.push_back(kf);
_keyframeMutex.unlock();
}
void InputState::clearKeyframes() {
_keyframeMutex.lock();
_keyframes.clear();
_keyframeMutex.unlock();
}
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::isMouseButtonPressed(MouseButton mouseButton) const {
for (auto it = _mouseButtonsDown.begin(); it != _mouseButtonsDown.end(); it++) {
if (*it == mouseButton) {
return true;
}
}
return false;
}
InteractionMode::InteractionMode() {
}
InteractionMode::~InteractionMode() {
}
void InteractionMode::setFocusNode(SceneGraphNode* focusNode) {
_focusNode = focusNode;
}
SceneGraphNode* InteractionMode::focusNode() {
return _focusNode;
}
// KeyframeInteractionMode
KeyframeInteractionMode::KeyframeInteractionMode(){
}
KeyframeInteractionMode::~KeyframeInteractionMode() {
}
void KeyframeInteractionMode::update(double deltaTime) {
// TODO : Get keyframes from input state and use them to position and rotate the camera
}
void KeyframeInteractionMode::initialize(const Camera& camera) {
LWARNING("KeyframeInteractionMode::initialize not implemented yet");
}
// OrbitalInteractionMode
OrbitalInteractionMode::OrbitalInteractionMode(double sensitivity, double velocityScaleFactor)
: _sensitivity(sensitivity)
, _globalRotationMouseState(velocityScaleFactor)
, _localRotationMouseState(velocityScaleFactor)
, _truckMovementMouseState(velocityScaleFactor)
, _rollMouseState(velocityScaleFactor) {
}
OrbitalInteractionMode::~OrbitalInteractionMode() {
}
void OrbitalInteractionMode::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(
std::pair<Key, KeyModifier>(Key::LeftControl, KeyModifier::Control));
// Update the mouse states
if (button1Pressed) {
if (keyCtrlPressed) {
glm::dvec2 mousePositionDelta =
_localRotationMouseState.previousPosition - mousePosition;
_localRotationMouseState.velocity.set(mousePositionDelta * deltaTime * _sensitivity, deltaTime);
_globalRotationMouseState.previousPosition = mousePosition;
_globalRotationMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
}
else {
glm::dvec2 mousePositionDelta =
_globalRotationMouseState.previousPosition - mousePosition;
_globalRotationMouseState.velocity.set(mousePositionDelta * deltaTime * _sensitivity, deltaTime);
_localRotationMouseState.previousPosition = mousePosition;
_localRotationMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
}
}
else { // !button1Pressed
_localRotationMouseState.previousPosition = mousePosition;
_localRotationMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
_globalRotationMouseState.previousPosition = mousePosition;
_globalRotationMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
}
if (button2Pressed) {
glm::dvec2 mousePositionDelta =
_truckMovementMouseState.previousPosition - mousePosition;
_truckMovementMouseState.velocity.set(mousePositionDelta * deltaTime * _sensitivity, deltaTime);
}
else { // !button2Pressed
_truckMovementMouseState.previousPosition = mousePosition;
_truckMovementMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
}
if (button3Pressed) {
glm::dvec2 mousePositionDelta =
_rollMouseState.previousPosition - mousePosition;
_rollMouseState.velocity.set(mousePositionDelta * deltaTime * _sensitivity, deltaTime);
}
else { // !button3Pressed
_rollMouseState.previousPosition = mousePosition;
_rollMouseState.velocity.set(glm::dvec2(0, 0), deltaTime);
}
}
void OrbitalInteractionMode::updateCameraStateFromMouseStates(Camera& camera) {
using namespace glm;
if (_focusNode) {
// Declare variables to use in interaction calculations
dvec3 centerPos = _focusNode->worldPosition().dvec3();
dvec3 camPos = camera.positionVec3();
dvec3 posDiff = camPos - centerPos;
dvec3 newPosition = camPos;
{ // Do local rotation
dvec3 eulerAngles(_localRotationMouseState.velocity.get().y, 0, 0);
dquat rotationDiff = dquat(eulerAngles);
_localCameraRotation = _localCameraRotation * rotationDiff;
}
{ // Do global rotation
dvec2 smoothMouseVelocity = _globalRotationMouseState.velocity.get();
dvec3 eulerAngles(smoothMouseVelocity.x, smoothMouseVelocity.y, 0);
dquat rotationDiffCamSpace = dquat(eulerAngles);
dquat newRotationCamspace = _globalCameraRotation * rotationDiffCamSpace;
dquat rotationDiffWorldSpace = newRotationCamspace * inverse(_globalCameraRotation);
dvec3 rotationDiffVec3 = posDiff * rotationDiffWorldSpace - posDiff;
newPosition = camPos + rotationDiffVec3;
dvec3 directionToCenter = normalize(centerPos - newPosition);
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
double boundingSphere = _focusNode->boundingSphere().lengthf();
dvec3 centerToBoundingSphere =
normalize(posDiff) *
static_cast<double>(_focusNode->boundingSphere().lengthf());
newPosition += -(posDiff - centerToBoundingSphere) *
_truckMovementMouseState.velocity.get().y;
}
{ // Do roll
dquat cameraRollRotation =
angleAxis(_rollMouseState.velocity.get().x, normalize(posDiff));
_globalCameraRotation = cameraRollRotation * _globalCameraRotation;
}
// Update the camera state
camera.setRotation(_globalCameraRotation * _localCameraRotation);
camera.setPositionVec3(newPosition);
}
}
void OrbitalInteractionMode::update(Camera& camera, const InputState& inputState, double deltaTime) {
updateMouseStatesFromInput(inputState, deltaTime);
updateCameraStateFromMouseStates(camera);
}
void OrbitalInteractionMode::initialize(const Camera& camera) {
LWARNING("Interaction has not implemented sync to camera. I.e. interaction \
mode may contain staate that is not transferred when reading camera state from disk");
// @Todo : extract _localCameraRotation and _globalCameraRotation from camera state
}
GlobeBrowsingInteractionMode::GlobeBrowsingInteractionMode(double sensitivity, double velocityScaleFactor)
: OrbitalInteractionMode(sensitivity, velocityScaleFactor)
{
}
GlobeBrowsingInteractionMode::~GlobeBrowsingInteractionMode() {
}
void GlobeBrowsingInteractionMode::setFocusNode(SceneGraphNode* focusNode) {
_focusNode = focusNode;
Renderable* baseRenderable = _focusNode->renderable();
if (RenderableGlobe* globe = dynamic_cast<RenderableGlobe*>(baseRenderable)) {
_globe = globe;
}
else {
LWARNING("Focus node is not a renderable globe. GlobeBrowsingInteraction is not possible");
_globe = nullptr;
}
}
void GlobeBrowsingInteractionMode::updateCameraStateFromMouseStates(Camera& camera) {
if (_focusNode && _globe) {
// Declare variables to use in interaction calculations
// Shrink interaction ellipsoid to enable interaction below height = 0
double ellipsoidShrinkTerm = 10000.0;
double minHeightAboveGround = 100.0;
glm::dvec3 centerPos = _focusNode->worldPosition().dvec3();
glm::dvec3 camPos = camera.positionVec3();
glm::dvec3 posDiff = camPos - centerPos;
glm::dvec3 directionFromSurfaceToCamera =
_globe->ellipsoid().geodeticSurfaceNormal(
_globe->ellipsoid().cartesianToGeodetic2(camPos));
glm::dvec3 centerToEllipsoidSurface = _globe->projectOnEllipsoid(camPos) -
directionFromSurfaceToCamera * ellipsoidShrinkTerm;
glm::dvec3 ellipsoidSurfaceToCamera = camPos - (centerPos + centerToEllipsoidSurface);
double distFromCenterToSurface =
glm::length(centerToEllipsoidSurface);
double distFromEllipsoidSurfaceToCamera = glm::length(ellipsoidSurfaceToCamera);
double distFromCenterToCamera = glm::length(posDiff);
{ // Do local rotation
glm::dvec3 eulerAngles(_localRotationMouseState.velocity.get().y, 0, 0);
glm::dquat rotationDiff = glm::dquat(eulerAngles);
_localCameraRotation = _localCameraRotation * rotationDiff;
}
{ // Do global rotation
glm::dvec3 eulerAngles = glm::dvec3(
-_globalRotationMouseState.velocity.get().y,
-_globalRotationMouseState.velocity.get().x,
0) * glm::clamp(distFromEllipsoidSurfaceToCamera / 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 = camPos + rotationDiffVec3;
directionFromSurfaceToCamera =
_globe->ellipsoid().geodeticSurfaceNormal(
_globe->ellipsoid().cartesianToGeodetic2(camPos));
centerToEllipsoidSurface = _globe->projectOnEllipsoid(camPos) -
directionFromSurfaceToCamera * ellipsoidShrinkTerm;
ellipsoidSurfaceToCamera = camPos - (centerPos + centerToEllipsoidSurface);
glm::dvec3 lookUpWhenFacingSurface =
_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
distFromEllipsoidSurfaceToCamera = glm::length(ellipsoidSurfaceToCamera);
camPos += -directionFromSurfaceToCamera * distFromEllipsoidSurfaceToCamera *
_truckMovementMouseState.velocity.get().y;
}
{ // Do roll
glm::dquat cameraRollRotation =
glm::angleAxis(_rollMouseState.velocity.get().x, directionFromSurfaceToCamera);
_globalCameraRotation = cameraRollRotation * _globalCameraRotation;
}
{ // Push up to surface
ellipsoidSurfaceToCamera = camPos - (centerPos + centerToEllipsoidSurface);
distFromEllipsoidSurfaceToCamera = glm::length(ellipsoidSurfaceToCamera);
double heightToSurface = _globe->getHeight(camPos) + ellipsoidShrinkTerm;
double heightToSurfaceAndPadding = heightToSurface + minHeightAboveGround;
camPos += directionFromSurfaceToCamera *
glm::max(heightToSurfaceAndPadding - distFromEllipsoidSurfaceToCamera, 0.0);
}
// Update the camera state
camera.setRotation(_globalCameraRotation * _localCameraRotation);
camera.setPositionVec3(camPos);
}
}
void GlobeBrowsingInteractionMode::update(Camera& camera, const InputState& inputState, double deltaTime) {
updateMouseStatesFromInput(inputState, deltaTime);
updateCameraStateFromMouseStates(camera);
}
} // namespace interaction
} // namespace openspace

View File

@@ -190,6 +190,22 @@ namespace openspace {
_cachedViewDirection.isDirty = true;
}
void Camera::serialize(std::ostream& os) const {
Vec3 p = positionVec3();
Quat q = rotationQuaternion();
os << p.x << " " << p.y << " " << p.z << std::endl;
os << q.x << " " << q.y << " " << q.z << " " << q.w << std::endl;
}
void Camera::deserialize(std::istream& is) {
Vec3 p;
Quat q;
is >> p.x >> p.y >> p.z;
is >> q.x >> q.y >> q.z >> q.w;
setPositionVec3(p);
setRotation(q);
}
void Camera::preSynchronization() {
std::lock_guard<std::mutex> _lock(_mutex);