diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index c5288e6f1d..4964fd4109 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit c5288e6f1da32366b0b35e2072cd0c21eb1f7453 +Subproject commit 4964fd4109a2c430b2b032d339e8f42a7dcabcaf diff --git a/data/web/documentation/scripting.hbs b/data/web/documentation/scripting.hbs index 984a92ed02..c40d1712ae 100644 --- a/data/web/documentation/scripting.hbs +++ b/data/web/documentation/scripting.hbs @@ -12,17 +12,28 @@

- {{name}}( - {{arguments}} + + {{#each arguments}} + {{name}} + ({{type}}) + {{#unless @last}},{{/unless}} + {{/each}} + ) + {{#if returnType}} + + -> + {{returnType}} + + {{/if}}

{{help}}

- {{/each}} + {{/each}} {{/each}} diff --git a/data/web/documentation/style.css b/data/web/documentation/style.css index 08cea11009..1309f012a5 100644 --- a/data/web/documentation/style.css +++ b/data/web/documentation/style.css @@ -63,6 +63,23 @@ font-style: italic; } +.documentation-function-arguments, +.documentation-function-return +{ + font-size: 0.8em; +} + +.documentation-function-arguments > .arguments-name { + color: #777; + font-style: italic; +} + +.documentation-function-arguments > .arguments-type, +.documentation-function-return +{ + color: #aaa; +} + .documentation-key { color: #333; font-weight: bold; diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 505eececc6..89bc1a28f7 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -213,11 +213,6 @@ void setAdditionalScriptsFromProfile(const Profile& p); } // namespace openspace -// Lua functions - exposed for testing -namespace openspace::luascriptfunctions { - -int createSingleColorImage(lua_State* L); - -} // openspace::luascriptfunctions +std::filesystem::path createSingleColorImage(std::string name, glm::dvec3 color); #endif // __OPENSPACE_CORE___OPENSPACEENGINE___H__ diff --git a/include/openspace/scene/scene.h b/include/openspace/scene/scene.h index fc842cf3a0..107f2ee4c9 100644 --- a/include/openspace/scene/scene.h +++ b/include/openspace/scene/scene.h @@ -237,9 +237,7 @@ public: /** * Returns the Lua library that contains all Lua functions available to change the - * scene graph. The functions contained are - * - openspace::luascriptfunctions::property_setValue - * - openspace::luascriptfunctions::property_getValue + * scene graph. * \return The Lua library that contains all Lua functions available to change the * scene graph */ diff --git a/include/openspace/scripting/lualibrary.h b/include/openspace/scripting/lualibrary.h index abdeb79c5f..8edefd9688 100644 --- a/include/openspace/scripting/lualibrary.h +++ b/include/openspace/scripting/lualibrary.h @@ -47,8 +47,18 @@ struct LuaLibrary { std::string name; /// The function pointer that is executed if the function is called lua_CFunction function; - /// A text describing the arguments to this function - std::string argumentText; + struct Argument { + /// The name of the arguments + std::string name; + /// The type of the argument + std::string type; + /// The default value if it exists + std::optional defaultValue = std::nullopt; + }; + /// The ordered arguments that this function takes + std::vector arguments; + /// Information about the type that this function returns + std::string returnType; /// A help text describing what the function does/ std::string helpText; }; @@ -61,19 +71,9 @@ struct LuaLibrary { /// A list of all libraries that are children for this library std::vector subLibraries = std::vector(); - /// This struct contains information about a function or constant that is defined in - /// a Lua script - struct Documentation { - /// The name of the function/variable - std::string name; - /// The description of the parameters for a function - std::string parameter; - /// The description of the function/variable - std::string description; - }; /// The list of documentations will be populated automatically by parsing the Lua /// scripts - std::vector documentations = std::vector(); + std::vector documentations = std::vector(); /// Comparison function that compares two LuaLibrary%s name bool operator<(const LuaLibrary& rhs) const; diff --git a/include/openspace/util/time.h b/include/openspace/util/time.h index 6910963568..624833e546 100644 --- a/include/openspace/util/time.h +++ b/include/openspace/util/time.h @@ -143,8 +143,6 @@ public: /** * Sets a relative time from profile. - * \param setTime a string containing time adjustment as described in documentation - * for luascriptfunctions::time_advancedTime */ void setTimeRelativeFromProfile(const std::string& setTime); diff --git a/modules/base/rendering/screenspacedashboard.cpp b/modules/base/rendering/screenspacedashboard.cpp index 05fef10db7..585ade5bb8 100644 --- a/modules/base/rendering/screenspacedashboard.cpp +++ b/modules/base/rendering/screenspacedashboard.cpp @@ -136,18 +136,8 @@ scripting::LuaLibrary ScreenSpaceDashboard::luaLibrary() { return { "dashboard", { - { - "addDashboardItemToScreenSpace", - &luascriptfunctions::addDashboardItemToScreenSpace, - "string, table", - "Adds a new dashboard item to an existing SceenSpaceDashboard." - }, - { - "removeDashboardItemsFromScreenSpace", - &luascriptfunctions::removeDashboardItemsFromScreenSpace, - "string", - "Removes all dashboard items from an existing ScreenSpaceDashboard." - } + codegen::lua::AddDashboardItemToScreenSpace, + codegen::lua::RemoveDashboardItemsFromScreenSpace } }; } diff --git a/modules/base/rendering/screenspacedashboard_lua.inl b/modules/base/rendering/screenspacedashboard_lua.inl index ef984b5c0f..104fc3eaf0 100644 --- a/modules/base/rendering/screenspacedashboard_lua.inl +++ b/modules/base/rendering/screenspacedashboard_lua.inl @@ -22,56 +22,48 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -namespace openspace::luascriptfunctions { +namespace { -/** - * \ingroup LuaScripts - * addDashboardItemToScreenSpace(string, table): - */ -int addDashboardItemToScreenSpace(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addDashboardItemToScreenSpace"); - auto [name, d] = ghoul::lua::values(L); +//Adds a new dashboard item to an existing SceenSpaceDashboard. +[[codegen::luawrap]] void addDashboardItemToScreenSpace(std::string identifier, + ghoul::Dictionary dashboard) +{ + using namespace openspace; - ScreenSpaceRenderable* ssr = global::renderEngine->screenSpaceRenderable(name); + ScreenSpaceRenderable* ssr = global::renderEngine->screenSpaceRenderable(identifier); if (!ssr) { - return ghoul::lua::luaError(L, "Provided name is not a ScreenSpace item"); + throw ghoul::lua::LuaError("Provided name is not a ScreenSpace item"); } ScreenSpaceDashboard* dash = dynamic_cast(ssr); if (!dash) { - return ghoul::lua::luaError( - L, + throw ghoul::lua::LuaError( "Provided name is a ScreenSpace item but not a dashboard" ); } - dash->dashboard().addDashboardItem(DashboardItem::createFromDictionary(d)); - return 0; + dash->dashboard().addDashboardItem(DashboardItem::createFromDictionary(dashboard)); } -/** - * \ingroup LuaScripts - * removeDashboardItemsFromScreenSpace(string): - */ -int removeDashboardItemsFromScreenSpace(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeDashboardItemsFromScreenSpace"); - const std::string name = ghoul::lua::value(L); +// Removes all dashboard items from an existing ScreenSpaceDashboard. +[[codegen::luawrap]] void removeDashboardItemsFromScreenSpace(std::string identifier) { + using namespace openspace; - ScreenSpaceRenderable* ssr = global::renderEngine->screenSpaceRenderable(name); + ScreenSpaceRenderable* ssr = global::renderEngine->screenSpaceRenderable(identifier); if (!ssr) { - return ghoul::lua::luaError(L, "Provided name is not a ScreenSpace item"); + throw ghoul::lua::LuaError("Provided identifier 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" + throw ghoul::lua::LuaError( + "Provided identifier is a ScreenSpace item but not a dashboard" ); } dash->dashboard().clearDashboardItems(); - return 0; } -} // namespace openspace::luascriptfunctions +#include "screenspacedashboard_lua_codegen.cpp" + +} // namespace diff --git a/modules/debugging/debuggingmodule.cpp b/modules/debugging/debuggingmodule.cpp index 68a8a82a78..15ec369cc4 100644 --- a/modules/debugging/debuggingmodule.cpp +++ b/modules/debugging/debuggingmodule.cpp @@ -26,9 +26,18 @@ #include #include +#include +#include +#include +#include #include +#include +#include +#include +#include #include #include +#include #include #include @@ -53,51 +62,16 @@ std::vector DebuggingModule::documentations() cons } scripting::LuaLibrary DebuggingModule::luaLibrary() const { - scripting::LuaLibrary res; - res.name = "debugging"; - res.functions = { + return { + "debugging", { - "renderCameraPath", - &luascriptfunctions::renderCameraPath, - "[number, bool, number]", - "Render the current camera path from the path navigation system. The " - "first optional argument is the number of samples to take along the path " - "(defaults to 100). If a second optional argument is included and set to " - "true, a line indicating the camera view direction along the path will " - "also be rendered. This can be useful when debugging camera orientations. " - "Finally, the third optional argument can be used to set the length " - "(in meter) of the view direction lines" - }, - { - "removeRenderedCameraPath", - &luascriptfunctions::removeRenderedCameraPath, - "", - "Removes the rendered camera path, if there is one" - }, - { - "renderPathControlPoints", - &luascriptfunctions::renderPathControlPoints, - "[number]", - "Render the control points for the camera path spline as spheres. The " - "optional argument can be used to set the radius of the created spheres. " - }, - { - "removePathControlPoints", - &luascriptfunctions::removePathControlPoints, - "", - "Removes the rendered control points" - }, - { - "addCartesianAxes", - &luascriptfunctions::addCartesianAxes, - "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 " - "(optional) argument is a scale value, in meters." + codegen::lua::RenderCameraPath, + codegen::lua::RemoveRenderedCameraPath, + codegen::lua::RenderPathControlPoints, + codegen::lua::RemovePathControlPoints, + codegen::lua::AddCartesianAxes } }; - - return res; } } // namespace openspace diff --git a/modules/debugging/debuggingmodule_lua.inl b/modules/debugging/debuggingmodule_lua.inl index 80425dde83..eae448dd5c 100644 --- a/modules/debugging/debuggingmodule_lua.inl +++ b/modules/debugging/debuggingmodule_lua.inl @@ -22,46 +22,39 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include -#include - namespace { - constexpr const char _loggerCat[] = "Debugging"; - constexpr const char RenderedPathIdentifier[] = "CurrentCameraPath"; - constexpr const char RenderedPointsIdentifier[] = "CurrentPathControlPoints"; - constexpr const char DebuggingGuiPath[] = "/Debugging"; +constexpr const char RenderedPathIdentifier[] = "CurrentCameraPath"; +constexpr const char RenderedPointsIdentifier[] = "CurrentPathControlPoints"; +constexpr const char DebuggingGuiPath[] = "/Debugging"; - constexpr const glm::vec3 PathColor = { 1.0, 1.0, 0.0 }; - constexpr const glm::vec3 OrientationLineColor = { 0.0, 1.0, 1.0 }; +constexpr const glm::vec3 PathColor = { 1.0, 1.0, 0.0 }; +constexpr const glm::vec3 OrientationLineColor = { 0.0, 1.0, 1.0 }; - // Conver the input string to a format that is valid as an identifier - std::string makeIdentifier(std::string s) { - std::replace(s.begin(), s.end(), ' ', '_'); - std::replace(s.begin(), s.end(), '.', '-'); - // Remove quotes and apostrophe, since they cause problems - // when a string is translated to a script call - s.erase(remove(s.begin(), s.end(), '\"'), s.end()); - s.erase(remove(s.begin(), s.end(), '\''), s.end()); - return s; - } -} // namespace - -namespace openspace::luascriptfunctions { +// Conver the input string to a format that is valid as an identifier +std::string makeIdentifier(std::string s) { + std::replace(s.begin(), s.end(), ' ', '_'); + std::replace(s.begin(), s.end(), '.', '-'); + // Remove quotes and apostrophe, since they cause problems + // when a string is translated to a script call + s.erase(remove(s.begin(), s.end(), '\"'), s.end()); + s.erase(remove(s.begin(), s.end(), '\''), s.end()); + return s; +} /** - * PathNavigation - * Renders the current camera path + * Render the current camera path from the path navigation system. The first optional + * argument is the number of samples to take along the path (defaults to 100). If a second + * optional argument is included and set to true, a line indicating the camera view + * direction along the path will also be rendered. This can be useful when debugging + * camera orientations. Finally, the third optional argument can be used to set the length + * (in meter) of the view direction lines. */ -int renderCameraPath(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, { 0, 3 }, "lua::renderCameraPath"); +[[codegen::luawrap]] void renderCameraPath(int nSteps = 100, + bool renderDirections = false, + double directionLineLength = 6e7) +{ + using namespace openspace; if (!global::navigationHandler->pathNavigator().hasCurrentPath()) { LWARNINGC("Debugging: PathNavigation", "There is no current path to render"); @@ -70,15 +63,7 @@ int renderCameraPath(lua_State* L) { const interaction::Path* currentPath = global::navigationHandler->pathNavigator().currentPath(); - auto [nSteps, renderDirections, directionLineLength] = ghoul::lua::values< - std::optional, std::optional, std::optional - >(L); - - 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 + // Parent node. Note that we only render one path at a time, so remove the previously // rendered one, if any std::string addParentScript = fmt::format( "if openspace.hasSceneGraphNode('{0}') then " @@ -88,14 +73,14 @@ int renderCameraPath(lua_State* L) { RenderedPathIdentifier ); - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( addParentScript, scripting::ScriptEngine::RemoteScripting::Yes ); // 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); @@ -120,7 +105,7 @@ int renderCameraPath(lua_State* L) { "}" "}"; - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( fmt::format("openspace.addSceneGraphNode({})", pointNode), scripting::ScriptEngine::RemoteScripting::Yes ); @@ -142,7 +127,7 @@ int renderCameraPath(lua_State* L) { "}" "}"; - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( fmt::format("openspace.addSceneGraphNode({})", lineNode), scripting::ScriptEngine::RemoteScripting::Yes ); @@ -162,43 +147,35 @@ 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(), *directionLineLength); + 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], *directionLineLength); + if (renderDirections) { + addDirectionLine(pointIdentifier(i), poses[i], directionLineLength); } } - - return 0; } -/** - * PathNavigation - * Removes the currently rendered camera path if there is one - */ -int removeRenderedCameraPath(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::removeRenderedCameraPath"); - - openspace::global::scriptEngine->queueScript( - fmt::format("openspace.removeSceneGraphNode('{}') ", RenderedPathIdentifier), +// Removes the currently rendered camera path if there is one. +[[codegen::luawrap]] void removeRenderedCameraPath() { + using namespace openspace; + global::scriptEngine->queueScript( + fmt::format("openspace.removeSceneGraphNode('{}');", RenderedPathIdentifier), scripting::ScriptEngine::RemoteScripting::Yes ); - - return 0; } /** - * PathNavigation - * Renders the control points of the current camera path + * Render the control points for the camera path spline as spheres. The optional argument + * can be used to set the radius of the created spheres. */ -int renderPathControlPoints(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, { 0, 1 }, "lua::renderPathControlPoints"); +[[codegen::luawrap]] void renderPathControlPoints(double radius = 2000000.0) { + using namespace openspace; if (!global::navigationHandler->pathNavigator().hasCurrentPath()) { LWARNINGC( @@ -209,20 +186,17 @@ int renderPathControlPoints(lua_State* L) { const interaction::Path* currentPath = global::navigationHandler->pathNavigator().currentPath(); - 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 + // Parent node. Note that we only render one set of points at a time, so remove any + // previously rendered ones std::string addParentScript = fmt::format( "if openspace.hasSceneGraphNode('{0}') then " - "openspace.removeSceneGraphNode('{0}') " + "openspace.removeSceneGraphNode('{0}') " "end " "openspace.addSceneGraphNode( {{ Identifier = '{0}' }} )", RenderedPointsIdentifier ); - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( addParentScript, scripting::ScriptEngine::RemoteScripting::Yes ); @@ -234,74 +208,69 @@ int renderPathControlPoints(lua_State* L) { const char* colorTexturePath = "openspace.absPath(" "openspace.createSingleColorImage('point_color', { 0.0, 1.0, 0.0 })" - ")"; + ")"; for (size_t i = 0; i < points.size(); i++) { const std::string& node = "{" "Identifier = 'ControlPoint_" + std::to_string(i) + "'," "Parent = '" + RenderedPointsIdentifier + "'," "Transform = { " - "Translation = {" - "Type = 'StaticTranslation'," - "Position = " + ghoul::to_string(points[i]) + "" - "}," + "Translation = {" + "Type = 'StaticTranslation'," + "Position = " + ghoul::to_string(points[i]) + "" + "}," "}," "Renderable = {" - "Type = 'RenderableSphere'," - "Enabled = true," - "Segments = 30," - "Size = " + std::to_string(*radius) + "," - "Texture = " + colorTexturePath + "" + "Type = 'RenderableSphere'," + "Enabled = true," + "Segments = 30," + "Size = " + std::to_string(radius) + "," + "Texture = " + colorTexturePath + "" "}," "GUI = {" - "Name = 'Control Point " + std::to_string(i) + "'," - "Path = '" + guiPath + "'" + "Name = 'Control Point " + std::to_string(i) + "'," + "Path = '" + guiPath + "'" "}" - "}"; + "}"; - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( fmt::format("openspace.addSceneGraphNode({})", node), scripting::ScriptEngine::RemoteScripting::Yes ); } - - return 0; } -/** - * PathNavigation - * Removes the rendered control points - */ -int removePathControlPoints(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::removePathControlPoints"); - - openspace::global::scriptEngine->queueScript( - fmt::format("openspace.removeSceneGraphNode('{}') ", RenderedPointsIdentifier), +// Removes the rendered control points. +[[codegen::luawrap]] void removePathControlPoints() { + using namespace openspace; + global::scriptEngine->queueScript( + fmt::format("openspace.removeSceneGraphNode('{}');", RenderedPointsIdentifier), scripting::ScriptEngine::RemoteScripting::Yes ); - - return 0; } /** - * Add a set of cartesian axes to the specified scene graph node + * Adds a set of Cartesian axes to the scene graph node identified by the first string, to + * illustrate its local coordinate system. The second (optional) argument is a scale + * value, in meters. */ -int addCartesianAxes(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::addCartesianAxes"); - - auto [nodeIdentifier, scale] = - ghoul::lua::values>(L); - +[[codegen::luawrap]] void addCartesianAxes(std::string nodeIdentifier, + std::optional scale) +{ + using namespace openspace; SceneGraphNode* n = global::renderEngine->scene()->sceneGraphNode(nodeIdentifier); if (!n) { - return ghoul::lua::luaError(L, "Unknown scene graph node: " + nodeIdentifier); + throw ghoul::lua::LuaError("Unknown scene graph node: " + nodeIdentifier); } 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"); + if (n->boundingSphere() <= 0.0) { + LWARNINGC( + "Debugging: Cartesian Axes", + "Using zero bounding sphere for scale of created axes. You need to set " + "the scale manually for them to be visible" + ); scale = 1.0; } } @@ -311,31 +280,30 @@ int addCartesianAxes(lua_State* L) { "Identifier = '" + identifier + "'," "Parent = '" + nodeIdentifier + "'," "Transform = { " - "Scale = {" - "Type = 'StaticScale'," - "Scale = " + std::to_string(*scale) + "" - "}" + "Scale = {" + "Type = 'StaticScale'," + "Scale = " + std::to_string(*scale) + "" + "}" "}," "Renderable = {" - "Type = 'RenderableCartesianAxes'," - "Enabled = true," - "XColor = { 1.0, 0.0, 0.0 }," - "YColor = { 0.0, 1.0, 0.0 }," - "ZColor = { 0.0, 0.0, 1.0 }" + "Type = 'RenderableCartesianAxes'," + "Enabled = true," + "XColor = { 1.0, 0.0, 0.0 }," + "YColor = { 0.0, 1.0, 0.0 }," + "ZColor = { 0.0, 0.0, 1.0 }" "}," "GUI = {" - "Name = '" + identifier + "'," - "Path = '" + DebuggingGuiPath + "/Coordiante Systems'" + "Name = '" + identifier + "'," + "Path = '" + DebuggingGuiPath + "/Coordiante Systems'" "}" "}"; - openspace::global::scriptEngine->queueScript( - fmt::format("openspace.addSceneGraphNode({})", axes), + global::scriptEngine->queueScript( + fmt::format("openspace.addSceneGraphNode({});", axes), scripting::ScriptEngine::RemoteScripting::Yes ); - - return 0; } -} // namespace openspace::luascriptfunctions +#include "debuggingmodule_lua_codegen.cpp" +} // namespace diff --git a/modules/exoplanets/exoplanetsmodule.cpp b/modules/exoplanets/exoplanetsmodule.cpp index 4b0a4191f2..c602a9cedc 100644 --- a/modules/exoplanets/exoplanetsmodule.cpp +++ b/modules/exoplanets/exoplanetsmodule.cpp @@ -24,15 +24,29 @@ #include +#include #include #include #include #include +#include +#include #include #include #include +#include +#include #include +#include +#include +#include +#include +#include +#include +#include #include +#include +#include #include "exoplanetsmodule_lua.inl" @@ -256,41 +270,6 @@ float ExoplanetsModule::habitableZoneOpacity() const { return _habitableZoneOpacity; } -scripting::LuaLibrary ExoplanetsModule::luaLibrary() const { - scripting::LuaLibrary res; - res.name = "exoplanets"; - res.functions = { - { - "addExoplanetSystem", - &exoplanets::luascriptfunctions::addExoplanetSystem, - "string or list of strings", - "Add one or multiple exoplanet systems to the scene, as specified by the " - "input. An input string should be the name of the system host star" - }, - { - "removeExoplanetSystem", - &exoplanets::luascriptfunctions::removeExoplanetSystem, - "string", - "Removes the nodes of the specified exoplanet system from the scene graph" - }, - { - "listAvailableExoplanetSystems", - &exoplanets::luascriptfunctions::listAvailableExoplanetSystems, - "", - "Prints a list with the names of all exoplanet systems that can be added to " - "the scene graph to the OpenSpace Log" - }, - { - "getListOfExoplanets", - &exoplanets::luascriptfunctions::getListOfExoplanets, - "", - "Gets a list with the names of all exoplanet systems" - } - }; - - return res; -} - void ExoplanetsModule::internalInitialize(const ghoul::Dictionary& dict) { const Parameters p = codegen::bake(dict); @@ -343,4 +322,16 @@ std::vector ExoplanetsModule::documentations() con }; } +scripting::LuaLibrary ExoplanetsModule::luaLibrary() const { + return { + "exoplanets", + { + codegen::lua::AddExoplanetSystem, + codegen::lua::RemoveExoplanetSystem, + codegen::lua::GetListOfExoplanets, + codegen::lua::ListAvailableExoplanetSystems + } + }; +} + } // namespace openspace diff --git a/modules/exoplanets/exoplanetsmodule_lua.inl b/modules/exoplanets/exoplanetsmodule_lua.inl index 79e2c397f6..c7f562cf94 100644 --- a/modules/exoplanets/exoplanetsmodule_lua.inl +++ b/modules/exoplanets/exoplanetsmodule_lua.inl @@ -22,44 +22,25 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - namespace { - constexpr const char _loggerCat[] = "ExoplanetsModule"; - constexpr const char ExoplanetsGuiPath[] = "/Milky Way/Exoplanets/Exoplanet Systems/"; +constexpr const char _loggerCat[] = "ExoplanetsModule"; - // Lua cannot handle backslashes, so replace these with forward slashes - std::string formatPathToLua(const std::string& path) { - std::string resPath = path; - std::replace(resPath.begin(), resPath.end(), '\\', '/'); - return resPath; - } -} // namespace +constexpr const char ExoplanetsGuiPath[] = "/Milky Way/Exoplanets/Exoplanet Systems/"; -namespace openspace::exoplanets::luascriptfunctions { +// Lua cannot handle backslashes, so replace these with forward slashes +std::string formatPathToLua(const std::string& path) { + std::string resPath = path; + std::replace(resPath.begin(), resPath.end(), '\\', '/'); + return resPath; +} -constexpr const float AU = static_cast(distanceconstants::AstronomicalUnit); -constexpr const float SolarRadius = static_cast(distanceconstants::SolarRadius); -constexpr const float JupiterRadius = - static_cast(distanceconstants::JupiterRadius); +openspace::exoplanets::ExoplanetSystem findExoplanetSystemInData( + std::string_view starName) +{ + using namespace openspace; + using namespace exoplanets; -ExoplanetSystem findExoplanetSystemInData(std::string_view starName) { const ExoplanetsModule* module = global::moduleEngine->module(); const std::string binPath = module->exoplanetsDataPath(); @@ -135,6 +116,9 @@ ExoplanetSystem findExoplanetSystemInData(std::string_view starName) { } void createExoplanetSystem(const std::string& starName) { + using namespace openspace; + using namespace exoplanets; + const std::string starIdentifier = createIdentifier(starName); std::string sanitizedStarName = starName; @@ -173,7 +157,7 @@ void createExoplanetSystem(const std::string& starName) { const glm::dmat3 exoplanetSystemRotation = computeSystemRotation(starPos); // Star - float radiusInMeter = SolarRadius; + double radiusInMeter = distanceconstants::SolarRadius; if (!std::isnan(system.starData.radius)) { radiusInMeter *= system.starData.radius; } @@ -242,7 +226,7 @@ void createExoplanetSystem(const std::string& starName) { "}" "}"; - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( "openspace.addSceneGraphNode(" + starParent + ");", scripting::ScriptEngine::RemoteScripting::Yes ); @@ -278,25 +262,25 @@ void createExoplanetSystem(const std::string& starName) { sEpoch = "2009-05-19T07:11:34.080"; } - float planetRadius; + double planetRadius; std::string enabled; if (std::isnan(planet.r)) { if (std::isnan(planet.rStar)) { - planetRadius = planet.a * 0.001f * AU; + planetRadius = planet.a * 0.001 * distanceconstants::AstronomicalUnit; } else { - planetRadius = planet.rStar * 0.1f * SolarRadius; + planetRadius = planet.rStar * 0.1 * distanceconstants::SolarRadius; } enabled = "false"; } else { - planetRadius = static_cast(planet.r) * JupiterRadius; + planetRadius = planet.r * distanceconstants::JupiterRadius; enabled = "true"; } - const float periodInSeconds = static_cast(planet.per * SecondsPerDay); - const float semiMajorAxisInMeter = planet.a * AU; - const float semiMajorAxisInKm = semiMajorAxisInMeter * 0.001f; + float periodInSeconds = static_cast(planet.per * SecondsPerDay); + double semiMajorAxisInMeter = planet.a * distanceconstants::AstronomicalUnit; + double semiMajorAxisInKm = semiMajorAxisInMeter * 0.001; const std::string planetIdentifier = createIdentifier(planetName); @@ -356,7 +340,7 @@ void createExoplanetSystem(const std::string& starName) { "}" "}"; - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( "openspace.addSceneGraphNode(" + planetTrailNode + ");" "openspace.addSceneGraphNode(" + planetNode + ");", scripting::ScriptEngine::RemoteScripting::Yes @@ -406,7 +390,7 @@ void createExoplanetSystem(const std::string& starName) { "}" "}"; - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( "openspace.addSceneGraphNode(" + discNode + ");", scripting::ScriptEngine::RemoteScripting::Yes ); @@ -442,7 +426,7 @@ void createExoplanetSystem(const std::string& starName) { "}," "Scale = {" "Type = 'StaticScale'," - "Scale = " + std::to_string(AU) + "" + "Scale = " + std::to_string(distanceconstants::AstronomicalUnit) + "" "}" "}," "GUI = {" @@ -451,7 +435,7 @@ void createExoplanetSystem(const std::string& starName) { "}" "}"; - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( "openspace.addSceneGraphNode(" + circle + ");", scripting::ScriptEngine::RemoteScripting::Yes ); @@ -506,7 +490,7 @@ void createExoplanetSystem(const std::string& starName) { "}" "}"; - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( "openspace.addSceneGraphNode(" + zoneDiscNode + ");", scripting::ScriptEngine::RemoteScripting::Yes ); @@ -547,7 +531,7 @@ void createExoplanetSystem(const std::string& starName) { "}" "}"; - openspace::global::scriptEngine->queueScript( + global::scriptEngine->queueScript( "openspace.addSceneGraphNode(" + starGlare + ");", scripting::ScriptEngine::RemoteScripting::Yes ); @@ -555,46 +539,9 @@ 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); - - if (std::holds_alternative(v)) { - // The user provided a single name - std::string starName = std::get(v); - createExoplanetSystem(starName); - } - else { - // A list of names was provided - 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) - ); - } - const std::string& starName = starNames.value(std::to_string(i)); - createExoplanetSystem(starName); - } - } - return 0; -} - -int removeExoplanetSystem(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeExoplanetSystem"); - std::string starName = ghoul::lua::value(L); - - const std::string starIdentifier = createIdentifier(std::move(starName)); - openspace::global::scriptEngine->queueScript( - "openspace.removeSceneGraphNode('" + starIdentifier + "');", - scripting::ScriptEngine::RemoteScripting::Yes - ); - return 0; -} - std::vector hostStarsWithSufficientData() { + using namespace openspace; + using namespace exoplanets; const ExoplanetsModule* module = global::moduleEngine->module(); if (!module->hasDataFiles()) { @@ -657,23 +604,42 @@ std::vector hostStarsWithSufficientData() { return names; } -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) { - ghoul::lua::push(L, s); - lua_rawseti(L, -2, number); - ++number; +/** + * Add one or multiple exoplanet systems to the scene, as specified by the input. An input + * string should be the name of the system host star. + */ +[[codegen::luawrap]] void addExoplanetSystem( + std::variant> starNames) +{ + if (std::holds_alternative(starNames)) { + // The user provided a single name + std::string starName = std::get(starNames); + createExoplanetSystem(starName); + } + else { + std::vector sns = std::get>(starNames); + for (const std::string& starName : sns) { + createExoplanetSystem(starName); + } } - return 1; } -int listAvailableExoplanetSystems(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::listAvailableExoplanetSystems"); +[[codegen::luawrap]] void removeExoplanetSystem(std::string starName) { + using namespace openspace; + using namespace exoplanets; + const std::string starIdentifier = createIdentifier(std::move(starName)); + global::scriptEngine->queueScript( + "openspace.removeSceneGraphNode('" + starIdentifier + "');", + scripting::ScriptEngine::RemoteScripting::Yes + ); +} +[[codegen::luawrap]] std::vector getListOfExoplanets() { + std::vector names = hostStarsWithSufficientData(); + return names; +} + +[[codegen::luawrap]] void listAvailableExoplanetSystems() { std::vector names = hostStarsWithSufficientData(); std::string output; @@ -687,7 +653,8 @@ int listAvailableExoplanetSystems(lua_State* L) { "There is data available for the following {} exoplanet systems: {}", names.size(), output )); - return 0; } -} //namespace openspace::exoplanets::luascriptfunctions +#include "exoplanetsmodule_lua_codegen.cpp" + +} // namespace diff --git a/modules/gaia/scripts/filtering.lua b/modules/gaia/scripts/filtering.lua index d1b3179863..896f6c2d24 100644 --- a/modules/gaia/scripts/filtering.lua +++ b/modules/gaia/scripts/filtering.lua @@ -1,22 +1,22 @@ openspace.gaia.documentation = { { Name = "addClippingBox", - Arguments = "string, vec3, vec3", + Arguments = { name = "String", size = "vec3", position = "vec3" }, Documentation = "Creates a clipping box for the Gaia renderable in the first argument" }, { Name = "removeClippingBox", - Arguments = "", + Arguments = {}, Documentation = "" }, { Name = "addClippingSphere", - Arguments = "string, float", + Arguments = { name = "String", radius = "Number" }, Documentation = "Creates a clipping sphere for the Gaia renderable in the first argument" }, { Name = "removeClippingBox", - Arguments = "", + Arguments = {}, Documentation = "" } } @@ -104,4 +104,4 @@ openspace.gaia.removeClippingSphere = function() if openspace.hasSceneGraphNode(grid_identifier) then openspace.removeSceneGraphNode(grid_identifier) end -end \ No newline at end of file +end diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index 8a39e68755..774bb2fb10 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -33,8 +33,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -45,13 +47,22 @@ #include #include #include +#include #include +#include #include +#include #include #include #include +#include +#include +#include +#include +#include #include #include +#include #include #include #include @@ -338,141 +349,6 @@ globebrowsing::cache::MemoryAwareTileCache* GlobeBrowsingModule::tileCache() { return _tileCache.get(); } -scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { - std::string listLayerGroups = layerGroupNamesList(); - - scripting::LuaLibrary res; - res.name = "globebrowsing"; - res.functions = { - { - "addLayer", - &globebrowsing::luascriptfunctions::addLayer, - "string, string, table", - "Adds a layer to the specified globe. The first argument specifies the " - "name of the scene graph node of which to add the layer. The renderable " - "of the specified scene graph node needs to be a renderable globe. " - "The second argument is the layer group which can be any of " - + listLayerGroups + ". The third argument is the dictionary defining the " - "layer." - }, - { - "deleteLayer", - &globebrowsing::luascriptfunctions::deleteLayer, - "string, string, (string, table)", - "Removes a layer from the specified globe. The first argument specifies " - "the name of the scene graph node of which to remove the layer. " - "The renderable of the specified scene graph node needs to be a " - "renderable globe. The second argument is the layer group which can be " - "any of " + listLayerGroups + ". The third argument is either the identifier " - "for the layer or a dictionary with the 'Identifier' key that is used instead" - }, - { - "getLayers", - &globebrowsing::luascriptfunctions::getLayers, - "string, string", - "Returns the list of layers for the scene graph node specified in the first " - "parameter. The second parameter specifies which layer type should be " - "queried." - }, - { - "moveLayer", - &globebrowsing::luascriptfunctions::moveLayer, - "string, string, number, number", - "Rearranges the order of a single layer on a globe. The first parameter" - "is the identifier of the globe, the second parameter specifies " - "the name of the layer group, the third parameter is the original position " - "of the layer that should be moved and the last parameter is the new " - "position in the list. The first position in the list has index 0, and the " - "last position is given by the number of layers minus one. The new position " - "may be -1 to place the layer at the top or any number bigger than the " - "number of layers to place it at the bottom." - }, - { - "goToChunk", - &globebrowsing::luascriptfunctions::goToChunk, - "void", - "Go to chunk with given index x, y, level" - }, - { - "goToGeo", - &globebrowsing::luascriptfunctions::goToGeo, - "[string], number, number, [number]", - "Go to geographic coordinates of a globe. The first (optional) argument is " - "the identifier of a scene graph node that has a RenderableGlobe attached. " - "If no globe is passed in, the current anchor will be used. " - "The second argument is latitude and the third is longitude (degrees). " - "North and East are expressed as positive angles, while South and West are " - "negative. The optional fourh argument is the altitude in meters. If no " - "altitude is provided, the altitude will be kept as the current distance to " - "the surface of the specified globe." - }, - { - // @TODO (2021-06-23, emmbr) Combine with the above function when the camera - // paths work really well close to surfaces - "flyToGeo", - &globebrowsing::luascriptfunctions::flyToGeo, - "[string], number, number, number [, bool, number]", - "Fly the camera to geographic coordinates of a globe, using the path " - "navigation system. The first (optional) argument is the identifier of a " - "scene graph node with a RenderableGlobe. If no globe is passed in, the " - "current anchor will be used. The second and third argument is latitude and " - "longitude (degrees). The fourth argument is the altitude, in meters. The " - "last two optional arguments are: a bool specifying whether the up vector " - "at the target position should be set to the globe's North vector, and a " - "duration for the motion, in seconds. Either of the two can be left out." - }, - { - "getLocalPositionFromGeo", - &globebrowsing::luascriptfunctions::getLocalPositionFromGeo, - "string, number, number, number", - "Returns a position in the local Cartesian coordinate system of the globe " - "identified by the first argument, that corresponds to the given geographic " - "coordinates: latitude, longitude and altitude (in degrees and meters). In " - "the local coordinate system, the position (0,0,0) corresponds to the " - "globe's center." - }, - { - "getGeoPositionForCamera", - &globebrowsing::luascriptfunctions::getGeoPositionForCamera, - "void", - "Get geographic coordinates of the camera position in latitude, " - "longitude, and altitude (degrees and meters)." - }, - { - "loadWMSCapabilities", - &globebrowsing::luascriptfunctions::loadWMSCapabilities, - "string, string, string", - "Loads and parses the WMS capabilities xml file from a remote server. " - "The first argument is the name of the capabilities that can be used to " - "later refer to the set of capabilities. The second argument is the " - "globe for which this server is applicable. The third argument is the " - "URL at which the capabilities file can be found." - }, - { - "removeWMSServer", - &globebrowsing::luascriptfunctions::removeWMSServer, - "string", - "Removes the WMS server identified by the first argument from the list " - "of available servers. The parameter corrsponds to the first argument in " - "the loadWMSCapabilities call that was used to load the WMS server." - }, - { - "capabilitiesWMS", - &globebrowsing::luascriptfunctions::capabilities, - "string", - "Returns an array of tables that describe the available layers that are " - "supported by the WMS server identified by the provided name. The 'URL'" - "component of the returned table can be used in the 'FilePath' argument " - "for a call to the 'addLayer' function to add the value to a globe." - } - }; - res.scripts = { - absPath("${MODULE_GLOBEBROWSING}/scripts/layer_support.lua") - }; - - return res; -} - std::vector GlobeBrowsingModule::documentations() const { return { globebrowsing::Layer::Documentation(), @@ -821,4 +697,32 @@ uint64_t GlobeBrowsingModule::wmsCacheSize() const { return size * 1024 * 1024; } +scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const { + std::string listLayerGroups = layerGroupNamesList(); + + scripting::LuaLibrary res; + res.name = "globebrowsing"; + res.functions = { + codegen::lua::AddLayer, + codegen::lua::DeleteLayer, + codegen::lua::GetLayers, + codegen::lua::MoveLayer, + codegen::lua::GoToChunk, + codegen::lua::GoToGeo, + // @TODO (2021-06-23, emmbr) Combine with the above function when the camera + // paths work really well close to surfaces + codegen::lua::FlyToGeo, + codegen::lua::GetLocalPositionFromGeo, + codegen::lua::GetGeoPositionForCamera, + codegen::lua::LoadWMSCapabilities, + codegen::lua::RemoveWMSServer, + codegen::lua::Capabilities + }; + res.scripts = { + absPath("${MODULE_GLOBEBROWSING}/scripts/layer_support.lua") + }; + + return res; +} + } // namespace openspace diff --git a/modules/globebrowsing/globebrowsingmodule_lua.inl b/modules/globebrowsing/globebrowsingmodule_lua.inl index 5818a34b3a..045e3b8ec9 100644 --- a/modules/globebrowsing/globebrowsingmodule_lua.inl +++ b/modules/globebrowsing/globebrowsingmodule_lua.inl @@ -22,89 +22,78 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace openspace::globebrowsing::luascriptfunctions { +namespace { /** - * Adds a layer to the specified globe. + * Adds a layer to the specified globe. The first argument specifies the name of the scene + * graph node of which to add the layer. The renderable of the specified scene graph node + * needs to be a renderable globe. The second argument is the layer group which can be any + * of the supported layer groups. The third argument is the dictionary defining the layer. */ -int addLayer(lua_State* L) { - ZoneScoped - - ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::addLayer"); - auto [globeName, layerGroupName, layerDict] = - ghoul::lua::values(L); +[[codegen::luawrap]] void addLayer(std::string globeName, std::string layerGroupName, + ghoul::Dictionary layer) +{ + using namespace openspace; + using namespace globebrowsing; // Get the node and make sure it exists SceneGraphNode* n = global::renderEngine->scene()->sceneGraphNode(globeName); if (!n) { - return ghoul::lua::luaError(L, "Unknown globe name: " + globeName); + throw ghoul::lua::LuaError("Unknown globe name: " + globeName); } // Get the renderable globe RenderableGlobe* globe = dynamic_cast(n->renderable()); if (!globe) { - return ghoul::lua::luaError(L, "Renderable is not a globe: " + globeName); + throw ghoul::lua::LuaError("Renderable is not a globe: " + globeName); } // Get the layer group layergroupid::GroupID groupID = ghoul::from_string( layerGroupName - ); + ); if (groupID == layergroupid::GroupID::Unknown) { - return ghoul::lua::luaError(L, "Unknown layer group: " + layerGroupName); + throw ghoul::lua::LuaError("Unknown layer group: " + layerGroupName); } // Get the dictionary defining the layer - Layer* layer = globe->layerManager().addLayer(groupID, layerDict); - if (layer) { - layer->initialize(); + Layer* l = globe->layerManager().addLayer(groupID, layer); + if (l) { + l->initialize(); } - return 0; } /** - * Deletes a layer from the specified globe. + * Removes a layer from the specified globe. The first argument specifies the name of the + * scene graph node of which to remove the layer. The renderable of the specified scene + * graph node needs to be a renderable globe. The second argument is the layer group which + * can be any of the supported layer groups. The third argument is either the identifier + * for the layer or a dictionary with the 'Identifier' key that is used instead. */ -int deleteLayer(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::deleteLayer"); - auto [globeName, layerGroupName, layerOrName] = ghoul::lua::values< - std::string, std::string, std::variant - >(L); +[[codegen::luawrap]] void deleteLayer(std::string globeName, std::string layerGroupName, + std::variant layerOrName) +{ + using namespace openspace; + using namespace globebrowsing; // Get the node and make sure it exists SceneGraphNode* n = global::renderEngine->scene()->sceneGraphNode(globeName); if (!n) { - return ghoul::lua::luaError(L, "Unknown globe name: " + globeName); + throw ghoul::lua::LuaError("Unknown globe name: " + globeName); } // Get the renderable globe RenderableGlobe* globe = dynamic_cast(n->renderable()); if (!globe) { - return ghoul::lua::luaError(L, "Renderable is not a globe: " + globeName); + throw ghoul::lua::LuaError("Renderable is not a globe: " + globeName); } // Get the layer group layergroupid::GroupID groupID = ghoul::from_string( layerGroupName - ); + ); if (groupID == layergroupid::GroupID::Unknown) { - return ghoul::lua::luaError(L, "Unknown layer group: " + layerGroupName); + throw ghoul::lua::LuaError("Unknown layer group: " + layerGroupName); } std::string layerName; @@ -112,15 +101,9 @@ int deleteLayer(lua_State* L) { layerName = std::get(layerOrName); } else { - ghoul_assert( - std::holds_alternative(layerOrName), - "Missing case" - ); - ghoul::Dictionary d = std::get(layerOrName); if (!d.hasValue("Identifier")) { - return ghoul::lua::luaError( - L, + throw ghoul::lua::LuaError( "Table passed to deleteLayer does not contain an Identifier" ); } @@ -128,131 +111,144 @@ int deleteLayer(lua_State* L) { } globe->layerManager().deleteLayer(groupID, layerName); - return 0; } -int getLayers(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::getLayers"); - auto [globeIdentifier, layer] = ghoul::lua::values(L); +/** + * Returns the list of layers for the scene graph node specified in the first parameter. + * The second parameter specifies which layer type should be queried. + */ +[[codegen::luawrap]] std::vector getLayers(std::string globeIdentifier, + std::string layer) +{ + using namespace openspace; + using namespace globebrowsing; SceneGraphNode* n = sceneGraphNode(globeIdentifier); if (!n) { - return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier); + throw ghoul::lua::LuaError("Unknown globe name: " + globeIdentifier); } const RenderableGlobe* globe = dynamic_cast(n->renderable()); if (!globe) { - return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe"); + throw ghoul::lua::LuaError("Identifier must be a RenderableGlobe"); } globebrowsing::layergroupid::GroupID group = ghoul::from_string(layer); if (group == globebrowsing::layergroupid::GroupID::Unknown) { - return ghoul::lua::luaError(L, "Unknown layer groupd: " + layer); + throw ghoul::lua::LuaError("Unknown layer groupd: " + layer); } const globebrowsing::LayerGroup& lg = globe->layerManager().layerGroup(group); std::vector layers = lg.layers(); - lua_newtable(L); - int key = 1; + std::vector res; + res.reserve(layers.size()); for (globebrowsing::Layer* l : layers) { - ghoul::lua::push(L, key, l->identifier()); - lua_settable(L, -3); - key++; + res.push_back(l->identifier()); } - return 1; + return res; } -int moveLayer(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::moveLayer"); - auto [globeIdentifier, layer, oldPosition, newPosition] = - ghoul::lua::values(L); +/** + * Rearranges the order of a single layer on a globe. The first parameter is the + * identifier of the globe, the second parameter specifies the name of the layer group, + * the third parameter is the original position of the layer that should be moved and the + * last parameter is the new position in the list. The first position in the list has + * index 0, and the last position is given by the number of layers minus one. The new + * position may be -1 to place the layer at the top or any number bigger than the number + * of layers to place it at the bottom. + */ +[[codegen::luawrap]] void moveLayer(std::string globeIdentifier, std::string layer, + int oldPosition, int newPosition) +{ + using namespace openspace; + using namespace globebrowsing; if (oldPosition == newPosition) { - return 0; + return; } SceneGraphNode* n = sceneGraphNode(globeIdentifier); if (!n) { - return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier); + throw ghoul::lua::LuaError("Unknown globe name: " + globeIdentifier); } RenderableGlobe* globe = dynamic_cast(n->renderable()); if (!globe) { - return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe"); + throw ghoul::lua::LuaError("Identifier must be a RenderableGlobe"); } globebrowsing::layergroupid::GroupID group = ghoul::from_string(layer); if (group == globebrowsing::layergroupid::GroupID::Unknown) { - return ghoul::lua::luaError(L, "Unknown layer groupd: " + layer); + throw ghoul::lua::LuaError("Unknown layer groupd: " + layer); } globebrowsing::LayerGroup& lg = globe->layerManager().layerGroup(group); lg.moveLayer(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); +/** + * Go to the chunk on a globe with given index x, y, level. + */ +[[codegen::luawrap]] void goToChunk(std::string identifier, int x, int y, int level) { + using namespace openspace; + using namespace globebrowsing; SceneGraphNode* n = sceneGraphNode(identifier); if (!n) { - return ghoul::lua::luaError(L, "Unknown globe name: " + identifier); + throw ghoul::lua::LuaError("Unknown globe name: " + identifier); } const RenderableGlobe* globe = dynamic_cast(n->renderable()); if (!globe) { - return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe"); + throw ghoul::lua::LuaError("Identifier must be a RenderableGlobe"); } global::moduleEngine->module()->goToChunk(*globe, x, y, level); - return 0; } -int goToGeo(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::goToGeo"); +/** + * Go to geographic coordinates of a globe. The first (optional) argument is the + * identifier of a scene graph node that has a RenderableGlobe attached. If no globe is + * passed in, the current anchor will be used. The second argument is latitude and the + * third is longitude (degrees). North and East are expressed as positive angles, while + * South and West are negative. The optional fourh argument is the altitude in meters. If + * no altitude is provided, the altitude will be kept as the current distance to the + * surface of the specified globe. + */ +[[codegen::luawrap]] void goToGeo(std::optional globe, double latitude, + double longitude, std::optional altitude) +{ + using namespace openspace; + using namespace globebrowsing; - // 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 SceneGraphNode* n; - if (providedGlobeIdentifier) { - const std::string& globeIdentifier = ghoul::lua::value(L); - n = sceneGraphNode(globeIdentifier); + if (globe.has_value()) { + n = sceneGraphNode(*globe); if (!n) { - return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier); + throw ghoul::lua::LuaError("Unknown globe name: " + *globe); } } else { n = global::navigationHandler->orbitalNavigator().anchorNode(); if (!n) { - return ghoul::lua::luaError(L, "No anchor node is set."); + throw ghoul::lua::LuaError("No anchor node is set."); } } - auto [latitude, longitude, altitude] = - ghoul::lua::values>(L); - - const RenderableGlobe* globe = dynamic_cast(n->renderable()); - if (!globe) { - if (providedGlobeIdentifier) { - 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" - ); - } + const RenderableGlobe* gl = dynamic_cast(n->renderable()); + if (!gl) { + throw ghoul::lua::LuaError( + "Current anchor node is not a RenderableGlobe. Either change the anchor " + "to a globe, or specify a globe identifier as the first argument" + ); } if (altitude.has_value()) { global::moduleEngine->module()->goToGeo( - *globe, + *gl, latitude, longitude, *altitude @@ -260,63 +256,52 @@ int goToGeo(lua_State* L) { } else { global::moduleEngine->module()->goToGeo( - *globe, + *gl, latitude, longitude ); } - return 0; } -int flyToGeo(lua_State* L) { - int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 3, 6 }, "lua::flyToGeo"); - - // 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; +/** + * Fly the camera to geographic coordinates of a globe, using the path navigation system. + * The first (optional) argument is the identifier of a scene graph node with a + * RenderableGlobe. If no globe is passed in, the current anchor will be used. The second + * and third argument is latitude and longitude (degrees). The fourth argument is the + * altitude, in meters. The last two optional arguments are: a bool specifying whether the + * up vector at the target position should be set to the globe's North vector, and a + * duration for the motion, in seconds. Either of the two can be left out. + */ +[[codegen::luawrap]] void flyToGeo(std::optional globe, double latitude, + double longitude, double altitude, + std::optional duration, + std::optional shouldUseUpVector) +{ + using namespace openspace; + using namespace globebrowsing; const SceneGraphNode* n; - if (providedGlobeIdentifier) { - const std::string& globeIdentifier = - ghoul::lua::value(L, 1, ghoul::lua::PopValue::No); - n = sceneGraphNode(globeIdentifier); + if (globe.has_value()) { + n = sceneGraphNode(*globe); if (!n) { - return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier); + throw ghoul::lua::LuaError("Unknown globe name: " + *globe); } } else { n = global::navigationHandler->orbitalNavigator().anchorNode(); if (!n) { - return ghoul::lua::luaError(L, "No anchor node is set."); + throw ghoul::lua::LuaError("No anchor node is set."); } } - const RenderableGlobe* globe = dynamic_cast(n->renderable()); - if (!globe) { - if (providedGlobeIdentifier) { - 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" - ); - } + const RenderableGlobe* gl = dynamic_cast(n->renderable()); + if (!gl) { + throw ghoul::lua::LuaError("Current anchor node is not a RenderableGlobe"); } - 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(); const glm::dvec3 positionModelCoords = module->cartesianCoordinatesFromGeo( - *globe, + *gl, latitude, longitude, altitude @@ -324,12 +309,12 @@ int flyToGeo(lua_State* L) { const glm::dvec3 currentPosW = global::navigationHandler->camera()->positionVec3(); const glm::dvec3 currentPosModelCoords = - glm::inverse(globe->modelTransform()) * glm::dvec4(currentPosW, 1.0); + glm::inverse(gl->modelTransform()) * glm::dvec4(currentPosW, 1.0); constexpr const double LengthEpsilon = 10.0; // meters if (glm::distance(currentPosModelCoords, positionModelCoords) < LengthEpsilon) { LINFOC("GlobeBrowsing", "flyToGeo: Already at the requested position"); - return 0; + return; } ghoul::Dictionary instruction; @@ -338,83 +323,63 @@ int flyToGeo(lua_State* L) { instruction.setValue("Position", positionModelCoords); instruction.setValue("PathType", std::string("ZoomOutOverview")); - // Handle the two optional arguments: duration and use target's up direction argument - // The user can either provide both, or one of them - if (nArguments >= parameterOffset + 4) { - const int firstLocation = parameterOffset + 4; - const bool firstIsNumber = (lua_isnumber(L, firstLocation) != 0); - const bool firstIsBool = (lua_isboolean(L, firstLocation) != 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 #{} ({})", firstLocation, msg) - ); + if (duration.has_value()) { + constexpr const double Epsilon = 1e-5; + if (*duration <= Epsilon) { + throw ghoul::lua::LuaError("Duration must be larger than zero"); } + instruction.setValue("Duration", *duration); + } - int location = firstLocation; - if (firstIsBool) { - const bool useUpFromTarget = (lua_toboolean(L, location) == 1); - instruction.setValue("UseTargetUpDirection", useUpFromTarget); + if (shouldUseUpVector.has_value()) { + instruction.setValue("UseTargetUpDirection", *shouldUseUpVector); - if (nArguments > location) { - location++; - } - } - - if (firstIsNumber || nArguments > firstLocation) { - 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"); - } - instruction.setValue("Duration", duration); - } } global::navigationHandler->pathNavigator().createPath(instruction); global::navigationHandler->pathNavigator().startPath(); - - lua_settop(L, 0); - - ghoul_assert(lua_gettop(L) == 0, "Incorrect number of items left on stack"); - return 0; } -int getLocalPositionFromGeo(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::getLocalPositionFromGeo"); - auto [globeIdentifier, latitude, longitude, altitude] = - ghoul::lua::values(L); - +/** + * Returns a position in the local Cartesian coordinate system of the globe identified by + * the first argument, that corresponds to the given geographic coordinates: latitude, + * longitude and altitude (in degrees and meters). In the local coordinate system, the + * position (0,0,0) corresponds to the globe's center. + */ +[[codegen::luawrap]] +std::tuple +getLocalPositionFromGeo(std::string globeIdentifier, double latitude, double longitude, + double altitude) +{ + using namespace openspace; + using namespace globebrowsing; + SceneGraphNode* n = sceneGraphNode(globeIdentifier); if (!n) { - return ghoul::lua::luaError(L, "Unknown globe identifier: " + globeIdentifier); + throw ghoul::lua::LuaError("Unknown globe identifier: " + globeIdentifier); } const RenderableGlobe* globe = dynamic_cast(n->renderable()); if (!globe) { - return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe"); + throw ghoul::lua::LuaError("Identifier must be a RenderableGlobe"); } GlobeBrowsingModule& mod = *(global::moduleEngine->module()); glm::vec3 p = mod.cartesianCoordinatesFromGeo(*globe, latitude, longitude, altitude); - ghoul::lua::push(L, p.x, p.y, p.z); - return 3; + return { p.x, p.y, p.z }; } -int getGeoPositionForCamera(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::getGeoPositionForCamera"); +/** + * Get geographic coordinates of the camera position in latitude, longitude, and altitude + * (degrees and meters). + */ +[[codegen::luawrap]] std::tuple getGeoPositionForCamera() { + using namespace openspace; + using namespace globebrowsing; GlobeBrowsingModule* module = global::moduleEngine->module(); const RenderableGlobe* globe = module->castFocusNodeRenderableToGlobe(); if (!globe) { - return ghoul::lua::luaError(L, "Focus node must be a RenderableGlobe"); + throw ghoul::lua::LuaError("Focus node must be a RenderableGlobe"); } const glm::dvec3 cameraPosition = global::navigationHandler->camera()->positionVec3(); @@ -430,53 +395,66 @@ int getGeoPositionForCamera(lua_State* L) { const Geodetic2 geo2 = globe->ellipsoid().cartesianToGeodetic2( posHandle.centerToReferenceSurface ); - const double altitude = glm::length(cameraPositionModelSpace - - posHandle.centerToReferenceSurface); + const double altitude = glm::length( + cameraPositionModelSpace - posHandle.centerToReferenceSurface + ); - ghoul::lua::push(L, glm::degrees(geo2.lat), glm::degrees(geo2.lon), altitude); - return 3; + return { glm::degrees(geo2.lat), glm::degrees(geo2.lon), altitude }; } -int loadWMSCapabilities(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::loadWMSCapabilities"); - auto [name, globe, url] = - ghoul::lua::values(L); - +/** + * Loads and parses the WMS capabilities xml file from a remote server. The first argument + * is the name of the capabilities that can be used to later refer to the set of + * capabilities. The second argument is the globe for which this server is applicable. The + * third argument is the URL at which the capabilities file can be found. + */ +[[codegen::luawrap]] void loadWMSCapabilities(std::string name, std::string globe, + std::string url) +{ + using namespace openspace; + using namespace globebrowsing; global::moduleEngine->module()->loadWMSCapabilities( std::move(name), std::move(globe), std::move(url) ); - return 0; } -int removeWMSServer(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::removeWMSServer"); - const std::string name = ghoul::lua::value(L); - +/** + * Removes the WMS server identified by the first argument from the list of available + * servers. The parameter corrsponds to the first argument in the loadWMSCapabilities call + * that was used to load the WMS server. + */ +[[codegen::luawrap]] void removeWMSServer(std::string name) { + using namespace openspace; + using namespace globebrowsing; global::moduleEngine->module()->removeWMSServer(name); - return 0; } -int capabilities(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::capabilities"); - const std::string name = ghoul::lua::value(L); +/** + * Returns an array of tables that describe the available layers that are supported by the + * WMS server identified by the provided name. The 'URL' component of the returned table + * can be used in the 'FilePath' argument for a call to the 'addLayer' function to add the + * value to a globe. + */ +[[codegen::luawrap]] std::vector capabilities(std::string name) { + using namespace openspace; + using namespace globebrowsing; GlobeBrowsingModule::Capabilities cap = global::moduleEngine->module()->capabilities(name); - lua_newtable(L); + std::vector res; + res.reserve(cap.size()); 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::Dictionary c; + c.setValue("Name", cap[i].name); + c.setValue("URL", cap[i].url); + res.push_back(c); } - return 1; + return res; } -} // namespace openspace::globebrowsing::luascriptfunctions +#include "globebrowsingmodule_lua_codegen.cpp" + +} // namespace diff --git a/modules/globebrowsing/scripts/layer_support.lua b/modules/globebrowsing/scripts/layer_support.lua index 8f2d50bc29..d9c89cc383 100644 --- a/modules/globebrowsing/scripts/layer_support.lua +++ b/modules/globebrowsing/scripts/layer_support.lua @@ -1,7 +1,7 @@ openspace.globebrowsing.documentation = { { Name = "createTemporalGibsGdalXml", - Arguments = "string, string, string", + Arguments = { layerName = "String", resolution = "String", format = "String" }, Documentation = [[ Creates an XML configuration for a temporal GIBS dataset to be used in a TemporalTileprovider @@ -9,7 +9,7 @@ openspace.globebrowsing.documentation = { }, { Name = "createGibsGdalXml", - Arguments = "string, string, string, string", + Arguments = { layerName = "String", date = "String", resolution = "String", format = "String" }, Documentation = "Creates an XML configuration for a GIBS dataset." .. "Arguments are: layerName, date, resolution, format." .. @@ -32,7 +32,7 @@ openspace.globebrowsing.documentation = { }, { Name = "addGibsLayer", - Arguments = "string, string, string, string, string", + Arguments = { layer = "String", resolution = "String", format = "String", startDate = "String", endDate = "String" }, Documentation = "Adds a new layer from NASA GIBS to the Earth globe. Arguments " .. "are: imagery layer name, imagery resolution, start date, end date, format. " .. "For all specifications, see " .. @@ -42,7 +42,7 @@ openspace.globebrowsing.documentation = { }, { Name = "parseInfoFile", - Arguments = "string", + Arguments = { file = "String" }, Documentation = "Parses the passed info file and return the table with the information " .. "provided in the info file. The return table contains the optional keys: " .. @@ -53,7 +53,7 @@ openspace.globebrowsing.documentation = { }, { Name = "addBlendingLayersFromDirectory", - Arguments = "string, string", + Arguments = { directory = "String", nodeName = "String" }, Documentation = "Retrieves all info files recursively in the directory passed as the first " .. "argument to this function. The color and height tables retrieved from these " .. @@ -63,7 +63,7 @@ openspace.globebrowsing.documentation = { }, { Name = "addFocusNodesFromDirectory", - Arguments = "string, string", + Arguments = { directory = "String", nodeName = "String" }, Documentation = "Retrieves all info files recursively in the directory passed as the first " .. "argument to this function. The name and location retrieved from these info " .. @@ -73,7 +73,7 @@ openspace.globebrowsing.documentation = { }, { Name = "addFocusNodeFromLatLong", - Arguments = "string, string, number, number, number", + Arguments = { name = "String", globeIdentifier = "String", latitude = "Number", longitude = "Number", altitude = "Number" }, Documentation = "Creates a new SceneGraphNode that can be used as focus node. " .. "Usage: openspace.globebrowsing.addFocusNodeFromLatLong(" .. @@ -81,7 +81,7 @@ openspace.globebrowsing.documentation = { }, { Name = "loadWMSServersFromFile", - Arguments = "string", + Arguments = { filePath = "String" }, Documentation = "Loads all WMS servers from the provided file and passes them to the " .. "'openspace.globebrowsing.loadWMSCapabilities' file." diff --git a/modules/globebrowsing/src/tileprovider/spoutimageprovider.cpp b/modules/globebrowsing/src/tileprovider/spoutimageprovider.cpp index 31826e9358..a85c065445 100644 --- a/modules/globebrowsing/src/tileprovider/spoutimageprovider.cpp +++ b/modules/globebrowsing/src/tileprovider/spoutimageprovider.cpp @@ -186,6 +186,7 @@ TileDepthTransform SpoutImageProvider::depthTransform() { } void SpoutImageProvider::update() { +#ifdef OPENSPACE_HAS_SPOUT if (!spoutUpdate) { return; } @@ -198,10 +199,13 @@ void SpoutImageProvider::update() { } spoutReceiver->updateReceiver(); +#endif // OPENSPACE_HAS_SPOUT } void SpoutImageProvider::reset() { +#ifdef OPENSPACE_HAS_SPOUT spoutReceiver->updateReceiver(); +#endif // OPENSPACE_HAS_SPOUT } int SpoutImageProvider::minLevel() { diff --git a/modules/iswa/util/iswamanager.cpp b/modules/iswa/util/iswamanager.cpp index 29cc009743..86d32542e4 100644 --- a/modules/iswa/util/iswamanager.cpp +++ b/modules/iswa/util/iswamanager.cpp @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include #include @@ -753,54 +755,14 @@ scripting::LuaLibrary IswaManager::luaLibrary() { return { "iswa", { - { - "addCygnet", - &luascriptfunctions::iswa_addCygnet, - "int, string, string", - "Adds a IswaCygnet", - }, - { - "addScreenSpaceCygnet", - &luascriptfunctions::iswa_addScreenSpaceCygnet, - "int, string, string", - "Adds a Screen Space Cygnets", - }, - { - "addKameleonPlanes", - &luascriptfunctions::iswa_addKameleonPlanes, - "string, int", - "Adds KameleonPlanes from cdf file.", - }, - { - "addCdfFiles", - &luascriptfunctions::iswa_addCdfFiles, - "string", - "Adds a cdf files to choose from.", - }, - { - "removeCygnet", - &luascriptfunctions::iswa_removeCygnet, - "string", - "Remove a Cygnets", - }, - { - "removeScreenSpaceCygnet", - &luascriptfunctions::iswa_removeScrenSpaceCygnet, - "int", - "Remove a Screen Space Cygnets", - }, - { - "removeGroup", - &luascriptfunctions::iswa_removeGroup, - "int", - "Remove a group of Cygnets", - }, - { - "setBaseUrl", - &luascriptfunctions::iswa_setBaseUrl, - "string", - "sets the base url", - } + codegen::lua::AddCygnet, + codegen::lua::AddScreenSpaceCygnet, + codegen::lua::RemoveCygnet, + codegen::lua::RemoveScreenSpaceCygnet, + codegen::lua::RemoveGroup, + codegen::lua::AddCdfFiles, + codegen::lua::AddKameleonPlanes, + codegen::lua::SetBaseUrl } }; } diff --git a/modules/iswa/util/iswamanager_lua.inl b/modules/iswa/util/iswamanager_lua.inl index 93d5465c98..8e3f2c2ac7 100644 --- a/modules/iswa/util/iswamanager_lua.inl +++ b/modules/iswa/util/iswamanager_lua.inl @@ -22,63 +22,26 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include -#include -#include +namespace { -namespace openspace::luascriptfunctions { - -int iswa_addCygnet(lua_State* L) { - int nArguments = lua_gettop(L); - - int id = -1; - std::string type = "Texture"; - std::string group = ""; - - if (nArguments > 0) { - id = static_cast(lua_tonumber(L, 1)); - } - - if (nArguments > 1) { - type = luaL_checkstring(L, 2); - } - - if (nArguments > 2) { - group = luaL_checkstring(L, 3); - } - - IswaManager::ref().addIswaCygnet(id, type, group); - - return 0; +// Adds a IswaCygnet. +[[codegen::luawrap]] void addCygnet(int id = -1, std::string type = "Texture", + std::string group = "") +{ + openspace::IswaManager::ref().addIswaCygnet(id, type, group); } -int iswa_addScreenSpaceCygnet(lua_State* L) { - static const std::string _loggerCat = "addScreenSpaceCygnet"; - using ghoul::lua::errorLocation; - - int nArguments = lua_gettop(L); - if (nArguments != 1) { - return ghoul::lua::luaError(L, fmt::format( - "Expected {} argumemts, got {}", 1, nArguments - )); - } - - ghoul::Dictionary d; - try { - ghoul::lua::luaDictionaryFromState(L, d); - } - catch (const ghoul::lua::LuaFormatException& e) { - LERROR(e.what()); - return 0; - } +// Adds a Screen Space Cygnets. +[[codegen::luawrap]] void addScreenSpaceCygnet(ghoul::Dictionary d) { + using namespace openspace; int id = static_cast(d.value("CygnetId")); - std::map> cygnetInformation = IswaManager::ref().cygnetInformation(); if (cygnetInformation.find(id) == cygnetInformation.end()) { - LWARNING("Could not find Cygnet with id = " + std::to_string(id)); - return 0; + throw ghoul::lua::LuaError( + "Could not find Cygnet with id = " + std::to_string(id) + ); } std::shared_ptr info = cygnetInformation[id]; @@ -87,8 +50,9 @@ int iswa_addScreenSpaceCygnet(lua_State* L) { info->selected = true; if (global::renderEngine->screenSpaceRenderable(name)) { - LERROR("A cygnet with the name \"" + name +"\" already exist"); - return 0; + throw ghoul::lua::LuaError(fmt::format( + "A cygnet with the name \"{}\" already exist", name + )); } else { d.setValue("Name", name); @@ -100,99 +64,68 @@ int iswa_addScreenSpaceCygnet(lua_State* L) { ); global::renderEngine->addScreenSpaceRenderable(std::move(s)); } - return 0; } -// int iswa_addKameleonPlane(lua_State* L){ -// int nArguments = lua_gettop(L); - -// std::string kwPath = ""; -// std::string type = "x"; -// std::string group = ""; - -// if (nArguments > 0) { -// kwPath = luaL_checkstring(L, 1); -// } - -// if (nArguments > 1) { -// type = luaL_checkstring(L, 2); -// } - -// if (nArguments > 2) { -// group = luaL_checkstring(L, 3); -// } - -// IswaManager::ref().createKameleonPlane(kwPath, type, group); -// return 0; -// } - -int iswa_removeCygnet(lua_State* L) { - std::string name = luaL_checkstring(L, -1); +// Remove a Cygnets. +[[codegen::luawrap]] void removeCygnet(std::string name) { + using namespace openspace; global::scriptEngine->queueScript( "openspace.removeSceneGraphNode('" + name + "')", scripting::ScriptEngine::RemoteScripting::Yes ); - // IswaManager::ref().deleteIswaCygnet(s); - return 0; } -int iswa_removeScrenSpaceCygnet(lua_State* L) { - static const std::string _loggerCat = "removeScreenSpaceCygnet"; - - int id = static_cast(lua_tonumber(L, 1)); - +// Remove a Screen Space Cygnets. +[[codegen::luawrap]] void removeScreenSpaceCygnet(int id) { + using namespace openspace; + std::map> cygnetInformation = IswaManager::ref().cygnetInformation(); if (cygnetInformation.find(id) == cygnetInformation.end()) { - LWARNING("Could not find Cygnet with id = " + std::to_string(id)); - return 0; + throw ghoul::lua::LuaError( + "Could not find Cygnet with id = " + std::to_string(id) + ); } std::shared_ptr info = cygnetInformation[id]; info->selected = false; - std::string script = - "openspace.unregisterScreenSpaceRenderable('" + - cygnetInformation[id]->name + "');"; + std::string script = fmt::format( + "openspace.unregisterScreenSpaceRenderable('{}');", cygnetInformation[id]->name + ); global::scriptEngine->queueScript( script, scripting::ScriptEngine::RemoteScripting::Yes ); - return 0; } -int iswa_removeGroup(lua_State* L) { - std::string name = luaL_checkstring(L, -1); - // IswaManager::ref().unregisterGroup(id); - +// Remove a group of Cygnets. +[[codegen::luawrap]] void removeGroup(std::string name) { + using namespace openspace; + std::map> groups = IswaManager::ref().groups(); if (groups.find(name) != groups.end()) { groups[name]->clearGroup(); } - - return 0; } -int iswa_addCdfFiles(lua_State* L) { - std::string path = luaL_checkstring(L, 1); - IswaManager::ref().addCdfFiles(path); - - return 0; +// Adds a cdf files to choose from. +[[codegen::luawrap]] void addCdfFiles(std::string path) { + openspace::IswaManager::ref().addCdfFiles(path); } -int iswa_addKameleonPlanes(lua_State* L) { - std::string group = luaL_checkstring(L, 1); - int pos = static_cast(lua_tonumber(L, 2)); - IswaManager::ref().addKameleonCdf(group, pos); - return 0; +// Adds KameleonPlanes from cdf file. +[[codegen::luawrap]] void addKameleonPlanes(std::string group, int pos) { + openspace::IswaManager::ref().addKameleonCdf(group, pos); } -int iswa_setBaseUrl(lua_State* L) { - std::string url = luaL_checkstring(L, 1); - IswaManager::ref().setBaseUrl(url); - return 0; +// Sets the base url. +[[codegen::luawrap]] void setBaseUrl(std::string url) { + openspace::IswaManager::ref().setBaseUrl(url); } -} // namespace openspace::luascriptfunctions +#include "iswamanager_lua_codegen.cpp" + +} // namespace diff --git a/modules/space/spacemodule.cpp b/modules/space/spacemodule.cpp index 52167897b0..f73711b250 100644 --- a/modules/space/spacemodule.cpp +++ b/modules/space/spacemodule.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -140,28 +141,13 @@ std::vector SpaceModule::documentations() const { } scripting::LuaLibrary SpaceModule::luaLibrary() const { - scripting::LuaLibrary res; - res.name = "space"; - res.functions = { + return { + "space", { - "convertFromRaDec", - &space::luascriptfunctions::convertFromRaDec, - "string/double, string/double, double", - "Returns the cartesian world position of a ra dec coordinate with distance. " - "If the coordinate is given as strings the format should be ra 'XhYmZs' and " - "dec 'XdYmZs'. If the coordinate is given as numbers the values should be " - "in degrees." - }, - { - "convertToRaDec", - &space::luascriptfunctions::convertToRaDec, - "double, double, double", - "Returns the formatted ra, dec strings and distance for a given cartesian " - "world coordinate." + codegen::lua::ConvertFromRaDec, + codegen::lua::ConvertToRaDec } }; - - return res; } } // namespace openspace diff --git a/modules/space/spacemodule_lua.inl b/modules/space/spacemodule_lua.inl index dd2ebfe57a..c83cf8209d 100644 --- a/modules/space/spacemodule_lua.inl +++ b/modules/space/spacemodule_lua.inl @@ -22,47 +22,61 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include +namespace { -namespace openspace::space::luascriptfunctions { - -int convertFromRaDec(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::convertFromRaDec"); +/** + * Returns the cartesian world position of a ra dec coordinate with distance. If the + * coordinate is given as strings the format should be ra 'XhYmZs' and dec 'XdYmZs'. If + * the coordinate is given as numbers the values should be in degrees. + */ +[[codegen::luawrap]] glm::dvec3 convertFromRaDec( + std::variant rightAscension, + std::variant declination, + double distance) +{ + using namespace openspace; glm::dvec2 degrees = glm::dvec2(0.0); - if (ghoul::lua::hasValue(L, 1) && - ghoul::lua::hasValue(L, 2)) + if (std::holds_alternative(rightAscension) && + std::holds_alternative(declination)) { - auto [ra, dec] = ghoul::lua::values(L); - degrees = icrsToDecimalDegrees(ra, dec); + degrees = glm::dvec2( + std::get(rightAscension), + std::get(declination) + ); } - 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 if (std::holds_alternative(rightAscension) && + std::holds_alternative(declination)) + { + degrees = icrsToDecimalDegrees( + std::get(rightAscension), + std::get(declination) + ); } else { - throw ghoul::lua::LuaRuntimeException( + throw ghoul::lua::LuaError( "Ra and Dec have to be of the same type, either String or Number" ); } - double distance = ghoul::lua::value(L); glm::dvec3 pos = icrsToGalacticCartesian(degrees.x, degrees.y, distance); - ghoul::lua::push(L, pos); - return 1; + return pos; } -int convertToRaDec(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 3, "lua::convertToRaDec"); - auto [x, y, z] = ghoul::lua::values(L); - +/** + * Returns the formatted ra, dec strings and distance for a given cartesian world + * coordinate. + */ +[[codegen::luawrap]] std::tuple convertToRaDec(double x, + double y, + double z) +{ + using namespace openspace; glm::dvec3 deg = galacticCartesianToIcrs(x, y, z); std::pair raDecPair = decimalDegreesToIcrs(deg.x, deg.y); - - // Ra, Dec, Distance - ghoul::lua::push(L, raDecPair.first, raDecPair.second, deg.z); - return 3; + return { raDecPair.first, raDecPair.second, deg.z }; } -} // namespace openspace::space::luascriptfunctions +#include "spacemodule_lua_codegen.cpp" + +} // namespace diff --git a/modules/statemachine/statemachinemodule.cpp b/modules/statemachine/statemachinemodule.cpp index 3a3737cc11..e6854ebd3c 100644 --- a/modules/statemachine/statemachinemodule.cpp +++ b/modules/statemachine/statemachinemodule.cpp @@ -28,10 +28,15 @@ #include #include #include +#include +#include #include +#include #include #include +#include #include +#include #include "statemachinemodule_lua.inl" @@ -140,78 +145,20 @@ void StateMachineModule::saveToFile(const std::string& filename, } scripting::LuaLibrary StateMachineModule::luaLibrary() const { - scripting::LuaLibrary res; - res.name = "statemachine"; - res.functions = { - { - "createStateMachine", - &luascriptfunctions::createStateMachine, - "table, table, [string]", - "Creates a state machine from a list of states and transitions. See State " - "and Transition documentation for details. The optional thrid argument is " - "the identifier of the desired initial state. If left out, the first state " - "in the list will be used." - }, + return { + "statemachine", { - "destroyStateMachine", - &luascriptfunctions::destroyStateMachine, - "", - "Destroys the current state machine and deletes all the memory." - }, - { - "goToState", - &luascriptfunctions::goToState, - "string", - "Triggers a transition from the current state to the state with the given " - "identifier. Requires that the specified string corresponds to an existing " - "state, and that a transition between the two states exists." - }, - { - "setInitialState", - &luascriptfunctions::setInitialState, - "string", - "Immediately sets the current state to the state with the given name, if " - "it exists. This is done without doing a transition and completely ignores " - "the previous state." - }, - { - "currentState", - &luascriptfunctions::currentState, - "", - "Returns the string name of the current state that the statemachine is in." - }, - { - "possibleTransitions", - &luascriptfunctions::possibleTransitions, - "", - "Returns a list with the identifiers of all the states that can be " - "transitioned to from the current state." - }, - { - "canGoToState", - &luascriptfunctions::canGoToState, - "string", - "Returns true if there is a defined transition between the current state and " - "the given string name of a state, otherwise false" - }, - { - "printCurrentStateInfo", - &luascriptfunctions::printCurrentStateInfo, - "", - "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." + codegen::lua::CreateStateMachine, + codegen::lua::DestroyStateMachine, + codegen::lua::GoToState, + codegen::lua::SetInitialState, + codegen::lua::CurrentState, + codegen::lua::PossibleTransitions, + codegen::lua::CanGoToState, + codegen::lua::PrintCurrentStateInfo, + codegen::lua::SaveToDotFile } }; - return res; } std::vector StateMachineModule::documentations() const { diff --git a/modules/statemachine/statemachinemodule_lua.inl b/modules/statemachine/statemachinemodule_lua.inl index a4888c42f4..555a47f237 100644 --- a/modules/statemachine/statemachinemodule_lua.inl +++ b/modules/statemachine/statemachinemodule_lua.inl @@ -22,90 +22,91 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include -#include -#include -#include -#include -#include -#include - -namespace openspace::luascriptfunctions { - -int createStateMachine(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, { 2, 3 }, "lua::createStateMachine"); - auto [states, transitions, startState] = ghoul::lua::values< - ghoul::Dictionary, ghoul::Dictionary, std::optional - >(L); +namespace { +/** + * Creates a state machine from a list of states and transitions. See State and Transition + * documentation for details. The optional thrid argument is the identifier of the desired + * initial state. If left out, the first state in the list will be used. + */ +[[codegen::luawrap]] void createStateMachine(ghoul::Dictionary states, + ghoul::Dictionary transitions, + std::optional startState) +{ + using namespace openspace; StateMachineModule* module = global::moduleEngine->module(); module->initializeStateMachine( std::move(states), std::move(transitions), std::move(startState) ); - return 0; } - -int destroyStateMachine(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::destroyStateMachine"); - +// Destroys the current state machine and deletes all the memory. +[[codegen::luawrap]] void destroyStateMachine() { + using namespace openspace; StateMachineModule* module = global::moduleEngine->module(); module->deinitializeStateMachine(); - return 0; } -int goToState(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::goToState"); - std::string newState = ghoul::lua::value(L); - +/** + * Triggers a transition from the current state to the state with the given identifier. + * Requires that the specified string corresponds to an existing state, and that a + * transition between the two states exists. + */ +[[codegen::luawrap]] void goToState(std::string newState) { + using namespace openspace; StateMachineModule* module = global::moduleEngine->module(); module->transitionTo(newState); LINFOC("StateMachine", "Transitioning to " + newState); - return 0; } -int setInitialState(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setStartState"); - std::string startState = ghoul::lua::value(L); - +/** + * Immediately sets the current state to the state with the given name, if it exists. This + * is done without doing a transition and completely ignores the previous state. + */ +[[codegen::luawrap]] void setInitialState(std::string startState) { + using namespace openspace; StateMachineModule* module = global::moduleEngine->module(); module->setInitialState(startState); LINFOC("StateMachine", "Initial state set to: " + startState); - return 0; } -int currentState(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::currentState"); - +// Returns the string name of the current state that the statemachine is in. +[[codegen::luawrap]] std::string currentState() { + using namespace openspace; StateMachineModule* module = global::moduleEngine->module(); std::string currentState = module->currentState(); - ghoul::lua::push(L, std::move(currentState)); - return 1; + return currentState; } -int possibleTransitions(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::possibleTransitions"); - +/** + * Returns a list with the identifiers of all the states that can be transitioned to from + * the current state. + */ +[[codegen::luawrap]] std::vector possibleTransitions() { + using namespace openspace; StateMachineModule* module = global::moduleEngine->module(); std::vector transitions = module->possibleTransitions(); - ghoul::lua::push(L, transitions); - return 1; + return transitions; } -int canGoToState(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::canGoToState"); - std::string state = ghoul::lua::value(L); - +/** + * Returns true if there is a defined transition between the current state and the given + * string name of a state, otherwise false. + */ +[[codegen::luawrap]] bool canGoToState(std::string state) { + using namespace openspace; StateMachineModule* module = global::moduleEngine->module(); - ghoul::lua::push(L, module->canGoToState(state)); - return 1; + bool canTransition = module->canGoToState(state); + return canTransition; } -int printCurrentStateInfo(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 0, "lua::printCurrentStateInfo"); - +/** + * Prints information about the current state and possible transitions to the log. + */ +[[codegen::luawrap]] void printCurrentStateInfo() { + using namespace openspace; StateMachineModule* module = global::moduleEngine->module(); if (module->hasStateMachine()) { std::string currentState = module->currentState(); @@ -119,24 +120,27 @@ int printCurrentStateInfo(lua_State* L) { else { LINFOC("StateMachine", "No state machine has been created"); } - - return 1; } -int saveToDotFile(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::saveToDotFile"); - auto [filename, directory] = - ghoul::lua::values>(L); - +/** + * 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. + */ +[[codegen::luawrap]] void saveToDotFile(std::string filename, + std::optional directory) +{ + using namespace openspace; StateMachineModule* module = global::moduleEngine->module(); - if (directory.has_value()) { module->saveToFile(filename, *directory); } else { module->saveToFile(filename); } - return 0; } -} //namespace openspace::luascriptfunctions +#include "statemachinemodule_lua_codegen.cpp" + +} // namespace diff --git a/modules/sync/syncmodule.cpp b/modules/sync/syncmodule.cpp index a9e519394b..c943b7cc18 100644 --- a/modules/sync/syncmodule.cpp +++ b/modules/sync/syncmodule.cpp @@ -27,7 +27,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -119,30 +121,13 @@ std::vector SyncModule::documentations() const { } scripting::LuaLibrary SyncModule::luaLibrary() const { - scripting::LuaLibrary res; - res.name = "sync"; - res.functions = { + return { + "sync", { - "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." + codegen::lua::SyncResource, + codegen::lua::UnsyncResource } }; - return res; } } // namespace openspace diff --git a/modules/sync/syncmodule_lua.inl b/modules/sync/syncmodule_lua.inl index df6366159e..0feb0c8ed8 100644 --- a/modules/sync/syncmodule_lua.inl +++ b/modules/sync/syncmodule_lua.inl @@ -22,14 +22,15 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#include -#include +namespace { -namespace openspace::luascriptfunctions { - -int syncResource(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::syncResource"); - auto [identifier, version] = ghoul::lua::values(L); +/** + * 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. + */ +[[codegen::luawrap]] bool syncResource(std::string identifier, int version) { + using namespace openspace; ghoul::Dictionary dict; dict.setValue("Type", std::string("HttpSynchronization")); @@ -45,14 +46,20 @@ int syncResource(lua_State* L) { std::this_thread::sleep_for(std::chrono::milliseconds(20)); } - ghoul::lua::push(L, sync->isResolved()); - return 1; + bool isResolved = sync->isResolved(); + return isResolved; } -int unsyncResource(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::unsyncResource"); - auto [identifier, version] = ghoul::lua::values>(L); - +/** + * 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. + */ +[[codegen::luawrap]] void unsyncResource(std::string identifier, std::optional version) { + using namespace openspace; + const SyncModule* module = global::moduleEngine->module(); std::filesystem::path sync = absPath(module->synchronizationRoot()); std::filesystem::path base = sync / "http" / identifier; @@ -70,8 +77,8 @@ int unsyncResource(lua_State* L) { std::filesystem::remove_all(folder); std::filesystem::remove(base / syncFile); } - - return 0; } -} // namespace openspace::luascriptfunctions +#include "syncmodule_lua_codegen.cpp" + +} // namespace diff --git a/scripts/core_scripts.lua b/scripts/core_scripts.lua index 3117b3ca6a..23bd537286 100644 --- a/scripts/core_scripts.lua +++ b/scripts/core_scripts.lua @@ -1,34 +1,34 @@ openspace.documentation = { { Name = "markInterestingNodes", - Arguments = "List of nodes", + Arguments = { sceneGraphNode = "[ String ]" }, Documentation = "This function marks the scene graph nodes identified by name " .. "as interesting, which will provide shortcut access to focus buttons and " .. "featured properties." }, { Name = "markInterestingTimes", - Arguments = "List of { Name = '...', Time = '...' } or { '', '