From c03f98717a98104d0e141b4666187beac1afb652 Mon Sep 17 00:00:00 2001 From: GPayne Date: Fri, 30 Aug 2019 16:25:09 -0600 Subject: [PATCH 01/26] Initial non-working version of convert recording format task. --- .../interaction/tasks/convertrecformattask.h | 56 +++++++++ .../tasks/convertrecformattask.cpp | 116 ++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 include/openspace/interaction/tasks/convertrecformattask.h create mode 100644 src/interaction/tasks/convertrecformattask.cpp diff --git a/include/openspace/interaction/tasks/convertrecformattask.h b/include/openspace/interaction/tasks/convertrecformattask.h new file mode 100644 index 0000000000..ae89b4ab3a --- /dev/null +++ b/include/openspace/interaction/tasks/convertrecformattask.h @@ -0,0 +1,56 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2019 * + * * + * 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___CONVERTRECFORMATTASK___H__ +#define __OPENSPACE_CORE___CONVERTRECFORMATTASK___H__ + +#include + +#include + +#include + +namespace openspace { + +class ConvertRecFormatTask : public Task { +public: + enum class ConversionDirection { + ToAscii = 0, + ToBinary + }; + ConvertRecFormatTask(const ghoul::Dictionary& dictionary); + std::string description() override; + void perform(const Task::ProgressCallback& progressCallback) override; + static documentation::Documentation documentation(); + +private: + std::string _inFilePath; + std::string _outFilePath; + + std::string _valueFunctionLua; +}; + +} // namespace openspace + +#endif //__OPENSPACE_CORE___CONVERTRECFORMATTASK___H__ diff --git a/src/interaction/tasks/convertrecformattask.cpp b/src/interaction/tasks/convertrecformattask.cpp new file mode 100644 index 0000000000..ce8b004353 --- /dev/null +++ b/src/interaction/tasks/convertrecformattask.cpp @@ -0,0 +1,116 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2019 * + * * + * 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 +#include +#include + +#include +#include +#include +#include + +namespace { + constexpr const char* KeyConvertToAscii = "ConvertToAscii"; + constexpr const char* KeyConvertToBinary = "ConvertToBinary"; + constexpr const char* KeyInFilePath = "InputFilePath"; + constexpr const char* KeyOutFilePath = "OutputFilePath"; +} + +namespace openspace { + +ConvertRecFormatTask::ConvertRecFormatTask(const ghoul::Dictionary& dictionary) { + openspace::documentation::testSpecificationAndThrow( + documentation(), + dictionary, + "ConvertRecFormatTask" + ); + + _inFilePath = absPath(dictionary.value(KeyInFilePath)); + _outFilePath = absPath(dictionary.value(KeyOutFilePath)); +} + +void ConvertRecFormatTask::perform(const Task::ProgressCallback& progressCallback) { + +} + +void ConvertRecFormatTask::convert() { + RecordedDataMode type = formatType(); + + if (type == RecordedDataMode::Ascii) { + convertToBinary(); + } + else if (type == RecordedDataMode::Binary) { + convertToAscii(); + } + else { + //Add error output for file type not recognized + } +} + +RecordedDataMode ConvertRecFormatTask::formatType() { + //Read file at _inFilePath + + //Read first line + + //First verify that the line starts with the valid string + + //Get last character which should be either 'A' or 'B', and return Ascii or Binary based on this. +} + +void ConvertRecFormatTask::convertToAscii() { + +} + +void ConvertRecFormatTask::convertToBinary() { + +} + +documentation::Documentation ConvertRecFormatTask::documentation() { + using namespace documentation; + return { + "ConvertRecFormatTask", + "convert_format_task", + { + { + "Type", + new StringEqualVerifier("ConvertRecFormatTask"), + Optional::No, + "The type of this task", + }, + { + KeyInFilePath, + new StringAnnotationVerifier("A valid filename to convert"), + Optional::No, + "The filename to convert to the opposite format.", + }, + { + KeyOutFilePath, + new StringAnnotationVerifier("A valid output filename"), + Optional::No, + "The filename containing the converted result.", + }, + }, + }; +} From 40526b11a2918e270cb2c16a72245142d17ebb5f Mon Sep 17 00:00:00 2001 From: GPayne Date: Fri, 30 Aug 2019 16:57:48 -0600 Subject: [PATCH 02/26] Added command to save current delta time when recording starts. --- src/interaction/sessionrecording.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index b46206e6d7..73000cc2fd 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -168,8 +168,15 @@ bool SessionRecording::startRecording(const std::string& filename) { } _recordFile << '\n'; + //Record the current delta time so this is preserved in recording + double currentDeltaTime = global::timeManager.deltaTime(); + std::string scriptCommandForInitializingDeltaTime = "openspace.time.setDeltaTime("; + scriptCommandForInitializingDeltaTime << currentDeltaTime << ");"; + saveScriptKeyframe(scriptCommandForInitializingDeltaTime); + LINFO("Session recording started"); _timestampRecordStarted = global::windowDelegate.applicationTime(); + return true; } From 1e426f3c4604924cb3bd8589869c3049f9f97e41 Mon Sep 17 00:00:00 2001 From: GPayne Date: Wed, 4 Sep 2019 11:10:08 -0600 Subject: [PATCH 03/26] Prevent changing the simulation time rate during playback --- include/openspace/util/timemanager.h | 1 + src/interaction/sessionrecording.cpp | 5 +++-- src/util/timemanager.cpp | 13 ++++++++++--- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/include/openspace/util/timemanager.h b/include/openspace/util/timemanager.h index 523ec5da5b..fb9d5293e2 100644 --- a/include/openspace/util/timemanager.h +++ b/include/openspace/util/timemanager.h @@ -105,6 +105,7 @@ public: void removeTimeChangeCallback(CallbackHandle handle); void removeDeltaTimeChangeCallback(CallbackHandle handle); void triggerPlaybackStart(); + void stopPlayback(); void removeTimeJumpCallback(CallbackHandle handle); void removeTimelineChangeCallback(CallbackHandle handle); diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index 73000cc2fd..0c51e6ad23 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -170,8 +170,8 @@ bool SessionRecording::startRecording(const std::string& filename) { //Record the current delta time so this is preserved in recording double currentDeltaTime = global::timeManager.deltaTime(); - std::string scriptCommandForInitializingDeltaTime = "openspace.time.setDeltaTime("; - scriptCommandForInitializingDeltaTime << currentDeltaTime << ");"; + std::string scriptCommandForInitializingDeltaTime = + "openspace.time.setDeltaTime(" + std::to_string(currentDeltaTime) + ");"; saveScriptKeyframe(scriptCommandForInitializingDeltaTime); LINFO("Session recording started"); @@ -360,6 +360,7 @@ void SessionRecording::stopPlayback() { void SessionRecording::cleanUpPlayback() { global::navigationHandler.stopPlayback(); + global::timeManager.stopPlayback(); Camera* camera = global::navigationHandler.camera(); ghoul_assert(camera != nullptr, "Camera must not be nullptr"); diff --git a/src/util/timemanager.cpp b/src/util/timemanager.cpp index d8e920d2a7..430e4035b5 100644 --- a/src/util/timemanager.cpp +++ b/src/util/timemanager.cpp @@ -103,6 +103,10 @@ TimeManager::TimeManager() } void TimeManager::interpolateTime(double targetTime, double durationSeconds) { + if (_playbackModeEnabled) { + return; + } + ghoul_precondition(durationSeconds > 0.f, "durationSeconds must be positive"); const double now = global::windowDelegate.applicationTime(); @@ -275,8 +279,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) { _latestConsumedTimestamp = lastPastKeyframe->timestamp; @@ -456,6 +459,10 @@ void TimeManager::triggerPlaybackStart() { _playbackModeEnabled = true; } +void TimeManager::stopPlayback() { + _playbackModeEnabled = false; +} + void TimeManager::removeTimeJumpCallback(CallbackHandle handle) { const auto it = std::find_if( _timeJumpCallbacks.begin(), @@ -520,7 +527,7 @@ double TimeManager::targetDeltaTime() const { void TimeManager::interpolateDeltaTime(double newDeltaTime, double interpolationDuration) { - if (newDeltaTime == _targetDeltaTime) { + if (newDeltaTime == _targetDeltaTime || _playbackModeEnabled) { return; } From b375205c1a5f7b63745eaafeec792bbd6b84d32e Mon Sep 17 00:00:00 2001 From: GPayne Date: Thu, 5 Sep 2019 12:42:01 -0600 Subject: [PATCH 04/26] Undo on recently-added changes that restricted time manipulation during playback. --- src/util/timemanager.cpp | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/util/timemanager.cpp b/src/util/timemanager.cpp index 430e4035b5..3a03fd3cc0 100644 --- a/src/util/timemanager.cpp +++ b/src/util/timemanager.cpp @@ -103,10 +103,6 @@ TimeManager::TimeManager() } void TimeManager::interpolateTime(double targetTime, double durationSeconds) { - if (_playbackModeEnabled) { - return; - } - ghoul_precondition(durationSeconds > 0.f, "durationSeconds must be positive"); const double now = global::windowDelegate.applicationTime(); @@ -279,7 +275,7 @@ void TimeManager::progressTime(double dt) { // and time is not paused, just advance time. _deltaTime = _targetDeltaTime; _currentTime.data().advanceTime(dt * _deltaTime); - } + } if (hasPastKeyframes) { _latestConsumedTimestamp = lastPastKeyframe->timestamp; @@ -527,7 +523,7 @@ double TimeManager::targetDeltaTime() const { void TimeManager::interpolateDeltaTime(double newDeltaTime, double interpolationDuration) { - if (newDeltaTime == _targetDeltaTime || _playbackModeEnabled) { + if (newDeltaTime == _targetDeltaTime) { return; } From 5b4ecf2b62d550a5f3ba1920ca96a356978e5755 Mon Sep 17 00:00:00 2001 From: GPayne Date: Thu, 5 Sep 2019 14:56:11 -0600 Subject: [PATCH 05/26] Fixed timestamp problem with time rate script at start of recording --- src/interaction/sessionrecording.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index 0c51e6ad23..3ae0695f60 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -168,14 +168,15 @@ bool SessionRecording::startRecording(const std::string& filename) { } _recordFile << '\n'; + _timestampRecordStarted = global::windowDelegate.applicationTime(); + //Record the current delta time so this is preserved in recording double currentDeltaTime = global::timeManager.deltaTime(); std::string scriptCommandForInitializingDeltaTime = - "openspace.time.setDeltaTime(" + std::to_string(currentDeltaTime) + ");"; + "openspace.time.setDeltaTime(" + std::to_string(currentDeltaTime) + ")"; saveScriptKeyframe(scriptCommandForInitializingDeltaTime); LINFO("Session recording started"); - _timestampRecordStarted = global::windowDelegate.applicationTime(); return true; } From 299c4f10c43c9c08eb5425e5d3db0ef0c9e64d81 Mon Sep 17 00:00:00 2001 From: GPayne Date: Fri, 11 Oct 2019 11:45:55 -0600 Subject: [PATCH 06/26] Added some file handling to record conversion tasks --- .../openspace/interaction/sessionrecording.h | 8 +++ .../interaction/tasks/convertrecformattask.h | 13 ++++ src/interaction/sessionrecording.cpp | 21 ------ .../tasks/convertrecformattask.cpp | 71 +++++++++++++++---- 4 files changed, 77 insertions(+), 36 deletions(-) diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index 26c5f5a094..82e22f38c2 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -45,6 +45,14 @@ public: Playback }; + const std::string FileHeaderTitle = "OpenSpace_record/playback"; + constexpr const size_t FileHeaderVersionLength = 5; + constexpr const char FileHeaderVersion[FileHeaderVersionLength] = { + '0', '0', '.', '8', '5' + }; + constexpr const char DataFormatAsciiTag = 'A'; + constexpr const char DataFormatBinaryTag = 'B'; + using CallbackHandle = int; using StateChangeCallback = std::function; diff --git a/include/openspace/interaction/tasks/convertrecformattask.h b/include/openspace/interaction/tasks/convertrecformattask.h index ae89b4ab3a..65c6aeef28 100644 --- a/include/openspace/interaction/tasks/convertrecformattask.h +++ b/include/openspace/interaction/tasks/convertrecformattask.h @@ -31,6 +31,13 @@ #include +namespace { + constexpr const char* KeyConvertToAscii = "ConvertToAscii"; + constexpr const char* KeyConvertToBinary = "ConvertToBinary"; + constexpr const char* KeyInFilePath = "InputFilePath"; + constexpr const char* KeyOutFilePath = "OutputFilePath"; +} + namespace openspace { class ConvertRecFormatTask : public Task { @@ -40,13 +47,19 @@ public: ToBinary }; ConvertRecFormatTask(const ghoul::Dictionary& dictionary); + ~ConvertRecFormatTask(); std::string description() override; void perform(const Task::ProgressCallback& progressCallback) override; static documentation::Documentation documentation(); private: + void convertToAscii(); + void convertToBinary(); + std::string _inFilePath; std::string _outFilePath; + std::ifstream _iFile; + std::ifstream _oFile; std::string _valueFunctionLua; }; diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index 0c51e6ad23..1eb8fd2d03 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -46,14 +46,6 @@ namespace { constexpr const char* _loggerCat = "SessionRecording"; constexpr const bool UsingTimeKeyframes = false; - const std::string FileHeaderTitle = "OpenSpace_record/playback"; - constexpr const size_t FileHeaderVersionLength = 5; - constexpr const char FileHeaderVersion[FileHeaderVersionLength] = { - '0', '0', '.', '8', '5' - }; - constexpr const char DataFormatAsciiTag = 'A'; - constexpr const char DataFormatBinaryTag = 'B'; - template T readFromPlayback(std::ifstream& stream) { @@ -979,19 +971,6 @@ void SessionRecording::playbackScript() { } } double timeRef = appropriateTimestamp(timeOs, timeRec, timeSim); - //timeRef = getEquivalentSimulationTime(timeOs, timeRec, timeSim); - - //Call script scheduler with this new script entry - //std::string timeDescription = SpiceManager::ref().dateFromEphemerisTime( - // timeRef, - // "YYYY MON DD HR:MN:SC.###" - //); - //ghoul::Dictionary scriptDict(ghoul::Dictionary{ - // { KeyTime, timeDescription }, - // { KeyForwardScript, pbFrame._script} - //} - // ); - //global::scriptScheduler.loadScripts({ { "1", scriptDict } }); addKeyframe(timeRef, pbFrame._script); } diff --git a/src/interaction/tasks/convertrecformattask.cpp b/src/interaction/tasks/convertrecformattask.cpp index ce8b004353..1425e04e51 100644 --- a/src/interaction/tasks/convertrecformattask.cpp +++ b/src/interaction/tasks/convertrecformattask.cpp @@ -30,13 +30,11 @@ #include #include #include +#include namespace { - constexpr const char* KeyConvertToAscii = "ConvertToAscii"; - constexpr const char* KeyConvertToBinary = "ConvertToBinary"; - constexpr const char* KeyInFilePath = "InputFilePath"; - constexpr const char* KeyOutFilePath = "OutputFilePath"; -} + constexpr const char* _loggerCat = "ConvertRecFormatTask"; +} // namespace namespace openspace { @@ -49,6 +47,20 @@ ConvertRecFormatTask::ConvertRecFormatTask(const ghoul::Dictionary& dictionary) _inFilePath = absPath(dictionary.value(KeyInFilePath)); _outFilePath = absPath(dictionary.value(KeyOutFilePath)); + + ghoul_assert(FileSys.fileExists(_inFilePath), "The filename must exist"); + if (!FileSys.fileExists(_inFilePath)) { + LERROR(fmt::format("Failed to load session recording file: {}", _inFilePath)); + //throw ghoul::FileNotFoundError(_inFilePath); + } + + _iFile.exceptions(std::ofstream::failbit | std::ofstream::badbit); + _iFile.open(_inFilePath); +} + +ConvertRecFormatTask::~ConvertRecFormatTask() { + _iFile.close(); + _oFile.close(); } void ConvertRecFormatTask::perform(const Task::ProgressCallback& progressCallback) { @@ -56,35 +68,64 @@ void ConvertRecFormatTask::perform(const Task::ProgressCallback& progressCallbac } void ConvertRecFormatTask::convert() { - RecordedDataMode type = formatType(); + interaction::RecordedDataMode type = formatType(); - if (type == RecordedDataMode::Ascii) { + if (type == interaction::RecordedDataMode::Ascii) { convertToBinary(); } - else if (type == RecordedDataMode::Binary) { + else if (type == interaction::RecordedDataMode::Binary) { convertToAscii(); } else { //Add error output for file type not recognized + LERROR("Session recording file unrecognized format type."); } } RecordedDataMode ConvertRecFormatTask::formatType() { - //Read file at _inFilePath + const std::string expectedHeader = "OpenSpace_record/playback"; + std::string line; + //Get first line, which is ASCII regardless of format + std::getline(_iFile, line); - //Read first line - - //First verify that the line starts with the valid string - - //Get last character which should be either 'A' or 'B', and return Ascii or Binary based on this. + if (line.substr(0, interaction::FileHeaderTitle.length()) + != interaction::FileHeaderTitle) + { + LERROR(fmt::format("Session recording file {} does not have expected header.", _inFilePath)); + return RecordedDataMode::Binary + 1; + } + else { + if (line.back() == DataFormatAsciiTag) { + return RecordedDataMode::Ascii; + } + else if (line.back() == DataFormatBinaryTag) { + return RecordedDataMode::Binary; + } + else { + return RecordedDataMode::Binary + 1; + } + } } void ConvertRecFormatTask::convertToAscii() { - + _outFilePath = addFileSuffix(_inFilePath, "_ascii"); } void ConvertRecFormatTask::convertToBinary() { + _outFilePath = addFileSuffix(_inFilePath, "_binary"); +} +std::string ConvertRecFormatTask::addFileSuffix(const std::string& filePath, + const std::string& suffix) +{ + size_t lastdot = filename.find_last_of("."); + std::string extension = filePath.substr(0, lastdot); + if (lastdot == std::string::npos) { + return filePath + suffix; + } + else { + return filePath.substr(0, lastdot) + suffix + extension; + } } documentation::Documentation ConvertRecFormatTask::documentation() { From 27ef369338991affeb6687703d5027e79fd8d49d Mon Sep 17 00:00:00 2001 From: GPayne Date: Thu, 17 Oct 2019 18:20:37 -0600 Subject: [PATCH 07/26] Separated playback keyframe extraction into steps (file read & parse) --- .../openspace/interaction/keyframenavigator.h | 8 ++ .../openspace/interaction/sessionrecording.h | 30 ++++ include/openspace/network/messagestructures.h | 16 +++ src/interaction/sessionrecording.cpp | 135 +++++++++--------- 4 files changed, 120 insertions(+), 69 deletions(-) diff --git a/include/openspace/interaction/keyframenavigator.h b/include/openspace/interaction/keyframenavigator.h index a241815c2c..77783d6bd4 100644 --- a/include/openspace/interaction/keyframenavigator.h +++ b/include/openspace/interaction/keyframenavigator.h @@ -54,6 +54,14 @@ public: std::string focusNode; float scale; bool followFocusNodeRotation; + + CameraPose(const openspace::datamessagestructures::CameraKeyframe& kf) { + position = kf._position; + rotation = kf._rotation; + focusNode = kf._focusNode; + scale = kf._scale; + followFocusNodeRotation = kf._followNodeRotation; + } }; /** diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index 82e22f38c2..025a91a7d7 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -45,6 +45,12 @@ public: Playback }; + struct timestamps { + double timeOs; + double timeRec; + double timeSim; + }; + const std::string FileHeaderTitle = "OpenSpace_record/playback"; constexpr const size_t FileHeaderVersionLength = 5; constexpr const char FileHeaderVersion[FileHeaderVersionLength] = { @@ -216,6 +222,30 @@ public: */ std::vector playbackList() const; + /** + * Reads a camera keyframe from a binary format playback file, and populates input + * references with the parameters of the keyframe. + * + * \param times reference to a timestamps structure which contains recorded times + * \param kf reference to a camera keyframe which contains camera details + * \param file an ifstream reference to the playback file being read + * \param lineN keyframe number in playback file where this keyframe resides + */ + static void readCameraKeyframeBinary(timestamps& times, + datamessagestructures::CameraKeyframe& kf, std::ifstream& file, int lineN); + + /** + * Reads a camera keyframe from an ascii format playback file, and populates input + * references with the parameters of the keyframe. + * + * \param times reference to a timestamps structure which contains recorded times + * \param kf reference to a camera keyframe which contains camera details + * \param filenameRead a string containing the playback filename + * \param lineN line number in playback file where this keyframe resides + */ + static void readCameraKeyframeAscii(timestamps& times, + datamessagestructures::CameraKeyframe& kf, std::string filenameRead, int lineN); + private: enum class RecordedType { Camera = 0, diff --git a/include/openspace/network/messagestructures.h b/include/openspace/network/messagestructures.h index d1e60f7bb3..aa873d8ca4 100644 --- a/include/openspace/network/messagestructures.h +++ b/include/openspace/network/messagestructures.h @@ -233,6 +233,22 @@ struct CameraKeyframe { sizeof(_timestamp) ); }; + + void read(std::istringstream* iss) { + std::string rotationFollowing; + + iss >> _position.x + >> _position.y + >> _position.z + >> _rotation.x + >> _rotation.y + >> _rotation.z + >> _rotation.w + >> _scale + >> rotationFollowing + >> _focusNode; + _followNodeRotation = (rotationFollowing == "F"); + }; }; struct TimeKeyframe { diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index 37a9303403..091c7fe1d1 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -781,84 +781,81 @@ double SessionRecording::fixedDeltaTimeDuringFrameOutput() const { } void SessionRecording::playbackCamera() { - double timeOs; - double timeRec; - double timeSim; - std::string rotationFollowing; - interaction::KeyframeNavigator::CameraPose pbFrame; + timestamps times; datamessagestructures::CameraKeyframe kf; + if (_recordingDataMode == RecordedDataMode::Binary) { - timeOs = readFromPlayback(_playbackFile); - timeRec = readFromPlayback(_playbackFile); - timeSim = readFromPlayback(_playbackFile); - try { - kf.read(&_playbackFile); - } - catch (std::bad_alloc&) { - LERROR(fmt::format( - "Allocation error with camera playback from keyframe entry {}", - _playbackLineNum - 1 - )); - return; - } - catch (std::length_error&) { - LERROR(fmt::format( - "length_error with camera playback from keyframe entry {}", - _playbackLineNum - 1 - )); - return; - } - - timeOs = kf._timestamp; - - pbFrame.focusNode = kf._focusNode; - pbFrame.position = kf._position; - pbFrame.rotation = kf._rotation; - pbFrame.scale = kf._scale; - pbFrame.followFocusNodeRotation = kf._followNodeRotation; - - if (!_playbackFile) { - LINFO(fmt::format( - "Error reading camera playback from keyframe entry {}", - _playbackLineNum - 1 - )); - return; - } + readCameraKeyframeBinary(times, kf, _playbackFile, _playbackLineNum); } else { - std::istringstream iss(_playbackLineParsing); - std::string entryType; - iss >> entryType; - iss >> timeOs >> timeRec >> timeSim; - iss >> pbFrame.position.x - >> pbFrame.position.y - >> pbFrame.position.z - >> pbFrame.rotation.x - >> pbFrame.rotation.y - >> pbFrame.rotation.z - >> pbFrame.rotation.w - >> pbFrame.scale - >> rotationFollowing - >> pbFrame.focusNode; - if (iss.fail() || !iss.eof()) { - LERROR(fmt::format( - "Error parsing camera line {} of playback file", _playbackLineNum - )); - return; - } - pbFrame.followFocusNodeRotation = (rotationFollowing == "F"); + readCameraKeyframeAscii(times, kf, _playbackLineParsing, _playbackLineNum); } - if (_setSimulationTimeWithNextCameraKeyframe) { - global::timeManager.setTimeNextFrame(Time(timeSim)); - _setSimulationTimeWithNextCameraKeyframe = false; - _saveRenderingCurrentRecordedTime = timeRec; - } - double timeRef = appropriateTimestamp(timeOs, timeRec, timeSim); - //global::navigationHandler.keyframeNavigator().addKeyframe(timeRef, pbFrame); + if (_setSimulationTimeWithNextCameraKeyframe) { + global::timeManager.setTimeNextFrame(Time(times.timeSim)); + _setSimulationTimeWithNextCameraKeyframe = false; + _saveRenderingCurrentRecordedTime = times.timeRec; + } + double timeRef = appropriateTimestamp(times.timeOs, times.timeRec, times.timeSim); + + interaction::KeyframeNavigator::CameraPose pbFrame(kf); addKeyframe(timeRef, pbFrame); } +static void SessionRecording::readCameraKeyframeBinary(timestamps& times, + datamessagestructures::CameraKeyframe& kf, + std::ifstream& file, int lineN) +{ + times.timeOs = readFromPlayback(file); + times.timeRec = readFromPlayback(file); + times.timeSim = readFromPlayback(file); + try { + kf.read(&file); + } + catch (std::bad_alloc&) { + LERROR(fmt::format( + "Allocation error with camera playback from keyframe entry {}", + lineN - 1 + )); + return; + } + catch (std::length_error&) { + LERROR(fmt::format( + "length_error with camera playback from keyframe entry {}", + lineN - 1 + )); + return; + } + times.timeOs = kf._timestamp; + + if (!file) { + LINFO(fmt::format( + "Error reading camera playback from keyframe entry {}", + lineN - 1 + )); + return; + } +} + +static void SessionRecording::readCameraKeyframeAscii(timestamps& times, + datamessagestructures::CameraKeyframe& kf, + std::string filenameRead, + int lineN) +{ + std::string rotationFollowing; + std::string entryType; + + std::istringstream iss(filenameRead); + iss >> entryType; + iss >> times.timeOs >> times.timeRec >> times.timeSim; + kf.read(&iss); + + if (iss.fail() || !iss.eof()) { + LERROR(fmt::format("Error parsing camera line {} of playback file", lineN)); + return; + } +} + void SessionRecording::playbackTimeChange() { double timeOs; double timeRec; From a549993727a314305fc895a2cf41892f3c9df3fc Mon Sep 17 00:00:00 2001 From: GPayne Date: Wed, 23 Oct 2019 18:02:20 -0600 Subject: [PATCH 08/26] Finished time and script keyframe types into separate read & parse steps --- .../openspace/interaction/sessionrecording.h | 50 ++++ include/openspace/network/messagestructures.h | 24 ++ src/interaction/sessionrecording.cpp | 231 ++++++++++-------- 3 files changed, 203 insertions(+), 102 deletions(-) diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index 025a91a7d7..7cf6905312 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -246,6 +246,56 @@ public: static void readCameraKeyframeAscii(timestamps& times, datamessagestructures::CameraKeyframe& kf, std::string filenameRead, int lineN); + /** + * Reads a time keyframe from a binary format playback file, and populates input + * references with the parameters of the keyframe. + * + * \param times reference to a timestamps structure which contains recorded times + * \param kf reference to a time keyframe which contains time details + * \param file an ifstream reference to the playback file being read + * \param lineN keyframe number in playback file where this keyframe resides + */ + static void SessionRecording::readTimeKeyframeBinary(timestamps& times, + datamessagestructures::TimeKeyframe& kf, std::ifstream& file, int lineN); + + /** + * Reads a time keyframe from an ascii format playback file, and populates input + * references with the parameters of the keyframe. + * + * \param times reference to a timestamps structure which contains recorded times + * \param kf reference to a time keyframe which contains time details + * \param filenameRead a string containing the playback filename + * \param lineN line number in playback file where this keyframe resides + */ + static void SessionRecording::readTimeKeyframeAscii(timestamps& times, + datamessagestructures::TimeKeyframe& kf, std::string filenameRead, int lineN); + + /** + * Reads a script keyframe from a binary format playback file, and populates input + * references with the parameters of the keyframe. + * + * \param times reference to a timestamps structure which contains recorded times + * \param kf reference to a script keyframe which contains the size of the script + * (in chars) and the text itself + * \param file an ifstream reference to the playback file being read + * \param lineN keyframe number in playback file where this keyframe resides + */ + static void SessionRecording::readScriptKeyframeBinary(timestamps& times, + datamessagestructures::ScriptMessage& kf, std::ifstream& file, int lineN); + + /** + * Reads a script keyframe from an ascii format playback file, and populates input + * references with the parameters of the keyframe. + * + * \param times reference to a timestamps structure which contains recorded times + * \param kf reference to a script keyframe which contains the size of the script + * (in chars) and the text itself + * \param filenameRead a string containing the playback filename + * \param lineN line number in playback file where this keyframe resides + */ + static void SessionRecording::readScriptKeyframeAscii(timestamps& times, + datamessagestructures::ScriptMessage& kf, std::string filenameRead, int lineN); + private: enum class RecordedType { Camera = 0, diff --git a/include/openspace/network/messagestructures.h b/include/openspace/network/messagestructures.h index aa873d8ca4..8b9d72cc64 100644 --- a/include/openspace/network/messagestructures.h +++ b/include/openspace/network/messagestructures.h @@ -290,6 +290,16 @@ struct TimeKeyframe { sizeof(TimeKeyframe) ); }; + + void read(std::istringstream* iss) { + std::string paused, jump; + + iss >> _dt + >> paused + >> jump; + _paused = (paused == "P"); + _requiresTimeJump = (jump == "J"); + }; }; struct TimeTimeline { @@ -404,6 +414,20 @@ struct ScriptMessage { _script.erase(); _script = temp.data(); }; + + void read(std::istringstream* iss) { + int numScriptLines; + iss >> numScriptLines; + std::string tmpReadbackScript; + _script.erase(); + for (unsigned int i = 0; i < numScriptLines; ++i) { + std::getline(iss, tmpReadbackScript); + _script.append(tmpReadbackScript); + if (i < (numScriptLines - 1)) { + _script.append("\n"); + } + } + }; }; } // namespace openspace::messagestructures diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index 091c7fe1d1..656298d65a 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -803,7 +803,7 @@ void SessionRecording::playbackCamera() { } static void SessionRecording::readCameraKeyframeBinary(timestamps& times, - datamessagestructures::CameraKeyframe& kf, + datamessagestructures::CameraKeyframe& kf, std::ifstream& file, int lineN) { times.timeOs = readFromPlayback(file); @@ -838,7 +838,7 @@ static void SessionRecording::readCameraKeyframeBinary(timestamps& times, } static void SessionRecording::readCameraKeyframeAscii(timestamps& times, - datamessagestructures::CameraKeyframe& kf, + datamessagestructures::CameraKeyframe& kf, std::string filenameRead, int lineN) { @@ -857,119 +857,146 @@ static void SessionRecording::readCameraKeyframeAscii(timestamps& times, } void SessionRecording::playbackTimeChange() { - double timeOs; - double timeRec; - double timeSim; - datamessagestructures::TimeKeyframe pbFrame; + timestamps times; + datamessagestructures::TimeKeyframe kf; + if (_recordingDataMode == RecordedDataMode::Binary) { - timeOs = readFromPlayback(_playbackFile); - timeRec = readFromPlayback(_playbackFile); - timeSim = readFromPlayback(_playbackFile); - pbFrame._dt = readFromPlayback(_playbackFile); - pbFrame._paused = readFromPlayback(_playbackFile); - pbFrame._requiresTimeJump = readFromPlayback(_playbackFile); - - if (!_playbackFile) { - LERROR(fmt::format( - "Error reading time playback from keyframe entry {}", _playbackLineNum - 1 - )); - return; - } + readTimeKeyframeBinary(times, kf, _playbackFile, _playbackLineNum); } else { - std::istringstream iss(_playbackLineParsing); - std::string entryType; - //double timeRef; - std::string paused, jump; - iss >> entryType; - iss >> timeOs >> timeRec >> timeSim; - iss >> pbFrame._dt - >> paused - >> jump; - if (iss.fail() || !iss.eof()) { - LERROR(fmt::format( - "Error parsing time line {} of playback file", _playbackLineNum - )); - return; - } - pbFrame._paused = (paused == "P"); - pbFrame._requiresTimeJump = (jump == "J"); + readTimeKeyframeAscii(times, kf, _playbackLineParsing, _playbackLineNum); } - pbFrame._timestamp = equivalentApplicationTime(timeOs, timeRec, timeSim); + kf._timestamp = equivalentApplicationTime(times.timeOs, times.timeRec, times.timeSim); - pbFrame._time = pbFrame._timestamp + _timestampApplicationStarted_simulation; + kf._time = kf._timestamp + _timestampApplicationStarted_simulation; //global::timeManager.addKeyframe(timeRef, pbFrame._timestamp); //_externInteract.timeInteraction(pbFrame); - addKeyframe(pbFrame._timestamp, pbFrame); + addKeyframe(kf._timestamp, kf); +} + +static void SessionRecording::readTimeKeyframeBinary(timestamps& times, + datamessagestructures::TimeKeyframe& kf, + std::ifstream& file, int lineN) +{ + times.timeOs = readFromPlayback(file); + times.timeRec = readFromPlayback(file); + times.timeSim = readFromPlayback(file); + + try { + kf.read(&file); + } + catch (std::bad_alloc&) { + LERROR(fmt::format( + "Allocation error with time playback from keyframe entry {}", + lineN - 1 + )); + return; + } + catch (std::length_error&) { + LERROR(fmt::format( + "length_error with time playback from keyframe entry {}", + lineN - 1 + )); + return; + } + + if (!file) { + LERROR(fmt::format( + "Error reading time playback from keyframe entry {}", lineN - 1 + )); + return; + } +} + +static void SessionRecording::readTimeKeyframeAscii(timestamps& times, + datamessagestructures::TimeKeyframe& kf, + std::string filenameRead, + int lineN) +{ + std::string entryType; + + std::istringstream iss(filenameRead); + iss >> entryType; + iss >> times.timeOs >> times.timeRec >> times.timeSim; + kf.read(&iss); + + if (iss.fail() || !iss.eof()) { + LERROR(fmt::format( + "Error parsing time line {} of playback file", _playbackLineNum + )); + return; + } } void SessionRecording::playbackScript() { - double timeOs; - double timeRec; - double timeSim; - unsigned int numScriptLines; - datamessagestructures::ScriptMessage pbFrame; + timestamps times; + datamessagestructures::ScriptMessage kf; if (_recordingDataMode == RecordedDataMode::Binary) { - timeOs = readFromPlayback(_playbackFile); - timeRec = readFromPlayback(_playbackFile); - timeSim = readFromPlayback(_playbackFile); - try { - pbFrame._script = readFromPlayback(_playbackFile); - } - catch (std::bad_alloc&) { - LERROR(fmt::format( - "Allocation error with script playback from keyframe entry {}", - _playbackLineNum - 1 - )); - return; - } - catch (std::length_error&) { - LERROR(fmt::format( - "length_error with script playback from keyframe entry {}", - _playbackLineNum - 1 - )); - return; - } - - if (!_playbackFile) { - LERROR(fmt::format( - "Error reading script playback from keyframe entry {}", - _playbackLineNum - 1 - )); - return; - } + readScriptKeyframeBinary(times, kf, _playbackFile, _playbackLineNum); } else { - std::istringstream iss(_playbackLineParsing); - std::string entryType; - std::string tmpReadbackScript; - - iss >> entryType; - iss >> timeOs >> timeRec >> timeSim; - iss >> numScriptLines; - std::getline(iss, tmpReadbackScript); //iss >> tmpReadbackScript; - pbFrame._script.append(tmpReadbackScript); - if (iss.fail()) { - LERROR(fmt::format( - "Error parsing script line {} of playback file", _playbackLineNum - )); - return; - } else if (!iss.eof()) { - LERROR(fmt::format( - "Did not find an EOL at line {} of playback file", _playbackLineNum - )); - return; - } - if (numScriptLines > 1) { - //Now loop to read any subsequent lines if is a multi-line script - for (unsigned int i = 1; i < numScriptLines; ++i) { - pbFrame._script.append("\n"); - std::getline(_playbackFile, tmpReadbackScript); - pbFrame._script.append(tmpReadbackScript); - } - } + readScriptKeyframeAscii(times, kf, _playbackLineParsing, _playbackLineNum); + } + + double timeRef = appropriateTimestamp(times.timeOs, times.timeRec, times.timeSim); + addKeyframe(timeRef, kf._script); +} + +static void SessionRecording::readScriptKeyframeBinary(timestamps& times, + datamessagestructures::ScriptMessage& kf, + std::ifstream& file, int lineN) +{ + times.timeOs = readFromPlayback(file); + times.timeRec = readFromPlayback(file); + times.timeSim = readFromPlayback(file); + + try { + kf.read(&file); + } + catch (std::bad_alloc&) { + LERROR(fmt::format( + "Allocation error with script playback from keyframe entry {}", + lineN - 1 + )); + return; + } + catch (std::length_error&) { + LERROR(fmt::format( + "length_error with script playback from keyframe entry {}", + lineN - 1 + )); + return; + } + + if (!file) { + LERROR(fmt::format( + "Error reading script playback from keyframe entry {}", + lineN - 1 + )); + return; + } +} + +static void SessionRecording::readScriptKeyframeAscii(timestamps& times, + datamessagestructures::ScriptMessage& kf, + std::string filenameRead, + int lineN) +{ + std::string entryType; + std::istringstream iss(filenameRead); + iss >> entryType; + iss >> times.timeOs >> times.timeRec >> times.timeSim; + kf.read(&iss); + if (iss.fail()) { + LERROR(fmt::format( + "Error parsing script line {} of playback file", _playbackLineNum + )); + return; + } else if (!iss.eof()) { + LERROR(fmt::format( + "Did not find an EOL at line {} of playback file", _playbackLineNum + )); + return; } - double timeRef = appropriateTimestamp(timeOs, timeRec, timeSim); - addKeyframe(timeRef, pbFrame._script); } void SessionRecording::addKeyframe(double timestamp, From 915eefbf11c1d9aec00070c4f23d50ec04d16216 Mon Sep 17 00:00:00 2001 From: GPayne Date: Thu, 24 Oct 2019 13:06:52 -0600 Subject: [PATCH 09/26] Working on separating writing of recording keyframes into separate read & parse steps --- .../openspace/interaction/sessionrecording.h | 37 +++- src/interaction/sessionrecording.cpp | 179 +++++++++++------- 2 files changed, 137 insertions(+), 79 deletions(-) diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index 7cf6905312..69ddb74ee5 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -296,6 +296,29 @@ public: static void SessionRecording::readScriptKeyframeAscii(timestamps& times, datamessagestructures::ScriptMessage& kf, std::string filenameRead, int lineN); + /** + * Writes a camera keyframe to a binary format recording file using a CameraKeyframe + * + * \param times reference to a timestamps structure which contains recorded times + * \param kf reference to a camera keyframe which contains the camera details + * \param kfBuffer a buffer temporarily used for preparing data to be written + * \param idx index into the temporary buffer + * \param file an ofstream reference to the playback file being written-to + */ + static void SessionRecording::saveCameraKeyframeBinary(timestamps times, + datamessagestructures::CameraKeyframe& kf, unsigned char* kfBuffer, size_t& idx, + std::ofstream& file); + + /** + * Writes a camera keyframe to an ascii format recording file using a CameraKeyframe + * + * \param times reference to a timestamps structure which contains recorded times + * \param kf reference to a camera keyframe which contains the camera details + * \param file an ofstream reference to the playback file being written-to + */ + static void SessionRecording::saveCameraKeyframeAscii(timestamps times, + datamessagestructures::CameraKeyframe& kf, std::ofstream& file); + private: enum class RecordedType { Camera = 0, @@ -323,14 +346,11 @@ private: void playbackScript(); bool playbackAddEntriesToTimeline(); void signalPlaybackFinishedForComponent(RecordedType type); - void writeToFileBuffer(double src); - void writeToFileBuffer(std::vector& cvec); - void writeToFileBuffer(unsigned char c); - void writeToFileBuffer(bool b); void saveStringToFile(const std::string& s); - void saveKeyframeToFileBinary(unsigned char* bufferSource, size_t size); + void saveKeyframeToFileBinary(unsigned char* bufferSource, size_t size, + std::ofstream& file); void findFirstCameraKeyframeInTimeline(); - void saveKeyframeToFile(std::string entry); + void saveKeyframeToFile(std::string entry, std::ofstream& file); void addKeyframe(double timestamp, interaction::KeyframeNavigator::CameraPose keyframe); @@ -355,6 +375,11 @@ private: double getPrevTimestamp(); void cleanUpPlayback(); + static void writeToFileBuffer(unsigned char* buf, size_t& idx, double src); + static void writeToFileBuffer(unsigned char* buf, size_t& idx, std::vector& cv); + static void writeToFileBuffer(unsigned char* buf, size_t& idx, unsigned char c); + static void writeToFileBuffer(unsigned char* buf, size_t& idx, bool b); + RecordedDataMode _recordingDataMode = RecordedDataMode::Binary; SessionState _state = SessionState::Idle; SessionState _lastState = SessionState::Idle; diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index 656298d65a..89bde19f33 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -385,28 +385,40 @@ void SessionRecording::cleanUpPlayback() { _cleanupNeeded = false; } -void SessionRecording::writeToFileBuffer(double src) { +static void SessionRecording::writeToFileBuffer(unsigned char* buf, + size_t& idx, + double src) +{ const size_t writeSize_bytes = sizeof(double); unsigned char const *p = reinterpret_cast(&src); - memcpy((_keyframeBuffer + _bufferIndex), p, writeSize_bytes); - _bufferIndex += writeSize_bytes; + memcpy((buf + idx), p, writeSize_bytes); + idx += writeSize_bytes; } -void SessionRecording::writeToFileBuffer(std::vector& cvec) { - const size_t writeSize_bytes = cvec.size() * sizeof(char); - memcpy((_keyframeBuffer + _bufferIndex), cvec.data(), writeSize_bytes); - _bufferIndex += writeSize_bytes; +static void SessionRecording::writeToFileBuffer(unsigned char* buf, + size_t& idx, + std::vector& cv) +{ + const size_t writeSize_bytes = cv.size() * sizeof(char); + memcpy((buf + idx), cv.data(), writeSize_bytes); + idx += writeSize_bytes; } -void SessionRecording::writeToFileBuffer(unsigned char c) { +static void SessionRecording::writeToFileBuffer(unsigned char* buf, + size_t& idx, + unsigned char c) +{ const size_t writeSize_bytes = sizeof(char); - _keyframeBuffer[_bufferIndex] = c; - _bufferIndex += writeSize_bytes; + buf[idx] = c; + idx += writeSize_bytes; } -void SessionRecording::writeToFileBuffer(bool b) { - _keyframeBuffer[_bufferIndex] = b ? 1 : 0; - _bufferIndex += sizeof(char); +static void SessionRecording::writeToFileBuffer(unsigned char* buf, + size_t& idx, + bool b) +{ + buf[idx] = b ? 1 : 0; + idx += sizeof(char); } void SessionRecording::saveStringToFile(const std::string& s) { @@ -417,7 +429,7 @@ void SessionRecording::saveStringToFile(const std::string& s) { unsigned char const *p = reinterpret_cast(&strLen); memcpy((_keyframeBuffer + _bufferIndex), p, writeSize_bytes); _bufferIndex += static_cast(writeSize_bytes); - saveKeyframeToFileBinary(_keyframeBuffer, _bufferIndex); + saveKeyframeToFileBinary(_keyframeBuffer, _bufferIndex, _recordFile); _recordFile.write(s.c_str(), s.size()); } @@ -456,54 +468,71 @@ void SessionRecording::saveCameraKeyframe() { // & orientation of camera datamessagestructures::CameraKeyframe kf = _externInteract.generateCameraKeyframe(); + timestamps times = { + kf._timestamp, + kf._timestamp - _timestampRecordStarted, + global::timeManager.time().j2000Seconds() + }; if (_recordingDataMode == RecordedDataMode::Binary) { - // Writing to a binary session recording file - _bufferIndex = 0; - _keyframeBuffer[_bufferIndex++] = 'c'; - - // Writing to internal buffer, and then to file, for performance reasons - writeToFileBuffer(kf._timestamp); - writeToFileBuffer(kf._timestamp - _timestampRecordStarted); - writeToFileBuffer(global::timeManager.time().j2000Seconds()); - std::vector kfBuffer; - kf.serialize(kfBuffer); - writeToFileBuffer(kfBuffer); - - saveKeyframeToFileBinary(_keyframeBuffer, _bufferIndex); + saveCameraKeyframeBinary(times, kf, _keyframeBuffer, _bufferIndex, _recordFile); } else { - // Writing to an ASCII session recording file - std::stringstream keyframeLine = std::stringstream(); - // Add simulation timestamp, timestamp relative, simulation time to recording - // start - keyframeLine << "camera "; - keyframeLine << kf._timestamp << ' '; - keyframeLine << (kf._timestamp - _timestampRecordStarted) << ' '; - keyframeLine << std::fixed << std::setprecision(3) << - global::timeManager.time().j2000Seconds(); - keyframeLine << ' '; - // Add camera position - keyframeLine << std::fixed << std::setprecision(7) << kf._position.x << ' ' - << std::fixed << std::setprecision(7) << kf._position.y << ' ' - << std::fixed << std::setprecision(7) << kf._position.z << ' '; - // Add camera rotation - keyframeLine << std::fixed << std::setprecision(7) << kf._rotation.x << ' ' - << std::fixed << std::setprecision(7) << kf._rotation.y << ' ' - << std::fixed << std::setprecision(7) << kf._rotation.z << ' ' - << std::fixed << std::setprecision(7) << kf._rotation.w << ' '; - keyframeLine << std::scientific << kf._scale << ' '; - if (kf._followNodeRotation) { - keyframeLine << "F "; - } - else { - keyframeLine << "- "; - } - keyframeLine << kf._focusNode; - - saveKeyframeToFile(keyframeLine.str()); + saveCameraKeyframeAscii(times, kf, _recordFile); } } +static void SessionRecording::saveCameraKeyframeBinary(timestamps times, + datamessagestructures::CameraKeyframe& kf, + unsigned char* kfBuffer, + size_t& idx, + std::ofstream& file) +{ + // Writing to a binary session recording file + idx = 0; + kfBuffer[idx++] = 'c'; + + // Writing to internal buffer, and then to file, for performance reasons + writeToFileBuffer(kfBuffer, idx, times.timeOs); + writeToFileBuffer(kfBuffer, idx, times.timeRec); + writeToFileBuffer(kfBuffer, idx, times.timeSim); + std::vector writeBuffer; + kf.serialize(writeBuffer); + writeToFileBuffer(kfBuffer, idx, writeBuffer); + + saveKeyframeToFileBinary(kfBuffer, idx, file); +} + +static void SessionRecording::saveCameraKeyframeAscii(timestamps times, + datamessagestructures::CameraKeyframe& kf, + std::ofstream& file) +{ + std::stringstream keyframeLine = std::stringstream(); + // Add simulation timestamp, timestamp relative, simulation time to recording start + keyframeLine << "camera "; + keyframeLine << times.timeOs << ' '; + keyframeLine << times.timeRec << ' '; + keyframeLine << std::fixed << std::setprecision(3) << times.timeSim << ' '; + // Add camera position + keyframeLine << std::fixed << std::setprecision(7) << kf._position.x << ' ' + << std::fixed << std::setprecision(7) << kf._position.y << ' ' + << std::fixed << std::setprecision(7) << kf._position.z << ' '; + // Add camera rotation + keyframeLine << std::fixed << std::setprecision(7) << kf._rotation.x << ' ' + << std::fixed << std::setprecision(7) << kf._rotation.y << ' ' + << std::fixed << std::setprecision(7) << kf._rotation.z << ' ' + << std::fixed << std::setprecision(7) << kf._rotation.w << ' '; + keyframeLine << std::scientific << kf._scale << ' '; + if (kf._followNodeRotation) { + keyframeLine << "F "; + } + else { + keyframeLine << "- "; + } + keyframeLine << kf._focusNode; + + saveKeyframeToFile(keyframeLine.str(), file); +} + void SessionRecording::saveTimeKeyframe() { if (_state != SessionState::Recording) { return; @@ -515,14 +544,15 @@ void SessionRecording::saveTimeKeyframe() { if (_recordingDataMode == RecordedDataMode::Binary) { _bufferIndex = 0; _keyframeBuffer[_bufferIndex++] = 't'; - writeToFileBuffer(kf._timestamp); - writeToFileBuffer(kf._timestamp - _timestampRecordStarted); - writeToFileBuffer(kf._time); - writeToFileBuffer(kf._dt); - writeToFileBuffer(kf._paused); - writeToFileBuffer(kf._requiresTimeJump); + writeToFileBuffer(_keyframeBuffer, _bufferIndex, kf._timestamp); + writeToFileBuffer(_keyframeBuffer, _bufferIndex, kf._timestamp + - _timestampRecordStarted); + writeToFileBuffer(_keyframeBuffer, _bufferIndex, kf._time); + writeToFileBuffer(_keyframeBuffer, _bufferIndex, kf._dt); + writeToFileBuffer(_keyframeBuffer, _bufferIndex, kf._paused); + writeToFileBuffer(_keyframeBuffer, _bufferIndex, kf._requiresTimeJump); - saveKeyframeToFileBinary(_keyframeBuffer, _bufferIndex); + saveKeyframeToFileBinary(_keyframeBuffer, _bufferIndex, _recordFile); } else { std::stringstream keyframeLine = std::stringstream(); //Add simulation timestamp, timestamp relative, simulation time to recording start @@ -545,7 +575,7 @@ void SessionRecording::saveTimeKeyframe() { else { keyframeLine << " -"; } - saveKeyframeToFile(keyframeLine.str()); + saveKeyframeToFile(keyframeLine.str(), _recordFile); } } @@ -560,11 +590,11 @@ void SessionRecording::saveScriptKeyframe(std::string scriptToSave) { if (_recordingDataMode == RecordedDataMode::Binary) { _bufferIndex = 0; _keyframeBuffer[_bufferIndex++] = 's'; - writeToFileBuffer(sm._timestamp); - writeToFileBuffer(sm._timestamp - _timestampRecordStarted); - writeToFileBuffer(global::timeManager.time().j2000Seconds()); + writeToFileBuffer(_keyframeBuffer, _bufferIndex, sm._timestamp); + writeToFileBuffer(_keyframeBuffer, _bufferIndex, sm._timestamp - _timestampRecordStarted); + writeToFileBuffer(_keyframeBuffer, _bufferIndex, global::timeManager.time().j2000Seconds()); //Write header to file - saveKeyframeToFileBinary(_keyframeBuffer, _bufferIndex); + saveKeyframeToFileBinary(_keyframeBuffer, _bufferIndex, _recordFile); saveStringToFile(scriptToSave); } @@ -583,7 +613,7 @@ void SessionRecording::saveScriptKeyframe(std::string scriptToSave) { keyframeLine << (numLinesInScript + 1) << ' '; keyframeLine << scriptToSave; - saveKeyframeToFile(keyframeLine.str()); + saveKeyframeToFile(keyframeLine.str(), _recordFile); } } @@ -1320,12 +1350,15 @@ SessionRecording::RecordedType SessionRecording::getPrevKeyframeType() { } } -void SessionRecording::saveKeyframeToFileBinary(unsigned char* buffer, size_t size) { - _recordFile.write(reinterpret_cast(buffer), size); +void SessionRecording::saveKeyframeToFileBinary(unsigned char* buffer, + size_t size, + std::ofstream& file) +{ + file.write(reinterpret_cast(buffer), size); } -void SessionRecording::saveKeyframeToFile(std::string entry) { - _recordFile << std::move(entry) << std::endl; +void SessionRecording::saveKeyframeToFile(std::string entry, std::ofstream& file) { + file << std::move(entry) << std::endl; } SessionRecording::CallbackHandle SessionRecording::addStateChangeCallback( From ae5da23b0434d8b228dee72e3dc9b6a56cd3f435 Mon Sep 17 00:00:00 2001 From: GPayne Date: Mon, 28 Oct 2019 15:56:27 -0600 Subject: [PATCH 10/26] Separated writing of time keyframes into separate read & parse steps --- .../openspace/interaction/sessionrecording.h | 27 +++++- src/interaction/sessionrecording.cpp | 91 ++++++++++++------- 2 files changed, 81 insertions(+), 37 deletions(-) diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index 69ddb74ee5..a584dd56c6 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -303,7 +303,7 @@ public: * \param kf reference to a camera keyframe which contains the camera details * \param kfBuffer a buffer temporarily used for preparing data to be written * \param idx index into the temporary buffer - * \param file an ofstream reference to the playback file being written-to + * \param file an ofstream reference to the recording file being written-to */ static void SessionRecording::saveCameraKeyframeBinary(timestamps times, datamessagestructures::CameraKeyframe& kf, unsigned char* kfBuffer, size_t& idx, @@ -314,11 +314,34 @@ public: * * \param times reference to a timestamps structure which contains recorded times * \param kf reference to a camera keyframe which contains the camera details - * \param file an ofstream reference to the playback file being written-to + * \param file an ofstream reference to the recording file being written-to */ static void SessionRecording::saveCameraKeyframeAscii(timestamps times, datamessagestructures::CameraKeyframe& kf, std::ofstream& file); + /** + * Writes a time keyframe to a binary format recording file using a TimeKeyframe + * + * \param times reference to a timestamps structure which contains recorded times + * \param kf reference to a time keyframe which contains the time details + * \param kfBuffer a buffer temporarily used for preparing data to be written + * \param idx index into the temporary buffer + * \param file an ofstream reference to the recording file being written-to + */ + static void SessionRecording::saveTimeKeyframeBinary(timestamps times, + datamessagestructures::TimeKeyframe& kf, unsigned char* kfBuffer, size_t& idx, + std::ofstream& file); + + /** + * Writes a time keyframe to an ascii format recording file using a TimeKeyframe + * + * \param times reference to a timestamps structure which contains recorded times + * \param kf reference to a time keyframe which contains the time details + * \param file an ofstream reference to the recording file being written-to + */ + static void SessionRecording::saveTimeKeyframeAscii(timestamps times, + datamessagestructures::TimeKeyframe& kf, std::ofstream& file); + private: enum class RecordedType { Camera = 0, diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index 89bde19f33..7547c834a9 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -513,11 +513,13 @@ static void SessionRecording::saveCameraKeyframeAscii(timestamps times, keyframeLine << times.timeRec << ' '; keyframeLine << std::fixed << std::setprecision(3) << times.timeSim << ' '; // Add camera position - keyframeLine << std::fixed << std::setprecision(7) << kf._position.x << ' ' + keyframeLine + << std::fixed << std::setprecision(7) << kf._position.x << ' ' << std::fixed << std::setprecision(7) << kf._position.y << ' ' << std::fixed << std::setprecision(7) << kf._position.z << ' '; // Add camera rotation - keyframeLine << std::fixed << std::setprecision(7) << kf._rotation.x << ' ' + keyframeLine + << std::fixed << std::setprecision(7) << kf._rotation.x << ' ' << std::fixed << std::setprecision(7) << kf._rotation.y << ' ' << std::fixed << std::setprecision(7) << kf._rotation.z << ' ' << std::fixed << std::setprecision(7) << kf._rotation.w << ' '; @@ -541,44 +543,63 @@ void SessionRecording::saveTimeKeyframe() { //Create a time keyframe, then call to populate it with current time props datamessagestructures::TimeKeyframe kf = _externInteract.generateTimeKeyframe(); + timestamps times = { + kf._timestamp, + kf._timestamp - _timestampRecordStarted, + global::timeManager.time().j2000Seconds() + }; if (_recordingDataMode == RecordedDataMode::Binary) { - _bufferIndex = 0; - _keyframeBuffer[_bufferIndex++] = 't'; - writeToFileBuffer(_keyframeBuffer, _bufferIndex, kf._timestamp); - writeToFileBuffer(_keyframeBuffer, _bufferIndex, kf._timestamp - - _timestampRecordStarted); - writeToFileBuffer(_keyframeBuffer, _bufferIndex, kf._time); - writeToFileBuffer(_keyframeBuffer, _bufferIndex, kf._dt); - writeToFileBuffer(_keyframeBuffer, _bufferIndex, kf._paused); - writeToFileBuffer(_keyframeBuffer, _bufferIndex, kf._requiresTimeJump); - - saveKeyframeToFileBinary(_keyframeBuffer, _bufferIndex, _recordFile); + saveTimeKeyframeBinary(times, kf, _keyframeBuffer, _bufferIndex, _recordFile); } else { - std::stringstream keyframeLine = std::stringstream(); - //Add simulation timestamp, timestamp relative, simulation time to recording start - keyframeLine << "time "; - keyframeLine << kf._timestamp << ' '; - keyframeLine << (kf._timestamp - _timestampRecordStarted) << ' '; - - keyframeLine << std::fixed << std::setprecision(3) << kf._time; - - keyframeLine << ' ' << kf._dt; - if (kf._paused) { - keyframeLine << " P"; - } - else { - keyframeLine << " R"; - } - if (kf._requiresTimeJump) { - keyframeLine << " J"; - } - else { - keyframeLine << " -"; - } - saveKeyframeToFile(keyframeLine.str(), _recordFile); + saveTimeKeyframeAscii(times, kf, _recordFile); } } +static void SessionRecording::saveTimeKeyframeBinary(timestamps times, + datamessagestructures::TimeKeyframe& kf, + unsigned char* kfBuffer, + size_t& idx, + std::ofstream& file) +{ + idx = 0; + kfBuffer[idx++] = 't'; + writeToFileBuffer(kfBuffer, idx, times.timeOs); + writeToFileBuffer(kfBuffer, idx, times.timeRec); + writeToFileBuffer(kfBuffer, idx, times.timeSim); + std::vector writeBuffer; + kf.serialize(writeBuffer); + writeToFileBuffer(kfBuffer, idx, writeBuffer); + + saveKeyframeToFileBinary(kfBuffer, idx, file); +} + +static void SessionRecording::saveTimeKeyframeAscii(timestamps times, + datamessagestructures::CameraKeyframe& kf, + std::ofstream& file) +{ + std::stringstream keyframeLine = std::stringstream(); + //Add simulation timestamp, timestamp relative, simulation time to recording start + keyframeLine << "time "; + keyframeLine << times.timeOs << ' '; + keyframeLine << times.timeRec << ' '; + keyframeLine << std::fixed << std::setprecision(3) << times.timeSim << ' '; + + keyframeLine << ' ' << kf._dt; + if (kf._paused) { + keyframeLine << " P"; + } + else { + keyframeLine << " R"; + } + if (kf._requiresTimeJump) { + keyframeLine << " J"; + } + else { + keyframeLine << " -"; + } + saveKeyframeToFile(keyframeLine.str(), _recordFile); +} + void SessionRecording::saveScriptKeyframe(std::string scriptToSave) { if (_state != SessionState::Recording) { return; From 37924c273464acdb1f9b19da27e7cb5e037ec9d4 Mon Sep 17 00:00:00 2001 From: GPayne Date: Tue, 29 Oct 2019 19:23:34 -0600 Subject: [PATCH 11/26] Finished separating script messages into separate read & parse steps --- .../openspace/interaction/sessionrecording.h | 34 +++- include/openspace/network/messagestructures.h | 59 ++++++ src/interaction/sessionrecording.cpp | 172 ++++++++---------- 3 files changed, 166 insertions(+), 99 deletions(-) diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index a584dd56c6..a9dc5852c1 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -302,11 +302,10 @@ public: * \param times reference to a timestamps structure which contains recorded times * \param kf reference to a camera keyframe which contains the camera details * \param kfBuffer a buffer temporarily used for preparing data to be written - * \param idx index into the temporary buffer * \param file an ofstream reference to the recording file being written-to */ static void SessionRecording::saveCameraKeyframeBinary(timestamps times, - datamessagestructures::CameraKeyframe& kf, unsigned char* kfBuffer, size_t& idx, + datamessagestructures::CameraKeyframe& kf, unsigned char* kfBuffer, std::ofstream& file); /** @@ -325,11 +324,10 @@ public: * \param times reference to a timestamps structure which contains recorded times * \param kf reference to a time keyframe which contains the time details * \param kfBuffer a buffer temporarily used for preparing data to be written - * \param idx index into the temporary buffer * \param file an ofstream reference to the recording file being written-to */ static void SessionRecording::saveTimeKeyframeBinary(timestamps times, - datamessagestructures::TimeKeyframe& kf, unsigned char* kfBuffer, size_t& idx, + datamessagestructures::TimeKeyframe& kf, unsigned char* kfBuffer, std::ofstream& file); /** @@ -342,6 +340,28 @@ public: static void SessionRecording::saveTimeKeyframeAscii(timestamps times, datamessagestructures::TimeKeyframe& kf, std::ofstream& file); + /** + * Writes a script keyframe to a binary format recording file using a ScriptMessage + * + * \param times reference to a timestamps structure which contains recorded times + * \param sm reference to a ScriptMessage object which contains the script details + * \param smBuffer a buffer temporarily used for preparing data to be written + * \param file an ofstream reference to the recording file being written-to + */ + static void SessionRecording::saveScriptKeyframeBinary(timestamps times, + datamessagestructures::ScriptMessage& sm, unsigned char* smBuffer, + std::string& script, std::ofstream& file); + + /** + * Writes a script keyframe to an ascii format recording file using a ScriptMessage + * + * \param times reference to a timestamps structure which contains recorded times + * \param sm reference to a ScriptMessage which contains the script details + * \param file an ofstream reference to the recording file being written-to + */ + static void SessionRecording::saveScriptKeyframeAscii(timestamps times, + datamessagestructures::ScriptMessage& sm, std::ofstream& file); + private: enum class RecordedType { Camera = 0, @@ -403,6 +423,11 @@ private: static void writeToFileBuffer(unsigned char* buf, size_t& idx, unsigned char c); static void writeToFileBuffer(unsigned char* buf, size_t& idx, bool b); + static void SessionRecording::saveHeaderBinary(timestamps times, char type, + unsigned char* kfBuffer, size_t& idx); + static void SessionRecording::saveHeaderAscii(timestamps times, std::string& type, + std::stringstream& line); + RecordedDataMode _recordingDataMode = RecordedDataMode::Binary; SessionState _state = SessionState::Idle; SessionState _lastState = SessionState::Idle; @@ -430,7 +455,6 @@ private: + saveBufferCameraSize_min + saveBufferStringSize_max; unsigned char _keyframeBuffer[_saveBufferMaxSize_bytes]; - size_t _bufferIndex = 0; bool _cleanupNeeded = false; diff --git a/include/openspace/network/messagestructures.h b/include/openspace/network/messagestructures.h index 8b9d72cc64..d68b0b6ab3 100644 --- a/include/openspace/network/messagestructures.h +++ b/include/openspace/network/messagestructures.h @@ -188,6 +188,26 @@ struct CameraKeyframe { ); }; + void write(std::stringstream& out) const { + // Add camera position + out << std::fixed << std::setprecision(7) << _position.x << ' ' + << std::fixed << std::setprecision(7) << _position.y << ' ' + << std::fixed << std::setprecision(7) << _position.z << ' '; + // Add camera rotation + out << std::fixed << std::setprecision(7) << _rotation.x << ' ' + << std::fixed << std::setprecision(7) << _rotation.y << ' ' + << std::fixed << std::setprecision(7) << _rotation.z << ' ' + << std::fixed << std::setprecision(7) << _rotation.w << ' '; + out << std::scientific << _scale << ' '; + if (_followNodeRotation) { + out << "F "; + } + else { + out << "- "; + } + out << _focusNode; + }; + void read(std::istream* in) { // Read position in->read( @@ -284,6 +304,22 @@ struct TimeKeyframe { ); }; + void write(std::stringstream out) const { + out << ' ' << _dt; + if (_paused) { + out << " P"; + } + else { + out << " R"; + } + if (_requiresTimeJump) { + out << " J"; + } + else { + out << " -"; + } + }; + void read(std::istream* in) { in->read( reinterpret_cast(this), @@ -402,6 +438,29 @@ struct ScriptMessage { out->write(_script.c_str(), _script.size()); }; + void write(unsigned char* buf, size_t& idx, std::ofstream& file) const { + size_t strLen = _script.size(); + size_t writeSize_bytes = sizeof(size_t); + + unsigned char const *p = reinterpret_cast(&strLen); + memcpy((buf + idx), p, writeSize_bytes); + idx += static_cast(writeSize_bytes); + + memcpy((buf + idx), _script.c_str(), _script.size()); + idx += static_cast(strLen); + file.write(reinterpret_cast(buf), idx); + //Write directly to file because some scripts can be very long + file.write(_script.c_str(), _script.size()); + }; + + void write(std::stringstream& ss) const { + unsigned int numLinesInScript = static_cast( + std::count(_script.begin(), _script.end(), '\n') + ); + ss << ' ' << (numLinesInScript + 1) << ' '; + ss << _script; + } + void read(std::istream* in) { size_t strLen; //Read string length from file diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index 7547c834a9..93e54dc8f6 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -421,17 +421,21 @@ static void SessionRecording::writeToFileBuffer(unsigned char* buf, idx += sizeof(char); } -void SessionRecording::saveStringToFile(const std::string& s) { +void SessionRecording::saveStringToFile(const std::string& s, + unsigned char* kfBuffer, + size_t& idx, + std::ofstream& file) +{ size_t strLen = s.size(); size_t writeSize_bytes = sizeof(size_t); - _bufferIndex = 0; + idx = 0; unsigned char const *p = reinterpret_cast(&strLen); - memcpy((_keyframeBuffer + _bufferIndex), p, writeSize_bytes); - _bufferIndex += static_cast(writeSize_bytes); - saveKeyframeToFileBinary(_keyframeBuffer, _bufferIndex, _recordFile); + memcpy((kfBuffer + idx), p, writeSize_bytes); + idx += static_cast(writeSize_bytes); + saveKeyframeToFileBinary(kfBuffer, idx, file); - _recordFile.write(s.c_str(), s.size()); + file.write(s.c_str(), s.size()); } bool SessionRecording::hasCameraChangedFromPrev( @@ -474,31 +478,46 @@ void SessionRecording::saveCameraKeyframe() { global::timeManager.time().j2000Seconds() }; if (_recordingDataMode == RecordedDataMode::Binary) { - saveCameraKeyframeBinary(times, kf, _keyframeBuffer, _bufferIndex, _recordFile); + saveCameraKeyframeBinary(times, kf, _keyframeBuffer, _recordFile); } else { saveCameraKeyframeAscii(times, kf, _recordFile); } } -static void SessionRecording::saveCameraKeyframeBinary(timestamps times, - datamessagestructures::CameraKeyframe& kf, - unsigned char* kfBuffer, - size_t& idx, - std::ofstream& file) +static void SessionRecording::saveHeaderBinary(timestamps times, + char type, + unsigned char* kfBuffer, + size_t& idx) { - // Writing to a binary session recording file - idx = 0; - kfBuffer[idx++] = 'c'; - - // Writing to internal buffer, and then to file, for performance reasons + kfBuffer[idx++] = type; writeToFileBuffer(kfBuffer, idx, times.timeOs); writeToFileBuffer(kfBuffer, idx, times.timeRec); writeToFileBuffer(kfBuffer, idx, times.timeSim); +} + +static void SessionRecording::saveHeaderAscii(timestamps times, + std::string& type, + std::stringstream& line) +{ + line << type << ' '; + line << times.timeOs << ' '; + line << times.timeRec << ' '; + line << std::fixed << std::setprecision(3) << times.timeSim << ' '; +} + +static void SessionRecording::saveCameraKeyframeBinary(timestamps times, + datamessagestructures::CameraKeyframe& kf, + unsigned char* kfBuffer, + std::ofstream& file) +{ + // Writing to a binary session recording file + size_t idx = 0; + saveHeaderBinary(times, 'c', kfBuffer, idx); + // Writing to internal buffer, and then to file, for performance reasons std::vector writeBuffer; kf.serialize(writeBuffer); writeToFileBuffer(kfBuffer, idx, writeBuffer); - saveKeyframeToFileBinary(kfBuffer, idx, file); } @@ -507,31 +526,8 @@ static void SessionRecording::saveCameraKeyframeAscii(timestamps times, std::ofstream& file) { std::stringstream keyframeLine = std::stringstream(); - // Add simulation timestamp, timestamp relative, simulation time to recording start - keyframeLine << "camera "; - keyframeLine << times.timeOs << ' '; - keyframeLine << times.timeRec << ' '; - keyframeLine << std::fixed << std::setprecision(3) << times.timeSim << ' '; - // Add camera position - keyframeLine - << std::fixed << std::setprecision(7) << kf._position.x << ' ' - << std::fixed << std::setprecision(7) << kf._position.y << ' ' - << std::fixed << std::setprecision(7) << kf._position.z << ' '; - // Add camera rotation - keyframeLine - << std::fixed << std::setprecision(7) << kf._rotation.x << ' ' - << std::fixed << std::setprecision(7) << kf._rotation.y << ' ' - << std::fixed << std::setprecision(7) << kf._rotation.z << ' ' - << std::fixed << std::setprecision(7) << kf._rotation.w << ' '; - keyframeLine << std::scientific << kf._scale << ' '; - if (kf._followNodeRotation) { - keyframeLine << "F "; - } - else { - keyframeLine << "- "; - } - keyframeLine << kf._focusNode; - + saveHeaderAscii(times, "camera", keyframeLine); + kf.write(keyframeLine); saveKeyframeToFile(keyframeLine.str(), file); } @@ -549,7 +545,7 @@ void SessionRecording::saveTimeKeyframe() { global::timeManager.time().j2000Seconds() }; if (_recordingDataMode == RecordedDataMode::Binary) { - saveTimeKeyframeBinary(times, kf, _keyframeBuffer, _bufferIndex, _recordFile); + saveTimeKeyframeBinary(times, kf, _keyframeBuffer, _recordFile); } else { saveTimeKeyframeAscii(times, kf, _recordFile); } @@ -558,18 +554,13 @@ void SessionRecording::saveTimeKeyframe() { static void SessionRecording::saveTimeKeyframeBinary(timestamps times, datamessagestructures::TimeKeyframe& kf, unsigned char* kfBuffer, - size_t& idx, std::ofstream& file) { - idx = 0; - kfBuffer[idx++] = 't'; - writeToFileBuffer(kfBuffer, idx, times.timeOs); - writeToFileBuffer(kfBuffer, idx, times.timeRec); - writeToFileBuffer(kfBuffer, idx, times.timeSim); + size_t idx = 0; + saveHeaderBinary(times, 't', kfBuffer, idx); std::vector writeBuffer; kf.serialize(writeBuffer); writeToFileBuffer(kfBuffer, idx, writeBuffer); - saveKeyframeToFileBinary(kfBuffer, idx, file); } @@ -578,25 +569,8 @@ static void SessionRecording::saveTimeKeyframeAscii(timestamps times, std::ofstream& file) { std::stringstream keyframeLine = std::stringstream(); - //Add simulation timestamp, timestamp relative, simulation time to recording start - keyframeLine << "time "; - keyframeLine << times.timeOs << ' '; - keyframeLine << times.timeRec << ' '; - keyframeLine << std::fixed << std::setprecision(3) << times.timeSim << ' '; - - keyframeLine << ' ' << kf._dt; - if (kf._paused) { - keyframeLine << " P"; - } - else { - keyframeLine << " R"; - } - if (kf._requiresTimeJump) { - keyframeLine << " J"; - } - else { - keyframeLine << " -"; - } + saveHeaderAscii(times, "time", keyframeLine); + kf.write(keyframeLine); saveKeyframeToFile(keyframeLine.str(), _recordFile); } @@ -608,36 +582,46 @@ void SessionRecording::saveScriptKeyframe(std::string scriptToSave) { datamessagestructures::ScriptMessage sm = _externInteract.generateScriptMessage(scriptToSave); - if (_recordingDataMode == RecordedDataMode::Binary) { - _bufferIndex = 0; - _keyframeBuffer[_bufferIndex++] = 's'; - writeToFileBuffer(_keyframeBuffer, _bufferIndex, sm._timestamp); - writeToFileBuffer(_keyframeBuffer, _bufferIndex, sm._timestamp - _timestampRecordStarted); - writeToFileBuffer(_keyframeBuffer, _bufferIndex, global::timeManager.time().j2000Seconds()); - //Write header to file - saveKeyframeToFileBinary(_keyframeBuffer, _bufferIndex, _recordFile); + timestamps times = { + sm._timestamp, + sm._timestamp - _timestampRecordStarted, + global::timeManager.time().j2000Seconds() + }; - saveStringToFile(scriptToSave); + if (_recordingDataMode == RecordedDataMode::Binary) { + saveScriptKeyframeBinary(times, sm, _keyframeBuffer, scriptToSave, + _recordFile); } else { - unsigned int numLinesInScript = static_cast( - std::count(scriptToSave.begin(), scriptToSave.end(), '\n') - ); - std::stringstream keyframeLine = std::stringstream(); - //Add simulation timestamp, timestamp relative, simulation time to recording start - keyframeLine << "script "; - keyframeLine << sm._timestamp << ' '; - keyframeLine << (sm._timestamp - _timestampRecordStarted) << ' '; - keyframeLine << std::fixed << std::setprecision(3) << - global::timeManager.time().j2000Seconds(); - keyframeLine << ' '; - keyframeLine << (numLinesInScript + 1) << ' '; - keyframeLine << scriptToSave; - - saveKeyframeToFile(keyframeLine.str(), _recordFile); + saveScriptKeyframeAscii(times, sm, _recordFile); } } +static void SessionRecording::saveScriptKeyframeBinary(timestamps times, + datamessagestructures::ScriptMessage& sm, + unsigned char* smBuffer, + std::string& script, + std::ofstream& file) +{ + size_t idx = 0; + saveHeaderBinary(times, 's', smBuffer, idx); + //Write script header to file + saveKeyframeToFileBinary(smBuffer, idx, file); + //Write script data to file + sm.write(smBuffer, idx, file); +} + +static void SessionRecording::saveScriptKeyframeAscii(timestamps times, + datamessagestructures::ScriptMessage& sm, + std::ofstream& file) +{ + + std::stringstream keyframeLine = std::stringstream(); + saveHeaderAscii(times, "script", keyframeLine); + sm.write(keyframeLine); + saveKeyframeToFile(keyframeLine.str(), _recordFile); +} + void SessionRecording::preSynchronization() { if (_state == SessionState::Recording) { saveCameraKeyframe(); From 88135c1db00873440984c84c6bd83e3a5c92085d Mon Sep 17 00:00:00 2001 From: GPayne Date: Thu, 31 Oct 2019 14:48:26 -0600 Subject: [PATCH 12/26] Fixed compile issues, now needs testing --- .../openspace/interaction/keyframenavigator.h | 10 +- .../openspace/interaction/sessionrecording.h | 43 ++--- include/openspace/network/messagestructures.h | 15 +- src/interaction/sessionrecording.cpp | 178 ++++++++---------- 4 files changed, 119 insertions(+), 127 deletions(-) diff --git a/include/openspace/interaction/keyframenavigator.h b/include/openspace/interaction/keyframenavigator.h index 77783d6bd4..50fae1d9eb 100644 --- a/include/openspace/interaction/keyframenavigator.h +++ b/include/openspace/interaction/keyframenavigator.h @@ -55,13 +55,21 @@ public: float scale; bool followFocusNodeRotation; + CameraPose() { + position = {0., 0., 0.}; + rotation = {0., 0., 0., 0.}; + focusNode = ""; + scale = 1.0; + followFocusNodeRotation = false; + }; + CameraPose(const openspace::datamessagestructures::CameraKeyframe& kf) { position = kf._position; rotation = kf._rotation; focusNode = kf._focusNode; scale = kf._scale; followFocusNodeRotation = kf._followNodeRotation; - } + }; }; /** diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index a9dc5852c1..46441feead 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -52,12 +52,12 @@ public: }; const std::string FileHeaderTitle = "OpenSpace_record/playback"; - constexpr const size_t FileHeaderVersionLength = 5; - constexpr const char FileHeaderVersion[FileHeaderVersionLength] = { + static const size_t FileHeaderVersionLength = 5; + const char FileHeaderVersion[FileHeaderVersionLength] = { '0', '0', '.', '8', '5' }; - constexpr const char DataFormatAsciiTag = 'A'; - constexpr const char DataFormatBinaryTag = 'B'; + const char DataFormatAsciiTag = 'A'; + const char DataFormatBinaryTag = 'B'; using CallbackHandle = int; using StateChangeCallback = std::function; @@ -255,7 +255,7 @@ public: * \param file an ifstream reference to the playback file being read * \param lineN keyframe number in playback file where this keyframe resides */ - static void SessionRecording::readTimeKeyframeBinary(timestamps& times, + static void readTimeKeyframeBinary(timestamps& times, datamessagestructures::TimeKeyframe& kf, std::ifstream& file, int lineN); /** @@ -267,7 +267,7 @@ public: * \param filenameRead a string containing the playback filename * \param lineN line number in playback file where this keyframe resides */ - static void SessionRecording::readTimeKeyframeAscii(timestamps& times, + static void readTimeKeyframeAscii(timestamps& times, datamessagestructures::TimeKeyframe& kf, std::string filenameRead, int lineN); /** @@ -280,7 +280,7 @@ public: * \param file an ifstream reference to the playback file being read * \param lineN keyframe number in playback file where this keyframe resides */ - static void SessionRecording::readScriptKeyframeBinary(timestamps& times, + static void readScriptKeyframeBinary(timestamps& times, datamessagestructures::ScriptMessage& kf, std::ifstream& file, int lineN); /** @@ -293,7 +293,7 @@ public: * \param filenameRead a string containing the playback filename * \param lineN line number in playback file where this keyframe resides */ - static void SessionRecording::readScriptKeyframeAscii(timestamps& times, + static void readScriptKeyframeAscii(timestamps& times, datamessagestructures::ScriptMessage& kf, std::string filenameRead, int lineN); /** @@ -304,7 +304,7 @@ public: * \param kfBuffer a buffer temporarily used for preparing data to be written * \param file an ofstream reference to the recording file being written-to */ - static void SessionRecording::saveCameraKeyframeBinary(timestamps times, + static void saveCameraKeyframeBinary(timestamps times, datamessagestructures::CameraKeyframe& kf, unsigned char* kfBuffer, std::ofstream& file); @@ -315,7 +315,7 @@ public: * \param kf reference to a camera keyframe which contains the camera details * \param file an ofstream reference to the recording file being written-to */ - static void SessionRecording::saveCameraKeyframeAscii(timestamps times, + static void saveCameraKeyframeAscii(timestamps times, datamessagestructures::CameraKeyframe& kf, std::ofstream& file); /** @@ -326,7 +326,7 @@ public: * \param kfBuffer a buffer temporarily used for preparing data to be written * \param file an ofstream reference to the recording file being written-to */ - static void SessionRecording::saveTimeKeyframeBinary(timestamps times, + static void saveTimeKeyframeBinary(timestamps times, datamessagestructures::TimeKeyframe& kf, unsigned char* kfBuffer, std::ofstream& file); @@ -337,7 +337,7 @@ public: * \param kf reference to a time keyframe which contains the time details * \param file an ofstream reference to the recording file being written-to */ - static void SessionRecording::saveTimeKeyframeAscii(timestamps times, + static void saveTimeKeyframeAscii(timestamps times, datamessagestructures::TimeKeyframe& kf, std::ofstream& file); /** @@ -348,9 +348,9 @@ public: * \param smBuffer a buffer temporarily used for preparing data to be written * \param file an ofstream reference to the recording file being written-to */ - static void SessionRecording::saveScriptKeyframeBinary(timestamps times, + static void saveScriptKeyframeBinary(timestamps times, datamessagestructures::ScriptMessage& sm, unsigned char* smBuffer, - std::string& script, std::ofstream& file); + std::ofstream& file); /** * Writes a script keyframe to an ascii format recording file using a ScriptMessage @@ -359,7 +359,7 @@ public: * \param sm reference to a ScriptMessage which contains the script details * \param file an ofstream reference to the recording file being written-to */ - static void SessionRecording::saveScriptKeyframeAscii(timestamps times, + static void saveScriptKeyframeAscii(timestamps times, datamessagestructures::ScriptMessage& sm, std::ofstream& file); private: @@ -389,11 +389,12 @@ private: void playbackScript(); bool playbackAddEntriesToTimeline(); void signalPlaybackFinishedForComponent(RecordedType type); - void saveStringToFile(const std::string& s); - void saveKeyframeToFileBinary(unsigned char* bufferSource, size_t size, - std::ofstream& file); void findFirstCameraKeyframeInTimeline(); - void saveKeyframeToFile(std::string entry, std::ofstream& file); + static void saveStringToFile(const std::string& s, unsigned char* kfBuffer, size_t& idx, + std::ofstream& file); + static void saveKeyframeToFileBinary(unsigned char* bufferSource, size_t size, + std::ofstream& file); + static void saveKeyframeToFile(std::string entry, std::ofstream& file); void addKeyframe(double timestamp, interaction::KeyframeNavigator::CameraPose keyframe); @@ -423,9 +424,9 @@ private: static void writeToFileBuffer(unsigned char* buf, size_t& idx, unsigned char c); static void writeToFileBuffer(unsigned char* buf, size_t& idx, bool b); - static void SessionRecording::saveHeaderBinary(timestamps times, char type, + static void saveHeaderBinary(timestamps times, char type, unsigned char* kfBuffer, size_t& idx); - static void SessionRecording::saveHeaderAscii(timestamps times, std::string& type, + static void saveHeaderAscii(timestamps times, const std::string& type, std::stringstream& line); RecordedDataMode _recordingDataMode = RecordedDataMode::Binary; diff --git a/include/openspace/network/messagestructures.h b/include/openspace/network/messagestructures.h index d68b0b6ab3..4f1bf0c4a8 100644 --- a/include/openspace/network/messagestructures.h +++ b/include/openspace/network/messagestructures.h @@ -30,6 +30,8 @@ #include #include #include +#include +#include namespace openspace::datamessagestructures { @@ -254,7 +256,7 @@ struct CameraKeyframe { ); }; - void read(std::istringstream* iss) { + void read(std::istringstream& iss) { std::string rotationFollowing; iss >> _position.x @@ -304,7 +306,7 @@ struct TimeKeyframe { ); }; - void write(std::stringstream out) const { + void write(std::stringstream& out) const { out << ' ' << _dt; if (_paused) { out << " P"; @@ -327,7 +329,7 @@ struct TimeKeyframe { ); }; - void read(std::istringstream* iss) { + void read(std::istringstream& iss) { std::string paused, jump; iss >> _dt @@ -474,12 +476,15 @@ struct ScriptMessage { _script = temp.data(); }; - void read(std::istringstream* iss) { + void read(std::istringstream& iss) { int numScriptLines; iss >> numScriptLines; + if (numScriptLines < 0) { + numScriptLines = 0; + } std::string tmpReadbackScript; _script.erase(); - for (unsigned int i = 0; i < numScriptLines; ++i) { + for (int i = 0; i < numScriptLines; ++i) { std::getline(iss, tmpReadbackScript); _script.append(tmpReadbackScript); if (i < (numScriptLines - 1)) { diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index 93e54dc8f6..96b437a00f 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -54,30 +54,6 @@ namespace { return res; } - template <> - bool readFromPlayback(std::ifstream& stream) { - unsigned char b; - stream.read(reinterpret_cast(&b), sizeof(unsigned char)); - if (b == 0) { - return false; - } - else { - return true; - } - } - - template <> - std::string readFromPlayback(std::ifstream& stream) { - size_t strLen; - // Read string length from file - stream.read(reinterpret_cast(&strLen), sizeof(strLen)); - // Read back full string - std::vector temp(strLen + 1); - stream.read(temp.data(), strLen); - temp[strLen] = '\0'; - return temp.data(); - } - std::string readHeaderElement(std::ifstream& stream, size_t readLen_chars) { std::vector readTemp(readLen_chars); stream.read(&readTemp[0], readLen_chars); @@ -183,7 +159,8 @@ void SessionRecording::stopRecording() { } bool SessionRecording::startPlayback(const std::string& filename, - KeyframeTimeRef timeMode, bool forceSimTimeAtStart) + KeyframeTimeRef timeMode, + bool forceSimTimeAtStart) { if (filename.find("/") != std::string::npos) { LERROR("Playback filename must not contain path (/) elements"); @@ -385,9 +362,9 @@ void SessionRecording::cleanUpPlayback() { _cleanupNeeded = false; } -static void SessionRecording::writeToFileBuffer(unsigned char* buf, - size_t& idx, - double src) +void SessionRecording::writeToFileBuffer(unsigned char* buf, + size_t& idx, + double src) { const size_t writeSize_bytes = sizeof(double); unsigned char const *p = reinterpret_cast(&src); @@ -395,27 +372,27 @@ static void SessionRecording::writeToFileBuffer(unsigned char* buf, idx += writeSize_bytes; } -static void SessionRecording::writeToFileBuffer(unsigned char* buf, - size_t& idx, - std::vector& cv) +void SessionRecording::writeToFileBuffer(unsigned char* buf, + size_t& idx, + std::vector& cv) { const size_t writeSize_bytes = cv.size() * sizeof(char); memcpy((buf + idx), cv.data(), writeSize_bytes); idx += writeSize_bytes; } -static void SessionRecording::writeToFileBuffer(unsigned char* buf, - size_t& idx, - unsigned char c) +void SessionRecording::writeToFileBuffer(unsigned char* buf, + size_t& idx, + unsigned char c) { const size_t writeSize_bytes = sizeof(char); buf[idx] = c; idx += writeSize_bytes; } -static void SessionRecording::writeToFileBuffer(unsigned char* buf, - size_t& idx, - bool b) +void SessionRecording::writeToFileBuffer(unsigned char* buf, + size_t& idx, + bool b) { buf[idx] = b ? 1 : 0; idx += sizeof(char); @@ -439,7 +416,7 @@ void SessionRecording::saveStringToFile(const std::string& s, } bool SessionRecording::hasCameraChangedFromPrev( - datamessagestructures::CameraKeyframe kfNew) + datamessagestructures::CameraKeyframe kfNew) { constexpr const double threshold = 1e-2; bool hasChanged = false; @@ -485,10 +462,10 @@ void SessionRecording::saveCameraKeyframe() { } } -static void SessionRecording::saveHeaderBinary(timestamps times, - char type, - unsigned char* kfBuffer, - size_t& idx) +void SessionRecording::saveHeaderBinary(timestamps times, + char type, + unsigned char* kfBuffer, + size_t& idx) { kfBuffer[idx++] = type; writeToFileBuffer(kfBuffer, idx, times.timeOs); @@ -496,9 +473,9 @@ static void SessionRecording::saveHeaderBinary(timestamps times, writeToFileBuffer(kfBuffer, idx, times.timeSim); } -static void SessionRecording::saveHeaderAscii(timestamps times, - std::string& type, - std::stringstream& line) +void SessionRecording::saveHeaderAscii(timestamps times, + const std::string& type, + std::stringstream& line) { line << type << ' '; line << times.timeOs << ' '; @@ -506,10 +483,10 @@ static void SessionRecording::saveHeaderAscii(timestamps times, line << std::fixed << std::setprecision(3) << times.timeSim << ' '; } -static void SessionRecording::saveCameraKeyframeBinary(timestamps times, - datamessagestructures::CameraKeyframe& kf, - unsigned char* kfBuffer, - std::ofstream& file) +void SessionRecording::saveCameraKeyframeBinary(timestamps times, + datamessagestructures::CameraKeyframe& kf, + unsigned char* kfBuffer, + std::ofstream& file) { // Writing to a binary session recording file size_t idx = 0; @@ -521,9 +498,9 @@ static void SessionRecording::saveCameraKeyframeBinary(timestamps times, saveKeyframeToFileBinary(kfBuffer, idx, file); } -static void SessionRecording::saveCameraKeyframeAscii(timestamps times, +void SessionRecording::saveCameraKeyframeAscii(timestamps times, datamessagestructures::CameraKeyframe& kf, - std::ofstream& file) + std::ofstream& file) { std::stringstream keyframeLine = std::stringstream(); saveHeaderAscii(times, "camera", keyframeLine); @@ -551,10 +528,10 @@ void SessionRecording::saveTimeKeyframe() { } } -static void SessionRecording::saveTimeKeyframeBinary(timestamps times, - datamessagestructures::TimeKeyframe& kf, - unsigned char* kfBuffer, - std::ofstream& file) +void SessionRecording::saveTimeKeyframeBinary(timestamps times, + datamessagestructures::TimeKeyframe& kf, + unsigned char* kfBuffer, + std::ofstream& file) { size_t idx = 0; saveHeaderBinary(times, 't', kfBuffer, idx); @@ -564,14 +541,14 @@ static void SessionRecording::saveTimeKeyframeBinary(timestamps times, saveKeyframeToFileBinary(kfBuffer, idx, file); } -static void SessionRecording::saveTimeKeyframeAscii(timestamps times, - datamessagestructures::CameraKeyframe& kf, - std::ofstream& file) +void SessionRecording::saveTimeKeyframeAscii(timestamps times, + datamessagestructures::TimeKeyframe& kf, + std::ofstream& file) { std::stringstream keyframeLine = std::stringstream(); saveHeaderAscii(times, "time", keyframeLine); kf.write(keyframeLine); - saveKeyframeToFile(keyframeLine.str(), _recordFile); + saveKeyframeToFile(keyframeLine.str(), file); } void SessionRecording::saveScriptKeyframe(std::string scriptToSave) { @@ -589,19 +566,17 @@ void SessionRecording::saveScriptKeyframe(std::string scriptToSave) { }; if (_recordingDataMode == RecordedDataMode::Binary) { - saveScriptKeyframeBinary(times, sm, _keyframeBuffer, scriptToSave, - _recordFile); + saveScriptKeyframeBinary(times, sm, _keyframeBuffer, _recordFile); } else { saveScriptKeyframeAscii(times, sm, _recordFile); } } -static void SessionRecording::saveScriptKeyframeBinary(timestamps times, - datamessagestructures::ScriptMessage& sm, - unsigned char* smBuffer, - std::string& script, - std::ofstream& file) +void SessionRecording::saveScriptKeyframeBinary(timestamps times, + datamessagestructures::ScriptMessage& sm, + unsigned char* smBuffer, + std::ofstream& file) { size_t idx = 0; saveHeaderBinary(times, 's', smBuffer, idx); @@ -611,15 +586,15 @@ static void SessionRecording::saveScriptKeyframeBinary(timestamps times, sm.write(smBuffer, idx, file); } -static void SessionRecording::saveScriptKeyframeAscii(timestamps times, - datamessagestructures::ScriptMessage& sm, - std::ofstream& file) +void SessionRecording::saveScriptKeyframeAscii(timestamps times, + datamessagestructures::ScriptMessage& sm, + std::ofstream& file) { std::stringstream keyframeLine = std::stringstream(); saveHeaderAscii(times, "script", keyframeLine); sm.write(keyframeLine); - saveKeyframeToFile(keyframeLine.str(), _recordFile); + saveKeyframeToFile(keyframeLine.str(), file); } void SessionRecording::preSynchronization() { @@ -743,7 +718,8 @@ bool SessionRecording::playbackAddEntriesToTimeline() { return !parsingErrorsFound; } -double SessionRecording::appropriateTimestamp(double timeOs, double timeRec, +double SessionRecording::appropriateTimestamp(double timeOs, + double timeRec, double timeSim) { if (_playbackTimeReferenceMode == KeyframeTimeRef::Relative_recordedStart) { @@ -757,7 +733,8 @@ double SessionRecording::appropriateTimestamp(double timeOs, double timeRec, } } -double SessionRecording::equivalentSimulationTime(double timeOs, double timeRec, +double SessionRecording::equivalentSimulationTime(double timeOs, + double timeRec, double timeSim) { if (_playbackTimeReferenceMode == KeyframeTimeRef::Relative_recordedStart) { @@ -771,7 +748,8 @@ double SessionRecording::equivalentSimulationTime(double timeOs, double timeRec, } } -double SessionRecording::equivalentApplicationTime(double timeOs, double timeRec, +double SessionRecording::equivalentApplicationTime(double timeOs, + double timeRec, double timeSim) { if (_playbackTimeReferenceMode == KeyframeTimeRef::Relative_recordedStart) { @@ -837,9 +815,9 @@ void SessionRecording::playbackCamera() { addKeyframe(timeRef, pbFrame); } -static void SessionRecording::readCameraKeyframeBinary(timestamps& times, - datamessagestructures::CameraKeyframe& kf, - std::ifstream& file, int lineN) +void SessionRecording::readCameraKeyframeBinary(timestamps& times, + datamessagestructures::CameraKeyframe& kf, + std::ifstream& file, int lineN) { times.timeOs = readFromPlayback(file); times.timeRec = readFromPlayback(file); @@ -872,10 +850,10 @@ static void SessionRecording::readCameraKeyframeBinary(timestamps& times, } } -static void SessionRecording::readCameraKeyframeAscii(timestamps& times, - datamessagestructures::CameraKeyframe& kf, - std::string filenameRead, - int lineN) +void SessionRecording::readCameraKeyframeAscii(timestamps& times, + datamessagestructures::CameraKeyframe& kf, + std::string filenameRead, + int lineN) { std::string rotationFollowing; std::string entryType; @@ -883,7 +861,7 @@ static void SessionRecording::readCameraKeyframeAscii(timestamps& times, std::istringstream iss(filenameRead); iss >> entryType; iss >> times.timeOs >> times.timeRec >> times.timeSim; - kf.read(&iss); + kf.read(iss); if (iss.fail() || !iss.eof()) { LERROR(fmt::format("Error parsing camera line {} of playback file", lineN)); @@ -908,9 +886,9 @@ void SessionRecording::playbackTimeChange() { addKeyframe(kf._timestamp, kf); } -static void SessionRecording::readTimeKeyframeBinary(timestamps& times, - datamessagestructures::TimeKeyframe& kf, - std::ifstream& file, int lineN) +void SessionRecording::readTimeKeyframeBinary(timestamps& times, + datamessagestructures::TimeKeyframe& kf, + std::ifstream& file, int lineN) { times.timeOs = readFromPlayback(file); times.timeRec = readFromPlayback(file); @@ -942,21 +920,21 @@ static void SessionRecording::readTimeKeyframeBinary(timestamps& times, } } -static void SessionRecording::readTimeKeyframeAscii(timestamps& times, - datamessagestructures::TimeKeyframe& kf, - std::string filenameRead, - int lineN) +void SessionRecording::readTimeKeyframeAscii(timestamps& times, + datamessagestructures::TimeKeyframe& kf, + std::string filenameRead, + int lineN) { std::string entryType; std::istringstream iss(filenameRead); iss >> entryType; iss >> times.timeOs >> times.timeRec >> times.timeSim; - kf.read(&iss); + kf.read(iss); if (iss.fail() || !iss.eof()) { LERROR(fmt::format( - "Error parsing time line {} of playback file", _playbackLineNum + "Error parsing time line {} of playback file", lineN )); return; } @@ -976,9 +954,9 @@ void SessionRecording::playbackScript() { addKeyframe(timeRef, kf._script); } -static void SessionRecording::readScriptKeyframeBinary(timestamps& times, - datamessagestructures::ScriptMessage& kf, - std::ifstream& file, int lineN) +void SessionRecording::readScriptKeyframeBinary(timestamps& times, + datamessagestructures::ScriptMessage& kf, + std::ifstream& file, int lineN) { times.timeOs = readFromPlayback(file); times.timeRec = readFromPlayback(file); @@ -1011,24 +989,24 @@ static void SessionRecording::readScriptKeyframeBinary(timestamps& times, } } -static void SessionRecording::readScriptKeyframeAscii(timestamps& times, - datamessagestructures::ScriptMessage& kf, - std::string filenameRead, - int lineN) +void SessionRecording::readScriptKeyframeAscii(timestamps& times, + datamessagestructures::ScriptMessage& kf, + std::string filenameRead, + int lineN) { std::string entryType; std::istringstream iss(filenameRead); iss >> entryType; iss >> times.timeOs >> times.timeRec >> times.timeSim; - kf.read(&iss); + kf.read(iss); if (iss.fail()) { LERROR(fmt::format( - "Error parsing script line {} of playback file", _playbackLineNum + "Error parsing script line {} of playback file", lineN )); return; } else if (!iss.eof()) { LERROR(fmt::format( - "Did not find an EOL at line {} of playback file", _playbackLineNum + "Did not find an EOL at line {} of playback file", lineN )); return; } From 97e393b0f6b78c103f258cc0ed848db6f8ac6eea Mon Sep 17 00:00:00 2001 From: GPayne Date: Thu, 27 Feb 2020 13:35:10 -0700 Subject: [PATCH 13/26] Added task code for conversion to ascii --- .../openspace/interaction/sessionrecording.h | 9 +++ .../interaction/sessionrecording.inl | 7 ++ .../interaction/tasks/convertrecformattask.h | 13 ++- src/interaction/sessionrecording.cpp | 20 ++--- .../tasks/convertrecformattask.cpp | 80 +++++++++++++++---- 5 files changed, 99 insertions(+), 30 deletions(-) diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index 46441feead..3b3372ba56 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -362,6 +362,15 @@ public: static void saveScriptKeyframeAscii(timestamps times, datamessagestructures::ScriptMessage& sm, std::ofstream& file); + /** + * Reads header information from a session recording file + * + * \param stream reference to ifstream that contains the session recording file data + * \param readLen_chars number of characters to be read, which may be the expected + * length of the header line, or an arbitrary number of characters within it + */ + static std::string readHeaderElement(std::ifstream& stream, size_t readLen_chars); + private: enum class RecordedType { Camera = 0, diff --git a/include/openspace/interaction/sessionrecording.inl b/include/openspace/interaction/sessionrecording.inl index 0839562306..30876e95f8 100644 --- a/include/openspace/interaction/sessionrecording.inl +++ b/include/openspace/interaction/sessionrecording.inl @@ -51,4 +51,11 @@ T prevKeyframeObj(unsigned int index, const std::vector& keyframeContainer) { } } +template +T readFromPlayback(std::ifstream& stream) { + T res; + stream.read(reinterpret_cast(&res), sizeof(T)); + return res; +} + } // namespace openspace::interaction diff --git a/include/openspace/interaction/tasks/convertrecformattask.h b/include/openspace/interaction/tasks/convertrecformattask.h index 65c6aeef28..fab8dfab51 100644 --- a/include/openspace/interaction/tasks/convertrecformattask.h +++ b/include/openspace/interaction/tasks/convertrecformattask.h @@ -26,6 +26,7 @@ #define __OPENSPACE_CORE___CONVERTRECFORMATTASK___H__ #include +#include #include @@ -38,7 +39,7 @@ namespace { constexpr const char* KeyOutFilePath = "OutputFilePath"; } -namespace openspace { +namespace openspace::interaction { class ConvertRecFormatTask : public Task { public: @@ -51,19 +52,23 @@ public: std::string description() override; void perform(const Task::ProgressCallback& progressCallback) override; static documentation::Documentation documentation(); + void convert(); + SessionRecording::RecordedDataMode ConvertRecFormatTask::formatType(); private: void convertToAscii(); void convertToBinary(); - + std::string addFileSuffix(const std::string& filePath, const std::string& suffix); std::string _inFilePath; std::string _outFilePath; std::ifstream _iFile; - std::ifstream _oFile; + std::ofstream _oFile; std::string _valueFunctionLua; + + SessionRecording sr; }; -} // namespace openspace +} // namespace openspace::interaction #endif //__OPENSPACE_CORE___CONVERTRECFORMATTASK___H__ diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index 96b437a00f..c425d76b74 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -47,18 +47,6 @@ namespace { constexpr const bool UsingTimeKeyframes = false; - template - T readFromPlayback(std::ifstream& stream) { - T res; - stream.read(reinterpret_cast(&res), sizeof(T)); - return res; - } - - std::string readHeaderElement(std::ifstream& stream, size_t readLen_chars) { - std::vector readTemp(readLen_chars); - stream.read(&readTemp[0], readLen_chars); - return std::string(readTemp.begin(), readTemp.end()); - } } // namespace @@ -940,6 +928,14 @@ void SessionRecording::readTimeKeyframeAscii(timestamps& times, } } +static std::string SessionRecording::readHeaderElement(std::ifstream& stream, + size_t readLen_chars) +{ + std::vector readTemp(readLen_chars); + stream.read(&readTemp[0], readLen_chars); + return std::string(readTemp.begin(), readTemp.end()); +} + void SessionRecording::playbackScript() { timestamps times; datamessagestructures::ScriptMessage kf; diff --git a/src/interaction/tasks/convertrecformattask.cpp b/src/interaction/tasks/convertrecformattask.cpp index 1425e04e51..fbed41dd71 100644 --- a/src/interaction/tasks/convertrecformattask.cpp +++ b/src/interaction/tasks/convertrecformattask.cpp @@ -36,7 +36,7 @@ namespace { constexpr const char* _loggerCat = "ConvertRecFormatTask"; } // namespace -namespace openspace { +namespace openspace::interaction { ConvertRecFormatTask::ConvertRecFormatTask(const ghoul::Dictionary& dictionary) { openspace::documentation::testSpecificationAndThrow( @@ -68,12 +68,12 @@ void ConvertRecFormatTask::perform(const Task::ProgressCallback& progressCallbac } void ConvertRecFormatTask::convert() { - interaction::RecordedDataMode type = formatType(); + SessionRecording::RecordedDataMode type = formatType(); - if (type == interaction::RecordedDataMode::Ascii) { + if (type == SessionRecording::RecordedDataMode::Ascii) { convertToBinary(); } - else if (type == interaction::RecordedDataMode::Binary) { + else if (type == SessionRecording::RecordedDataMode::Binary) { convertToAscii(); } else { @@ -82,33 +82,83 @@ void ConvertRecFormatTask::convert() { } } -RecordedDataMode ConvertRecFormatTask::formatType() { +SessionRecording::RecordedDataMode ConvertRecFormatTask::formatType() { const std::string expectedHeader = "OpenSpace_record/playback"; std::string line; //Get first line, which is ASCII regardless of format std::getline(_iFile, line); - if (line.substr(0, interaction::FileHeaderTitle.length()) - != interaction::FileHeaderTitle) + if (line.substr(0, SessionRecording::FileHeaderTitle.length()) + != SessionRecording::FileHeaderTitle) { LERROR(fmt::format("Session recording file {} does not have expected header.", _inFilePath)); - return RecordedDataMode::Binary + 1; + return SessionRecording::RecordedDataMode::Binary + 1; } else { - if (line.back() == DataFormatAsciiTag) { - return RecordedDataMode::Ascii; + if (line.back() == SessionRecording::DataFormatAsciiTag) { + return SessionRecording::RecordedDataMode::Ascii; } - else if (line.back() == DataFormatBinaryTag) { - return RecordedDataMode::Binary; + else if (line.back() == SessionRecording::DataFormatBinaryTag) { + return SessionRecording::RecordedDataMode::Binary; } else { - return RecordedDataMode::Binary + 1; + return SessionRecording::RecordedDataMode::Binary + 1; } } } void ConvertRecFormatTask::convertToAscii() { + SessionRecording::timestamps times; + datamessagestructures::CameraKeyframe ckf; + datamessagestructures::TimeKeyframe tkf; + datamessagestructures::ScriptMessage skf; + int lineNum = 1; + unsigned char frameType; _outFilePath = addFileSuffix(_inFilePath, "_ascii"); + + bool fileReadOk = true; + while (fileReadOk) { + frameType = readFromPlayback(_iFile); + // Check if have reached EOF + if (!_iFile) { + LINFO(fmt::format( + "Finished converting {} entries from playback file {}", + lineNum - 1, _inFilePath + )); + fileReadOk = false; + break; + } + + if (frameType == 'c') { + SessionRecording::readCameraKeyframeBinary(times, ckf, _iFile, lineNum); + std::stringstream keyframeLine = std::stringstream(); + SessionRecording::saveHeaderAscii(times, "camera", keyframeLine); + ckf.write(keyframeLine); + SessionRecording::saveKeyframeToFile(keyframeLine.str(), _oFile); + } + else if (frameType == 't') { + SessionRecording::readTimeKeyframeBinary(times, tkf, _iFile, lineNum); + std::stringstream keyframeLine = std::stringstream(); + SessionRecording::saveHeaderAscii(times, "time", keyframeLine); + ckf.write(keyframeLine); + SessionRecording::saveKeyframeToFile(keyframeLine.str(), _oFile); + } + else if (frameType == 's') { + SessionRecording::readScriptKeyframeBinary(times, skf, _iFile, lineNum); + std::stringstream keyframeLine = std::stringstream(); + SessionRecording::saveHeaderAscii(times, "script", keyframeLine); + ckf.write(keyframeLine); + SessionRecording::saveKeyframeToFile(keyframeLine.str(), _oFile); + } + else { + LERROR(fmt::format( + "Unknown frame type @ index {} of playback file {}", + lineNum - 1, _inFilePath + )); + break; + } + lineNum++; + } } void ConvertRecFormatTask::convertToBinary() { @@ -118,7 +168,7 @@ void ConvertRecFormatTask::convertToBinary() { std::string ConvertRecFormatTask::addFileSuffix(const std::string& filePath, const std::string& suffix) { - size_t lastdot = filename.find_last_of("."); + size_t lastdot = filePath.find_last_of("."); std::string extension = filePath.substr(0, lastdot); if (lastdot == std::string::npos) { return filePath + suffix; @@ -155,3 +205,5 @@ documentation::Documentation ConvertRecFormatTask::documentation() { }, }; } + +} From 754dfd9c91864a009d1aa2885484f66a10f69f53 Mon Sep 17 00:00:00 2001 From: GPayne Date: Thu, 27 Feb 2020 13:45:30 -0700 Subject: [PATCH 14/26] Corrections to ascii conversion steps --- src/interaction/tasks/convertrecformattask.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/interaction/tasks/convertrecformattask.cpp b/src/interaction/tasks/convertrecformattask.cpp index fbed41dd71..d54c64f09e 100644 --- a/src/interaction/tasks/convertrecformattask.cpp +++ b/src/interaction/tasks/convertrecformattask.cpp @@ -115,6 +115,7 @@ void ConvertRecFormatTask::convertToAscii() { int lineNum = 1; unsigned char frameType; _outFilePath = addFileSuffix(_inFilePath, "_ascii"); + std::stringstream keyframeLine = std::stringstream(); bool fileReadOk = true; while (fileReadOk) { @@ -129,26 +130,21 @@ void ConvertRecFormatTask::convertToAscii() { break; } + keyframeLine.str(std::string()); if (frameType == 'c') { SessionRecording::readCameraKeyframeBinary(times, ckf, _iFile, lineNum); - std::stringstream keyframeLine = std::stringstream(); SessionRecording::saveHeaderAscii(times, "camera", keyframeLine); ckf.write(keyframeLine); - SessionRecording::saveKeyframeToFile(keyframeLine.str(), _oFile); } else if (frameType == 't') { SessionRecording::readTimeKeyframeBinary(times, tkf, _iFile, lineNum); - std::stringstream keyframeLine = std::stringstream(); SessionRecording::saveHeaderAscii(times, "time", keyframeLine); - ckf.write(keyframeLine); - SessionRecording::saveKeyframeToFile(keyframeLine.str(), _oFile); + tkf.write(keyframeLine); } else if (frameType == 's') { SessionRecording::readScriptKeyframeBinary(times, skf, _iFile, lineNum); - std::stringstream keyframeLine = std::stringstream(); SessionRecording::saveHeaderAscii(times, "script", keyframeLine); - ckf.write(keyframeLine); - SessionRecording::saveKeyframeToFile(keyframeLine.str(), _oFile); + skf.write(keyframeLine); } else { LERROR(fmt::format( @@ -157,6 +153,7 @@ void ConvertRecFormatTask::convertToAscii() { )); break; } + SessionRecording::saveKeyframeToFile(keyframeLine.str(), _oFile); lineNum++; } } From 9ba31ee0825bf9c292bae627cabc3ea33af5a71a Mon Sep 17 00:00:00 2001 From: GPayne Date: Wed, 4 Mar 2020 09:55:51 -0700 Subject: [PATCH 15/26] Added code for conversion to binary format --- .../openspace/interaction/sessionrecording.h | 12 ++-- .../tasks/convertrecformattask.cpp | 55 ++++++++++++++++++- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index 3b3372ba56..b0d523e8b9 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -59,6 +59,12 @@ public: const char DataFormatAsciiTag = 'A'; const char DataFormatBinaryTag = 'B'; + 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; + using CallbackHandle = int; using StateChangeCallback = std::function; @@ -458,12 +464,6 @@ private: double _saveRenderingDeltaTime = 1.0 / 30.0; double _saveRenderingCurrentRecordedTime; - 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]; bool _cleanupNeeded = false; diff --git a/src/interaction/tasks/convertrecformattask.cpp b/src/interaction/tasks/convertrecformattask.cpp index d54c64f09e..8b79e4477e 100644 --- a/src/interaction/tasks/convertrecformattask.cpp +++ b/src/interaction/tasks/convertrecformattask.cpp @@ -123,7 +123,7 @@ void ConvertRecFormatTask::convertToAscii() { // Check if have reached EOF if (!_iFile) { LINFO(fmt::format( - "Finished converting {} entries from playback file {}", + "Finished converting {} entries from file {}", lineNum - 1, _inFilePath )); fileReadOk = false; @@ -159,7 +159,58 @@ void ConvertRecFormatTask::convertToAscii() { } void ConvertRecFormatTask::convertToBinary() { - _outFilePath = addFileSuffix(_inFilePath, "_binary"); + SessionRecording::timestamps times; + datamessagestructures::CameraKeyframe ckf; + datamessagestructures::TimeKeyframe tkf; + datamessagestructures::ScriptMessage skf; + int lineNum = 1; + std::string lineContents; + unsigned char keyframeBuffer[SessionRecording::_saveBufferMaxSize_bytes]; + std::ofstream saveFile; + saveFile.open(_outFilePath, std::ios::binary); + size_t idx = 0; + + while (std::getline(_iFile, lineContents)) { + lineNum++; + + std::istringstream iss(lineContents); + std::string entryType; + if (!(iss >> entryType)) { + LERROR(fmt::format( + "Error reading entry type @ line {} of file {}", + lineNum, _inFilePath + )); + break; + } + + if (entryType == "camera") { + SessionRecording::readCameraKeyframeAscii(times, ckf, _inFilePath, lineNum); + SessionRecording::saveCameraKeyframeBinary(times, ckf, keyframeBuffer, + saveFile); + } + else if (entryType == "time") { + SessionRecording::readTimeKeyframeAscii(times, tkf, _inFilePath, lineNum); + SessionRecording::saveTimeKeyframeBinary(times, tkf, keyframeBuffer, + saveFile); + } + else if (entryType == "script") { + SessionRecording::readScriptKeyframeAscii(times, skf, _inFilePath, lineNum); + SessionRecording::saveScriptKeyframeBinary(times, skf, keyframeBuffer, + saveFile); + } + else { + LERROR(fmt::format( + "Unknown frame type {} @ line {} of file {}", + entryType, lineContents, _inFilePath + )); + break; + } + } + saveFile.close(); + LINFO(fmt::format( + "Finished converting {} entries from file {}", + lineNum, _inFilePath + )); } std::string ConvertRecFormatTask::addFileSuffix(const std::string& filePath, From cd7be9b87045f731a5a4b7dec0653e398bcf40d3 Mon Sep 17 00:00:00 2001 From: Gene Payne Date: Tue, 14 Jul 2020 17:19:24 -0600 Subject: [PATCH 16/26] Conversion task working for both directions --- data/tasks/sessionRecordConvertExample1.task | 7 + .../openspace/interaction/sessionrecording.h | 80 +++++++---- .../interaction/tasks/convertrecformattask.h | 5 +- include/openspace/network/messagestructures.h | 8 ++ src/CMakeLists.txt | 2 + src/interaction/sessionrecording.cpp | 100 +++++++------- src/interaction/sessionrecording_lua.inl | 4 +- .../tasks/convertrecformattask.cpp | 124 ++++++++++++------ 8 files changed, 211 insertions(+), 119 deletions(-) create mode 100644 data/tasks/sessionRecordConvertExample1.task diff --git a/data/tasks/sessionRecordConvertExample1.task b/data/tasks/sessionRecordConvertExample1.task new file mode 100644 index 0000000000..2237c462e8 --- /dev/null +++ b/data/tasks/sessionRecordConvertExample1.task @@ -0,0 +1,7 @@ +return { + { + Type = "ConvertRecFormatTask", + InputFilePath = "../../recordings/input", + OutputFilePath = "../../recordings/output" + } +} diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index bcfedcd918..fbfc1b5c9c 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -32,13 +32,21 @@ namespace openspace::interaction { +enum class SessionRecordingDataMode { + Ascii = 0, + Binary, + Unknown +}; +static const std::string SessionRecordingFileHeaderTitle = "OpenSpace_record/playback"; +static const std::string SessionRecordingHeaderCameraAscii = "camera"; +static const std::string SessionRecordingHeaderTimeAscii = "time"; +static const std::string SessionRecordingHeaderScriptAscii = "script"; +static const char SessionRecordingHeaderCameraBinary = 'c'; +static const char SessionRecordingHeaderTimeBinary = 't'; +static const char SessionRecordingHeaderScriptBinary = 's'; + class SessionRecording : public properties::PropertyOwner { public: - enum class RecordedDataMode { - Ascii = 0, - Binary - }; - enum class SessionState { Idle = 0, Recording, @@ -51,14 +59,12 @@ public: double timeSim; }; - const std::string FileHeaderTitle = "OpenSpace_record/playback"; static const size_t FileHeaderVersionLength = 5; - const char FileHeaderVersion[FileHeaderVersionLength] = { + static constexpr char FileHeaderVersion[FileHeaderVersionLength] = { '0', '0', '.', '8', '5' }; - const char DataFormatAsciiTag = 'A'; - const char DataFormatBinaryTag = 'B'; - + static const char DataFormatAsciiTag = 'A'; + static const char DataFormatBinaryTag = 'B'; static const size_t keyframeHeaderSize_bytes = 33; static const size_t saveBufferCameraSize_min = 82; static const size_t saveBufferStringSize_max = 500; @@ -114,7 +120,7 @@ public: * * \return \c true if recording to file starts without errors */ - void setRecordDataFormat(RecordedDataMode dataMode); + void setRecordDataFormat(SessionRecordingDataMode dataMode); /** * Used to stop a recording in progress. If open, the recording file will be closed, @@ -246,11 +252,12 @@ public: * * \param times reference to a timestamps structure which contains recorded times * \param kf reference to a camera keyframe which contains camera details - * \param filenameRead a string containing the playback filename + * \param currentParsingLine string containing the most current line that was read * \param lineN line number in playback file where this keyframe resides */ static void readCameraKeyframeAscii(timestamps& times, - datamessagestructures::CameraKeyframe& kf, std::string filenameRead, int lineN); + datamessagestructures::CameraKeyframe& kf, std::string currentParsingLine, + int lineN); /** * Reads a time keyframe from a binary format playback file, and populates input @@ -270,11 +277,12 @@ public: * * \param times reference to a timestamps structure which contains recorded times * \param kf reference to a time keyframe which contains time details - * \param filenameRead a string containing the playback filename + * \param currentParsingLine string containing the most current line that was read * \param lineN line number in playback file where this keyframe resides */ static void readTimeKeyframeAscii(timestamps& times, - datamessagestructures::TimeKeyframe& kf, std::string filenameRead, int lineN); + datamessagestructures::TimeKeyframe& kf, std::string currentParsingLine, + int lineN); /** * Reads a script keyframe from a binary format playback file, and populates input @@ -296,11 +304,12 @@ public: * \param times reference to a timestamps structure which contains recorded times * \param kf reference to a script keyframe which contains the size of the script * (in chars) and the text itself - * \param filenameRead a string containing the playback filename + * \param currentParsingLine string containing the most current line that was read * \param lineN line number in playback file where this keyframe resides */ static void readScriptKeyframeAscii(timestamps& times, - datamessagestructures::ScriptMessage& kf, std::string filenameRead, int lineN); + datamessagestructures::ScriptMessage& kf, std::string currentParsingLine, + int lineN); /** * Writes a camera keyframe to a binary format recording file using a CameraKeyframe @@ -377,6 +386,35 @@ public: */ static std::string readHeaderElement(std::ifstream& stream, size_t readLen_chars); + /** + * Writes a header to a binary recording file buffer + * + * \param times reference to a timestamps structure which contains recorded times + * \param type single character signifying the keyframe type + * \param kfBuffer the char buffer holding the recording info to be written + * \param idx index into write buffer (this is updated with the num of chars written) + */ + static void saveHeaderBinary(timestamps times, char type, unsigned char* kfBuffer, + size_t& idx); + + /** + * Writes a header to an ascii recording file buffer + * + * \param times reference to a timestamps structure which contains recorded times + * \param type string signifying the keyframe type + * \param line the stringstream buffer being written to + */ + static void saveHeaderAscii(timestamps times, const std::string& type, + std::stringstream& line); + + /** + * Saves a keyframe to an ascii recording file + * + * \param entry the ascii string version of the keyframe (any type) + * \param file ofstream object to write to + */ + static void saveKeyframeToFile(std::string entry, std::ofstream& file); + private: enum class RecordedType { Camera = 0, @@ -409,7 +447,6 @@ private: std::ofstream& file); static void saveKeyframeToFileBinary(unsigned char* bufferSource, size_t size, std::ofstream& file); - static void saveKeyframeToFile(std::string entry, std::ofstream& file); void addKeyframe(double timestamp, interaction::KeyframeNavigator::CameraPose keyframe); @@ -439,12 +476,7 @@ private: static void writeToFileBuffer(unsigned char* buf, size_t& idx, unsigned char c); static void writeToFileBuffer(unsigned char* buf, size_t& idx, bool b); - static void saveHeaderBinary(timestamps times, char type, - unsigned char* kfBuffer, size_t& idx); - static void saveHeaderAscii(timestamps times, const std::string& type, - std::stringstream& line); - - RecordedDataMode _recordingDataMode = RecordedDataMode::Binary; + SessionRecordingDataMode _recordingDataMode = SessionRecordingDataMode::Binary; SessionState _state = SessionState::Idle; SessionState _lastState = SessionState::Idle; std::string _playbackFilename; diff --git a/include/openspace/interaction/tasks/convertrecformattask.h b/include/openspace/interaction/tasks/convertrecformattask.h index fab8dfab51..d084bec2a6 100644 --- a/include/openspace/interaction/tasks/convertrecformattask.h +++ b/include/openspace/interaction/tasks/convertrecformattask.h @@ -53,20 +53,19 @@ public: void perform(const Task::ProgressCallback& progressCallback) override; static documentation::Documentation documentation(); void convert(); - SessionRecording::RecordedDataMode ConvertRecFormatTask::formatType(); private: void convertToAscii(); void convertToBinary(); + void determineFormatType(); std::string addFileSuffix(const std::string& filePath, const std::string& suffix); std::string _inFilePath; std::string _outFilePath; std::ifstream _iFile; std::ofstream _oFile; + SessionRecordingDataMode _fileFormatType; std::string _valueFunctionLua; - - SessionRecording sr; }; } // namespace openspace::interaction diff --git a/include/openspace/network/messagestructures.h b/include/openspace/network/messagestructures.h index bad251b66f..0131383ebe 100644 --- a/include/openspace/network/messagestructures.h +++ b/include/openspace/network/messagestructures.h @@ -429,6 +429,12 @@ struct ScriptMessage { double _timestamp; void serialize(std::vector &buffer) const { + size_t strLen = _script.size(); + size_t writeSize_bytes = sizeof(size_t); + + unsigned char const *p = reinterpret_cast(&strLen); + buffer.insert(buffer.end(), p, p + writeSize_bytes); + buffer.insert(buffer.end(), _script.begin(), _script.end()); }; @@ -486,6 +492,8 @@ struct ScriptMessage { _script.erase(); for (int i = 0; i < numScriptLines; ++i) { std::getline(iss, tmpReadbackScript); + size_t start = tmpReadbackScript.find_first_not_of(" "); + tmpReadbackScript = tmpReadbackScript.substr(start); _script.append(tmpReadbackScript); if (i < (numScriptLines - 1)) { _script.append("\n"); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b5642e724a..ae2315ffc6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -63,6 +63,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/interaction/shortcutmanager_lua.inl ${OPENSPACE_BASE_DIR}/src/interaction/websocketinputstate.cpp ${OPENSPACE_BASE_DIR}/src/interaction/websocketcamerastates.cpp + ${OPENSPACE_BASE_DIR}/src/interaction/tasks/convertrecformattask.cpp ${OPENSPACE_BASE_DIR}/src/mission/mission.cpp ${OPENSPACE_BASE_DIR}/src/mission/missionmanager.cpp ${OPENSPACE_BASE_DIR}/src/mission/missionmanager_lua.inl @@ -245,6 +246,7 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/interaction/shortcutmanager.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/websocketinputstate.h ${OPENSPACE_BASE_DIR}/include/openspace/interaction/websocketcamerastates.h + ${OPENSPACE_BASE_DIR}/include/openspace/interaction/tasks/convertrecformattask.h ${OPENSPACE_BASE_DIR}/include/openspace/mission/mission.h ${OPENSPACE_BASE_DIR}/include/openspace/mission/missionmanager.h ${OPENSPACE_BASE_DIR}/include/openspace/network/parallelconnection.h diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index eba6a4313a..8e26877d3d 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -36,6 +37,8 @@ #include #include #include +#include +#include #include #include #include @@ -57,7 +60,11 @@ namespace openspace::interaction { SessionRecording::SessionRecording() : properties::PropertyOwner({ "SessionRecording", "Session Recording" }) -{} +{ + auto fTask = FactoryManager::ref().factory(); + ghoul_assert(fRenderable, "No task factory existed"); + fTask->registerClass("ConvertRecFormatTask"); +} SessionRecording::~SessionRecording() {} // NOLINT @@ -66,7 +73,7 @@ void SessionRecording::deinitialize() { stopPlayback(); } -void SessionRecording::setRecordDataFormat(RecordedDataMode dataMode) { +void SessionRecording::setRecordDataFormat(SessionRecordingDataMode dataMode) { _recordingDataMode = dataMode; } @@ -102,7 +109,7 @@ bool SessionRecording::startRecording(const std::string& filename) { _playbackActive_camera = false; _playbackActive_time = false; _playbackActive_script = false; - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { _recordFile.open(absFilename, std::ios::binary); } else { @@ -115,9 +122,9 @@ bool SessionRecording::startRecording(const std::string& filename) { )); return false; } - _recordFile << FileHeaderTitle; + _recordFile << SessionRecordingFileHeaderTitle; _recordFile.write(FileHeaderVersion, FileHeaderVersionLength); - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { _recordFile << DataFormatBinaryTag; } else { @@ -180,9 +187,9 @@ bool SessionRecording::startPlayback(const std::string& filename, // Read header std::string readBackHeaderString = readHeaderElement( _playbackFile, - FileHeaderTitle.length() + SessionRecordingFileHeaderTitle.length() ); - if (readBackHeaderString != FileHeaderTitle) { + if (readBackHeaderString != SessionRecordingFileHeaderTitle) { LERROR("Specified playback file does not contain expected header."); cleanUpPlayback(); return false; @@ -190,10 +197,10 @@ bool SessionRecording::startPlayback(const std::string& filename, readHeaderElement(_playbackFile, FileHeaderVersionLength); std::string readDataMode = readHeaderElement(_playbackFile, 1); if (readDataMode[0] == DataFormatAsciiTag) { - _recordingDataMode = RecordedDataMode::Ascii; + _recordingDataMode = SessionRecordingDataMode::Ascii; } else if (readDataMode[0] == DataFormatBinaryTag) { - _recordingDataMode = RecordedDataMode::Binary; + _recordingDataMode = SessionRecordingDataMode::Binary; } else { LERROR("Unknown data type in header (should be Ascii or Binary)"); @@ -201,13 +208,14 @@ bool SessionRecording::startPlayback(const std::string& filename, } std::string throwawayNewlineChar = readHeaderElement(_playbackFile, 1); - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { //Close & re-open the file, starting from the beginning, and do dummy read // past the header, version, and data type _playbackFile.close(); _playbackFile.open(_playbackFilename, std::ifstream::in | std::ios::binary); - size_t headerSize = FileHeaderTitle.length() + FileHeaderVersionLength + - sizeof(DataFormatBinaryTag) + sizeof('\n'); + size_t headerSize = SessionRecordingFileHeaderTitle.length() + + FileHeaderVersionLength + + sizeof(DataFormatBinaryTag) + sizeof('\n'); _playbackFile.read(reinterpret_cast(&_keyframeBuffer), headerSize); } @@ -443,7 +451,7 @@ void SessionRecording::saveCameraKeyframe() { kf._timestamp - _timestampRecordStarted, global::timeManager.time().j2000Seconds() }; - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { saveCameraKeyframeBinary(times, kf, _keyframeBuffer, _recordFile); } else { @@ -479,7 +487,7 @@ void SessionRecording::saveCameraKeyframeBinary(timestamps times, { // Writing to a binary session recording file size_t idx = 0; - saveHeaderBinary(times, 'c', kfBuffer, idx); + saveHeaderBinary(times, SessionRecordingHeaderCameraBinary, kfBuffer, idx); // Writing to internal buffer, and then to file, for performance reasons std::vector writeBuffer; kf.serialize(writeBuffer); @@ -492,7 +500,7 @@ void SessionRecording::saveCameraKeyframeAscii(timestamps times, std::ofstream& file) { std::stringstream keyframeLine = std::stringstream(); - saveHeaderAscii(times, "camera", keyframeLine); + saveHeaderAscii(times, SessionRecordingHeaderCameraAscii, keyframeLine); kf.write(keyframeLine); saveKeyframeToFile(keyframeLine.str(), file); } @@ -510,7 +518,7 @@ void SessionRecording::saveTimeKeyframe() { kf._timestamp - _timestampRecordStarted, global::timeManager.time().j2000Seconds() }; - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { saveTimeKeyframeBinary(times, kf, _keyframeBuffer, _recordFile); } else { saveTimeKeyframeAscii(times, kf, _recordFile); @@ -523,7 +531,7 @@ void SessionRecording::saveTimeKeyframeBinary(timestamps times, std::ofstream& file) { size_t idx = 0; - saveHeaderBinary(times, 't', kfBuffer, idx); + saveHeaderBinary(times, SessionRecordingHeaderTimeBinary, kfBuffer, idx); std::vector writeBuffer; kf.serialize(writeBuffer); writeToFileBuffer(kfBuffer, idx, writeBuffer); @@ -535,7 +543,7 @@ void SessionRecording::saveTimeKeyframeAscii(timestamps times, std::ofstream& file) { std::stringstream keyframeLine = std::stringstream(); - saveHeaderAscii(times, "time", keyframeLine); + saveHeaderAscii(times, SessionRecordingHeaderTimeAscii, keyframeLine); kf.write(keyframeLine); saveKeyframeToFile(keyframeLine.str(), file); } @@ -554,7 +562,7 @@ void SessionRecording::saveScriptKeyframe(std::string scriptToSave) { global::timeManager.time().j2000Seconds() }; - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { saveScriptKeyframeBinary(times, sm, _keyframeBuffer, _recordFile); } else { @@ -568,11 +576,12 @@ void SessionRecording::saveScriptKeyframeBinary(timestamps times, std::ofstream& file) { size_t idx = 0; - saveHeaderBinary(times, 's', smBuffer, idx); - //Write script header to file + saveHeaderBinary(times, SessionRecordingHeaderScriptBinary, smBuffer, idx); + // Writing to internal buffer, and then to file, for performance reasons + std::vector writeBuffer; + sm.serialize(writeBuffer); + writeToFileBuffer(smBuffer, idx, writeBuffer); saveKeyframeToFileBinary(smBuffer, idx, file); - //Write script data to file - sm.write(smBuffer, idx, file); } void SessionRecording::saveScriptKeyframeAscii(timestamps times, @@ -581,7 +590,7 @@ void SessionRecording::saveScriptKeyframeAscii(timestamps times, { std::stringstream keyframeLine = std::stringstream(); - saveHeaderAscii(times, "script", keyframeLine); + saveHeaderAscii(times, SessionRecordingHeaderScriptAscii, keyframeLine); sm.write(keyframeLine); saveKeyframeToFile(keyframeLine.str(), file); } @@ -632,7 +641,7 @@ SessionRecording::SessionState SessionRecording::state() const { bool SessionRecording::playbackAddEntriesToTimeline() { bool parsingErrorsFound = false; - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { unsigned char frameType; bool fileReadOk = true; @@ -647,13 +656,13 @@ bool SessionRecording::playbackAddEntriesToTimeline() { fileReadOk = false; break; } - if (frameType == 'c') { + if (frameType == SessionRecordingHeaderCameraBinary) { playbackCamera(); } - else if (frameType == 't') { + else if (frameType == SessionRecordingHeaderTimeBinary) { playbackTimeChange(); } - else if (frameType == 's') { + else if (frameType == SessionRecordingHeaderScriptBinary) { playbackScript(); } else { @@ -682,13 +691,13 @@ bool SessionRecording::playbackAddEntriesToTimeline() { break; } - if (entryType == "camera") { + if (entryType == SessionRecordingHeaderCameraAscii) { playbackCamera(); } - else if (entryType == "time") { + else if (entryType == SessionRecordingHeaderTimeAscii) { playbackTimeChange(); } - else if (entryType == "script") { + else if (entryType == SessionRecordingHeaderScriptAscii) { playbackScript(); } else { @@ -788,7 +797,7 @@ void SessionRecording::playbackCamera() { timestamps times; datamessagestructures::CameraKeyframe kf; - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { readCameraKeyframeBinary(times, kf, _playbackFile, _playbackLineNum); } else { @@ -843,16 +852,18 @@ void SessionRecording::readCameraKeyframeBinary(timestamps& times, void SessionRecording::readCameraKeyframeAscii(timestamps& times, datamessagestructures::CameraKeyframe& kf, - std::string filenameRead, + std::string currentParsingLine, int lineN) { std::string rotationFollowing; std::string entryType; - std::istringstream iss(filenameRead); + std::istringstream iss(currentParsingLine); iss >> entryType; iss >> times.timeOs >> times.timeRec >> times.timeSim; kf.read(iss); + //ASCII format does not contain trailing timestamp so add it here + kf._timestamp = times.timeOs; if (iss.fail() || !iss.eof()) { LERROR(fmt::format("Error parsing camera line {} of playback file", lineN)); @@ -864,7 +875,7 @@ void SessionRecording::playbackTimeChange() { timestamps times; datamessagestructures::TimeKeyframe kf; - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { readTimeKeyframeBinary(times, kf, _playbackFile, _playbackLineNum); } else { readTimeKeyframeAscii(times, kf, _playbackLineParsing, _playbackLineNum); @@ -913,12 +924,12 @@ void SessionRecording::readTimeKeyframeBinary(timestamps& times, void SessionRecording::readTimeKeyframeAscii(timestamps& times, datamessagestructures::TimeKeyframe& kf, - std::string filenameRead, + std::string currentParsingLine, int lineN) { std::string entryType; - std::istringstream iss(filenameRead); + std::istringstream iss(currentParsingLine); iss >> entryType; iss >> times.timeOs >> times.timeRec >> times.timeSim; kf.read(iss); @@ -931,8 +942,8 @@ void SessionRecording::readTimeKeyframeAscii(timestamps& times, } } -static std::string SessionRecording::readHeaderElement(std::ifstream& stream, - size_t readLen_chars) +std::string SessionRecording::readHeaderElement(std::ifstream& stream, + size_t readLen_chars) { std::vector readTemp(readLen_chars); stream.read(&readTemp[0], readLen_chars); @@ -943,7 +954,7 @@ void SessionRecording::playbackScript() { timestamps times; datamessagestructures::ScriptMessage kf; - if (_recordingDataMode == RecordedDataMode::Binary) { + if (_recordingDataMode == SessionRecordingDataMode::Binary) { readScriptKeyframeBinary(times, kf, _playbackFile, _playbackLineNum); } else { readScriptKeyframeAscii(times, kf, _playbackLineParsing, _playbackLineNum); @@ -990,11 +1001,11 @@ void SessionRecording::readScriptKeyframeBinary(timestamps& times, void SessionRecording::readScriptKeyframeAscii(timestamps& times, datamessagestructures::ScriptMessage& kf, - std::string filenameRead, + std::string currentParsingLine, int lineN) { std::string entryType; - std::istringstream iss(filenameRead); + std::istringstream iss(currentParsingLine); iss >> entryType; iss >> times.timeOs >> times.timeRec >> times.timeSim; kf.read(iss); @@ -1156,11 +1167,6 @@ bool SessionRecording::doesTimelineEntryContainCamera(unsigned int index) const } bool SessionRecording::processNextNonCameraKeyframeAheadInTime() { - //LINFO(fmt::format( - // "Keyframe at {} frame={} timelineIndex={}", - // now, global::renderEngine._frameNumber, _idxTimeline - //)); - switch (getNextKeyframeType()) { case RecordedType::Camera: // Just return true since this function no longer handles camera keyframes diff --git a/src/interaction/sessionrecording_lua.inl b/src/interaction/sessionrecording_lua.inl index 8a1c2409b4..8e4761295b 100644 --- a/src/interaction/sessionrecording_lua.inl +++ b/src/interaction/sessionrecording_lua.inl @@ -40,7 +40,7 @@ int startRecording(lua_State* L) { return luaL_error(L, "filepath string is empty"); } global::sessionRecording.setRecordDataFormat( - openspace::interaction::SessionRecording::RecordedDataMode::Binary + openspace::interaction::SessionRecordingDataMode::Binary ); global::sessionRecording.startRecording(recordFilePath); @@ -63,7 +63,7 @@ int startRecordingAscii(lua_State* L) { return luaL_error(L, "filepath string is empty"); } global::sessionRecording.setRecordDataFormat( - openspace::interaction::SessionRecording::RecordedDataMode::Ascii + openspace::interaction::SessionRecordingDataMode::Ascii ); global::sessionRecording.startRecording(recordFilePath); diff --git a/src/interaction/tasks/convertrecformattask.cpp b/src/interaction/tasks/convertrecformattask.cpp index 8b79e4477e..6cbe5257db 100644 --- a/src/interaction/tasks/convertrecformattask.cpp +++ b/src/interaction/tasks/convertrecformattask.cpp @@ -51,11 +51,11 @@ ConvertRecFormatTask::ConvertRecFormatTask(const ghoul::Dictionary& dictionary) ghoul_assert(FileSys.fileExists(_inFilePath), "The filename must exist"); if (!FileSys.fileExists(_inFilePath)) { LERROR(fmt::format("Failed to load session recording file: {}", _inFilePath)); - //throw ghoul::FileNotFoundError(_inFilePath); } - - _iFile.exceptions(std::ofstream::failbit | std::ofstream::badbit); - _iFile.open(_inFilePath); + else { + _iFile.open(_inFilePath, std::ifstream::in); + determineFormatType(); + } } ConvertRecFormatTask::~ConvertRecFormatTask() { @@ -63,17 +63,42 @@ ConvertRecFormatTask::~ConvertRecFormatTask() { _oFile.close(); } -void ConvertRecFormatTask::perform(const Task::ProgressCallback& progressCallback) { +std::string ConvertRecFormatTask::description() { + std::string description = "Convert session recording file '" + _inFilePath + "' "; + if (_fileFormatType == SessionRecordingDataMode::Ascii) { + description += "(ascii format) "; + } + else if (_fileFormatType == SessionRecordingDataMode::Binary) { + description += "(binary format) "; + } + else { + description += "(UNKNOWN format) "; + } + description += "conversion to file '" + _outFilePath + "'."; + return description; +} +void ConvertRecFormatTask::perform(const Task::ProgressCallback& progressCallback) { + convert(); } void ConvertRecFormatTask::convert() { - SessionRecording::RecordedDataMode type = formatType(); + if (_fileFormatType == SessionRecordingDataMode::Ascii) { + _oFile.open(_outFilePath); + } + else if (_fileFormatType == SessionRecordingDataMode::Binary) { + _oFile.open(_outFilePath, std::ios::binary); + } + _oFile.write(SessionRecordingFileHeaderTitle.c_str(), + SessionRecordingFileHeaderTitle.length()); + _oFile.write(SessionRecording::FileHeaderVersion, + SessionRecording::FileHeaderVersionLength); + _oFile.close(); - if (type == SessionRecording::RecordedDataMode::Ascii) { + if (_fileFormatType == SessionRecordingDataMode::Ascii) { convertToBinary(); } - else if (type == SessionRecording::RecordedDataMode::Binary) { + else if (_fileFormatType == SessionRecordingDataMode::Binary) { convertToAscii(); } else { @@ -82,27 +107,31 @@ void ConvertRecFormatTask::convert() { } } -SessionRecording::RecordedDataMode ConvertRecFormatTask::formatType() { - const std::string expectedHeader = "OpenSpace_record/playback"; +void ConvertRecFormatTask::determineFormatType() { + _fileFormatType = SessionRecordingDataMode::Unknown; std::string line; - //Get first line, which is ASCII regardless of format - std::getline(_iFile, line); - if (line.substr(0, SessionRecording::FileHeaderTitle.length()) - != SessionRecording::FileHeaderTitle) + line = SessionRecording::readHeaderElement(_iFile, + SessionRecordingFileHeaderTitle.length()); + + if (line.substr(0, SessionRecordingFileHeaderTitle.length()) + != SessionRecordingFileHeaderTitle) { - LERROR(fmt::format("Session recording file {} does not have expected header.", _inFilePath)); - return SessionRecording::RecordedDataMode::Binary + 1; + LERROR(fmt::format("Session recording file {} does not have expected header.", + _inFilePath)); } else { - if (line.back() == SessionRecording::DataFormatAsciiTag) { - return SessionRecording::RecordedDataMode::Ascii; + //Read version string and throw it away (and also line feed character at end) + SessionRecording::readHeaderElement(_iFile, + SessionRecording::FileHeaderVersionLength); + line = SessionRecording::readHeaderElement(_iFile, 1); + SessionRecording::readHeaderElement(_iFile, 1); + + if (line.at(0) == SessionRecording::DataFormatAsciiTag) { + _fileFormatType = SessionRecordingDataMode::Ascii; } - else if (line.back() == SessionRecording::DataFormatBinaryTag) { - return SessionRecording::RecordedDataMode::Binary; - } - else { - return SessionRecording::RecordedDataMode::Binary + 1; + else if (line.at(0) == SessionRecording::DataFormatBinaryTag) { + _fileFormatType = SessionRecordingDataMode::Binary; } } } @@ -114,8 +143,10 @@ void ConvertRecFormatTask::convertToAscii() { datamessagestructures::ScriptMessage skf; int lineNum = 1; unsigned char frameType; - _outFilePath = addFileSuffix(_inFilePath, "_ascii"); - std::stringstream keyframeLine = std::stringstream(); + _oFile.open(_outFilePath, std::ifstream::app); + char tmpType = SessionRecording::DataFormatAsciiTag; + _oFile.write(&tmpType, 1); + _oFile.write("\n", 1); bool fileReadOk = true; while (fileReadOk) { @@ -130,20 +161,24 @@ void ConvertRecFormatTask::convertToAscii() { break; } + std::stringstream keyframeLine = std::stringstream(); keyframeLine.str(std::string()); - if (frameType == 'c') { + if (frameType == SessionRecordingHeaderCameraBinary) { SessionRecording::readCameraKeyframeBinary(times, ckf, _iFile, lineNum); - SessionRecording::saveHeaderAscii(times, "camera", keyframeLine); + SessionRecording::saveHeaderAscii(times, SessionRecordingHeaderCameraAscii, + keyframeLine); ckf.write(keyframeLine); } - else if (frameType == 't') { + else if (frameType == SessionRecordingHeaderTimeBinary) { SessionRecording::readTimeKeyframeBinary(times, tkf, _iFile, lineNum); - SessionRecording::saveHeaderAscii(times, "time", keyframeLine); + SessionRecording::saveHeaderAscii(times, SessionRecordingHeaderTimeAscii, + keyframeLine); tkf.write(keyframeLine); } - else if (frameType == 's') { + else if (frameType == SessionRecordingHeaderScriptBinary) { SessionRecording::readScriptKeyframeBinary(times, skf, _iFile, lineNum); - SessionRecording::saveHeaderAscii(times, "script", keyframeLine); + SessionRecording::saveHeaderAscii(times, SessionRecordingHeaderScriptAscii, + keyframeLine); skf.write(keyframeLine); } else { @@ -156,6 +191,7 @@ void ConvertRecFormatTask::convertToAscii() { SessionRecording::saveKeyframeToFile(keyframeLine.str(), _oFile); lineNum++; } + _oFile.close(); } void ConvertRecFormatTask::convertToBinary() { @@ -166,8 +202,10 @@ void ConvertRecFormatTask::convertToBinary() { int lineNum = 1; std::string lineContents; unsigned char keyframeBuffer[SessionRecording::_saveBufferMaxSize_bytes]; - std::ofstream saveFile; - saveFile.open(_outFilePath, std::ios::binary); + _oFile.open(_outFilePath, std::ifstream::app | std::ios::binary); + char tmpType = SessionRecording::DataFormatBinaryTag; + _oFile.write(&tmpType, 1); + _oFile.write("\n", 1); size_t idx = 0; while (std::getline(_iFile, lineContents)) { @@ -183,20 +221,20 @@ void ConvertRecFormatTask::convertToBinary() { break; } - if (entryType == "camera") { - SessionRecording::readCameraKeyframeAscii(times, ckf, _inFilePath, lineNum); + if (entryType == SessionRecordingHeaderCameraAscii) { + SessionRecording::readCameraKeyframeAscii(times, ckf, lineContents, lineNum); SessionRecording::saveCameraKeyframeBinary(times, ckf, keyframeBuffer, - saveFile); + _oFile); } - else if (entryType == "time") { - SessionRecording::readTimeKeyframeAscii(times, tkf, _inFilePath, lineNum); + else if (entryType == SessionRecordingHeaderTimeAscii) { + SessionRecording::readTimeKeyframeAscii(times, tkf, lineContents, lineNum); SessionRecording::saveTimeKeyframeBinary(times, tkf, keyframeBuffer, - saveFile); + _oFile); } - else if (entryType == "script") { - SessionRecording::readScriptKeyframeAscii(times, skf, _inFilePath, lineNum); + else if (entryType == SessionRecordingHeaderScriptAscii) { + SessionRecording::readScriptKeyframeAscii(times, skf, lineContents, lineNum); SessionRecording::saveScriptKeyframeBinary(times, skf, keyframeBuffer, - saveFile); + _oFile); } else { LERROR(fmt::format( @@ -206,7 +244,7 @@ void ConvertRecFormatTask::convertToBinary() { break; } } - saveFile.close(); + _oFile.close(); LINFO(fmt::format( "Finished converting {} entries from file {}", lineNum, _inFilePath From 273e04464755f4cacc9ac1a3be8ec119c2084887 Mon Sep 17 00:00:00 2001 From: Gene Payne Date: Wed, 15 Jul 2020 08:39:31 -0600 Subject: [PATCH 17/26] Added handling of playback file that is too large for memory --- .../openspace/interaction/sessionrecording.h | 21 ++-- src/interaction/sessionrecording.cpp | 101 ++++++++++++------ 2 files changed, 78 insertions(+), 44 deletions(-) diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index fbfc1b5c9c..5fb72268a4 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -437,21 +437,24 @@ private: double equivalentSimulationTime(double timeOs, double timeRec, double timeSim); double equivalentApplicationTime(double timeOs, double timeRec, double timeSim); - void playbackCamera(); - void playbackTimeChange(); - void playbackScript(); + bool playbackCamera(); + bool playbackTimeChange(); + bool playbackScript(); bool playbackAddEntriesToTimeline(); void signalPlaybackFinishedForComponent(RecordedType type); void findFirstCameraKeyframeInTimeline(); - static void saveStringToFile(const std::string& s, unsigned char* kfBuffer, size_t& idx, - std::ofstream& file); + static void saveStringToFile(const std::string& s, unsigned char* kfBuffer, + size_t& idx, std::ofstream& file); static void saveKeyframeToFileBinary(unsigned char* bufferSource, size_t size, std::ofstream& file); - void addKeyframe(double timestamp, - interaction::KeyframeNavigator::CameraPose keyframe); - void addKeyframe(double timestamp, datamessagestructures::TimeKeyframe keyframe); - void addKeyframe(double timestamp, std::string scriptToQueue); + bool addKeyframe(double timestamp, + interaction::KeyframeNavigator::CameraPose keyframe, int lineNum); + bool addKeyframe(double timestamp, datamessagestructures::TimeKeyframe keyframe, + int lineNum); + bool addKeyframe(double timestamp, std::string scriptToQueue, int lineNum); + bool addKeyframeToTimeline(RecordedType type, size_t indexIntoTypeKeyframes, + double timestamp, int lineNum); void moveAheadInTime(); void lookForNonCameraKeyframesThatHaveComeDue(double currTime); void updateCameraWithOrWithoutNewKeyframes(double currTime); diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index 8e26877d3d..4a545275b7 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -639,13 +639,13 @@ SessionRecording::SessionState SessionRecording::state() const { } bool SessionRecording::playbackAddEntriesToTimeline() { - bool parsingErrorsFound = false; + bool parsingStatusOk = true; if (_recordingDataMode == SessionRecordingDataMode::Binary) { unsigned char frameType; bool fileReadOk = true; - while (fileReadOk) { + while (parsingStatusOk && fileReadOk) { frameType = readFromPlayback(_playbackFile); // Check if have reached EOF if (!_playbackFile) { @@ -657,20 +657,20 @@ bool SessionRecording::playbackAddEntriesToTimeline() { break; } if (frameType == SessionRecordingHeaderCameraBinary) { - playbackCamera(); + parsingStatusOk = playbackCamera(); } else if (frameType == SessionRecordingHeaderTimeBinary) { - playbackTimeChange(); + parsingStatusOk = playbackTimeChange(); } else if (frameType == SessionRecordingHeaderScriptBinary) { - playbackScript(); + parsingStatusOk = playbackScript(); } else { LERROR(fmt::format( "Unknown frame type {} @ index {} of playback file {}", frameType, _playbackLineNum - 1, _playbackFilename )); - parsingErrorsFound = true; + parsingStatusOk = false; break; } @@ -678,7 +678,7 @@ bool SessionRecording::playbackAddEntriesToTimeline() { } } else { - while (std::getline(_playbackFile, _playbackLineParsing)) { + while (parsingStatusOk && std::getline(_playbackFile, _playbackLineParsing)) { _playbackLineNum++; std::istringstream iss(_playbackLineParsing); @@ -692,20 +692,20 @@ bool SessionRecording::playbackAddEntriesToTimeline() { } if (entryType == SessionRecordingHeaderCameraAscii) { - playbackCamera(); + parsingStatusOk = playbackCamera(); } else if (entryType == SessionRecordingHeaderTimeAscii) { - playbackTimeChange(); + parsingStatusOk = playbackTimeChange(); } else if (entryType == SessionRecordingHeaderScriptAscii) { - playbackScript(); + parsingStatusOk = playbackScript(); } else { LERROR(fmt::format( "Unknown frame type {} @ line {} of playback file {}", entryType, _playbackLineNum, _playbackFilename )); - parsingErrorsFound = true; + parsingStatusOk = false; break; } } @@ -715,7 +715,7 @@ bool SessionRecording::playbackAddEntriesToTimeline() { )); } - return !parsingErrorsFound; + return parsingStatusOk; } double SessionRecording::appropriateTimestamp(double timeOs, @@ -793,7 +793,7 @@ double SessionRecording::fixedDeltaTimeDuringFrameOutput() const { } } -void SessionRecording::playbackCamera() { +bool SessionRecording::playbackCamera() { timestamps times; datamessagestructures::CameraKeyframe kf; @@ -812,7 +812,7 @@ void SessionRecording::playbackCamera() { double timeRef = appropriateTimestamp(times.timeOs, times.timeRec, times.timeSim); interaction::KeyframeNavigator::CameraPose pbFrame(kf); - addKeyframe(timeRef, pbFrame); + return addKeyframe(timeRef, pbFrame, _playbackLineNum); } void SessionRecording::readCameraKeyframeBinary(timestamps& times, @@ -871,7 +871,7 @@ void SessionRecording::readCameraKeyframeAscii(timestamps& times, } } -void SessionRecording::playbackTimeChange() { +bool SessionRecording::playbackTimeChange() { timestamps times; datamessagestructures::TimeKeyframe kf; @@ -885,7 +885,7 @@ void SessionRecording::playbackTimeChange() { kf._time = kf._timestamp + _timestampApplicationStarted_simulation; //global::timeManager.addKeyframe(timeRef, pbFrame._timestamp); //_externInteract.timeInteraction(pbFrame); - addKeyframe(kf._timestamp, kf); + return addKeyframe(kf._timestamp, kf, _playbackLineNum); } void SessionRecording::readTimeKeyframeBinary(timestamps& times, @@ -950,7 +950,7 @@ std::string SessionRecording::readHeaderElement(std::ifstream& stream, return std::string(readTemp.begin(), readTemp.end()); } -void SessionRecording::playbackScript() { +bool SessionRecording::playbackScript() { timestamps times; datamessagestructures::ScriptMessage kf; @@ -961,7 +961,7 @@ void SessionRecording::playbackScript() { } double timeRef = appropriateTimestamp(times.timeOs, times.timeRec, times.timeSim); - addKeyframe(timeRef, kf._script); + return addKeyframe(timeRef, kf._script, _playbackLineNum); } void SessionRecording::readScriptKeyframeBinary(timestamps& times, @@ -1022,38 +1022,69 @@ void SessionRecording::readScriptKeyframeAscii(timestamps& times, } } -void SessionRecording::addKeyframe(double timestamp, - interaction::KeyframeNavigator::CameraPose keyframe) +bool SessionRecording::addKeyframe(double timestamp, + interaction::KeyframeNavigator::CameraPose keyframe, + int lineNum) { size_t indexIntoCameraKeyframesFromMainTimeline = _keyframesCamera.size(); _keyframesCamera.push_back(std::move(keyframe)); - _timeline.push_back({ + return addKeyframeToTimeline( RecordedType::Camera, - static_cast(indexIntoCameraKeyframesFromMainTimeline), - timestamp - }); + indexIntoCameraKeyframesFromMainTimeline, + timestamp, + lineNum + ); } -void SessionRecording::addKeyframe(double timestamp, - datamessagestructures::TimeKeyframe keyframe) +bool SessionRecording::addKeyframe(double timestamp, + datamessagestructures::TimeKeyframe keyframe, + int lineNum) { size_t indexIntoTimeKeyframesFromMainTimeline = _keyframesTime.size(); _keyframesTime.push_back(std::move(keyframe)); - _timeline.push_back({ + return addKeyframeToTimeline( RecordedType::Time, - static_cast(indexIntoTimeKeyframesFromMainTimeline), - timestamp - }); + indexIntoTimeKeyframesFromMainTimeline, + timestamp, + lineNum + ); } -void SessionRecording::addKeyframe(double timestamp, std::string scriptToQueue) { +bool SessionRecording::addKeyframe(double timestamp, + std::string scriptToQueue, + int lineNum) +{ size_t indexIntoScriptKeyframesFromMainTimeline = _keyframesScript.size(); _keyframesScript.push_back(std::move(scriptToQueue)); - _timeline.push_back({ + return addKeyframeToTimeline( RecordedType::Script, - static_cast(indexIntoScriptKeyframesFromMainTimeline), - timestamp - }); + indexIntoScriptKeyframesFromMainTimeline, + timestamp, + lineNum + ); +} + +bool SessionRecording::addKeyframeToTimeline(RecordedType type, + size_t indexIntoTypeKeyframes, + double timestamp, + int lineNum) +{ + try { + _timeline.push_back({ + type, + static_cast(indexIntoTypeKeyframes), + timestamp + }); + } + catch(...) { + LERROR(fmt::format( + "Timeline memory allocation error trying to add keyframe {}. " + "The playback file may be too large for system memory.", + lineNum - 1 + )); + return false; + } + return true; } void SessionRecording::moveAheadInTime() { From 5a23ae35c8ce51741d13175314e38c92846dfe1e Mon Sep 17 00:00:00 2001 From: Gene Payne Date: Wed, 15 Jul 2020 13:04:39 -0600 Subject: [PATCH 18/26] Added file extensions for session recording files --- .../openspace/interaction/sessionrecording.h | 13 +- src/interaction/sessionrecording.cpp | 120 ++++++++++++------ .../tasks/convertrecformattask.cpp | 32 +++++ 3 files changed, 123 insertions(+), 42 deletions(-) diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index 5fb72268a4..23635a7780 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -41,10 +41,13 @@ static const std::string SessionRecordingFileHeaderTitle = "OpenSpace_record/pla static const std::string SessionRecordingHeaderCameraAscii = "camera"; static const std::string SessionRecordingHeaderTimeAscii = "time"; static const std::string SessionRecordingHeaderScriptAscii = "script"; +static const std::string SessionRecordingFileExtensionBinary = ".osrec"; +static const std::string SessionRecordingFileExtensionAscii = ".osrectxt"; static const char SessionRecordingHeaderCameraBinary = 'c'; static const char SessionRecordingHeaderTimeBinary = 't'; static const char SessionRecordingHeaderScriptBinary = 's'; + class SessionRecording : public properties::PropertyOwner { public: enum class SessionState { @@ -415,6 +418,14 @@ public: */ static void saveKeyframeToFile(std::string entry, std::ofstream& file); + /** + * Checks if a specified recording file ends with a particular file extension + * + * \param filename the name of the file to record to + * \param extension the file extension to check for + */ + static bool hasFileExtension(std::string filename, std::string extension); + private: enum class RecordedType { Camera = 0, @@ -436,7 +447,7 @@ private: double appropriateTimestamp(double timeOs, double timeRec, double timeSim); double equivalentSimulationTime(double timeOs, double timeRec, double timeSim); double equivalentApplicationTime(double timeOs, double timeRec, double timeSim); - + bool handleRecordingFile(std::string filenameIn); bool playbackCamera(); bool playbackTimeChange(); bool playbackScript(); diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index 4a545275b7..a39e059351 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -77,18 +77,41 @@ void SessionRecording::setRecordDataFormat(SessionRecordingDataMode dataMode) { _recordingDataMode = dataMode; } -bool SessionRecording::startRecording(const std::string& filename) { - if (filename.find("/") != std::string::npos) { +bool SessionRecording::hasFileExtension(std::string filename, std::string extension) { + if (filename.length() <= extension.length()) { + return false; + } + else { + return (filename.substr(filename.length() - extension.length()) == extension); + } +} + +bool SessionRecording::handleRecordingFile(std::string filenameIn) { + if (filenameIn.find("/") != std::string::npos) { LERROR("Recording filename must not contain path (/) elements"); return false; } - if (!FileSys.directoryExists(absPath("${RECORDINGS}"))) { - FileSys.createDirectory( - absPath("${RECORDINGS}"), - ghoul::filesystem::FileSystem::Recursive::Yes - ); + + if (_recordingDataMode == SessionRecordingDataMode::Binary) { + if (hasFileExtension(filenameIn, SessionRecordingFileExtensionAscii)) { + LERROR("Specified filename for binary recording has ascii file extension"); + return false; + } + else if (!hasFileExtension(filenameIn, SessionRecordingFileExtensionBinary)) { + filenameIn += SessionRecordingFileExtensionBinary; + } } - const std::string absFilename = absPath("${RECORDINGS}/" + filename); + else if (_recordingDataMode == SessionRecordingDataMode::Ascii) { + if (hasFileExtension(filenameIn, SessionRecordingFileExtensionBinary)) { + LERROR("Specified filename for ascii recording has binary file extension"); + return false; + } + else if (!hasFileExtension(filenameIn, SessionRecordingFileExtensionAscii)) { + filenameIn += SessionRecordingFileExtensionAscii; + } + } + + std::string absFilename = absPath("${RECORDINGS}/" + filenameIn); if (FileSys.fileExists(absFilename)) { LERROR(fmt::format( @@ -96,19 +119,6 @@ bool SessionRecording::startRecording(const std::string& filename) { )); return false; } - if (_state == SessionState::Recording) { - LERROR("Unable to start recording while already in recording mode"); - return false; - } - else if (_state == SessionState::Playback) { - LERROR("Unable to start recording while in session playback mode"); - return false; - } - - _state = SessionState::Recording; - _playbackActive_camera = false; - _playbackActive_time = false; - _playbackActive_script = false; if (_recordingDataMode == SessionRecordingDataMode::Binary) { _recordFile.open(absFilename, std::ios::binary); } @@ -122,29 +132,57 @@ bool SessionRecording::startRecording(const std::string& filename) { )); return false; } - _recordFile << SessionRecordingFileHeaderTitle; - _recordFile.write(FileHeaderVersion, FileHeaderVersionLength); - if (_recordingDataMode == SessionRecordingDataMode::Binary) { - _recordFile << DataFormatBinaryTag; - } - else { - _recordFile << DataFormatAsciiTag; - } - _recordFile << '\n'; - - _timestampRecordStarted = global::windowDelegate.applicationTime(); - - //Record the current delta time so this is preserved in recording - double currentDeltaTime = global::timeManager.deltaTime(); - std::string scriptCommandForInitializingDeltaTime = - "openspace.time.setDeltaTime(" + std::to_string(currentDeltaTime) + ")"; - saveScriptKeyframe(scriptCommandForInitializingDeltaTime); - - LINFO("Session recording started"); - return true; } +bool SessionRecording::startRecording(const std::string& filename) { + if (_state == SessionState::Recording) { + LERROR("Unable to start recording while already in recording mode"); + return false; + } + else if (_state == SessionState::Playback) { + LERROR("Unable to start recording while in session playback mode"); + return false; + } + if (!FileSys.directoryExists(absPath("${RECORDINGS}"))) { + FileSys.createDirectory( + absPath("${RECORDINGS}"), + ghoul::filesystem::FileSystem::Recursive::Yes + ); + } + + bool recordingFileOK = handleRecordingFile(filename); + + if (recordingFileOK) { + _state = SessionState::Recording; + _playbackActive_camera = false; + _playbackActive_time = false; + _playbackActive_script = false; + + _recordFile << SessionRecordingFileHeaderTitle; + _recordFile.write(FileHeaderVersion, FileHeaderVersionLength); + if (_recordingDataMode == SessionRecordingDataMode::Binary) { + _recordFile << DataFormatBinaryTag; + } + else { + _recordFile << DataFormatAsciiTag; + } + _recordFile << '\n'; + + _timestampRecordStarted = global::windowDelegate.applicationTime(); + + //Record the current delta time so this is preserved in recording + double currentDeltaTime = global::timeManager.deltaTime(); + std::string scriptCommandForInitializingDeltaTime = + "openspace.time.setDeltaTime(" + std::to_string(currentDeltaTime) + ")"; + saveScriptKeyframe(scriptCommandForInitializingDeltaTime); + + LINFO("Session recording started"); + } + + return recordingFileOK; +} + void SessionRecording::stopRecording() { if (_state == SessionState::Recording) { _state = SessionState::Idle; diff --git a/src/interaction/tasks/convertrecformattask.cpp b/src/interaction/tasks/convertrecformattask.cpp index 6cbe5257db..de938626ec 100644 --- a/src/interaction/tasks/convertrecformattask.cpp +++ b/src/interaction/tasks/convertrecformattask.cpp @@ -83,6 +83,38 @@ void ConvertRecFormatTask::perform(const Task::ProgressCallback& progressCallbac } void ConvertRecFormatTask::convert() { + std::string expectedFileExtension_in, expectedFileExtension_out; + std::string currentFormat; + if (_fileFormatType == SessionRecordingDataMode::Binary) { + currentFormat = "binary"; + expectedFileExtension_in = SessionRecordingFileExtensionBinary; + expectedFileExtension_out = SessionRecordingFileExtensionAscii; + } + else if (_fileFormatType == SessionRecordingDataMode::Ascii) { + currentFormat = "ascii"; + expectedFileExtension_in = SessionRecordingFileExtensionAscii; + expectedFileExtension_out = SessionRecordingFileExtensionBinary; + } + + if (!SessionRecording::hasFileExtension(_inFilePath, expectedFileExtension_in)) { + LWARNING(fmt::format( + "Input filename doesn't have expected {} " + "format file extension", + currentFormat) + ); + } + if (SessionRecording::hasFileExtension(_outFilePath, expectedFileExtension_in)) { + LERROR(fmt::format( + "Output filename has {} file extension, but is conversion from {}", + currentFormat, + currentFormat) + ); + return; + } + else if (!SessionRecording::hasFileExtension(_outFilePath, expectedFileExtension_out)) { + _outFilePath += expectedFileExtension_out; + } + if (_fileFormatType == SessionRecordingDataMode::Ascii) { _oFile.open(_outFilePath); } From 3ee1a112571b14772dd0b86b795dad0ff7278f13 Mon Sep 17 00:00:00 2001 From: Gene Payne Date: Thu, 16 Jul 2020 09:49:21 -0600 Subject: [PATCH 19/26] Added support for comment line in ascii session recording file --- include/openspace/interaction/sessionrecording.h | 1 + src/interaction/sessionrecording.cpp | 3 +++ src/interaction/tasks/convertrecformattask.cpp | 3 +++ 3 files changed, 7 insertions(+) diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index 23635a7780..2a23252cd6 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -41,6 +41,7 @@ static const std::string SessionRecordingFileHeaderTitle = "OpenSpace_record/pla static const std::string SessionRecordingHeaderCameraAscii = "camera"; static const std::string SessionRecordingHeaderTimeAscii = "time"; static const std::string SessionRecordingHeaderScriptAscii = "script"; +static const std::string SessionRecordingHeaderCommentAscii = "#"; static const std::string SessionRecordingFileExtensionBinary = ".osrec"; static const std::string SessionRecordingFileExtensionAscii = ".osrectxt"; static const char SessionRecordingHeaderCameraBinary = 'c'; diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index a39e059351..9d31e5ba43 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -738,6 +738,9 @@ bool SessionRecording::playbackAddEntriesToTimeline() { else if (entryType == SessionRecordingHeaderScriptAscii) { parsingStatusOk = playbackScript(); } + else if (entryType.substr(0, 1) == SessionRecordingHeaderCommentAscii) { + continue; + } else { LERROR(fmt::format( "Unknown frame type {} @ line {} of playback file {}", diff --git a/src/interaction/tasks/convertrecformattask.cpp b/src/interaction/tasks/convertrecformattask.cpp index de938626ec..05ad083dae 100644 --- a/src/interaction/tasks/convertrecformattask.cpp +++ b/src/interaction/tasks/convertrecformattask.cpp @@ -268,6 +268,9 @@ void ConvertRecFormatTask::convertToBinary() { SessionRecording::saveScriptKeyframeBinary(times, skf, keyframeBuffer, _oFile); } + else if (entryType.substr(0, 1) == SessionRecordingHeaderCommentAscii) { + continue; + } else { LERROR(fmt::format( "Unknown frame type {} @ line {} of file {}", From 3cc2d2aedf1371ecaf715da144a1cc8506949c61 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Wed, 7 Oct 2020 17:12:06 +0200 Subject: [PATCH 20/26] Fix for compile errors in Linux in exoplanets module --- modules/exoplanets/rendering/renderableorbitdisc.h | 1 + modules/exoplanets/tasks/exoplanetscsvtobintask.cpp | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/modules/exoplanets/rendering/renderableorbitdisc.h b/modules/exoplanets/rendering/renderableorbitdisc.h index 3cae6e64c4..3a78546596 100644 --- a/modules/exoplanets/rendering/renderableorbitdisc.h +++ b/modules/exoplanets/rendering/renderableorbitdisc.h @@ -30,6 +30,7 @@ #include #include #include +#include #include namespace ghoul::filesystem { class File; } diff --git a/modules/exoplanets/tasks/exoplanetscsvtobintask.cpp b/modules/exoplanets/tasks/exoplanetscsvtobintask.cpp index 6cb232fb79..8277830923 100644 --- a/modules/exoplanets/tasks/exoplanetscsvtobintask.cpp +++ b/modules/exoplanets/tasks/exoplanetscsvtobintask.cpp @@ -95,21 +95,31 @@ void ExoplanetsCsvToBinTask::perform(const Task::ProgressCallback& progressCallb LINFOC("CSVTOBIN", fmt::format("Loading {} stars", total)); auto readFloatData = [](const std::string& str) -> float { + #ifdef WIN32 float result; auto [p, ec] = std::from_chars(str.data(), str.data() + str.size(), result); if (ec == std::errc()) { return result; } return NAN; + #else + // clang is missing float support for std::from_chars + return !str.empty() ? std::stof(str.c_str(), nullptr) : NAN; + #endif }; auto readDoubleData = [](const std::string& str) -> double { + #ifdef WIN32 double result; auto [p, ec] = std::from_chars(str.data(), str.data() + str.size(), result); if (ec == std::errc()) { return result; } return NAN; + #else + // clang is missing double support for std::from_chars + return !str.empty() ? std::stod(str.c_str(), nullptr) : NAN; + #endif }; auto readIntegerData = [](const std::string& str) -> int { From 50a456b87f828701f20200a0b6ecfac794bcd239 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 9 Oct 2020 17:32:30 +0200 Subject: [PATCH 21/26] Issue/1299 (#1312) Change profile file format from a custom one to JSON --- apps/OpenSpace/ext/sgct | 2 +- .../constellations/constellation_data.csv | 85 -- data/profiles/default.profile | 52 +- ext/ghoul | 2 +- include/openspace/scene/profile.h | 39 +- src/CMakeLists.txt | 2 + src/engine/openspaceengine.cpp | 10 +- src/scene/profile.cpp | 1222 +++++++---------- src/util/time.cpp | 3 +- .../profile/basic/additional_scripts.profile | 8 + tests/profile/basic/assets.profile | 8 + tests/profile/basic/camera_gotogeo.profile | 9 + .../basic/camera_gotogeo_altitude.profile | 10 + .../basic/camera_navstate_full.profile | 13 + .../basic/camera_navstate_no_aim.profile | 12 + .../basic/camera_navstate_no_pitch.profile | 12 + .../basic/camera_navstate_no_up.profile | 12 + .../basic/camera_navstate_no_yaw.profile | 12 + tests/profile/basic/deltatimes.profile | 10 + tests/profile/basic/keybindings.profile | 29 + tests/profile/basic/mark_nodes.profile | 6 + tests/profile/basic/meta_empty.profile | 11 + tests/profile/basic/meta_full.profile | 11 + tests/profile/basic/meta_no_author.profile | 10 + .../profile/basic/meta_no_description.profile | 10 + tests/profile/basic/meta_no_license.profile | 10 + tests/profile/basic/meta_no_name.profile | 10 + tests/profile/basic/meta_no_url.profile | 10 + tests/profile/basic/meta_no_version.profile | 10 + tests/profile/basic/modules.profile | 19 + tests/profile/basic/properties.profile | 35 + tests/profile/basic/time_absolute.profile | 7 + tests/profile/basic/time_relative.profile | 7 + .../profile/basic_additional_scripts.profile | 7 - tests/profile/basic_assets.profile | 7 - tests/profile/basic_camera_gotogeo.profile | 5 - .../basic_camera_gotogeo_altitude.profile | 5 - tests/profile/basic_camera_navstate.profile | 5 - tests/profile/basic_deltatimes.profile | 9 - tests/profile/basic_keybindings.profile | 7 - tests/profile/basic_mark_nodes.profile | 7 - tests/profile/basic_meta.profile | 10 - tests/profile/basic_modules.profile | 7 - tests/profile/basic_properties.profile | 10 - tests/profile/basic_time_absolute.profile | 5 - tests/profile/basic_time_relative.profile | 5 - .../basic_version_one_component.profile | 2 - .../basic_version_two_components.profile | 2 - .../camera/camera_gotogeo_altitude.profile | 10 + .../camera/gotogeo_missing_anchor.profile | 9 + .../camera/gotogeo_missing_latitude.profile | 9 + .../camera/gotogeo_missing_longitude.profile | 9 + .../camera/gotogeo_wrongtype_altitude.profile | 10 + .../camera/gotogeo_wrongtype_anchor.profile | 10 + .../camera/gotogeo_wrongtype_latitude.profile | 10 + .../gotogeo_wrongtype_longitude.profile | 10 + .../camera/navstate_missing_anchor.profile | 12 + .../camera/navstate_missing_frame.profile | 12 + .../camera/navstate_missing_position.profile | 12 + .../navstate_missing_position_x.profile | 13 + .../navstate_missing_position_y.profile | 13 + .../navstate_missing_position_z.profile | 13 + .../camera/navstate_missing_up_x.profile | 13 + .../camera/navstate_missing_up_y.profile | 13 + .../camera/navstate_missing_up_z.profile | 13 + .../camera/navstate_wrongtype_aim.profile | 13 + .../camera/navstate_wrongtype_anchor.profile | 13 + .../camera/navstate_wrongtype_frame.profile | 13 + .../camera/navstate_wrongtype_pitch.profile | 13 + .../navstate_wrongtype_position.profile | 13 + .../navstate_wrongtype_position_x.profile | 13 + .../navstate_wrongtype_position_y.profile | 13 + .../navstate_wrongtype_position_z.profile | 13 + .../camera/navstate_wrongtype_up.profile | 13 + .../camera/navstate_wrongtype_up_x.profile | 13 + .../camera/navstate_wrongtype_up_y.profile | 13 + .../camera/navstate_wrongtype_up_z.profile | 13 + .../camera/navstate_wrongtype_yaw.profile | 13 + .../error/camera/wrongvalue_type.profile | 6 + .../error/deltatimes/wrongtype_value.profile | 6 + .../keybinding/missing_documentation.profile | 12 + .../error/keybinding/missing_guipath.profile | 12 + .../error/keybinding/missing_islocal.profile | 12 + .../error/keybinding/missing_key.profile | 12 + .../error/keybinding/missing_name.profile | 12 + .../keybinding/missing_script - Copy.profile | 13 + .../error/keybinding/missing_script.profile | 12 + .../wrongtype_documentation.profile | 13 + .../keybinding/wrongtype_guipath.profile | 13 + .../keybinding/wrongtype_islocal.profile | 13 + .../error/keybinding/wrongtype_name.profile | 13 + .../error/keybinding/wrongtype_script.profile | 13 + .../error/keybinding/wrongvalue_key.profile | 13 + .../keybinding/wrongvalue_modifier.profile | 29 + .../meta/wrong_parameter_value_type.profile | 6 + .../profile/error/module/missing_name.profile | 8 + .../wrongtype_loadedInstruction.profile | 10 + .../error/module/wrongtype_name.profile | 10 + .../wrongtype_notLoadedInstruction.profile | 10 + .../error/property/missing_name.profile | 9 + .../error/property/missing_name_value.profile | 8 + .../error/property/missing_value.profile | 9 + .../error/property/wrongtype_name.profile | 10 + .../error/property/wrongtype_value.profile | 10 + .../error/property/wrongvalue_type.profile | 10 + .../error/time/absolute_missing_value.profile | 6 + tests/profile/error/time/missing_type.profile | 5 + .../error/time/relative_missing_value.profile | 6 + .../error/time/too_few_parameters.profile | 6 + .../error/time/wrongvalue_type.profile | 7 + .../error/version/missing_major.profile | 3 + .../error/version/missing_minor.profile | 3 + .../error/version/wrongtype_major.profile | 3 + .../version/wrongtype_major_minor.profile | 3 + .../error/version/wrongtype_minor.profile | 3 + .../error_asset_too_few_parameters.profile | 5 - .../error_asset_too_many_parameters.profile | 5 - ..._camera_gotogeo_too_few_parameters.profile | 5 - ...camera_gotogeo_too_many_parameters.profile | 5 - ...camera_navstate_too_few_parameters.profile | 5 - ...amera_navstate_too_many_parameters.profile | 5 - ...ameter_too_few_components_position.profile | 5 - ...ng_parameter_too_few_components_up.profile | 5 - ...meter_too_many_components_position.profile | 5 - ...avstate_wrong_parameter_type_pitch.profile | 5 - ..._navstate_wrong_parameter_type_yaw.profile | 5 - ...eter_wrong_component_type_position.profile | 5 - ..._parameter_wrong_component_type_up.profile | 5 - ..._camera_wrong_parameter_value_type.profile | 5 - ...tatimes_wrong_parameter_value_type.profile | 8 - ...rror_keybinding_too_few_parameters.profile | 5 - ...ror_keybinding_too_many_parameters.profile | 5 - ...binding_wrong_parameter_type_local.profile | 5 - ...ybinding_wrong_parameter_value_key.profile | 7 - ...ing_wrong_parameter_value_modifier.profile | 7 - ...or_meta_wrong_parameter_value_type.profile | 5 - .../error_missing_separator_line.profile | 4 - .../error_module_too_few_parameters.profile | 5 - .../error_module_too_many_parameters.profile | 5 - .../error_property_too_few_parameters.profile | 5 - ...error_property_too_many_parameters.profile | 5 - ...roperty_wrong_parameter_value_type.profile | 5 - .../error_time_too_few_parameters.profile | 5 - .../error_time_too_many_parameters.profile | 5 - ...or_time_wrong_parameter_value_type.profile | 5 - .../profile/error_two_camera_sections.profile | 8 - tests/profile/error_two_meta_sections.profile | 18 - tests/profile/error_two_time_sections.profile | 8 - .../error_two_version_sections.profile | 5 - .../profile/error_unrecognized_header.profile | 7 - .../error_version_malformed_component.profile | 2 - tests/profile/error_version_not_first.profile | 7 - .../error_version_too_many_components.profile | 2 - tests/profile/integration/full_test.profile | 116 ++ tests/profile/integration_full_test.profile | 53 - ...ntegration_full_test_permutation_1.profile | 54 - ...gration_full_test_permutation_base.profile | 53 - tests/profile/minimal.profile | 5 +- tests/test_profile.cpp | 1125 +++++++++------ tests/test_spicemanager.cpp | 1 - tests/test_timequantizer.cpp | 2 +- 161 files changed, 2366 insertions(+), 1766 deletions(-) delete mode 100644 data/assets/scene/milkyway/constellations/constellation_data.csv create mode 100644 tests/profile/basic/additional_scripts.profile create mode 100644 tests/profile/basic/assets.profile create mode 100644 tests/profile/basic/camera_gotogeo.profile create mode 100644 tests/profile/basic/camera_gotogeo_altitude.profile create mode 100644 tests/profile/basic/camera_navstate_full.profile create mode 100644 tests/profile/basic/camera_navstate_no_aim.profile create mode 100644 tests/profile/basic/camera_navstate_no_pitch.profile create mode 100644 tests/profile/basic/camera_navstate_no_up.profile create mode 100644 tests/profile/basic/camera_navstate_no_yaw.profile create mode 100644 tests/profile/basic/deltatimes.profile create mode 100644 tests/profile/basic/keybindings.profile create mode 100644 tests/profile/basic/mark_nodes.profile create mode 100644 tests/profile/basic/meta_empty.profile create mode 100644 tests/profile/basic/meta_full.profile create mode 100644 tests/profile/basic/meta_no_author.profile create mode 100644 tests/profile/basic/meta_no_description.profile create mode 100644 tests/profile/basic/meta_no_license.profile create mode 100644 tests/profile/basic/meta_no_name.profile create mode 100644 tests/profile/basic/meta_no_url.profile create mode 100644 tests/profile/basic/meta_no_version.profile create mode 100644 tests/profile/basic/modules.profile create mode 100644 tests/profile/basic/properties.profile create mode 100644 tests/profile/basic/time_absolute.profile create mode 100644 tests/profile/basic/time_relative.profile delete mode 100644 tests/profile/basic_additional_scripts.profile delete mode 100644 tests/profile/basic_assets.profile delete mode 100644 tests/profile/basic_camera_gotogeo.profile delete mode 100644 tests/profile/basic_camera_gotogeo_altitude.profile delete mode 100644 tests/profile/basic_camera_navstate.profile delete mode 100644 tests/profile/basic_deltatimes.profile delete mode 100644 tests/profile/basic_keybindings.profile delete mode 100644 tests/profile/basic_mark_nodes.profile delete mode 100644 tests/profile/basic_meta.profile delete mode 100644 tests/profile/basic_modules.profile delete mode 100644 tests/profile/basic_properties.profile delete mode 100644 tests/profile/basic_time_absolute.profile delete mode 100644 tests/profile/basic_time_relative.profile delete mode 100644 tests/profile/basic_version_one_component.profile delete mode 100644 tests/profile/basic_version_two_components.profile create mode 100644 tests/profile/error/camera/camera_gotogeo_altitude.profile create mode 100644 tests/profile/error/camera/gotogeo_missing_anchor.profile create mode 100644 tests/profile/error/camera/gotogeo_missing_latitude.profile create mode 100644 tests/profile/error/camera/gotogeo_missing_longitude.profile create mode 100644 tests/profile/error/camera/gotogeo_wrongtype_altitude.profile create mode 100644 tests/profile/error/camera/gotogeo_wrongtype_anchor.profile create mode 100644 tests/profile/error/camera/gotogeo_wrongtype_latitude.profile create mode 100644 tests/profile/error/camera/gotogeo_wrongtype_longitude.profile create mode 100644 tests/profile/error/camera/navstate_missing_anchor.profile create mode 100644 tests/profile/error/camera/navstate_missing_frame.profile create mode 100644 tests/profile/error/camera/navstate_missing_position.profile create mode 100644 tests/profile/error/camera/navstate_missing_position_x.profile create mode 100644 tests/profile/error/camera/navstate_missing_position_y.profile create mode 100644 tests/profile/error/camera/navstate_missing_position_z.profile create mode 100644 tests/profile/error/camera/navstate_missing_up_x.profile create mode 100644 tests/profile/error/camera/navstate_missing_up_y.profile create mode 100644 tests/profile/error/camera/navstate_missing_up_z.profile create mode 100644 tests/profile/error/camera/navstate_wrongtype_aim.profile create mode 100644 tests/profile/error/camera/navstate_wrongtype_anchor.profile create mode 100644 tests/profile/error/camera/navstate_wrongtype_frame.profile create mode 100644 tests/profile/error/camera/navstate_wrongtype_pitch.profile create mode 100644 tests/profile/error/camera/navstate_wrongtype_position.profile create mode 100644 tests/profile/error/camera/navstate_wrongtype_position_x.profile create mode 100644 tests/profile/error/camera/navstate_wrongtype_position_y.profile create mode 100644 tests/profile/error/camera/navstate_wrongtype_position_z.profile create mode 100644 tests/profile/error/camera/navstate_wrongtype_up.profile create mode 100644 tests/profile/error/camera/navstate_wrongtype_up_x.profile create mode 100644 tests/profile/error/camera/navstate_wrongtype_up_y.profile create mode 100644 tests/profile/error/camera/navstate_wrongtype_up_z.profile create mode 100644 tests/profile/error/camera/navstate_wrongtype_yaw.profile create mode 100644 tests/profile/error/camera/wrongvalue_type.profile create mode 100644 tests/profile/error/deltatimes/wrongtype_value.profile create mode 100644 tests/profile/error/keybinding/missing_documentation.profile create mode 100644 tests/profile/error/keybinding/missing_guipath.profile create mode 100644 tests/profile/error/keybinding/missing_islocal.profile create mode 100644 tests/profile/error/keybinding/missing_key.profile create mode 100644 tests/profile/error/keybinding/missing_name.profile create mode 100644 tests/profile/error/keybinding/missing_script - Copy.profile create mode 100644 tests/profile/error/keybinding/missing_script.profile create mode 100644 tests/profile/error/keybinding/wrongtype_documentation.profile create mode 100644 tests/profile/error/keybinding/wrongtype_guipath.profile create mode 100644 tests/profile/error/keybinding/wrongtype_islocal.profile create mode 100644 tests/profile/error/keybinding/wrongtype_name.profile create mode 100644 tests/profile/error/keybinding/wrongtype_script.profile create mode 100644 tests/profile/error/keybinding/wrongvalue_key.profile create mode 100644 tests/profile/error/keybinding/wrongvalue_modifier.profile create mode 100644 tests/profile/error/meta/wrong_parameter_value_type.profile create mode 100644 tests/profile/error/module/missing_name.profile create mode 100644 tests/profile/error/module/wrongtype_loadedInstruction.profile create mode 100644 tests/profile/error/module/wrongtype_name.profile create mode 100644 tests/profile/error/module/wrongtype_notLoadedInstruction.profile create mode 100644 tests/profile/error/property/missing_name.profile create mode 100644 tests/profile/error/property/missing_name_value.profile create mode 100644 tests/profile/error/property/missing_value.profile create mode 100644 tests/profile/error/property/wrongtype_name.profile create mode 100644 tests/profile/error/property/wrongtype_value.profile create mode 100644 tests/profile/error/property/wrongvalue_type.profile create mode 100644 tests/profile/error/time/absolute_missing_value.profile create mode 100644 tests/profile/error/time/missing_type.profile create mode 100644 tests/profile/error/time/relative_missing_value.profile create mode 100644 tests/profile/error/time/too_few_parameters.profile create mode 100644 tests/profile/error/time/wrongvalue_type.profile create mode 100644 tests/profile/error/version/missing_major.profile create mode 100644 tests/profile/error/version/missing_minor.profile create mode 100644 tests/profile/error/version/wrongtype_major.profile create mode 100644 tests/profile/error/version/wrongtype_major_minor.profile create mode 100644 tests/profile/error/version/wrongtype_minor.profile delete mode 100644 tests/profile/error_asset_too_few_parameters.profile delete mode 100644 tests/profile/error_asset_too_many_parameters.profile delete mode 100644 tests/profile/error_camera_gotogeo_too_few_parameters.profile delete mode 100644 tests/profile/error_camera_gotogeo_too_many_parameters.profile delete mode 100644 tests/profile/error_camera_navstate_too_few_parameters.profile delete mode 100644 tests/profile/error_camera_navstate_too_many_parameters.profile delete mode 100644 tests/profile/error_camera_navstate_wrong_parameter_too_few_components_position.profile delete mode 100644 tests/profile/error_camera_navstate_wrong_parameter_too_few_components_up.profile delete mode 100644 tests/profile/error_camera_navstate_wrong_parameter_too_many_components_position.profile delete mode 100644 tests/profile/error_camera_navstate_wrong_parameter_type_pitch.profile delete mode 100644 tests/profile/error_camera_navstate_wrong_parameter_type_yaw.profile delete mode 100644 tests/profile/error_camera_navstate_wrong_parameter_wrong_component_type_position.profile delete mode 100644 tests/profile/error_camera_navstate_wrong_parameter_wrong_component_type_up.profile delete mode 100644 tests/profile/error_camera_wrong_parameter_value_type.profile delete mode 100644 tests/profile/error_deltatimes_wrong_parameter_value_type.profile delete mode 100644 tests/profile/error_keybinding_too_few_parameters.profile delete mode 100644 tests/profile/error_keybinding_too_many_parameters.profile delete mode 100644 tests/profile/error_keybinding_wrong_parameter_type_local.profile delete mode 100644 tests/profile/error_keybinding_wrong_parameter_value_key.profile delete mode 100644 tests/profile/error_keybinding_wrong_parameter_value_modifier.profile delete mode 100644 tests/profile/error_meta_wrong_parameter_value_type.profile delete mode 100644 tests/profile/error_missing_separator_line.profile delete mode 100644 tests/profile/error_module_too_few_parameters.profile delete mode 100644 tests/profile/error_module_too_many_parameters.profile delete mode 100644 tests/profile/error_property_too_few_parameters.profile delete mode 100644 tests/profile/error_property_too_many_parameters.profile delete mode 100644 tests/profile/error_property_wrong_parameter_value_type.profile delete mode 100644 tests/profile/error_time_too_few_parameters.profile delete mode 100644 tests/profile/error_time_too_many_parameters.profile delete mode 100644 tests/profile/error_time_wrong_parameter_value_type.profile delete mode 100644 tests/profile/error_two_camera_sections.profile delete mode 100644 tests/profile/error_two_meta_sections.profile delete mode 100644 tests/profile/error_two_time_sections.profile delete mode 100644 tests/profile/error_two_version_sections.profile delete mode 100644 tests/profile/error_unrecognized_header.profile delete mode 100644 tests/profile/error_version_malformed_component.profile delete mode 100644 tests/profile/error_version_not_first.profile delete mode 100644 tests/profile/error_version_too_many_components.profile create mode 100644 tests/profile/integration/full_test.profile delete mode 100644 tests/profile/integration_full_test.profile delete mode 100644 tests/profile/integration_full_test_permutation_1.profile delete mode 100644 tests/profile/integration_full_test_permutation_base.profile diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index 3d3835c38c..f54b2fc6f0 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit 3d3835c38c8b87972f406ed44af1b5b2d48b1600 +Subproject commit f54b2fc6f01f42bb0158734a3cfc565c3d5cf281 diff --git a/data/assets/scene/milkyway/constellations/constellation_data.csv b/data/assets/scene/milkyway/constellations/constellation_data.csv deleted file mode 100644 index 7c02f310de..0000000000 --- a/data/assets/scene/milkyway/constellations/constellation_data.csv +++ /dev/null @@ -1,85 +0,0 @@ -Data about Constellations columns are: group, name, x, y, z, scale, imageName, rotX, rotY, rotZ, centerStar -normal,Ori,Orion,-550.8742,-259.3621,-188.9620,1.5,Ori.png,1.128407,1.058407,1.668407,HD37128 -zodiac,Tau,Taurus,-18.7277,-0.3175,-6.9092,1.2,Tau.png,1.198407,0.908407,1.378407,Aldebran -zodiac,Ari,Aries,-13.2892,9.4519,-11.9378,0.8,Ari.png,0.668407,0.538407,0.518407,Hamal -zodiac,Gem,Gemini,-362.5493,-102.2245,79.4030,0.85,Gem.png,-0.731593,2.268407,-0.451593,Mekbuda -zodiac,Cnc,Cancer,-30.9209,-16.4584,22.6601,0.8,Cnc.png,-1.151593,1.888407,-1.041593,HD74442 -zodiac,Leo,Leo,-17.9030,-13.2719,31.4196,1.33,Leo.png,-0.131593,2.448407,0.418407,HD89484 -zodiac,Vir,Virgo,36.5809,-35.1877,62.3341,1.5,Vir.png,-0.371593,3.138407,0.518407,HD116658 -zodiac,Lib,Libra,17.5393,-6.2768,14.5916,1.0,Lib.png,-1.011593,3.138407,1.318407,HD130819 -zodiac,Sco,Scorpius,137.4378,-19.4456,37.3606,1.2,Sco.png,1.698407,-1.001593,-1.751593,HD148478 -zodiac,Sgr,Sagittarius,66.2304,11.1498,-14.8095,1.2,Sgr.png,1.728407,-1.321593,-1.751593,HD175191 -zodiac,Cap,Capricornus,32.9799,20.0621,-29.3945,1.3,Cap.png,1.158407,-0.881593,-0.561593,HD200761 -zodiac,Aqr,Aquarius,86.5090,149.4078,-155.8102,1.2,Aqr.png,-2.921593,-2.391593,-2.551593,-2.511593 -zodiac,Psc,Pisces,-28.0235,45.3150,-76.8893,1.6,Psc.png,0.458407,-0.001593,0.618407,HD4656 -northern,Uma,Ursa Major,-12.0503,7.1931,19.8974,1.6,UMa.png,0.748407,2.398407,0.658407,HD95418 -northern,Dra,Draco,-1.4340,20.6566,23.5098,1.9,Dra.png,0.658407,-2.541593,1.058407,HD137759 -southern,Ant,Antila,-0.2233,-103.8908,42.7940,1.3,Ant.png,1.848407,0.198407,-3.141593,HD90610 -southern,Crv,Corvus,8.0442,-16.8858,19.3984,1.1,Crv.png,2.198407,-0.041593,-2.221593,HD108767 -southern,Cet,Cetus,-28.7960,7.2425,-73.6693,1.5,Cet.png,0.238407,0.368407,0.688407,HD11353 -southern,Cha,Chameleon,53.5121,-108.3624,-38.1807,1.1,Cha.png,-1.801593,2.738407,0.448407,HD92305 -northern,Cam,Camelopardalis,-304.8155,179.0620,71.1454,1.7,Cam.png,2.128407,1.228407,1.478407,HD31910 -equatorial,Aql,Aquila,11.7741,9.7467,-1.6418,1.0,Aql.png,-2.601593,-2.511593,-3.141593,HD182640 -southern,Aps,Apus,31.6370,-32.5620,-16.5786,1.1,Aps.png,-1.691593,-2.281593,0.838407,HD149324 -northern,Lyn,Lynx,-98.3174,4.4830,67.2289,1.2,Lyn.png,1.688407,1.768407,1.668407,HD70272 -southern,Phe,Phoenix,5.0172,-4.2096,-22.8088,1.5,Phe.png,-3.141593,3.138407,-3.141593,HD6595 -northern,Cyg,Cygnus,78.7445,375.2440,12.4995,1.4,Cyg.png,1.668407,-0.931593,-0.261593,HD194093 -southern,Cen,Centaurus,20.1398,-33.1830,9.5915,2.7,Cen.png,-1.291593,3.088407,0.458407,HD110304 -northern,Aur,Auriga,-12.3062,3.8595,1.0302,1.5,Aur.png,1.378407,1.108407,1.178407,HD34029 -northern,Peg,Pegasus,0.9791,32.5947,-27.7339,2.42,Peg.png,0.918407,-0.221593,-0.191593,HD218045 -southern,Hya,Hydra,-2.9043,-33.5496,25.8962,3,Hya.png,-0.531593,2.838407,0.368407,HD93813 -southern,Oct,Octans,22.0434,-27.8601,-24.3108,1.0,Oct.png,-0.911593,0.398407,1.198407,HD214846 -southern,Nor,Norma,34.9251,-17.5643,0.0068,1.0,Nor.png,-1.631593,-2.421593,1.298407,HD146686 -southern,Mus,Musca,48.8888,-79.2952,-10.2828,1.25,Mus.png,-1.871593,3.138407,0.358407,HD109668 -southern,Hyi,Hydrus,3.2767,-4.7183,-4.7829,1.1,Hyi.png,2.438407,-3.141593,-2.381593,HD2151 -northern,Lac,Lacerta,-6.0878,30.5794,-3.6064,1.0,Lac.png,-1.521593,-2.391593,3.138407,HD213558 -equatorial,Lep,Lepus,-212.6297,-184.4909,-132.1156,1.0,Lep.png,-1.801593,-2.351593,-0.861593,HD36673 -southern,Lup,Lupus,129.1166,-102.2983,33.3251,1.2,Lup.png,-1.191593,-2.391593,0.798407,HD129056 -southern,Men,Mensa,2.4149,-8.5586,-4.8892,1.0,Men.png,-2.101593,-2.781593,0.828407,HD43834 -southern,Mic,Microscopium,51.0335,11.1671,-44.3692,1.0,Mic.png,0.728407,-0.831593,-0.561593,HD199951 -equatorial,Mon,Monoceros,-93.0725,-66.8909,8.6548,1.2,Mon.png,-1.331593,1.988407,-0.891593,HD55185 -southern,Pav,Pavo,4.4549,-2.5959,-3.2739,1.3,Pav.png,-2.391593,-2.171593,1.648407,HD190248 -southern,Ind,Indus,133.6149,-53.5569,-115.9552,1.5,Ind.png,-2.031593,-1.491593,1.758407,HD198700 -northern,LMi,Leo Minor,-23.3948,-2.5770,38.0756,1.1,LMi.png,-3.141593,0.478407,-2.201593,HD90537 -northern,Lyr,Lyra,2.8086,6.7630,2.5555,1.0,Lyr.png,-1.831593,-2.091593,3.141500,HD172167 -northern,Her,Hercules,14.0526,14.9773,12.5478,1.3,Her.png,-1.511593,-1.811593,2.288407,HD156164 -southern,Gru,Grus,18.6528,-3.2893,-24.6602,1.3,Gru.png,-3.141593,-2.511593,-2.901593,HD209952 -southern,Crt,Crater,1.5886,-43.9831,40.3390,1.3,Crt.png,-0.521593,3.140000,0.588407,HD98430 -northern,Del,Delphinus,14.8599,24.6150,-8.0550,1.2,Del.png,1.308407,-0.951593,-0.241593,HD196524 -southern,Dor,Dorado,-0.6460,-9.3172,-6.9654,1.2,Dor.png,2.118407,1.768407,-2.901593,HD33262 -northern,Equ,Equuleus,27.7363,41.7071,-27.4371,1.2,Equ.png,-1.801593,-2.511593,2.558407,HD202447 -southern,Eri,Eridanus,-37.5153,-23.5231,-65.6368,2.1,Eri.png,0.128407,0.698407,0.998407,HD20720 -southern,For,Fornax,-14.0351,-17.8282,-46.5514,1.4,For.png,3.138407,2.678407,-2.351593,HD17652 -southern,Hor,Horologium,2.1021,-27.1310,-40.5136,1.2,Hor.png,-3.141593,2.468407,-2.191593,HD16920 -southern,Pyx,Pyxis,-66.7424,-248.9639,26.0445,1.2,Pyx.png,1.838407,-1.651593,2.708407,HD74575 -southern,Ret,Reticulum,2.8130,-37.2904,-33.2644,1.5,Ret.png,1.998407,2.188407,-2.591593,HD27256 -northern,Sge,Sagitta,44.3886,70.9446,-7.6264,1.2,Sge.png,-0.741593,-2.231593,2.108407,HD189319 -southern,Scl,Sculptor,21.6545,-6.8861,-166.5240,1.3,Scl.png,-0.071593,-0.221593,0.638407,HD2429 -southern,Sct,Scutum,48.8939,21.5158,-0.1629,1.2,Sct.png,1.188407,-1.271593,-0.971593,HD171443 -southern,Tuc,Tucana,35.3950,-20.2535,-45.2324,1.1,Tuc.png,-0.351593,-0.161593,0.308407,HD211416 -northern,Tri,Triangulum,-26.6263,21.9119,-16.2254,1.2,Tri.png,1.168407,0.218407,0.558407,HD13161 -southern,TrA,Triangulum Australe,96.2283,-76.4459,-33.5257,1.2,TrA.png,-1.991593,-2.491593,1.128407,HD150798 -southern,Tel,Telescopium,72.3444,-14.5016,-20.0248,1.2,Tel.png,-0.461593,-1.731593,0.298407,HD169467 -southern,Ara,Ara,164.9273,-75.6246,-35.3100,1.1,Ara.png,-1.381593,-2.131593,1.048407,HD157244 -southern,Cae,Caelum,-6.0961,-13.7926,-13.3392,1.0,Cae.png,-0.661593,0.948407,0.418407,HD29875 -southern,CMa,Canis Major,-1.7693,-1.9125,-0.4074,1.3,CMa.png,1.128407,1.048407,1.878407,HD48915 -northern,CMi,Canis Minor,-2.8348,-1.8906,0.7881,1.2,CMi.png,2.538407,1.138407,-3.141593,HD61421 -southern,Vol,Volans,37.6000,-182.7856,-62.6559,1.2,Vol.png,-2.441593,1.988407,-0.351593,HD68520 -northern,UMi,Ursa Minor,-11.3527,27.2100,25.1835,1.3,UMi.png,-2.491593,-0.581593,-2.381593,HD131873 -northern,And,Andromdeda,-32.8276,43.3946,-27.8475,1.6,And.png,-2.021593,-3.141593,-2.521593,HD6860 -northern,Boo,Bootes,11.2468,14.9864,30.4945,2.0,Boo.png,-3.141593,-0.601593,-2.361593,HD135722 -northern,Vul,Vulpecula,46.7540,77.7780,5.3953,1.1,Vul.png,-2.301593,-2.061593,-3.141593,HD131873 -northern,CVn,Canes Venatici,-3.1198,5.7935,33.1368,1.3,CVn.png,0.148407,3.138407,0.428407,HD112413 -southern,Cir,Circinus,11.4255,-11.6937,-1.3129,1.0,Cir.png,1.448407,-0.391593,-2.211593,HD128898 -northern,Com,Coma Berenices,1.9257,-1.2062,12.2465,1.4,Com.png,3.138407,-0.051593,-2.711593,HD114378 -southern,CrA,Corona Australis,146.1322,-4.7492,-53.7124,1.0,CrA.png,-3.141593,-2.021593,-3.141593,HD178345 -northern,CrB,Corona Borealis,33.5737,32.0314,52.9729,1.3,CrB.png,-3.141593,-0.601593,-2.271593,HD143107 -northern,Cas,Cassiopeia,-36.3073,59.4424,-7.6926,1.4,Cas.png,-1.431593,3.128407,-2.331593,HD3712 -northern,Cep,Cepheus,-2.8178,14.4985,2.3848,1.7,Cep.png,-1.331593,-2.291593,-2.931593,HD203280 -southern,Car,Carina Vela Puppis,14.1325,-188.6018,-42.2785,2.0,Car.png,2.078407,1.048407,-3.111593,HD71129 -northern,Col,Columba,-11.2568,-20.5973,-11.9895,1.0,Col.png,2.518407,1.358407,-2.981593,HD39425 -northern,Per,Perseus,-139.8202,79.8063,-16.2631,1.3,Per.png,-1.751593,2.428407,-2.411593,HD22928 -northern,Oph,Ophiuchus,127.9419,14.0822,56.2015,3.2,Oph.png,2.178407,-0.781593,-1.681593,HD149757 -southern,PsA,Piscis Austrinus,99.9977,47.6679,-199.6345,1.0,PsA.png,3.138407,-2.541593,-2.881593,HD214748 -southern,Cru,Crux,49.3509,-85.0446,-0.6223,1.1,Cru.png,1.718407,0.048407,-2.741593,HD108248 -southern,Pic,Pictor,-4.5417,-45.5649,-27.1768,1.0,Pic.png,2.568407,2.138407,-2.081593,HD39523 diff --git a/data/profiles/default.profile b/data/profiles/default.profile index cedf4ad6d7..d9cd9a8631 100644 --- a/data/profiles/default.profile +++ b/data/profiles/default.profile @@ -1,22 +1,30 @@ -#Version -1.0 - -#Asset -base -scene/solarsystem/planets/earth/earth earthAsset -scene/solarsystem/planets/earth/satellites/satellites - -#Property -setPropertyValue {earth_satellites}.Renderable.Enabled false - -#Time -relative -1d - -#Camera -goToGeo earthAsset.Earth.Identifier 58.5877 16.1924 20000000 - -#MarkNodes -Earth -Mars -Moon -Sun +{ + "version": { + "major": 1, + "minor": 0 + }, + "assets": [ + "base", + "scene/solarsystem/planets/earth/earth", + "scene/solarsystem/planets/earth/satellites/satellites" + ], + "properties": [ + { + "type": "setPropertyValue", + "name": "{earth_satellites}.Renderable.Enabled", + "value": "false" + } + ], + "time": { + "type": "relative", + "value": "-1d" + }, + "camera": { + "type": "goToGeo", + "anchor": "Earth", + "latitude": 58.5877, + "longitude": 16.1924, + "altitude": 20000000 + }, + "mark_nodes": [ "Earth", "Mars", "Moon", "Sun" ] +} diff --git a/ext/ghoul b/ext/ghoul index f568acc5fe..6e9bb084a1 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit f568acc5fee29a5b0c654f183baddcb7a061e7a6 +Subproject commit 6e9bb084a147d85faf7f28980251752d6dae5f98 diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index c70df31be3..eccf6a0dd7 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,14 @@ namespace scripting { struct LuaLibrary; } class Profile { public: + struct ParsingError : public ghoul::RuntimeError { + enum class Severity { Info, Warning, Error }; + + explicit ParsingError(Severity severity, std::string msg); + + Severity severity; + }; + // Version struct Version { int major = 0; @@ -47,20 +56,16 @@ public: }; struct Module { std::string name; - std::string loadedInstruction; - std::string notLoadedInstruction; + std::optional loadedInstruction; + std::optional notLoadedInstruction; }; struct Meta { - std::string name; - std::string version; - std::string description; - std::string author; - std::string url; - std::string license; - }; - struct Asset { - std::string path; - std::string name; + std::optional name; + std::optional version; + std::optional description; + std::optional author; + std::optional url; + std::optional license; }; struct Property { enum class SetType { @@ -87,13 +92,13 @@ public: }; Type type; - std::string time; + std::string value; }; struct CameraNavState { static constexpr const char* Type = "setNavigationState"; std::string anchor; - std::string aim; + std::optional aim; std::string referenceFrame; glm::dvec3 position; std::optional up; @@ -109,9 +114,9 @@ public: std::optional altitude; }; using CameraType = std::variant; - + Profile() = default; - Profile(const std::vector& content); + explicit Profile(const std::string& content); std::string serialize() const; std::string convertToScene() const; @@ -147,7 +152,7 @@ private: Version version = CurrentVersion; std::vector modules; std::optional meta; - std::vector assets; + std::vector assets; std::vector properties; std::vector keybindings; std::optional