Feature/session recording (#737)

* In progress with new version of session recording

* Session recording coding pass for both record and playback, not building yet.

* Working on getting first build of prototype

* Code changes to get playback working with all 3 timing modes

* Fixing session recording interactions with the timemanager

* Bug fixes for newly discovered timing issues, mothballing recording of timing updates

* Fixed camera jitter issue

* Updated new reference to latest ghoul

* Got session recording/playback working with changes made in master

* Added threshold for differences in camera movement as criteria for saving to recording file

* Added support for binary file for session recording/playback

* Minor changes with handling timeManager keyframes in playback

* New timeline structure & keyframes specific to session recording

* Fixed bug with fixed-script size

* Switched to new timeline specific to session recording, bug fixes, currently debugging camera position & rotation

* Formatting changes only

* Fixed scripts not working after timeline change

* Add session recording test scene

* Fixed problem with re-running the same playback multiple times

* Fixed problems with camera interpolation

* Fixed detection of camera playback finishing, and improved camera interpolation

* Added comments for interface of externInteraction include

* Fixed view frustum culling issues in session playback due to not appropiate camera scaling. Also made function in datamessagestructures to read and write this data to streams.

* Added camera scaling fix to code that supports Ascii format

* Added startPlayback default command for playing back while forcing simulation time to match the recording

* Fixed camera jump in sessionRecording after playback finished. Cleanup in playback of camera to re-use same functionality in keyframenavigator.

* Superb fix to sessionRecording. Realized focusNode of globalNavigationHandler needed to be activly update when camera change for either position of camera to be accurate or for rendered objects to be calculated without precision issues. Can now achieve a correct playback, even close to chunks/renderable, which was not possible before.

* sessionRecording cleanup, fixed all warnings and renamed files to lowercase to match current standards.

* Added error handling for bad input playback filename, protection from corrupted playback file

* Implemented code review changes on pull request #737 for sessionRecording
This commit is contained in:
Gene Payne
2018-11-01 18:24:10 -06:00
committed by GitHub
parent 45359516f1
commit b671ad35e6
27 changed files with 2472 additions and 44 deletions
+34
View File
@@ -0,0 +1,34 @@
local sceneHelper = asset.require('util/scene_helper')
local propertyHelper = asset.require('util/property_helper')
-- Specifying which other assets should be loaded in this scene
asset.require('spice/base')
assetHelper.requestAll(asset, 'scene/solarsystem/sun')
asset.require('scene/solarsystem/planets/earth/earth')
asset.require('scene/digitaluniverse/constellationbounds')
asset.require('util/default_keybindings')
asset.require('util/default_dashboard')
asset.onInitialize(function ()
openspace.time.setTime("2010 AUG 01")
openspace.navigation.setCameraState({
Focus = "Earth",
Position = { -1500000000000, 0, 0 },
Rotation = { 0.0, 0.0, 1.0, 1.0 },
})
openspace.navigation.setCameraState({
Focus = "Sun",
Position = { 100000000000, 0, 0 },
Rotation = { 0.0, 0.0, 1.0, 1.0 },
})
openspace.setPropertyValue('Scene.ConstellationBounds.renderable.Enabled', true)
openspace.setPropertyValueSingle('Scene.Earth.RenderableGlobe.Enabled', false);
openspace.setPropertyValueSingle('Scene.EarthTrail.renderable.Enabled', false);
openspace.time.interpolateTogglePause()
end)
+3
View File
@@ -54,6 +54,7 @@ namespace interaction {
struct JoystickInputStates;
class KeybindingManager;
class NavigationHandler;
class SessionRecording;
class ShortcutManager;
} // namespace interaction
namespace performance { class PerformanceManager; }
@@ -88,6 +89,7 @@ configuration::Configuration& gConfiguration();
interaction::JoystickInputStates& gJoystickInputStates();
interaction::KeybindingManager& gKeybindingManager();
interaction::NavigationHandler& gNavigationHandler();
interaction::SessionRecording& gSessionRecording();
interaction::ShortcutManager& gShortcutManager();
performance::PerformanceManager& gPerformanceManager();
properties::PropertyOwner& gRootPropertyOwner();
@@ -120,6 +122,7 @@ static interaction::JoystickInputStates& joystickInputStates =
detail::gJoystickInputStates();
static interaction::KeybindingManager& keybindingManager = detail::gKeybindingManager();
static interaction::NavigationHandler& navigationHandler = detail::gNavigationHandler();
static interaction::SessionRecording& sessionRecording = detail::gSessionRecording();
static interaction::ShortcutManager& shortcutManager = detail::gShortcutManager();
static performance::PerformanceManager& performanceManager =
detail::gPerformanceManager();
@@ -0,0 +1,82 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2018 *
* *
* 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___EXTERNINTERACTION___H__
#define __OPENSPACE_CORE___EXTERNINTERACTION___H__
#include <openspace/network/messagestructures.h>
#include <openspace/properties/propertyowner.h>
#include <ghoul/io/socket/tcpsocket.h>
#include <vector>
namespace openspace {
class ExternInteraction : public properties::PropertyOwner {
public:
ExternInteraction();
/**
* Method that generates a keyframeNavigator CameraPose from a CameraKeyframe
* object, and then adds this to the navigationHandler's keyframe navigator.
* \param kf The camera keyframe to add.
*/
void cameraInteraction(datamessagestructures::CameraKeyframe kf);
/**
* Method that generates a TimeKeyframeData from a TimeKeyframe object, and
* then adds this to the timeManager.
* \param kf The time keyframe to add.
*/
void timeInteraction(datamessagestructures::TimeKeyframe kf);
/**
* Method that passes a ScriptMessage object to the script engine, calling its
* queueScript method to add it for execution.
* \param sm The ScriptMessage object to queue in the script engine.
*/
void scriptInteraction(datamessagestructures::ScriptMessage sm);
/**
* Method that accepts a reference to a CameraKeyframe object, and populates
* it with the current properties of the camera from the navigation handler.
* \returns CameraKeyframe with current state from NavigationHandler.
*/
datamessagestructures::CameraKeyframe generateCameraKeyframe();
/**
* Method that accepts a reference to a TimeKeyframe object, and populates
* it with the current time values from the application time manager.
* \returns TimeKeyframe The time keyframe.
*/
datamessagestructures::TimeKeyframe generateTimeKeyframe();
/**
* Method that accepts a reference to a ScriptMessage object and a script
* string, and populates the ScriptMessage with the script and timestamp
* of the current application time.
* \param script The script to execute in std::string form.
* \returns ScriptMessage The ScriptMessage data structure with script.
*/
datamessagestructures::ScriptMessage generateScriptMessage(std::string script);
private:
};
} // namespace openspace
#endif // __OPENSPACE_CORE___EXTERNINTERACTION___H__
@@ -31,10 +31,19 @@
#include <ghoul/misc/boolean.h>
#include <glm/gtx/quaternion.hpp>
namespace openspace { class Camera; }
namespace openspace {
class Camera;
class TimeManager;
} // namespace openspace
namespace openspace::interaction {
enum class KeyframeTimeRef {
Relative_applicationStart,
Relative_recordedStart,
Absolute_simTimeJ2000
};
class KeyframeNavigator {
public:
BooleanType(Inclusive);
@@ -47,16 +56,31 @@ public:
bool followFocusNodeRotation;
};
void updateCamera(Camera& camera);
/**
* Update camera position using the next camera pose keyframe from the timeline.
* Returns true if camera was set to a pose from the next keyframe.
* Returns false if no keyframes are available after the current time.
* \param camera A reference to the camera object to have its pose updated.
* \param ignoreFutureKeyframes true if only past keyframes are to be used.
* \returns true only if a new future keyframe is available to set camera pose.
*/
bool updateCamera(Camera& camera, bool ignoreFutureKeyframes);
static bool updateCamera(Camera* camera, const CameraPose prevPose,
const CameraPose nextPose, double t, bool ignoreFutureKeyframes);
Timeline<CameraPose>& timeline();
void addKeyframe(double timestamp, KeyframeNavigator::CameraPose pose);
void removeKeyframesAfter(double timestamp, Inclusive inclusive = Inclusive::No);
void clearKeyframes();
size_t nKeyframes() const;
const std::vector<datamessagestructures::CameraKeyframe>& keyframes() const;
double currentTime() const;
void setTimeReferenceMode(KeyframeTimeRef refType, double referenceTimestamp);
private:
Timeline<CameraPose> _cameraPoseTimeline;
KeyframeTimeRef _timeframeMode = KeyframeTimeRef::Relative_applicationStart;
double _referenceTimestamp = 0.0;
};
} // namespace openspace::interaction
@@ -61,8 +61,11 @@ public:
void setInterpolationTime(float durationInSeconds);
void setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict);
void updateCamera(double deltaTime);
void setEnableKeyFrameInteraction();
void setDisableKeyFrameInteraction();
void triggerPlaybackStart();
void stopPlayback();
// Accessors
ghoul::Dictionary cameraStateDictionary();
@@ -73,6 +76,7 @@ public:
const InputState& inputState() const;
const OrbitalNavigator& orbitalNavigator() const;
KeyframeNavigator& keyframeNavigator() const;
bool isKeyFrameInteractionEnabled() const;
float interpolationTime() const;
// Callback functions
@@ -113,9 +117,11 @@ public:
private:
bool _cameraUpdatedFromScript = false;
bool _playbackModeEnabled = false;
std::unique_ptr<InputState> _inputState;
Camera* _camera = nullptr;
std::function<void()> _playbackEndCallback;
std::unique_ptr<OrbitalNavigator> _orbitalNavigator;
std::unique_ptr<KeyframeNavigator> _keyframeNavigator;
@@ -0,0 +1,268 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2018 *
* *
* 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___SESSIONRECORDING___H__
#define __OPENSPACE_CORE___SESSIONRECORDING___H__
#include <openspace/interaction/externinteraction.h>
#include <openspace/interaction/keyframenavigator.h>
#include <openspace/network/messagestructures.h>
#include <openspace/scripting/lualibrary.h>
#include <ghoul/io/socket/tcpsocket.h>
#include <vector>
#include <fstream>
#include <iomanip>
namespace openspace::interaction {
#define RECORD_BINARY
class KeyframeNavigator;
class SessionRecording : public properties::PropertyOwner {
public:
enum class RecordedDataMode {
Ascii,
Binary
};
SessionRecording();
~SessionRecording();
/**
* Used to de-initialize the session recording feature. Any recording or playback
* in progress will be stopped, files closed, and keyframes in memory deleted.
*/
void deinitialize();
/**
* This is called with every rendered frame. If in recording state, the camera
* state will be saved to the recording file (if its state has changed since last).
* If in playback state, the next keyframe will be used (if it is time to do so).
*/
void preSynchronization();
/**
* Starts a recording session, which will save data to the provided filename
* according to the data format specified, and will continue until recording is
* stopped using stopRecording() method.
* \param filename file saved with recorded keyframes.
* \returns true if recording to file starts without errors.
*/
bool startRecording(std::string filename);
/**
* Starts a recording session, which will save data to the provided filename
* in ASCII data format until recording is stopped using stopRecording() method.
* \param filename file saved with recorded keyframes.
* \returns true if recording to file starts without errors.
*/
void setRecordDataFormat(RecordedDataMode dataMode);
/**
* Used to stop a recording in progress. If open, the recording file will be closed,
* and all keyframes deleted from memory.
*/
void stopRecording();
/**
* Used to check if a session recording is in progress.
* \returns true if recording is in progress.
*/
bool isRecording() const;
/**
* Starts a playback session, which can run in one of three different time modes.
* \param filename file containing recorded keyframes to play back
* \param timeMode which of the 3 time modes to use for time reference during
* \param forceSimTimeAtStart if true simulation time is forced to that of playback
* playback: recorded time, application time, or simulation time. See the LuaLibrary
* entry for SessionRecording for details on these time modes.
* \returns true if recording to file starts without errors.
*/
bool startPlayback(const std::string& filename, KeyframeTimeRef timeMode,
bool forceSimTimeAtStart);
/**
* Used to stop a playback in progress. If open, the playback file will be closed,
* and all keyframes deleted from memory.
*/
void stopPlayback();
/**
* Used to check if a session playback is in progress.
* \returns true if playback is in progress.
*/
bool isPlayingBack() const;
/**
* Used to trigger a save of the camera states (position, rotation, focus node,
* whether it is following the rotation of a node, and timestamp). The data will
* be saved to the recording file only if a recording is currently in progress.
*/
void saveCameraKeyframe();
/**
* Used to trigger a save of the current timing states. The data will be saved
* to the recording file only if a recording is currently in progress.
*/
void saveTimeKeyframe();
/**
* Used to trigger a save of a script to the recording file, but only if a recording
* is currently in progress.
* \param scriptToSave String of the Lua command to be saved.
*/
void saveScriptKeyframe(std::string scriptToSave);
/**
* \return The Lua library that contains all Lua functions available to affect the
* interaction
*/
static openspace::scripting::LuaLibrary luaLibrary();
private:
enum class SessionState {
Idle = 0,
Recording,
Playback
};
enum class RecordedType {
Camera = 0,
Time,
Script,
Invalid
};
struct timelineEntry {
RecordedType keyframeType;
unsigned int idxIntoKeyframeTypeArray;
double timestamp;
};
ExternInteraction _externInteract;
bool _isRecording = false;
double _timestampRecordStarted;
double _timestampPlaybackStarted_application;
double _timestampPlaybackStarted_simulation;
double _timestampApplicationStarted_simulation;
bool hasCameraChangedFromPrev(datamessagestructures::CameraKeyframe kfNew);
double appropriateTimestamp(double timeOs, double timeRec, double timeSim);
double equivalentSimulationTime(double timeOs, double timeRec, double timeSim);
double equivalentApplicationTime(double timeOs, double timeRec, double timeSim);
double currentTime() const;
void playbackCamera();
void playbackTimeChange();
void playbackScript();
bool playbackAddEntriesToTimeline();
void signalPlaybackFinishedForComponent(RecordedType type);
void writeToFileBuffer(const double src);
void writeToFileBuffer(std::vector<char>& cvec);
void writeToFileBuffer(const unsigned char c);
void writeToFileBuffer(bool b);
void saveStringToFile(const std::string s);
void saveKeyframeToFileBinary(unsigned char* bufferSource, size_t size);
void findFirstCameraKeyframeInTimeline();
std::string readHeaderElement(size_t readLen_chars);
void readFromPlayback(unsigned char& result);
void readFromPlayback(double& result);
void readFromPlayback(float& result);
void readFromPlayback(size_t& result);
void readFromPlayback(bool& result);
void readFromPlayback(std::string& result);
void saveKeyframeToFile(std::string entry);
void addKeyframe(double timestamp, interaction::KeyframeNavigator::CameraPose keyframe);
void addKeyframe(double timestamp, datamessagestructures::TimeKeyframe keyframe);
void addKeyframe(double timestamp, std::string scriptToQueue);
void moveAheadInTime();
void lookForNonCameraKeyframesThatHaveComeDue(double currTime);
void updateCameraWithOrWithoutNewKeyframes(double currTime);
bool isTimeToHandleNextNonCameraKeyframe(double currTime);
bool processNextNonCameraKeyframeAheadInTime();
bool findNextFutureCameraIndex(double currTime);
bool processCameraKeyframe(double now);
bool processScriptKeyframe();
bool isDataModeBinary();
unsigned int findIndexOfLastCameraKeyframeInTimeline();
bool doesTimelineEntryContainCamera(unsigned int index) const;
RecordedType getNextKeyframeType();
RecordedType getPrevKeyframeType();
double getNextTimestamp();
double getPrevTimestamp();
void cleanUpPlayback();
const bool _usingTimeKeyframes = false;
const std::string _fileHeaderTitle = "OpenSpace_record/playback";
static const size_t _fileHeaderVersionLength = 5;
const char _fileHeaderVersion[_fileHeaderVersionLength] = { '0', '0', '.', '8', '5' };
const char dataFormatAsciiTag = 'A';
const char dataFormatBinaryTag = 'B';
RecordedDataMode _recordingDataMode = RecordedDataMode::Binary;
SessionState _state = SessionState::Idle;
std::string _playbackFilename;
std::ifstream _playbackFile;
std::string _playbackLineParsing;
std::ofstream _recordFile;
int _playbackLineNum = 1;
KeyframeTimeRef _playbackTimeReferenceMode;
datamessagestructures::CameraKeyframe _prevRecordedCameraKeyframe;
bool _playbackActive_camera = false;
bool _playbackActive_time = false;
bool _playbackActive_script = false;
bool _hasHitEndOfCameraKeyframes = false;
bool _setSimulationTimeWithNextCameraKeyframe = false;
static const size_t keyframeHeaderSize_bytes = 33;
static const size_t saveBufferCameraSize_min = 82;
static const size_t saveBufferStringSize_max = 500;
static const size_t _saveBufferMaxSize_bytes = keyframeHeaderSize_bytes +
+ saveBufferCameraSize_min
+ saveBufferStringSize_max;
unsigned char _keyframeBuffer[_saveBufferMaxSize_bytes];
size_t _bufferIndex = 0;
bool _cleanupNeeded = false;
std::vector < interaction::KeyframeNavigator::CameraPose> _keyframesCamera;
std::vector<datamessagestructures::TimeKeyframe> _keyframesTime;
std::vector<std::string> _keyframesScript;
std::vector<timelineEntry> _timeline;
unsigned int _idxTimeline_nonCamera = 0;
unsigned int _idxTime = 0;
unsigned int _idxScript = 0;
unsigned int _idxTimeline_cameraPtrNext = 0;
unsigned int _idxTimeline_cameraPtrPrev = 0;
unsigned int _idxTimeline_cameraFirstInTimeline = 0;
double _cameraFirstInTimeline_timestamp = 0;
};
} // namespace openspace
#include "sessionrecording.inl"
#endif // __OPENSPACE_CORE___SESSIONRECORDING___H__
@@ -0,0 +1,57 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2018 *
* *
* 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::interaction {
template <class T>
T nextKeyframeObj(unsigned int index,
const std::vector<T>& keyframeContainer,
std::function<void()> finishedCallback)
{
if (index >= (keyframeContainer.size() - 1)) {
if( index == (keyframeContainer.size() - 1) )
finishedCallback();
return keyframeContainer.back();
} else if (index < keyframeContainer.size()) {
return keyframeContainer[index];
} else {
return keyframeContainer.back();
}
}
template <class T>
T prevKeyframeObj(unsigned int index,
const std::vector<T>& keyframeContainer)
{
if (index >= keyframeContainer.size()) {
return keyframeContainer.back();
} else if (index > 0) {
return keyframeContainer[index - 1];
} else {
return keyframeContainer.front();
}
}
} // namespace openspace::interaction
@@ -29,6 +29,7 @@
#include <cstring>
#include <string>
#include <vector>
#include <fstream>
namespace openspace::datamessagestructures {
@@ -142,6 +143,96 @@ struct CameraKeyframe {
return offset;
};
void write(std::ostream& out) const {
// Write position
out.write(
reinterpret_cast<const char*>(&_position),
sizeof(_position)
);
// Write orientation
out.write(
reinterpret_cast<const char*>(&_rotation),
sizeof(_rotation)
);
// Write follow focus node rotation?
out.write(
reinterpret_cast<const char*>(&_followNodeRotation),
sizeof(_followNodeRotation)
);
int nodeNameLength = static_cast<int>(_focusNode.size());
// Write focus node
out.write(
reinterpret_cast<const char*>(&nodeNameLength),
sizeof(nodeNameLength)
);
out.write(
_focusNode.c_str(),
_focusNode.size()
);
//Write scale
out.write(
reinterpret_cast<const char*>(&_scale),
sizeof(_scale)
);
// Write timestamp
out.write(
reinterpret_cast<const char*>(&_timestamp),
sizeof(_timestamp)
);
};
void read(std::istream* in) {
// Read position
in->read(
reinterpret_cast<char*>(&_position),
sizeof(_position)
);
// Read orientation
in->read(
reinterpret_cast<char*>(&_rotation),
sizeof(_rotation)
);
// Read follow focus node rotation
unsigned char b;
in->read(
reinterpret_cast<char*>(&b),
sizeof(unsigned char)
);
_followNodeRotation = (b == 1);
// Read focus node
int nodeNameLength = static_cast<int>(_focusNode.size());
in->read(
reinterpret_cast<char*>(&nodeNameLength),
sizeof(nodeNameLength)
);
std::vector<char> temp(nodeNameLength + 1);
in->read(temp.data(), nodeNameLength);
temp[nodeNameLength] = '\0';
_focusNode = temp.data();
// Read scale
in->read(
reinterpret_cast<char*>(&_scale),
sizeof(_scale)
);
// Read timestamp
in->read(
reinterpret_cast<char*>(&_timestamp),
sizeof(_timestamp)
);
};
};
struct TimeKeyframe {
@@ -169,6 +260,20 @@ struct TimeKeyframe {
offset += sizeof(TimeKeyframe);
return offset;
};
void write(std::ostream* out) const {
out->write(
reinterpret_cast<const char*>(this),
sizeof(TimeKeyframe)
);
};
void read(std::istream* in) {
in->read(
reinterpret_cast<char*>(this),
sizeof(TimeKeyframe)
);
};
};
struct TimeTimeline {
@@ -216,6 +321,38 @@ struct TimeTimeline {
}
return offset;
};
void write(std::ostream* out) const {
out->write(
reinterpret_cast<const char*>(&_clear),
sizeof(bool)
);
int64_t nKeyframes = _keyframes.size();
out->write(
reinterpret_cast<const char*>(&nKeyframes),
sizeof(int64_t)
);
for (const auto& k : _keyframes) {
k.write(out);
}
};
void read(std::istream* in) {
in->read(
reinterpret_cast<char*>(&_clear),
sizeof(bool)
);
int64_t nKeyframes = _keyframes.size();
in->read(
reinterpret_cast<char*>(&nKeyframes),
sizeof(int64_t)
);
for (auto& k : _keyframes) {
k.read(in);
}
};
};
struct ScriptMessage {
@@ -225,6 +362,7 @@ struct ScriptMessage {
}
std::string _script;
double _timestamp;
void serialize(std::vector<char> &buffer) const {
buffer.insert(buffer.end(), _script.begin(), _script.end());
@@ -233,6 +371,23 @@ struct ScriptMessage {
void deserialize(const std::vector<char> &buffer) {
_script.assign(buffer.begin(), buffer.end());
};
void write(std::ostream* out) const {
out->write(_script.c_str(), _script.size());
};
void read(std::istream* in) {
size_t strLen;
//Read string length from file
in->read(reinterpret_cast<char*>(&strLen), sizeof(strLen));
//Read back full string
std::vector<char> temp(strLen + 1);
in->read(temp.data(), strLen);
temp[strLen] = '\0';
_script.erase();
_script = temp.data();
};
};
} // namespace openspace::messagestructures
+3
View File
@@ -26,6 +26,7 @@
#define __OPENSPACE_CORE___PARALLELPEER___H__
#include <openspace/network/parallelconnection.h>
#include <openspace/interaction/externinteraction.h>
#include <openspace/network/messagestructures.h>
#include <openspace/util/timemanager.h>
@@ -132,6 +133,8 @@ private:
std::unique_ptr<std::thread> _receiveThread = nullptr;
std::shared_ptr<ghoul::Event<>> _connectionEvent;
ExternInteraction _externInteract;
ParallelConnection _connection;
TimeManager::CallbackHandle _timeJumpCallback = -1;
+48 -9
View File
@@ -25,8 +25,21 @@
#ifndef __OPENSPACE_CORE___SCRIPTSCHEDULER___H__
#define __OPENSPACE_CORE___SCRIPTSCHEDULER___H__
#include <openspace/scripting/lualibrary.h>
#include <openspace/interaction/keyframenavigator.h>
#include <queue>
#include <string>
#include <vector>
#include <functional>
namespace {
constexpr const char* KeyTime = "Time";
constexpr const char* KeyForwardScript = "ForwardScript";
constexpr const char* KeyBackwardScript = "BackwardScript";
constexpr const char* KeyUniversalScript = "Script";
} // namespace
namespace ghoul { class Dictionary; }
namespace openspace::documentation { struct Documentation; }
@@ -71,15 +84,16 @@ public:
void clearSchedule();
/**
* Progresses the script schedulers time and returns all scripts that has been
* scheduled to run between \param newTime and the time provided in the last
* invocation of this method.
*
* \param newTime A j2000 time value specifying the new time stamp that
* the script scheduler should progress to.
*
* \returns the ordered queue of scripts .
*/
* Progresses the script schedulers time and returns all scripts that has been
* scheduled to run between \param newTime and the time provided in the last invocation
* of this method.
*
* \param newTime_simulation A j2000 time value specifying the new time stamp that
* the script scheduler should progress to.
* \param newTime_application The seconds elapsed since the application started
*
* \returns the ordered queue of scripts .
*/
// std::queue<std::string> progressTo(double newTime);
/**
@@ -103,8 +117,29 @@ public:
*/
std::vector<ScheduledScript> allScripts() const;
/**
* Sets the mode for how each scheduled script's timestamp will be interpreted.
* \param refType reference mode (for exact syntax, see definition of
* openspace::interaction::KeyframeTimeRef) which is either relative to the
* application start time, relative to the recorded session playback start time,
* or according to the absolute simulation time in seconds from J2000 epoch.
*/
void setTimeReferenceMode(openspace::interaction::KeyframeTimeRef refType);
/**
* Sets the mode for scripts being run from playback
*/
void triggerPlaybackStart();
/**
* Sets the flag for scripts no longer being run from playback
*/
void stopPlayback();
static LuaLibrary luaLibrary();
void setModeApplicationTime();
void setModeRecordedTime();
void setModeSimulationTime();
static documentation::Documentation Documentation();
@@ -115,6 +150,10 @@ private:
int _currentIndex = 0;
double _currentTime = 0;
bool _playbackModeEnabled = false;
openspace::interaction::KeyframeTimeRef _timeframeMode
= openspace::interaction::KeyframeTimeRef::Absolute_simTimeJ2000;
};
} // namespace openspace::scripting
+3
View File
@@ -103,6 +103,7 @@ public:
void removeTimeChangeCallback(CallbackHandle handle);
void removeDeltaTimeChangeCallback(CallbackHandle handle);
void triggerPlaybackStart();
void removeTimeJumpCallback(CallbackHandle handle);
void removeTimelineChangeCallback(CallbackHandle handle);
@@ -134,9 +135,11 @@ private:
double _latestConsumedTimestamp = -std::numeric_limits<double>::max();
int _nextCallbackHandle = 0;
bool _playbackModeEnabled = false;
std::vector<std::pair<CallbackHandle, TimeChangeCallback>> _timeChangeCallbacks;
std::vector<std::pair<CallbackHandle, TimeChangeCallback>> _deltaTimeChangeCallbacks;
std::vector<std::pair<CallbackHandle, TimeChangeCallback>> _timeJumpCallbacks;
std::vector<std::pair<CallbackHandle, TimeChangeCallback>> _timelineChangeCallbacks;
};
+2
View File
@@ -30,6 +30,7 @@
#include <openspace/engine/windowdelegate.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/network/parallelpeer.h>
#include <openspace/rendering/dashboard.h>
#include <openspace/rendering/luaconsole.h>
@@ -50,6 +51,7 @@ ImGUIModule::ImGUIModule() : OpenSpaceModule(Name) {
[]() {
std::vector<properties::PropertyOwner*> res = {
&global::navigationHandler,
&global::sessionRecording,
&global::timeManager,
&global::renderEngine,
&global::parallelPeer,
+5
View File
@@ -53,6 +53,9 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/interaction/navigationhandler_lua.inl
${OPENSPACE_BASE_DIR}/src/interaction/mousecamerastates.cpp
${OPENSPACE_BASE_DIR}/src/interaction/orbitalnavigator.cpp
${OPENSPACE_BASE_DIR}/src/interaction/externinteraction.cpp
${OPENSPACE_BASE_DIR}/src/interaction/sessionrecording.cpp
${OPENSPACE_BASE_DIR}/src/interaction/sessionrecording_lua.inl
${OPENSPACE_BASE_DIR}/src/interaction/shortcutmanager.cpp
${OPENSPACE_BASE_DIR}/src/interaction/shortcutmanager_lua.inl
${OPENSPACE_BASE_DIR}/src/mission/mission.cpp
@@ -232,6 +235,8 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/interaction/mousecamerastates.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/navigationhandler.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/orbitalnavigator.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/externinteraction.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/sessionrecording.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/shortcutmanager.h
${OPENSPACE_BASE_DIR}/include/openspace/mission/mission.h
${OPENSPACE_BASE_DIR}/include/openspace/mission/missionmanager.h
+2
View File
@@ -30,6 +30,7 @@
#include <openspace/engine/openspaceengine.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/keybindingmanager.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/interaction/shortcutmanager.h>
#include <openspace/mission/mission.h>
#include <openspace/mission/missionmanager.h>
@@ -80,6 +81,7 @@ void registerCoreClasses(scripting::ScriptEngine& engine) {
engine.addLibrary(Time::luaLibrary());
engine.addLibrary(interaction::KeybindingManager::luaLibrary());
engine.addLibrary(interaction::NavigationHandler::luaLibrary());
engine.addLibrary(interaction::SessionRecording::luaLibrary());
engine.addLibrary(interaction::ShortcutManager::luaLibrary());
engine.addLibrary(scripting::ScriptScheduler::luaLibrary());
engine.addLibrary(scripting::generalSystemCapabilities());
+8
View File
@@ -34,6 +34,7 @@
#include <openspace/interaction/keybindingmanager.h>
#include <openspace/interaction/joystickinputstate.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/interaction/shortcutmanager.h>
#include <openspace/mission/missionmanager.h>
#include <openspace/network/networkengine.h>
@@ -163,6 +164,12 @@ interaction::NavigationHandler& gNavigationHandler() {
return g;
}
interaction::SessionRecording& gSessionRecording() {
static interaction::SessionRecording g;
return g;
}
interaction::ShortcutManager& gShortcutManager() {
static interaction::ShortcutManager g;
return g;
@@ -201,6 +208,7 @@ void initialize() {
global::navigationHandler.setPropertyOwner(&global::rootPropertyOwner);
// New property subowners also have to be added to the ImGuiModule callback!
global::rootPropertyOwner.addPropertySubOwner(global::navigationHandler);
global::rootPropertyOwner.addPropertySubOwner(global::sessionRecording);
global::rootPropertyOwner.addPropertySubOwner(global::timeManager);
global::rootPropertyOwner.addPropertySubOwner(global::renderEngine);
+6
View File
@@ -37,6 +37,7 @@
#include <openspace/engine/virtualpropertymanager.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/keybindingmanager.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/network/networkengine.h>
#include <openspace/network/parallelpeer.h>
@@ -785,6 +786,7 @@ void OpenSpaceEngine::deinitialize() {
global::renderEngine.scene()->camera()->getSyncables()
);
}
global::sessionRecording.deinitialize();
global::deinitialize();
@@ -931,6 +933,8 @@ void OpenSpaceEngine::writeSceneDocumentation() {
void OpenSpaceEngine::preSynchronization() {
LTRACE("OpenSpaceEngine::preSynchronization(begin)");
//std::this_thread::sleep_for(std::chrono::milliseconds(10));
std::unique_ptr<performance::PerformanceMeasurement> perf;
if (global::performanceManager.isEnabled()) {
perf = std::make_unique<performance::PerformanceMeasurement>(
@@ -972,6 +976,7 @@ void OpenSpaceEngine::preSynchronization() {
global::renderEngine.updateScene();
//_navigationHandler->updateCamera(dt);
if (_scene) {
Camera* camera = _scene->camera();
if (camera) {
@@ -979,6 +984,7 @@ void OpenSpaceEngine::preSynchronization() {
camera->invalidateCache();
}
}
global::sessionRecording.preSynchronization();
global::parallelPeer.preSynchronization();
}
+158
View File
@@ -0,0 +1,158 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2018 *
* *
* 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/externinteraction.h>
#include <openspace/openspace.h>
#include <openspace/engine/globals.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/windowdelegate.h>
#include <openspace/interaction/keyframenavigator.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/scene/scenegraphnode.h>
#include <openspace/scripting/scriptengine.h>
#include <openspace/util/camera.h>
#include <openspace/util/time.h>
#include <openspace/util/timemanager.h>
#include <ghoul/logging/logmanager.h>
namespace {
const uint32_t ProtocolVersion = 3;
const size_t MaxLatencyDiffs = 64;
const char* _loggerCat = "ExternInteraction";
static const openspace::properties::Property::PropertyInfo BufferTimeInfo = {
"BufferTime",
"Buffer Time",
"" // @TODO Missing documentation
};
static const openspace::properties::Property::PropertyInfo TimeKeyFrameInfo = {
"TimeKeyframeInterval",
"Time keyframe interval",
"" // @TODO Missing documentation
};
static const openspace::properties::Property::PropertyInfo CameraKeyFrameInfo = {
"CameraKeyframeInterval",
"Camera Keyframe interval",
"" // @TODO Missing documentation
};
static const openspace::properties::Property::PropertyInfo TimeToleranceInfo = {
"TimeTolerance",
"Time tolerance",
"" // @TODO Missing documentation
};
} // namespace
namespace openspace {
ExternInteraction::ExternInteraction()
: properties::PropertyOwner({ "ExternInteration", "External Interaction" })
{
}
void ExternInteraction::cameraInteraction(datamessagestructures::CameraKeyframe kf) {
interaction::KeyframeNavigator::CameraPose pose;
pose.focusNode = std::move(kf._focusNode);
pose.position = std::move(kf._position);
pose.rotation = std::move(kf._rotation);
pose.scale = std::move(kf._scale);
pose.followFocusNodeRotation = std::move(kf._followNodeRotation);
global::navigationHandler.keyframeNavigator().addKeyframe(kf._timestamp, pose);
}
void ExternInteraction::timeInteraction(datamessagestructures::TimeKeyframe kf) {
TimeKeyframeData timeKfData;
timeKfData.delta = std::move(kf._dt);
timeKfData.pause = std::move(kf._paused);
timeKfData.jump = std::move(kf._requiresTimeJump);
global::timeManager.addKeyframe(kf._timestamp, timeKfData);
}
void ExternInteraction::scriptInteraction(datamessagestructures::ScriptMessage sm) {
global::scriptEngine.queueScript(
std::move(sm._script),
scripting::ScriptEngine::RemoteScripting::No
);
}
datamessagestructures::CameraKeyframe ExternInteraction::generateCameraKeyframe() {
datamessagestructures::CameraKeyframe kf;
SceneGraphNode* focusNode = global::navigationHandler.focusNode();
if (!focusNode) {
return kf;
}
//kf._position = global::navigationHandler.camera()->positionVec3();
kf._position = global::navigationHandler.focusNodeToCameraVector();
kf._followNodeRotation =
global::navigationHandler.orbitalNavigator().followingNodeRotation();
if (kf._followNodeRotation) {
kf._position = glm::inverse(focusNode->worldRotationMatrix()) * kf._position;
kf._rotation = global::navigationHandler.focusNodeToCameraRotation();
}
else {
kf._rotation = global::navigationHandler.camera()->rotationQuaternion();
}
kf._focusNode = focusNode->identifier();
kf._scale = global::navigationHandler.camera()->scaling();
// Timestamp as current runtime of OpenSpace instance
kf._timestamp = global::windowDelegate.applicationTime();
return kf;
}
datamessagestructures::TimeKeyframe ExternInteraction::generateTimeKeyframe() {
datamessagestructures::TimeKeyframe kf;
const Time& time = global::timeManager.time();
kf._dt = global::timeManager.deltaTime();
kf._paused = global::timeManager.isPaused();
kf._time = time.j2000Seconds();
// Timestamp as current runtime of OpenSpace instance
kf._timestamp = global::windowDelegate.applicationTime();
return kf;
}
datamessagestructures::ScriptMessage ExternInteraction::generateScriptMessage(std::string script) {
datamessagestructures::ScriptMessage sm;
sm._script = std::move(script);
// Timestamp as current runtime of OpenSpace instance
sm._timestamp = global::windowDelegate.applicationTime();
return sm;
}
} // namespace openspace
+81 -21
View File
@@ -30,27 +30,35 @@
#include <openspace/scene/scene.h>
#include <openspace/util/camera.h>
#include <openspace/util/time.h>
#include <openspace/util/timemanager.h>
#include <ghoul/logging/logmanager.h>
#include <glm/gtx/quaternion.hpp>
namespace openspace::interaction {
void KeyframeNavigator::updateCamera(Camera& camera) {
double now = global::windowDelegate.applicationTime();
bool KeyframeNavigator::updateCamera(Camera& camera, bool ignoreFutureKeyframes) {
double now = currentTime();
bool foundPrevKeyframe = false;
if (_cameraPoseTimeline.nKeyframes() == 0) {
return;
return false;
}
const Keyframe<CameraPose>* nextKeyframe =
_cameraPoseTimeline.firstKeyframeAfter(now);
_cameraPoseTimeline.firstKeyframeAfter(now);
const Keyframe<CameraPose>* prevKeyframe =
_cameraPoseTimeline.lastKeyframeBefore(now);
_cameraPoseTimeline.lastKeyframeBefore(now);
double nextTime = 0.0;
if (nextKeyframe) {
nextTime = nextKeyframe->timestamp;
} else {
return;
}
else {
if (ignoreFutureKeyframes) {
_cameraPoseTimeline.removeKeyframesBefore(now);
}
return false;
}
double prevTime = 0.0;
@@ -58,24 +66,33 @@ void KeyframeNavigator::updateCamera(Camera& camera) {
if (prevKeyframe) {
prevTime = prevKeyframe->timestamp;
t = (now - prevTime) / (nextTime - prevTime);
} else {
foundPrevKeyframe = true;
}
else {
// If there is no keyframe before: Only use the next keyframe.
prevTime = nextTime;
prevKeyframe = nextKeyframe;
t = 1;
}
const CameraPose prevPose = prevKeyframe->data;
const CameraPose nextPose = nextKeyframe->data;
_cameraPoseTimeline.removeKeyframesBefore(prevTime);
const CameraPose& prevPose = prevKeyframe->data;
const CameraPose& nextPose = nextKeyframe->data;
if (!foundPrevKeyframe && ignoreFutureKeyframes) {
return false;
}
Scene* scene = camera.parent()->scene();
return updateCamera(&camera, prevKeyframe->data, nextKeyframe->data, t, ignoreFutureKeyframes);
}
bool KeyframeNavigator::updateCamera(Camera* camera, const CameraPose prevPose, const CameraPose nextPose, double t, bool ignoreFutureKeyframes) {
Scene* scene = camera->parent()->scene();
SceneGraphNode* prevFocusNode = scene->sceneGraphNode(prevPose.focusNode);
SceneGraphNode* nextFocusNode = scene->sceneGraphNode(nextPose.focusNode);
if (!prevFocusNode || !nextFocusNode) {
return;
return false;
}
glm::dvec3 prevKeyframeCameraPosition = prevPose.position;
@@ -107,22 +124,65 @@ void KeyframeNavigator::updateCamera(Camera& camera) {
nextKeyframeCameraPosition += nextFocusNode->worldPosition();
// Linear interpolation
camera.setPositionVec3(
t = std::max(0.0, std::min(1.0, t));
camera->setPositionVec3(
prevKeyframeCameraPosition * (1 - t) + nextKeyframeCameraPosition * t
);
camera.setRotation(
camera->setRotation(
glm::slerp(prevKeyframeCameraRotation, nextKeyframeCameraRotation, t)
);
// We want to affect view scaling, such that we achieve
// logarithmic interpolation of distance to an imagined focus node.
// To do this, we interpolate the scale reciprocal logarithmically.
const float prevInvScaleExp = glm::log(1.f / prevPose.scale);
const float nextInvScaleExp = glm::log(1.f / nextPose.scale);
const float interpolatedInvScaleExp = static_cast<float>(
prevInvScaleExp * (1 - t) + nextInvScaleExp * t
);
camera.setScaling(1.f / glm::exp(interpolatedInvScaleExp));
if (!ignoreFutureKeyframes) {
const float prevInvScaleExp = glm::log(1.f / prevPose.scale);
const float nextInvScaleExp = glm::log(1.f / nextPose.scale);
const float interpolatedInvScaleExp = static_cast<float>(
prevInvScaleExp * (1 - t) + nextInvScaleExp * t
);
camera->setScaling(1.f / glm::exp(interpolatedInvScaleExp));
}
#ifdef INTERPOLATION_DEBUG_PRINT
LINFO(fmt::format("Cam pos prev={}, next={}", std::to_string(prevKeyframeCameraPosition),
std::to_string(nextKeyframeCameraPosition)));
LINFO(fmt::format("Cam rot prev={} {} {} {} next={} {} {} {}", prevKeyframeCameraRotation.x,
prevKeyframeCameraRotation.y, prevKeyframeCameraRotation.z, prevKeyframeCameraRotation.w,
nextKeyframeCameraRotation.x, nextKeyframeCameraRotation.y, nextKeyframeCameraRotation.z,
nextKeyframeCameraRotation.w));
LINFO(fmt::format("Cam interp = {}", t));
LINFO(fmt::format("camera {} {} {} {} {} {}", global::windowDelegate.applicationTime(),
global::windowDelegate.applicationTime() - _timestampPlaybackStarted_application,
global::timeManager.time().j2000Seconds(), interpolatedCamera.x,
interpolatedCamera.y, interpolatedCamera.z));
//Following is for direct print to save & compare camera positions against recorded file
printf("camera %8.4f %8.4f %13.3f %16.7f %16.7f %16.7f\n", global::windowDelegate.applicationTime(),
global::windowDelegate.applicationTime() - _timestampPlaybackStarted_application,
global::timeManager.time().j2000Seconds(), interpolatedCamera.x,
interpolatedCamera.y, interpolatedCamera.z);
#endif
return true;
}
double KeyframeNavigator::currentTime() const {
if (_timeframeMode == KeyframeTimeRef::Relative_recordedStart) {
return (global::windowDelegate.applicationTime() - _referenceTimestamp);
}
else if (_timeframeMode == KeyframeTimeRef::Absolute_simTimeJ2000) {
return global::timeManager.time().j2000Seconds();
}
else {
return global::windowDelegate.applicationTime();
}
}
void KeyframeNavigator::setTimeReferenceMode(KeyframeTimeRef refType, double referenceTimestamp) {
_timeframeMode = refType;
_referenceTimestamp = referenceTimestamp;
}
Timeline<KeyframeNavigator::CameraPose>& KeyframeNavigator::timeline() {
+23 -3
View File
@@ -135,6 +135,10 @@ KeyframeNavigator& NavigationHandler::keyframeNavigator() const {
return *_keyframeNavigator;
}
bool NavigationHandler::isKeyFrameInteractionEnabled() const {
return _useKeyFrameInteraction;
}
float NavigationHandler::interpolationTime() const {
return _orbitalNavigator->rotateToFocusInterpolationTime();
}
@@ -150,20 +154,36 @@ void NavigationHandler::updateCamera(double deltaTime) {
if (_cameraUpdatedFromScript) {
_cameraUpdatedFromScript = false;
}
else {
else if ( ! _playbackModeEnabled ) {
if (_camera && focusNode()) {
if (_useKeyFrameInteraction) {
_keyframeNavigator->updateCamera(*_camera);
_keyframeNavigator->updateCamera(*_camera, _playbackModeEnabled);
}
else {
_orbitalNavigator->updateStatesFromInput(*_inputState, deltaTime);
_orbitalNavigator->updateCameraStateFromStates(*_camera, deltaTime);
_camera->setFocusPositionVec3(focusNode()->worldPosition());
}
_camera->setFocusPositionVec3(focusNode()->worldPosition());
}
}
}
void NavigationHandler::setEnableKeyFrameInteraction() {
_useKeyFrameInteraction = true;
}
void NavigationHandler::setDisableKeyFrameInteraction() {
_useKeyFrameInteraction = false;
}
void NavigationHandler::triggerPlaybackStart() {
_playbackModeEnabled = true;
}
void NavigationHandler::stopPlayback() {
_playbackModeEnabled = false;
}
SceneGraphNode* NavigationHandler::focusNode() const {
return _orbitalNavigator->focusNode();
}
File diff suppressed because it is too large Load Diff
+125
View File
@@ -0,0 +1,125 @@
/*****************************************************************************************
* *
* OpenSpace *
* *
* Copyright (c) 2014-2018 *
* *
* 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::luascriptfunctions {
int startRecording(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startRecording");
using ghoul::lua::luaTypeToString;
const std::string recordFilePath = ghoul::lua::value<std::string>(L, 1, ghoul::lua::PopValue::Yes);
if (recordFilePath.empty()) {
return luaL_error(L, "filepath string is empty");
}
global::sessionRecording.setRecordDataFormat(openspace::interaction::SessionRecording::RecordedDataMode::Binary);
global::sessionRecording.startRecording(recordFilePath);
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
int startRecordingAscii(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startRecordingAscii");
using ghoul::lua::luaTypeToString;
const std::string recordFilePath = ghoul::lua::value<std::string>(L, 1, ghoul::lua::PopValue::Yes);
if (recordFilePath.empty()) {
return luaL_error(L, "filepath string is empty");
}
global::sessionRecording.setRecordDataFormat(openspace::interaction::SessionRecording::RecordedDataMode::Ascii);
global::sessionRecording.startRecording(recordFilePath);
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
int stopRecording(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::stopRecording");
global::sessionRecording.stopRecording();
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
int startPlayback(lua_State* L, openspace::interaction::KeyframeTimeRef timeMode,
bool forceSimTimeAtStart)
{
using ghoul::lua::luaTypeToString;
const std::string playbackFilePath = ghoul::lua::value<std::string>(L, 1, ghoul::lua::PopValue::Yes);
if (playbackFilePath.empty()) {
return luaL_error(L, "filepath string is empty");
}
global::sessionRecording.startPlayback(playbackFilePath, timeMode, forceSimTimeAtStart);
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
int startPlaybackDefault(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startPlaybackDefault");
using openspace::interaction::KeyframeNavigator;
return startPlayback(L,
openspace::interaction::KeyframeTimeRef::Relative_recordedStart, true);
}
int startPlaybackApplicationTime(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startPlaybackApplicationTime");
return startPlayback(L,
openspace::interaction::KeyframeTimeRef::Relative_applicationStart, false);
}
int startPlaybackRecordedTime(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startPlaybackRecordedTime");
using openspace::interaction::KeyframeNavigator;
return startPlayback(L,
openspace::interaction::KeyframeTimeRef::Relative_recordedStart, false);
}
int startPlaybackSimulationTime(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startPlaybackSimulationTime");
using openspace::interaction::KeyframeNavigator;
return startPlayback(L,
openspace::interaction::KeyframeTimeRef::Absolute_simTimeJ2000, false);
}
int stopPlayback(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::stopPlayback");
global::sessionRecording.stopPlayback();
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
} // namespace openspace::luascriptfunctions
+1
View File
@@ -242,6 +242,7 @@ double ParallelPeer::convertTimestamp(double messageTimestamp) {
return messageTimestamp + _initialTimeDiff + _bufferTime;
}
double ParallelPeer::latencyStandardDeviation() const {
double accumulatedLatencyDiffSquared = 0;
double accumulatedLatencyDiff = 0;
+15
View File
@@ -662,6 +662,21 @@ void RenderEngine::renderDashboard() {
);
global::dashboard.render(penPosition);
#ifdef REALTIME_CAMERA_POS_DISPLAY
penPosition += glm::vec2(0.f, -50.f);
glm::dvec3 p = _camera->positionVec3();
glm::dquat rot = _camera->rotationQuaternion();
std::string fc = global::navigationHandler.focusNode()->identifier();
RenderFont(
*_fontInfo,
penPosition,
fmt::format("Pos: {} {} {}\nOrientation: {} {} {} {}\nFocus: {}",
p.x, p.y, p.z, rot[0], rot[1], rot[2], rot[3], fc
)
);
#endif
}
void RenderEngine::postDraw() {
+4
View File
@@ -26,6 +26,7 @@
#include <openspace/engine/configuration.h>
#include <openspace/engine/globals.h>
#include <openspace/interaction/sessionrecording.h>
#include <openspace/network/parallelpeer.h>
#include <openspace/util/syncbuffer.h>
#include <ghoul/filesystem/filesystem.h>
@@ -636,6 +637,9 @@ void ScriptEngine::preSync(bool isMaster) {
if (global::parallelPeer.isHost() && remoteScripting) {
global::parallelPeer.sendScript(_currentSyncedScript);
}
if (global::sessionRecording.isRecording()) {
global::sessionRecording.saveScriptKeyframe(_currentSyncedScript);
}
}
_mutex.unlock();
}
+50 -7
View File
@@ -30,13 +30,6 @@
#include <openspace/util/time.h>
#include <ghoul/logging/logmanager.h>
namespace {
constexpr const char* KeyTime = "Time";
constexpr const char* KeyForwardScript = "ForwardScript";
constexpr const char* KeyBackwardScript = "BackwardScript";
constexpr const char* KeyUniversalScript = "Script";
} // namespace
#include "scriptscheduler_lua.inl"
namespace openspace::scripting {
@@ -93,6 +86,8 @@ documentation::Documentation ScriptScheduler::Documentation() {
};
}
using namespace openspace::interaction;
ScriptScheduler::ScheduledScript::ScheduledScript(const ghoul::Dictionary& dictionary) {
const std::string& timeStr = dictionary.value<std::string>(KeyTime);
time = Time::convertTime(timeStr);
@@ -235,6 +230,18 @@ ScriptScheduler::progressTo(double newTime)
}
}
void ScriptScheduler::setTimeReferenceMode(KeyframeTimeRef refType) {
_timeframeMode = refType;
}
void ScriptScheduler::triggerPlaybackStart() {
_playbackModeEnabled = true;
}
void ScriptScheduler::stopPlayback() {
_playbackModeEnabled = false;
}
double ScriptScheduler::currentTime() const {
return _currentTime;
}
@@ -252,6 +259,18 @@ std::vector<ScriptScheduler::ScheduledScript> ScriptScheduler::allScripts() cons
return result;
}
void ScriptScheduler::setModeApplicationTime() {
_timeframeMode = KeyframeTimeRef::Relative_applicationStart;
}
void ScriptScheduler::setModeRecordedTime() {
_timeframeMode = KeyframeTimeRef::Relative_recordedStart;
}
void ScriptScheduler::setModeSimulationTime() {
_timeframeMode = KeyframeTimeRef::Absolute_simTimeJ2000;
}
LuaLibrary ScriptScheduler::luaLibrary() {
return {
"scriptScheduler",
@@ -276,6 +295,30 @@ LuaLibrary ScriptScheduler::luaLibrary() {
"last argument is the universal script, executed in either direction."
},
{
"setModeApplicationTime",
&luascriptfunctions::setModeApplicationTime,
{},
"",
"Sets the time reference for scheduled scripts to application time "
"(seconds since OpenSpace application started)."
},
{
"setModeRecordedTime",
&luascriptfunctions::setModeRecordedTime,
{},
"",
"Sets the time reference for scheduled scripts to the time since the "
"recording was started (the same relative time applies to playback)."
},
{
"setModeSimulationTime",
&luascriptfunctions::setModeSimulationTime,
{},
"",
"Sets the time reference for scheduled scripts to the simulated "
"date & time (J2000 epoch seconds)."
},
{
"clear",
&luascriptfunctions::clear,
+27
View File
@@ -103,6 +103,33 @@ int loadScheduledScript(lua_State* L) {
return 0;
}
int setModeApplicationTime(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::setModeApplicationTime");
global::scriptScheduler.setModeApplicationTime();
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
int setModeRecordedTime(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::setModeRecordedTime");
global::scriptScheduler.setModeRecordedTime();
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
int setModeSimulationTime(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::setModeSimulationTime");
global::scriptScheduler.setModeSimulationTime();
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
return 0;
}
int clear(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::clear");
+5
View File
@@ -258,6 +258,7 @@ void TimeManager::progressTime(double dt) {
// and time is not paused, just advance time.
_deltaTime = _targetDeltaTime;
_currentTime.data().advanceTime(dt * _deltaTime);
_playbackModeEnabled = false;
}
if (hasPastKeyframes) {
@@ -434,6 +435,10 @@ void TimeManager::removeDeltaTimeChangeCallback(CallbackHandle handle) {
_deltaTimeChangeCallbacks.erase(it);
}
void TimeManager::triggerPlaybackStart() {
_playbackModeEnabled = true;
}
void TimeManager::removeTimeJumpCallback(CallbackHandle handle) {
const auto it = std::find_if(
_timeJumpCallbacks.begin(),