diff --git a/data/scene/osirisrex.scene b/data/scene/osirisrex.scene index 65d1e13774..4f0016adf7 100644 --- a/data/scene/osirisrex.scene +++ b/data/scene/osirisrex.scene @@ -143,11 +143,18 @@ function preInitialization() dofile(openspace.absPath('${SCRIPTS}/bind_keys.lua')) dofile(openspace.absPath('${SCRIPTS}/bind_keys_osirisrex.lua')) + local startTime = "2019 APR 16 12:03:00.00"; -- openspace.time.setTime("2018-12-20T22:47:00.00") --openspace.time.setTime("2019-05-25T03:57:55.00") --openspace.time.setTime("2016 SEP 8 23:05:00.50") - openspace.time.setTime("2019 APR 16 12:03:00.00") + openspace.time.setTime(startTime) openspace.time.setDeltaTime(0) + + openspace.scriptScheduler.load("${OPENSPACE_DATA}/scene/osirisrex/scheduled_scripts.lua") + + -- Removing the line below will cause all scripts prior to to be executed during initialization + openspace.scriptScheduler.skipTo(startTime); + end function postInitialization() @@ -173,6 +180,8 @@ function postInitialization() openspace.printInfo("Done setting default values") openspace.loadMission("${OPENSPACE_DATA}/scene/osirisrex/osirisrex/osirisrex.mission") + + openspace.resetCameraDirection() end diff --git a/data/scene/osirisrex/scheduled_scripts.lua b/data/scene/osirisrex/scheduled_scripts.lua new file mode 100644 index 0000000000..5f58a00218 --- /dev/null +++ b/data/scene/osirisrex/scheduled_scripts.lua @@ -0,0 +1,17 @@ +return +{ + { + Time = "2016 SEP 08 23:10:13", + ReversibleLuaScript = { + Forward = "openspace.printInfo('forward test 1');", + Backward = "openspace.printInfo('backward test 1');", + } + }, + { + Time = "2016 SEP 09 00:08:13", + ReversibleLuaScript = { + Forward = "openspace.printInfo('forward test 2');", + Backward = "openspace.printInfo('backward test 2');", + } + }, +} \ No newline at end of file diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 99b6507d78..3af650bcf7 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -80,6 +81,7 @@ public: interaction::InteractionHandler& interactionHandler(); RenderEngine& renderEngine(); scripting::ScriptEngine& scriptEngine(); + scripting::ScriptScheduler& scriptScheduler(); NetworkEngine& networkEngine(); LuaConsole& console(); ModuleEngine& moduleEngine(); @@ -138,6 +140,7 @@ private: std::unique_ptr _interactionHandler; std::unique_ptr _renderEngine; std::unique_ptr _scriptEngine; + std::unique_ptr _scriptScheduler; std::unique_ptr _networkEngine; std::unique_ptr _commandlineParser; std::unique_ptr _console; diff --git a/include/openspace/scripting/scriptscheduler.h b/include/openspace/scripting/scriptscheduler.h new file mode 100644 index 0000000000..75c45e1e71 --- /dev/null +++ b/include/openspace/scripting/scriptscheduler.h @@ -0,0 +1,86 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * 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 __SCRIPTSCHEDULER_H__ +#define __SCRIPTSCHEDULER_H__ + +#include + +#include + +#include +#include + +namespace openspace { + +namespace scripting { + + + +struct ReversibleLuaScript { + std::string forwardScript; + std::string backwardScript; +}; + +struct ScheduledScript { + ScheduledScript() : time(-DBL_MAX) { } + ScheduledScript(const ghoul::Dictionary& dict); + + double time; + ReversibleLuaScript script; +}; + + +/** + * Maintains an ordered list of \code ScheduledScripts. + */ +class ScriptScheduler { +public: + + void loadScripts(const std::string& filename); + void loadScripts(const ghoul::Dictionary& dict); + + void skipTo(double time); + void skipTo(const std::string& timeStr); + + std::queue scheduledScripts(double newTime); + std::queue scheduledScripts(const std::string& timeStr); + + const std::vector& allScripts() const { return _scheduledScripts; }; + + static LuaLibrary luaLibrary(); + +private: + + std::vector _scheduledScripts; + + size_t _currentIndex = 0; + double _lastTime; + +}; + +} // namespace scripting +} // namespace openspace + +#endif // __SCRIPTSCHEDULER_H__ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 718429a4e2..0edb26d5f7 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -82,6 +82,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/scene/scenegraphnode.cpp ${OPENSPACE_BASE_DIR}/src/scripting/lualibrary.cpp ${OPENSPACE_BASE_DIR}/src/scripting/scriptengine.cpp + ${OPENSPACE_BASE_DIR}/src/scripting/scriptscheduler.cpp ${OPENSPACE_BASE_DIR}/src/scripting/scriptengine_lua.inl ${OPENSPACE_BASE_DIR}/src/util/blockplaneintersectiongeometry.cpp ${OPENSPACE_BASE_DIR}/src/util/boxgeometry.cpp @@ -169,6 +170,7 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/scripting/lualibrary.h ${OPENSPACE_BASE_DIR}/include/openspace/scripting/script_helper.h ${OPENSPACE_BASE_DIR}/include/openspace/scripting/scriptengine.h + ${OPENSPACE_BASE_DIR}/include/openspace/scripting/scriptscheduler.h ${OPENSPACE_BASE_DIR}/include/openspace/util/blockplaneintersectiongeometry.h ${OPENSPACE_BASE_DIR}/include/openspace/util/boxgeometry.h ${OPENSPACE_BASE_DIR}/include/openspace/util/camera.h diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index c6c58c861e..e0751a3066 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include #include #include @@ -49,6 +50,7 @@ #include #include + #include #include #include @@ -64,6 +66,7 @@ #include #include +#include #ifdef OPENSPACE_MODULE_ONSCREENGUI_ENABLED #include @@ -123,6 +126,7 @@ OpenSpaceEngine::OpenSpaceEngine(std::string programName, , _interactionHandler(new interaction::InteractionHandler) , _renderEngine(new RenderEngine) , _scriptEngine(new scripting::ScriptEngine) + , _scriptScheduler(new scripting::ScriptScheduler) , _networkEngine(new NetworkEngine) , _commandlineParser(new ghoul::cmdparser::CommandlineParser( programName, ghoul::cmdparser::CommandlineParser::AllowUnknownCommands::Yes @@ -386,6 +390,7 @@ bool OpenSpaceEngine::initialize() { _scriptEngine->addLibrary(gui::GUI::luaLibrary()); _scriptEngine->addLibrary(network::ParallelConnection::luaLibrary()); _scriptEngine->addLibrary(ModuleEngine::luaLibrary()); + _scriptEngine->addLibrary(ScriptScheduler::luaLibrary()); #ifdef OPENSPACE_MODULE_ISWA_ENABLED _scriptEngine->addLibrary(IswaManager::luaLibrary()); @@ -748,6 +753,12 @@ void OpenSpaceEngine::preSynchronization() { Time::ref().advanceTime(dt); Time::ref().preSynchronization(); + auto scheduledScripts = _scriptScheduler->scheduledScripts(Time::ref().currentTime()); + while(scheduledScripts.size()){ + _scriptEngine->queueScript(scheduledScripts.front()); + scheduledScripts.pop(); + } + _scriptEngine->preSynchronization(); _renderEngine->preSynchronization(); @@ -771,7 +782,7 @@ void OpenSpaceEngine::postSynchronizationPreDraw() { } Time::ref().postSynchronizationPreDraw(); - + _scriptEngine->postSynchronizationPreDraw(); _renderEngine->postSynchronizationPreDraw(); @@ -782,6 +793,7 @@ void OpenSpaceEngine::postSynchronizationPreDraw() { _interactionHandler->postSynchronizationPreDraw(); // Update the synched variables in the camera class + _renderEngine->camera()->preSynchronization(); _renderEngine->camera()->postSynchronizationPreDraw(); @@ -1019,6 +1031,11 @@ ScriptEngine& OpenSpaceEngine::scriptEngine() { return *_scriptEngine; } +ScriptScheduler& OpenSpaceEngine::scriptScheduler(){ + ghoul_assert(_scriptScheduler, "ScriptScheduler must not be nullptr"); + return *_scriptScheduler; +} + LuaConsole& OpenSpaceEngine::console() { ghoul_assert(_console, "LuaConsole must not be nullptr"); return *_console; diff --git a/src/scripting/scriptscheduler.cpp b/src/scripting/scriptscheduler.cpp new file mode 100644 index 0000000000..ef73fb4a13 --- /dev/null +++ b/src/scripting/scriptscheduler.cpp @@ -0,0 +1,186 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2016 * + * * + * 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 // parse time +#include +#include + + +namespace openspace { +namespace scripting { + +namespace { + const std::string _loggerCat = "ScriptScheduler"; + + const std::string KEY_TIME = "Time"; + const std::string KEY_FORWARD_SCRIPT = "ReversibleLuaScript.Forward"; + const std::string KEY_BACKWARD_SCRIPT = "ReversibleLuaScript.Backward"; +} + + +ScheduledScript::ScheduledScript(const ghoul::Dictionary& dict) + : ScheduledScript() // default init first +{ + std::string timeStr; + if (dict.getValue(KEY_TIME, timeStr)) { + time = SpiceManager::ref().ephemerisTimeFromDate(timeStr); + + if (!dict.getValue(KEY_FORWARD_SCRIPT, script.forwardScript)) { + LERROR("Unable to read " << KEY_FORWARD_SCRIPT); + } + if (!dict.getValue(KEY_BACKWARD_SCRIPT, script.backwardScript)) { + LERROR("Unable to read " << KEY_BACKWARD_SCRIPT); + } + } + else { + LERROR("Unable to read " << KEY_TIME); + } +} + +void ScriptScheduler::loadScripts(const std::string& filepath) { + ghoul::Dictionary timedScriptsDict; + try { + ghoul::lua::loadDictionaryFromFile(absPath(filepath), timedScriptsDict); + } + catch (const ghoul::RuntimeError& e) { + LERROR(e.what()); + return; + } + loadScripts(timedScriptsDict); +} + +void ScriptScheduler::loadScripts(const ghoul::Dictionary& dict) { + for (size_t i = 0; i < dict.size(); ++i) { + std::string id = std::to_string(i + 1); + const ghoul::Dictionary& timedScriptDict = dict.value(id); + _scheduledScripts.push_back(ScheduledScript(timedScriptDict)); + } +} + +void ScriptScheduler::skipTo(double newTime) { + if (newTime > _lastTime) { + while (_currentIndex < _scheduledScripts.size() && _scheduledScripts[_currentIndex].time <= newTime) { + _currentIndex++; + } + } + else { + while (0 < _currentIndex && _scheduledScripts[_currentIndex - 1].time > newTime) { + _currentIndex--; + } + } +} + +void ScriptScheduler::skipTo(const std::string& timeStr) { + skipTo(SpiceManager::ref().ephemerisTimeFromDate(timeStr)); +} + + +std::queue ScriptScheduler::scheduledScripts(double newTime) { + std::queue triggeredScripts; + if (newTime > _lastTime) { + while(_currentIndex < _scheduledScripts.size() && _scheduledScripts[_currentIndex].time <= newTime){ + triggeredScripts.push(_scheduledScripts[_currentIndex].script.forwardScript); + _currentIndex++; + } + } + else { + while (0 < _currentIndex && _scheduledScripts[_currentIndex - 1].time > newTime) { + triggeredScripts.push(_scheduledScripts[_currentIndex - 1].script.backwardScript); + _currentIndex--; + } + } + + _lastTime = newTime; + return triggeredScripts; +} + +std::queue ScriptScheduler::scheduledScripts(const std::string& timeStr) { + return std::move(scheduledScripts(SpiceManager::ref().ephemerisTimeFromDate(timeStr))); +} + + +///////////////////////////////////////////////////////////////////// +// Lua library functions // +///////////////////////////////////////////////////////////////////// + +namespace luascriptfunctions { + int loadTimedScripts(lua_State* L) { + using ghoul::lua::luaTypeToString; + int nArguments = lua_gettop(L); + if (nArguments != 1) + return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments); + + std::string missionFileName = luaL_checkstring(L, -1); + if (missionFileName.empty()) { + return luaL_error(L, "filepath string is empty"); + } + + OsEng.scriptScheduler().loadScripts(missionFileName); + } + + int skipTo(lua_State* L) { + using ghoul::lua::luaTypeToString; + int nArguments = lua_gettop(L); + if (nArguments != 1) + return luaL_error(L, "Expected %i arguments, got %i", 1, nArguments); + + std::string dateStr = luaL_checkstring(L, -1); + if (dateStr.empty()) { + return luaL_error(L, "date string is empty"); + } + + OsEng.scriptScheduler().skipTo(dateStr); + } +} // namespace luascriptfunction + + + +LuaLibrary ScriptScheduler::luaLibrary() { + return { + "scriptScheduler", + { + { + "load", + &luascriptfunctions::loadTimedScripts, + "string", + "Load timed scripts from file" + }, + { + "skipTo", + &luascriptfunctions::skipTo, + "string", + "skip to a time without executing scripts" + }, + } + }; +} + +} // namespace scripting + +} // namespace openspace