From 752081d31be6eb88f625fd44049dd15b32e72315 Mon Sep 17 00:00:00 2001 From: Emil Axelsson Date: Mon, 22 May 2017 14:01:08 +0200 Subject: [PATCH] feature/time-refactor (#294) - Change Time class to become a non-singleton - Move ownership of the current time to TimeManager(instead of singleton access). - Store the Time as a Syncable in TimeManager instead of representing all member variables of Time as Syncables. - Pass a Time object around in the update/render methods, so that renderables don't have to query the OpenSpaceEngine to know if time is paused or if it jumped. - Introduce Timeline and Keyframe classes - Make use of Timelineand Keyframeclasses in KeyframeInteractionMode and TimeManager - Added basic unit tests for Timelineand Keyframe Future work: Add interpolation schemes for keyframes. Possibly use keyframes+interpolation feature to tween/morph properties, or figure out if this should be a separate mechanism. --- .../interaction/interactionhandler.h | 16 ++- .../openspace/interaction/interactionmode.h | 23 ++-- include/openspace/util/time.h | 27 +--- include/openspace/util/timeline.h | 96 +++++++++++++ include/openspace/util/timeline.inl | 121 ++++++++++++++++ include/openspace/util/timemanager.h | 16 ++- include/openspace/util/updatestructures.h | 9 +- .../rendering/renderablesphericalgrid.cpp | 2 +- .../base/rendering/renderabletrailorbit.cpp | 14 +- .../rendering/renderabletrailtrajectory.cpp | 6 +- .../globebrowsing/globes/renderableglobe.cpp | 2 +- .../tile/tileprovider/temporaltileprovider.h | 4 +- modules/iswa/rendering/iswacygnet.h | 5 +- modules/iswa/util/iswamanager.h | 5 +- .../rendering/renderablemultiresvolume.cpp | 4 +- .../rendering/renderablecrawlingline.cpp | 4 +- .../newhorizons/rendering/renderablefov.cpp | 22 +-- .../rendering/renderablemodelprojection.cpp | 2 +- .../rendering/renderableplaneprojection.cpp | 2 +- .../rendering/renderableplanetprojection.cpp | 3 +- .../rendering/renderableshadowcylinder.cpp | 4 +- modules/newhorizons/util/imagesequencer.cpp | 14 +- modules/newhorizons/util/imagesequencer.h | 3 +- .../onscreengui/src/guiparallelcomponent.cpp | 8 +- modules/onscreengui/src/guitimecomponent.cpp | 3 +- .../renderableconstellationbounds.cpp | 2 +- modules/space/rendering/renderableplanet.cpp | 2 +- modules/space/rotation/spicerotation.cpp | 2 +- .../space/translation/keplertranslation.cpp | 2 +- .../space/translation/spicetranslation.cpp | 2 +- .../rendering/renderabletoyvolume.cpp | 2 +- src/CMakeLists.txt | 3 + src/engine/openspaceengine.cpp | 10 +- src/interaction/interactionhandler.cpp | 130 +++++++++--------- src/interaction/interactionhandler_lua.inl | 22 --- src/interaction/interactionmode.cpp | 117 ++++++---------- src/network/networkengine.cpp | 9 +- src/network/parallelconnection.cpp | 26 +++- src/rendering/abufferrenderer.cpp | 4 +- src/rendering/framebufferrenderer.cpp | 5 +- src/rendering/renderengine.cpp | 18 +-- src/scene/scenegraphnode.cpp | 1 + src/scene/translation.cpp | 3 - src/scripting/scriptscheduler.cpp | 2 +- src/util/time.cpp | 30 +--- src/util/time_lua.inl | 16 +-- src/util/timeline.cpp | 41 ++++++ src/util/timemanager.cpp | 113 ++++++++------- tests/main.cpp | 1 + tests/test_scriptscheduler.inl | 120 ++++++++-------- tests/test_timeline.inl | 100 ++++++++++++++ 51 files changed, 745 insertions(+), 453 deletions(-) create mode 100644 include/openspace/util/timeline.h create mode 100644 include/openspace/util/timeline.inl create mode 100644 src/util/timeline.cpp create mode 100644 tests/test_timeline.inl diff --git a/include/openspace/interaction/interactionhandler.h b/include/openspace/interaction/interactionhandler.h index 891dfca494..162404d227 100644 --- a/include/openspace/interaction/interactionhandler.h +++ b/include/openspace/interaction/interactionhandler.h @@ -65,7 +65,6 @@ public: // Interaction mode setters void setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict); - void setInteractionMode(const std::string& interactionModeKey); InteractionMode* interactionMode(); void goToChunk(int x, int y, int level); @@ -73,9 +72,10 @@ public: void resetKeyBindings(); - void addKeyframe(const datamessagestructures::CameraKeyframe &kf); + void addKeyframe(double timestamp, KeyframeInteractionMode::CameraPose pose); void removeKeyframesAfter(double timestamp); void clearKeyframes(); + size_t nKeyframes() const; const std::vector& keyframes() const; void bindKeyLocal( @@ -134,7 +134,7 @@ private: std::string generateJson() const override; - void setInteractionMode(std::shared_ptr interactionMode); + void setInteractionMode(InteractionMode* interactionMode); bool _cameraUpdatedFromScript = false; @@ -143,14 +143,18 @@ private: std::unique_ptr _inputState; Camera* _camera; - std::shared_ptr _currentInteractionMode; + InteractionMode* _currentInteractionMode; - std::map> _interactionModes; std::shared_ptr _mouseStates; + std::unique_ptr _orbitalInteractionMode; + std::unique_ptr _globeBrowsingInteractionMode; + std::unique_ptr _keyframeInteractionMode; + // Properties properties::StringProperty _origin; - + properties::OptionProperty _interactionModeOption; + properties::BoolProperty _rotationalFriction; properties::BoolProperty _horizontalFriction; properties::BoolProperty _verticalFriction; diff --git a/include/openspace/interaction/interactionmode.h b/include/openspace/interaction/interactionmode.h index 0698e2992e..dc99ec1498 100644 --- a/include/openspace/interaction/interactionmode.h +++ b/include/openspace/interaction/interactionmode.h @@ -28,6 +28,7 @@ #include #include #include +#include #ifdef OPENSPACE_MODULE_GLOBEBROWSING_ENABLED #include @@ -80,14 +81,6 @@ namespace interaction { void mousePositionCallback(double mouseX, double mouseY); void mouseScrollWheelCallback(double mouseScrollDelta); - // Mutators - void addKeyframe(const datamessagestructures::CameraKeyframe &kf); - void removeKeyframesAfter(double timestamp); - void clearKeyframes(); - void clearOldKeyframes(); - - static bool compareKeyframeTimes(const datamessagestructures::CameraKeyframe& a, const datamessagestructures::CameraKeyframe& b); - // Accessors const std::list >& getPressedKeys() const; const std::list& getPressedMouseButtons() const; @@ -104,9 +97,6 @@ namespace interaction { std::list _mouseButtonsDown; glm::dvec2 _mousePosition; double _mouseScrollDelta; - - // Remote input via keyframes - std::vector _keyframes; }; @@ -194,16 +184,23 @@ protected: 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& timeline(); private: - std::vector _keyframes; - double _currentKeyframeTime; + Timeline _cameraPoseTimeline; }; class GlobeBrowsingInteractionMode; diff --git a/include/openspace/util/time.h b/include/openspace/util/time.h index 5241d21a61..947f7a0948 100644 --- a/include/openspace/util/time.h +++ b/include/openspace/util/time.h @@ -55,8 +55,6 @@ namespace openspace { * The synchronization of the simulation time requires */ -class SyncBuffer; - class Time { public: /** @@ -90,20 +88,6 @@ public: static Time now(); - /** - * Returns the reference to the Time singleton object. - * \return The reference to the Time singleton object - * \pre The Time singleton must have been initialized - */ - static Time& ref(); - - /** - * Returns true if the singleton has been successfully initialized, - * false otherwise - * \return true if the singleton has been successfully initialized, - * false otherwise - */ - static bool isInitialized(); /** * Sets the current time to the specified value in seconds past the J2000 epoch. This @@ -210,15 +194,10 @@ public: */ static scripting::LuaLibrary luaLibrary(); - std::vector getSyncables(); - private: - static Time* _instance; ///< The singleton instance - - SyncData _time; - SyncData _dt; - SyncData _timeJumped; - + double _time; + double _dt; + bool _timeJumped; bool _timePaused = false; }; diff --git a/include/openspace/util/timeline.h b/include/openspace/util/timeline.h new file mode 100644 index 0000000000..794aecf96a --- /dev/null +++ b/include/openspace/util/timeline.h @@ -0,0 +1,96 @@ +/***************************************************************************************** + * * + * 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___TIMELINE___H__ +#define __OPENSPACE_CORE___TIMELINE___H__ + +#include +#include +#include + +namespace openspace { + +/** +* Base class for keyframes +*/ +struct KeyframeBase { + size_t id; + double timestamp; +}; + +/** +* Templated class for keyframes containing data +*/ +template +struct Keyframe : public KeyframeBase { + Keyframe(size_t i, double t, T p) + : KeyframeBase{i, t} + , data(p) + {} + T data; +}; + +/** +* Templated class for timelines +*/ +template +class Timeline { +public: + Timeline(); + virtual ~Timeline(); + void addKeyframe(double time, T data); + void clearKeyframes(); + void removeKeyframe(size_t id); + void removeKeyframesBefore(double timestamp, bool inclusive = false); + void removeKeyframesAfter(double timestamp, bool inclusive = false); + void removeKeyframesBetween(double begin, double end, bool inclusiveBegin = false, bool inclusiveEnd = false); + size_t nKeyframes() const; + const Keyframe* firstKeyframeAfter(double timestamp, bool inclusive = false) const; + const Keyframe* lastKeyframeBefore(double timestamp, bool inclusive = false) const; + const std::deque>& keyframes() const; +private: + size_t _nextKeyframeId; + std::deque> _keyframes; +}; + +/** +* Return true if the timestamp of a is smaller the timestamp of b. +*/ +bool compareKeyframeTimes(const KeyframeBase& a, const KeyframeBase& b); + +/** +* Return true if a is smaller than the timestamp of b. +*/ +bool compareTimeWithKeyframeTime(double a, const KeyframeBase& b); + +/** +* Return true if the timestamp of a is smaller than b. +*/ +bool compareKeyframeTimeWithTime(const KeyframeBase& a, double b); + +} // namespace openspace + +#include ; + +#endif // __OPENSPACE_CORE___TIMELINE___H__ diff --git a/include/openspace/util/timeline.inl b/include/openspace/util/timeline.inl new file mode 100644 index 0000000000..f3b4a3774f --- /dev/null +++ b/include/openspace/util/timeline.inl @@ -0,0 +1,121 @@ +/***************************************************************************************** + * * + * 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 { + +template +Timeline::Timeline() + : _nextKeyframeId(1) +{} + +template +Timeline::~Timeline() {} + +template +void Timeline::addKeyframe(double timestamp, T data) { + Keyframe keyframe(++_nextKeyframeId, timestamp, data); + auto iter = std::upper_bound(_keyframes.begin(), _keyframes.end(), keyframe, &compareKeyframeTimes); + _keyframes.insert(iter, keyframe); +} + +template +void Timeline::removeKeyframesAfter(double timestamp, bool inclusive) { + auto iter = inclusive + ? std::lower_bound(_keyframes.begin(), _keyframes.end(), timestamp, &compareKeyframeTimeWithTime) + : std::upper_bound(_keyframes.begin(), _keyframes.end(), timestamp, &compareTimeWithKeyframeTime); + + _keyframes.erase(iter, _keyframes.end()); +} + +template +void Timeline::removeKeyframesBefore(double timestamp, bool inclusive) { + auto iter = inclusive + ? std::upper_bound(_keyframes.begin(), _keyframes.end(), timestamp, &compareTimeWithKeyframeTime) + : std::lower_bound(_keyframes.begin(), _keyframes.end(), timestamp, &compareKeyframeTimeWithTime); + + _keyframes.erase(_keyframes.begin(), iter); +} + +template +void Timeline::removeKeyframesBetween(double begin, double end, bool inclusiveBegin, bool inclusiveEnd) { + auto beginIter = inclusiveBegin + ? std::lower_bound(_keyframes.begin(), _keyframes.end(), begin, &compareKeyframeTimeWithTime) + : std::upper_bound(_keyframes.begin(), _keyframes.end(), begin, &compareTimeWithKeyframeTime); + + auto endIter = inclusiveEnd + ? std::upper_bound(beginIter, _keyframes.end(), end, &compareTimeWithKeyframeTime) + : std::lower_bound(beginIter, _keyframes.end(), end, &compareKeyframeTimeWithTime); + + _keyframes.erase(beginIter, endIter); +} + +template +void Timeline::clearKeyframes() { + _keyframes.clear(); +} + +template +void Timeline::removeKeyframe(size_t id) { + _keyframes.erase(std::remove_if(_keyframes.begin(), _keyframes.end(), [id] (Keyframe keyframe) { + return keyframe.id == id; + }), _keyframes.end()); +} + +template +size_t Timeline::nKeyframes() const { + return _keyframes.size(); +} + +template +const Keyframe* Timeline::firstKeyframeAfter(double timestamp, bool inclusive) const { + auto it = inclusive + ? std::lower_bound(_keyframes.begin(), _keyframes.end(), timestamp, &compareKeyframeTimeWithTime) + : std::upper_bound(_keyframes.begin(), _keyframes.end(), timestamp, &compareTimeWithKeyframeTime); + if (it == _keyframes.end()) { + return nullptr; + } + return &(*it); +} + +template +const Keyframe* Timeline::lastKeyframeBefore(double timestamp, bool inclusive) const { + auto it = inclusive + ? std::upper_bound(_keyframes.begin(), _keyframes.end(), timestamp, &compareTimeWithKeyframeTime) + : std::lower_bound(_keyframes.begin(), _keyframes.end(), timestamp, &compareKeyframeTimeWithTime); + if (it == _keyframes.begin()) { + return nullptr; + } + it--; + return &(*it); +} + + +template +const std::deque>& Timeline::keyframes() const { + return _keyframes; +} + + +} + diff --git a/include/openspace/util/timemanager.h b/include/openspace/util/timemanager.h index 018765fbf6..a499c2d400 100644 --- a/include/openspace/util/timemanager.h +++ b/include/openspace/util/timemanager.h @@ -27,24 +27,26 @@ #include #include -#include +#include +#include +#include namespace openspace { class TimeManager { public: + Time& time(); + std::vector getSyncables(); void preSynchronization(double dt); - void addKeyframe(const datamessagestructures::TimeKeyframe& kf); + void addKeyframe(double timestamp, Time kf); void removeKeyframesBefore(double timestamp); void removeKeyframesAfter(double timestamp); void clearKeyframes(); - const std::deque& keyframes() const; + size_t nKeyframes() const; private: + Timeline