From af617d1d101c24bed08c1b2df3d0d5bc5aeb460c Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 19 Aug 2021 16:02:14 +0200 Subject: [PATCH 01/23] Feature/lua function cleanup (#1719) General cleanup of Lua functions and handling of variable extract from a Lua state --- ext/ghoul | 2 +- .../interaction/joystickinputstate.h | 11 +- modules/base/CMakeLists.txt | 1 + .../base/rendering/screenspacedashboard.cpp | 73 +- .../rendering/screenspacedashboard_lua.inl | 77 ++ modules/exoplanets/exoplanetsmodule_lua.inl | 114 ++- .../globebrowsing/globebrowsingmodule_lua.inl | 150 +--- modules/space/spacemodule_lua.inl | 42 +- .../statemachine/statemachinemodule_lua.inl | 104 +-- src/engine/moduleengine_lua.inl | 25 +- src/engine/openspaceengine_lua.inl | 131 +--- src/interaction/actionmanager_lua.inl | 32 +- src/interaction/keybindingmanager_lua.inl | 42 +- src/interaction/sessionrecording_lua.inl | 168 +---- src/mission/missionmanager_lua.inl | 38 +- src/navigation/navigationhandler_lua.inl | 221 ++---- src/navigation/pathnavigator_lua.inl | 99 +-- src/network/parallelpeer_lua.inl | 12 - src/rendering/dashboard_lua.inl | 75 +- src/rendering/renderengine_lua.inl | 30 +- src/scene/assetloader_lua.inl | 60 +- src/scene/assetmanager_lua.inl | 37 +- src/scene/profile_lua.inl | 80 +- src/scene/scene_lua.inl | 224 ++---- src/scripting/scriptengine_lua.inl | 121 +-- src/scripting/scriptscheduler_lua.inl | 48 +- src/util/spicemanager.cpp | 4 +- src/util/spicemanager_lua.inl | 197 +---- src/util/time_lua.inl | 703 +++++------------- 29 files changed, 860 insertions(+), 2061 deletions(-) create mode 100644 modules/base/rendering/screenspacedashboard_lua.inl diff --git a/ext/ghoul b/ext/ghoul index bce78a781c..350c0f6ec9 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit bce78a781c0da924e54af01e031ecc3de62441f5 +Subproject commit 350c0f6ec9df6bbaf3790109188d6c97600fb60d diff --git a/include/openspace/interaction/joystickinputstate.h b/include/openspace/interaction/joystickinputstate.h index c5d320c7b8..e256f39552 100644 --- a/include/openspace/interaction/joystickinputstate.h +++ b/include/openspace/interaction/joystickinputstate.h @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -126,18 +127,18 @@ inline std::string to_string(const openspace::interaction::JoystickAction& value case openspace::interaction::JoystickAction::Press: return "Press"; case openspace::interaction::JoystickAction::Repeat: return "Repeat"; case openspace::interaction::JoystickAction::Release: return "Release"; - default: throw MissingCaseException(); + default: throw MissingCaseException(); } } template <> constexpr openspace::interaction::JoystickAction from_string(std::string_view string) { - if (string == "Idle") { return openspace::interaction::JoystickAction::Idle; } - if (string == "Press") { return openspace::interaction::JoystickAction::Press; } - if (string == "Repeat") { return openspace::interaction::JoystickAction::Repeat; } + if (string == "Idle") { return openspace::interaction::JoystickAction::Idle; } + if (string == "Press") { return openspace::interaction::JoystickAction::Press; } + if (string == "Repeat") { return openspace::interaction::JoystickAction::Repeat; } if (string == "Release") { return openspace::interaction::JoystickAction::Release; } - throw RuntimeError("Unknown action '" + std::string(string) + "'"); + throw RuntimeError(fmt::format("Unknown action '{}'", string)); } } // namespace ghoul diff --git a/modules/base/CMakeLists.txt b/modules/base/CMakeLists.txt index 4a69424b32..f294216f35 100644 --- a/modules/base/CMakeLists.txt +++ b/modules/base/CMakeLists.txt @@ -108,6 +108,7 @@ set(SOURCE_FILES rendering/renderabletrailorbit.cpp rendering/renderabletrailtrajectory.cpp rendering/screenspacedashboard.cpp + rendering/screenspacedashboard_lua.inl rendering/screenspaceframebuffer.cpp rendering/screenspaceimagelocal.cpp rendering/screenspaceimageonline.cpp diff --git a/modules/base/rendering/screenspacedashboard.cpp b/modules/base/rendering/screenspacedashboard.cpp index 5c3ebae6eb..5cbb793421 100644 --- a/modules/base/rendering/screenspacedashboard.cpp +++ b/modules/base/rendering/screenspacedashboard.cpp @@ -54,79 +54,10 @@ namespace { #include "screenspacedashboard_codegen.cpp" } // namespace +#include "screenspacedashboard_lua.inl" + namespace openspace { -namespace luascriptfunctions { - -/** -* \ingroup LuaScripts -* addDashboardItemToScreenSpace(string, table): -*/ -int addDashboardItemToScreenSpace(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addDashboardItemToScreenSpace"); - - const std::string& name = ghoul::lua::value(L, 1); - const int type = lua_type(L, 2); - if (type != LUA_TTABLE) { - return ghoul::lua::luaError(L, "Expected argument of type 'table'"); - } - - ghoul::Dictionary d; - try { - ghoul::lua::luaDictionaryFromState(L, d); - } - catch (const ghoul::lua::LuaFormatException& e) { - LERRORC("addDashboardItem", e.what()); - return 0; - } - - ScreenSpaceRenderable* ssr = global::renderEngine->screenSpaceRenderable(name); - - if (!ssr) { - return ghoul::lua::luaError(L, "Provided name is not a ScreenSpace item"); - } - - ScreenSpaceDashboard* dash = dynamic_cast(ssr); - if (!dash) { - return ghoul::lua::luaError( - L, - "Provided name is a ScreenSpace item but not a dashboard" - ); - } - - dash->dashboard().addDashboardItem(DashboardItem::createFromDictionary(d)); - - lua_settop(L, 0); - return 0; -} - -/** -* \ingroup LuaScripts -* removeDashboardItemsFromScreenSpace(string): -*/ -int removeDashboardItemsFromScreenSpace(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeDashboardItemsFromScreenSpace"); - - const std::string& name = ghoul::lua::value(L, 1); - ScreenSpaceRenderable* ssr = global::renderEngine->screenSpaceRenderable(name); - - if (!ssr) { - return ghoul::lua::luaError(L, "Provided name is not a ScreenSpace item"); - } - - ScreenSpaceDashboard* dash = dynamic_cast(ssr); - if (!dash) { - return ghoul::lua::luaError( - L, - "Provided name is a ScreenSpace item but not a dashboard" - ); - } - - dash->dashboard().clearDashboardItems(); - return 0; -} -} // namespace luascriptfunctions - documentation::Documentation ScreenSpaceDashboard::Documentation() { return codegen::doc("base_screenspace_dashboard"); } diff --git a/modules/base/rendering/screenspacedashboard_lua.inl b/modules/base/rendering/screenspacedashboard_lua.inl new file mode 100644 index 0000000000..ba424e8a5d --- /dev/null +++ b/modules/base/rendering/screenspacedashboard_lua.inl @@ -0,0 +1,77 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +namespace openspace::luascriptfunctions { + +/** + * \ingroup LuaScripts + * addDashboardItemToScreenSpace(string, table): + */ +int addDashboardItemToScreenSpace(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addDashboardItemToScreenSpace"); + auto [name, d] = ghoul::lua::values(L); + + ScreenSpaceRenderable* ssr = global::renderEngine->screenSpaceRenderable(name); + if (!ssr) { + return ghoul::lua::luaError(L, "Provided name is not a ScreenSpace item"); + } + + ScreenSpaceDashboard* dash = dynamic_cast(ssr); + if (!dash) { + return ghoul::lua::luaError( + L, + "Provided name is a ScreenSpace item but not a dashboard" + ); + } + + dash->dashboard().addDashboardItem(DashboardItem::createFromDictionary(d)); + return 0; +} + +/** + * \ingroup LuaScripts + * removeDashboardItemsFromScreenSpace(string): + */ +int removeDashboardItemsFromScreenSpace(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeDashboardItemsFromScreenSpace"); + const std::string name = ghoul::lua::value(L); + + ScreenSpaceRenderable* ssr = global::renderEngine->screenSpaceRenderable(name); + if (!ssr) { + return ghoul::lua::luaError(L, "Provided name is not a ScreenSpace item"); + } + + ScreenSpaceDashboard* dash = dynamic_cast(ssr); + if (!dash) { + return ghoul::lua::luaError( + L, + "Provided name is a ScreenSpace item but not a dashboard" + ); + } + + dash->dashboard().clearDashboardItems(); + return 0; +} + +} // namespace openspace::luascriptfunctions diff --git a/modules/exoplanets/exoplanetsmodule_lua.inl b/modules/exoplanets/exoplanetsmodule_lua.inl index f5359e9dbe..4a2128b9dc 100644 --- a/modules/exoplanets/exoplanetsmodule_lua.inl +++ b/modules/exoplanets/exoplanetsmodule_lua.inl @@ -88,43 +88,45 @@ ExoplanetSystem findExoplanetSystemInData(std::string_view starName) { std::string name; std::getline(ss, name, ','); - if (name.substr(0, name.length() - 2) == starName) { - std::string location_s; - std::getline(ss, location_s); - long location = std::stol(location_s.c_str()); + if (name.substr(0, name.length() - 2) != starName) { + continue; + } - data.seekg(location); - data.read(reinterpret_cast(&p), sizeof(ExoplanetDataEntry)); + std::string location_s; + std::getline(ss, location_s); + long location = std::stol(location_s.c_str()); - sanitizeNameString(name); + data.seekg(location); + data.read(reinterpret_cast(&p), sizeof(ExoplanetDataEntry)); - if (!hasSufficientData(p)) { - LWARNING(fmt::format("Insufficient data for exoplanet: '{}'", name)); - continue; - } + sanitizeNameString(name); - system.planetNames.push_back(name); - system.planetsData.push_back(p); + if (!hasSufficientData(p)) { + LWARNING(fmt::format("Insufficient data for exoplanet: '{}'", name)); + continue; + } - // Star data - Should not vary between planets, but one data entry might - // lack data for the host star while another does not. So for every planet, - // update star data if needed - const glm::vec3 pos{ p.positionX, p.positionY, p.positionZ }; - if (system.starData.position != pos && isValidPosition(pos)) { - system.starData.position = pos; - } - if (system.starData.radius != p.rStar && !std::isnan(p.rStar)) { - system.starData.radius = p.rStar; - } - if (system.starData.bv != p.bmv && !std::isnan(p.bmv)) { - system.starData.bv = p.bmv; - } - if (system.starData.teff != p.teff && !std::isnan(p.teff)) { - system.starData.teff = p.teff; - } - if (system.starData.luminosity != p.luminosity && !std::isnan(p.luminosity)) { - system.starData.luminosity = p.luminosity; - } + system.planetNames.push_back(name); + system.planetsData.push_back(p); + + // Star data - Should not vary between planets, but one data entry might lack data + // for the host star while another does not. So for every planet, update star data + // if needed + const glm::vec3 pos = glm::vec3(p.positionX, p.positionY, p.positionZ); + if (system.starData.position != pos && isValidPosition(pos)) { + system.starData.position = pos; + } + if (system.starData.radius != p.rStar && !std::isnan(p.rStar)) { + system.starData.radius = p.rStar; + } + if (system.starData.bv != p.bmv && !std::isnan(p.bmv)) { + system.starData.bv = p.bmv; + } + if (system.starData.teff != p.teff && !std::isnan(p.teff)) { + system.starData.teff = p.teff; + } + if (system.starData.luminosity != p.luminosity && !std::isnan(p.luminosity)) { + system.starData.luminosity = p.luminosity; } } @@ -555,50 +557,40 @@ void createExoplanetSystem(const std::string& starName) { int addExoplanetSystem(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::addExoplanetSystem"); + std::variant v = + ghoul::lua::value>(L); - const int t = lua_type(L, 1); - if (t == LUA_TSTRING) { + if (std::holds_alternative(v)) { // The user provided a single name - const std::string& starName = ghoul::lua::value(L, 1); + std::string starName = std::get(v); createExoplanetSystem(starName); } - else if (t == LUA_TTABLE) { + else { // A list of names was provided - ghoul::Dictionary d; - ghoul::lua::luaDictionaryFromState(L, d); - - for (size_t i = 1; i <= d.size(); ++i) { - if (!d.hasValue(std::to_string(i))) { + ghoul::Dictionary starNames = ghoul::lua::value(L); + for (size_t i = 1; i <= starNames.size(); ++i) { + if (!starNames.hasValue(std::to_string(i))) { return ghoul::lua::luaError( - L, fmt::format("List item {} is of invalid type", i) + L, + fmt::format("List item {} is of invalid type", i) ); } - const std::string& starName = d.value(std::to_string(i)); + const std::string& starName = starNames.value(std::to_string(i)); createExoplanetSystem(starName); } - lua_pop(L, 1); } - else { - return ghoul::lua::luaError(L, "Invalid input"); - } - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int removeExoplanetSystem(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeExoplanetSystem"); + std::string starName = ghoul::lua::value(L); - const int StringLocation = -1; - const std::string starName = luaL_checkstring(L, StringLocation); - const std::string starIdentifier = createIdentifier(starName); - + const std::string starIdentifier = createIdentifier(std::move(starName)); openspace::global::scriptEngine->queueScript( "openspace.removeSceneGraphNode('" + starIdentifier + "');", scripting::ScriptEngine::RemoteScripting::Yes ); - return 0; } @@ -656,7 +648,6 @@ std::vector hostStarsWithSufficientData() { // For easier read, sort by names and remove duplicates std::sort(names.begin(), names.end()); names.erase(std::unique(names.begin(), names.end()), names.end()); - return names; } @@ -664,15 +655,13 @@ int getListOfExoplanets(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getListOfExoplanets"); std::vector names = hostStarsWithSufficientData(); - lua_newtable(L); int number = 1; for (const std::string& s : names) { - lua_pushstring(L, s.c_str()); + ghoul::lua::push(L, s); lua_rawseti(L, -2, number); ++number; } - return 1; } @@ -683,16 +672,15 @@ int listAvailableExoplanetSystems(lua_State* L) { std::string output; for (auto it = names.begin(); it != names.end(); ++it) { - if (it != names.end()) { - output += *it + ", "; - } + output += *it + ", "; } + output.pop_back(); + output.pop_back(); LINFO(fmt::format( "There is data available for the following {} exoplanet systems: {}", names.size(), output )); - return 0; } diff --git a/modules/globebrowsing/globebrowsingmodule_lua.inl b/modules/globebrowsing/globebrowsingmodule_lua.inl index 053ce7d6a3..eb7ab0f871 100644 --- a/modules/globebrowsing/globebrowsingmodule_lua.inl +++ b/modules/globebrowsing/globebrowsingmodule_lua.inl @@ -47,10 +47,8 @@ int addLayer(lua_State* L) { ZoneScoped ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::addLayer"); - - // String arguments - const std::string& globeName = ghoul::lua::value(L, 1); - const std::string& layerGroupName = ghoul::lua::value(L, 2); + auto [globeName, layerGroupName, layerDict] = + ghoul::lua::values(L); // Get the node and make sure it exists SceneGraphNode* n = global::renderEngine->scene()->sceneGraphNode(globeName); @@ -73,23 +71,10 @@ int addLayer(lua_State* L) { } // Get the dictionary defining the layer - ghoul::Dictionary d; - try { - ghoul::lua::luaDictionaryFromState(L, d); - } - catch (const ghoul::lua::LuaFormatException& e) { - LERRORC("addLayerFromDictionary", e.what()); - lua_settop(L, 0); - return 0; - } - lua_settop(L, 0); - - Layer* layer = globe->layerManager().addLayer(groupID, d); + Layer* layer = globe->layerManager().addLayer(groupID, layerDict); if (layer) { layer->initialize(); } - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } @@ -98,11 +83,8 @@ int addLayer(lua_State* L) { */ int deleteLayer(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::deleteLayer"); - - const std::string& globeName = luaL_checkstring(L, 1); - const std::string& layerGroupName = luaL_checkstring(L, 2); - const std::string& layerName = luaL_checkstring(L, 3); - lua_pop(L, 3); + auto [globeName, layerGroupName, layerName] = + ghoul::lua::values(L); // Get the node and make sure it exists SceneGraphNode* n = global::renderEngine->scene()->sceneGraphNode(globeName); @@ -125,17 +107,12 @@ int deleteLayer(lua_State* L) { } globe->layerManager().deleteLayer(groupID, layerName); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int getLayers(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::getLayers"); - - const std::string& globeIdentifier = ghoul::lua::value(L, 1); - const std::string& layer = ghoul::lua::value(L, 2); - lua_pop(L, 2); + auto [globeIdentifier, layer] = ghoul::lua::values(L); SceneGraphNode* n = sceneGraphNode(globeIdentifier); if (!n) { @@ -168,12 +145,8 @@ int getLayers(lua_State* L) { int moveLayer(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::moveLayer"); - - const std::string& globeIdentifier = ghoul::lua::value(L, 1); - const std::string& layer = ghoul::lua::value(L, 2); - int oldPosition = ghoul::lua::value(L, 3); - int newPosition = ghoul::lua::value(L, 4); - lua_pop(L, 4); + auto [globeIdentifier, layer, oldPosition, newPosition] = + ghoul::lua::values(L); if (oldPosition == newPosition) { return 0; @@ -197,22 +170,16 @@ int moveLayer(lua_State* L) { globebrowsing::LayerGroup& lg = globe->layerManager().layerGroup(group); lg.moveLayers(oldPosition, newPosition); - return 0; } int goToChunk(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::goToChunk"); + auto [identifier, x, y, level] = ghoul::lua::values(L); - const std::string& globeIdentifier = ghoul::lua::value(L, 1); - const int x = ghoul::lua::value(L, 2); - const int y = ghoul::lua::value(L, 3); - const int level = ghoul::lua::value(L, 4); - lua_pop(L, 4); - - SceneGraphNode* n = sceneGraphNode(globeIdentifier); + SceneGraphNode* n = sceneGraphNode(identifier); if (!n) { - return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier); + return ghoul::lua::luaError(L, "Unknown globe name: " + identifier); } const RenderableGlobe* globe = dynamic_cast(n->renderable()); @@ -221,22 +188,18 @@ int goToChunk(lua_State* L) { } global::moduleEngine->module()->goToChunk(*globe, x, y, level); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int goToGeo(lua_State* L) { - int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::goToGeo"); + ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::goToGeo"); // Check if the user provided a Scene graph node identifier as the first argument. // lua_isstring returns true for both numbers and strings, so better use !lua_isnumber const bool providedGlobeIdentifier = !lua_isnumber(L, 1); - const int parameterOffset = providedGlobeIdentifier ? 1 : 0; - const SceneGraphNode* n; if (providedGlobeIdentifier) { - const std::string& globeIdentifier = ghoul::lua::value(L, 1); + const std::string& globeIdentifier = ghoul::lua::value(L); n = sceneGraphNode(globeIdentifier); if (!n) { return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier); @@ -249,8 +212,8 @@ int goToGeo(lua_State* L) { } } - const double latitude = ghoul::lua::value(L, parameterOffset + 1); - const double longitude = ghoul::lua::value(L, parameterOffset + 2); + auto [latitude, longitude, altitude] = + ghoul::lua::values>(L); const RenderableGlobe* globe = dynamic_cast(n->renderable()); if (!globe) { @@ -258,32 +221,29 @@ int goToGeo(lua_State* L) { return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe"); } else { - return ghoul::lua::luaError(L, - "Current anchor node is not a RenderableGlobe. " - "Either change the anchor to a globe, or specify a globe identifier " - "as the first argument" + return ghoul::lua::luaError( + L, + "Current anchor node is not a RenderableGlobe. Either change the anchor " + "to a globe, or specify a globe identifier as the first argument" ); } } - if (nArguments == parameterOffset + 2) { - global::moduleEngine->module()->goToGeo( - *globe, latitude, longitude - ); - } - else if (nArguments == parameterOffset + 3) { - const double altitude = ghoul::lua::value(L, parameterOffset + 3); + if (altitude.has_value()) { global::moduleEngine->module()->goToGeo( *globe, latitude, longitude, - altitude + *altitude + ); + } + else { + global::moduleEngine->module()->goToGeo( + *globe, + latitude, + longitude ); } - - lua_settop(L, 0); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } @@ -394,12 +354,8 @@ int flyToGeo(lua_State* L) { int getLocalPositionFromGeo(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::getLocalPositionFromGeo"); - - const std::string& globeIdentifier = ghoul::lua::value(L, 1); - const double latitude = ghoul::lua::value(L, 2); - const double longitude = ghoul::lua::value(L, 3); - const double altitude = ghoul::lua::value(L, 4); - lua_pop(L, 4); + auto [globeIdentifier, latitude, longitude, altitude] = + ghoul::lua::values(L); SceneGraphNode* n = sceneGraphNode(globeIdentifier); if (!n) { @@ -411,16 +367,8 @@ int getLocalPositionFromGeo(lua_State* L) { } GlobeBrowsingModule& mod = *(global::moduleEngine->module()); - glm::vec3 pos = mod.cartesianCoordinatesFromGeo( - *globe, - latitude, - longitude, - altitude - ); - - ghoul::lua::push(L, pos.x, pos.y, pos.z); - - ghoul_assert(lua_gettop(L) == 3, "Incorrect number of items left on stack"); + glm::vec3 p = mod.cartesianCoordinatesFromGeo(*globe, latitude, longitude, altitude); + ghoul::lua::push(L, p.x, p.y, p.z); return 3; } @@ -450,72 +398,48 @@ int getGeoPositionForCamera(lua_State* L) { posHandle.centerToReferenceSurface); ghoul::lua::push(L, glm::degrees(geo2.lat), glm::degrees(geo2.lon), altitude); - - ghoul_assert(lua_gettop(L) == 3, "Incorrect number of items left on stack"); return 3; } int loadWMSCapabilities(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::loadWMSCapabilities"); - - std::string name = ghoul::lua::value(L, 1); - std::string globe = ghoul::lua::value(L, 2); - std::string url = ghoul::lua::value(L, 3); + auto [name, globe, url] = + ghoul::lua::values(L); global::moduleEngine->module()->loadWMSCapabilities( std::move(name), std::move(globe), std::move(url) ); - - lua_pop(L, 3); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int removeWMSServer(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeWMSServer"); - - const std::string& name = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); + const std::string name = ghoul::lua::value(L); global::moduleEngine->module()->removeWMSServer(name); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int capabilities(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::capabilities"); + const std::string name = ghoul::lua::value(L); - const std::string& name = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); GlobeBrowsingModule::Capabilities cap = global::moduleEngine->module()->capabilities(name); lua_newtable(L); - for (unsigned long i = 0; i < cap.size(); ++i) { + for (size_t i = 0; i < cap.size(); ++i) { const GlobeBrowsingModule::Layer& l = cap[i]; lua_newtable(L); - ghoul::lua::push(L, "Name", l.name); lua_settable(L, -3); - ghoul::lua::push(L, "URL", l.url); lua_settable(L, -3); - lua_rawseti(L, -2, i + 1); } - - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } diff --git a/modules/space/spacemodule_lua.inl b/modules/space/spacemodule_lua.inl index 881a191afe..826ca8c53f 100644 --- a/modules/space/spacemodule_lua.inl +++ b/modules/space/spacemodule_lua.inl @@ -30,48 +30,38 @@ int convertFromRaDec(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::convertFromRaDec"); glm::dvec2 degrees = glm::dvec2(0.0); - if (lua_type(L, 1) == LUA_TSTRING && lua_type(L, 2) == LUA_TSTRING) { - std::string ra = ghoul::lua::value(L, 1); - std::string dec = ghoul::lua::value(L, 2); + if (ghoul::lua::hasValue(L, 1) && + ghoul::lua::hasValue(L, 2)) + { + auto [ra, dec] = ghoul::lua::values(L); degrees = icrsToDecimalDegrees(ra, dec); } - else if (lua_type(L, 1) == LUA_TNUMBER && lua_type(L, 2) == LUA_TNUMBER) { - degrees.x = ghoul::lua::value(L, 1); - degrees.y = ghoul::lua::value(L, 2); + else if (ghoul::lua::hasValue(L, 1) && ghoul::lua::hasValue(L, 2)) { + auto [x, y] = ghoul::lua::values(L); + degrees.x = x; + degrees.y = y; } else { - throw ghoul::lua::LuaRuntimeException("lua::convertFromRaDec: Ra and Dec have to " - "be of the same type, either String or Number" + throw ghoul::lua::LuaRuntimeException( + "Ra and Dec have to be of the same type, either String or Number" ); } - double distance = ghoul::lua::value(L, 3); - lua_settop(L, 0); - + double distance = ghoul::lua::value(L); glm::dvec3 pos = icrsToGalacticCartesian(degrees.x, degrees.y, distance); ghoul::lua::push(L, pos); - - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } int convertToRaDec(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::convertToRaDec"); + auto [x, y, z] = ghoul::lua::values(L); - double x = ghoul::lua::value(L, 1); - double y = ghoul::lua::value(L, 2); - double z = ghoul::lua::value(L, 3); - lua_settop(L, 0); + glm::dvec3 deg = galacticCartesianToIcrs(x, y, z); + std::pair raDecPair = decimalDegreesToIcrs(deg.x, deg.y); - glm::dvec3 degrees = galacticCartesianToIcrs(x, y, z); - std::pair raDecPair - = decimalDegreesToIcrs(degrees.x, degrees.y); - - ghoul::lua::push(L, raDecPair.first); // Ra - ghoul::lua::push(L, raDecPair.second); // Dec - ghoul::lua::push(L, degrees.z); // Distance - - ghoul_assert(lua_gettop(L) == 3, "Incorrect number of items left on stack"); + // Ra, Dec, Distance + ghoul::lua::push(L, raDecPair.first, raDecPair.second, deg.z); return 3; } diff --git a/modules/statemachine/statemachinemodule_lua.inl b/modules/statemachine/statemachinemodule_lua.inl index 0cacd48dc9..55415af46e 100644 --- a/modules/statemachine/statemachinemodule_lua.inl +++ b/modules/statemachine/statemachinemodule_lua.inl @@ -33,95 +33,37 @@ namespace openspace::luascriptfunctions { int createStateMachine(lua_State* L) { - const int nArguments = ghoul::lua::checkArgumentsAndThrow( - L, - { 2, 3 }, - "lua::createStateMachine" - ); - - // If three arguments, a start state was included - std::optional startState = std::nullopt; - if (nArguments > 2) { - startState = ghoul::lua::value(L, 3, ghoul::lua::PopValue::Yes); - } - - // Last dictionary is on top of the stack - ghoul::Dictionary transitions; - try { - ghoul::lua::luaDictionaryFromState(L, transitions); - } - catch (const ghoul::lua::LuaFormatException& e) { - LERRORC("createStateMachine", e.what()); - return 0; - } - - // Pop, so that first dictionary is on top and can be read - lua_pop(L, 1); - ghoul::Dictionary states; - try { - ghoul::lua::luaDictionaryFromState(L, states); - } - catch (const ghoul::lua::LuaFormatException& e) { - LERRORC("createStateMachine", e.what()); - return 0; - } + ghoul::lua::checkArgumentsAndThrow(L, { 2, 3 }, "lua::createStateMachine"); + auto [states, transitions, startState] = ghoul::lua::values< + ghoul::Dictionary, ghoul::Dictionary, std::optional + >(L); StateMachineModule* module = global::moduleEngine->module(); - - module->initializeStateMachine(states, transitions, startState); - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + module->initializeStateMachine( + std::move(states), + std::move(transitions), + std::move(startState) + ); return 0; } int goToState(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::goToState"); - const bool isString = (lua_isstring(L, 1) != 0); + std::string newState = ghoul::lua::value(L); - if (!isString) { - lua_settop(L, 0); - const char* msg = lua_pushfstring( - L, - "%s expected, got %s", - lua_typename(L, LUA_TSTRING), - luaL_typename(L, 0) - ); - return luaL_error(L, "bad argument #%d (%s)", 1, msg); - } - - const std::string newState = lua_tostring(L, 1); StateMachineModule* module = global::moduleEngine->module(); module->transitionTo(newState); LINFOC("StateMachine", "Transitioning to " + newState); - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int setInitialState(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setStartState"); - const bool isString = (lua_isstring(L, 1) != 0); + std::string startState = ghoul::lua::value(L); - if (!isString) { - lua_settop(L, 0); - const char* msg = lua_pushfstring( - L, - "%s expected, got %s", - lua_typename(L, LUA_TSTRING), - luaL_typename(L, 0) - ); - return luaL_error(L, "bad argument #%d (%s)", 1, msg); - } - - const std::string startState = lua_tostring(L, 1); StateMachineModule* module = global::moduleEngine->module(); module->setInitialState(startState); LINFOC("StateMachine", "Initial state set to: " + startState); - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } @@ -130,9 +72,7 @@ int currentState(lua_State* L) { StateMachineModule* module = global::moduleEngine->module(); std::string currentState = module->currentState(); - - lua_pushstring(L, currentState.c_str()); - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); + ghoul::lua::push(L, std::move(currentState)); return 1; } @@ -141,32 +81,16 @@ int possibleTransitions(lua_State* L) { StateMachineModule* module = global::moduleEngine->module(); std::vector transitions = module->possibleTransitions(); - ghoul::lua::push(L, transitions); - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } int canGoToState(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::canGoToState"); - const bool isString = (lua_isstring(L, 1) != 0); + std::string state = ghoul::lua::value(L); - if (!isString) { - lua_settop(L, 0); - const char* msg = lua_pushfstring( - L, - "%s expected, got %s", - lua_typename(L, LUA_TSTRING), - luaL_typename(L, 0) - ); - return luaL_error(L, "bad argument #%d (%s)", 1, msg); - } - - const std::string state = lua_tostring(L, 1); StateMachineModule* module = global::moduleEngine->module(); ghoul::lua::push(L, module->canGoToState(state)); - - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } @@ -174,7 +98,6 @@ int printCurrentStateInfo(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::printCurrentStateInfo"); StateMachineModule* module = global::moduleEngine->module(); - if (module->hasStateMachine()) { std::string currentState = module->currentState(); std::vector transitions = module->possibleTransitions(); @@ -188,7 +111,6 @@ int printCurrentStateInfo(lua_State* L) { LINFOC("StateMachine", "No state machine has been created"); } - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 1; } diff --git a/src/engine/moduleengine_lua.inl b/src/engine/moduleengine_lua.inl index f999ea1d92..5107f21c06 100644 --- a/src/engine/moduleengine_lua.inl +++ b/src/engine/moduleengine_lua.inl @@ -34,30 +34,15 @@ namespace openspace::luascriptfunctions { */ int isLoaded(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::isLoaded"); - - const int type = lua_type(L, 1); - if (type != LUA_TSTRING) { - return ghoul::lua::luaError(L, "Expected argument of type 'string'"); - } - const std::string& moduleName = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); + const std::string name = ghoul::lua::value(L); const std::vector& modules = global::moduleEngine->modules(); - - auto it = std::find_if( - modules.begin(), - modules.end(), - [moduleName](OpenSpaceModule* module) { - return module->identifier() == moduleName; - } + const auto it = std::find_if( + modules.cbegin(), modules.cend(), + [name](OpenSpaceModule* module) { return module->identifier() == name; } ); - ghoul::lua::push(L, it != modules.end()); - - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); + ghoul::lua::push(L, it != modules.cend()); return 1; } diff --git a/src/engine/openspaceengine_lua.inl b/src/engine/openspaceengine_lua.inl index 275300606a..31bdce378d 100644 --- a/src/engine/openspaceengine_lua.inl +++ b/src/engine/openspaceengine_lua.inl @@ -43,25 +43,19 @@ namespace openspace::luascriptfunctions { */ int toggleShutdown(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::toggleShutdown"); - global::openSpaceEngine->toggleShutdownMode(); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } /** -* \ingroup LuaScripts -* writeDocumentation(): -* Writes out documentation files -*/ + * \ingroup LuaScripts + * writeDocumentation(): + * Writes out documentation files + */ int writeDocumentation(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::writeDocumentation"); - global::openSpaceEngine->writeStaticDocumentation(); global::openSpaceEngine->writeSceneDocumentation(); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } @@ -72,15 +66,12 @@ int writeDocumentation(lua_State* L) { */ int addVirtualProperty(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, { 5, 7 }, "lua::addVirtualProperty"); - - const std::string& type = ghoul::lua::value(L, 1); - const std::string& name = ghoul::lua::value(L, 2); - const std::string& identifier = ghoul::lua::value(L, 3); - const std::string& description = ghoul::lua::value(L, 4); + auto [type, name, identifier, description] = + ghoul::lua::values(L); std::unique_ptr prop; if (type == "BoolProperty") { - const bool v = ghoul::lua::value(L, 5); + const bool v = ghoul::lua::value(L); prop = std::make_unique( properties::Property::PropertyInfo { identifier.c_str(), @@ -91,10 +82,7 @@ int addVirtualProperty(lua_State* L) { ); } else if (type == "IntProperty") { - const int v = ghoul::lua::value(L, 5); - const int min = ghoul::lua::value(L, 6); - const int max = ghoul::lua::value(L, 7); - + auto [v, min, max] = ghoul::lua::values(L); prop = std::make_unique( properties::Property::PropertyInfo { identifier.c_str(), @@ -107,10 +95,7 @@ int addVirtualProperty(lua_State* L) { ); } else if (type == "FloatProperty") { - const float v = ghoul::lua::value(L, 5); - const float min = ghoul::lua::value(L, 6); - const float max = ghoul::lua::value(L, 7); - + auto [v, min, max] = ghoul::lua::values(L); prop = std::make_unique( properties::Property::PropertyInfo { identifier.c_str(), @@ -132,26 +117,22 @@ int addVirtualProperty(lua_State* L) { ); } else { - lua_settop(L, 0); return ghoul::lua::luaError(L, fmt::format("Unknown property type '{}'", type)); } - lua_settop(L, 0); global::virtualPropertyManager->addProperty(std::move(prop)); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } /** -* \ingroup LuaScripts -* removeVirtualProperty(): -* Removes a previously added virtual property -*/ + * \ingroup LuaScripts + * removeVirtualProperty(): + * Removes a previously added virtual property + */ int removeVirtualProperty(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeVirtualProperty"); + const std::string name = ghoul::lua::value(L); - const std::string& name = ghoul::lua::value(L, 1); properties::Property* p = global::virtualPropertyManager->property(name); if (p) { global::virtualPropertyManager->removeProperty(p); @@ -159,39 +140,30 @@ int removeVirtualProperty(lua_State* L) { else { LWARNINGC( "removeVirtualProperty", - fmt::format("Virtual Property with name '{}'' did not exist", name) + fmt::format("Virtual Property with name '{}' did not exist", name) ); } - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } /** -* \ingroup LuaScripts -* removeAllVirtualProperties(): -* Remove all registered virtual properties -*/ + * \ingroup LuaScripts + * removeAllVirtualProperties(): + * Remove all registered virtual properties + */ int removeAllVirtualProperties(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::removeAllVirtualProperties"); - const std::vector& ps = - global::virtualPropertyManager->properties(); - for (properties::Property* p : ps) { + for (properties::Property* p : global::virtualPropertyManager->properties()) { global::virtualPropertyManager->removeProperty(p); delete p; } - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int setScreenshotFolder(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setScreenshotFolder"); - - std::string arg = ghoul::lua::value(L); - lua_pop(L, 0); + const std::string arg = ghoul::lua::value(L); std::filesystem::path folder = absPath(arg); if (!std::filesystem::exists(folder)) { @@ -215,22 +187,14 @@ int setScreenshotFolder(lua_State* L) { */ int addTag(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addTag"); - - const std::string& uri = ghoul::lua::value(L, 1); - std::string tag = ghoul::lua::value(L, 2); - lua_settop(L, 0); + auto [uri, tag] = ghoul::lua::values(L); SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(uri); if (!node) { - return ghoul::lua::luaError( - L, - fmt::format("Unknown scene graph node type '{}'", uri) - ); + return ghoul::lua::luaError(L, fmt::format("Unknown scene graph node '{}'", uri)); } node->addTag(std::move(tag)); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } @@ -240,41 +204,28 @@ int addTag(lua_State* L) { * Removes a tag from a SceneGraphNode */ int removeTag(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addTag"); - - const std::string& uri = ghoul::lua::value(L, 1); - const std::string& tag = ghoul::lua::value(L, 2); - lua_settop(L, 0); + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::removeTag"); + auto [uri, tag] = ghoul::lua::values(L); SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(uri); if (!node) { - return ghoul::lua::luaError( - L, - fmt::format("Unknown scene graph node type '{}'", uri) - ); + return ghoul::lua::luaError(L, fmt::format("Unknown scene graph node '{}'", uri)); } node->removeTag(tag); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } /** -* \ingroup LuaScripts -* downloadFile(): -* Downloads a file from Lua interpreter -*/ + * \ingroup LuaScripts + * downloadFile(): + * Downloads a file from Lua interpreter + */ int downloadFile(lua_State* L) { - int n = ghoul::lua::checkArgumentsAndThrow(L, {2, 3}, "lua::addTag"); - - const std::string& uri = ghoul::lua::value(L, 1); - const std::string& savePath = ghoul::lua::value(L, 2); - bool waitForComplete = false; - if (n == 3) { - waitForComplete = ghoul::lua::value(L, 3); - } - lua_settop(L, 0); + ghoul::lua::checkArgumentsAndThrow(L, { 2, 3 }, "lua::downloadFile"); + auto [uri, savePath, waitForComplete] = + ghoul::lua::values>(L); + waitForComplete = waitForComplete.value_or(false); LINFOC("OpenSpaceEngine", fmt::format("Downloading file from {}", uri)); std::shared_ptr future = @@ -300,21 +251,17 @@ int downloadFile(lua_State* L) { ); } - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } /** -* \ingroup LuaScripts -* createSingleColorImage(): -* Creates a one pixel image with a given color and returns the path to the cached file -*/ + * \ingroup LuaScripts + * createSingleColorImage(): + * Creates a one pixel image with a given color and returns the path to the cached file + */ int createSingleColorImage(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::createSingleColorImage"); - - const std::string& name = ghoul::lua::value(L, 1); - const ghoul::Dictionary& d = ghoul::lua::value(L, 2); - lua_settop(L, 0); + auto [name, d] = ghoul::lua::values(L); // @TODO (emmbr 2020-12-18) Verify that the input dictionary is a vec3 // Would like to clean this up with a more direct use of the Verifier in the future diff --git a/src/interaction/actionmanager_lua.inl b/src/interaction/actionmanager_lua.inl index 909d74d2b7..1c677d5226 100644 --- a/src/interaction/actionmanager_lua.inl +++ b/src/interaction/actionmanager_lua.inl @@ -33,8 +33,8 @@ namespace openspace::luascriptfunctions { */ int hasAction(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::hasAction"); + const std::string identifier = ghoul::lua::value(L); - const std::string& identifier = ghoul::lua::value(L, 1); if (identifier.empty()) { return ghoul::lua::luaError(L, "Identifier must not be empty"); } @@ -51,8 +51,8 @@ int hasAction(lua_State* L) { */ int removeAction(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeAction"); + const std::string identifier = ghoul::lua::value(L); - const std::string& identifier = ghoul::lua::value(L, 1); if (identifier.empty()) { return ghoul::lua::luaError(L, "Identifier must not be empty"); } @@ -63,7 +63,6 @@ int removeAction(lua_State* L) { ); } - global::actionManager->removeAction(identifier); return 0; } @@ -81,8 +80,7 @@ int removeAction(lua_State* L) { */ int registerAction(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::registerAction"); - - ghoul::Dictionary d = ghoul::lua::value(L, 1); + const ghoul::Dictionary d = ghoul::lua::value(L); if (!d.hasValue("Identifier")) { return ghoul::lua::luaError(L, "Identifier must to provided to register action"); @@ -138,8 +136,8 @@ int registerAction(lua_State* L) { */ int action(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::action"); + const std::string identifier = ghoul::lua::value(L); - const std::string& identifier = ghoul::lua::value(L, 1); if (identifier.empty()) { return ghoul::lua::luaError(L, "Identifier must not be empty"); } @@ -168,7 +166,6 @@ int action(lua_State* L) { action.synchronization == interaction::Action::IsSynchronized::Yes ); lua_settable(L, -3); - return 1; } @@ -216,25 +213,18 @@ int actions(lua_State* L) { * Triggers the action given by the specified identifier. */ int triggerAction(lua_State* L) { - int n = ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::triggerAction"); + ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::triggerAction"); + auto [id, arg] = ghoul::lua::values>(L); + arg = arg.value_or(ghoul::Dictionary()); - const std::string& identifier = ghoul::lua::value(L, 1); - if (identifier.empty()) { + if (id.empty()) { return ghoul::lua::luaError(L, "Identifier must not be empty"); } - if (!global::actionManager->hasAction(identifier)) { - return ghoul::lua::luaError( - L, - fmt::format("Identifier '{}' for action not found", identifier) - ); + if (!global::actionManager->hasAction(id)) { + return ghoul::lua::luaError(L, fmt::format("Action '{}' not found", id)); } - ghoul::Dictionary arguments; - if (n == 2) { - ghoul::lua::luaDictionaryFromState(L, arguments, 2); - } - - global::actionManager->triggerAction(identifier, arguments); + global::actionManager->triggerAction(id, *arg); return 0; } diff --git a/src/interaction/keybindingmanager_lua.inl b/src/interaction/keybindingmanager_lua.inl index db8fb38258..f55650997b 100644 --- a/src/interaction/keybindingmanager_lua.inl +++ b/src/interaction/keybindingmanager_lua.inl @@ -34,35 +34,24 @@ namespace openspace::luascriptfunctions { * node is hosting a parallel connection. */ int bindKey(lua_State* L) { - using ghoul::lua::luaTypeToString; - ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::bindKey"); - - std::string key = ghoul::lua::value(L, 1); - std::string action = ghoul::lua::value(L, 2); + auto [key, action] = ghoul::lua::values(L); if (action.empty()) { - lua_settop(L, 0); return ghoul::lua::luaError(L, "Action must not be empty"); } if (!global::actionManager->hasAction(action)) { - lua_settop(L, 0); return ghoul::lua::luaError(L, fmt::format("Action '{}' does not exist", action)); } openspace::KeyWithModifier iKey = openspace::stringToKey(key); - if (iKey.key == openspace::Key::Unknown) { std::string error = fmt::format("Could not find key '{}'", key); LERRORC("lua.bindKey", error); - lua_settop(L, 0); return ghoul::lua::luaError(L, error); } global::keybindingManager->bindKey(iKey.key, iKey.modifier, std::move(action)); - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } @@ -74,16 +63,10 @@ int bindKey(lua_State* L) { */ int getKeyBindings(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::getKeyBindings"); - - const std::string& key = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); + const std::string& key = ghoul::lua::value(L); using K = KeyWithModifier; using V = std::string; - const std::vector>& info = global::keybindingManager->keyBinding( stringToKey(key) ); @@ -97,7 +80,6 @@ int getKeyBindings(lua_State* L) { ++i; } - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } @@ -109,25 +91,18 @@ int getKeyBindings(lua_State* L) { int clearKey(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::clearKey"); - const int t = lua_type(L, 1); - if (t == LUA_TSTRING) { - // The user provided a single key - const std::string& key = ghoul::lua::value(L, 1); - global::keybindingManager->removeKeyBinding(stringToKey(key)); + std::variant key = ghoul::lua::value>(L); + if (std::holds_alternative(key)) { + KeyWithModifier k = stringToKey(std::get(key)); + global::keybindingManager->removeKeyBinding(k); } else { - // The user provided a list of keys - ghoul::Dictionary d; - ghoul::lua::luaDictionaryFromState(L, d); + ghoul::Dictionary d = std::get(key); for (size_t i = 1; i <= d.size(); ++i) { const std::string& k = d.value(std::to_string(i)); global::keybindingManager->removeKeyBinding(stringToKey(k)); } - lua_pop(L, 1); } - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } @@ -138,10 +113,7 @@ int clearKey(lua_State* L) { */ int clearKeys(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::clearKeys"); - global::keybindingManager->resetKeyBindings(); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } diff --git a/src/interaction/sessionrecording_lua.inl b/src/interaction/sessionrecording_lua.inl index 520f074dd5..f4004d2796 100644 --- a/src/interaction/sessionrecording_lua.inl +++ b/src/interaction/sessionrecording_lua.inl @@ -24,17 +24,9 @@ namespace openspace::luascriptfunctions { - int startRecording(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startRecording"); - - using ghoul::lua::luaTypeToString; - - const std::string recordFilePath = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); + const std::string recordFilePath = ghoul::lua::value(L); if (recordFilePath.empty()) { return luaL_error(L, "filepath string is empty"); @@ -43,21 +35,12 @@ int startRecording(lua_State* L) { interaction::SessionRecording::DataMode::Binary ); global::sessionRecording->startRecording(recordFilePath); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int startRecordingAscii(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startRecordingAscii"); - - using ghoul::lua::luaTypeToString; - - const std::string recordFilePath = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); + const std::string recordFilePath = ghoul::lua::value(L); if (recordFilePath.empty()) { return luaL_error(L, "filepath string is empty"); @@ -66,196 +49,109 @@ int startRecordingAscii(lua_State* L) { interaction::SessionRecording::DataMode::Ascii ); global::sessionRecording->startRecording(recordFilePath); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int stopRecording(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::stopRecording"); - global::sessionRecording->stopRecording(); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int startPlayback(lua_State* L, interaction::KeyframeTimeRef timeMode, bool forceSimTimeAtStart) { - using ghoul::lua::luaTypeToString; - const int nArguments = lua_gettop(L); - bool loop = false; + ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::startPlayback"); + auto [file, loop] = ghoul::lua::values>(L); + loop = loop.value_or(false); - if (nArguments == 2) { - loop = lua_toboolean(L, 2) == 1; + if (file.empty()) { + return ghoul::lua::luaError(L, "Filepath string is empty"); } - 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( - L, - 1, - ghoul::lua::PopValue::Yes - ); - - if (playbackFilePath.empty()) { - return luaL_error(L, "filepath string is empty"); - } - - global::sessionRecording->startPlayback( - const_cast(playbackFilePath), - timeMode, - forceSimTimeAtStart, - loop - ); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + global::sessionRecording->startPlayback(file, timeMode, forceSimTimeAtStart, *loop); return 0; } int startPlaybackDefault(lua_State* L) { - using interaction::KeyframeNavigator; - ghoul::lua::checkArgumentsAndThrow(L, {1, 2}, "lua::startPlaybackDefault"); - return startPlayback(L, - interaction::KeyframeTimeRef::Relative_recordedStart, true); + ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::startPlaybackDefault"); + return startPlayback(L, interaction::KeyframeTimeRef::Relative_recordedStart, true); } int startPlaybackApplicationTime(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startPlaybackApplicationTime"); - return startPlayback(L, - interaction::KeyframeTimeRef::Relative_applicationStart, false); + return startPlayback( + L, + interaction::KeyframeTimeRef::Relative_applicationStart, + false + ); } int startPlaybackRecordedTime(lua_State* L) { using interaction::KeyframeNavigator; - ghoul::lua::checkArgumentsAndThrow(L, {1, 2}, "lua::startPlaybackRecordedTime"); - return startPlayback(L, - interaction::KeyframeTimeRef::Relative_recordedStart, false); + ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::startPlaybackRecordedTime"); + return startPlayback(L, interaction::KeyframeTimeRef::Relative_recordedStart, false); } int startPlaybackSimulationTime(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::startPlaybackSimulationTime"); - using interaction::KeyframeNavigator; - return startPlayback(L, - interaction::KeyframeTimeRef::Absolute_simTimeJ2000, false); + return startPlayback(L, interaction::KeyframeTimeRef::Absolute_simTimeJ2000, false); } int stopPlayback(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::stopPlayback"); - global::sessionRecording->stopPlayback(); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int enableTakeScreenShotDuringPlayback(lua_State* L) { - const int nArguments = ghoul::lua::checkArgumentsAndThrow( + ghoul::lua::checkArgumentsAndThrow( L, { 0, 1 }, "lua::enableTakeScreenShotDuringPlayback" ); + std::optional fps = ghoul::lua::value>(L); + fps = fps.value_or(60); - const int fps = nArguments == 0 ? 60 : ghoul::lua::value(L, 1); - - global::sessionRecording->enableTakeScreenShotDuringPlayback(fps); - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + global::sessionRecording->enableTakeScreenShotDuringPlayback(*fps); return 0; } int disableTakeScreenShotDuringPlayback(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::disableTakeScreenShotDuringPlayback"); - global::sessionRecording->disableTakeScreenShotDuringPlayback(); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int fileFormatConversion(lua_State* L) { - using ghoul::lua::luaTypeToString; - - const std::string convertFilePath = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::fileFormatConversion"); + const std::string convertFilePath = ghoul::lua::value(L); if (convertFilePath.empty()) { - return luaL_error(L, "filepath string is empty"); + return luaL_error(L, "Filepath string must not be empty"); } global::sessionRecording->convertFile(convertFilePath); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int setPlaybackPause(lua_State* L) { - const int nArguments = lua_gettop(L); + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setPlaybackPause"); + const bool pause = ghoul::lua::value(L); - if (nArguments == 1) { - const bool pause = lua_toboolean(L, 1) == 1; - global::sessionRecording->setPlaybackPause(pause); - } - else { - lua_settop(L, 0); - return luaL_error( - L, - "bad number of arguments, expected 1, got %i", - nArguments - ); - } - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + global::sessionRecording->setPlaybackPause(pause); return 0; } int togglePlaybackPause(lua_State* L) { - const int nArguments = lua_gettop(L); - - if (nArguments == 0) { - bool isPlaybackPaused = global::sessionRecording->isPlaybackPaused(); - global::sessionRecording->setPlaybackPause(!isPlaybackPaused); - } - else { - lua_settop(L, 0); - return luaL_error( - L, - "bad number of arguments, expected 0, got %i", - nArguments - ); - } - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::togglePlaybackPause"); + bool isPlaybackPaused = global::sessionRecording->isPlaybackPaused(); + global::sessionRecording->setPlaybackPause(!isPlaybackPaused); return 0; } int isPlayingBack(lua_State* L) { - const int nArguments = lua_gettop(L); - - if (nArguments != 0) { - lua_settop(L, 0); - return luaL_error( - L, - "bad number of arguments, expected 0, got %i", - nArguments - ); - } - + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::isPlayingBack"); ghoul::lua::push(L, global::sessionRecording->isPlayingBack()); - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } diff --git a/src/mission/missionmanager_lua.inl b/src/mission/missionmanager_lua.inl index 029737fd09..910690a0b2 100644 --- a/src/mission/missionmanager_lua.inl +++ b/src/mission/missionmanager_lua.inl @@ -28,33 +28,21 @@ namespace openspace::luascriptfunctions { int loadMission(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadMission"); + const std::string& missionFileName = ghoul::lua::value(L); - const std::string& missionFileName = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); if (missionFileName.empty()) { return ghoul::lua::luaError(L, "Filepath is empty"); } - std::string name = global::missionManager->loadMission( - absPath(missionFileName).string() - ); + const std::string name = global::missionManager->loadMission(missionFileName); ghoul::lua::push(L, name); - - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } int unloadMission(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::unloadMission"); + const std::string missionName = ghoul::lua::value(L); - const std::string& missionName = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); if (missionName.empty()) { return ghoul::lua::luaError(L, "Mission name is empty"); } @@ -64,46 +52,30 @@ int unloadMission(lua_State* L) { } global::missionManager->unloadMission(missionName); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int hasMission(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::hasMission"); + const std::string missionName = ghoul::lua::value(L); - const std::string& missionName = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); if (missionName.empty()) { return ghoul::lua::luaError(L, "Missing name is empty"); } const bool hasMission = global::missionManager->hasMission(missionName); - ghoul::lua::push(L, hasMission); - - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } int setCurrentMission(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setCurrentMission"); + const std::string missionName = ghoul::lua::value(L); - const std::string& missionName = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); if (missionName.empty()) { return ghoul::lua::luaError(L, "Mission name is empty"); } - global::missionManager->setCurrentMission(missionName); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } diff --git a/src/navigation/navigationhandler_lua.inl b/src/navigation/navigationhandler_lua.inl index c0fd722b09..c3c9b1e4a4 100644 --- a/src/navigation/navigationhandler_lua.inl +++ b/src/navigation/navigationhandler_lua.inl @@ -30,41 +30,28 @@ namespace openspace::luascriptfunctions { int loadNavigationState(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadNavigationState"); - - const std::string& cameraStateFilePath = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); + const std::string cameraStateFilePath = ghoul::lua::value(L); if (cameraStateFilePath.empty()) { return ghoul::lua::luaError(L, "filepath string is empty"); } global::navigationHandler->loadNavigationState(cameraStateFilePath); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int getNavigationState(lua_State* L) { - const int n = ghoul::lua::checkArgumentsAndThrow( - L, - { 0, 1 }, - "lua::getNavigationState" - ); + ghoul::lua::checkArgumentsAndThrow(L, { 0, 1 }, "lua::getNavigationState"); + std::optional frame = ghoul::lua::value>(L); interaction::NavigationState state; - if (n == 1) { - const std::string referenceFrameIdentifier = ghoul::lua::value(L, 1); - const SceneGraphNode* referenceFrame = sceneGraphNode(referenceFrameIdentifier); + if (frame.has_value()) { + const SceneGraphNode* referenceFrame = sceneGraphNode(*frame); if (!referenceFrame) { - LERROR(fmt::format( - "Could not find node '{}' to use as reference frame", - referenceFrameIdentifier - )); - lua_settop(L, 0); - return 0; + return ghoul::lua::luaError( + L, + fmt::format("Could not find node '{}' as reference frame", *frame) + ); } state = global::navigationHandler->navigationState(*referenceFrame); } @@ -72,7 +59,6 @@ int getNavigationState(lua_State* L) { state = global::navigationHandler->navigationState(); } - lua_settop(L, 0); const auto pushVector = [](lua_State* s, const glm::dvec3& v) { lua_newtable(s); @@ -114,15 +100,12 @@ int getNavigationState(lua_State* L) { lua_rawset(L, -3); } - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } int setNavigationState(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setNavigationState"); - - ghoul::Dictionary navigationStateDictionary; - ghoul::lua::luaDictionaryFromState(L, navigationStateDictionary); + ghoul::Dictionary navigationStateDictionary = ghoul::lua::value(L); openspace::documentation::TestResult r = openspace::documentation::testSpecification( interaction::NavigationState::Documentation(), @@ -130,278 +113,196 @@ int setNavigationState(lua_State* L) { ); if (!r.success) { - lua_settop(L, 0); return ghoul::lua::luaError( - L, fmt::format("Could not set camera state: {}", ghoul::to_string(r)) + L, + fmt::format("Could not set camera state: {}", ghoul::to_string(r)) ); } global::navigationHandler->setNavigationStateNextFrame( interaction::NavigationState(navigationStateDictionary) ); - - // @CLEANUP: When luaDictionaryFromState doesn't leak space anymore, remove the next - // line ---abock(2018-02-15) - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int saveNavigationState(lua_State* L) { - const int n = ghoul::lua::checkArgumentsAndThrow( - L, - { 1, 2 }, - "lua::saveNavigationState" - ); + ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::saveNavigationState"); + auto [path, frame] = ghoul::lua::values>(L); + frame = frame.value_or(""); - const std::string& cameraStateFilePath = ghoul::lua::value(L, 1); - - std::string referenceFrame = ""; - if (n > 1) { - referenceFrame = ghoul::lua::value(L, 2); + if (path.empty()) { + return ghoul::lua::luaError(L, "Filepath string is empty"); } - if (cameraStateFilePath.empty()) { - return ghoul::lua::luaError(L, "filepath string is empty"); - } - - global::navigationHandler->saveNavigationState(cameraStateFilePath, referenceFrame); - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + global::navigationHandler->saveNavigationState(path, *frame); return 0; } int retargetAnchor(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::retargetAnchor"); - global::navigationHandler->orbitalNavigator().startRetargetAnchor(); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int retargetAim(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::retargetAim"); - global::navigationHandler->orbitalNavigator().startRetargetAim(); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int bindJoystickAxis(lua_State* L) { - const int n = ghoul::lua::checkArgumentsAndThrow( - L, - { 2, 6 }, - "lua::bindJoystickAxis" - ); - - const int axis = ghoul::lua::value(L, 1); - const std::string& axisType = ghoul::lua::value(L, 2); - - const bool shouldInvert = n > 2 ? ghoul::lua::value(L, 3) : false; - const bool shouldNormalize = n > 3 ? ghoul::lua::value(L, 4) : false; - const bool isSticky = n > 4 ? ghoul::lua::value(L, 5) : false; - const double sensitivity = n > 5 ? ghoul::lua::value(L, 6) : 0.0; + ghoul::lua::checkArgumentsAndThrow(L, { 2, 6 }, "lua::bindJoystickAxis"); + auto [axis, axisType, shouldInvert, shouldNormalize, isSticky, sensitivity] = + ghoul::lua::values< + int, std::string, std::optional, std::optional, + std::optional, std::optional + >(L); + shouldInvert = shouldInvert.value_or(false); + shouldNormalize = shouldNormalize.value_or(false); + isSticky = isSticky.value_or(false); + sensitivity = sensitivity.value_or(0.0); global::navigationHandler->setJoystickAxisMapping( axis, ghoul::from_string(axisType), - interaction::JoystickCameraStates::AxisInvert(shouldInvert), - interaction::JoystickCameraStates::AxisNormalize(shouldNormalize), - isSticky, - sensitivity + interaction::JoystickCameraStates::AxisInvert(*shouldInvert), + interaction::JoystickCameraStates::AxisNormalize(*shouldNormalize), + *isSticky, + *sensitivity ); - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int joystickAxis(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::joystickAxis"); - - const int axis = ghoul::lua::value(L, 1); + const int axis = ghoul::lua::value(L); using AI = interaction::JoystickCameraStates::AxisInformation; AI info = global::navigationHandler->joystickAxisMapping(axis); - lua_settop(L, 0); - const bool invert = info.invert; - const bool normalize = info.normalize; - const bool isSticky = info.isSticky; - const double sensitivity = info.sensitivity; ghoul::lua::push( L, ghoul::to_string(info.type), - invert, - normalize, - isSticky, - sensitivity + static_cast(info.invert), + static_cast(info.normalize), + info.isSticky, + info.sensitivity ); - - ghoul_assert(lua_gettop(L) == 5, "Incorrect number of items left on stack"); return 5; } int setJoystickAxisDeadzone(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::setJoystickAxisDeadzone"); - - const int axis = ghoul::lua::value(L, 1); - const float deadzone = ghoul::lua::value(L, 2); - lua_settop(L, 0); + auto [axis, deadzone] = ghoul::lua::values(L); global::navigationHandler->setJoystickAxisDeadzone(axis, deadzone); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int joystickAxisDeadzone(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setJoystickAxisDeadzone"); - - const int axis = ghoul::lua::value(L, 1, ghoul::lua::PopValue::Yes); + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::joystickAxisDeadzone"); + const int axis = ghoul::lua::value(L); const float deadzone = global::navigationHandler->joystickAxisDeadzone(axis); - ghoul::lua::push(L, deadzone); - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } int bindJoystickButton(lua_State* L) { - const int n = ghoul::lua::checkArgumentsAndThrow( - L, - { 3, 5 }, - "lua::bindJoystickButton" - ); + ghoul::lua::checkArgumentsAndThrow(L, { 3, 5 }, "lua::bindJoystickButton"); + auto [button, command, documentation, actionStr, isRemote] = + ghoul::lua::values< + int, std::string, std::string, std::optional, std::optional + >(L); + actionStr = actionStr.value_or("Press"); + isRemote = isRemote.value_or(true); - const int button = ghoul::lua::value(L, 1); - std::string command = ghoul::lua::value(L, 2); - std::string documentation = ghoul::lua::value(L, 3); - - interaction::JoystickAction action = interaction::JoystickAction::Press; - if (n >= 4) { - const std::string& actionStr = ghoul::lua::value(L, 4); - action = ghoul::from_string(actionStr); - } - - const bool isRemote = n == 5 ? ghoul::lua::value(L, 5) : true; - lua_settop(L, 0); + interaction::JoystickAction action = + ghoul::from_string(*actionStr); global::navigationHandler->bindJoystickButtonCommand( button, command, action, - interaction::JoystickCameraStates::ButtonCommandRemote(isRemote), + interaction::JoystickCameraStates::ButtonCommandRemote(*isRemote), documentation ); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int clearJoystickButton(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::bindJoystickButton"); - - const int button = ghoul::lua::value(L, 1, ghoul::lua::PopValue::Yes); - + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::clearJoystickButton"); + const int button = ghoul::lua::value(L); global::navigationHandler->clearJoystickButtonCommand(button); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int joystickButton(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::bindJoystickButton"); - - const int button = ghoul::lua::value(L, 1, ghoul::lua::PopValue::Yes); + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::joystickButton"); + const int button = ghoul::lua::value(L); const std::vector& cmds = global::navigationHandler->joystickButtonCommand(button); std::string cmd = std::accumulate( - cmds.begin(), - cmds.end(), + cmds.cbegin(), + cmds.cend(), std::string(), [](const std::string& lhs, const std::string& rhs) { return lhs + ";" + rhs; } ); - ghoul::lua::push(L, cmd); - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } int addGlobalRotation(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addGlobalRotation"); - - const double v1 = ghoul::lua::value(L, 1, ghoul::lua::PopValue::No); - const double v2 = ghoul::lua::value(L, 2, ghoul::lua::PopValue::No); + auto [v1, v2] = ghoul::lua::values(L); global::navigationHandler->orbitalNavigator().scriptStates().addGlobalRotation( glm::dvec2(v1, v2) ); - - lua_settop(L, 0); return 0; } int addLocalRotation(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addLocalRotation"); - - const double v1 = ghoul::lua::value(L, 1, ghoul::lua::PopValue::No); - const double v2 = ghoul::lua::value(L, 2, ghoul::lua::PopValue::No); + auto [v1, v2] = ghoul::lua::values(L); global::navigationHandler->orbitalNavigator().scriptStates().addLocalRotation( glm::dvec2(v1, v2) ); - - lua_settop(L, 0); return 0; } int addTruckMovement(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addTruckMovement"); - - const double v1 = ghoul::lua::value(L, 1, ghoul::lua::PopValue::No); - const double v2 = ghoul::lua::value(L, 2, ghoul::lua::PopValue::No); + auto [v1, v2] = ghoul::lua::values(L); global::navigationHandler->orbitalNavigator().scriptStates().addTruckMovement( glm::dvec2(v1, v2) ); - - lua_settop(L, 0); return 0; } int addLocalRoll(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addLocalRoll"); - - const double v1 = ghoul::lua::value(L, 1, ghoul::lua::PopValue::No); - const double v2 = ghoul::lua::value(L, 2, ghoul::lua::PopValue::No); + auto [v1, v2] = ghoul::lua::values(L); global::navigationHandler->orbitalNavigator().scriptStates().addLocalRoll( glm::dvec2(v1, v2) ); - - lua_settop(L, 0); return 0; } int addGlobalRoll(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addGlobalRoll"); - - const double v1 = ghoul::lua::value(L, 1, ghoul::lua::PopValue::No); - const double v2 = ghoul::lua::value(L, 2, ghoul::lua::PopValue::No); + auto [v1, v2] = ghoul::lua::values(L); global::navigationHandler->orbitalNavigator().scriptStates().addGlobalRoll( glm::dvec2(v1, v2) ); - - lua_settop(L, 0); return 0; } diff --git a/src/navigation/pathnavigator_lua.inl b/src/navigation/pathnavigator_lua.inl index 8766fbacd6..4fc9978e03 100644 --- a/src/navigation/pathnavigator_lua.inl +++ b/src/navigation/pathnavigator_lua.inl @@ -44,44 +44,29 @@ namespace openspace::luascriptfunctions { int isFlying(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::isFlying"); - bool hasFinished = global::navigationHandler->pathNavigator().hasFinished(); - ghoul::lua::push(L, !hasFinished); - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } int continuePath(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::continuePath"); - global::navigationHandler->pathNavigator().continuePath(); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int pausePath(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::pausePath"); - global::navigationHandler->pathNavigator().pausePath(); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int stopPath(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::stopPath"); - global::navigationHandler->pathNavigator().abortPath(); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } -// All the goTo function has the same two optional input parameters at the end. The -// purpose of this function is to handle these input parameters and add the result -// to the dictionary specifying the instruction for a camera path. int handleOptionalGoToParameters(lua_State* L, const int startLocation, const int nArguments, ghoul::Dictionary& resultInstruction) @@ -127,11 +112,19 @@ int handleOptionalGoToParameters(lua_State* L, const int startLocation, int goTo(lua_State* L) { int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 1, 3 }, "lua::goTo"); + auto [nodeIdentifier, useUpFromTargetOrDuration, duration] = ghoul::lua::values< + std::string, std::optional>, std::optional + >(L); + + if (useUpFromTargetOrDuration.has_value() && + std::holds_alternative(*useUpFromTargetOrDuration) + && duration.has_value()) + { + return ghoul::lua::luaError(L, "Duration cannot be specified twice"); + } - const std::string& nodeIdentifier = ghoul::lua::value(L, 1); if (!sceneGraphNode(nodeIdentifier)) { - lua_settop(L, 0); return ghoul::lua::luaError(L, "Unknown node name: " + nodeIdentifier); } @@ -139,12 +132,27 @@ int goTo(lua_State* L) { ghoul::Dictionary insDict; insDict.setValue("TargetType", "Node"s); insDict.setValue("Target", nodeIdentifier); - - if (nArguments > 1) { - int result = handleOptionalGoToParameters(L, 2, nArguments, insDict); - if (result != 0) { - return result; // An error occurred + if (useUpFromTargetOrDuration.has_value()) { + if (std::holds_alternative(*useUpFromTargetOrDuration)) { + insDict.setValue( + "UseTargetUpDirection", + std::get(*useUpFromTargetOrDuration) + ); } + else { + double d = std::get(*useUpFromTargetOrDuration); + if (d <= Epsilon) { + return ghoul::lua::luaError(L, "Duration must be larger than zero"); + } + insDict.setValue("Duration", d); + } + } + if (duration.has_value()) { + double d = *duration; + if (d <= Epsilon) { + return ghoul::lua::luaError(L, "Duration must be larger than zero"); + } + insDict.setValue("Duration", d); } global::navigationHandler->pathNavigator().createPath(insDict); @@ -152,35 +160,48 @@ int goTo(lua_State* L) { if (global::navigationHandler->pathNavigator().hasCurrentPath()) { global::navigationHandler->pathNavigator().startPath(); } - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int goToHeight(lua_State* L) { int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::goToHeight"); + auto [nodeIdentifier, height, useUpFromTargetOrDuration, duration] = + ghoul::lua::values< + std::string, double, std::optional>, + std::optional + >(L); - const std::string& nodeIdentifier = ghoul::lua::value(L, 1); if (!sceneGraphNode(nodeIdentifier)) { - lua_settop(L, 0); return ghoul::lua::luaError(L, "Unknown node name: " + nodeIdentifier); } - double height = ghoul::lua::value(L, 2); - using namespace std::string_literals; ghoul::Dictionary insDict; insDict.setValue("TargetType", "Node"s); insDict.setValue("Target", nodeIdentifier); insDict.setValue("Height", height); - - if (nArguments > 2) { - int result = handleOptionalGoToParameters(L, 3, nArguments, insDict); - if (result != 0) { - return result; // An error occurred + if (useUpFromTargetOrDuration.has_value()) { + if (std::holds_alternative(*useUpFromTargetOrDuration)) { + insDict.setValue( + "UseTargetUpDirection", + std::get(*useUpFromTargetOrDuration) + ); } + else { + double d = std::get(*useUpFromTargetOrDuration); + if (d <= Epsilon) { + return ghoul::lua::luaError(L, "Duration must be larger than zero"); + } + insDict.setValue("Duration", d); + } + } + if (duration.has_value()) { + double d = *duration; + if (d <= Epsilon) { + return ghoul::lua::luaError(L, "Duration must be larger than zero"); + } + insDict.setValue("Duration", d); } global::navigationHandler->pathNavigator().createPath(insDict); @@ -189,25 +210,17 @@ int goToHeight(lua_State* L) { global::navigationHandler->pathNavigator().startPath(); } - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int generatePath(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::generatePath"); - - ghoul::Dictionary dictionary; - ghoul::lua::luaDictionaryFromState(L, dictionary); + ghoul::Dictionary dictionary = ghoul::lua::value(L); global::navigationHandler->pathNavigator().createPath(dictionary); - if (global::navigationHandler->pathNavigator().hasCurrentPath()) { global::navigationHandler->pathNavigator().startPath(); } - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } diff --git a/src/network/parallelpeer_lua.inl b/src/network/parallelpeer_lua.inl index 8aad523b26..c3711d1e2f 100644 --- a/src/network/parallelpeer_lua.inl +++ b/src/network/parallelpeer_lua.inl @@ -26,45 +26,33 @@ namespace openspace::luascriptfunctions { int connect(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::connect"); - if (global::windowDelegate->isMaster()) { global::parallelPeer->connect(); } - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int disconnect(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::disconnect"); - if (global::windowDelegate->isMaster()) { global::parallelPeer->connect(); } - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int requestHostship(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::requestHostship"); - if (global::windowDelegate->isMaster()) { global::parallelPeer->requestHostship(); } - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int resignHostship(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::resignHostship"); - if (global::windowDelegate->isMaster()) { global::parallelPeer->resignHostship(); } - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } diff --git a/src/rendering/dashboard_lua.inl b/src/rendering/dashboard_lua.inl index 081e2ecbe1..3af0b132f4 100644 --- a/src/rendering/dashboard_lua.inl +++ b/src/rendering/dashboard_lua.inl @@ -28,70 +28,45 @@ namespace openspace::luascriptfunctions { /** -* \ingroup LuaScripts -* addDashboardItem(table): -*/ + * \ingroup LuaScripts + * addDashboardItem(table): + */ int addDashboardItem(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::addDashboardItem"); + ghoul::Dictionary d = ghoul::lua::value(L); - const int type = lua_type(L, -1); - if (type == LUA_TTABLE) { - ghoul::Dictionary d; - try { - ghoul::lua::luaDictionaryFromState(L, d); - } - catch (const ghoul::lua::LuaFormatException& e) { - LERRORC("addDashboardItem", e.what()); - lua_settop(L, 0); - return 0; - } - lua_settop(L, 0); - - try { - global::dashboard->addDashboardItem(DashboardItem::createFromDictionary(d)); - } - catch (const ghoul::RuntimeError& e) { - LERRORC("addDashboardItem", e.what()); - return ghoul::lua::luaError(L, "Error adding dashboard item"); - } - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); - return 0; + try { + global::dashboard->addDashboardItem( + DashboardItem::createFromDictionary(std::move(d)) + ); } - else { - return ghoul::lua::luaError(L, "Expected argument of type 'table'"); + catch (const ghoul::RuntimeError& e) { + LERRORC("addDashboardItem", e.what()); + return ghoul::lua::luaError(L, "Error adding dashboard item"); } -} -/** -* \ingroup LuaScripts -* removeDashboardItem(string): -*/ -int removeDashboardItem(lua_State* L) { - using ghoul::lua::errorLocation; - - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeDashbordItem"); - - std::string identifier = luaL_checkstring(L, -1); - - global::dashboard->removeDashboardItem(identifier); - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } +/** + * \ingroup LuaScripts + * removeDashboardItem(string): + */ +int removeDashboardItem(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeDashbordItem"); + const std::string identifier = ghoul::lua::value(L); + + global::dashboard->removeDashboardItem(identifier); + return 0; +} /** -* \ingroup LuaScripts -* removeDashboardItems(): -*/ + * \ingroup LuaScripts + * removeDashboardItems(): + */ int clearDashboardItems(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::clearDashboardItems"); - global::dashboard->clearDashboardItems(); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } diff --git a/src/rendering/renderengine_lua.inl b/src/rendering/renderengine_lua.inl index b011722f42..e3debf38c5 100644 --- a/src/rendering/renderengine_lua.inl +++ b/src/rendering/renderengine_lua.inl @@ -28,50 +28,28 @@ namespace openspace::luascriptfunctions { int addScreenSpaceRenderable(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::addScreenSpaceRenderable"); - - using ghoul::lua::errorLocation; - - ghoul::Dictionary d; - try { - ghoul::lua::luaDictionaryFromState(L, d); - lua_settop(L, 0); - } - catch (const ghoul::lua::LuaFormatException& e) { - LERRORC("addScreenSpaceRenderable", e.what()); - lua_settop(L, 0); - return 0; - } + const ghoul::Dictionary d = ghoul::lua::value(L); std::unique_ptr s = - ScreenSpaceRenderable::createFromDictionary(d); + ScreenSpaceRenderable::createFromDictionary(d); global::renderEngine->addScreenSpaceRenderable(std::move(s)); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int removeScreenSpaceRenderable(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeScreenSpaceRenderable"); + const std::string name = ghoul::lua::value(L); - const std::string& name = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); global::renderEngine->removeScreenSpaceRenderable(name); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int takeScreenshot(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::takeScreenshot"); - global::renderEngine->takeScreenshot(); const unsigned int screenshotNumber = global::renderEngine->latestScreenshotNumber(); - - lua_pushinteger(L, screenshotNumber); + ghoul::lua::push(L, screenshotNumber); return 1; } diff --git a/src/scene/assetloader_lua.inl b/src/scene/assetloader_lua.inl index 0b8884f3e2..b47b7ee4b8 100644 --- a/src/scene/assetloader_lua.inl +++ b/src/scene/assetloader_lua.inl @@ -28,8 +28,8 @@ namespace openspace::assetloader { * Adds a Lua function to be called upon asset initialization * Usage: void asset.onInitialize(function initFun) */ -int onInitialize(lua_State* state) { - Asset* asset = reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); +int onInitialize(lua_State* L) { + Asset* asset = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); return asset->loader()->onInitializeLua(asset); } @@ -37,36 +37,28 @@ int onInitialize(lua_State* state) { * Adds a Lua function to be called upon asset deinitialization * Usage: void asset.onDeinitialize(function initFun) */ -int onDeinitialize(lua_State* state) { - Asset* asset = reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); +int onDeinitialize(lua_State* L) { + Asset* asset = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); return asset->loader()->onDeinitializeLua(asset); } /** -* Adds a Lua function to be called when a dependency link is initialized -* Usage: void asset.onInitialize(function initFun) -*/ -int onInitializeDependency(lua_State* state) { - Asset* dependant = reinterpret_cast( - lua_touserdata(state, lua_upvalueindex(1)) - ); - Asset* dependency = reinterpret_cast( - lua_touserdata(state, lua_upvalueindex(2)) - ); + * Adds a Lua function to be called when a dependency link is initialized + * Usage: void asset.onInitialize(function initFun) + */ +int onInitializeDependency(lua_State* L) { + Asset* dependant = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); + Asset* dependency = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(2))); return dependant->loader()->onInitializeDependencyLua(dependant, dependency); } /** -* Adds a Lua function to be called upon asset deinitialization -* Usage: void asset.onDeinitialize(function initFun) -*/ -int onDeinitializeDependency(lua_State* state) { - Asset* dependant = reinterpret_cast( - lua_touserdata(state, lua_upvalueindex(1)) - ); - Asset* dependency = reinterpret_cast( - lua_touserdata(state, lua_upvalueindex(2)) - ); + * Adds a Lua function to be called upon asset deinitialization + * Usage: void asset.onDeinitialize(function initFun) + */ +int onDeinitializeDependency(lua_State* L) { + Asset* dependant = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); + Asset* dependency = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(2))); return dependant->loader()->onDeinitializeDependencyLua(dependant, dependency); } @@ -77,28 +69,28 @@ int onDeinitializeDependency(lua_State* state) { * Dependency: ... * Usage: {AssetTable, Dependency} = asset.import(string assetIdentifier) */ -int require(lua_State* state) { - Asset* asset = reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); +int require(lua_State* L) { + Asset* asset = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); return asset->loader()->requireLua(asset); } -int exists(lua_State* state) { - Asset* asset = reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); +int exists(lua_State* L) { + Asset* asset = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); return asset->loader()->existsLua(asset); } -int localResource(lua_State* state) { - Asset* asset = reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); +int localResource(lua_State* L) { + Asset* asset = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); return asset->loader()->localResourceLua(asset); } -int syncedResource(lua_State* state) { - Asset* asset = reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); +int syncedResource(lua_State* L) { + Asset* asset = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); return asset->loader()->syncedResourceLua(asset); } -int exportAsset(lua_State* state) { - Asset* asset = reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); +int exportAsset(lua_State* L) { + Asset* asset = reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); return asset->loader()->exportAssetLua(asset); } diff --git a/src/scene/assetmanager_lua.inl b/src/scene/assetmanager_lua.inl index 82bbbd62f9..a27e6a6bf4 100644 --- a/src/scene/assetmanager_lua.inl +++ b/src/scene/assetmanager_lua.inl @@ -28,17 +28,13 @@ namespace openspace::luascriptfunctions::asset { -int add(lua_State* state) { - ghoul::lua::checkArgumentsAndThrow(state, 1, "lua::add"); +int add(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::add"); - AssetManager* assetManager = - reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); - - const std::string& assetName = ghoul::lua::value( - state, - 1, - ghoul::lua::PopValue::Yes + AssetManager* assetManager = reinterpret_cast( + lua_touserdata(L, lua_upvalueindex(1)) ); + const std::string assetName = ghoul::lua::value(L); if (global::renderEngine->scene()) { assetManager->add(assetName); @@ -49,36 +45,27 @@ int add(lua_State* state) { global::openSpaceEngine->scheduleLoadSingleAsset(assetName); } - - ghoul_assert(lua_gettop(state) == 0, "Incorrect number of items left on stack"); return 0; } -int remove(lua_State* state) { - ghoul::lua::checkArgumentsAndThrow(state, 1, "lua::remove"); +int remove(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::remove"); AssetManager* assetManager = - reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); + reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); + const std::string assetName = ghoul::lua::value(L); - const std::string& assetName = ghoul::lua::value( - state, - 1, - ghoul::lua::PopValue::Yes - ); assetManager->remove(assetName); - - ghoul_assert(lua_gettop(state) == 0, "Incorrect number of items left on stack"); return 0; } -int removeAll(lua_State* state) { - ghoul::lua::checkArgumentsAndThrow(state, 0, "lua::removeAll"); +int removeAll(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::removeAll"); AssetManager* assetManager = - reinterpret_cast(lua_touserdata(state, lua_upvalueindex(1))); + reinterpret_cast(lua_touserdata(L, lua_upvalueindex(1))); assetManager->removeAll(); - return 0; } diff --git a/src/scene/profile_lua.inl b/src/scene/profile_lua.inl index 9f573830b0..a66f8dc1c2 100644 --- a/src/scene/profile_lua.inl +++ b/src/scene/profile_lua.inl @@ -37,21 +37,19 @@ namespace openspace::luascriptfunctions { int saveSettingsToProfile(lua_State* L) { if (!global::configuration->usingProfile) { - return luaL_error( + return ghoul::lua::luaError( L, "Program was not started with a profile, so cannot use this " "save-current-settings feature" ); } - const int n = ghoul::lua::checkArgumentsAndThrow( - L, - { 0, 2 }, - "lua::saveSettingsToProfile" - ); + ghoul::lua::checkArgumentsAndThrow(L, { 0, 2 }, "lua::saveSettingsToProfile"); + auto [saveFilePath, overwrite] = + ghoul::lua::values, std::optional>(L); + overwrite = overwrite.value_or(true); - std::string saveFilePath; - if (n == 0) { + if (!saveFilePath.has_value()) { std::time_t t = std::time(nullptr); std::tm* utcTime = std::gmtime(&t); ghoul_assert(utcTime, "Conversion to UTC failed"); @@ -68,22 +66,27 @@ int saveSettingsToProfile(lua_State* L) { std::filesystem::path path = global::configuration->profile; path.replace_extension(); std::string newFile = fmt::format("{}_{}", path.string(), time); - std::string sourcePath = fmt::format("{}/{}.profile", - absPath("${USER_PROFILES}").string(), global::configuration->profile); - std::string destPath = fmt::format("{}/{}.profile", - absPath("${PROFILES}").string(), global::configuration->profile); + std::string sourcePath = fmt::format( + "{}/{}.profile", + absPath("${USER_PROFILES}").string(), global::configuration->profile + ); + std::string destPath = fmt::format( + "{}/{}.profile", + absPath("${PROFILES}").string(), global::configuration->profile + ); if (!std::filesystem::is_regular_file(sourcePath)) { - sourcePath = absPath("${USER_PROFILES}").string() - + '/' + global::configuration->profile + ".profile"; + sourcePath = fmt::format( + "{}/{}.profile", + absPath("${USER_PROFILES}").string(), global::configuration->profile + ); } LINFOC("Profile", fmt::format("Saving a copy of the old profile as {}", newFile)); std::filesystem::copy(sourcePath, destPath); saveFilePath = global::configuration->profile; } else { - saveFilePath = ghoul::lua::value(L, 1); - if (saveFilePath.empty()) { - return luaL_error(L, "save filepath string is empty"); + if (saveFilePath->empty()) { + return ghoul::lua::luaError(L, "Save filepath string is empty"); } } @@ -91,32 +94,35 @@ int saveSettingsToProfile(lua_State* L) { std::string currentTime = std::string(global::timeManager->time().ISO8601()); interaction::NavigationState navState = global::navigationHandler->navigationState(); global::profile->saveCurrentSettingsToProfile(root, currentTime, navState); - global::configuration->profile = saveFilePath; + global::configuration->profile = *saveFilePath; - if (saveFilePath.find('/') != std::string::npos) { - return luaL_error(L, "Profile filename must not contain path (/) elements"); + if (saveFilePath->find('/') != std::string::npos) { + return ghoul::lua::luaError(L, "Profile filename must not contain (/) elements"); } - else if (saveFilePath.find(':') != std::string::npos) { - return luaL_error(L, "Profile filename must not contain path (:) elements"); + else if (saveFilePath->find(':') != std::string::npos) { + return ghoul::lua::luaError(L, "Profile filename must not contain (:) elements"); } - else if (saveFilePath.find('.') != std::string::npos) { - return luaL_error(L, "Only provide the filename to save without file extension"); + else if (saveFilePath->find('.') != std::string::npos) { + return ghoul::lua::luaError( + L, + "Only provide the filename to save without file extension" + ); } - std::string absFilename = fmt::format("{}/{}.profile", - absPath("${PROFILES}").string(), saveFilePath); + std::string absFilename = fmt::format( + "{}/{}.profile", absPath("${PROFILES}").string(), *saveFilePath + ); if (!std::filesystem::is_regular_file(absFilename)) { - absFilename = absPath("${USER_PROFILES}/" + saveFilePath + ".profile").string(); + absFilename = absPath("${USER_PROFILES}/" + *saveFilePath + ".profile").string(); } - const bool overwrite = (n == 2) ? ghoul::lua::value(L, 2) : true; if (std::filesystem::is_regular_file(absFilename) && !overwrite) { - return luaL_error( + return ghoul::lua::luaError( L, fmt::format( "Unable to save profile '{}'. File of same name already exists", absFilename - ).c_str() + ) ); } @@ -126,11 +132,11 @@ int saveSettingsToProfile(lua_State* L) { outFile.open(absFilename, std::ofstream::out); } catch (const std::ofstream::failure& e) { - return luaL_error( + return ghoul::lua::luaError( L, fmt::format( "Exception opening profile file for write: {} ({})", absFilename, e.what() - ).c_str() + ) ); } @@ -138,17 +144,11 @@ int saveSettingsToProfile(lua_State* L) { outFile << global::profile->serialize(); } catch (const std::ofstream::failure& e) { - return luaL_error( + return ghoul::lua::luaError( L, - fmt::format( - "Data write error to file: {} ({})", absFilename, e.what() - ).c_str() + fmt::format("Data write error to file: {} ({})", absFilename, e.what()) ); } - - outFile.close(); - - lua_settop(L, 0); return 0; } diff --git a/src/scene/scene_lua.inl b/src/scene/scene_lua.inl index e685a23370..77a5fd803a 100644 --- a/src/scene/scene_lua.inl +++ b/src/scene/scene_lua.inl @@ -35,7 +35,7 @@ namespace { template properties::PropertyOwner* findPropertyOwnerWithMatchingGroupTag(T* prop, - const std::string& tagToMatch) + const std::string& tagToMatch) { properties::PropertyOwner* tagMatchOwner = nullptr; properties::PropertyOwner* owner = prop->owner(); @@ -59,10 +59,9 @@ properties::PropertyOwner* findPropertyOwnerWithMatchingGroupTag(T* prop, } void applyRegularExpression(lua_State* L, const std::string& regex, - const std::vector& properties, - double interpolationDuration, - const std::string& groupName, - ghoul::EasingFunction easingFunction) + const std::vector& properties, + double interpolationDuration, const std::string& groupName, + ghoul::EasingFunction easingFunction) { using ghoul::lua::errorLocation; using ghoul::lua::luaTypeToString; @@ -73,8 +72,8 @@ void applyRegularExpression(lua_State* L, const std::string& regex, const int type = lua_type(L, -1); // Extract the property and node name to be searched for from regex - std::string propertyName = ""; - std::string nodeName = ""; + std::string propertyName; + std::string nodeName; size_t wildPos = regex.find_first_of("*"); if (wildPos != std::string::npos) { nodeName = regex.substr(0, wildPos); @@ -85,8 +84,8 @@ void applyRegularExpression(lua_State* L, const std::string& regex, LERRORC( "applyRegularExpression", fmt::format( - "Malformed regular expression: '{}': " - "Empty both before and after '*'", regex + "Malformed regular expression: '{}': Empty both before and after '*'", + regex ) ); return; @@ -97,8 +96,8 @@ void applyRegularExpression(lua_State* L, const std::string& regex, LERRORC( "applyRegularExpression", fmt::format( - "Malformed regular expression: '{}': " - "Currently only one '*' is supported", regex + "Malformed regular expression: '{}': Currently only one '*' is " + "supported", regex ) ); return; @@ -117,7 +116,7 @@ void applyRegularExpression(lua_State* L, const std::string& regex, bool foundMatching = false; for (properties::Property* prop : properties) { // Check the regular expression for all properties - const std::string& id = prop->fullyQualifiedIdentifier(); + const std::string id = prop->fullyQualifiedIdentifier(); if (isLiteral && id != propertyName) { continue; @@ -138,10 +137,7 @@ void applyRegularExpression(lua_State* L, const std::string& regex, // Check tag if (isGroupMode) { properties::PropertyOwner* matchingTaggedOwner = - findPropertyOwnerWithMatchingGroupTag( - prop, - groupName - ); + findPropertyOwnerWithMatchingGroupTag(prop, groupName); if (!matchingTaggedOwner) { continue; } @@ -154,14 +150,10 @@ void applyRegularExpression(lua_State* L, const std::string& regex, else if (!nodeName.empty()) { size_t nodePos = id.find(nodeName); if (nodePos != std::string::npos) { - // Check tag if (isGroupMode) { properties::PropertyOwner* matchingTaggedOwner = - findPropertyOwnerWithMatchingGroupTag( - prop, - groupName - ); + findPropertyOwnerWithMatchingGroupTag(prop, groupName); if (!matchingTaggedOwner) { continue; } @@ -181,12 +173,10 @@ void applyRegularExpression(lua_State* L, const std::string& regex, LERRORC( "property_setValue", fmt::format( - "{}: Property '{}' does not accept input of type '{}'. " - "Requested type: '{}'", - errorLocation(L), - prop->fullyQualifiedIdentifier(), - luaTypeToString(type), - luaTypeToString(prop->typeLua()) + "{}: Property '{}' does not accept input of type '{}'. Requested " + "type: '{}'", + errorLocation(L), prop->fullyQualifiedIdentifier(), + luaTypeToString(type), luaTypeToString(prop->typeLua()) ) ); } @@ -217,9 +207,7 @@ void applyRegularExpression(lua_State* L, const std::string& regex, LERRORC( "property_setValue", fmt::format( - "{}: No property matched the requested URI '{}'", - errorLocation(L), - regex + "{}: No property matched the requested URI '{}'", errorLocation(L), regex ) ); } @@ -228,7 +216,7 @@ void applyRegularExpression(lua_State* L, const std::string& regex, // Checks to see if URI contains a group tag (with { } around the first term). If so, // returns true and sets groupName with the tag bool doesUriContainGroupTag(const std::string& command, std::string& groupName) { - std::string name = command.substr(0, command.find_first_of(".")); + const std::string name = command.substr(0, command.find_first_of(".")); if (name.front() == '{' && name.back() == '}') { groupName = name.substr(1, name.length() - 2); return true; @@ -248,8 +236,8 @@ std::string removeGroupNameFromUri(const std::string& uri) { namespace openspace::luascriptfunctions { int setPropertyCall_single(properties::Property& prop, const std::string& uri, - lua_State* L, double duration, - ghoul::EasingFunction easingFunction) + lua_State* L, double duration, + ghoul::EasingFunction easingFunction) { using ghoul::lua::errorLocation; using ghoul::lua::luaTypeToString; @@ -261,9 +249,7 @@ int setPropertyCall_single(properties::Property& prop, const std::string& uri, fmt::format( "{}: Property '{}' does not accept input of type '{}'. " "Requested type: '{}'", - errorLocation(L), - uri, - luaTypeToString(type), + errorLocation(L), uri, luaTypeToString(type), luaTypeToString(prop.typeLua()) ) ); @@ -301,37 +287,39 @@ int setPropertyCall_single(properties::Property& prop, const std::string& uri, */ int property_setValue(lua_State* L) { - using ghoul::lua::errorLocation; - using ghoul::lua::luaTypeToString; - ghoul::lua::checkArgumentsAndThrow(L, { 2, 5 }, "lua::property_setValue"); defer { lua_settop(L, 0); }; - std::string uriOrRegex = ghoul::lua::value(L, 1); + std::string uriOrRegex = + ghoul::lua::value(L, 1, ghoul::lua::PopValue::No); std::string optimization; double interpolationDuration = 0.0; std::string easingMethodName; ghoul::EasingFunction easingMethod = ghoul::EasingFunction::Linear; if (lua_gettop(L) >= 3) { - if (lua_type(L, 3) == LUA_TNUMBER) { - interpolationDuration = ghoul::lua::value(L, 3); + if (ghoul::lua::hasValue(L, 3)) { + interpolationDuration = + ghoul::lua::value(L, 3, ghoul::lua::PopValue::No); } else { - optimization = ghoul::lua::value(L, 3); + optimization = + ghoul::lua::value(L, 3, ghoul::lua::PopValue::No); } if (lua_gettop(L) >= 4) { - if (lua_type(L, 4) == LUA_TNUMBER) { - interpolationDuration = ghoul::lua::value(L, 4); + if (ghoul::lua::hasValue(L, 4)) { + interpolationDuration = + ghoul::lua::value(L, 4, ghoul::lua::PopValue::No); } else { - easingMethodName = ghoul::lua::value(L, 4); + easingMethodName = + ghoul::lua::value(L, 4, ghoul::lua::PopValue::No); } } if (lua_gettop(L) == 5) { - optimization = ghoul::lua::value(L, 5); + optimization = ghoul::lua::value(L, 5, ghoul::lua::PopValue::No); } // Later functions expect the value to be at the last position on the stack @@ -346,7 +334,7 @@ int property_setValue(lua_State* L) { } if (!easingMethodName.empty()) { - bool correctName = ghoul::isValidEasingFunctionName(easingMethodName.c_str()); + bool correctName = ghoul::isValidEasingFunctionName(easingMethodName); if (!correctName) { LWARNINGC( "property_setValue", @@ -354,7 +342,7 @@ int property_setValue(lua_State* L) { ); } else { - easingMethod = ghoul::easingFunctionFromName(easingMethodName.c_str()); + easingMethod = ghoul::easingFunctionFromName(easingMethodName); } } @@ -392,8 +380,7 @@ int property_setValue(lua_State* L) { "property_setValue", fmt::format( "{}: Property with URI '{}' was not found", - errorLocation(L), - uriOrRegex + ghoul::lua::errorLocation(L), uriOrRegex ) ); return 0; @@ -411,8 +398,7 @@ int property_setValue(lua_State* L) { "lua::property_setGroup", fmt::format( "{}: Unexpected optimization '{}'", - errorLocation(L), - optimization + ghoul::lua::errorLocation(L), optimization ) ); } @@ -439,14 +425,9 @@ int property_setValueSingle(lua_State* L) { */ int property_hasProperty(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::property_hasProperty"); + const std::string uri = ghoul::lua::value(L); - std::string uri = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); - - openspace::properties::Property* prop = property(uri); + properties::Property* prop = property(uri); ghoul::lua::push(L, prop != nullptr); return 1; } @@ -459,44 +440,33 @@ int property_hasProperty(lua_State* L) { */ int property_getValue(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::property_getValue"); + const std::string uri = ghoul::lua::value(L); - std::string uri = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); - - openspace::properties::Property* prop = property(uri); + properties::Property* prop = property(uri); if (!prop) { LERRORC( "property_getValue", fmt::format( "{}: Property with URI '{}' was not found", - ghoul::lua::errorLocation(L), - uri + ghoul::lua::errorLocation(L), uri ) ); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } else { prop->getLuaValue(L); } - - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } /** -* \ingroup LuaScripts -* getProperty -* Returns a list of property identifiers that match the passed regular expression -*/ + * \ingroup LuaScripts + * getProperty + * Returns a list of property identifiers that match the passed regular expression + */ int property_getProperty(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::property_getProperty"); - - std::string regex = ghoul::lua::value(L, 1); - lua_pop(L, 1); + std::string regex = ghoul::lua::value(L); std::string groupName; if (doesUriContainGroupTag(regex, groupName)) { @@ -506,8 +476,8 @@ int property_getProperty(lua_State* L) { // Extract the property and node name to be searched for from regex bool isLiteral = false; - std::string propertyName = ""; - std::string nodeName = ""; + std::string propertyName; + std::string nodeName; size_t wildPos = regex.find_first_of("*"); if (wildPos != std::string::npos) { nodeName = regex.substr(0, wildPos); @@ -518,8 +488,8 @@ int property_getProperty(lua_State* L) { LERRORC( "property_getProperty", fmt::format( - "Malformed regular expression: '{}': " - "Empty both before and after '*'", regex + "Malformed regular expression: '{}': Empty both before and after '*'", + regex ) ); return 0; @@ -571,10 +541,7 @@ int property_getProperty(lua_State* L) { // Check tag if (!groupName.empty()) { properties::PropertyOwner* matchingTaggedOwner = - findPropertyOwnerWithMatchingGroupTag( - prop, - groupName - ); + findPropertyOwnerWithMatchingGroupTag(prop, groupName); if (!matchingTaggedOwner) { continue; } @@ -591,10 +558,7 @@ int property_getProperty(lua_State* L) { // Check tag if (!groupName.empty()) { properties::PropertyOwner* matchingTaggedOwner = - findPropertyOwnerWithMatchingGroupTag( - prop, - groupName - ); + findPropertyOwnerWithMatchingGroupTag(prop, groupName); if (!matchingTaggedOwner) { continue; } @@ -615,35 +579,24 @@ int property_getProperty(lua_State* L) { lua_newtable(L); int number = 1; for (const std::string& s : res) { - lua_pushstring(L, s.c_str()); + ghoul::lua::push(L, s); lua_rawseti(L, -2, number); ++number; } - return 1; } int loadScene(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadScene"); + std::string sceneFile = ghoul::lua::value(L); - const std::string& sceneFile = ghoul::lua::value(L, 1); - global::openSpaceEngine->scheduleLoadSingleAsset(sceneFile); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + global::openSpaceEngine->scheduleLoadSingleAsset(std::move(sceneFile)); return 0; } int addSceneGraphNode(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::addSceneGraphNode"); - - ghoul::Dictionary d; - try { - ghoul::lua::luaDictionaryFromState(L, d); - } - catch (const ghoul::lua::LuaFormatException& e) { - LERRORC("addSceneGraphNode", e.what()); - return ghoul::lua::luaError(L, "Error loading dictionary from lua state"); - } + const ghoul::Dictionary d = ghoul::lua::value(L); try { SceneGraphNode* node = global::renderEngine->scene()->loadNode(d); @@ -655,7 +608,7 @@ int addSceneGraphNode(lua_State* L) { global::renderEngine->scene()->initializeNode(node); } catch (const documentation::SpecificationError& e) { - std::string cat = + std::string cat = d.hasValue("Identifier") ? d.value("Identifier") : "Scene"; @@ -672,16 +625,12 @@ int addSceneGraphNode(lua_State* L) { fmt::format("Error loading scene graph node: {}", e.what()) ); } - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int removeSceneGraphNode(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeSceneGraphNode"); - - std::string name = ghoul::lua::value(L, 1, ghoul::lua::PopValue::Yes); + const std::string name = ghoul::lua::value(L); SceneGraphNode* foundNode = sceneGraphNode(name); if (!foundNode) { @@ -730,23 +679,20 @@ int removeSceneGraphNode(lua_State* L) { }; removeNode(foundNode); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int removeSceneGraphNodesFromRegex(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeSceneGraphNodesFromRegex"); - - std::string name = ghoul::lua::value(L, 1, ghoul::lua::PopValue::Yes); + const std::string name = ghoul::lua::value(L); const std::vector& nodes = global::renderEngine->scene()->allSceneGraphNodes(); // Extract the property and node name to be searched for from name bool isLiteral = false; - std::string propertyName = ""; - std::string nodeName = ""; + std::string propertyName; + std::string nodeName; size_t wildPos = name.find_first_of("*"); if (wildPos != std::string::npos) { nodeName = name.substr(0, wildPos); @@ -757,8 +703,8 @@ int removeSceneGraphNodesFromRegex(lua_State* L) { LERRORC( "removeSceneGraphNodesFromRegex", fmt::format( - "Malformed regular expression: '{}': " - "Empty both before and after '*'", name + "Malformed regular expression: '{}': Empty both before and after '*'", + name ) ); return 0; @@ -824,8 +770,7 @@ int removeSceneGraphNodesFromRegex(lua_State* L) { SceneGraphNode* parent = node->parent(); if (!parent) { LERRORC( - "removeSceneGraphNodesFromRegex", - fmt::format("Cannot remove root node") + "removeSceneGraphNodesFromRegex", fmt::format("Cannot remove root node") ); } else { @@ -845,8 +790,7 @@ int removeSceneGraphNodesFromRegex(lua_State* L) { std::function&)> markNode = [&markNode](SceneGraphNode* node, std::vector& marked) { - std::vector children = node->children(); - for (SceneGraphNode* child : children) { + for (SceneGraphNode* child : node->children()) { markNode(child, marked); } @@ -896,48 +840,33 @@ int removeSceneGraphNodesFromRegex(lua_State* L) { removeNode(markedList[0]); } - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int hasSceneGraphNode(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::hasSceneGraphNode"); + const std::string nodeName = ghoul::lua::value(L); - std::string nodeName = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(nodeName); - ghoul::lua::push(L, node != nullptr); - - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } int addInterestingTime(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addInterestingTime"); - - std::string name = ghoul::lua::value(L, 1, ghoul::lua::PopValue::No); - std::string time = ghoul::lua::value(L, 2, ghoul::lua::PopValue::No); - lua_pop(L, 2); + auto [name, time] = ghoul::lua::values(L); global::renderEngine->scene()->addInterestingTime( { std::move(name), std::move(time) } ); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int worldPosition(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::worldPosition"); + const std::string identifier = ghoul::lua::value(L); - std::string identifier = ghoul::lua::value(L, 1, ghoul::lua::PopValue::Yes); SceneGraphNode* node = sceneGraphNode(identifier); - if (!node) { return ghoul::lua::luaError( L, @@ -946,18 +875,15 @@ int worldPosition(lua_State* L) { } glm::dvec3 pos = node->worldPosition(); - ghoul::lua::push(L, pos); - - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); + ghoul::lua::push(L, std::move(pos)); return 1; } int worldRotation(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::worldRotation"); + std::string identifier = ghoul::lua::value(L); - std::string identifier = ghoul::lua::value(L, 1, ghoul::lua::PopValue::Yes); SceneGraphNode* node = sceneGraphNode(identifier); - if (!node) { return ghoul::lua::luaError( L, @@ -966,9 +892,7 @@ int worldRotation(lua_State* L) { } glm::dmat3 rot = node->worldRotationMatrix(); - ghoul::lua::push(L, rot); - - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); + ghoul::lua::push(L, std::move(rot)); return 1; } diff --git a/src/scripting/scriptengine_lua.inl b/src/scripting/scriptengine_lua.inl index 1cdc5882f9..894f6387ab 100644 --- a/src/scripting/scriptengine_lua.inl +++ b/src/scripting/scriptengine_lua.inl @@ -35,8 +35,6 @@ int printInternal(ghoul::logging::LogLevel level, lua_State* L) { log(level, "print", ghoul::lua::luaValueToString(L, i)); } lua_pop(L, nArguments); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } @@ -114,16 +112,9 @@ int printFatal(lua_State* L) { */ int absolutePath(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::absolutePath"); - - const std::string& path = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); + const std::string path = ghoul::lua::value(L); ghoul::lua::push(L, absPath(path).string()); - - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } @@ -135,18 +126,13 @@ int absolutePath(lua_State* L) { */ int setPathToken(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::setPathToken"); - - std::string pathToken = ghoul::lua::value(L, 1); - std::string path = ghoul::lua::value(L, 2); + auto [pathToken, path] = ghoul::lua::values(L); FileSys.registerPathToken( std::move(pathToken), std::move(path), ghoul::filesystem::FileSystem::Override::Yes ); - - lua_pop(L, 2); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } @@ -157,17 +143,10 @@ int setPathToken(lua_State* L) { */ int fileExists(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::fileExists"); + std::string file = ghoul::lua::value(L); - const std::string& file = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); - const bool e = std::filesystem::is_regular_file(absPath(file)); - + const bool e = std::filesystem::is_regular_file(absPath(std::move(file))); ghoul::lua::push(L, e); - - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } @@ -178,15 +157,11 @@ int fileExists(lua_State* L) { */ int readFile(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::readFile"); + const std::string file = ghoul::lua::value(L); - const std::string& file = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); std::filesystem::path p = absPath(file); if (!std::filesystem::is_regular_file(p)) { - return ghoul::lua::luaError(L, fmt::format("Could not open file {}", file)); + return ghoul::lua::luaError(L, fmt::format("Could not open file '{}'", file)); } std::ifstream f(p); @@ -204,26 +179,19 @@ int readFile(lua_State* L) { */ int directoryExists(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::directoryExists"); + std::string file = ghoul::lua::value(L); - const std::string& file = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); - const bool e = std::filesystem::is_directory(absPath(file)); - + const bool e = std::filesystem::is_directory(absPath(std::move(file))); ghoul::lua::push(L, e); - - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } int walkCommon(lua_State* L, std::function filter) { - int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 1, 3 }, "lua::walkCommon"); - - const std::string path = ghoul::lua::value(L, 1); - const bool recursive = nArguments >= 2 ? ghoul::lua::value(L, 2) : false; - const bool sorted = nArguments == 3 ? ghoul::lua::value(L, 3) : false; + ghoul::lua::checkArgumentsAndThrow(L, { 1, 3 }, "lua::walkCommon"); + auto [path, recursive, sorted] = + ghoul::lua::values, std::optional>(L); + recursive = recursive.value_or(false); + sorted = sorted.value_or(false); namespace fs = std::filesystem; std::vector result; @@ -242,16 +210,14 @@ int walkCommon(lua_State* L, std::function f } } } - - if (sorted) { - std::sort(result.begin(), result.end()); - } + } + if (sorted) { + std::sort(result.begin(), result.end()); } lua_newtable(L); - for (int i = 0; i < static_cast(result.size()); ++i) { - lua_pushstring(L, result[i].path().string().c_str()); + ghoul::lua::push(L, result[i].path().string()); lua_rawseti(L, -2, i + 1); } return 1; @@ -289,14 +255,14 @@ int walkDirectoryFiles(lua_State* L) { } /** -* \ingroup LuaScripts -* walkDirectory(string, bool, bool): -* Walks a directory and returns the subfolders of the directory as absolute paths. The -* first argument is the path of the directory that should be walked, the second argument -* determines if the walk is recursive and will continue in contained directories. The -* default value for this parameter is "false". The third argument determines whether the -* table that is returned is sorted. The default value for this parameter is "false". -*/ + * \ingroup LuaScripts + * walkDirectory(string, bool, bool): + * Walks a directory and returns the subfolders of the directory as absolute paths. The + * first argument is the path of the directory that should be walked, the second argument + * determines if the walk is recursive and will continue in contained directories. The + * default value for this parameter is "false". The third argument determines whether the + * table that is returned is sorted. The default value for this parameter is "false". + */ int walkDirectoryFolder(lua_State* L) { namespace fs = std::filesystem; return walkCommon(L, [](const fs::path& p) { return fs::is_directory(p); }); @@ -311,13 +277,10 @@ int walkDirectoryFolder(lua_State* L) { */ int directoryForPath(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::directoryForPath"); + std::string file = ghoul::lua::value(L); - std::string file = ghoul::lua::value(L, 1, ghoul::lua::PopValue::Yes); std::string path = std::filesystem::path(std::move(file)).parent_path().string(); - - ghoul::lua::push(L, path); - - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); + ghoul::lua::push(L, std::move(path)); return 1; } @@ -330,33 +293,19 @@ int directoryForPath(lua_State* L) { * is finished. */ int unzipFile(lua_State* L) { - const int nArguments = ghoul::lua::checkArgumentsAndThrow( - L, - { 2, 3 }, - "lua::unzipFile" - ); + ghoul::lua::checkArgumentsAndThrow(L, { 2, 3 }, "lua::unzipFile"); + auto [source, dest, deleteSource] = + ghoul::lua::values>(L); + source = absPath(source).string(); + dest = absPath(dest).string(); + deleteSource = deleteSource.value_or(false); - std::filesystem::path source = absPath( - ghoul::lua::value(L, 1, ghoul::lua::PopValue::No) - ); - std::filesystem::path dest = absPath( - ghoul::lua::value(L, 2, ghoul::lua::PopValue::No) - ); - - bool deleteSource = false; - if (nArguments == 3) { - deleteSource = ghoul::lua::value(L, 3, ghoul::lua::PopValue::No); - } - - auto onExtractEntry = [](const char*, void*) { return 0; }; int arg = 2; - zip_extract(source.string().c_str(), dest.string().c_str(), onExtractEntry, &arg); + zip_extract(source.c_str(), dest.c_str(), [](const char*, void*) { return 0; }, &arg); if (deleteSource && std::filesystem::is_regular_file(source)) { std::filesystem::remove(source); } - - lua_settop(L, 0); return 0; } @@ -372,7 +321,7 @@ int saveLastChangeToProfile(lua_State* L) { std::string actualLastLine; std::string lastLine; std::string line; - //add check for log file + // add check for log file if (!logfile.good()) { ghoul::lua::push(L, fmt::format("Could not open scriptlog {}", logFilePath)); printInternal(ghoul::logging::LogLevel::Error, L); diff --git a/src/scripting/scriptscheduler_lua.inl b/src/scripting/scriptscheduler_lua.inl index f0d2402539..2fe74d9ede 100644 --- a/src/scripting/scriptscheduler_lua.inl +++ b/src/scripting/scriptscheduler_lua.inl @@ -28,12 +28,8 @@ namespace openspace::luascriptfunctions { int loadFile(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadFile"); + const std::string& fileName = ghoul::lua::value(L); - const std::string& fileName = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); if (fileName.empty()) { return ghoul::lua::luaError(L, "filepath string is empty"); } @@ -56,78 +52,48 @@ int loadFile(lua_State* L) { } global::scriptScheduler->loadScripts(scripts); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int loadScheduledScript(lua_State* L) { - int nArguments = ghoul::lua::checkArgumentsAndThrow( - L, - { 2, 4 }, - "lua::loadScheduledScript" - ); + ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::loadScheduledScript"); + auto [time, forwardScript, backwardScript, universalScript] = ghoul::lua::values< + std::string, std::string, std::optional, std::optional + >(L); scripting::ScriptScheduler::ScheduledScript script; - - std::string time = ghoul::lua::value(L, 1); script.time = Time::convertTime(time); - std::string forwardScript = ghoul::lua::value(L, 2); script.forwardScript = std::move(forwardScript); + script.backwardScript = backwardScript.value_or(script.backwardScript); + script.universalScript = universalScript.value_or(script.universalScript); - if (nArguments == 3) { - std::string backwardScript = ghoul::lua::value(L, 3); - script.backwardScript = std::move(backwardScript); - } - else if (nArguments == 4) { - std::string backwardScript = ghoul::lua::value(L, 3); - script.backwardScript = std::move(backwardScript); - std::string universalScript = ghoul::lua::value(L, 4); - script.universalScript = std::move(universalScript); - } std::vector scripts; scripts.push_back(std::move(script)); global::scriptScheduler->loadScripts(scripts); - - lua_settop(L, 0); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int setModeApplicationTime(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::setModeApplicationTime"); - global::scriptScheduler->setModeApplicationTime(); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int setModeRecordedTime(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::setModeRecordedTime"); - global::scriptScheduler->setModeRecordedTime(); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int setModeSimulationTime(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::setModeSimulationTime"); - global::scriptScheduler->setModeSimulationTime(); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } int clear(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::clear"); - global::scriptScheduler->clearSchedule(); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } diff --git a/src/util/spicemanager.cpp b/src/util/spicemanager.cpp index 0f4897ac31..f5defa1f1c 100644 --- a/src/util/spicemanager.cpp +++ b/src/util/spicemanager.cpp @@ -1362,14 +1362,14 @@ scripting::LuaLibrary SpiceManager::luaLibrary() { "getSpkCoverage", &luascriptfunctions::spkCoverage, {}, - "{string [, printValues]}", + "string", "Returns a list of SPK coverage intervals for the target." }, { "getCkCoverage", &luascriptfunctions::ckCoverage, {}, - "{string [, printValues]}", + "string", "Returns a list of CK coverage intervals for the target." }, { diff --git a/src/util/spicemanager_lua.inl b/src/util/spicemanager_lua.inl index b0c2df9b63..268de67d63 100644 --- a/src/util/spicemanager_lua.inl +++ b/src/util/spicemanager_lua.inl @@ -38,20 +38,8 @@ namespace openspace::luascriptfunctions { int loadKernel(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadKernel"); + std::string argument = ghoul::lua::value(L); - bool isString = (lua_isstring(L, 1) == 1); - if (!isString) { - LERROR(fmt::format( - "{}: Expected argument of type 'string'", ghoul::lua::errorLocation(L) - )); - return 0; - } - - std::string argument = ghoul::lua::value( - L, - 1, - ghoul::lua::PopValue::Yes - ); if (!std::filesystem::is_regular_file(argument)) { return ghoul::lua::luaError( L, @@ -59,10 +47,7 @@ int loadKernel(lua_State* L) { ); } unsigned int result = SpiceManager::ref().loadKernel(argument); - - lua_pushnumber(L, result); - - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); + ghoul::lua::push(L, result); return 1; } @@ -72,37 +57,16 @@ int loadKernel(lua_State* L) { * automatically resolved. */ int unloadKernel(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::loadKernel"); + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::unloadKernel"); + std::variant argument = + ghoul::lua::value>(L); - bool isString = (lua_isstring(L, 1) == 1); - bool isNumber = (lua_isnumber(L, 1) == 1); - - if (!isString && !isNumber) { - LERRORC( - "loadKernel", - fmt::format( - "{}: Expected argument of type 'string' or 'number'", - ghoul::lua::errorLocation(L) - ) - ); - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); - return 0; + if (std::holds_alternative(argument)) { + SpiceManager::ref().unloadKernel(std::get(argument)); } - - if (isString) { - std::string argument = ghoul::lua::value(L, 1); - SpiceManager::ref().unloadKernel(argument); + else { + SpiceManager::ref().unloadKernel(std::get(argument)); } - - if (isNumber) { - unsigned int argument = ghoul::lua::value(L, 1); - SpiceManager::ref().unloadKernel(argument); - } - - lua_settop(L, 0); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } @@ -111,13 +75,9 @@ int unloadKernel(lua_State* L) { * Returns the list of bodies loaded into the spicemanager */ int spiceBodies(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, { 1,2 }, "lua::getSpiceBodies"); - bool isBool = (lua_isboolean(L, 1) == 1); - const bool buildInBodies = isBool ? ghoul::lua::value(L, 1) : false; + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::spiceBodies"); + const bool buildInBodies = ghoul::lua::value(L); - isBool = (lua_isboolean(L, 2) == 1); - bool printValues = isBool ? ghoul::lua::value(L, 2) : false; - lua_settop(L, 0); std::vector> bodies = SpiceManager::ref().spiceBodies( buildInBodies ); @@ -132,35 +92,20 @@ int spiceBodies(lua_State* L) { lua_rawset(L, -3); lua_rawseti(L, -2, number); ++number; - - if (printValues) { - LINFO(fmt::format("Body id '{}' and name: {}", body.first, body.second)); - } } - return 1; } -//internal function for getSpk and getCk coverages +// internal function for getSpk and getCk coverages void buildLuaCoverageStack(lua_State* L, - const std::vector>& coverage, - bool printValues) + const std::vector>& coverage) { - lua_settop(L, 0); lua_newtable(L); int number = 1; for (const std::pair& window : coverage) { std::string start = SpiceManager::ref().dateFromEphemerisTime(window.first); std::string end = SpiceManager::ref().dateFromEphemerisTime(window.second); - if (printValues) { - LINFO(fmt::format( - "Coverage start {} and end: {}", - SpiceManager::ref().dateFromEphemerisTime(window.first), - SpiceManager::ref().dateFromEphemerisTime(window.second) - )); - } - lua_newtable(L); ghoul::lua::push(L, 1, start); lua_rawset(L, -3); @@ -172,97 +117,45 @@ void buildLuaCoverageStack(lua_State* L, } /** - * getSpkCoverage({string, bool(optional)}): + * spkCoverage(string): * Returns the spk coverage for given body */ int spkCoverage(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::getSpkCoverage"); - const bool isString = (lua_isstring(L, 1) == 1); - const bool isBool = (lua_isboolean(L, 2) == 1); - - if (!isString) { - LERRORC( - "getSpkCoverage", - fmt::format( - "{}: Expected argument of type 'string'", - ghoul::lua::errorLocation(L) - ) - ); - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); - return 0; - } - - std::string argument = ghoul::lua::value(L, 1); - - bool printValues = isBool ? ghoul::lua::value(L, 2) : false; - buildLuaCoverageStack(L, SpiceManager::ref().spkCoverage(argument), printValues); + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::spkCoverage"); + std::string argument = ghoul::lua::value(L); + buildLuaCoverageStack(L, SpiceManager::ref().spkCoverage(argument)); return 1; } /** - * getCkCoverage({string, bool(optional)}): + * ckCoverage(string): * Returns the spk coverage for given body */ int ckCoverage(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::getCkCoverage"); - - const bool isString = (lua_isstring(L, 1) == 1); - const bool isBool = (lua_isboolean(L, 2) == 1); - - if (!isString) { - LERRORC( - "getCkCoverage", - fmt::format( - "{}: Expected argument of type 'string'", - ghoul::lua::errorLocation(L) - ) - ); - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); - return 0; - } - - std::string argument = ghoul::lua::value(L, 1); - bool printValues = isBool ? ghoul::lua::value(L, 2) : false; - buildLuaCoverageStack(L, SpiceManager::ref().ckCoverage(argument), printValues); + ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::ckCoverage"); + std::string argument = ghoul::lua::value(L); + buildLuaCoverageStack(L, SpiceManager::ref().ckCoverage(argument)); return 1; } /** * rotationMatrix({string, string, string}): - * Returns the rotationMatrix for a given body in a frame of reference - * at a specific time. + * Returns the rotationMatrix for a given body in a frame of reference at a specific time */ int rotationMatrix(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::rotationMatrix"); + auto [body, frame, date] = + ghoul::lua::values(L); - const bool isString = (lua_isstring(L, 1) == 1) && - (lua_isstring(L, 2) == 1) && (lua_isstring(L, 3) == 1); - - if (!isString) { - LERRORC( - "rotationMatrix", - fmt::format( - "{}: Expected argument of type 'string' for all three agruments", - ghoul::lua::errorLocation(L) - ) - ); - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); - return 0; - } - - std::string body = ghoul::lua::value(L, 1); - std::string frame = ghoul::lua::value(L, 2); - std::string date = ghoul::lua::value(L, 3); const double ephemerisTime = SpiceManager::ref().ephemerisTimeFromDate(date); - glm::dmat3 rotationMatrix = SpiceManager::ref().frameTransformationMatrix - (body, frame, ephemerisTime); + glm::dmat3 rotationMatrix = SpiceManager::ref().frameTransformationMatrix( + body, + frame, + ephemerisTime + ); ghoul::lua::push(L, 1, rotationMatrix); - return 1; } @@ -273,31 +166,17 @@ int rotationMatrix(lua_State* L) { */ int position(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::position"); + auto [target, observer, frame, date] = + ghoul::lua::values(L); - const bool isString = (lua_isstring(L, 1) == 1) && - (lua_isstring(L, 2) == 1) && - (lua_isstring(L, 3) == 1) && - (lua_isstring(L, 4) == 1); - - if (!isString) { - LERRORC( - "position", - fmt::format( - "{}: Expected argument of type 'string' for all four agruments", - ghoul::lua::errorLocation(L) - ) - ); - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); - return 0; - } - - std::string target = ghoul::lua::value(L, 1); - std::string observer = ghoul::lua::value(L, 2); - std::string frame = ghoul::lua::value(L, 3); - std::string date = ghoul::lua::value(L, 4); const double ephemerisTime = SpiceManager::ref().ephemerisTimeFromDate(date); - glm::dvec3 postion = SpiceManager::ref().targetPosition(target, observer, frame, {}, ephemerisTime); + glm::dvec3 postion = SpiceManager::ref().targetPosition( + target, + observer, + frame, + {}, + ephemerisTime + ); ghoul::lua::push(L, 1, postion); return 1; diff --git a/src/util/time_lua.inl b/src/util/time_lua.inl index 185567f97b..45b62120c1 100644 --- a/src/util/time_lua.inl +++ b/src/util/time_lua.inl @@ -42,46 +42,23 @@ namespace openspace::luascriptfunctions { * Sets the delta time by calling the Time::setDeltaTime method */ int time_setDeltaTime(lua_State* L) { - const int nArguments = lua_gettop(L); - if (nArguments == 1) { - const bool isNumber = (lua_isnumber(L, 1) != 0); - if (!isNumber) { - lua_settop(L, 0); - const char* msg = lua_pushfstring( - L, - "%s expected, got %s", - lua_typename(L, LUA_TNUMBER), - luaL_typename(L, -1) - ); - return luaL_error(L, "bad argument #%d (%s)", 2, msg); - } - const double newDeltaTime = lua_tonumber(L, 1); - global::timeManager->setDeltaTime(newDeltaTime); - } - else { - lua_settop(L, 0); - const char* msg = lua_pushfstring(L, - "Bad number of arguments. Expected 1 or 2."); - return ghoul::lua::luaError(L, fmt::format("bad argument ({})", msg)); - } + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::time_setDeltaTime"); + double newDeltaTime = ghoul::lua::value(L); - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + global::timeManager->setDeltaTime(newDeltaTime); return 0; } /** * \ingroup LuaScripts -* interpolateNextDeltaTimeStep(list of numbers): -* Sets the list of discrete delta time steps for the simulation speed. + * interpolateNextDeltaTimeStep(list of numbers): + * Sets the list of discrete delta time steps for the simulation speed. */ int time_setDeltaTimeSteps(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::time_setDeltaTimeSteps"); + ghoul::Dictionary dict = ghoul::lua::value(L); - ghoul::Dictionary dict; - ghoul::lua::luaDictionaryFromState(L, dict); const size_t nItems = dict.size(); - std::vector inputDeltaTimes; inputDeltaTimes.reserve(nItems); @@ -92,61 +69,48 @@ int time_setDeltaTimeSteps(lua_State* L) { inputDeltaTimes.push_back(time); } else { - const char* msg = lua_pushfstring( + return ghoul::lua::luaError( L, "Error setting delta times. Expected list of numbers" ); - return ghoul::lua::luaError(L, fmt::format("bad argument ({})", msg)); } } - lua_pop(L, 1); global::timeManager->setDeltaTimeSteps(inputDeltaTimes); - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } /** * \ingroup LuaScripts -* setNextDeltaTimeStep(): -* Immediately set the simulation speed to the first delta time step in the list that is -* larger than the current choice of simulation speed, if any. + * setNextDeltaTimeStep(): + * Immediately set the simulation speed to the first delta time step in the list that is + * larger than the current choice of simulation speed, if any. */ int time_setNextDeltaTimeStep(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::time_setNextDeltaTimeStep"); - global::timeManager->setNextDeltaTimeStep(); - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } /** * \ingroup LuaScripts -* setPreviousDeltaTimeStep(): -* Immediately set the simulation speed to the first delta time step in the list that is -* smaller than the current choice of simulation speed, if any. + * setPreviousDeltaTimeStep(): + * Immediately set the simulation speed to the first delta time step in the list that is + * smaller than the current choice of simulation speed, if any. */ int time_setPreviousDeltaTimeStep(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::time_setPreviousDeltaTimeStep"); - global::timeManager->setPreviousDeltaTimeStep(); - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } /** * \ingroup LuaScripts -* interpolateNextDeltaTimeStep([interpolationDuration]): -* Interpolate the simulation speed to the next delta time step in the list. If an input -* value is given, the interpolation is done over the specified number of seconds. -* If interpolationDuration is not provided, the interpolation time will be based on the -* `defaultDeltaTimeInterpolationDuration` property of the TimeManager. + * interpolateNextDeltaTimeStep([interpolationDuration]): + * Interpolate the simulation speed to the next delta time step in the list. If an input + * value is given, the interpolation is done over the specified number of seconds. + * If interpolationDuration is not provided, the interpolation time will be based on the + * `defaultDeltaTimeInterpolationDuration` property of the TimeManager. */ int time_interpolateNextDeltaTimeStep(lua_State* L) { ghoul::lua::checkArgumentsAndThrow( @@ -154,40 +118,22 @@ int time_interpolateNextDeltaTimeStep(lua_State* L) { { 0, 1 }, "lua::time_interpolateNextDeltaTimeStep" ); + std::optional interpDuration = ghoul::lua::value>(L); + interpDuration = interpDuration.value_or( + global::timeManager->defaultDeltaTimeInterpolationDuration() + ); - double interpolationDuration = - global::timeManager->defaultDeltaTimeInterpolationDuration(); - - const int nArguments = lua_gettop(L); - if (nArguments == 1) { - const bool durationIsNumber = (lua_isnumber(L, 1) != 0); - if (!durationIsNumber) { - lua_settop(L, 0); - const char* msg = lua_pushfstring( - L, - "%s expected, got %s", - lua_typename(L, LUA_TNUMBER), - luaL_typename(L, -1) - ); - return luaL_error(L, "bad argument #%d (%s)", 1, msg); - } - interpolationDuration = lua_tonumber(L, 1); - } - - global::timeManager->interpolateNextDeltaTimeStep(interpolationDuration); - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + global::timeManager->interpolateNextDeltaTimeStep(*interpDuration); return 0; } /** * \ingroup LuaScripts -* interpolatePreviousDeltaTimeStep([interpolationDuration]): -* Interpolate the simulation speed to the previous delta time step in the list. If an -* input value is given, the interpolation is done over the specified number of seconds. -* If interpolationDuration is not provided, the interpolation time will be based on the -* `defaultDeltaTimeInterpolationDuration` property of the TimeManager. + * interpolatePreviousDeltaTimeStep([interpolationDuration]): + * Interpolate the simulation speed to the previous delta time step in the list. If an + * input value is given, the interpolation is done over the specified number of seconds. + * If interpolationDuration is not provided, the interpolation time will be based on the + * `defaultDeltaTimeInterpolationDuration` property of the TimeManager. */ int time_interpolatePreviousDeltaTimeStep(lua_State* L) { ghoul::lua::checkArgumentsAndThrow( @@ -195,111 +141,43 @@ int time_interpolatePreviousDeltaTimeStep(lua_State* L) { { 0, 1 }, "lua::time_interpolatePreviousDeltaTimeStep" ); + std::optional interpDuration = ghoul::lua::value>(L); + interpDuration = interpDuration.value_or( + global::timeManager->defaultDeltaTimeInterpolationDuration() + ); - double interpolationDuration = - global::timeManager->defaultDeltaTimeInterpolationDuration(); - - const int nArguments = lua_gettop(L); - if (nArguments == 1) { - const bool durationIsNumber = (lua_isnumber(L, 1) != 0); - if (!durationIsNumber) { - lua_settop(L, 0); - const char* msg = lua_pushfstring( - L, - "%s expected, got %s", - lua_typename(L, LUA_TNUMBER), - luaL_typename(L, -1) - ); - return luaL_error(L, "bad argument #%d (%s)", 1, msg); - } - interpolationDuration = lua_tonumber(L, 1); - } - - global::timeManager->interpolatePreviousDeltaTimeStep(interpolationDuration); - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + global::timeManager->interpolatePreviousDeltaTimeStep(*interpDuration); return 0; } /** -* \ingroup LuaScripts -* time_interpolateDeltaTime(number [, number]): -* Interpolates the delta time by calling the Time::interpolateDeltaTime method -* Same behaviour as setDeltaTime, but interpolates the delta time. -* If interpolationDuration is not provided, the interpolation time will be based on the -* `defaultDeltaTimeInterpolationDuration` property of the TimeManager. -*/ + * \ingroup LuaScripts + * time_interpolateDeltaTime(number [, number]): + * Interpolates the delta time by calling the Time::interpolateDeltaTime method + * Same behaviour as setDeltaTime, but interpolates the delta time. + * If interpolationDuration is not provided, the interpolation time will be based on the + * `defaultDeltaTimeInterpolationDuration` property of the TimeManager. + */ int time_interpolateDeltaTime(lua_State* L) { - const int nArguments = lua_gettop(L); - if (nArguments == 2) { - const bool deltaIsNumber = (lua_isnumber(L, 1) != 0); - if (!deltaIsNumber) { - lua_settop(L, 0); - const char* msg = lua_pushfstring( - L, - "%s expected, got %s", - lua_typename(L, LUA_TNUMBER), - luaL_typename(L, -1) - ); - return luaL_error(L, "bad argument #%d (%s)", 2, msg); - } + ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::time_interpolateDeltaTime"); + auto [deltaTime, interpDuration] = + ghoul::lua::values>(L); + interpDuration = interpDuration.value_or( + global::timeManager->defaultDeltaTimeInterpolationDuration() + ); - const bool durationIsNumber = (lua_isnumber(L, 2) != 0); - if (!durationIsNumber) { - lua_settop(L, 0); - const char* msg = lua_pushfstring( - L, - "%s expected, got %s", - lua_typename(L, LUA_TNUMBER), - luaL_typename(L, -1) - ); - return luaL_error(L, "bad argument #%d (%s)", 2, msg); - } - - const double interpolationDuration = lua_tonumber(L, 2); - const double newDeltaTime = lua_tonumber(L, 1); - global::timeManager->interpolateDeltaTime(newDeltaTime, interpolationDuration); - } - else if (nArguments == 1) { - const bool isNumber = (lua_isnumber(L, 1) != 0); - if (!isNumber) { - lua_settop(L, 0); - const char* msg = lua_pushfstring( - L, - "%s expected, got %s", - lua_typename(L, LUA_TNUMBER), - luaL_typename(L, -1) - ); - return luaL_error(L, "bad argument #%d (%s)", 2, msg); - } - const double newDeltaTime = lua_tonumber(L, 1); - global::timeManager->interpolateDeltaTime( - newDeltaTime, - global::timeManager->defaultDeltaTimeInterpolationDuration() - ); - } - else { - lua_settop(L, 0); - const char* msg = lua_pushfstring(L, - "Bad number of arguments. Expected 1 or 2."); - return ghoul::lua::luaError(L, fmt::format("bad argument ({})", msg)); - } - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + global::timeManager->interpolateDeltaTime(deltaTime, *interpDuration); return 0; } - /** * \ingroup LuaScripts * deltaTime(): * Returns the delta time by calling the Time::deltaTime method */ int time_deltaTime(lua_State* L) { - lua_pushnumber(L, global::timeManager->deltaTime()); - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::time_deltaTime"); + ghoul::lua::push(L, global::timeManager->deltaTime()); return 1; } @@ -309,56 +187,51 @@ int time_deltaTime(lua_State* L) { * Toggles pause, i.e. setting the delta time to 0 and restoring it afterwards */ int time_togglePause(lua_State* L) { - const int nArguments = lua_gettop(L); - - if (nArguments == 0) { - global::timeManager->setPause(!global::timeManager->isPaused()); - } - else { - lua_settop(L, 0); - return luaL_error( - L, - "bad number of arguments, expected 0, got %i", - nArguments - ); - } - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::time_togglePause"); + global::timeManager->setPause(!global::timeManager->isPaused()); return 0; } /** -* \ingroup LuaScripts -* interpolateTogglePause([interpolationDuration]): -* Same behaviour as togglePause, but with interpolation. -* If no interpolation duration is provided, the interpolation time will be based on the -* `defaultPauseInterpolationDuration` and `defaultUnpauseInterpolationDuration` properties -* of the TimeManager. -*/ + * \ingroup LuaScripts + * interpolateTogglePause([interpolationDuration]): + * Same behaviour as togglePause, but with interpolation. + * If no interpolation duration is provided, the interpolation time will be based on the + * `defaultPauseInterpolationDuration` and `defaultUnpauseInterpolationDuration` + * properties of the TimeManager. + */ int time_interpolateTogglePause(lua_State* L) { - const int nArguments = lua_gettop(L); + ghoul::lua::checkArgumentsAndThrow(L, { 0, 1 }, "lua::time_interpolateTogglePause"); + std::optional interpDuration = ghoul::lua::value>(L); + interpDuration = interpDuration.value_or( + global::timeManager->isPaused() ? + global::timeManager->defaultUnpauseInterpolationDuration() : + global::timeManager->defaultPauseInterpolationDuration() + ); - if (nArguments == 1) { - const bool isNumber = (lua_isnumber(L, 1) != 0); - if (!isNumber) { - const char* msg = lua_pushfstring( - L, - "%s expected, got %s", - lua_typename(L, LUA_TNUMBER), - luaL_typename(L, -1) - ); - return luaL_error(L, "bad argument #%d (%s)", 1, msg); - } + global::timeManager->interpolatePause( + !global::timeManager->isPaused(), + *interpDuration + ); + return 0; +} - const double interpolationDuration = lua_tonumber(L, 1); - - global::timeManager->interpolatePause( - !global::timeManager->isPaused(), - interpolationDuration - ); +/** + * \ingroup LuaScripts + * time_pauseToggleViaKeyboard(): + * This allows for a keypress (via keybinding) to have dual functionality. In normal +* operational mode it will behave just like time_interpolateTogglePause, but + * during playback of a session recording it will pause the playback without manipulating + * the delta time. + */ +int time_pauseToggleViaKeyboard(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::time_pauseToggleViaKeyboard"); + + if (global::sessionRecording->isPlayingBack()) { + bool isPlaybackPaused = global::sessionRecording->isPlaybackPaused(); + global::sessionRecording->setPlaybackPause(!isPlaybackPaused); } - else if (nArguments == 0) { + else { const bool pause = !global::timeManager->isPaused(); global::timeManager->interpolatePause(pause, pause ? @@ -366,56 +239,6 @@ int time_interpolateTogglePause(lua_State* L) { global::timeManager->defaultUnpauseInterpolationDuration() ); } - else { - lua_settop(L, 0); - return luaL_error( - L, - "bad number of arguments, expected 0 or 1, got %i", - nArguments - ); - } - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); - return 0; -} - -/** -* \ingroup LuaScripts -* time_pauseToggleViaKeyboard(): -* This allows for a keypress (via keybinding) to have dual functionality. In normal -* operational mode it will behave just like time_interpolateTogglePause, but -* during playback of a session recording it will pause the playback without manipulating -* the delta time. -*/ -int time_pauseToggleViaKeyboard(lua_State* L) { - const int nArguments = lua_gettop(L); - - if (nArguments == 0) { - if (global::sessionRecording->isPlayingBack()) { - bool isPlaybackPaused = global::sessionRecording->isPlaybackPaused(); - global::sessionRecording->setPlaybackPause(!isPlaybackPaused); - } - else { - const bool pause = !global::timeManager->isPaused(); - global::timeManager->interpolatePause(pause, - pause ? - global::timeManager->defaultPauseInterpolationDuration() : - global::timeManager->defaultUnpauseInterpolationDuration() - ); - } - } - else { - lua_settop(L, 0); - return luaL_error( - L, - "bad number of arguments, expected 0 or 1, got %i", - nArguments - ); - } - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } @@ -425,76 +248,34 @@ int time_pauseToggleViaKeyboard(lua_State* L) { * Toggles a pause function i.e. setting the delta time to 0 and restoring it afterwards */ int time_setPause(lua_State* L) { - const int nArguments = lua_gettop(L); + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::time_setPause"); + bool pause = ghoul::lua::value(L); - if (nArguments == 1) { - const bool pause = lua_toboolean(L, 1) == 1; - global::timeManager->setPause(pause); - } - else { - lua_settop(L, 0); - return luaL_error( - L, - "bad number of arguments, expected 1, got %i", - nArguments - ); - } - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + global::timeManager->setPause(pause); return 0; } /** -* \ingroup LuaScripts -* interpolateTogglePause(bool [, interpolationDuration]): -* Same behaviour as setPause, but with interpolation. -* If no interpolation duration is provided, the interpolation time will be based on the -* `defaultPauseInterpolationDuration` and `defaultUnpauseInterpolationDuration` properties -* of the TimeManager. -*/ + * \ingroup LuaScripts + * interpolateTogglePause(bool [, interpolationDuration]): + * Same behaviour as setPause, but with interpolation. + * If no interpolation duration is provided, the interpolation time will be based on the + * `defaultPauseInterpolationDuration` and `defaultUnpauseInterpolationDuration` + * properties of the TimeManager. + */ int time_interpolatePause(lua_State* L) { - const int nArguments = lua_gettop(L); + ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::time_interpolatePause"); + auto [pause, interpDuration] = ghoul::lua::values>(L); + interpDuration = interpDuration.value_or( + pause ? + global::timeManager->defaultPauseInterpolationDuration() : + global::timeManager->defaultUnpauseInterpolationDuration() + ); - if (nArguments == 2) { - const bool isNumber = (lua_isnumber(L, 2) != 0); - if (!isNumber) { - lua_settop(L, 0); - const char* msg = lua_pushfstring( - L, - "%s expected, got %s", - lua_typename(L, LUA_TNUMBER), - luaL_typename(L, -1) - ); - return luaL_error(L, "bad argument #%d (%s)", 2, msg); - } - const double interpolationDuration = lua_tonumber(L, 2); - const bool pause = lua_toboolean(L, 1) == 1; - global::timeManager->interpolatePause(pause, interpolationDuration); - } - else if (nArguments == 1) { - const bool pause = lua_toboolean(L, 1) == 1; - global::timeManager->interpolatePause(pause, - pause ? - global::timeManager->defaultPauseInterpolationDuration() : - global::timeManager->defaultUnpauseInterpolationDuration() - ); - } - else { - lua_settop(L, 0); - return luaL_error( - L, - "bad number of arguments, expected 1 or 2, got %i", - nArguments - ); - } - - lua_settop(L, 0); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + global::timeManager->interpolatePause(pause, *interpDuration); return 0; } - /** * \ingroup LuaScripts * setTime({number, string}): @@ -505,187 +286,76 @@ int time_interpolatePause(lua_State* L) { * is called */ int time_setTime(lua_State* L) { - const bool isFunction = (lua_isfunction(L, -1) != 0); - if (isFunction) { - // If the top of the stack is a function, it is ourself - const char* msg = lua_pushfstring(L, "method called without argument"); - return ghoul::lua::luaError(L, fmt::format("bad argument #1 ({})", msg)); - } + ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::time_setTime"); + std::variant time = + ghoul::lua::value>(L); - const bool isNumber = (lua_isnumber(L, 1) != 0); - const bool isString = (lua_isstring(L, 1) != 0); - if (!isNumber && !isString) { - const char* msg = lua_pushfstring( - L, - "%s or %s expected, got %s", - lua_typename(L, LUA_TNUMBER), - lua_typename(L, LUA_TSTRING), - luaL_typename(L, -1) - ); - return ghoul::lua::luaError(L, fmt::format("bad argument #1 ({})", msg)); - } - - const int nArguments = lua_gettop(L); - if (nArguments == 1) { - if (isNumber) { - double value = lua_tonumber(L, 1); - global::timeManager->setTimeNextFrame(Time(value)); - return 0; - } - if (isString) { - const char* time = lua_tostring(L, 1); - global::timeManager->setTimeNextFrame(Time(Time::convertTime(time))); - return 0; - } - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + double t; + if (std::holds_alternative(time)) { + t = Time::convertTime(std::get(time)); } else { - return luaL_error( - L, - "bad number of arguments, expected 1 or 2, got %i", - nArguments - ); + t = std::get(time); } + + global::timeManager->setTimeNextFrame(Time(t)); return 0; } - /** -* \ingroup LuaScripts -* interpolateTime({number, string} [, interpolationDuration]): -* Interpolates the simulation time to the passed value. -* Same behaviour as setTime, but interpolates time. -* If interpolationDuration is not provided, the interpolation time will be based on the -* `defaultTimeInterpolationDuration` property of the TimeManager. -*/ + * \ingroup LuaScripts + * interpolateTime({number, string} [, interpolationDuration]): + * Interpolates the simulation time to the passed value. + * Same behaviour as setTime, but interpolates time. + * If interpolationDuration is not provided, the interpolation time will be based on the + * `defaultTimeInterpolationDuration` property of the TimeManager. + */ int time_interpolateTime(lua_State* L) { - const bool isFunction = (lua_isfunction(L, -1) != 0); - if (isFunction) { - // If the top of the stack is a function, it is ourself - const char* msg = lua_pushfstring(L, "method called without argument"); - return ghoul::lua::luaError(L, fmt::format("bad argument #1 ({})", msg)); - } + ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::time_interpolateTime"); + auto [time, interpDuration] = + ghoul::lua::values, std::optional>(L); + interpDuration = interpDuration.value_or( + global::timeManager->defaultTimeInterpolationDuration() + ); - const bool isNumber = (lua_isnumber(L, 1) != 0); - const bool isString = (lua_isstring(L, 1) != 0); - if (!isNumber && !isString) { - const char* msg = lua_pushfstring( - L, - "%s or %s expected, got %s", - lua_typename(L, LUA_TNUMBER), - lua_typename(L, LUA_TSTRING), - luaL_typename(L, -1) - ); - return ghoul::lua::luaError(L, fmt::format("bad argument #1 ({})", msg)); - } - - if (lua_gettop(L) == 1) { - if (isNumber) { - double value = lua_tonumber(L, 1); - global::timeManager->interpolateTime( - value, - global::timeManager->defaultTimeInterpolationDuration() - ); - return 0; - } - if (isString) { - const char* time = lua_tostring(L, 1); - global::timeManager->interpolateTime( - Time::convertTime(time), - global::timeManager->defaultTimeInterpolationDuration() - ); - return 0; - } - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); + double targetTime; + if (std::holds_alternative(time)) { + targetTime = Time::convertTime(std::get(time)); } else { - int nArguments = lua_gettop(L); - if (nArguments != 2) { - return luaL_error( - L, - "bad number of arguments, expected 1 or 2, got %i", - nArguments - ); - } + targetTime = std::get(time); + } - double targetTime; - if (lua_isnumber(L, 1)) { - targetTime = lua_tonumber(L, 1); - } - else { - targetTime = Time::convertTime(lua_tostring(L, 1)); - } - - const double duration = lua_tonumber(L, 2); - if (duration > 0) { - global::timeManager->interpolateTime(targetTime, duration); - } - else { - global::timeManager->setTimeNextFrame(Time(targetTime)); - } + if (*interpDuration > 0) { + global::timeManager->interpolateTime(targetTime, *interpDuration); + } + else { + global::timeManager->setTimeNextFrame(Time(targetTime)); } return 0; } - /** -* \ingroup LuaScripts -* interpolateTimeRelative(number [, interpolationDuration]): -* Interpolates the simulation time relatively, based on the specified number of seconds. -* If interpolationDuration is not provided, the interpolation time will be based on the -* `defaultTimeInterpolationDuration` property of the TimeManager. + * \ingroup LuaScripts + * interpolateTimeRelative(number [, interpolationDuration]): + * Interpolates the simulation time relatively, based on the specified number of seconds. + * If interpolationDuration is not provided, the interpolation time will be based on the + * `defaultTimeInterpolationDuration` property of the TimeManager. */ int time_interpolateTimeRelative(lua_State* L) { - const bool isFunction = (lua_isfunction(L, -1) != 0); - if (isFunction) { - // If the top of the stack is a function, it is ourself - const char* msg = lua_pushfstring(L, "method called without argument"); - return ghoul::lua::luaError(L, fmt::format("bad argument #1 ({})", msg)); - } + ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::time_interpolateTimeRelative"); + auto [delta, interpDuration] = ghoul::lua::values>(L); + interpDuration = interpDuration.value_or( + global::timeManager->defaultTimeInterpolationDuration() + ); - const bool isNumber = (lua_isnumber(L, 1) != 0); - if (!isNumber) { - const char* msg = lua_pushfstring( - L, - "%s or expected, got %s", - lua_typename(L, LUA_TNUMBER), - luaL_typename(L, -1) - ); - return ghoul::lua::luaError(L, fmt::format("bad argument #1 ({})", msg)); - } - - if (lua_gettop(L) == 1) { - double delta = lua_tonumber(L, 1); - global::timeManager->interpolateTimeRelative( - delta, - global::timeManager->defaultTimeInterpolationDuration() - ); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); - - return 0; + if (*interpDuration > 0) { + global::timeManager->interpolateTimeRelative(delta, *interpDuration); } else { - int nArguments = lua_gettop(L); - if (nArguments != 2) { - return luaL_error( - L, - "bad number of arguments, expected 1 or 2, got %i", - nArguments - ); - } - - double delta; - delta = lua_tonumber(L, 1); - - const double duration = lua_tonumber(L, 2); - if (duration > 0) { - global::timeManager->interpolateTimeRelative(delta, duration); - } - else { - global::timeManager->setTimeNextFrame( - Time(global::timeManager->time().j2000Seconds() + delta) - ); - } + global::timeManager->setTimeNextFrame( + Time(global::timeManager->time().j2000Seconds() + delta) + ); } return 0; } @@ -697,8 +367,8 @@ int time_interpolateTimeRelative(lua_State* L) { * It is returned by calling the Time::currentTime method. */ int time_currentTime(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::time_currentTime"); ghoul::lua::push(L, global::timeManager->time().j2000Seconds()); - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } @@ -709,8 +379,8 @@ int time_currentTime(lua_State* L) { * timezone by calling the Time::UTC method */ int time_currentTimeUTC(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::time_currentTimeUTC"); ghoul::lua::push(L, global::timeManager->time().UTC()); - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); return 1; } @@ -720,45 +390,44 @@ int time_currentTimeUTC(lua_State* L) { * Returns the current wallclock time as a structured ISO 8601 string in the UTC timezone. */ int time_currentWallTime(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::time_currentWallTime"); + std::time_t t = std::time(nullptr); std::tm* utcTime = std::gmtime(&t); - ghoul_assert(utcTime, "Conversion to UTC failed"); std::string time = fmt::format( "{:04d}-{:02d}-{:02d}T{:02d}:{:02d}:{:02d}", - utcTime->tm_year + 1900, - utcTime->tm_mon + 1, - utcTime->tm_mday, - utcTime->tm_hour, - utcTime->tm_min, - utcTime->tm_sec + utcTime->tm_year + 1900, utcTime->tm_mon + 1, utcTime->tm_mday, + utcTime->tm_hour, utcTime->tm_min, utcTime->tm_sec ); - lua_pushstring(L, time.c_str()); - ghoul_assert(lua_gettop(L) == 1, "Incorrect number of items left on stack"); + ghoul::lua::push(L, time); return 1; } int time_advancedTime(lua_State* L) { ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::time_advanceTime"); + auto [base, change] = + ghoul::lua::values< + std::variant, std::variant + >(L); double j2000Seconds = -1.0; - Time t; bool usesISO = false; - if (lua_type(L, 1) == LUA_TSTRING) { - j2000Seconds = Time::convertTime(ghoul::lua::value(L, 1)); + if (std::holds_alternative(base)) { + j2000Seconds = Time::convertTime(std::get(base)); usesISO = true; } - else if (lua_type(L, 1) == LUA_TNUMBER) { - j2000Seconds = ghoul::lua::value(L, 1); + else { + j2000Seconds = std::get(base); usesISO = false; } double dt = 0.0; - if (lua_type(L, 2) == LUA_TNUMBER) { - dt = ghoul::lua::value(L, 2); + if (std::holds_alternative(change)) { + dt = std::get(change); } else { - std::string modifier = ghoul::lua::value(L, 2); + std::string modifier = std::get(change); if (modifier.empty()) { return ghoul::lua::luaError(L, "Modifier string must not be empty"); } @@ -770,8 +439,7 @@ int time_advancedTime(lua_State* L) { } auto it = std::find_if( - modifier.begin(), - modifier.end(), + modifier.begin(), modifier.end(), [](unsigned char c) { const bool digit = std::isdigit(c) != 0; const bool isDot = c == '.'; @@ -784,29 +452,14 @@ int time_advancedTime(lua_State* L) { std::string unitName = std::string(it, modifier.end()); TimeUnit unit = TimeUnit::Second; - if (unitName == "s") { - unit = TimeUnit::Second; - } - else if (unitName == "m") { - unit = TimeUnit::Minute; - } - else if (unitName == "h") { - unit = TimeUnit::Hour; - } - else if (unitName == "d") { - unit = TimeUnit::Day; - } - else if (unitName == "M") { - unit = TimeUnit::Month; - } - else if (unitName == "y") { - unit = TimeUnit::Year; - } + if (unitName == "s") { unit = TimeUnit::Second; } + else if (unitName == "m") { unit = TimeUnit::Minute; } + else if (unitName == "h") { unit = TimeUnit::Hour; } + else if (unitName == "d") { unit = TimeUnit::Day; } + else if (unitName == "M") { unit = TimeUnit::Month; } + else if (unitName == "y") { unit = TimeUnit::Year; } else { - return ghoul::lua::luaError( - L, - fmt::format("Unknown unit '{}'", unitName) - ); + return ghoul::lua::luaError(L, fmt::format("Unknown unit '{}'", unitName)); } dt = convertTime(value, unit, TimeUnit::Second); @@ -815,8 +468,6 @@ int time_advancedTime(lua_State* L) { } } - lua_pop(L, 2); - if (usesISO) { ghoul::lua::push(L, Time(j2000Seconds + dt).ISO8601()); } From b2d12476dd56394f0d32f57ee5ced69c7fc85c7e Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 20 Aug 2021 12:43:47 +0200 Subject: [PATCH 02/23] Correctly specify the model size of the Apollo capsules (closes #1718) --- .../scene/solarsystem/missions/apollo/15/apollo15.asset | 1 + .../scene/solarsystem/missions/apollo/8/launch_model.asset | 6 +----- data/assets/scene/solarsystem/missions/apollo/8/model.asset | 6 +----- modules/base/rendering/renderablemodel.cpp | 2 +- 4 files changed, 4 insertions(+), 11 deletions(-) diff --git a/data/assets/scene/solarsystem/missions/apollo/15/apollo15.asset b/data/assets/scene/solarsystem/missions/apollo/15/apollo15.asset index 349ad80572..0fe0283e1e 100644 --- a/data/assets/scene/solarsystem/missions/apollo/15/apollo15.asset +++ b/data/assets/scene/solarsystem/missions/apollo/15/apollo15.asset @@ -50,6 +50,7 @@ local Apollo15 = { Renderable = { Type = "RenderableModel", GeometryFile = models .. "/ApolloCSM.osmodel", + ModelScale = 0.0001, LightSources = { { Type = "SceneGraphLightSource", diff --git a/data/assets/scene/solarsystem/missions/apollo/8/launch_model.asset b/data/assets/scene/solarsystem/missions/apollo/8/launch_model.asset index 19a8084f4e..448df1dd70 100644 --- a/data/assets/scene/solarsystem/missions/apollo/8/launch_model.asset +++ b/data/assets/scene/solarsystem/missions/apollo/8/launch_model.asset @@ -38,11 +38,6 @@ local Apollo8LaunchModel = { End = "1968 DEC 22" }, Transform = { - Scale = { - Type = "StaticScale", - -- The scale of the model is in cm; OpenSpace is in m - Scale = 0.01 - }, Rotation = { Type = "StaticRotation", Rotation = {0.0, 0.0, -3.1415 / 2} @@ -51,6 +46,7 @@ local Apollo8LaunchModel = { Renderable = { Type = "RenderableModel", GeometryFile = models .. "/ApolloCSM.osmodel", + ModelScale = 0.0001, LightSources = { { Type = "SceneGraphLightSource", diff --git a/data/assets/scene/solarsystem/missions/apollo/8/model.asset b/data/assets/scene/solarsystem/missions/apollo/8/model.asset index 4399deb973..30d2e70a15 100644 --- a/data/assets/scene/solarsystem/missions/apollo/8/model.asset +++ b/data/assets/scene/solarsystem/missions/apollo/8/model.asset @@ -50,11 +50,6 @@ local Apollo8Model = { End = "1968 DEC 28" }, Transform = { - Scale = { - Type = "StaticScale", - -- The scale of the model is in cm; OpenSpace is in m - Scale = 0.01 - }, Rotation = { Type = "StaticRotation", Rotation = {0.0, 0.0, -3.1415 / 2} @@ -63,6 +58,7 @@ local Apollo8Model = { Renderable = { Type = "RenderableModel", GeometryFile = models .. "/ApolloCSM.osmodel", + ModelScale = 0.0001, LightSources = { { Type = "SceneGraphLightSource", diff --git a/modules/base/rendering/renderablemodel.cpp b/modules/base/rendering/renderablemodel.cpp index 9b33abab36..0668183742 100644 --- a/modules/base/rendering/renderablemodel.cpp +++ b/modules/base/rendering/renderablemodel.cpp @@ -335,7 +335,7 @@ RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary) distanceUnit = DistanceUnit::Kilometer; break; - // Weired units + // Weird units case Parameters::ScaleUnit::Thou: distanceUnit = DistanceUnit::Thou; break; From 41c146654f59a58a42feb1b42d48f7b5c9a193c5 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Fri, 20 Aug 2021 13:20:35 +0200 Subject: [PATCH 03/23] Add function to print out state machine to a dot file (#1721) --- modules/statemachine/include/statemachine.h | 9 ++++- modules/statemachine/src/statemachine.cpp | 24 ++++++++++++ modules/statemachine/statemachinemodule.cpp | 38 ++++++++++++++++--- modules/statemachine/statemachinemodule.h | 7 ++++ .../statemachine/statemachinemodule_lua.inl | 16 ++++++++ 5 files changed, 88 insertions(+), 6 deletions(-) diff --git a/modules/statemachine/include/statemachine.h b/modules/statemachine/include/statemachine.h index 1bb3811a41..d1cc9e5ecb 100644 --- a/modules/statemachine/include/statemachine.h +++ b/modules/statemachine/include/statemachine.h @@ -43,11 +43,18 @@ public: void transitionTo(const std::string& newState); bool canTransitionTo(const std::string& state) const; - /* + /** * Return the identifiers of all possible transitions from the current state */ std::vector possibleTransitions() const; + /** + * Saves the state machine to a .dot file, as a directed graph. + * filename is the full name of the file, including the directory, + * but without the extension. + */ + void saveToDotFile(const std::string& filename) const; + static documentation::Documentation Documentation(); private: diff --git a/modules/statemachine/src/statemachine.cpp b/modules/statemachine/src/statemachine.cpp index aa160c302f..7511e9fa52 100644 --- a/modules/statemachine/src/statemachine.cpp +++ b/modules/statemachine/src/statemachine.cpp @@ -26,6 +26,7 @@ #include #include +#include #include namespace { @@ -195,4 +196,27 @@ std::vector StateMachine::possibleTransitions() const { return res; } +void StateMachine::saveToDotFile(const std::string& filename) const { + const std::string outputFile = filename + ".dot"; + + std::ofstream file(outputFile); + if (!file.good()) { + LERROR(fmt::format( + "Error opening file {} for saving state machine dot file", outputFile + )); + return; + } + + file << "digraph statemachine {" << std::endl; + for (const State& s : _states) { + file << "\t" << s.name() << ";" << std::endl; + } + for (const Transition& t : _transitions) { + file << "\t" << t.from() << " -> " << t.to() << ";" << std::endl; + } + file << "}" << std::endl; + + LINFO(fmt::format("Saved state machine to file: {}", outputFile)); +} + } // namespace openspace diff --git a/modules/statemachine/statemachinemodule.cpp b/modules/statemachine/statemachinemodule.cpp index 9b4f5e1a34..c8b306ba6f 100644 --- a/modules/statemachine/statemachinemodule.cpp +++ b/modules/statemachine/statemachinemodule.cpp @@ -29,7 +29,9 @@ #include #include #include +#include #include +#include #include "statemachinemodule_lua.inl" @@ -73,7 +75,7 @@ bool StateMachineModule::hasStateMachine() const { void StateMachineModule::setInitialState(const std::string initialState) { if (!_machine) { - LWARNING("Attempting to use uninitialized state machine"); + LERROR("Attempting to use uninitialized state machine"); return; } @@ -82,7 +84,7 @@ void StateMachineModule::setInitialState(const std::string initialState) { std::string StateMachineModule::currentState() const { if (!_machine || !_machine->currentState()) { - LWARNING("Attempting to use uninitialized state machine"); + LERROR("Attempting to use uninitialized state machine"); return ""; } @@ -91,7 +93,7 @@ std::string StateMachineModule::currentState() const { std::vector StateMachineModule::possibleTransitions() const { if (!_machine) { - LWARNING("Attempting to use uninitialized state machine"); + LERROR("Attempting to use uninitialized state machine"); return std::vector(); } @@ -100,7 +102,7 @@ std::vector StateMachineModule::possibleTransitions() const { void StateMachineModule::transitionTo(const std::string& newState) { if (!_machine) { - LWARNING("Attempting to use uninitialized state machine"); + LERROR("Attempting to use uninitialized state machine"); return; } @@ -109,13 +111,29 @@ void StateMachineModule::transitionTo(const std::string& newState) { bool StateMachineModule::canGoToState(const std::string& state) const { if (!_machine) { - LWARNING("Attempting to use uninitialized state machine"); + LERROR("Attempting to use uninitialized state machine"); return false; } return _machine->canTransitionTo(state); } +void StateMachineModule::saveToFile(const std::string& filename, + std::string directory) const +{ + if (!_machine) { + LERROR("Attempting to use uninitialized state machine"); + return; + } + + if (directory.back() != '/') { + directory += '/'; + } + + const std::string outputFile = absPath(directory + filename).string(); + _machine->saveToDotFile(outputFile); +} + scripting::LuaLibrary StateMachineModule::luaLibrary() const { scripting::LuaLibrary res; res.name = "statemachine"; @@ -177,6 +195,16 @@ scripting::LuaLibrary StateMachineModule::luaLibrary() const { {}, "", "Prints information about the current state and possible transitions to the log." + }, + { + "saveToDotFile", + &luascriptfunctions::saveToDotFile, + {}, + "string, [string]", + "Saves the current state machine to a .dot file as a directed graph. The " + "resulting graph can be rendered using external tools such as Graphviz. " + "The first parameter is the name of the file, and the second is an optional " + "directory. If no directory is given, the file is saved to the temp folder." } }; return res; diff --git a/modules/statemachine/statemachinemodule.h b/modules/statemachine/statemachinemodule.h index 1d0d2a39a6..0489cd117d 100644 --- a/modules/statemachine/statemachinemodule.h +++ b/modules/statemachine/statemachinemodule.h @@ -53,6 +53,13 @@ public: void transitionTo(const std::string& newState); bool canGoToState(const std::string& state) const; + /** + * Save the state machine to a file given by the name and optional directory. + * If no directory is given, the TEMP folder is used + */ + void saveToFile(const std::string& fileName, + std::string directory = "${TEMPORARY}/") const; + scripting::LuaLibrary luaLibrary() const override; std::vector documentations() const override; diff --git a/modules/statemachine/statemachinemodule_lua.inl b/modules/statemachine/statemachinemodule_lua.inl index 55415af46e..067aac3bb7 100644 --- a/modules/statemachine/statemachinemodule_lua.inl +++ b/modules/statemachine/statemachinemodule_lua.inl @@ -114,4 +114,20 @@ int printCurrentStateInfo(lua_State* L) { return 1; } +int saveToDotFile(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::saveToDotFile"); + auto [filename, directory] = + ghoul::lua::values>(L); + + StateMachineModule* module = global::moduleEngine->module(); + + if (directory.has_value()) { + module->saveToFile(filename, *directory); + } + else { + module->saveToFile(filename); + } + return 0; +} + } //namespace openspace::luascriptfunctions From e0312d32e88522e2d62088c687093bf4df6e34b8 Mon Sep 17 00:00:00 2001 From: Malin E Date: Fri, 20 Aug 2021 15:41:01 +0200 Subject: [PATCH 04/23] Add support for Qt6 --- apps/OpenSpace/ext/launcher/CMakeLists.txt | 30 +++++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/apps/OpenSpace/ext/launcher/CMakeLists.txt b/apps/OpenSpace/ext/launcher/CMakeLists.txt index fde2d6d029..6a01a739d2 100644 --- a/apps/OpenSpace/ext/launcher/CMakeLists.txt +++ b/apps/OpenSpace/ext/launcher/CMakeLists.txt @@ -64,11 +64,7 @@ set(SOURCE_FILES src/profile/propertiesdialog.cpp ) -find_package(Qt5 COMPONENTS Widgets REQUIRED) - -set(MOC_FILES "") -qt5_wrap_cpp( - MOC_FILES +set(HEADER_SOURCE include/launcherwindow.h include/profile/actiondialog.h include/profile/additionalscriptsdialog.h @@ -85,13 +81,33 @@ qt5_wrap_cpp( include/profile/propertiesdialog.h ) +find_package(Qt5 COMPONENTS Widgets) +set(MOC_FILES "") set(RESOURCE_FILES "") -qt5_add_resources(RESOURCE_FILES resources/resources.qrc) +set(LIBRARIES "") + +if (${Qt5_found}) + qt5_wrap_cpp( + MOC_FILES + ${HEADER_SOURCE} + ) + qt5_add_resources(RESOURCE_FILES resources/resources.qrc) + set(LIBRARIES Qt5::Core Qt5::Gui Qt5::Widgets) +else () + find_package(Qt6 COMPONENTS Widgets REQUIRED) + + qt6_wrap_cpp( + MOC_FILES + ${HEADER_SOURCE} + ) + qt6_add_resources(RESOURCE_FILES resources/resources.qrc) + set(LIBRARIES Qt6::Core Qt6::Gui Qt6::Widgets) +endif() add_library(openspace-ui-launcher STATIC ${HEADER_FILES} ${SOURCE_FILES} ${MOC_FILES} ${RESOURCE_FILES}) set_openspace_compile_settings(openspace-ui-launcher) target_include_directories(openspace-ui-launcher PUBLIC include) -target_link_libraries(openspace-ui-launcher PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets openspace-core) +target_link_libraries(openspace-ui-launcher PUBLIC ${LIBRARIES} openspace-core) if (MSVC) set(MSVC_WARNINGS From 4fea3d8019bb6e10221b05e73d344ae44e380428 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 20 Aug 2021 16:30:27 +0200 Subject: [PATCH 05/23] Explicitly request the Qt version --- apps/OpenSpace/ext/launcher/CMakeLists.txt | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/apps/OpenSpace/ext/launcher/CMakeLists.txt b/apps/OpenSpace/ext/launcher/CMakeLists.txt index 6a01a739d2..1f3a1061f5 100644 --- a/apps/OpenSpace/ext/launcher/CMakeLists.txt +++ b/apps/OpenSpace/ext/launcher/CMakeLists.txt @@ -81,19 +81,20 @@ set(HEADER_SOURCE include/profile/propertiesdialog.h ) -find_package(Qt5 COMPONENTS Widgets) +find_package(QT NAMES Qt6 Qt5 COMPONENTS Core Widgets REQUIRED) set(MOC_FILES "") set(RESOURCE_FILES "") set(LIBRARIES "") -if (${Qt5_found}) +if (${QT_VERSION_MAJOR} EQUAL 5) + find_package(Qt5 COMPONENTS Widgets) qt5_wrap_cpp( MOC_FILES ${HEADER_SOURCE} ) qt5_add_resources(RESOURCE_FILES resources/resources.qrc) - set(LIBRARIES Qt5::Core Qt5::Gui Qt5::Widgets) -else () + set(LIBRARIES ) +elseif (${QT_VERSION_MAJOR} EQUAL 6) find_package(Qt6 COMPONENTS Widgets REQUIRED) qt6_wrap_cpp( @@ -101,13 +102,21 @@ else () ${HEADER_SOURCE} ) qt6_add_resources(RESOURCE_FILES resources/resources.qrc) - set(LIBRARIES Qt6::Core Qt6::Gui Qt6::Widgets) +elseif (NOT DEFINED QT_VERSION_MAJOR) + message(FATAL_ERROR "Unable to find Qt version") +else () + message(FATAL_ERROR "Unsupported Qt version") endif() add_library(openspace-ui-launcher STATIC ${HEADER_FILES} ${SOURCE_FILES} ${MOC_FILES} ${RESOURCE_FILES}) set_openspace_compile_settings(openspace-ui-launcher) target_include_directories(openspace-ui-launcher PUBLIC include) -target_link_libraries(openspace-ui-launcher PUBLIC ${LIBRARIES} openspace-core) +target_link_libraries( + openspace-ui-launcher + PUBLIC + openspace-core + Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Gui Qt${QT_VERSION_MAJOR}::Widgets +) if (MSVC) set(MSVC_WARNINGS From 37d39868a9a4dc985fa71c670596d4682c2e3894 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Fri, 20 Aug 2021 16:41:29 +0200 Subject: [PATCH 06/23] Make flyTogeo work again Broke after lua function cleanup PR --- modules/globebrowsing/globebrowsingmodule_lua.inl | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/modules/globebrowsing/globebrowsingmodule_lua.inl b/modules/globebrowsing/globebrowsingmodule_lua.inl index eb7ab0f871..394f768118 100644 --- a/modules/globebrowsing/globebrowsingmodule_lua.inl +++ b/modules/globebrowsing/globebrowsingmodule_lua.inl @@ -257,7 +257,8 @@ int flyToGeo(lua_State* L) { const SceneGraphNode* n; if (providedGlobeIdentifier) { - const std::string& globeIdentifier = ghoul::lua::value(L, 1); + const std::string& globeIdentifier = + ghoul::lua::value(L, 1, ghoul::lua::PopValue::No); n = sceneGraphNode(globeIdentifier); if (!n) { return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier); @@ -284,9 +285,12 @@ int flyToGeo(lua_State* L) { } } - const double latitude = ghoul::lua::value(L, parameterOffset + 1); - const double longitude = ghoul::lua::value(L, parameterOffset + 2); - const double altitude = ghoul::lua::value(L, parameterOffset + 3); + const double latitude = + ghoul::lua::value(L, parameterOffset + 1, ghoul::lua::PopValue::No); + const double longitude = + ghoul::lua::value(L, parameterOffset + 2, ghoul::lua::PopValue::No); + const double altitude = + ghoul::lua::value(L, parameterOffset + 3, ghoul::lua::PopValue::No); // Compute the relative position based on the input values auto module = global::moduleEngine->module(); @@ -334,7 +338,8 @@ int flyToGeo(lua_State* L) { } if (firstIsNumber || nArguments > firstLocation) { - double duration = ghoul::lua::value(L, location); + double duration = + ghoul::lua::value(L, location, ghoul::lua::PopValue::No); constexpr const double Epsilon = 1e-5; if (duration <= Epsilon) { return ghoul::lua::luaError(L, "Duration must be larger than zero"); From 27c270b217244eebf1b3a962443f0b2464f096b0 Mon Sep 17 00:00:00 2001 From: Micah Date: Fri, 20 Aug 2021 13:21:14 -0400 Subject: [PATCH 07/23] update to rawtilereader size calculation. Closes #1716 --- modules/globebrowsing/src/rawtiledatareader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/globebrowsing/src/rawtiledatareader.cpp b/modules/globebrowsing/src/rawtiledatareader.cpp index 6b7b56951a..6cb557f1de 100644 --- a/modules/globebrowsing/src/rawtiledatareader.cpp +++ b/modules/globebrowsing/src/rawtiledatareader.cpp @@ -188,7 +188,8 @@ int calculateTileLevelDifference(GDALDataset* dataset, int minimumPixelSize) { } const int sizeLevel0 = maxOverview->GetXSize(); const double diff = log2(minimumPixelSize) - log2(sizeLevel0); - return static_cast(diff); + const double intdiff = diff >= 0 ? ceil(diff) : floor(diff); + return static_cast(intdiff); } /** From 2f32ddaf28ca6c86ba028a57a5785452940a801d Mon Sep 17 00:00:00 2001 From: Micah Date: Fri, 20 Aug 2021 14:02:15 -0400 Subject: [PATCH 08/23] updating earth Terrain WMS to new esri server --- .../earth/map_service_configs/ESRI/Terrain.wms | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/data/assets/scene/solarsystem/planets/earth/map_service_configs/ESRI/Terrain.wms b/data/assets/scene/solarsystem/planets/earth/map_service_configs/ESRI/Terrain.wms index ab5521e76e..5de12576ea 100644 --- a/data/assets/scene/solarsystem/planets/earth/map_service_configs/ESRI/Terrain.wms +++ b/data/assets/scene/solarsystem/planets/earth/map_service_configs/ESRI/Terrain.wms @@ -1,8 +1,17 @@ - - http://198.102.45.23/arcgis/rest/services/worldelevation3d/terrain3d? - GCS_Elevation + + http://earthlive.maptiles.arcgis.com/arcgis/rest/services/GCS_Elevation3D/ImageServer/tile/${z}/${y}/${x} - 2 + + -180 90 + 180 -90 + 16777216 8388608 + 14 top + + EPSG:4326 + 512 512 + 1 Float32 + 5 + 404,400 From db472030de710180ff96c9c8c707c19ef3bcfe41 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 21 Aug 2021 11:42:44 +0200 Subject: [PATCH 09/23] GCC warnings (#1725) --- .../launcher/include/profile/actiondialog.h | 2 +- .../include/profile/additionalscriptsdialog.h | 2 +- .../launcher/include/profile/assetsdialog.h | 2 +- .../launcher/include/profile/assettreemodel.h | 18 +++++++++--------- .../launcher/include/profile/cameradialog.h | 2 +- .../include/profile/deltatimesdialog.h | 2 +- .../launcher/include/profile/marknodesdialog.h | 2 +- .../ext/launcher/include/profile/metadialog.h | 2 +- .../launcher/include/profile/modulesdialog.h | 2 +- .../ext/launcher/include/profile/profileedit.h | 2 +- .../include/profile/propertiesdialog.h | 2 +- .../launcher/include/profile/scriptlogdialog.h | 2 +- .../ext/launcher/include/profile/timedialog.h | 2 +- .../ext/launcher/src/profile/actiondialog.cpp | 6 ++---- apps/OpenSpace/ext/sgct | 2 +- apps/OpenSpace/main.cpp | 6 +++--- apps/Wormhole/main.cpp | 2 +- ext/ghoul | 2 +- .../openspace/properties/templateproperty.h | 2 +- .../openspace/rendering/framebufferrenderer.h | 4 ++-- include/openspace/scene/sceneinitializer.h | 4 ++-- modules/base/rendering/renderabletrail.cpp | 1 - modules/debugging/debuggingmodule_lua.inl | 2 +- modules/exoplanets/exoplanetsmodule.cpp | 4 ++-- modules/globebrowsing/src/timequantizer.cpp | 5 ++--- .../space/rendering/renderablesmallbody.cpp | 3 +-- modules/statemachine/include/state.h | 2 +- modules/statemachine/include/statemachine.h | 2 +- modules/statemachine/include/transition.h | 2 +- modules/statemachine/statemachinemodule.h | 2 +- src/engine/globals.cpp | 2 +- src/interaction/tasks/convertrecformattask.cpp | 8 +++----- src/navigation/navigationstate.cpp | 3 +-- src/navigation/orbitalnavigator.cpp | 2 +- src/scene/profile.cpp | 12 ++++-------- src/util/collisionhelper.cpp | 4 +--- src/util/httprequest.cpp | 8 +++----- src/util/spicemanager.cpp | 4 ++-- .../cmake/set_openspace_compile_settings.cmake | 5 +---- support/coding/codegen | 2 +- tests/test_concurrentjobmanager.cpp | 10 +++++----- tests/test_timequantizer.cpp | 11 ----------- 42 files changed, 67 insertions(+), 97 deletions(-) diff --git a/apps/OpenSpace/ext/launcher/include/profile/actiondialog.h b/apps/OpenSpace/ext/launcher/include/profile/actiondialog.h index 2b840380c2..c08964631f 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/actiondialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/actiondialog.h @@ -38,7 +38,7 @@ class QListWidget; class QPushButton; class QTextEdit; -class ActionDialog : public QDialog { +class ActionDialog final : public QDialog { Q_OBJECT public: ActionDialog(QWidget* parent, diff --git a/apps/OpenSpace/ext/launcher/include/profile/additionalscriptsdialog.h b/apps/OpenSpace/ext/launcher/include/profile/additionalscriptsdialog.h index 661a81496e..40c330d9dd 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/additionalscriptsdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/additionalscriptsdialog.h @@ -29,7 +29,7 @@ class QTextEdit; -class AdditionalScriptsDialog : public QDialog { +class AdditionalScriptsDialog final : public QDialog { Q_OBJECT public: /** diff --git a/apps/OpenSpace/ext/launcher/include/profile/assetsdialog.h b/apps/OpenSpace/ext/launcher/include/profile/assetsdialog.h index c3a06e6c12..e11c110d55 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/assetsdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/assetsdialog.h @@ -32,7 +32,7 @@ class QTextEdit; class QTreeView; -class AssetsDialog : public QDialog { +class AssetsDialog final : public QDialog { Q_OBJECT public: /** diff --git a/apps/OpenSpace/ext/launcher/include/profile/assettreemodel.h b/apps/OpenSpace/ext/launcher/include/profile/assettreemodel.h index cce942a2d4..bfe3db62c7 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/assettreemodel.h +++ b/apps/OpenSpace/ext/launcher/include/profile/assettreemodel.h @@ -31,7 +31,7 @@ #include "openspace/scene/profile.h" #include -class AssetTreeModel : public QAbstractItemModel { +class AssetTreeModel final : public QAbstractItemModel { Q_OBJECT public: @@ -45,7 +45,7 @@ public: * function (can be multiple times) * \return QVariant data object */ - QVariant data(const QModelIndex& index, int role) const override; + QVariant data(const QModelIndex& index, int role) const final; /** * Returns the header data of the tree view @@ -57,7 +57,7 @@ public: * \return QVariant data object in the header */ QVariant headerData(int section, Qt::Orientation orientation, - int role = Qt::DisplayRole) const override; + int role = Qt::DisplayRole) const final; /** * Returns the index of item in #QModelIndex object form @@ -68,7 +68,7 @@ public: * \return #QModelIndex index of the item at specified position */ QModelIndex index(int row, int column, - const QModelIndex& parent = QModelIndex()) const override; + const QModelIndex& parent = QModelIndex()) const final; /** * Returns the index of the parent of the item specified by input param @@ -76,7 +76,7 @@ public: * \param index of item that is a child of the parent * \return #QModelIndex index of the parent */ - QModelIndex parent(const QModelIndex& index) const override; + QModelIndex parent(const QModelIndex& index) const final; /** * Returns the index of the parent of the item specified by the input params @@ -103,7 +103,7 @@ public: * \param parent #QModelIndex of the parent item * \return number of children/rows of this parent */ - int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const final; /** * Returns the number of columns of data in each item of the tree @@ -111,7 +111,7 @@ public: * \param parent specified by the #QModelIndex index * \return the number of data columns */ - int columnCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex& parent = QModelIndex()) const final; /** * Return the Qt flags of the item specified by index, which can include @@ -120,7 +120,7 @@ public: * \param index specified by the #QModelIndex index * \return the Qt flags */ - Qt::ItemFlags flags(const QModelIndex& index) const override; + Qt::ItemFlags flags(const QModelIndex& index) const final; /** * Set data at index \p index @@ -131,7 +131,7 @@ public: * \return true if the data set was successful */ bool setData(const QModelIndex& index, const QVariant& value, - int role = Qt::EditRole) override; + int role = Qt::EditRole) final; /** * Returns a vector of all #Assets selected in the tree view diff --git a/apps/OpenSpace/ext/launcher/include/profile/cameradialog.h b/apps/OpenSpace/ext/launcher/include/profile/cameradialog.h index a82211e5f2..3f60f6953a 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/cameradialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/cameradialog.h @@ -34,7 +34,7 @@ class QLabel; class QLineEdit; class QTabWidget; -class CameraDialog : public QDialog { +class CameraDialog final : public QDialog { Q_OBJECT public: /** diff --git a/apps/OpenSpace/ext/launcher/include/profile/deltatimesdialog.h b/apps/OpenSpace/ext/launcher/include/profile/deltatimesdialog.h index b366f1c57c..76c9184c25 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/deltatimesdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/deltatimesdialog.h @@ -33,7 +33,7 @@ class QListWidget; class QLineEdit; class QPushButton; -class DeltaTimesDialog : public QDialog { +class DeltaTimesDialog final : public QDialog { Q_OBJECT public: /** diff --git a/apps/OpenSpace/ext/launcher/include/profile/marknodesdialog.h b/apps/OpenSpace/ext/launcher/include/profile/marknodesdialog.h index 5524a807a3..8ff3fd7cd6 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/marknodesdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/marknodesdialog.h @@ -32,7 +32,7 @@ class QListWidget; class QListWidgetItem; class QPushButton; -class MarkNodesDialog : public QDialog { +class MarkNodesDialog final : public QDialog { Q_OBJECT public: /** diff --git a/apps/OpenSpace/ext/launcher/include/profile/metadialog.h b/apps/OpenSpace/ext/launcher/include/profile/metadialog.h index e369054d7f..b8d784aabb 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/metadialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/metadialog.h @@ -33,7 +33,7 @@ class QLineEdit; class QTextEdit; -class MetaDialog : public QDialog { +class MetaDialog final : public QDialog { Q_OBJECT public: /** diff --git a/apps/OpenSpace/ext/launcher/include/profile/modulesdialog.h b/apps/OpenSpace/ext/launcher/include/profile/modulesdialog.h index f43867c891..4245e5ff88 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/modulesdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/modulesdialog.h @@ -35,7 +35,7 @@ class QLineEdit; class QListWidget; class QPushButton; -class ModulesDialog : public QDialog { +class ModulesDialog final : public QDialog { Q_OBJECT public: /** diff --git a/apps/OpenSpace/ext/launcher/include/profile/profileedit.h b/apps/OpenSpace/ext/launcher/include/profile/profileedit.h index 2f7a655a09..f83fa1f458 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/profileedit.h +++ b/apps/OpenSpace/ext/launcher/include/profile/profileedit.h @@ -36,7 +36,7 @@ class QLabel; class QLineEdit; class QTextEdit; -class ProfileEdit : public QDialog { +class ProfileEdit final : public QDialog { Q_OBJECT public: /** diff --git a/apps/OpenSpace/ext/launcher/include/profile/propertiesdialog.h b/apps/OpenSpace/ext/launcher/include/profile/propertiesdialog.h index 6e27c30b95..c3ce1a1402 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/propertiesdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/propertiesdialog.h @@ -36,7 +36,7 @@ class QLineEdit; class QListWidget; class QPushButton; -class PropertiesDialog : public QDialog { +class PropertiesDialog final : public QDialog { Q_OBJECT public: /** diff --git a/apps/OpenSpace/ext/launcher/include/profile/scriptlogdialog.h b/apps/OpenSpace/ext/launcher/include/profile/scriptlogdialog.h index cec9bd3a52..dc970494f5 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/scriptlogdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/scriptlogdialog.h @@ -28,7 +28,7 @@ #include #include -class ScriptlogDialog : public QDialog { +class ScriptlogDialog final : public QDialog { Q_OBJECT public: /** diff --git a/apps/OpenSpace/ext/launcher/include/profile/timedialog.h b/apps/OpenSpace/ext/launcher/include/profile/timedialog.h index 244b3cfd53..81ddf0d144 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/timedialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/timedialog.h @@ -34,7 +34,7 @@ class QDateTimeEdit; class QLabel; class QLineEdit; -class TimeDialog : public QDialog { +class TimeDialog final : public QDialog { Q_OBJECT public: /** diff --git a/apps/OpenSpace/ext/launcher/src/profile/actiondialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/actiondialog.cpp index 54ad1112a1..2edd32ed2a 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/actiondialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/actiondialog.cpp @@ -65,8 +65,8 @@ ActionDialog::ActionDialog(QWidget* parent, std::vector* keybindings) : QDialog(parent) , _actions(actions) - , _keybindings(keybindings) , _actionData(*_actions) + , _keybindings(keybindings) , _keybindingsData(*_keybindings) { setWindowTitle("Actions and Keybindings"); @@ -512,9 +512,7 @@ void ActionDialog::actionSaved() { const auto it = std::find_if( _actionData.begin(), _actionData.end(), - [id = newIdentifier](const Profile::Action& action) { - return action.identifier == id; - } + [id = newIdentifier](const Profile::Action& a) { return a.identifier == id; } ); if (it != _actionData.end()) { QMessageBox::critical( diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index 2a3ef78f72..f295ad95d0 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit 2a3ef78f721e919531bb05b0cedab2dabe2bb0be +Subproject commit f295ad95d08caf18a2128c032c5179249bc36716 diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index dfd8b32c52..063057d6a5 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -960,7 +960,7 @@ void checkCommandLineForSettings(int& argc, char** argv, bool& hasSGCT, bool& ha } std::string setWindowConfigPresetForGui(const std::string labelFromCfgFile, - const std::string xmlExt, bool haveCliSGCTConfig, + bool haveCliSGCTConfig, const std::string& sgctFunctionName) { configuration::Configuration& config = *global::configuration; @@ -1046,8 +1046,9 @@ int main(int argc, char* argv[]) { // // Parse commandline arguments // + char* prgName = argv[0]; ghoul::cmdparser::CommandlineParser parser( - std::string(argv[0]), + std::string(prgName), ghoul::cmdparser::CommandlineParser::AllowUnknownCommands::Yes ); @@ -1159,7 +1160,6 @@ int main(int argc, char* argv[]) { const std::string xmlExt = ".xml"; std::string windowCfgPreset = setWindowConfigPresetForGui( labelFromCfgFile, - xmlExt, hasSGCTConfig, sgctFunctionName ); diff --git a/apps/Wormhole/main.cpp b/apps/Wormhole/main.cpp index f38d7f130a..1faa0b7c5d 100644 --- a/apps/Wormhole/main.cpp +++ b/apps/Wormhole/main.cpp @@ -129,4 +129,4 @@ int main(int argc, char** argv) { LINFO("Server stopped"); return 0; -}; +} diff --git a/ext/ghoul b/ext/ghoul index 350c0f6ec9..427a674d35 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 350c0f6ec9df6bbaf3790109188d6c97600fb60d +Subproject commit 427a674d3561dae5e0d67a18ce410765ff61040b diff --git a/include/openspace/properties/templateproperty.h b/include/openspace/properties/templateproperty.h index a9ccd7a8b7..7ad5423c4a 100644 --- a/include/openspace/properties/templateproperty.h +++ b/include/openspace/properties/templateproperty.h @@ -87,7 +87,7 @@ public: * * \param value The value that is used to set this Property */ - virtual void set(std::any value) override; + virtual void set(std::any value) final; /** * Returns the std::type_info describing the template parameter diff --git a/include/openspace/rendering/framebufferrenderer.h b/include/openspace/rendering/framebufferrenderer.h index f88e6460c3..b4207b8dcf 100644 --- a/include/openspace/rendering/framebufferrenderer.h +++ b/include/openspace/rendering/framebufferrenderer.h @@ -94,9 +94,9 @@ public: virtual void updateRendererData(); virtual void raycastersChanged(VolumeRaycaster& raycaster, - RaycasterListener::IsAttached attached); + RaycasterListener::IsAttached attached) override; virtual void deferredcastersChanged(Deferredcaster& deferredcaster, - DeferredcasterListener::IsAttached isAttached); + DeferredcasterListener::IsAttached isAttached) override; private: using RaycasterProgObjMap = std::map< diff --git a/include/openspace/scene/sceneinitializer.h b/include/openspace/scene/sceneinitializer.h index 9f7eff48e6..1439f227e3 100644 --- a/include/openspace/scene/sceneinitializer.h +++ b/include/openspace/scene/sceneinitializer.h @@ -41,7 +41,7 @@ public: virtual bool isInitializing() const = 0; }; -class SingleThreadedSceneInitializer : public SceneInitializer { +class SingleThreadedSceneInitializer final : public SceneInitializer { public: void initializeNode(SceneGraphNode* node) override; std::vector takeInitializedNodes() override; @@ -51,7 +51,7 @@ private: std::vector _initializedNodes; }; -class MultiThreadedSceneInitializer : public SceneInitializer { +class MultiThreadedSceneInitializer final : public SceneInitializer { public: MultiThreadedSceneInitializer(unsigned int nThreads); diff --git a/modules/base/rendering/renderabletrail.cpp b/modules/base/rendering/renderabletrail.cpp index 509be6db13..12f3b1f305 100644 --- a/modules/base/rendering/renderabletrail.cpp +++ b/modules/base/rendering/renderabletrail.cpp @@ -338,7 +338,6 @@ void RenderableTrail::internalRender(bool renderLines, bool renderPoints, _programObject->setUniform(_uniformCache.nVertices, nVertices); #if !defined(__APPLE__) - glm::ivec2 resolution = global::renderEngine->renderingResolution(); GLint viewport[4]; global::renderEngine->openglStateCache().viewport(viewport); _programObject->setUniform( diff --git a/modules/debugging/debuggingmodule_lua.inl b/modules/debugging/debuggingmodule_lua.inl index 36c9928b05..0d00abd3b2 100644 --- a/modules/debugging/debuggingmodule_lua.inl +++ b/modules/debugging/debuggingmodule_lua.inl @@ -170,7 +170,7 @@ int renderCameraPath(lua_State* L) { addDirectionLine(pointIdentifier(0), poses.front()); } - for (int i = 1; i < poses.size(); i++) { + for (int i = 1; i < static_cast(poses.size()); i++) { addPoint(pointIdentifier(i), poses[i].position); addLineBetweenPoints(pointIdentifier(i), pointIdentifier(i - 1), PathColor, 4.f); diff --git a/modules/exoplanets/exoplanetsmodule.cpp b/modules/exoplanets/exoplanetsmodule.cpp index f65a905e47..2f483cd099 100644 --- a/modules/exoplanets/exoplanetsmodule.cpp +++ b/modules/exoplanets/exoplanetsmodule.cpp @@ -200,13 +200,13 @@ std::string ExoplanetsModule::exoplanetsDataPath() const { return absPath( fmt::format("{}/{}", _exoplanetsDataFolder.value(), ExoplanetsDataFileName) ).string(); -}; +} std::string ExoplanetsModule::lookUpTablePath() const { return absPath( fmt::format("{}/{}", _exoplanetsDataFolder, LookupTableFileName) ).string(); -}; +} std::string ExoplanetsModule::bvColormapPath() const { return _bvColorMapPath; diff --git a/modules/globebrowsing/src/timequantizer.cpp b/modules/globebrowsing/src/timequantizer.cpp index 5317be039e..00a086d352 100644 --- a/modules/globebrowsing/src/timequantizer.cpp +++ b/modules/globebrowsing/src/timequantizer.cpp @@ -370,8 +370,8 @@ void TimeQuantizer::setResolution(const std::string& resolutionString) { } void TimeQuantizer::verifyStartTimeRestrictions() { - //If monthly time resolution then restrict to 28 days so every month is consistent - unsigned int dayUpperLimit; + // If monthly time resolution then restrict to 28 days so every month is consistent + int dayUpperLimit; std::string helpfulDescription = "the selected month"; if (_resolutionUnit == 'M') { dayUpperLimit = 28; @@ -631,7 +631,6 @@ std::vector TimeQuantizer::quantized(Time& start, Time& end) { const double startSeconds = s.J2000(); const double endSeconds = e.J2000(); const double delta = endSeconds - startSeconds; - ghoul_assert( static_cast(delta) % static_cast(_resolution) == 0, "Quantization error" diff --git a/modules/space/rendering/renderablesmallbody.cpp b/modules/space/rendering/renderablesmallbody.cpp index 3236bab79a..e3aa129911 100644 --- a/modules/space/rendering/renderablesmallbody.cpp +++ b/modules/space/rendering/renderablesmallbody.cpp @@ -134,8 +134,7 @@ RenderableSmallBody::RenderableSmallBody(const ghoul::Dictionary& dictionary) } if (dictionary.hasValue(ContiguousModeInfo.identifier)) { - _contiguousMode = static_cast( - dictionary.value(ContiguousModeInfo.identifier)); + _contiguousMode = dictionary.value(ContiguousModeInfo.identifier); } else { _contiguousMode = false; diff --git a/modules/statemachine/include/state.h b/modules/statemachine/include/state.h index 9790697830..32adb27a17 100644 --- a/modules/statemachine/include/state.h +++ b/modules/statemachine/include/state.h @@ -52,4 +52,4 @@ private: } // namespace openspace -#endif __OPENSPACE_MODULE_STATEMACHINE___STATE___H__ +#endif // __OPENSPACE_MODULE_STATEMACHINE___STATE___H__ diff --git a/modules/statemachine/include/statemachine.h b/modules/statemachine/include/statemachine.h index d1cc9e5ecb..a1a994b089 100644 --- a/modules/statemachine/include/statemachine.h +++ b/modules/statemachine/include/statemachine.h @@ -68,4 +68,4 @@ private: } // namespace openspace -#endif __OPENSPACE_MODULE_STATEMACHINE___STATEMACHINE___H__ +#endif // __OPENSPACE_MODULE_STATEMACHINE___STATEMACHINE___H__ diff --git a/modules/statemachine/include/transition.h b/modules/statemachine/include/transition.h index 7dd5932386..52761e0df1 100644 --- a/modules/statemachine/include/transition.h +++ b/modules/statemachine/include/transition.h @@ -51,4 +51,4 @@ private: } // namespace openspace -#endif __OPENSPACE_MODULE_STATEMACHINE___TRANSITION___H__ +#endif // __OPENSPACE_MODULE_STATEMACHINE___TRANSITION___H__ diff --git a/modules/statemachine/statemachinemodule.h b/modules/statemachine/statemachinemodule.h index 0489cd117d..096ced7435 100644 --- a/modules/statemachine/statemachinemodule.h +++ b/modules/statemachine/statemachinemodule.h @@ -70,4 +70,4 @@ private: } // namespace openspace -#endif __OPENSPACE_MODULE_STATEMACHINE___STATEMACHINEMODULE___H__ +#endif // __OPENSPACE_MODULE_STATEMACHINE___STATEMACHINEMODULE___H__ diff --git a/src/engine/globals.cpp b/src/engine/globals.cpp index 2d3c5a10dc..79667a34bd 100644 --- a/src/engine/globals.cpp +++ b/src/engine/globals.cpp @@ -276,7 +276,7 @@ void create() { actionManager = new (currentPos) interaction::ActionManager; ghoul_assert(actionManager, "No action manager"); currentPos += sizeof(interaction::ActionManager); -#else ^^^ WIN32 / !WIN32 vvv +#else // ^^^ WIN32 / !WIN32 vvv actionManager = new interaction::ActionManager; #endif // WIN32 diff --git a/src/interaction/tasks/convertrecformattask.cpp b/src/interaction/tasks/convertrecformattask.cpp index 505d7dc8ae..c028d34fd2 100644 --- a/src/interaction/tasks/convertrecformattask.cpp +++ b/src/interaction/tasks/convertrecformattask.cpp @@ -105,21 +105,19 @@ void ConvertRecFormatTask::convert() { expectedFileExtension_out = SessionRecording::FileExtensionBinary; } - if (std::filesystem::path(_inFilePath).extension() != expectedFileExtension_in) { + if (_inFilePath.extension() != expectedFileExtension_in) { LWARNING(fmt::format( "Input filename doesn't have expected {} format file extension", currentFormat )); } - if (std::filesystem::path(_outFilePath).extension() == expectedFileExtension_in) { + if (_outFilePath.extension() == expectedFileExtension_in) { LERROR(fmt::format( "Output filename has {} file extension, but is conversion from {}", currentFormat, currentFormat )); return; } - else if (std::filesystem::path(_outFilePath).extension() != - expectedFileExtension_out) - { + else if (_outFilePath.extension() != expectedFileExtension_out) { _outFilePath += expectedFileExtension_out; } diff --git a/src/navigation/navigationstate.cpp b/src/navigation/navigationstate.cpp index de2a28e4db..52a0346170 100644 --- a/src/navigation/navigationstate.cpp +++ b/src/navigation/navigationstate.cpp @@ -121,8 +121,7 @@ CameraPose NavigationState::cameraPose() const { const glm::dvec3 anchorWorldPosition = anchorNode->worldPosition(); const glm::dmat3 referenceFrameTransform = referenceFrameNode->worldRotationMatrix(); - resultingPose.position = anchorWorldPosition + - glm::dvec3(referenceFrameTransform * glm::dvec4(position, 1.0)); + resultingPose.position = anchorWorldPosition + referenceFrameTransform * position; glm::dvec3 upVector = up.has_value() ? glm::normalize(referenceFrameTransform * up.value()) : diff --git a/src/navigation/orbitalnavigator.cpp b/src/navigation/orbitalnavigator.cpp index a33bf4bfa4..d8cbed89d7 100644 --- a/src/navigation/orbitalnavigator.cpp +++ b/src/navigation/orbitalnavigator.cpp @@ -572,7 +572,7 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) { // Calculate a position handle based on the camera position in world space glm::dvec3 camPosToAnchorPosDiff = prevCameraPosition - anchorPos; // Use the interaction sphere to get an approximate distance to the node surface - double nodeRadius = static_cast(_anchorNode->interactionSphere()); + double nodeRadius = _anchorNode->interactionSphere(); double distFromCameraToFocus = glm::distance(prevCameraPosition, anchorPos) - nodeRadius; diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index b2f14fc04f..bbb1e2e1f1 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -498,12 +498,8 @@ void convertVersion10to11(nlohmann::json& profile) { return; } - // This needs to be changed if there is another version for any of these types later - using Action = Profile::Action; - using Keybinding = Profile::Keybinding; - - std::vector actions; - std::vector keybindings; + std::vector actions; + std::vector keybindings; std::vector kbs = profile.at("keybindings").get>(); @@ -511,7 +507,7 @@ void convertVersion10to11(nlohmann::json& profile) { version10::Keybinding& kb = kbs[i]; std::string identifier = fmt::format("profile.keybind.{}", i); - Action action; + Profile::Action action; action.identifier = identifier; action.documentation = std::move(kb.documentation); action.name = std::move(kb.name); @@ -520,7 +516,7 @@ void convertVersion10to11(nlohmann::json& profile) { action.script = std::move(kb.script); actions.push_back(std::move(action)); - Keybinding keybinding; + Profile::Keybinding keybinding; keybinding.key = kb.key; keybinding.action = identifier; keybindings.push_back(keybinding); diff --git a/src/util/collisionhelper.cpp b/src/util/collisionhelper.cpp index 411db611ef..1366e2f293 100644 --- a/src/util/collisionhelper.cpp +++ b/src/util/collisionhelper.cpp @@ -50,9 +50,7 @@ bool lineSphereIntersection(glm::dvec3 p1, glm::dvec3 p2, glm::dvec3 center, // Intersection else { // Only care about the first intersection point if we have two - const double t = static_cast( - (-b - std::sqrt(intersectionTest)) / (2.0 * a) - ); + const double t = (-b - std::sqrt(intersectionTest)) / (2.0 * a); // Check if utside of line segment between p1 and p2 if (t <= 0 || t >= 1.0) { diff --git a/src/util/httprequest.cpp b/src/util/httprequest.cpp index fe5c982b7d..76f56c3cb4 100644 --- a/src/util/httprequest.cpp +++ b/src/util/httprequest.cpp @@ -406,21 +406,19 @@ bool HttpFileDownload::initDownload() { char buffer[255]; LERROR(fmt::format( "Cannot open file '{}': {}", - std::string(_destination), + _destination, std::string(strerror_r(errno, buffer, sizeof(buffer))) )); return false; #else LERROR(fmt::format( - "Cannot open file '{}': {}", - std::string(_destination), - std::string(strerror(errno)) + "Cannot open file '{}': {}", _destination, std::string(strerror(errno)) )); return false; #endif } - LERROR(fmt::format("Cannot open file {}", std::string(_destination))); + LERROR(fmt::format("Cannot open file {}", _destination)); return false; #endif } diff --git a/src/util/spicemanager.cpp b/src/util/spicemanager.cpp index f5defa1f1c..b5500e1690 100644 --- a/src/util/spicemanager.cpp +++ b/src/util/spicemanager.cpp @@ -231,7 +231,7 @@ SpiceManager::KernelHandle SpiceManager::loadKernel(std::string filePath) { // kernels std::filesystem::path currentDirectory = std::filesystem::current_path(); - std::filesystem::path p = std::filesystem::path(path).parent_path(); + std::filesystem::path p = path.parent_path(); std::filesystem::current_path(p); LINFO(fmt::format("Loading SPICE kernel {}", path)); @@ -245,7 +245,7 @@ SpiceManager::KernelHandle SpiceManager::loadKernel(std::string filePath) { throwSpiceError("Kernel loading"); } - std::filesystem::path fileExtension = std::filesystem::path(path).extension(); + std::filesystem::path fileExtension = path.extension(); if (fileExtension == ".bc" || fileExtension == ".BC") { findCkCoverage(path.string()); // binary ck kernel } diff --git a/support/cmake/set_openspace_compile_settings.cmake b/support/cmake/set_openspace_compile_settings.cmake index 2dc978d17f..2cfd0a2e97 100644 --- a/support/cmake/set_openspace_compile_settings.cmake +++ b/support/cmake/set_openspace_compile_settings.cmake @@ -172,7 +172,7 @@ function (set_openspace_compile_settings target) "-Wvla" "-Wzero-length-array" "-Wno-missing-braces" - "-Wno-unknown-attributes" + "-Wno-ignored-attributes" ) if (OPENSPACE_WARNINGS_AS_ERRORS) set(CLANG_WARNINGS ${CLANG_WARNINGS} "-Werror") @@ -186,9 +186,6 @@ function (set_openspace_compile_settings target) "-Wpedantic" "-Wunused-parameter" "-Wuninitialized" - "-Wsuggest-attribute=const" - "-Wsuggest-final-types" - "-Wsuggest-final-methods" "-Wsuggest-override" "-Walloc-zero" "-Wduplicated-cond" diff --git a/support/coding/codegen b/support/coding/codegen index 49199f28e9..9b0d5a2b0a 160000 --- a/support/coding/codegen +++ b/support/coding/codegen @@ -1 +1 @@ -Subproject commit 49199f28e90dbd94df45f4f0b736aceb11cf4f82 +Subproject commit 9b0d5a2b0a06257640e9cd3df39084482252a8a2 diff --git a/tests/test_concurrentjobmanager.cpp b/tests/test_concurrentjobmanager.cpp index 552c212366..4eb7888cdc 100644 --- a/tests/test_concurrentjobmanager.cpp +++ b/tests/test_concurrentjobmanager.cpp @@ -34,13 +34,13 @@ namespace { : _jobExecutingTime(jobExecutingTime) {} - virtual void execute() { + virtual void execute() override { std::this_thread::sleep_for(std::chrono::milliseconds(_jobExecutingTime)); prod = 1337; } - virtual int product() { - return int(prod); + virtual int product() override { + return prod; } private: @@ -64,12 +64,12 @@ namespace { , _product(-1) {} - virtual void execute() { + virtual void execute() override { std::this_thread::sleep_for(std::chrono::milliseconds(_jobExecutingTime)); _product = VerboseProduct(1337); } - virtual VerboseProduct product() { + virtual VerboseProduct product() override { return _product; } diff --git a/tests/test_timequantizer.cpp b/tests/test_timequantizer.cpp index 6f7f777a77..e48e8e0b58 100644 --- a/tests/test_timequantizer.cpp +++ b/tests/test_timequantizer.cpp @@ -34,17 +34,6 @@ using namespace openspace; namespace { - constexpr const int FILLEN = 128; - constexpr const int TYPLEN = 32; - constexpr const int SRCLEN = 128; - - namespace spicemanager_constants { - const int nrMetaKernels = 9; - SpiceInt which, handle, count = 0; - char file[FILLEN], filtyp[TYPLEN], source[SRCLEN]; - double abs_error = 0.00001; - } // namespace spicemanager_constants - int loadLSKKernel() { int kernelID = openspace::SpiceManager::ref().loadKernel( absPath("${TESTDIR}/SpiceTest/spicekernels/naif0008.tls").string() From 8b59760a5993d38af7fd165017c7f11cda949cd8 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 21 Aug 2021 11:45:38 +0200 Subject: [PATCH 10/23] Update submodules --- apps/OpenSpace/ext/sgct | 2 +- ext/ghoul | 2 +- support/coding/codegen | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index f295ad95d0..a7b225f605 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit f295ad95d08caf18a2128c032c5179249bc36716 +Subproject commit a7b225f605efe02eeb98ee485c1c71cdb12e31fa diff --git a/ext/ghoul b/ext/ghoul index 427a674d35..c7f7c61026 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 427a674d3561dae5e0d67a18ce410765ff61040b +Subproject commit c7f7c6102609eadb8f8d4c45ab6dc8193740f809 diff --git a/support/coding/codegen b/support/coding/codegen index 9b0d5a2b0a..6b503ca507 160000 --- a/support/coding/codegen +++ b/support/coding/codegen @@ -1 +1 @@ -Subproject commit 9b0d5a2b0a06257640e9cd3df39084482252a8a2 +Subproject commit 6b503ca507df9ef057991d4acc248cab021a3355 From 9d8d4147e851faf78b8a7c338a94474c18189980 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 23 Aug 2021 13:42:08 +0200 Subject: [PATCH 11/23] Feature/sync unsync (#1722) Add Lua script to manually sync or unsync resources (closes #1713) --- modules/sync/CMakeLists.txt | 1 + modules/sync/syncmodule.cpp | 32 +++++++++++++ modules/sync/syncmodule.h | 2 + modules/sync/syncmodule_lua.inl | 80 +++++++++++++++++++++++++++++++++ 4 files changed, 115 insertions(+) create mode 100644 modules/sync/syncmodule_lua.inl diff --git a/modules/sync/CMakeLists.txt b/modules/sync/CMakeLists.txt index 2870e014cb..8efa3552de 100644 --- a/modules/sync/CMakeLists.txt +++ b/modules/sync/CMakeLists.txt @@ -34,6 +34,7 @@ source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES syncmodule.cpp + syncmodule_lua.inl syncs/httpsynchronization.cpp syncs/urlsynchronization.cpp tasks/syncassettask.cpp diff --git a/modules/sync/syncmodule.cpp b/modules/sync/syncmodule.cpp index d3339de8c7..7a0a82c0da 100644 --- a/modules/sync/syncmodule.cpp +++ b/modules/sync/syncmodule.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -40,6 +41,8 @@ #include #include +#include "syncmodule_lua.inl" + namespace { constexpr const char* KeyHttpSynchronizationRepositories = "HttpSynchronizationRepositories"; @@ -140,4 +143,33 @@ std::vector SyncModule::documentations() const { }; } +scripting::LuaLibrary SyncModule::luaLibrary() const { + scripting::LuaLibrary res; + res.name = "sync"; + res.functions = { + { + "syncResource", + &luascriptfunctions::syncResource, + {}, + "string, number", + "Synchronizes the http resource identified by the name passed as the " + "first parameter and the version provided as the second parameter. The " + "application will hang while the data is being downloaded" + }, + { + "unsyncResource", + &luascriptfunctions::unsyncResource, + {}, + "string [, number]", + "Unsynchronizes the http resources identified by the name passed as the " + "first parameter by removing all data that was downloaded as part of the " + "original synchronization. If the second parameter is provided, is it " + "the version of the resources that is unsynchronized, if the parameter " + "is not provided, all versions for the specified http resource are " + "removed." + } + }; + return res; +} + } // namespace openspace diff --git a/modules/sync/syncmodule.h b/modules/sync/syncmodule.h index 03c7956eaf..08f7b48532 100644 --- a/modules/sync/syncmodule.h +++ b/modules/sync/syncmodule.h @@ -42,6 +42,8 @@ public: std::vector documentations() const override; + scripting::LuaLibrary luaLibrary() const override; + protected: void internalInitialize(const ghoul::Dictionary& configuration) override; diff --git a/modules/sync/syncmodule_lua.inl b/modules/sync/syncmodule_lua.inl new file mode 100644 index 0000000000..b9d2c648e5 --- /dev/null +++ b/modules/sync/syncmodule_lua.inl @@ -0,0 +1,80 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * 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 + +namespace openspace::luascriptfunctions { + +int syncResource(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::syncResource"); + auto [identifier, version] = ghoul::lua::values(L); + + ghoul::Dictionary dict; + dict.setValue("Identifier", identifier); + dict.setValue("Version", version); + + const SyncModule* module = global::moduleEngine->module(); + HttpSynchronization sync( + dict, + module->synchronizationRoot(), + module->httpSynchronizationRepositories() + ); + + sync.start(); + + while (sync.isSyncing()) { + std::this_thread::sleep_for(std::chrono::milliseconds(20)); + } + + ghoul::lua::push(L, sync.isResolved()); + return 1; +} + +int unsyncResource(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::unsyncResource"); + auto [identifier, version] = ghoul::lua::values>(L); + + const SyncModule* module = global::moduleEngine->module(); + std::filesystem::path sync = absPath(module->synchronizationRoot()); + std::filesystem::path base = sync / "http" / identifier; + + if (!version.has_value()) { + // If no version was provided, we remove all of the files + std::filesystem::remove_all(base); + } + else { + const int v = *version; + + std::filesystem::path folder = base / std::to_string(v); + std::string syncFile = std::to_string(v) + ".ossync"; + + std::filesystem::remove_all(folder); + std::filesystem::remove(base / syncFile); + } + + return 0; +} + +} // namespace openspace::luascriptfunctions From b649509bf08a994c64943279e20c7cff0583fefd Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Tue, 24 Aug 2021 10:45:19 +0200 Subject: [PATCH 12/23] Feature/model shader (#1723) * Add support for RenderableModel to take custom shader code * Added example to highlight usage --- .../assets/examples/modelshader/model_fs.glsl | 75 +++++++++++++++++++ .../assets/examples/modelshader/model_vs.glsl | 68 +++++++++++++++++ .../examples/modelshader/modelshader.asset | 45 +++++++++++ modules/base/rendering/renderablemodel.cpp | 55 ++++++++++++-- modules/base/rendering/renderablemodel.h | 2 + modules/base/shaders/model_vs.glsl | 14 ++-- 6 files changed, 244 insertions(+), 15 deletions(-) create mode 100644 data/assets/examples/modelshader/model_fs.glsl create mode 100644 data/assets/examples/modelshader/model_vs.glsl create mode 100644 data/assets/examples/modelshader/modelshader.asset diff --git a/data/assets/examples/modelshader/model_fs.glsl b/data/assets/examples/modelshader/model_fs.glsl new file mode 100644 index 0000000000..854a04fa98 --- /dev/null +++ b/data/assets/examples/modelshader/model_fs.glsl @@ -0,0 +1,75 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * 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 "fragment.glsl" + +in vec2 vs_st; +in vec3 vs_normalViewSpace; +in vec4 vs_positionCameraSpace; +in float vs_screenSpaceDepth; +in mat3 TBN; + +uniform float ambientIntensity = 0.2; +uniform float diffuseIntensity = 1.0; +uniform float specularIntensity = 1.0; + +uniform bool performShading = true; +uniform bool use_forced_color = false; +uniform bool has_texture_diffuse; +uniform bool has_texture_normal; +uniform bool has_texture_specular; +uniform bool has_color_specular; + +uniform bool opacityBlending = false; + +uniform sampler2D texture_diffuse; +uniform sampler2D texture_normal; +uniform sampler2D texture_specular; + +uniform vec3 color_diffuse; +uniform vec3 color_specular; + +uniform int nLightSources; +uniform vec3 lightDirectionsViewSpace[8]; +uniform float lightIntensities[8]; + +uniform float opacity = 1.0; + +Fragment getFragment() { + Fragment frag; + + if (has_texture_normal) { + vec3 normalAlbedo = texture(texture_normal, vs_st).rgb; + normalAlbedo = normalize(normalAlbedo * 2.0 - 1.0); + frag.color.rgb = normalize(TBN * normalAlbedo); + } + else { + frag.color.rgb = normalize(vs_normalViewSpace); + } + frag.color.a = 1.0; + frag.gPosition = vs_positionCameraSpace; + frag.gNormal = vec4(vs_normalViewSpace, 0.0); + frag.disableLDR2HDR = true; + return frag; +} diff --git a/data/assets/examples/modelshader/model_vs.glsl b/data/assets/examples/modelshader/model_vs.glsl new file mode 100644 index 0000000000..4ea52f749b --- /dev/null +++ b/data/assets/examples/modelshader/model_vs.glsl @@ -0,0 +1,68 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * 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. * + ****************************************************************************************/ + +#version __CONTEXT__ + +#include "PowerScaling/powerScaling_vs.hglsl" + +layout(location = 0) in vec4 in_position; +layout(location = 1) in vec2 in_st; +layout(location = 2) in vec3 in_normal; +layout(location = 3) in vec3 in_tangent; + +out vec2 vs_st; +out vec3 vs_normalViewSpace; +out float vs_screenSpaceDepth; +out vec4 vs_positionCameraSpace; +out mat3 TBN; + +uniform mat4 modelViewTransform; +uniform mat4 projectionTransform; +uniform mat4 normalTransform; +uniform mat4 meshTransform; +uniform mat4 meshNormalTransform; + +void main() { + vs_positionCameraSpace = modelViewTransform * (meshTransform * in_position); + vec4 positionClipSpace = projectionTransform * vs_positionCameraSpace; + vec4 positionScreenSpace = z_normalization(positionClipSpace); + + gl_Position = positionScreenSpace; + vs_st = in_st; + vs_screenSpaceDepth = positionScreenSpace.w; + + vs_normalViewSpace = normalize(mat3(normalTransform) * (mat3(meshNormalTransform) * in_normal)); + + // TBN matrix for normal mapping + vec3 T = normalize(mat3(normalTransform) * (mat3(meshNormalTransform) * in_tangent)); + vec3 N = normalize(mat3(normalTransform) * (mat3(meshNormalTransform) * in_normal)); + + // Re-orthogonalize T with respect to N + T = normalize(T - dot(T, N) * N); + + // Retrieve perpendicular vector B with cross product of T and N + vec3 B = normalize(cross(N, T)); + + TBN = mat3(T, B, N); +} diff --git a/data/assets/examples/modelshader/modelshader.asset b/data/assets/examples/modelshader/modelshader.asset new file mode 100644 index 0000000000..3fafbb7184 --- /dev/null +++ b/data/assets/examples/modelshader/modelshader.asset @@ -0,0 +1,45 @@ +local assetHelper = asset.require('util/asset_helper') +local sunTransforms = asset.require('scene/solarsystem/sun/transforms') +local transforms = asset.require('scene/solarsystem/planets/earth/transforms') + +local model = asset.syncedResource({ + Name = "Animated Box", + Type = "HttpSynchronization", + Identifier = "animated_box", + Version = 1 +}) + +local model = { + Identifier = "modelshader", + Parent = transforms.EarthCenter.Identifier, + Transform = { + Translation = { + Type = "StaticTranslation", + Position = { 11E7, 0.0, 0.0 } + } + }, + Renderable = { + Type = "RenderableModel", + GeometryFile = model .. "/BoxAnimated.glb", + ModelScale = 3E7, + LightSources = { + { + Type = "SceneGraphLightSource", + Identifier = "Sun", + Node = sunTransforms.SolarSystemBarycenter.Identifier, + Intensity = 1.0 + } + }, + PerformShading = true, + DisableFaceCulling = true, + VertexShader = asset.localResource("model_vs.glsl"), + FragmentShader = asset.localResource("model_fs.glsl"), + }, + GUI = { + Name = "Model Shader", + Path = "/Example", + Description = "Simple box model with a custom shader", + } +} + +assetHelper.registerSceneGraphNodesAndExport(asset, { model }) diff --git a/modules/base/rendering/renderablemodel.cpp b/modules/base/rendering/renderablemodel.cpp index 0668183742..cdec42d396 100644 --- a/modules/base/rendering/renderablemodel.cpp +++ b/modules/base/rendering/renderablemodel.cpp @@ -249,6 +249,14 @@ namespace { // [[codegen::verbatim(EnableOpacityBlendingInfo.description)]] std::optional enableOpacityBlending; + + // The path to the vertex shader program that is used instead of the default + // shader. + std::optional vertexShader; + + // The path to the fragment shader program that is used instead of the default + // shader. + std::optional fragmentShader; }; #include "renderablemodel_codegen.cpp" } // namespace @@ -472,6 +480,13 @@ RenderableModel::RenderableModel(const ghoul::Dictionary& dictionary) _disableDepthTest = p.disableDepthTest.value_or(_disableDepthTest); _disableFaceCulling = p.disableFaceCulling.value_or(_disableFaceCulling); + if (p.vertexShader.has_value()) { + _vertexShaderPath = p.vertexShader->string(); + } + if (p.fragmentShader.has_value()) { + _fragmentShaderPath = p.fragmentShader->string(); + } + if (p.lightSources.has_value()) { std::vector lightsources = *p.lightSources; @@ -560,16 +575,33 @@ void RenderableModel::initialize() { void RenderableModel::initializeGL() { ZoneScoped + std::string program = ProgramName; + if (!_vertexShaderPath.empty()) { + program += "|vs=" + _vertexShaderPath; + } + if (!_fragmentShaderPath.empty()) { + program += "|fs=" + _fragmentShaderPath; + } _program = BaseModule::ProgramObjectManager.request( - ProgramName, - []() -> std::unique_ptr { - return global::renderEngine->buildRenderProgram( - ProgramName, - absPath("${MODULE_BASE}/shaders/model_vs.glsl"), - absPath("${MODULE_BASE}/shaders/model_fs.glsl") - ); + program, + [&]() -> std::unique_ptr { + std::filesystem::path vs = + _vertexShaderPath.empty() ? + absPath("${MODULE_BASE}/shaders/model_vs.glsl") : + _vertexShaderPath; + std::filesystem::path fs = + _fragmentShaderPath.empty() ? + absPath("${MODULE_BASE}/shaders/model_fs.glsl") : + _fragmentShaderPath; + + return global::renderEngine->buildRenderProgram(ProgramName, vs, fs); } ); + // We don't really know what kind of shader the user provides us with, so we can't + // make the assumption that we are going to use all uniforms + _program->setIgnoreUniformLocationError( + ghoul::opengl::ProgramObject::IgnoreError::Yes + ); ghoul::opengl::updateUniformLocations(*_program, _uniformCache, UniformNames); @@ -581,8 +613,15 @@ void RenderableModel::deinitializeGL() { _geometry->deinitialize(); _geometry.reset(); + std::string program = ProgramName; + if (!_vertexShaderPath.empty()) { + program += "|vs=" + _vertexShaderPath; + } + if (!_fragmentShaderPath.empty()) { + program += "|fs=" + _fragmentShaderPath; + } BaseModule::ProgramObjectManager.release( - ProgramName, + program, [](ghoul::opengl::ProgramObject* p) { global::renderEngine->removeRenderProgram(p); } diff --git a/modules/base/rendering/renderablemodel.h b/modules/base/rendering/renderablemodel.h index 1de33afe5b..5e9f577ed2 100644 --- a/modules/base/rendering/renderablemodel.h +++ b/modules/base/rendering/renderablemodel.h @@ -101,6 +101,8 @@ private: properties::BoolProperty _enableOpacityBlending; properties::OptionProperty _blendingFuncOption; + std::string _vertexShaderPath; + std::string _fragmentShaderPath; ghoul::opengl::ProgramObject* _program = nullptr; UniformCache(opacity, nLightSources, lightDirectionsViewSpace, lightIntensities, modelViewTransform, normalTransform, projectionTransform, diff --git a/modules/base/shaders/model_vs.glsl b/modules/base/shaders/model_vs.glsl index 1a0e9cac14..4ea52f749b 100644 --- a/modules/base/shaders/model_vs.glsl +++ b/modules/base/shaders/model_vs.glsl @@ -44,15 +44,15 @@ uniform mat4 meshTransform; uniform mat4 meshNormalTransform; void main() { - vs_positionCameraSpace = modelViewTransform * (meshTransform * in_position); - vec4 positionClipSpace = projectionTransform * vs_positionCameraSpace; - vec4 positionScreenSpace = z_normalization(positionClipSpace); + vs_positionCameraSpace = modelViewTransform * (meshTransform * in_position); + vec4 positionClipSpace = projectionTransform * vs_positionCameraSpace; + vec4 positionScreenSpace = z_normalization(positionClipSpace); - gl_Position = positionScreenSpace; - vs_st = in_st; - vs_screenSpaceDepth = positionScreenSpace.w; + gl_Position = positionScreenSpace; + vs_st = in_st; + vs_screenSpaceDepth = positionScreenSpace.w; - vs_normalViewSpace = normalize(mat3(normalTransform) * (mat3(meshNormalTransform) * in_normal)); + vs_normalViewSpace = normalize(mat3(normalTransform) * (mat3(meshNormalTransform) * in_normal)); // TBN matrix for normal mapping vec3 T = normalize(mat3(normalTransform) * (mat3(meshNormalTransform) * in_tangent)); From bfd220374d5067d2387b9347229d418f47a83035 Mon Sep 17 00:00:00 2001 From: BlueVista Date: Tue, 24 Aug 2021 03:45:44 -0500 Subject: [PATCH 13/23] Feature/fontcolor (#1726) * Added two properties to control the font color of the Rotation, Zoom, and Roll toggles. --- include/openspace/rendering/renderengine.h | 4 ++++ src/rendering/renderengine.cpp | 24 ++++++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/include/openspace/rendering/renderengine.h b/include/openspace/rendering/renderengine.h index 388e0c8044..6da4d21c0d 100644 --- a/include/openspace/rendering/renderengine.h +++ b/include/openspace/rendering/renderengine.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -219,6 +220,9 @@ private: } _cameraButtonLocations; std::string _versionString; + + properties::Vec4Property _enabledFontColor; + properties::Vec4Property _disabledFontColor; }; } // namespace openspace diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index ebc26b6cde..d7c68c6e1b 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -252,6 +252,18 @@ namespace { "Enable FXAA", "Enable FXAA" }; + + constexpr openspace::properties::Property::PropertyInfo EnabledFontColorInfo = { + "EnabledFontColor", + "Enabled Font Color", + "The font color used for enabled options." + }; + + constexpr openspace::properties::Property::PropertyInfo DisabledFontColorInfo = { + "DisabledFontColor", + "Disabled Font Color", + "The font color used for disabled options." + }; } // namespace namespace openspace { @@ -295,6 +307,8 @@ RenderEngine::RenderEngine() glm::vec3(-glm::pi()), glm::vec3(glm::pi()) ) + , _enabledFontColor(EnabledFontColorInfo, glm::vec4(0.2f, 0.75f, 0.2f, 1.f)) + , _disabledFontColor(DisabledFontColorInfo, glm::vec4(0.55f, 0.2f, 0.2f, 1.f)) { addProperty(_showOverlayOnSlaves); addProperty(_showLog); @@ -380,6 +394,12 @@ RenderEngine::RenderEngine() addProperty(_screenSpaceRotation); addProperty(_masterRotation); addProperty(_disableMasterRendering); + + _enabledFontColor.setViewOption(openspace::properties::Property::ViewOptions::Color); + addProperty(_enabledFontColor); + + _disabledFontColor.setViewOption(openspace::properties::Property::ViewOptions::Color); + addProperty(_disabledFontColor); } RenderEngine::~RenderEngine() {} // NOLINT @@ -1148,8 +1168,8 @@ void RenderEngine::renderCameraInformation() { return; } - const glm::vec4 EnabledColor = glm::vec4(0.2f, 0.75f, 0.2f, 1.f); - const glm::vec4 DisabledColor = glm::vec4(0.55f, 0.2f, 0.2f, 1.f); + const glm::vec4 EnabledColor = _enabledFontColor.value(); + const glm::vec4 DisabledColor = _disabledFontColor.value(); const glm::vec2 rotationBox = _fontCameraInfo->boundingBox("Rotation"); From 4fb88eb7af20736354014a4d286da0eec83789e9 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Tue, 24 Aug 2021 16:26:49 +0200 Subject: [PATCH 14/23] Fix some more functions that broke after Lua function cleanup And simplify debugging axes usage --- modules/debugging/debuggingmodule.cpp | 7 +-- modules/debugging/debuggingmodule_lua.inl | 74 +++++++++-------------- 2 files changed, 33 insertions(+), 48 deletions(-) diff --git a/modules/debugging/debuggingmodule.cpp b/modules/debugging/debuggingmodule.cpp index 4c344f2d3a..7e7e2eac9c 100644 --- a/modules/debugging/debuggingmodule.cpp +++ b/modules/debugging/debuggingmodule.cpp @@ -94,11 +94,10 @@ scripting::LuaLibrary DebuggingModule::luaLibrary() const { "addCartesianAxes", &luascriptfunctions::addCartesianAxes, {}, - "string, string [,number]", + "string, [number]", "Adds a set of Cartesian axes to the scene graph node identified by the " - "first string, to illustrate its local coordinate system. The second string " - "will be used to set the identifier of the axes. The third (optional) " - "argument is a scale value, in meters." + "first string, to illustrate its local coordinate system. The second " + "(optional) argument is a scale value, in meters." } }; diff --git a/modules/debugging/debuggingmodule_lua.inl b/modules/debugging/debuggingmodule_lua.inl index 0d00abd3b2..2f90b92376 100644 --- a/modules/debugging/debuggingmodule_lua.inl +++ b/modules/debugging/debuggingmodule_lua.inl @@ -61,11 +61,7 @@ namespace openspace::luascriptfunctions { * Renders the current camera path */ int renderCameraPath(lua_State* L) { - int nArguments = ghoul::lua::checkArgumentsAndThrow( - L, - { 0, 3 }, - "lua::renderCameraPath" - ); + ghoul::lua::checkArgumentsAndThrow(L, { 0, 3 }, "lua::renderCameraPath"); if (!global::navigationHandler->pathNavigator().hasCurrentPath()) { LWARNINGC("Debugging: PathNavigation", "There is no current path to render"); @@ -74,12 +70,13 @@ int renderCameraPath(lua_State* L) { const interaction::Path* currentPath = global::navigationHandler->pathNavigator().currentPath(); - const int nSteps = (nArguments > 0) ? ghoul::lua::value(L, 1) : 100; - bool renderDirections = (nArguments > 1) ? ghoul::lua::value(L, 2) : false; + auto [nSteps, renderDirections, directionLineLength] = ghoul::lua::values< + std::optional, std::optional, std::optional + >(L); - constexpr const double defaultLineLength = 6e7; - const double directionLineLength = - (nArguments > 2) ? ghoul::lua::value(L, 3) : defaultLineLength; + nSteps = nSteps.value_or(100); + renderDirections = renderDirections.value_or(false); + directionLineLength = directionLineLength.value_or(6e7); // Parent node. Note that we only render one path at a time, so remove the previously // rendered one, if any @@ -98,7 +95,7 @@ int renderCameraPath(lua_State* L) { // Get the poses along the path std::vector poses; - const double du = 1.0 / nSteps; + const double du = 1.0 / (*nSteps); const double length = currentPath->pathLength(); for (double u = 0.0; u < 1.0; u += du) { const CameraPose p = currentPath->interpolatedPose(u * length); @@ -153,11 +150,12 @@ int renderCameraPath(lua_State* L) { ); }; - auto addDirectionLine = [addPoint, addLineBetweenPoints, directionLineLength] - (const std::string& pointId, const CameraPose& p) + auto addDirectionLine = [addPoint, addLineBetweenPoints] + (const std::string& pointId, const CameraPose& p, + double lineLength) { const glm::dvec3 dir = glm::normalize(p.rotation * glm::dvec3(0.0, 0.0, -1.0)); - const glm::dvec3 pointPosition = p.position + directionLineLength * dir; + const glm::dvec3 pointPosition = p.position + lineLength * dir; const std::string id = fmt::format("{}_orientation", pointId); addPoint(id, pointPosition); @@ -166,20 +164,19 @@ int renderCameraPath(lua_State* L) { // Add first point separately so that we can create first line in for loop addPoint(pointIdentifier(0), poses.front().position); - if (renderDirections) { - addDirectionLine(pointIdentifier(0), poses.front()); + if (*renderDirections) { + addDirectionLine(pointIdentifier(0), poses.front(), *directionLineLength); } for (int i = 1; i < static_cast(poses.size()); i++) { addPoint(pointIdentifier(i), poses[i].position); addLineBetweenPoints(pointIdentifier(i), pointIdentifier(i - 1), PathColor, 4.f); - if (renderDirections) { - addDirectionLine(pointIdentifier(i), poses[i]); + if (*renderDirections) { + addDirectionLine(pointIdentifier(i), poses[i], *directionLineLength); } } - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } @@ -195,7 +192,6 @@ int removeRenderedCameraPath(lua_State* L) { scripting::ScriptEngine::RemoteScripting::Yes ); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } @@ -204,11 +200,7 @@ int removeRenderedCameraPath(lua_State* L) { * Renders the control points of the current camera path */ int renderPathControlPoints(lua_State* L) { - int nArguments = ghoul::lua::checkArgumentsAndThrow( - L, - { 0, 1 }, - "lua::renderPathControlPoints" - ); + ghoul::lua::checkArgumentsAndThrow(L, { 0, 1 }, "lua::renderPathControlPoints"); if (!global::navigationHandler->pathNavigator().hasCurrentPath()) { LWARNINGC( @@ -219,7 +211,8 @@ int renderPathControlPoints(lua_State* L) { const interaction::Path* currentPath = global::navigationHandler->pathNavigator().currentPath(); - const double radius = (nArguments > 0) ? ghoul::lua::value(L, 1) : 2000000; + auto [radius] = ghoul::lua::values>(L); + radius = radius.value_or(2000000.0); // Parent node. Note that we only render one set of points at a time, // so remove any previously rendered ones @@ -259,7 +252,7 @@ int renderPathControlPoints(lua_State* L) { "Type = 'RenderableSphere'," "Enabled = true," "Segments = 30," - "Size = " + std::to_string(radius) + "," + "Size = " + std::to_string(*radius) + "," "Texture = " + colorTexturePath + "" "}," "GUI = {" @@ -274,7 +267,6 @@ int renderPathControlPoints(lua_State* L) { ); } - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } @@ -290,7 +282,6 @@ int removePathControlPoints(lua_State* L) { scripting::ScriptEngine::RemoteScripting::Yes ); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } @@ -298,37 +289,33 @@ int removePathControlPoints(lua_State* L) { * Add a set of cartesian axes to the specified scene graph node */ int addCartesianAxes(lua_State* L) { - int nArgs = ghoul::lua::checkArgumentsAndThrow(L, { 2, 3 }, "lua::addCartesianAxes"); + ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::addCartesianAxes"); - const std::string& nodeName = ghoul::lua::value(L, 1); - const std::string& axesIdentifier = ghoul::lua::value(L, 2); + auto [nodeIdentifier, scale] = + ghoul::lua::values>(L); - SceneGraphNode* n = global::renderEngine->scene()->sceneGraphNode(nodeName); + SceneGraphNode* n = global::renderEngine->scene()->sceneGraphNode(nodeIdentifier); if (!n) { - return ghoul::lua::luaError(L, "Unknown scene graph node: " + nodeName); + return ghoul::lua::luaError(L, "Unknown scene graph node: " + nodeIdentifier); } - double scale; - if (nArgs > 2) { - scale = ghoul::lua::value(L, 3); - } - else { + if (!scale.has_value()) { scale = 2.0 * n->boundingSphere(); if (n->boundingSphere() < 1E-3) { LWARNING("Using zero bounding sphere for scale of created axes. You might " "have to set the scale manually for them to be visible"); - scale += 1.0; + scale = 1.0; } } - const std::string identifier = makeIdentifier(axesIdentifier); + const std::string identifier = makeIdentifier(nodeIdentifier + "_AxesXYZ"); const std::string& axes = "{" "Identifier = '" + identifier + "'," - "Parent = '" + nodeName + "'," + "Parent = '" + nodeIdentifier + "'," "Transform = { " "Scale = {" "Type = 'StaticScale'," - "Scale = " + std::to_string(scale) + "" + "Scale = " + std::to_string(*scale) + "" "}" "}," "Renderable = {" @@ -349,7 +336,6 @@ int addCartesianAxes(lua_State* L) { scripting::ScriptEngine::RemoteScripting::Yes ); - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); return 0; } From 1516c066c9b7146ece04df3e1883971873bc2a3b Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Wed, 25 Aug 2021 15:58:28 +0200 Subject: [PATCH 15/23] Don't scale camera path speed if no duration was given Just using the current distance for camera speed works better than setting a default duration based on the path length --- include/openspace/navigation/path.h | 7 ------- src/navigation/path.cpp | 22 ++++++++++------------ 2 files changed, 10 insertions(+), 19 deletions(-) diff --git a/include/openspace/navigation/path.h b/include/openspace/navigation/path.h index 23dfff926a..7a1a33bc3e 100644 --- a/include/openspace/navigation/path.h +++ b/include/openspace/navigation/path.h @@ -57,12 +57,6 @@ public: Waypoint startPoint() const; Waypoint endPoint() const; - /** - * Return the specified duration for the path, in seconds. Note that the time it - * takes to actually traverse the path will not exactly match the provided duration - */ - double duration() const; - /** * Return the total length of the the curve for the path, in meters */ @@ -128,7 +122,6 @@ private: Waypoint _start; Waypoint _end; - double _duration; // seconds Type _type; std::unique_ptr _curve; diff --git a/src/navigation/path.cpp b/src/navigation/path.cpp index c15a964b58..6d78495fb8 100644 --- a/src/navigation/path.cpp +++ b/src/navigation/path.cpp @@ -107,19 +107,19 @@ Path::Path(Waypoint start, Waypoint end, Type type, throw ghoul::MissingCaseException(); } - _duration = duration.value_or(std::log(pathLength())); + // Compute speed factor to match any given duration, by traversing the path and + // computing how much faster/slower it should be + _speedFactorFromDuration = 1.0; + if (duration.has_value()) { + constexpr const double dt = 0.05; // 20 fps + while (!hasReachedEnd()) { + traversePath(dt); + } - // Compute speed factor to match the generated path length and duration, by - // traversing the path and computing how much faster/slower it should be - const int nSteps = 500; - const double dt = (_duration / nSteps) > 0.01 ? (_duration / nSteps) : 0.01; - - while (!hasReachedEnd()) { - traversePath(dt); + // We now know how long it took to traverse the path. Use that + _speedFactorFromDuration = _progressedTime / *duration; } - _speedFactorFromDuration = _progressedTime / _duration; - // Reset playback variables _traveledDistance = 0.0; _progressedTime = 0.0; @@ -129,8 +129,6 @@ Waypoint Path::startPoint() const { return _start; } Waypoint Path::endPoint() const { return _end; } -double Path::duration() const { return _duration; } - double Path::pathLength() const { return _curve->length(); } std::vector Path::controlPoints() const { From faf7a3d315a1332dba6951f54ced938cbf6aa2ed Mon Sep 17 00:00:00 2001 From: Micah Date: Fri, 27 Aug 2021 13:17:52 -0400 Subject: [PATCH 16/23] update guihash for tutorial link --- data/assets/util/webgui.asset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index e03c216905..aea760c206 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -3,7 +3,7 @@ asset.require('./static_server') local guiCustomization = asset.require('customization/gui') -- Select which commit hashes to use for the frontend and backend -local frontendHash = "829260614bb95e236d23cb500f6ec0fb2e3bdf51" +local frontendHash = "224ef14e76ab76f5f91df2f0e35d6b9f6805aaf4" local dataProvider = "data.openspaceproject.com/files/webgui" local frontend = asset.syncedResource({ From 671894bd0b5b1afd318322cbfbbe3ca734e306d0 Mon Sep 17 00:00:00 2001 From: Micah Date: Thu, 2 Sep 2021 14:56:25 -0400 Subject: [PATCH 17/23] changes for action panel --- data/assets/util/webgui.asset | 2 +- modules/server/src/topics/shortcuttopic.cpp | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index aea760c206..d405b8140e 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -3,7 +3,7 @@ asset.require('./static_server') local guiCustomization = asset.require('customization/gui') -- Select which commit hashes to use for the frontend and backend -local frontendHash = "224ef14e76ab76f5f91df2f0e35d6b9f6805aaf4" +local frontendHash = "f3e5a4021304c15bfdfb11835a6d19eeb332d1b8" local dataProvider = "data.openspaceproject.com/files/webgui" local frontend = asset.syncedResource({ diff --git a/modules/server/src/topics/shortcuttopic.cpp b/modules/server/src/topics/shortcuttopic.cpp index cd8fce7995..c40ed6ec25 100644 --- a/modules/server/src/topics/shortcuttopic.cpp +++ b/modules/server/src/topics/shortcuttopic.cpp @@ -47,6 +47,7 @@ std::vector ShortcutTopic::shortcutsJson() const { std::vector json; for (const interaction::Action& action : global::actionManager->actions()) { nlohmann::json shortcutJson = { + { "identifier", action.identifier }, { "name", action.name }, { "script", action.command }, { "synchronization", static_cast(action.synchronization) }, @@ -77,11 +78,7 @@ std::vector ShortcutTopic::shortcutsJson() const { { "super" , hasKeyModifier(k.modifier, KeyModifier::Super) } } }, - { "name", action.name }, - { "script", action.command }, - { "synchronization", static_cast(action.synchronization) }, - { "documentation", action.documentation }, - { "guiPath", action.guiPath }, + { "action", action.name }, }; json.push_back(shortcutJson); } From 19ab24374fc148faa1c7a75604b504853d98c363 Mon Sep 17 00:00:00 2001 From: Micah Date: Thu, 2 Sep 2021 16:42:04 -0400 Subject: [PATCH 18/23] update guihash for action cleanup and route --- data/assets/util/webgui.asset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index d405b8140e..b9f1d9be9a 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -3,7 +3,7 @@ asset.require('./static_server') local guiCustomization = asset.require('customization/gui') -- Select which commit hashes to use for the frontend and backend -local frontendHash = "f3e5a4021304c15bfdfb11835a6d19eeb332d1b8" +local frontendHash = "b777c48280801e3b54cf77c1231f949fe6e69ace" local dataProvider = "data.openspaceproject.com/files/webgui" local frontend = asset.syncedResource({ From 82ecf60ea2ca268fdca96f258b880f6a476db224 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Mon, 6 Sep 2021 09:28:12 +0200 Subject: [PATCH 19/23] Issue/1527 - GlobeRotation (#1737) * Add GlobeRotation and example * Put latitude before longitude in GlobeTranslation files --- data/assets/examples/globerotation.asset | 47 ++++ data/assets/examples/globetranslation.asset | 4 +- modules/globebrowsing/CMakeLists.txt | 2 + modules/globebrowsing/globebrowsingmodule.cpp | 5 + modules/globebrowsing/src/basictypes.h | 4 +- modules/globebrowsing/src/globerotation.cpp | 233 ++++++++++++++++++ modules/globebrowsing/src/globerotation.h | 64 +++++ .../globebrowsing/src/globetranslation.cpp | 44 ++-- modules/globebrowsing/src/globetranslation.h | 2 +- 9 files changed, 376 insertions(+), 29 deletions(-) create mode 100644 data/assets/examples/globerotation.asset create mode 100644 modules/globebrowsing/src/globerotation.cpp create mode 100644 modules/globebrowsing/src/globerotation.h diff --git a/data/assets/examples/globerotation.asset b/data/assets/examples/globerotation.asset new file mode 100644 index 0000000000..f685b0ae5e --- /dev/null +++ b/data/assets/examples/globerotation.asset @@ -0,0 +1,47 @@ +local assetHelper = asset.require('util/asset_helper') +local earth = asset.require('scene/solarsystem/planets/earth/earth') +local sunTransforms = asset.require('scene/solarsystem/sun/transforms') + +local models = asset.syncedResource({ + Name = "New Horizons Model", + Type = "HttpSynchronization", + Identifier = "newhorizons_model", + Version = 2 +}) + +local lat = 40.7306 +local long = -73.9352 + +local Example_GlobeRotation = { + Identifier = "Example_GlobeRotation", + Parent = earth.Earth.Identifier, + Transform = { + Translation = { + Type = "GlobeTranslation", + Globe = earth.Earth.Identifier, + Latitude = lat, + Longitude = long, + Altitude = 6, + UseHeightmap = true + }, + Rotation = { + Type = "GlobeRotation", + Globe = earth.Earth.Identifier, + Latitude = lat, + Longitude = long + -- Can be used to to put flat on leaning surfaces, but also leads to updating + -- the rotation every frame + --UseHeightmap = true + } + }, + Renderable = { + Type = "RenderableModel", + Body = "NEW HORIZONS", + GeometryFile = models .. "/NewHorizonsCleanModel.obj" + }, + GUI = { + Path = "/Example" + } +} + +assetHelper.registerSceneGraphNodesAndExport(asset, { Example_GlobeRotation }) diff --git a/data/assets/examples/globetranslation.asset b/data/assets/examples/globetranslation.asset index 1bf8d0089a..a61de7e465 100644 --- a/data/assets/examples/globetranslation.asset +++ b/data/assets/examples/globetranslation.asset @@ -16,8 +16,8 @@ local Example_Fixed_Height = { Translation = { Type = "GlobeTranslation", Globe = earth.Earth.Identifier, - Longitude = -74.006, Latitude = 40.7128, + Longitude = -74.006, Altitude = 100000.0 } }, @@ -38,8 +38,8 @@ local Example_Adaptive_Height = { Translation = { Type = "GlobeTranslation", Globe = earth.Earth.Identifier, - Longitude = -74.006, Latitude = 40.7128, + Longitude = -74.006, UseHeightmap = true } }, diff --git a/modules/globebrowsing/CMakeLists.txt b/modules/globebrowsing/CMakeLists.txt index 2b0496967b..127b9e53be 100644 --- a/modules/globebrowsing/CMakeLists.txt +++ b/modules/globebrowsing/CMakeLists.txt @@ -34,6 +34,7 @@ set(HEADER_FILES src/geodeticpatch.h src/globelabelscomponent.h src/globetranslation.h + src/globerotation.h src/gpulayergroup.h src/layer.h src/layeradjustment.h @@ -71,6 +72,7 @@ set(SOURCE_FILES src/geodeticpatch.cpp src/globelabelscomponent.cpp src/globetranslation.cpp + src/globerotation.cpp src/gpulayergroup.cpp src/layer.cpp src/layeradjustment.cpp diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index 4cc3049d29..f2d103a4b6 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -274,6 +275,10 @@ void GlobeBrowsingModule::internalInitialize(const ghoul::Dictionary& dict) { ghoul_assert(fTranslation, "Translation factory was not created"); fTranslation->registerClass("GlobeTranslation"); + auto fRotation = FactoryManager::ref().factory(); + ghoul_assert(fRotation, "Rotation factory was not created"); + fRotation->registerClass("GlobeRotation"); + auto fTileProvider = std::make_unique>(); ghoul_assert(fTileProvider, "TileProvider factory was not created"); diff --git a/modules/globebrowsing/src/basictypes.h b/modules/globebrowsing/src/basictypes.h index b509837fc2..646ca070f0 100644 --- a/modules/globebrowsing/src/basictypes.h +++ b/modules/globebrowsing/src/basictypes.h @@ -43,8 +43,8 @@ struct AABB3 { struct Geodetic2 { - double lat = 0.0; - double lon = 0.0; + double lat = 0.0; // in radians + double lon = 0.0; // in radians }; diff --git a/modules/globebrowsing/src/globerotation.cpp b/modules/globebrowsing/src/globerotation.cpp new file mode 100644 index 0000000000..e210ad5f6c --- /dev/null +++ b/modules/globebrowsing/src/globerotation.cpp @@ -0,0 +1,233 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * 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 +#include +#include +#include +#include +#include + +namespace { + constexpr openspace::properties::Property::PropertyInfo GlobeInfo = { + "Globe", + "Attached Globe", + "The globe on which the longitude/latitude is specified" + }; + + constexpr openspace::properties::Property::PropertyInfo LatitudeInfo = { + "Latitude", + "Latitude", + "The latitude of the location on the globe's surface. The value can range from " + "-90 to 90, with negative values representing the southern hemisphere of the " + "globe. The default value is 0.0." + }; + + constexpr openspace::properties::Property::PropertyInfo LongitudeInfo = { + "Longitude", + "Longitude", + "The longitude of the location on the globe's surface. The value can range from " + "-180 to 180, with negative values representing the western hemisphere of the " + "globe. The default value is 0.0." + }; + + constexpr openspace::properties::Property::PropertyInfo AngleInfo = { + "Angle", + "Angle", + "A rotation angle that can be used to rotate the object around its own y-axis, " + "which will be pointing out of the globe's surface." + }; + + constexpr openspace::properties::Property::PropertyInfo UseHeightmapInfo = { + "UseHeightmap", + "Use Heightmap", + "If set to true, the heightmap will be used when computing the surface normal. " + "This means that the object will be rotated to lay flat on the surface at the " + "given coordinate and follow the shape of the landscape." + }; + + struct [[codegen::Dictionary(GlobeRotation)]] Parameters { + // [[codegen::verbatim(GlobeInfo.description)]] + std::string globe + [[codegen::annotation("A valid scene graph node with a RenderableGlobe")]]; + + // [[codegen::verbatim(LatitudeInfo.description)]] + std::optional latitude; + + // [[codegen::verbatim(LongitudeInfo.description)]] + std::optional longitude; + + // [[codegen::verbatim(AngleInfo.description)]] + std::optional angle; + + // [[codegen::verbatim(UseHeightmapInfo.description)]] + std::optional useHeightmap; + }; +#include "globerotation_codegen.cpp" +} // namespace + +namespace openspace::globebrowsing { + +documentation::Documentation GlobeRotation::Documentation() { + return codegen::doc("globebrowsing_rotation_globerotation"); +} + +GlobeRotation::GlobeRotation(const ghoul::Dictionary& dictionary) + : _globe(GlobeInfo) + , _latitude(LatitudeInfo, 0.0, -90.0, 90.0) + , _longitude(LongitudeInfo, 0.0, -180.0, 180.0) + , _angle(AngleInfo, 0.0, 0.0, 360.0) + , _useHeightmap(UseHeightmapInfo, false) +{ + const Parameters p = codegen::bake(dictionary); + + _globe = p.globe; + + _latitude = p.latitude.value_or(_latitude); + _latitude.onChange([this]() { _matrixIsDirty = true; }); + addProperty(_latitude); + + _longitude = p.longitude.value_or(_longitude); + _longitude.onChange([this]() { _matrixIsDirty = true; }); + addProperty(_longitude); + + _useHeightmap = p.useHeightmap.value_or(_useHeightmap); + _useHeightmap.onChange([this]() { _matrixIsDirty = true; }); + addProperty(_useHeightmap); + + _angle = p.angle.value_or(_angle); + _angle.onChange([this]() { _matrixIsDirty = true; }); + addProperty(_angle); +} + +void GlobeRotation::findGlobe() { + SceneGraphNode* n = sceneGraphNode(_globe); + if (n->renderable() && dynamic_cast(n->renderable())) { + _globeNode = dynamic_cast(n->renderable()); + } + else { + LERRORC( + "GlobeRotation", + "Could not set attached node as it does not have a RenderableGlobe" + ); + if (_globeNode) { + // Reset the globe name to it's previous name + _globe = _globeNode->identifier(); + } + } +} + +glm::vec3 GlobeRotation::computeSurfacePosition(double latitude, double longitude) const +{ + ghoul_assert(_globeNode, "Globe cannot be nullptr"); + + GlobeBrowsingModule* mod = global::moduleEngine->module(); + glm::vec3 groundPos = mod->cartesianCoordinatesFromGeo( + *_globeNode, + latitude, + longitude, + 0.0 + ); + + SurfacePositionHandle h = + _globeNode->calculateSurfacePositionHandle(groundPos); + + // Compute position including heightmap + return mod->cartesianCoordinatesFromGeo( + *_globeNode, + latitude, + longitude, + h.heightToSurface + ); +} + +glm::dmat3 GlobeRotation::matrix(const UpdateData&) const { + if (!_globeNode) { + // @TODO(abock): The const cast should be removed on a redesign of the rotation + // to make the matrix function not constant. Const casting this + // away is fine as the factories that create the rotations don't + // create them as constant objects + const_cast(this)->findGlobe(); + _matrixIsDirty = true; + } + + if (_useHeightmap) { + // If we use the heightmap, we have to compute the height every frame + _matrixIsDirty = true; + } + + if (!_matrixIsDirty) { + return _matrix; + } + + // Compute vector that points out of globe surface + glm::dvec3 yAxis = glm::dvec3(0.0); + if (_useHeightmap) { + const double angleDiff = 0.00001; // corresponds to a meter-ish + const glm::vec3 posCenter = computeSurfacePosition(_latitude, _longitude); + const glm::vec3 pos1 = computeSurfacePosition(_latitude, _longitude + angleDiff); + const glm::vec3 pos2 = computeSurfacePosition(_latitude + angleDiff, _longitude); + + const glm::vec3 v1 = pos1 - posCenter; + const glm::vec3 v2 = pos2 - posCenter; + yAxis = glm::dvec3(glm::cross(v1, v2)); + } + else { + float latitudeRad = glm::radians(static_cast(_latitude)); + float longitudeRad = glm::radians(static_cast(_longitude)); + yAxis = _globeNode->ellipsoid().geodeticSurfaceNormal( + { latitudeRad, longitudeRad } + ); + } + yAxis = glm::normalize(yAxis); + + constexpr const glm::dvec3 n = glm::dvec3(0.0, 0.0, 1.0); + glm::dvec3 zAxis = glm::dvec3( + zAxis.x = yAxis.y * n.z - yAxis.z * n.y, + zAxis.y = yAxis.z * n.x - yAxis.x * n.z, + zAxis.z = yAxis.x * n.y - yAxis.y * n.x + ); + zAxis = glm::normalize(zAxis); + + const glm::dvec3 xAxis = glm::normalize(glm::cross(yAxis, zAxis)); + const glm::dmat3 mat = { + xAxis.x, xAxis.y, xAxis.z, + yAxis.x, yAxis.y, yAxis.z, + zAxis.x, zAxis.y, zAxis.z + }; + + const glm::dquat q = glm::angleAxis(glm::radians(_angle.value()), yAxis); + _matrix = glm::toMat3(q) * mat; + _matrixIsDirty = false; + return _matrix; +} + +} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/src/globerotation.h b/modules/globebrowsing/src/globerotation.h new file mode 100644 index 0000000000..4f46cf9447 --- /dev/null +++ b/modules/globebrowsing/src/globerotation.h @@ -0,0 +1,64 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * 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_MODULE_GLOBEBROWSING___GLOBEROTATION___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___GLOBEROTATION___H__ + +#include + +#include +#include +#include + +namespace openspace::globebrowsing { + +class RenderableGlobe; + +class GlobeRotation : public Rotation { +public: + GlobeRotation(const ghoul::Dictionary& dictionary); + + glm::dmat3 matrix(const UpdateData& data) const override; + + static documentation::Documentation Documentation(); + +private: + void findGlobe(); + glm::vec3 computeSurfacePosition(double latitude, double longitude) const; + + properties::StringProperty _globe; + properties::DoubleProperty _latitude; + properties::DoubleProperty _longitude; + properties::DoubleProperty _angle; + properties::BoolProperty _useHeightmap; + + RenderableGlobe* _globeNode = nullptr; + + mutable bool _matrixIsDirty = true; + mutable glm::dmat3 _matrix = glm::dmat3(0.0); +}; + +} // namespace openspace::globebrowsing + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___GLOBEROTATION___H__ diff --git a/modules/globebrowsing/src/globetranslation.cpp b/modules/globebrowsing/src/globetranslation.cpp index ff902b8f67..57b9368eda 100644 --- a/modules/globebrowsing/src/globetranslation.cpp +++ b/modules/globebrowsing/src/globetranslation.cpp @@ -42,14 +42,6 @@ namespace { "The globe on which the longitude/latitude is specified" }; - constexpr openspace::properties::Property::PropertyInfo LongitudeInfo = { - "Longitude", - "Longitude", - "The longitude of the location on the globe's surface. The value can range from " - "-180 to 180, with negative values representing the western hemisphere of the " - "globe. The default value is 0.0" - }; - constexpr openspace::properties::Property::PropertyInfo LatitudeInfo = { "Latitude", "Latitude", @@ -58,6 +50,14 @@ namespace { "globe. The default value is 0.0" }; + constexpr openspace::properties::Property::PropertyInfo LongitudeInfo = { + "Longitude", + "Longitude", + "The longitude of the location on the globe's surface. The value can range from " + "-180 to 180, with negative values representing the western hemisphere of the " + "globe. The default value is 0.0" + }; + constexpr openspace::properties::Property::PropertyInfo AltitudeInfo = { "Altitude", "Altitude", @@ -80,12 +80,12 @@ namespace { std::string globe [[codegen::annotation("A valid scene graph node with a RenderableGlobe")]]; - // [[codegen::verbatim(LongitudeInfo.description)]] - std::optional longitude; - // [[codegen::verbatim(LatitudeInfo.description)]] std::optional latitude; + // [[codegen::verbatim(LongitudeInfo.description)]] + std::optional longitude; + // [[codegen::verbatim(AltitudeInfo.description)]] std::optional altitude; @@ -103,27 +103,23 @@ documentation::Documentation GlobeTranslation::Documentation() { GlobeTranslation::GlobeTranslation(const ghoul::Dictionary& dictionary) : _globe(GlobeInfo) - , _longitude(LongitudeInfo, 0.0, -180.0, 180.0) , _latitude(LatitudeInfo, 0.0, -90.0, 90.0) + , _longitude(LongitudeInfo, 0.0, -180.0, 180.0) , _altitude(AltitudeInfo, 0.0, 0.0, 1e12) , _useHeightmap(UseHeightmapInfo, false) { const Parameters p = codegen::bake(dictionary); _globe = p.globe; - _globe.onChange([this]() { - fillAttachedNode(); - _positionIsDirty = true; - }); - - _longitude = p.longitude.value_or(_longitude); - _longitude.onChange([this]() { _positionIsDirty = true; }); - addProperty(_longitude); _latitude = p.latitude.value_or(_latitude); _latitude.onChange([this]() { _positionIsDirty = true; }); addProperty(_latitude); + _longitude = p.longitude.value_or(_longitude); + _longitude.onChange([this]() { _positionIsDirty = true; }); + addProperty(_longitude); + _altitude = p.altitude.value_or(_altitude); _altitude.setExponent(8.f); _altitude.onChange([this]() { _positionIsDirty = true; }); @@ -170,10 +166,10 @@ glm::dvec3 GlobeTranslation::position(const UpdateData&) const { return _position; } - GlobeBrowsingModule& mod = *(global::moduleEngine->module()); + GlobeBrowsingModule* mod = global::moduleEngine->module(); if (_useHeightmap) { - glm::vec3 groundPos = mod.cartesianCoordinatesFromGeo( + glm::vec3 groundPos = mod->cartesianCoordinatesFromGeo( *_attachedNode, _latitude, _longitude, @@ -183,7 +179,7 @@ glm::dvec3 GlobeTranslation::position(const UpdateData&) const { SurfacePositionHandle h = _attachedNode->calculateSurfacePositionHandle(groundPos); - _position = mod.cartesianCoordinatesFromGeo( + _position = mod->cartesianCoordinatesFromGeo( *_attachedNode, _latitude, _longitude, @@ -192,7 +188,7 @@ glm::dvec3 GlobeTranslation::position(const UpdateData&) const { return _position; } else { - _position = mod.cartesianCoordinatesFromGeo( + _position = mod->cartesianCoordinatesFromGeo( *_attachedNode, _latitude, _longitude, diff --git a/modules/globebrowsing/src/globetranslation.h b/modules/globebrowsing/src/globetranslation.h index 8ad737c994..3385903f34 100644 --- a/modules/globebrowsing/src/globetranslation.h +++ b/modules/globebrowsing/src/globetranslation.h @@ -47,8 +47,8 @@ private: void fillAttachedNode(); properties::StringProperty _globe; - properties::DoubleProperty _longitude; properties::DoubleProperty _latitude; + properties::DoubleProperty _longitude; properties::DoubleProperty _altitude; properties::BoolProperty _useHeightmap; From 46cb439a3fcb05262291c31fab8e3af28335957e Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Mon, 6 Sep 2021 09:38:39 +0200 Subject: [PATCH 20/23] Tiny pathnavigation cleanup --- src/navigation/path.cpp | 8 +++-- src/navigation/pathnavigator_lua.inl | 47 ++-------------------------- 2 files changed, 7 insertions(+), 48 deletions(-) diff --git a/src/navigation/path.cpp b/src/navigation/path.cpp index 6d78495fb8..ecb776b0d4 100644 --- a/src/navigation/path.cpp +++ b/src/navigation/path.cpp @@ -217,11 +217,13 @@ glm::dquat Path::lookAtTargetsRotation(double t) const { } // Handle up vector separately + // @TODO (2021-09-06 emmbr) This actually does not interpolate the up vector of the + // camera, but just the "hint" up vector for the lookAt. This leads to fast rolling + // when the up vector gets close to the camera's forward vector. Should be improved + // so any rolling is spread out over the entire motion instead + double tUp = ghoul::sineEaseInOut(t); glm::dvec3 startUp = _start.rotation() * glm::dvec3(0.0, 1.0, 0.0); glm::dvec3 endUp = _end.rotation() * glm::dvec3(0.0, 1.0, 0.0); - - double tUp = helpers::shiftAndScale(t, t1, t2); - tUp = ghoul::sineEaseInOut(tUp); glm::dvec3 up = ghoul::interpolateLinear(tUp, startUp, endUp); return ghoul::lookAtQuaternion(_curve->positionAt(t), lookAtPos, up); diff --git a/src/navigation/pathnavigator_lua.inl b/src/navigation/pathnavigator_lua.inl index 4fc9978e03..2228feac23 100644 --- a/src/navigation/pathnavigator_lua.inl +++ b/src/navigation/pathnavigator_lua.inl @@ -67,51 +67,8 @@ int stopPath(lua_State* L) { return 0; } -int handleOptionalGoToParameters(lua_State* L, const int startLocation, - const int nArguments, - ghoul::Dictionary& resultInstruction) -{ - const bool firstIsNumber = (lua_isnumber(L, startLocation) != 0); - const bool firstIsBool = (lua_isboolean(L, startLocation) != 0); - - if (!(firstIsNumber || firstIsBool)) { - const char* msg = lua_pushfstring( - L, - "%s or %s expected, got %s", - lua_typename(L, LUA_TNUMBER), - lua_typename(L, LUA_TBOOLEAN), - luaL_typename(L, -1) - ); - return ghoul::lua::luaError( - L, fmt::format("bad argument #{} ({})", startLocation, msg) - ); - } - - int location = startLocation; - - if (firstIsBool) { - const bool useUpFromTarget = (lua_toboolean(L, location) == 1); - resultInstruction.setValue("UseTargetUpDirection", useUpFromTarget); - - if (nArguments > startLocation) { - location++; - } - } - - if (firstIsNumber || nArguments > startLocation) { - double duration = ghoul::lua::value(L, location); - if (duration <= Epsilon) { - lua_settop(L, 0); - return ghoul::lua::luaError(L, "Duration must be larger than zero."); - } - resultInstruction.setValue("Duration", duration); - } - - return 0; -} - int goTo(lua_State* L) { - int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 1, 3 }, "lua::goTo"); + ghoul::lua::checkArgumentsAndThrow(L, { 1, 3 }, "lua::goTo"); auto [nodeIdentifier, useUpFromTargetOrDuration, duration] = ghoul::lua::values< std::string, std::optional>, std::optional >(L); @@ -164,7 +121,7 @@ int goTo(lua_State* L) { } int goToHeight(lua_State* L) { - int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::goToHeight"); + ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::goToHeight"); auto [nodeIdentifier, height, useUpFromTargetOrDuration, duration] = ghoul::lua::values< std::string, double, std::optional>, From 506eaa6cc32f740814c4b33051009412ef7f9875 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Mon, 6 Sep 2021 14:46:12 +0200 Subject: [PATCH 21/23] Fix GlobeRotation/Translation not updating if simulation time is paused --- modules/globebrowsing/src/globerotation.cpp | 13 +++++++++---- modules/globebrowsing/src/globerotation.h | 1 + modules/globebrowsing/src/globetranslation.cpp | 13 +++++++++---- modules/globebrowsing/src/globetranslation.h | 1 + 4 files changed, 20 insertions(+), 8 deletions(-) diff --git a/modules/globebrowsing/src/globerotation.cpp b/modules/globebrowsing/src/globerotation.cpp index e210ad5f6c..08f5eae9b8 100644 --- a/modules/globebrowsing/src/globerotation.cpp +++ b/modules/globebrowsing/src/globerotation.cpp @@ -112,19 +112,19 @@ GlobeRotation::GlobeRotation(const ghoul::Dictionary& dictionary) _globe = p.globe; _latitude = p.latitude.value_or(_latitude); - _latitude.onChange([this]() { _matrixIsDirty = true; }); + _latitude.onChange([this]() { setUpdateVariables(); }); addProperty(_latitude); _longitude = p.longitude.value_or(_longitude); - _longitude.onChange([this]() { _matrixIsDirty = true; }); + _longitude.onChange([this]() { setUpdateVariables(); }); addProperty(_longitude); _useHeightmap = p.useHeightmap.value_or(_useHeightmap); - _useHeightmap.onChange([this]() { _matrixIsDirty = true; }); + _useHeightmap.onChange([this]() { setUpdateVariables(); }); addProperty(_useHeightmap); _angle = p.angle.value_or(_angle); - _angle.onChange([this]() { _matrixIsDirty = true; }); + _angle.onChange([this]() { setUpdateVariables(); }); addProperty(_angle); } @@ -145,6 +145,11 @@ void GlobeRotation::findGlobe() { } } +void GlobeRotation::setUpdateVariables() { + _matrixIsDirty = true; + requireUpdate(); +} + glm::vec3 GlobeRotation::computeSurfacePosition(double latitude, double longitude) const { ghoul_assert(_globeNode, "Globe cannot be nullptr"); diff --git a/modules/globebrowsing/src/globerotation.h b/modules/globebrowsing/src/globerotation.h index 4f46cf9447..a1b30a67e6 100644 --- a/modules/globebrowsing/src/globerotation.h +++ b/modules/globebrowsing/src/globerotation.h @@ -45,6 +45,7 @@ public: private: void findGlobe(); + void setUpdateVariables(); glm::vec3 computeSurfacePosition(double latitude, double longitude) const; properties::StringProperty _globe; diff --git a/modules/globebrowsing/src/globetranslation.cpp b/modules/globebrowsing/src/globetranslation.cpp index 57b9368eda..79c23906fd 100644 --- a/modules/globebrowsing/src/globetranslation.cpp +++ b/modules/globebrowsing/src/globetranslation.cpp @@ -113,20 +113,20 @@ GlobeTranslation::GlobeTranslation(const ghoul::Dictionary& dictionary) _globe = p.globe; _latitude = p.latitude.value_or(_latitude); - _latitude.onChange([this]() { _positionIsDirty = true; }); + _latitude.onChange([this]() { setUpdateVariables(); }); addProperty(_latitude); _longitude = p.longitude.value_or(_longitude); - _longitude.onChange([this]() { _positionIsDirty = true; }); + _longitude.onChange([this]() { setUpdateVariables(); }); addProperty(_longitude); _altitude = p.altitude.value_or(_altitude); _altitude.setExponent(8.f); - _altitude.onChange([this]() { _positionIsDirty = true; }); + _altitude.onChange([this]() { setUpdateVariables(); }); addProperty(_altitude); _useHeightmap = p.useHeightmap.value_or(_useHeightmap); - _useHeightmap.onChange([this]() { _positionIsDirty = true; }); + _useHeightmap.onChange([this]() { setUpdateVariables(); }); addProperty(_useHeightmap); } @@ -147,6 +147,11 @@ void GlobeTranslation::fillAttachedNode() { } } +void GlobeTranslation::setUpdateVariables() { + _positionIsDirty = true; + requireUpdate(); +} + glm::dvec3 GlobeTranslation::position(const UpdateData&) const { if (!_attachedNode) { // @TODO(abock): The const cast should be removed on a redesign of the translation diff --git a/modules/globebrowsing/src/globetranslation.h b/modules/globebrowsing/src/globetranslation.h index 3385903f34..85e5945174 100644 --- a/modules/globebrowsing/src/globetranslation.h +++ b/modules/globebrowsing/src/globetranslation.h @@ -45,6 +45,7 @@ public: private: void fillAttachedNode(); + void setUpdateVariables(); properties::StringProperty _globe; properties::DoubleProperty _latitude; From 5620cec153c92cc856b68a8ca48ca9df3d0c92d2 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Mon, 6 Sep 2021 15:52:50 +0200 Subject: [PATCH 22/23] Add an OrbitAroundUp IdleBehavior Rotates around the y-axis of the node instead of the z-axis. Would be great if the nodes themselves knew about which axis of rotation would be to prefer. --- .../openspace/navigation/orbitalnavigator.h | 33 ++++++++++++---- src/navigation/orbitalnavigator.cpp | 38 +++++++++++-------- 2 files changed, 48 insertions(+), 23 deletions(-) diff --git a/include/openspace/navigation/orbitalnavigator.h b/include/openspace/navigation/orbitalnavigator.h index 7b6ea2265c..b2b6c8556e 100644 --- a/include/openspace/navigation/orbitalnavigator.h +++ b/include/openspace/navigation/orbitalnavigator.h @@ -199,7 +199,8 @@ private: struct IdleBehavior : public properties::PropertyOwner { enum Behavior { Orbit = 0, - OrbitAtConstantLat + OrbitAtConstantLat, + OrbitAroundUp }; IdleBehavior(); @@ -369,20 +370,36 @@ private: glm::dquat& localRotation, glm::dquat& globalRotation); /** - * IdleBehavior::Behavior::Orbit * Orbit the current anchor node, in a right-bound orbit, by updating the position - * and global rotation of the camera + * and global rotation of the camera. + * + * Used for IdleBehavior::Behavior::Orbit + * + * \param deltaTime The time step to use for the motion. Controls the rotation angle + * \param position The position of the camera. Will be changed by the function + * \param globalRotation The camera's global rotation. Will be changed by the function + * \param speedScale A speed scale that controls the speed of the motion */ void orbitAnchor(double deltaTime, glm::dvec3& position, glm::dquat& globalRotation, double speedScale); /** - * IdleBehavior::Behavior::OrbitAtConstantLat - * Orbit the current anchor node, but stay on the current latitude band. Note that - * this creates a rolling motion if looking at any of the anchor's poles, and should - * be used with care + * Orbit the current anchor node, by adding a rotation around the given axis. For + * example, when the axis is the north vector, the camera will stay on the current + * latitude band. Note that this creates a rolling motion if the camera's forward + * vector coincides with the axis, and should be used with care. + * + * Used for: + * IdleBehavior::Behavior::OrbitAtConstantLat ( axis = north = z-axis ) and + * IdleBehavior::Behavior::OrbitAroundUp ( axis = up = y-axis ) + * + * \param axis The axis to arbit around, given in model coordinates of the anchor + * \param deltaTime The time step to use for the motion. Controls the rotation angle + * \param position The position of the camera. Will be changed by the function + * \param globalRotation The camera's global rotation. Will be changed by the function + * \param speedScale A speed scale that controls the speed of the motion */ - void orbitAtConstantLatitude(double deltaTime, glm::dvec3& position, + void orbitAroundAxis(const glm::dvec3 axis, double deltaTime, glm::dvec3& position, glm::dquat& globalRotation, double speedScale); }; diff --git a/src/navigation/orbitalnavigator.cpp b/src/navigation/orbitalnavigator.cpp index d8cbed89d7..0be1d03c89 100644 --- a/src/navigation/orbitalnavigator.cpp +++ b/src/navigation/orbitalnavigator.cpp @@ -310,7 +310,8 @@ OrbitalNavigator::IdleBehavior::IdleBehavior() addProperty(apply); chosenBehavior.addOptions({ { IdleBehavior::Behavior::Orbit, "Orbit" }, - { IdleBehavior::Behavior::OrbitAtConstantLat, "OrbitAtConstantLatitude" } + { IdleBehavior::Behavior::OrbitAtConstantLat, "OrbitAtConstantLatitude" }, + { IdleBehavior::Behavior::OrbitAroundUp, "OrbitAroundUp" } }); chosenBehavior = IdleBehavior::Behavior::Orbit; addProperty(chosenBehavior); @@ -1614,9 +1615,21 @@ void OrbitalNavigator::applyIdleBehavior(double deltaTime, glm::dvec3& position, case IdleBehavior::Behavior::Orbit: orbitAnchor(deltaTime, position, globalRotation, speedScale); break; - case IdleBehavior::Behavior::OrbitAtConstantLat: - orbitAtConstantLatitude(deltaTime, position, globalRotation, speedScale); + case IdleBehavior::Behavior::OrbitAtConstantLat: { + // Assume that "north" coincides with the local z-direction + // @TODO (2021-07-09, emmbr) Make each scene graph node aware of its own + // north/up, so that we can query this information rather than assuming it. + // The we could also combine this idle behavior with the next + const glm::dvec3 north = glm::dvec3(0.0, 0.0, 1.0); + orbitAroundAxis(north, deltaTime, position, globalRotation, speedScale); break; + } + case IdleBehavior::Behavior::OrbitAroundUp: { + // Assume that "up" coincides with the local y-direction + const glm::dvec3 up = glm::dvec3(0.0, 1.0, 0.0); + orbitAroundAxis(up, deltaTime, position, globalRotation, speedScale); + break; + } default: throw ghoul::MissingCaseException(); } @@ -1645,24 +1658,19 @@ void OrbitalNavigator::orbitAnchor(double deltaTime, glm::dvec3& position, position += rotationDiffVec3; } -void OrbitalNavigator::orbitAtConstantLatitude(double deltaTime, glm::dvec3& position, - glm::dquat& globalRotation, - double speedScale) +void OrbitalNavigator::orbitAroundAxis(const glm::dvec3 axis, double deltaTime, + glm::dvec3& position, glm::dquat& globalRotation, + double speedScale) { ghoul_assert(_anchorNode != nullptr, "Node to orbit must be set!"); const glm::dmat4 modelTransform = _anchorNode->modelTransform(); + const glm::dvec3 axisInWorldCoords = + glm::dmat3(modelTransform) * glm::normalize(axis); - // Assume north coincides with the local z-direction - // @TODO (2021-07-09, emmbr) Make each scene graph node aware of its own north/up, so - // that we can query this information rather than assuming it - const glm::dvec3 northInWorldCoords = - glm::dmat3(modelTransform) * glm::dvec3(0.0, 0.0, 1.0); - - // Compute rotation around the north axis to be applied + // Compute rotation to be applied around the axis double angle = deltaTime * speedScale; - const glm::dquat spinRotation = - glm::angleAxis(angle, glm::normalize(northInWorldCoords)); + const glm::dquat spinRotation = glm::angleAxis(angle, axisInWorldCoords); // Rotate the position vector from the center to camera and update position const glm::dvec3 anchorCenterToCamera = position - _anchorNode->worldPosition(); From 5b69cf45f110354ecf3bdbcee8cf9d2c75b07e9e Mon Sep 17 00:00:00 2001 From: Malin E Date: Mon, 6 Sep 2021 16:22:36 +0200 Subject: [PATCH 23/23] Avoid crash in parallellconnection if there is no connection --- src/network/parallelconnection.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/network/parallelconnection.cpp b/src/network/parallelconnection.cpp index de1fc5300b..8290ab974e 100644 --- a/src/network/parallelconnection.cpp +++ b/src/network/parallelconnection.cpp @@ -61,7 +61,7 @@ ParallelConnection::ParallelConnection(std::unique_ptr soc {} bool ParallelConnection::isConnectedOrConnecting() const { - return _socket->isConnected() || _socket->isConnecting(); + return _socket != nullptr && (_socket->isConnected() || _socket->isConnecting()); } void ParallelConnection::sendDataMessage(const DataMessage& dataMessage) {