diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index 301f507912..deef5b20f6 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -27,18 +27,10 @@ #include #include -#include #include -#include - #include -#include -#include namespace openspace::interaction { -#define RECORD_BINARY - -class KeyframeNavigator; class SessionRecording : public properties::PropertyOwner { public: @@ -57,121 +49,137 @@ public: using StateChangeCallback = std::function; SessionRecording(); + ~SessionRecording(); + /** - * Used to de-initialize the session recording feature. Any recording or playback - * in progress will be stopped, files closed, and keyframes in memory deleted. - */ + * Used to de-initialize the session recording feature. Any recording or playback + * in progress will be stopped, files closed, and keyframes in memory deleted. + */ void deinitialize(); /** - * This is called with every rendered frame. If in recording state, the camera - * state will be saved to the recording file (if its state has changed since last). - * If in playback state, the next keyframe will be used (if it is time to do so). - */ + * This is called with every rendered frame. If in recording state, the camera + * state will be saved to the recording file (if its state has changed since last). + * If in playback state, the next keyframe will be used (if it is time to do so). + */ void preSynchronization(); /** - * Starts a recording session, which will save data to the provided filename - * according to the data format specified, and will continue until recording is - * stopped using stopRecording() method. - * \param filename file saved with recorded keyframes. - * \returns true if recording to file starts without errors. - */ + * Starts a recording session, which will save data to the provided filename + * according to the data format specified, and will continue until recording is + * stopped using stopRecording() method. + * + * \param filename file saved with recorded keyframes. + * + * \return \c true if recording to file starts without errors + */ bool startRecording(const std::string& filename); /** - * Starts a recording session, which will save data to the provided filename - * in ASCII data format until recording is stopped using stopRecording() method. - * \param filename file saved with recorded keyframes. - * \returns true if recording to file starts without errors. - */ + * Starts a recording session, which will save data to the provided filename + * in ASCII data format until recording is stopped using stopRecording() method. + * + * \param filename file saved with recorded keyframes. + * + * \return \c true if recording to file starts without errors + */ void setRecordDataFormat(RecordedDataMode dataMode); /** - * Used to stop a recording in progress. If open, the recording file will be closed, - * and all keyframes deleted from memory. - */ + * Used to stop a recording in progress. If open, the recording file will be closed, + * and all keyframes deleted from memory. + */ void stopRecording(); /** - * Used to check if a session recording is in progress. - * \returns true if recording is in progress. - */ + * Used to check if a session recording is in progress. + * + * \return true if recording is in progress + */ bool isRecording() const; /** - * Starts a playback session, which can run in one of three different time modes. - * \param filename file containing recorded keyframes to play back - * \param timeMode which of the 3 time modes to use for time reference during - * \param forceSimTimeAtStart if true simulation time is forced to that of playback - * playback: recorded time, application time, or simulation time. See the LuaLibrary - * entry for SessionRecording for details on these time modes. - * \returns true if recording to file starts without errors. - */ + * Starts a playback session, which can run in one of three different time modes. + * + * \param filename file containing recorded keyframes to play back + * \param timeMode which of the 3 time modes to use for time reference during + * \param forceSimTimeAtStart if true simulation time is forced to that of playback + * playback: recorded time, application time, or simulation time. See the + * LuaLibrary entry for SessionRecording for details on these time modes + * + * \return \c true if recording to file starts without errors + */ bool startPlayback(const std::string& filename, KeyframeTimeRef timeMode, bool forceSimTimeAtStart); /** - * Used to stop a playback in progress. If open, the playback file will be closed, - * and all keyframes deleted from memory. - */ + * Used to stop a playback in progress. If open, the playback file will be closed, + * and all keyframes deleted from memory. + */ void stopPlayback(); /** - * Used to check if a session playback is in progress. - * \returns true if playback is in progress. - */ + * Used to check if a session playback is in progress. + * + * \return \c true if playback is in progress + */ bool isPlayingBack() const; /** - * Used to obtain the state of idle/recording/playback. - * \returns int value of state as defined by struct SessionState. - */ + * Used to obtain the state of idle/recording/playback. + * + * \return int value of state as defined by struct SessionState + */ SessionState state() const; /** - * Used to trigger a save of the camera states (position, rotation, focus node, - * whether it is following the rotation of a node, and timestamp). The data will - * be saved to the recording file only if a recording is currently in progress. - */ + * Used to trigger a save of the camera states (position, rotation, focus node, + * whether it is following the rotation of a node, and timestamp). The data will be + * saved to the recording file only if a recording is currently in progress. + */ void saveCameraKeyframe(); /** - * Used to trigger a save of the current timing states. The data will be saved - * to the recording file only if a recording is currently in progress. - */ + * Used to trigger a save of the current timing states. The data will be saved to the + * recording file only if a recording is currently in progress. + */ void saveTimeKeyframe(); /** - * Used to trigger a save of a script to the recording file, but only if a recording - * is currently in progress. - * \param scriptToSave String of the Lua command to be saved. - */ + * Used to trigger a save of a script to the recording file, but only if a recording + * is currently in progress. + * + * \param scriptToSave String of the Lua command to be saved + */ void saveScriptKeyframe(std::string scriptToSave); /** - * \return The Lua library that contains all Lua functions available to affect the - * interaction - */ + * \return The Lua library that contains all Lua functions available to affect the + * interaction + */ static openspace::scripting::LuaLibrary luaLibrary(); /** - * Used to request a callback for notification of playback state change. - * \param cb function handle for callback. - * \returns CallbackHandle value of callback number. - */ + * Used to request a callback for notification of playback state change. + * + * \param cb function handle for callback + * + * \return CallbackHandle value of callback number + */ CallbackHandle addStateChangeCallback(StateChangeCallback cb); /** * Removes the callback for notification of playback state change. - * \param callback function handle for the callback. - */ + * + * \param callback function handle for the callback + */ void removeStateChangeCallback(CallbackHandle handle); /** * Provides list of available playback files. - * \returns vector of filenames in recordings dir. + * + * \return vector of filenames in recordings dir */ std::vector playbackList() const; @@ -211,7 +219,6 @@ private: void saveStringToFile(const std::string& s); void saveKeyframeToFileBinary(unsigned char* bufferSource, size_t size); void findFirstCameraKeyframeInTimeline(); - std::string readHeaderElement(size_t readLen_chars); void saveKeyframeToFile(std::string entry); void addKeyframe(double timestamp, @@ -226,7 +233,7 @@ private: bool findNextFutureCameraIndex(double currTime); bool processCameraKeyframe(double now); bool processScriptKeyframe(); - bool isDataModeBinary(); + //bool isDataModeBinary(); unsigned int findIndexOfLastCameraKeyframeInTimeline(); bool doesTimelineEntryContainCamera(unsigned int index) const; std::vector> _stateChangeCallbacks; @@ -237,13 +244,6 @@ private: double getPrevTimestamp(); void cleanUpPlayback(); - const bool _usingTimeKeyframes = false; - const std::string _fileHeaderTitle = "OpenSpace_record/playback"; - static const size_t _fileHeaderVersionLength = 5; - const char _fileHeaderVersion[_fileHeaderVersionLength] = { '0', '0', '.', '8', '5' }; - const char dataFormatAsciiTag = 'A'; - const char dataFormatBinaryTag = 'B'; - RecordedDataMode _recordingDataMode = RecordedDataMode::Binary; SessionState _state = SessionState::Idle; SessionState _lastState = SessionState::Idle; @@ -271,7 +271,7 @@ private: bool _cleanupNeeded = false; - std::vector < interaction::KeyframeNavigator::CameraPose> _keyframesCamera; + std::vector _keyframesCamera; std::vector _keyframesTime; std::vector _keyframesScript; std::vector _timeline; diff --git a/include/openspace/interaction/sessionrecording.inl b/include/openspace/interaction/sessionrecording.inl index c26f12df88..0839562306 100644 --- a/include/openspace/interaction/sessionrecording.inl +++ b/include/openspace/interaction/sessionrecording.inl @@ -25,13 +25,13 @@ namespace openspace::interaction { template -T nextKeyframeObj(unsigned int index, - const std::vector& keyframeContainer, +T nextKeyframeObj(unsigned int index, const std::vector& keyframeContainer, std::function finishedCallback) { if (index >= (keyframeContainer.size() - 1)) { - if( index == (keyframeContainer.size() - 1) ) + if (index == (keyframeContainer.size() - 1)) { finishedCallback(); + } return keyframeContainer.back(); } else if (index < keyframeContainer.size()) { return keyframeContainer[index]; @@ -41,9 +41,7 @@ T nextKeyframeObj(unsigned int index, } template -T prevKeyframeObj(unsigned int index, - const std::vector& keyframeContainer) -{ +T prevKeyframeObj(unsigned int index, const std::vector& keyframeContainer) { if (index >= keyframeContainer.size()) { return keyframeContainer.back(); } else if (index > 0) { @@ -53,5 +51,4 @@ T prevKeyframeObj(unsigned int index, } } - } // namespace openspace::interaction diff --git a/modules/server/include/topics/sessionrecordingtopic.h b/modules/server/include/topics/sessionrecordingtopic.h index 96a0529ed1..ffd5ff9bf1 100644 --- a/modules/server/include/topics/sessionrecordingtopic.h +++ b/modules/server/include/topics/sessionrecordingtopic.h @@ -26,6 +26,7 @@ #define __OPENSPACE_MODULE_SERVER___SESSION_RECORDING_TOPIC___H__ #include + #include namespace openspace { @@ -39,7 +40,7 @@ public: bool isDone() const override; private: - const int UnsetOnChangeHandle = -1; + static const int UnsetOnChangeHandle = -1; bool _sendState; bool _sendFiles; @@ -47,7 +48,8 @@ private: // Provides the idle/recording/playback state int value in json message void sendJsonData(); - interaction::SessionRecording::SessionState _lastState; + interaction::SessionRecording::SessionState _lastState = + interaction::SessionRecording::SessionState::Idle; int _stateCallbackHandle = UnsetOnChangeHandle; bool _isDone = false; }; diff --git a/modules/server/src/topics/sessionrecordingtopic.cpp b/modules/server/src/topics/sessionrecordingtopic.cpp index ae5cfbd8bf..4b5287bf93 100644 --- a/modules/server/src/topics/sessionrecordingtopic.cpp +++ b/modules/server/src/topics/sessionrecordingtopic.cpp @@ -27,7 +27,6 @@ #include #include #include -#include #include namespace { @@ -46,9 +45,7 @@ using nlohmann::json; namespace openspace { -SessionRecordingTopic::SessionRecordingTopic() - : _lastState(interaction::SessionRecording::SessionState::Idle) -{ +SessionRecordingTopic::SessionRecordingTopic() { LDEBUG("Starting new SessionRecording state subscription"); } @@ -63,14 +60,11 @@ bool SessionRecordingTopic::isDone() const { } void SessionRecordingTopic::handleJson(const nlohmann::json& json) { - using SessionRecording = openspace::interaction::SessionRecording; - const std::string event = json.at(EventKey).get(); - if (event != SubscribeEvent && - event != UnsubscribeEvent && + if (event != SubscribeEvent && event != UnsubscribeEvent && event != RefreshEvent) { - LERROR("Unsupported event."); + LERROR("Unsupported event"); _isDone = true; return; } @@ -103,19 +97,17 @@ void SessionRecordingTopic::handleJson(const nlohmann::json& json) { sendJsonData(); - if (event == SubscribeEvent) { - if (_sendState) { - _stateCallbackHandle = global::sessionRecording.addStateChangeCallback( - [this]() { - SessionRecording::SessionState currentState = + if (event == SubscribeEvent && _sendState) { + _stateCallbackHandle = global::sessionRecording.addStateChangeCallback( + [this]() { + interaction::SessionRecording::SessionState currentState = global::sessionRecording.state(); - if (currentState != _lastState) { - sendJsonData(); - _lastState = currentState; - } + if (currentState != _lastState) { + sendJsonData(); + _lastState = currentState; } - ); - } + } + ); } } @@ -126,22 +118,22 @@ void SessionRecordingTopic::sendJsonData() { SessionRecording::SessionState state = global::sessionRecording.state(); std::string stateString; switch (state) { - case SessionRecording::SessionState::Recording: - stateString = "recording"; - break; - case SessionRecording::SessionState::Playback: - stateString = "playing"; - break; - default: - stateString = "idle"; - break; + case SessionRecording::SessionState::Recording: + stateString = "recording"; + break; + case SessionRecording::SessionState::Playback: + stateString = "playing"; + break; + default: + stateString = "idle"; + break; } stateJson[StateKey] = stateString; }; if (_sendFiles) { stateJson[FilesKey] = global::sessionRecording.playbackList(); } - if (stateJson.size() > 0) { + if (!stateJson.empty()) { _connection->sendJson(wrappedPayload(stateJson)); } } diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index ca43040f02..e3fe0320cb 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -23,33 +23,32 @@ ****************************************************************************************/ #include -#include -#include #include -#include #include #include #include -#include -#include -#include -#include -#include #include +#include +#include #include -#include #include -#include -#include #include #include #include -#include +#include 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) { T res; @@ -71,17 +70,22 @@ namespace { template <> std::string readFromPlayback(std::ifstream& stream) { - std::string res; size_t strLen; - //Read string length from file + // Read string length from file stream.read(reinterpret_cast(&strLen), sizeof(strLen)); - //Read back full string + // Read back full string std::vector temp(strLen + 1); stream.read(temp.data(), strLen); temp[strLen] = '\0'; - res = temp.data(); - return res; + return temp.data(); } + + 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 #include "sessionrecording_lua.inl" @@ -123,7 +127,7 @@ bool SessionRecording::startRecording(const std::string& filename) { _playbackActive_camera = false; _playbackActive_time = false; _playbackActive_script = false; - if (isDataModeBinary()) { + if (_recordingDataMode == RecordedDataMode::Binary) { _recordFile.open(absFilename, std::ios::binary); } else { @@ -136,13 +140,13 @@ bool SessionRecording::startRecording(const std::string& filename) { )); return false; } - _recordFile << _fileHeaderTitle; - _recordFile.write(_fileHeaderVersion, _fileHeaderVersionLength); - if (isDataModeBinary()) { - _recordFile << dataFormatBinaryTag; + _recordFile << FileHeaderTitle; + _recordFile.write(FileHeaderVersion, FileHeaderVersionLength); + if (_recordingDataMode == RecordedDataMode::Binary) { + _recordFile << DataFormatBinaryTag; } else { - _recordFile << dataFormatAsciiTag; + _recordFile << DataFormatAsciiTag; } _recordFile << '\n'; @@ -156,7 +160,7 @@ void SessionRecording::stopRecording() { _state = SessionState::Idle; LINFO("Session recording stopped"); } - //Close the recording file + // Close the recording file _recordFile.close(); } @@ -177,8 +181,8 @@ bool SessionRecording::startPlayback(const std::string& filename, if (_state == SessionState::Playback && _playbackFilename == absFilename) { LERROR(fmt::format( "Unable to start playback on file {} since it is already in playback", - filename) - ); + filename + )); return false; } } @@ -192,36 +196,36 @@ bool SessionRecording::startPlayback(const std::string& filename, _playbackLineNum = 1; _playbackFilename = absFilename; - //Open in ASCII first + // Open in ASCII first _playbackFile.open(_playbackFilename, std::ifstream::in); - //Read header - std::string readBackHeaderString = readHeaderElement(_fileHeaderTitle.length()); - if (readBackHeaderString != _fileHeaderTitle) { + // Read header + std::string readBackHeaderString = readHeaderElement(_playbackFile, FileHeaderTitle.length()); + if (readBackHeaderString != FileHeaderTitle) { LERROR("Specified playback file does not contain expected header."); cleanUpPlayback(); return false; } - readHeaderElement(_fileHeaderVersionLength); - std::string readDataMode = readHeaderElement(1); - if (readDataMode[0] == dataFormatAsciiTag) { + readHeaderElement(_playbackFile, FileHeaderVersionLength); + std::string readDataMode = readHeaderElement(_playbackFile, 1); + if (readDataMode[0] == DataFormatAsciiTag) { _recordingDataMode = RecordedDataMode::Ascii; } - else if (readDataMode[0] == dataFormatBinaryTag) { + else if (readDataMode[0] == DataFormatBinaryTag) { _recordingDataMode = RecordedDataMode::Binary; } else { LERROR("Unknown data type in header (should be Ascii or Binary)"); cleanUpPlayback(); } - std::string throwawayNewlineChar = readHeaderElement(1); + std::string throwawayNewlineChar = readHeaderElement(_playbackFile, 1); - if (isDataModeBinary()) { + if (_recordingDataMode == RecordedDataMode::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 = FileHeaderTitle.length() + FileHeaderVersionLength + + sizeof(DataFormatBinaryTag) + sizeof('\n'); _playbackFile.read(reinterpret_cast(&_keyframeBuffer), headerSize); } @@ -243,7 +247,7 @@ bool SessionRecording::startPlayback(const std::string& filename, //Set playback flags to true for all modes _playbackActive_camera = true; _playbackActive_script = true; - if (_usingTimeKeyframes) { + if (UsingTimeKeyframes) { _playbackActive_time = true; } @@ -293,13 +297,6 @@ void SessionRecording::findFirstCameraKeyframeInTimeline() { } } -std::string SessionRecording::readHeaderElement(size_t readLen_chars) { - std::vector readTemp(readLen_chars); - _playbackFile.read(&readTemp[0], readLen_chars); - return std::string(readTemp.begin(), readTemp.end()); - //return std::string(&readTemp[0], &readTemp[readLen_chars - 1]); -} - void SessionRecording::signalPlaybackFinishedForComponent(RecordedType type) { if (type == RecordedType::Camera) { _playbackActive_camera = false; @@ -314,7 +311,7 @@ void SessionRecording::signalPlaybackFinishedForComponent(RecordedType type) { LINFO("Playback finished signal: script"); } - if (!_playbackActive_camera && !_playbackActive_time && !_playbackActive_script ) { + if (!_playbackActive_camera && !_playbackActive_time && !_playbackActive_script) { _state = SessionState::Idle; _cleanupNeeded = true; LINFO("Playback session finished"); @@ -346,7 +343,7 @@ void SessionRecording::cleanUpPlayback() { _playbackFile.close(); - //Clear all timelines and keyframes + // Clear all timelines and keyframes _timeline.clear(); _keyframesCamera.clear(); _keyframesTime.clear(); @@ -361,10 +358,6 @@ void SessionRecording::cleanUpPlayback() { _cleanupNeeded = false; } -bool SessionRecording::isDataModeBinary() { - return _recordingDataMode == RecordedDataMode::Binary; -} - void SessionRecording::writeToFileBuffer(double src) { const size_t writeSize_bytes = sizeof(double); unsigned char const *p = reinterpret_cast(&src); @@ -385,14 +378,8 @@ void SessionRecording::writeToFileBuffer(unsigned char c) { } void SessionRecording::writeToFileBuffer(bool b) { - const size_t writeSize_bytes = sizeof(char); - if (b) { - _keyframeBuffer[_bufferIndex] = 1; - } - else { - _keyframeBuffer[_bufferIndex] = 0; - } - _bufferIndex += writeSize_bytes; + _keyframeBuffer[_bufferIndex] = b ? 1 : 0; + _bufferIndex += sizeof(char); } void SessionRecording::saveStringToFile(const std::string& s) { @@ -411,7 +398,7 @@ void SessionRecording::saveStringToFile(const std::string& s) { bool SessionRecording::hasCameraChangedFromPrev( datamessagestructures::CameraKeyframe kfNew) { - const double threshold = 1e-2; + constexpr const double threshold = 1e-2; bool hasChanged = false; glm::dvec3 positionDiff = kfNew._position - _prevRecordedCameraKeyframe._position; @@ -433,60 +420,60 @@ void SessionRecording::saveCameraKeyframe() { return; } - const SceneGraphNode* anchorNode = - global::navigationHandler.orbitalNavigator().anchorNode(); - if (!anchorNode) { + const SceneGraphNode* an = global::navigationHandler.orbitalNavigator().anchorNode(); + if (!an) { return; } - //Create a camera keyframe, then call to populate it with current position + // Create a camera keyframe, then call to populate it with current position // & orientation of camera datamessagestructures::CameraKeyframe kf = _externInteract.generateCameraKeyframe(); - if (/*hasCameraChangedFromPrev(kf)*/true) { - if (isDataModeBinary()) { - _bufferIndex = 0; - _keyframeBuffer[_bufferIndex++] = 'c'; + 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); + // 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); - } else { - 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()); + saveKeyframeToFileBinary(_keyframeBuffer, _bufferIndex); + } + 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()); } } @@ -498,7 +485,7 @@ void SessionRecording::saveTimeKeyframe() { //Create a time keyframe, then call to populate it with current time props datamessagestructures::TimeKeyframe kf = _externInteract.generateTimeKeyframe(); - if (isDataModeBinary()) { + if (_recordingDataMode == RecordedDataMode::Binary) { _bufferIndex = 0; _keyframeBuffer[_bufferIndex++] = 't'; writeToFileBuffer(kf._timestamp); @@ -513,12 +500,12 @@ void SessionRecording::saveTimeKeyframe() { 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 << kf._timestamp << ' '; + keyframeLine << (kf._timestamp - _timestampRecordStarted) << ' '; keyframeLine << std::fixed << std::setprecision(3) << kf._time; - keyframeLine << " " << kf._dt; + keyframeLine << ' ' << kf._dt; if (kf._paused) { keyframeLine << " P"; } @@ -542,7 +529,8 @@ void SessionRecording::saveScriptKeyframe(std::string scriptToSave) { datamessagestructures::ScriptMessage sm = _externInteract.generateScriptMessage(scriptToSave); - if (isDataModeBinary()) { + + if (_recordingDataMode == RecordedDataMode::Binary) { _bufferIndex = 0; _keyframeBuffer[_bufferIndex++] = 's'; writeToFileBuffer(sm._timestamp); @@ -560,12 +548,12 @@ void SessionRecording::saveScriptKeyframe(std::string scriptToSave) { 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 << sm._timestamp << ' '; + keyframeLine << (sm._timestamp - _timestampRecordStarted) << ' '; keyframeLine << std::fixed << std::setprecision(3) << global::timeManager.time().j2000Seconds(); - keyframeLine << " "; - keyframeLine << (numLinesInScript + 1) << " "; + keyframeLine << ' '; + keyframeLine << (numLinesInScript + 1) << ' '; keyframeLine << scriptToSave; saveKeyframeToFile(keyframeLine.str()); @@ -575,7 +563,7 @@ void SessionRecording::saveScriptKeyframe(std::string scriptToSave) { void SessionRecording::preSynchronization() { if (_state == SessionState::Recording) { saveCameraKeyframe(); - if (_usingTimeKeyframes) { + if (UsingTimeKeyframes) { saveTimeKeyframe(); } } @@ -612,17 +600,17 @@ SessionRecording::SessionState SessionRecording::state() const { bool SessionRecording::playbackAddEntriesToTimeline() { bool parsingErrorsFound = false; - if (isDataModeBinary()) { + if (_recordingDataMode == RecordedDataMode::Binary) { unsigned char frameType; bool fileReadOk = true; while (fileReadOk) { frameType = readFromPlayback(_playbackFile); - //Check if have reached EOF + // Check if have reached EOF if (!_playbackFile) { LINFO(fmt::format( "Finished parsing {} entries from playback file {}", - _playbackLineNum - 1, _playbackFilename.c_str() + _playbackLineNum - 1, _playbackFilename )); fileReadOk = false; break; @@ -639,7 +627,7 @@ bool SessionRecording::playbackAddEntriesToTimeline() { else { LERROR(fmt::format( "Unknown frame type {} @ index {} of playback file {}", - frameType, _playbackLineNum - 1, _playbackFilename.c_str() + frameType, _playbackLineNum - 1, _playbackFilename )); parsingErrorsFound = true; break; @@ -647,7 +635,8 @@ bool SessionRecording::playbackAddEntriesToTimeline() { _playbackLineNum++; } - } else { + } + else { while (std::getline(_playbackFile, _playbackLineParsing)) { _playbackLineNum++; @@ -656,7 +645,7 @@ bool SessionRecording::playbackAddEntriesToTimeline() { if (!(iss >> entryType)) { LERROR(fmt::format( "Error reading entry type @ line {} of playback file {}", - _playbackLineNum, _playbackFilename.c_str() + _playbackLineNum, _playbackFilename )); break; } @@ -673,7 +662,7 @@ bool SessionRecording::playbackAddEntriesToTimeline() { else { LERROR(fmt::format( "Unknown frame type {} @ line {} of playback file {}", - entryType, _playbackLineNum, _playbackFilename.c_str() + entryType, _playbackLineNum, _playbackFilename )); parsingErrorsFound = true; break; @@ -681,7 +670,7 @@ bool SessionRecording::playbackAddEntriesToTimeline() { } LINFO(fmt::format( "Finished parsing {} entries from playback file {}", - _playbackLineNum, _playbackFilename.c_str() + _playbackLineNum, _playbackFilename )); } @@ -750,7 +739,7 @@ void SessionRecording::playbackCamera() { std::string rotationFollowing; interaction::KeyframeNavigator::CameraPose pbFrame; datamessagestructures::CameraKeyframe kf; - if (isDataModeBinary()) { + if (_recordingDataMode == RecordedDataMode::Binary) { timeOs = readFromPlayback(_playbackFile); timeRec = readFromPlayback(_playbackFile); timeSim = readFromPlayback(_playbackFile); @@ -787,7 +776,8 @@ void SessionRecording::playbackCamera() { )); return; } - } else { + } + else { std::istringstream iss(_playbackLineParsing); std::string entryType; iss >> entryType; @@ -808,12 +798,7 @@ void SessionRecording::playbackCamera() { )); return; } - if (rotationFollowing == "F") { - pbFrame.followFocusNodeRotation = true; - } - else { - pbFrame.followFocusNodeRotation = false; - } + pbFrame.followFocusNodeRotation = (rotationFollowing == "F"); } if (_setSimulationTimeWithNextCameraKeyframe) { global::timeManager.setTimeNextFrame(timeSim); @@ -830,7 +815,7 @@ void SessionRecording::playbackTimeChange() { double timeRec; double timeSim; datamessagestructures::TimeKeyframe pbFrame; - if (isDataModeBinary()) { + if (_recordingDataMode == RecordedDataMode::Binary) { timeOs = readFromPlayback(_playbackFile); timeRec = readFromPlayback(_playbackFile); timeSim = readFromPlayback(_playbackFile); @@ -860,18 +845,8 @@ void SessionRecording::playbackTimeChange() { )); return; } - if (paused == "P") { - pbFrame._paused = true; - } - else { - pbFrame._paused = false; - } - if (jump == "J") { - pbFrame._requiresTimeJump = true; - } - else { - pbFrame._requiresTimeJump = false; - } + pbFrame._paused = (paused == "P"); + pbFrame._requiresTimeJump = (jump == "J"); } pbFrame._timestamp = equivalentApplicationTime(timeOs, timeRec, timeSim); @@ -888,7 +863,7 @@ void SessionRecording::playbackScript() { unsigned int numScriptLines; datamessagestructures::ScriptMessage pbFrame; - if (isDataModeBinary()) { + if (_recordingDataMode == RecordedDataMode::Binary) { timeOs = readFromPlayback(_playbackFile); timeRec = readFromPlayback(_playbackFile); timeSim = readFromPlayback(_playbackFile); @@ -1024,20 +999,22 @@ void SessionRecording::lookForNonCameraKeyframesThatHaveComeDue(double currTime) } void SessionRecording::updateCameraWithOrWithoutNewKeyframes(double currTime) { - if (_playbackActive_camera) { - bool didFindFutureCameraKeyframes = findNextFutureCameraIndex(currTime); + if (!_playbackActive_camera) { + return; + } - bool isPrevAtFirstKeyframe = (_idxTimeline_cameraPtrPrev == - _idxTimeline_cameraFirstInTimeline); - bool isFirstTimelineCameraKeyframeInFuture = (currTime < - _cameraFirstInTimeline_timestamp); + bool didFindFutureCameraKeyframes = findNextFutureCameraIndex(currTime); - if (! (isPrevAtFirstKeyframe && isFirstTimelineCameraKeyframeInFuture)) { - processCameraKeyframe(currTime); - } - if (!didFindFutureCameraKeyframes) { - signalPlaybackFinishedForComponent(RecordedType::Camera); - } + bool isPrevAtFirstKeyframe = (_idxTimeline_cameraPtrPrev == + _idxTimeline_cameraFirstInTimeline); + bool isFirstTimelineCameraKeyframeInFuture = (currTime < + _cameraFirstInTimeline_timestamp); + + if (! (isPrevAtFirstKeyframe && isFirstTimelineCameraKeyframeInFuture)) { + processCameraKeyframe(currTime); + } + if (!didFindFutureCameraKeyframes) { + signalPlaybackFinishedForComponent(RecordedType::Camera); } } @@ -1070,7 +1047,7 @@ bool SessionRecording::findNextFutureCameraIndex(double currTime) { } break; } else { - //Force interpolation between consecutive keyframes + // Force interpolation between consecutive keyframes _idxTimeline_cameraPtrPrev = seekAheadIndex; } } @@ -1102,7 +1079,7 @@ bool SessionRecording::processNextNonCameraKeyframeAheadInTime() { switch (getNextKeyframeType()) { case RecordedType::Camera: - //Just return true since this function no longer handles camera keyframes + // Just return true since this function no longer handles camera keyframes return true; case RecordedType::Time: _idxTime = _timeline[_idxTimeline_nonCamera].idxIntoKeyframeTypeArray; @@ -1110,7 +1087,7 @@ bool SessionRecording::processNextNonCameraKeyframeAheadInTime() { return false; } LINFO("Time keyframe type"); - //TBD: the TimeManager restricts setting time directly + // TBD: the TimeManager restricts setting time directly return false; case RecordedType::Script: _idxScript = _timeline[_idxTimeline_nonCamera].idxIntoKeyframeTypeArray; @@ -1144,9 +1121,11 @@ bool SessionRecording::processCameraKeyframe(double now) { unsigned int nextIdx; if (!_playbackActive_camera) { return false; - } else if (_keyframesCamera.empty()) { + } + else if (_keyframesCamera.empty()) { return false; - } else { + } + else { prevIdx = _timeline[_idxTimeline_cameraPtrPrev].idxIntoKeyframeTypeArray; prevPose = _keyframesCamera[prevIdx]; nextIdx = _timeline[_idxTimeline_cameraPtrNext].idxIntoKeyframeTypeArray; @@ -1177,11 +1156,10 @@ bool SessionRecording::processCameraKeyframe(double now) { Camera* camera = global::navigationHandler.camera(); Scene* scene = camera->parent()->scene(); - const SceneGraphNode* node = - scene->sceneGraphNode(_keyframesCamera[prevIdx].focusNode); + const SceneGraphNode* n = scene->sceneGraphNode(_keyframesCamera[prevIdx].focusNode); - if (node) { - global::navigationHandler.orbitalNavigator().setFocusNode(node->identifier()); + if (n) { + global::navigationHandler.orbitalNavigator().setFocusNode(n->identifier()); } return interaction::KeyframeNavigator::updateCamera( @@ -1194,17 +1172,17 @@ bool SessionRecording::processCameraKeyframe(double now) { } bool SessionRecording::processScriptKeyframe() { - std::string nextScript; - if (!_playbackActive_script) { return false; - } else if (_keyframesScript.empty()) { + } + else if (_keyframesScript.empty()) { return false; - } else { - nextScript = nextKeyframeObj( + } + else { + std::string nextScript = nextKeyframeObj( _idxScript, _keyframesScript, - ([&]() { signalPlaybackFinishedForComponent(RecordedType::Script); }) + ([this]() { signalPlaybackFinishedForComponent(RecordedType::Script); }) ); global::scriptEngine.queueScript( nextScript, @@ -1218,9 +1196,11 @@ bool SessionRecording::processScriptKeyframe() { double SessionRecording::getNextTimestamp() { if (_timeline.empty()) { return 0.0; - } else if (_idxTimeline_nonCamera < _timeline.size()) { + } + else if (_idxTimeline_nonCamera < _timeline.size()) { return _timeline[_idxTimeline_nonCamera].timestamp; - } else { + } + else { return _timeline.back().timestamp; } } @@ -1243,9 +1223,11 @@ double SessionRecording::getPrevTimestamp() { SessionRecording::RecordedType SessionRecording::getNextKeyframeType() { if (_timeline.empty()) { return RecordedType::Invalid; - } else if (_idxTimeline_nonCamera < _timeline.size()) { + } + else if (_idxTimeline_nonCamera < _timeline.size()) { return _timeline[_idxTimeline_nonCamera].keyframeType; - } else { + } + else { return _timeline.back().keyframeType; } } @@ -1253,7 +1235,8 @@ SessionRecording::RecordedType SessionRecording::getNextKeyframeType() { SessionRecording::RecordedType SessionRecording::getPrevKeyframeType() { if (_timeline.empty()) { return RecordedType::Invalid; - } else if (_idxTimeline_nonCamera < _timeline.size()) { + } + else if (_idxTimeline_nonCamera < _timeline.size()) { if (_idxTimeline_nonCamera > 0) { return _timeline[_idxTimeline_nonCamera - 1].keyframeType; } @@ -1274,7 +1257,9 @@ void SessionRecording::saveKeyframeToFile(std::string entry) { _recordFile << std::move(entry) << std::endl; } -SessionRecording::CallbackHandle SessionRecording::addStateChangeCallback(StateChangeCallback cb) { +SessionRecording::CallbackHandle SessionRecording::addStateChangeCallback( + StateChangeCallback cb) +{ CallbackHandle handle = _nextCallbackHandle++; _stateChangeCallbacks.emplace_back(handle, std::move(cb)); return handle; @@ -1298,17 +1283,14 @@ void SessionRecording::removeStateChangeCallback(CallbackHandle handle) { } std::vector SessionRecording::playbackList() const { - const std::string recordingsPath = absPath("${RECORDINGS}"); + const std::string path = absPath("${RECORDINGS}"); std::vector fileList; - ghoul::filesystem::Directory currentDir(recordingsPath); + ghoul::filesystem::Directory currentDir(path); std::vector allInputFiles = currentDir.readFiles(); - for (std::string f : allInputFiles) { + for (const std::string& f : allInputFiles) { // Remove path and keep only the filename - fileList.push_back(f.substr( - recordingsPath.length() + 1, - f.length() - recordingsPath.length() - 1 - )); + fileList.push_back(f.substr(path.length() + 1, f.length() - path.length() - 1)); } return fileList; }