mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-02-18 10:59:18 -06:00
Added loop playback option to repeat playback file
This commit is contained in:
@@ -189,11 +189,13 @@ public:
|
||||
* \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
|
||||
* \param loop if true then the file will playback in loop mode, continuously
|
||||
* looping back to the beginning until it is manually stopped
|
||||
*
|
||||
* \return \c true if recording to file starts without errors
|
||||
*/
|
||||
bool startPlayback(std::string& filename, KeyframeTimeRef timeMode,
|
||||
bool forceSimTimeAtStart);
|
||||
bool forceSimTimeAtStart, bool loop);
|
||||
|
||||
/**
|
||||
* Used to stop a playback in progress. If open, the playback file will be closed,
|
||||
@@ -622,6 +624,10 @@ protected:
|
||||
bool addKeyframeToTimeline(std::vector<timelineEntry>& timeline, RecordedType type,
|
||||
size_t indexIntoTypeKeyframes, Timestamps t3stamps, int lineNum);
|
||||
|
||||
void initializePlayback_time(double now);
|
||||
void initializePlayback_modeFlags();
|
||||
bool initializePlayback_timeline();
|
||||
void initializePlayback_triggerStart();
|
||||
void moveAheadInTime();
|
||||
void lookForNonCameraKeyframesThatHaveComeDue(double currTime);
|
||||
void updateCameraWithOrWithoutNewKeyframes(double currTime);
|
||||
@@ -702,6 +708,8 @@ protected:
|
||||
bool _playbackActive_script = false;
|
||||
bool _hasHitEndOfCameraKeyframes = false;
|
||||
bool _playbackPausedWithinDeltaTimePause = false;
|
||||
bool _playbackLoopMode = false;
|
||||
bool _playbackForceSimTimeAtStart = false;
|
||||
double _playbackPauseOffset = 0.0;
|
||||
double _previousTime = 0.0;
|
||||
|
||||
|
||||
@@ -344,7 +344,8 @@ void SessionRecording::stopRecording() {
|
||||
|
||||
bool SessionRecording::startPlayback(std::string& filename,
|
||||
KeyframeTimeRef timeMode,
|
||||
bool forceSimTimeAtStart)
|
||||
bool forceSimTimeAtStart,
|
||||
bool loop)
|
||||
{
|
||||
std::string absFilename;
|
||||
//Run through conversion in case file is older. Does nothing if the file format
|
||||
@@ -374,6 +375,7 @@ bool SessionRecording::startPlayback(std::string& filename,
|
||||
|
||||
_playbackLineNum = 1;
|
||||
_playbackFilename = absFilename;
|
||||
_playbackLoopMode = loop;
|
||||
|
||||
// Open in ASCII first
|
||||
_playbackFile.open(_playbackFilename, std::ifstream::in);
|
||||
@@ -422,27 +424,13 @@ bool SessionRecording::startPlayback(std::string& filename,
|
||||
cleanUpPlayback();
|
||||
return false;
|
||||
}
|
||||
//Set time reference mode
|
||||
using namespace std::chrono;
|
||||
double now = global::windowDelegate->applicationTime();
|
||||
_timestampPlaybackStarted_application = now;
|
||||
_timestampPlaybackStarted_simulation = global::timeManager->time().j2000Seconds();
|
||||
_timestampApplicationStarted_simulation = _timestampPlaybackStarted_simulation - now;
|
||||
_playbackTimeReferenceMode = timeMode;
|
||||
_saveRenderingCurrentRecordedTime_interpolation = steady_clock::now();
|
||||
_saveRenderingClockInterpolation_countsPerSec =
|
||||
system_clock::duration::period::den / system_clock::duration::period::num;
|
||||
_saveRendering_isFirstFrame = true;
|
||||
_playbackPauseOffset = 0.0;
|
||||
//Set time reference mode
|
||||
_playbackForceSimTimeAtStart = forceSimTimeAtStart;
|
||||
double now = global::windowDelegate->applicationTime();
|
||||
_playbackTimeReferenceMode = timeMode;
|
||||
initializePlayback_time(now);
|
||||
|
||||
//Set playback flags to true for all modes
|
||||
_playbackActive_camera = true;
|
||||
_playbackActive_script = true;
|
||||
if (UsingTimeKeyframes) {
|
||||
_playbackActive_time = true;
|
||||
}
|
||||
|
||||
global::navigationHandler->keyframeNavigator().setTimeReferenceMode(timeMode, now);
|
||||
global::scriptScheduler->setTimeReferenceMode(timeMode);
|
||||
_loadedNodes.clear();
|
||||
populateListofLoadedSceneGraphNodes();
|
||||
@@ -452,30 +440,69 @@ bool SessionRecording::startPlayback(std::string& filename,
|
||||
return false;
|
||||
}
|
||||
|
||||
_hasHitEndOfCameraKeyframes = false;
|
||||
if (!findFirstCameraKeyframeInTimeline()) {
|
||||
initializePlayback_modeFlags();
|
||||
if (!initializePlayback_timeline()) {
|
||||
cleanUpPlayback();
|
||||
return false;
|
||||
}
|
||||
if (forceSimTimeAtStart) {
|
||||
Timestamps times = _timeline[_idxTimeline_cameraFirstInTimeline].t3stamps;
|
||||
global::timeManager->setTimeNextFrame(Time(times.timeSim));
|
||||
_saveRenderingCurrentRecordedTime = times.timeRec;
|
||||
}
|
||||
|
||||
LINFO(fmt::format(
|
||||
"Playback session started: ({:8.3f},0.0,{:13.3f}) with {}/{}/{} entries, "
|
||||
"forceTime={}",
|
||||
now, _timestampPlaybackStarted_simulation, _keyframesCamera.size(),
|
||||
_keyframesTime.size(), _keyframesScript.size(), (forceSimTimeAtStart ? 1 : 0)
|
||||
_keyframesTime.size(), _keyframesScript.size(),
|
||||
(_playbackForceSimTimeAtStart ? 1 : 0)
|
||||
));
|
||||
|
||||
initializePlayback_triggerStart();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SessionRecording::initializePlayback_time(double now) {
|
||||
using namespace std::chrono;
|
||||
_timestampPlaybackStarted_application = now;
|
||||
_timestampPlaybackStarted_simulation = global::timeManager->time().j2000Seconds();
|
||||
_timestampApplicationStarted_simulation = _timestampPlaybackStarted_simulation - now;
|
||||
_saveRenderingCurrentRecordedTime_interpolation = steady_clock::now();
|
||||
_saveRenderingClockInterpolation_countsPerSec =
|
||||
system_clock::duration::period::den / system_clock::duration::period::num;
|
||||
_playbackPauseOffset = 0.0;
|
||||
global::navigationHandler->keyframeNavigator().setTimeReferenceMode(
|
||||
_playbackTimeReferenceMode, now);
|
||||
}
|
||||
|
||||
void SessionRecording::initializePlayback_modeFlags() {
|
||||
_playbackActive_camera = true;
|
||||
_playbackActive_script = true;
|
||||
if (UsingTimeKeyframes) {
|
||||
_playbackActive_time = true;
|
||||
}
|
||||
_hasHitEndOfCameraKeyframes = false;
|
||||
}
|
||||
|
||||
bool SessionRecording::initializePlayback_timeline() {
|
||||
if (!findFirstCameraKeyframeInTimeline()) {
|
||||
return false;
|
||||
}
|
||||
if (_playbackForceSimTimeAtStart) {
|
||||
Timestamps times = _timeline[_idxTimeline_cameraFirstInTimeline].t3stamps;
|
||||
global::timeManager->setTimeNextFrame(Time(times.timeSim));
|
||||
_saveRenderingCurrentRecordedTime = times.timeRec;
|
||||
}
|
||||
_idxTimeline_nonCamera = 0;
|
||||
_idxTime = 0;
|
||||
_idxScript = 0;
|
||||
_idxTimeline_cameraPtrNext = 0;
|
||||
_idxTimeline_cameraPtrPrev = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SessionRecording::initializePlayback_triggerStart() {
|
||||
global::navigationHandler->triggerPlaybackStart();
|
||||
global::scriptScheduler->triggerPlaybackStart();
|
||||
global::timeManager->triggerPlaybackStart();
|
||||
_state = SessionState::Playback;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SessionRecording::isPlaybackPaused() {
|
||||
@@ -536,9 +563,19 @@ void SessionRecording::signalPlaybackFinishedForComponent(RecordedType type) {
|
||||
}
|
||||
|
||||
if (!_playbackActive_camera && !_playbackActive_time && !_playbackActive_script) {
|
||||
_state = SessionState::Idle;
|
||||
_cleanupNeeded = true;
|
||||
LINFO("Playback session finished");
|
||||
if (_playbackLoopMode) {
|
||||
//Loop back to the beginning to replay
|
||||
_saveRenderingDuringPlayback = false;
|
||||
initializePlayback_time(global::windowDelegate->applicationTime());
|
||||
initializePlayback_modeFlags();
|
||||
initializePlayback_timeline();
|
||||
initializePlayback_triggerStart();
|
||||
}
|
||||
else {
|
||||
_state = SessionState::Idle;
|
||||
_cleanupNeeded = true;
|
||||
LINFO("Playback session finished");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -604,6 +641,8 @@ void SessionRecording::cleanUpPlayback() {
|
||||
_saveRenderingDuringPlayback = false;
|
||||
_saveRendering_isFirstFrame = true;
|
||||
_playbackPauseOffset = 0.0;
|
||||
_playbackLoopMode = false;
|
||||
_playbackForceSimTimeAtStart = false;
|
||||
|
||||
_cleanupNeeded = false;
|
||||
}
|
||||
@@ -2496,14 +2535,15 @@ scripting::LuaLibrary SessionRecording::luaLibrary() {
|
||||
"startPlayback",
|
||||
&luascriptfunctions::startPlaybackDefault,
|
||||
{},
|
||||
"string",
|
||||
"string [, bool]",
|
||||
"Starts a playback session with keyframe times that are relative to "
|
||||
"the time since the recording was started (the same relative time "
|
||||
"applies to the playback). When playback starts, the simulation time "
|
||||
"is automatically set to what it was at recording time. The string "
|
||||
"argument is the filename to pull playback keyframes from (the file "
|
||||
"path is relative to the RECORDINGS variable specified in the config "
|
||||
"file)."
|
||||
"file). If a second input value of true is given, then playback will "
|
||||
"continually loop until it is manually stopped."
|
||||
},
|
||||
{
|
||||
"startPlaybackApplicationTime",
|
||||
@@ -2520,12 +2560,14 @@ scripting::LuaLibrary SessionRecording::luaLibrary() {
|
||||
"startPlaybackRecordedTime",
|
||||
&luascriptfunctions::startPlaybackRecordedTime,
|
||||
{},
|
||||
"string",
|
||||
"string [, bool]",
|
||||
"Starts a playback session with keyframe times that are relative to "
|
||||
"the time since the recording was started (the same relative time "
|
||||
"applies to the playback). The string argument is the filename to pull "
|
||||
"playback keyframes from (the file path is relative to the RECORDINGS "
|
||||
"variable specified in the config file)."
|
||||
"variable specified in the config file). If a second input value of "
|
||||
"true is given, then playback will continually loop until it is "
|
||||
"manually stopped."
|
||||
},
|
||||
{
|
||||
"startPlaybackSimulationTime",
|
||||
|
||||
@@ -84,6 +84,20 @@ int startPlayback(lua_State* L, interaction::KeyframeTimeRef timeMode,
|
||||
bool forceSimTimeAtStart)
|
||||
{
|
||||
using ghoul::lua::luaTypeToString;
|
||||
const int nArguments = lua_gettop(L);
|
||||
bool loop = false;
|
||||
|
||||
if (nArguments == 2) {
|
||||
loop = lua_toboolean(L, 2) == 1;
|
||||
}
|
||||
else if (nArguments != 1) {
|
||||
lua_settop(L, 0);
|
||||
return luaL_error(
|
||||
L,
|
||||
"bad number of arguments, expected 1 or 2, got %i",
|
||||
nArguments
|
||||
);
|
||||
}
|
||||
|
||||
const std::string playbackFilePath = ghoul::lua::value<std::string>(
|
||||
L,
|
||||
@@ -98,7 +112,8 @@ int startPlayback(lua_State* L, interaction::KeyframeTimeRef timeMode,
|
||||
global::sessionRecording->startPlayback(
|
||||
const_cast<std::string&>(playbackFilePath),
|
||||
timeMode,
|
||||
forceSimTimeAtStart
|
||||
forceSimTimeAtStart,
|
||||
loop
|
||||
);
|
||||
|
||||
ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack");
|
||||
@@ -106,7 +121,6 @@ int startPlayback(lua_State* L, interaction::KeyframeTimeRef timeMode,
|
||||
}
|
||||
|
||||
int startPlaybackDefault(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startPlaybackDefault");
|
||||
using interaction::KeyframeNavigator;
|
||||
return startPlayback(L,
|
||||
interaction::KeyframeTimeRef::Relative_recordedStart, true);
|
||||
@@ -120,7 +134,6 @@ int startPlaybackApplicationTime(lua_State* L) {
|
||||
}
|
||||
|
||||
int startPlaybackRecordedTime(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startPlaybackRecordedTime");
|
||||
using interaction::KeyframeNavigator;
|
||||
return startPlayback(L,
|
||||
interaction::KeyframeTimeRef::Relative_recordedStart, false);
|
||||
|
||||
Reference in New Issue
Block a user