From 6a708b1f1870ed54e7ad0575e372e4754a73bc03 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Thu, 3 Mar 2022 23:47:09 +0100 Subject: [PATCH 01/14] Implement new Spout input methods to Tileproviders and new Renderables (#1901) * Implement new Spout input methods to Tileproviders and new Renderables Co-authored-by: Marco Silva --- apps/OpenSpace/ext/sgct | 2 +- apps/OpenSpace/main.cpp | 116 ++-- config/single_gui_spout.json | 67 ++ config/spout_output.json | 36 - config/spout_output_cubemap.json | 60 ++ config/spout_output_equirectangular.json | 60 ++ config/spout_output_fisheye.json | 60 ++ config/spout_output_flat.json | 59 ++ .../colorlayers/terra_texture_spout.asset | 18 + modules/base/rendering/renderablesphere.cpp | 9 +- modules/base/rendering/renderablesphere.h | 4 + modules/globebrowsing/CMakeLists.txt | 2 + modules/globebrowsing/globebrowsingmodule.cpp | 4 + modules/globebrowsing/include.cmake | 5 + .../shaders/texturetilemapping.glsl | 3 +- modules/globebrowsing/src/gpulayergroup.cpp | 2 + modules/globebrowsing/src/layer.cpp | 5 +- modules/globebrowsing/src/layergroupid.h | 8 +- .../src/tileprovider/defaulttileprovider.cpp | 5 + .../src/tileprovider/defaulttileprovider.h | 1 + .../imagesequencetileprovider.cpp | 4 + .../tileprovider/imagesequencetileprovider.h | 1 + .../tileprovider/singleimagetileprovider.cpp | 4 + .../tileprovider/singleimagetileprovider.h | 1 + .../sizereferencetileprovider.cpp | 4 + .../tileprovider/sizereferencetileprovider.h | 1 + .../src/tileprovider/spoutimageprovider.cpp | 219 +++++++ .../src/tileprovider/spoutimageprovider.h | 66 ++ .../src/tileprovider/temporaltileprovider.cpp | 8 + .../src/tileprovider/temporaltileprovider.h | 2 + .../tileprovider/tileindextileprovider.cpp | 4 + .../src/tileprovider/tileindextileprovider.h | 1 + .../src/tileprovider/tileprovider.cpp | 3 +- .../src/tileprovider/tileprovider.h | 6 + .../src/tileprovider/tileproviderbyindex.cpp | 4 + .../src/tileprovider/tileproviderbyindex.h | 1 + .../src/tileprovider/tileproviderbylevel.cpp | 4 + .../src/tileprovider/tileproviderbylevel.h | 1 + modules/spout/CMakeLists.txt | 4 + modules/spout/ext/spout/SpoutLibrary.h | 2 + modules/spout/renderableplanespout.cpp | 114 +--- modules/spout/renderableplanespout.h | 16 +- modules/spout/renderablespherespout.cpp | 120 ++++ modules/spout/renderablespherespout.h | 58 ++ modules/spout/screenspacespout.cpp | 118 +--- modules/spout/screenspacespout.h | 19 +- modules/spout/spoutmodule.cpp | 2 + modules/spout/spoutwrapper.cpp | 613 ++++++++++++++++++ modules/spout/spoutwrapper.h | 190 ++++++ openspace.cfg | 43 +- 50 files changed, 1792 insertions(+), 367 deletions(-) create mode 100644 config/single_gui_spout.json delete mode 100644 config/spout_output.json create mode 100644 config/spout_output_cubemap.json create mode 100644 config/spout_output_equirectangular.json create mode 100644 config/spout_output_fisheye.json create mode 100644 config/spout_output_flat.json create mode 100644 data/assets/scene/solarsystem/planets/earth/layers/colorlayers/terra_texture_spout.asset create mode 100644 modules/globebrowsing/src/tileprovider/spoutimageprovider.cpp create mode 100644 modules/globebrowsing/src/tileprovider/spoutimageprovider.h create mode 100644 modules/spout/renderablespherespout.cpp create mode 100644 modules/spout/renderablespherespout.h create mode 100644 modules/spout/spoutwrapper.cpp create mode 100644 modules/spout/spoutwrapper.h diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index 3befe6c7a0..c5288e6f1d 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit 3befe6c7a083bf11a71eab8e87101afce8049997 +Subproject commit c5288e6f1da32366b0b35e2072cd0c21eb1f7453 diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index 2b0f28996e..5857440162 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -79,7 +79,7 @@ #endif // OPENVR_SUPPORT #ifdef OPENSPACE_HAS_SPOUT -#include "SpoutLibrary.h" +#include #endif // OPENSPACE_HAS_SPOUT #ifdef OPENSPACE_HAS_NVTOOLS @@ -120,16 +120,11 @@ Window* FirstOpenVRWindow = nullptr; * the \c leftOrMain and \c right members respectively. */ struct SpoutWindow { - struct SpoutData { - SPOUTHANDLE handle = nullptr; - bool initialized = false; - }; - /// The left framebuffer (or main, if there is no stereo rendering) - SpoutData leftOrMain; + openspace::spout::SpoutSender leftOrMain; /// The right framebuffer - SpoutData right; + openspace::spout::SpoutSender right; /// The window ID of this windows size_t windowId = size_t(-1); @@ -291,41 +286,33 @@ void mainInitFunc(GLFWwindow*) { #ifdef OPENSPACE_HAS_SPOUT SpoutWindow w; - - w.windowId = i; + bool retValue = true; + std::string mainWindowName = window.name(); const Window::StereoMode sm = window.stereoMode(); const bool hasStereo = (sm != Window::StereoMode::NoStereo) && (sm < Window::StereoMode::SideBySide); if (hasStereo) { - SpoutWindow::SpoutData& left = w.leftOrMain; - left.handle = GetSpout(); - left.initialized = left.handle->CreateSender( - (window.name() + "_left").c_str(), - window.framebufferResolution().x, - window.framebufferResolution().y - ); - - SpoutWindow::SpoutData& right = w.right; - right.handle = GetSpout(); - right.initialized = right.handle->CreateSender( - (window.name() + "_right").c_str(), - window.framebufferResolution().x, - window.framebufferResolution().y - ); - } - else { - SpoutWindow::SpoutData& main = w.leftOrMain; - main.handle = GetSpout(); - main.initialized = main.handle->CreateSender( - window.name().c_str(), + mainWindowName = window.name() + "_left"; + retValue &= w.right.updateSenderName((window.name() + "_right").c_str()); + retValue &= w.right.updateSenderSize( window.framebufferResolution().x, window.framebufferResolution().y ); } - SpoutWindows.push_back(std::move(w)); + retValue &= w.leftOrMain.updateSenderName(mainWindowName.c_str()); + retValue &= w.leftOrMain.updateSenderSize( + window.framebufferResolution().x, + window.framebufferResolution().y + ); + + w.windowId = i; + + if (retValue) { + SpoutWindows.push_back(std::move(w)); + } #else LWARNING("Spout was requested, but program was compiled without Spout support"); #endif // OPENSPACE_HAS_SPOUT @@ -513,6 +500,29 @@ void mainRenderFunc(const sgct::RenderData& data) { currentModelMatrix = modelMatrix; currentModelViewProjectionMatrix = modelMatrix * viewMatrix * projectionMatrix; global::openSpaceEngine->render(modelMatrix, viewMatrix, projectionMatrix); + +#ifdef OPENSPACE_HAS_SPOUT + for (SpoutWindow& w : SpoutWindows) { + sgct::Window& window = *Engine::instance().windows()[w.windowId]; + int width = window.framebufferResolution().x; + int height = window.framebufferResolution().y; + + w.leftOrMain.saveGLState(); + + if (w.leftOrMain.isCreated() && w.leftOrMain.updateSenderSize(width, height)) + { + GLuint texId = window.frameBufferTexture(Window::TextureIndex::LeftEye); + w.leftOrMain.updateSender(texId, static_cast(GL_TEXTURE_2D)); + } + + if (w.right.isCreated() && w.right.updateSenderSize(width, height)) { + GLuint texId = window.frameBufferTexture(Window::TextureIndex::RightEye); + w.right.updateSender(texId, static_cast(GL_TEXTURE_2D)); + } + + w.leftOrMain.restoreGLState(); + } +#endif // OPENSPACE_HAS_SPOUT } catch (const ghoul::RuntimeError& e) { LERRORC(e.component, e.message); @@ -564,34 +574,6 @@ void mainPostDrawFunc() { global::openSpaceEngine->postDraw(); -#ifdef OPENSPACE_HAS_SPOUT - for (const SpoutWindow& w : SpoutWindows) { - sgct::Window& window = *Engine::instance().windows()[w.windowId]; - if (w.leftOrMain.initialized) { - const GLuint texId = window.frameBufferTexture(Window::TextureIndex::LeftEye); - glBindTexture(GL_TEXTURE_2D, texId); - w.leftOrMain.handle->SendTexture( - texId, - GLuint(GL_TEXTURE_2D), - window.framebufferResolution().x, - window.framebufferResolution().y - ); - } - - if (w.right.initialized) { - const GLuint tId = window.frameBufferTexture(Window::TextureIndex::RightEye); - glBindTexture(GL_TEXTURE_2D, tId); - w.right.handle->SendTexture( - tId, - GLuint(GL_TEXTURE_2D), - window.framebufferResolution().x, - window.framebufferResolution().y - ); - } - } - glBindTexture(GL_TEXTURE_2D, 0); -#endif // OPENSPACE_HAS_SPOUT - LTRACE("main::mainPostDrawFunc(end)"); } @@ -797,8 +779,8 @@ void setSgctDelegateFunctions() { Viewport* viewport = currentWindow->viewports().front().get(); if (viewport != nullptr) { if (viewport->hasSubViewports() && viewport->nonLinearProjection()) { - int res = viewport->nonLinearProjection()->cubemapResolution(); - return glm::ivec2(res, res); + ivec2 dim = viewport->nonLinearProjection()->cubemapResolution(); + return glm::ivec2(dim.x, dim.y); } else if (currentWindow->viewports().size() > 1) { // @TODO (abock, 2020-04-09) This should probably be based on the current @@ -1361,14 +1343,8 @@ int main(int argc, char* argv[]) { #ifdef OPENSPACE_HAS_SPOUT for (SpoutWindow& w : SpoutWindows) { - if (w.leftOrMain.handle) { - w.leftOrMain.handle->ReleaseReceiver(); - w.leftOrMain.handle->Release(); - } - if (w.right.handle) { - w.right.handle->ReleaseReceiver(); - w.right.handle->Release(); - } + w.leftOrMain.release(); + w.right.release(); } #endif // OPENSPACE_HAS_SPOUT diff --git a/config/single_gui_spout.json b/config/single_gui_spout.json new file mode 100644 index 0000000000..db17b98a06 --- /dev/null +++ b/config/single_gui_spout.json @@ -0,0 +1,67 @@ +{ + "version": 1, + "masteraddress": "localhost", + "externalcontrolport": 20500, + "settings": { + "display": { + "swapinterval": 0 + } + }, + "nodes": [ + { + "address": "localhost", + "port": 20401, + "windows": [ + { + "name": "OpenSpace", + "pos": { "x": 50, "y": 50 }, + "size": { "x": 1280, "y": 720 }, + "stereo": "none", + "tags": [ "Spout" ], + "viewports": [ + { + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "tracked": true, + "projection": { + "type": "PlanarProjection", + "fov": { + "hfov": 80.0, + "vfov": 50.53401565551758 + }, + "orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 } + } + } + ] + }, + { + "name": "GUI", + "pos": { "x": 50, "y": 50 }, + "size": { "x": 1280, "y": 720 }, + "stereo": "none", + "tags": [ "GUI" ], + "viewports": [ + { + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "PlanarProjection", + "fov": { + "hfov": 80.0, + "vfov": 50.53401565551758 + }, + "orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 } + } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.06499999761581421, + "pos": { "x": 0.0, "y": 0.0, "z": 0.0 } + } + ] +} diff --git a/config/spout_output.json b/config/spout_output.json deleted file mode 100644 index a6d5d1148d..0000000000 --- a/config/spout_output.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "version": 1, - "masteraddress": "localhost", - "nodes": [ - { - "address": "localhost", - "port": 20401, - "windows": [ - { - "fullscreen": false, - "name": "OpenSpace", - "stereo": "none", - "size": { "x": 1024, "y": 1024 }, - "viewports": [ - { - "pos": { "x": 0.0, "y": 0.0 }, - "size": { "x": 1.0, "y": 1.0 }, - "projection": { - "type": "SpoutOutputProjection", - "quality": "1k", - "mappingspoutname": "OpenSpace", - "background": { "r": 0.1, "g": 0.1, "b": 0.1, "a": 1.0 } - } - } - ] - } - ] - } - ], - "users": [ - { - "eyeseparation": 0.06, - "pos": { "x": 0.0, "y": 0.0, "z": 0.0 } - } - ] -} diff --git a/config/spout_output_cubemap.json b/config/spout_output_cubemap.json new file mode 100644 index 0000000000..064f48ecfc --- /dev/null +++ b/config/spout_output_cubemap.json @@ -0,0 +1,60 @@ +{ + "version": 1, + "masteraddress": "localhost", + "scene": { + "offset": { "x": 0.0, "y": 0.0, "z": 0.0 }, + "orientation": { "yaw": 0.0, "pitch": -90.0, "roll": 0.0 }, + "scale": 1.0 + }, + "settings": { + "display": { + "swapinterval": 1 + } + }, + "nodes": [ + { + "address": "localhost", + "port": 20401, + "windows": [ + { + "name": "OpenSpace", + "size": { "x": 1024, "y": 1024 }, + "stereo": "none", + "viewports": [ + { + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "SpoutOutputProjection", + "background": { + "r": 0.1, + "g": 0.1, + "b": 0.1, + "a": 1.0 + }, + "channels": { + "bottom": true, + "left": true, + "right": true, + "top": true, + "zleft": true, + "zright": true + }, + "mapping": "cubemap", + "mappingspoutname": "OS_CUBEMAP", + "orientation": { "pitch": 0.0, "roll": 0.0, "yaw": 0.0 }, + "quality": "1024" + } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.05999999865889549, + "pos": { "x": 0.0, "y": 0.0, "z": 0.0 } + } + ] +} diff --git a/config/spout_output_equirectangular.json b/config/spout_output_equirectangular.json new file mode 100644 index 0000000000..87a3bd98c2 --- /dev/null +++ b/config/spout_output_equirectangular.json @@ -0,0 +1,60 @@ +{ + "version": 1, + "masteraddress": "localhost", + "scene": { + "offset": { "x": 0.0, "y": 0.0, "z": 0.0 }, + "orientation": { "yaw": 0.0, "pitch": -90.0, "roll": 0.0 }, + "scale": 1.0 + }, + "settings": { + "display": { + "swapinterval": 1 + } + }, + "nodes": [ + { + "address": "localhost", + "port": 20401, + "windows": [ + { + "name": "OpenSpace", + "size": { "x": 1024, "y": 1024 }, + "stereo": "none", + "viewports": [ + { + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "SpoutOutputProjection", + "background": { + "r": 0.1, + "g": 0.1, + "b": 0.1, + "a": 1.0 + }, + "channels": { + "bottom": true, + "left": true, + "right": true, + "top": true, + "zleft": true, + "zright": true + }, + "mapping": "equirectangular", + "mappingspoutname": "OS_EQUIRECTANGULAR", + "orientation": { "pitch": 0.0, "roll": 0.0, "yaw": 0.0 }, + "quality": "1024" + } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.06, + "pos": { "x": 0.0, "y": 0.0, "z": 0.0 } + } + ] +} diff --git a/config/spout_output_fisheye.json b/config/spout_output_fisheye.json new file mode 100644 index 0000000000..cd1b2a490e --- /dev/null +++ b/config/spout_output_fisheye.json @@ -0,0 +1,60 @@ +{ + "version": 1, + "masteraddress": "localhost", + "scene": { + "offset": { "x": 0.0, "y": 0.0, "z": 0.0 }, + "orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 }, + "scale": 1.0 + }, + "settings": { + "display": { + "swapinterval": 1 + } + }, + "nodes": [ + { + "address": "localhost", + "port": 20401, + "windows": [ + { + "name": "OpenSpace", + "size": { "x": 1024, "y": 1024 }, + "stereo": "none", + "viewports": [ + { + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "SpoutOutputProjection", + "background": { + "r": 0.1, + "g": 0.1, + "b": 0.1, + "a": 1.0 + }, + "channels": { + "bottom": false, + "left": true, + "right": true, + "top": true, + "zleft": true, + "zright": false + }, + "mapping": "fisheye", + "mappingspoutname": "OS_FISHEYE", + "orientation": { "pitch": 0.0, "roll": 0.0, "yaw": 45.0 }, + "quality": "1024" + } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.06, + "pos": { "x": 0.0, "y": 0.0, "z": 0.0 } + } + ] +} diff --git a/config/spout_output_flat.json b/config/spout_output_flat.json new file mode 100644 index 0000000000..0d1b775d77 --- /dev/null +++ b/config/spout_output_flat.json @@ -0,0 +1,59 @@ +{ + "version": 1, + "masteraddress": "localhost", + "scene": { + "offset": { "x": 0.0, "y": 0.0, "z": 0.0 }, + "orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 }, + "scale": 1.0 + }, + "settings": { + "display": { + "swapinterval": 1 + } + }, + "nodes": [ + { + "address": "localhost", + "port": 20401, + "windows": [ + { + "name": "OpenSpace", + "size": { "x": 1440, "y": 810 }, + "stereo": "none", + "viewports": [ + { + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "PlanarProjection": { + "fov": { + "hfov": 80.0, + "vfov": 50.534015846724 + }, + "orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 } + }, + "background": { + "r": 0.1, + "g": 0.1, + "b": 0.1, + "a": 1.0 + }, + "drawMain": true, + "height": "1080", + "mappingspoutname": "OS_FLAT", + "type": "SpoutFlatProjection", + "width": "1920" + } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.05999999865889549, + "pos": { "x": 0.0, "y": 0.0, "z": 0.0 } + } + ] +} diff --git a/data/assets/scene/solarsystem/planets/earth/layers/colorlayers/terra_texture_spout.asset b/data/assets/scene/solarsystem/planets/earth/layers/colorlayers/terra_texture_spout.asset new file mode 100644 index 0000000000..60059cf84d --- /dev/null +++ b/data/assets/scene/solarsystem/planets/earth/layers/colorlayers/terra_texture_spout.asset @@ -0,0 +1,18 @@ +local globeIdentifier = asset.require("../../earth").Earth.Identifier + +local layer = { + Identifier = "TextureSpout", + SpoutName = "SPOUT_TERRA_RECEIVER", + Type = "SpoutImageTileLayer" +} + +asset.onInitialize(function () + openspace.globebrowsing.addLayer(globeIdentifier, "ColorLayers", layer) +end) + + +asset.onDeinitialize(function() + openspace.globebrowsing.deleteLayer(globeIdentifier, "ColorLayers", layer) +end) + +asset.export("layer", layer) diff --git a/modules/base/rendering/renderablesphere.cpp b/modules/base/rendering/renderablesphere.cpp index 54ccf357ed..4324de5a7e 100644 --- a/modules/base/rendering/renderablesphere.cpp +++ b/modules/base/rendering/renderablesphere.cpp @@ -339,7 +339,8 @@ void RenderableSphere::render(const RenderData& data, RendererTasks&) { ghoul::opengl::TextureUnit unit; unit.activate(); - _texture->bind(); + bindTexture(); + defer{ unbindTexture(); }; _shader->setUniform(_uniformCache.colorTexture, unit); // Setting these states should not be necessary, @@ -390,6 +391,12 @@ void RenderableSphere::update(const UpdateData&) { } } +void RenderableSphere::bindTexture() { + _texture->bind(); +} + +void RenderableSphere::unbindTexture() {} + void RenderableSphere::loadTexture() { if (!_texturePath.value().empty()) { std::unique_ptr texture = diff --git a/modules/base/rendering/renderablesphere.h b/modules/base/rendering/renderablesphere.h index 5934dbdfdb..d06320de0c 100644 --- a/modules/base/rendering/renderablesphere.h +++ b/modules/base/rendering/renderablesphere.h @@ -60,6 +60,10 @@ public: static documentation::Documentation Documentation(); +protected: + virtual void bindTexture(); + virtual void unbindTexture(); + private: void loadTexture(); diff --git a/modules/globebrowsing/CMakeLists.txt b/modules/globebrowsing/CMakeLists.txt index 26d8a1e221..868a47ea2e 100644 --- a/modules/globebrowsing/CMakeLists.txt +++ b/modules/globebrowsing/CMakeLists.txt @@ -63,6 +63,7 @@ set(HEADER_FILES src/tileprovider/imagesequencetileprovider.h src/tileprovider/singleimagetileprovider.h src/tileprovider/sizereferencetileprovider.h + src/tileprovider/spoutimageprovider.h src/tileprovider/temporaltileprovider.h src/tileprovider/texttileprovider.h src/tileprovider/tileindextileprovider.h @@ -102,6 +103,7 @@ set(SOURCE_FILES src/tileprovider/imagesequencetileprovider.cpp src/tileprovider/singleimagetileprovider.cpp src/tileprovider/sizereferencetileprovider.cpp + src/tileprovider/spoutimageprovider.cpp src/tileprovider/temporaltileprovider.cpp src/tileprovider/texttileprovider.cpp src/tileprovider/tileindextileprovider.cpp diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index 8b0438741c..8a39e68755 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -306,6 +307,9 @@ void GlobeBrowsingModule::internalInitialize(const ghoul::Dictionary& dict) { fTileProvider->registerClass( LAYER_TYPE_NAMES[static_cast(TypeID::ImageSequenceTileLayer)] ); + fTileProvider->registerClass( + LAYER_TYPE_NAMES[static_cast(TypeID::SpoutImageTileLayer)] + ); fTileProvider->registerClass( LAYER_TYPE_NAMES[static_cast(TypeID::TemporalTileLayer)] ); diff --git a/modules/globebrowsing/include.cmake b/modules/globebrowsing/include.cmake index 5667e647fb..2c6ecfb83d 100644 --- a/modules/globebrowsing/include.cmake +++ b/modules/globebrowsing/include.cmake @@ -2,4 +2,9 @@ set (OPENSPACE_DEPENDENCIES debugging ) +# Don't **actually** add it as a dependency. Only mark it as a dependency if it was already enabled anyway. We need to do this as the GlobeBrowsing partially depends on being able to detect if OpenSpace was compiled with Spout support or not +if (OPENSPACE_MODULE_SPOUT) + set(OPENSPACE_DEPENDENCIES ${OPENSPACE_DEPENDENCIES} spout) +endif (OPENSPACE_MODULE_SPOUT) + set (DEFAULT_MODULE ON) diff --git a/modules/globebrowsing/shaders/texturetilemapping.glsl b/modules/globebrowsing/shaders/texturetilemapping.glsl index 76700f17e4..7995291c79 100644 --- a/modules/globebrowsing/shaders/texturetilemapping.glsl +++ b/modules/globebrowsing/shaders/texturetilemapping.glsl @@ -163,7 +163,8 @@ vec4 getSample#{layerGroup}#{i}(vec2 uv, vec3 levelWeights, c = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv, #{layerGroup}[#{i}].padding); #elif (#{#{layerGroup}#{i}LayerType} == 8) // SolidColor c.rgb = #{layerGroup}[#{i}].color; - +#elif (#{#{layerGroup}#{i}LayerType} == 9) // SpoutImageTileLayer + c = getTexVal(#{layerGroup}[#{i}].pile, levelWeights, uv, #{layerGroup}[#{i}].padding); #endif return c; diff --git a/modules/globebrowsing/src/gpulayergroup.cpp b/modules/globebrowsing/src/gpulayergroup.cpp index d32cbd9ace..151c029e59 100644 --- a/modules/globebrowsing/src/gpulayergroup.cpp +++ b/modules/globebrowsing/src/gpulayergroup.cpp @@ -68,6 +68,7 @@ void GPULayerGroup::setValue(ghoul::opengl::ProgramObject& program, // Intentional fall through. Same for all tile layers case layergroupid::TypeID::DefaultTileLayer: case layergroupid::TypeID::SingleImageTileLayer: + case layergroupid::TypeID::SpoutImageTileLayer: case layergroupid::TypeID::ImageSequenceTileLayer: case layergroupid::TypeID::SizeReferenceTileLayer: case layergroupid::TypeID::TemporalTileLayer: @@ -149,6 +150,7 @@ void GPULayerGroup::bind(ghoul::opengl::ProgramObject& p, // Intentional fall through. Same for all tile layers case layergroupid::TypeID::DefaultTileLayer: case layergroupid::TypeID::SingleImageTileLayer: + case layergroupid::TypeID::SpoutImageTileLayer: case layergroupid::TypeID::ImageSequenceTileLayer: case layergroupid::TypeID::SizeReferenceTileLayer: case layergroupid::TypeID::TemporalTileLayer: diff --git a/modules/globebrowsing/src/layer.cpp b/modules/globebrowsing/src/layer.cpp index f5b9070074..8ac7fc9aa1 100644 --- a/modules/globebrowsing/src/layer.cpp +++ b/modules/globebrowsing/src/layer.cpp @@ -115,7 +115,7 @@ namespace { std::optional type [[codegen::inlist("DefaultTileLayer", "SingleImageTileLayer", "ImageSequenceTileLayer", "SizeReferenceTileLayer", "TemporalTileLayer", "TileIndexTileLayer", "ByIndexTileLayer", - "ByLevelTileLayer", "SolidColor")]]; + "ByLevelTileLayer", "SolidColor", "SpoutImageTileLayer")]]; // Determine whether the layer is enabled or not. If this value is not specified, // the layer is disabled @@ -302,6 +302,7 @@ Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict, // Intentional fall through. Same for all tile layers case layergroupid::TypeID::DefaultTileLayer: case layergroupid::TypeID::SingleImageTileLayer: + case layergroupid::TypeID::SpoutImageTileLayer: case layergroupid::TypeID::ImageSequenceTileLayer: case layergroupid::TypeID::SizeReferenceTileLayer: case layergroupid::TypeID::TemporalTileLayer: @@ -470,6 +471,7 @@ void Layer::initializeBasedOnType(layergroupid::TypeID id, ghoul::Dictionary ini // Intentional fall through. Same for all tile layers case layergroupid::TypeID::DefaultTileLayer: case layergroupid::TypeID::SingleImageTileLayer: + case layergroupid::TypeID::SpoutImageTileLayer: case layergroupid::TypeID::ImageSequenceTileLayer: case layergroupid::TypeID::SizeReferenceTileLayer: case layergroupid::TypeID::TemporalTileLayer: @@ -502,6 +504,7 @@ void Layer::addVisibleProperties() { // Intentional fall through. Same for all tile layers case layergroupid::TypeID::DefaultTileLayer: case layergroupid::TypeID::SingleImageTileLayer: + case layergroupid::TypeID::SpoutImageTileLayer: case layergroupid::TypeID::ImageSequenceTileLayer: case layergroupid::TypeID::SizeReferenceTileLayer: case layergroupid::TypeID::TemporalTileLayer: diff --git a/modules/globebrowsing/src/layergroupid.h b/modules/globebrowsing/src/layergroupid.h index 9da5cba759..07377fb108 100644 --- a/modules/globebrowsing/src/layergroupid.h +++ b/modules/globebrowsing/src/layergroupid.h @@ -56,7 +56,7 @@ enum GroupID { Unknown }; -static constexpr const int NUM_LAYER_TYPES = 9; +static constexpr const int NUM_LAYER_TYPES = 10; static constexpr const char* LAYER_TYPE_NAMES[NUM_LAYER_TYPES] = { "DefaultTileLayer", "SingleImageTileLayer", @@ -66,7 +66,8 @@ static constexpr const char* LAYER_TYPE_NAMES[NUM_LAYER_TYPES] = { "TileIndexTileLayer", "ByIndexTileLayer", "ByLevelTileLayer", - "SolidColor" + "SolidColor", + "SpoutImageTileLayer" }; /** @@ -82,7 +83,8 @@ enum class TypeID { TileIndexTileLayer = 5, ByIndexTileLayer = 6, ByLevelTileLayer = 7, - SolidColor = 8 + SolidColor = 8, + SpoutImageTileLayer = 9 }; static constexpr int NUM_ADJUSTMENT_TYPES = 3; diff --git a/modules/globebrowsing/src/tileprovider/defaulttileprovider.cpp b/modules/globebrowsing/src/tileprovider/defaulttileprovider.cpp index 6a11f3acb4..c3ec9b5916 100644 --- a/modules/globebrowsing/src/tileprovider/defaulttileprovider.cpp +++ b/modules/globebrowsing/src/tileprovider/defaulttileprovider.cpp @@ -195,6 +195,11 @@ void DefaultTileProvider::reset() { _asyncTextureDataProvider->prepareToBeDeleted(); } +int DefaultTileProvider::minLevel() { + ghoul_assert(_asyncTextureDataProvider, "No data provider"); + return 1; +} + int DefaultTileProvider::maxLevel() { ghoul_assert(_asyncTextureDataProvider, "No data provider"); return _asyncTextureDataProvider->rawTileDataReader().maxChunkLevel(); diff --git a/modules/globebrowsing/src/tileprovider/defaulttileprovider.h b/modules/globebrowsing/src/tileprovider/defaulttileprovider.h index 0cb6195ea8..ea5b8f87f4 100644 --- a/modules/globebrowsing/src/tileprovider/defaulttileprovider.h +++ b/modules/globebrowsing/src/tileprovider/defaulttileprovider.h @@ -41,6 +41,7 @@ public: TileDepthTransform depthTransform() override final; void update() override final; void reset() override final; + int minLevel() override final; int maxLevel() override final; float noDataValueAsFloat() override final; diff --git a/modules/globebrowsing/src/tileprovider/imagesequencetileprovider.cpp b/modules/globebrowsing/src/tileprovider/imagesequencetileprovider.cpp index 597cacda81..b0b1423be5 100644 --- a/modules/globebrowsing/src/tileprovider/imagesequencetileprovider.cpp +++ b/modules/globebrowsing/src/tileprovider/imagesequencetileprovider.cpp @@ -149,6 +149,10 @@ void ImageSequenceTileProvider::reset() { } } +int ImageSequenceTileProvider::minLevel() { + return 1; +} + int ImageSequenceTileProvider::maxLevel() { return _currentTileProvider ? _currentTileProvider->maxLevel() : 0; } diff --git a/modules/globebrowsing/src/tileprovider/imagesequencetileprovider.h b/modules/globebrowsing/src/tileprovider/imagesequencetileprovider.h index afacdfe05b..af461f78de 100644 --- a/modules/globebrowsing/src/tileprovider/imagesequencetileprovider.h +++ b/modules/globebrowsing/src/tileprovider/imagesequencetileprovider.h @@ -40,6 +40,7 @@ public: TileDepthTransform depthTransform() override final; void update() override final; void reset() override final; + int minLevel() override final; int maxLevel() override final; float noDataValueAsFloat() override final; diff --git a/modules/globebrowsing/src/tileprovider/singleimagetileprovider.cpp b/modules/globebrowsing/src/tileprovider/singleimagetileprovider.cpp index a6e6911ef2..69698568d7 100644 --- a/modules/globebrowsing/src/tileprovider/singleimagetileprovider.cpp +++ b/modules/globebrowsing/src/tileprovider/singleimagetileprovider.cpp @@ -93,6 +93,10 @@ void SingleImageProvider::reset() { _tile = Tile{ _tileTexture.get(), std::nullopt, Tile::Status::OK }; } +int SingleImageProvider::minLevel() { + return 1; +} + int SingleImageProvider::maxLevel() { return 1337; // unlimited } diff --git a/modules/globebrowsing/src/tileprovider/singleimagetileprovider.h b/modules/globebrowsing/src/tileprovider/singleimagetileprovider.h index a911c719f3..c1132b5e33 100644 --- a/modules/globebrowsing/src/tileprovider/singleimagetileprovider.h +++ b/modules/globebrowsing/src/tileprovider/singleimagetileprovider.h @@ -40,6 +40,7 @@ public: TileDepthTransform depthTransform() override final; void update() override final; void reset() override final; + int minLevel() override final; int maxLevel() override final; float noDataValueAsFloat() override final; diff --git a/modules/globebrowsing/src/tileprovider/sizereferencetileprovider.cpp b/modules/globebrowsing/src/tileprovider/sizereferencetileprovider.cpp index 6da9209036..bc60464713 100644 --- a/modules/globebrowsing/src/tileprovider/sizereferencetileprovider.cpp +++ b/modules/globebrowsing/src/tileprovider/sizereferencetileprovider.cpp @@ -114,6 +114,10 @@ TileDepthTransform SizeReferenceTileProvider::depthTransform() { void SizeReferenceTileProvider::update() {} +int SizeReferenceTileProvider::minLevel() { + return 1; +} + int SizeReferenceTileProvider::maxLevel() { return 1337; // unlimited } diff --git a/modules/globebrowsing/src/tileprovider/sizereferencetileprovider.h b/modules/globebrowsing/src/tileprovider/sizereferencetileprovider.h index adb25c42c7..770eccd819 100644 --- a/modules/globebrowsing/src/tileprovider/sizereferencetileprovider.h +++ b/modules/globebrowsing/src/tileprovider/sizereferencetileprovider.h @@ -37,6 +37,7 @@ public: Tile::Status tileStatus(const TileIndex& index) override final; TileDepthTransform depthTransform() override final; void update() override final; + int minLevel() override final; int maxLevel() override final; float noDataValueAsFloat() override final; diff --git a/modules/globebrowsing/src/tileprovider/spoutimageprovider.cpp b/modules/globebrowsing/src/tileprovider/spoutimageprovider.cpp new file mode 100644 index 0000000000..31826e9358 --- /dev/null +++ b/modules/globebrowsing/src/tileprovider/spoutimageprovider.cpp @@ -0,0 +1,219 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include + +#ifdef OPENSPACE_HAS_SPOUT +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif // WIN32_LEAN_AND_MEAN +#ifndef NOMINMAX +#define NOMINMAX +#endif // NOMINMAX +#include +#endif + +namespace { + struct [[codegen::Dictionary(SpoutImageProvider)]] Parameters { + std::optional spoutName; + }; +#include "spoutimageprovider_codegen.cpp" +} // namespace + +namespace openspace::globebrowsing { + +documentation::Documentation SpoutImageProvider::Documentation() { + return codegen::doc("globebrowsing_spoutimageprovider"); +} + +SpoutImageProvider::SpoutImageProvider(const ghoul::Dictionary& dictionary) { + ZoneScoped + +#ifdef OPENSPACE_HAS_SPOUT + spoutReceiver = std::make_unique( + *this, + dictionary + ); + + spoutReceiver->onUpdateTexture([this](int width, int height) { + for (int i = 0; i < 2; i++) { + if (!fbo[i]) { + glGenFramebuffers(1, &fbo[i]); + } + tileTexture[i].release(); + tileTexture[i] = std::make_unique( + glm::uvec3(width / 2, height, 1), + GL_TEXTURE_2D, + ghoul::opengl::Texture::Format::RGBA, + GL_RGBA, + GL_UNSIGNED_BYTE, + ghoul::opengl::Texture::FilterMode::Linear, + ghoul::opengl::Texture::WrappingMode::Repeat, + ghoul::opengl::Texture::AllocateData::No, + ghoul::opengl::Texture::TakeOwnership::No + ); + + if (!tileTexture[i]) { + return false; + } + tileTexture[i]->uploadTexture(); + tiles[i] = Tile{ tileTexture[i].get(), std::nullopt, Tile::Status::OK }; + } + return true; + }); + + + spoutReceiver->onReleaseTexture([this]() { + for (int i = 0; i < 2; i++) { + if (fbo[i]) { + glDeleteFramebuffers(1, &fbo[i]); + } + tileTexture[i].release(); + fbo[i] = 0; + } + }); + + + spoutReceiver->onUpdateReceiver([this](int width, int height, unsigned int texture) { + glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo[0]); + glFramebufferTexture2D( + GL_READ_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + static_cast(texture), + 0 + ); + glReadBuffer(GL_COLOR_ATTACHMENT0); + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo[1]); + glFramebufferTexture2D( + GL_DRAW_FRAMEBUFFER, + GL_COLOR_ATTACHMENT1, + GL_TEXTURE_2D, + static_cast(*tileTexture[0]), + 0 + ); + glDrawBuffer(GL_COLOR_ATTACHMENT1); + + glBlitFramebuffer( + width / 2, + 0, + width, + height, + 0, + 0, + width / 2, + height, + GL_COLOR_BUFFER_BIT, + GL_NEAREST + ); + glFramebufferTexture2D( + GL_DRAW_FRAMEBUFFER, + GL_COLOR_ATTACHMENT1, + GL_TEXTURE_2D, + static_cast(*tileTexture[1]), + 0 + ); + glBlitFramebuffer( + 0, + 0, + width / 2, + height, + 0, + 0, + width / 2, + height, + GL_COLOR_BUFFER_BIT, + GL_NEAREST + ); + return true; + }); +#endif + + reset(); +} + +void SpoutImageProvider::internalInitialize() { + ZoneScoped + +#ifdef OPENSPACE_HAS_SPOUT + spoutReceiver->updateReceiver(); +#endif // OPENSPACE_HAS_SPOUT +} + +void SpoutImageProvider::internalDeinitialize() { +#ifdef OPENSPACE_HAS_SPOUT + spoutReceiver->release(); +#endif // OPENSPACE_HAS_SPOUT +} + +Tile SpoutImageProvider::tile(const TileIndex& tileIndex) { + ZoneScoped + + spoutUpdate = true; + return tiles[tileIndex.x]; +} + +Tile::Status SpoutImageProvider::tileStatus(const TileIndex&) { + return Tile::Status::OK; +} + +TileDepthTransform SpoutImageProvider::depthTransform() { + return { 0.f, 1.f }; +} + +void SpoutImageProvider::update() { + if (!spoutUpdate) { + return; + } + + if (!spoutReceiver->isCreated()) { + reset(); + if (!spoutReceiver->isCreated()) { + return; + } + } + + spoutReceiver->updateReceiver(); +} + +void SpoutImageProvider::reset() { + spoutReceiver->updateReceiver(); +} + +int SpoutImageProvider::minLevel() { + return 0; +} + +int SpoutImageProvider::maxLevel() { + return 1; +} + +float SpoutImageProvider::noDataValueAsFloat() { + return std::numeric_limits::min(); +} + +} // namespace openspace::globebrowsing diff --git a/modules/globebrowsing/src/tileprovider/spoutimageprovider.h b/modules/globebrowsing/src/tileprovider/spoutimageprovider.h new file mode 100644 index 0000000000..326fb24ad1 --- /dev/null +++ b/modules/globebrowsing/src/tileprovider/spoutimageprovider.h @@ -0,0 +1,66 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__SPOUTIMAGEPROVIDER___H__ +#define __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__SPOUTIMAGEPROVIDER___H__ + +#include + +namespace openspace::spout { class SpoutReceiverPropertyProxy; } + +namespace openspace::globebrowsing { + +class SpoutImageProvider : public TileProvider { +public: + SpoutImageProvider(const ghoul::Dictionary& dictionary); + + Tile tile(const TileIndex& tileIndex) override final; + Tile::Status tileStatus(const TileIndex& index) override final; + TileDepthTransform depthTransform() override final; + void update() override final; + void reset() override final; + int minLevel() override final; + int maxLevel() override final; + float noDataValueAsFloat() override final; + + static documentation::Documentation Documentation(); + +private: + void internalInitialize() override final; + void internalDeinitialize() override final; + + std::array, 2> tileTexture; + std::array fbo = { 0, 0 }; + std::array tiles; + +#ifdef OPENSPACE_HAS_SPOUT + std::unique_ptr spoutReceiver; +#endif + + bool spoutUpdate = false; +}; + +} // namespace openspace::globebrowsing + +#endif // __OPENSPACE_MODULE_GLOBEBROWSING___TILEPROVIDER__SPOUTIMAGEPROVIDER___H__ diff --git a/modules/globebrowsing/src/tileprovider/temporaltileprovider.cpp b/modules/globebrowsing/src/tileprovider/temporaltileprovider.cpp index dd1131cb68..77201c5c75 100644 --- a/modules/globebrowsing/src/tileprovider/temporaltileprovider.cpp +++ b/modules/globebrowsing/src/tileprovider/temporaltileprovider.cpp @@ -371,6 +371,10 @@ void TemporalTileProvider::reset() { } } +int TemporalTileProvider::minLevel() { + return 1; +} + int TemporalTileProvider::maxLevel() { if (!_currentTileProvider) { update(); @@ -833,6 +837,10 @@ void TemporalTileProvider::InterpolateTileProvider::reset() { future->reset(); } +int TemporalTileProvider::InterpolateTileProvider::minLevel() { + return glm::max(t1->minLevel(), t2->minLevel()); +} + int TemporalTileProvider::InterpolateTileProvider::maxLevel() { return glm::min(t1->maxLevel(), t2->maxLevel()); } diff --git a/modules/globebrowsing/src/tileprovider/temporaltileprovider.h b/modules/globebrowsing/src/tileprovider/temporaltileprovider.h index 469251ac4c..4e99809273 100644 --- a/modules/globebrowsing/src/tileprovider/temporaltileprovider.h +++ b/modules/globebrowsing/src/tileprovider/temporaltileprovider.h @@ -51,6 +51,7 @@ public: TileDepthTransform depthTransform() override final; void update() override final; void reset() override final; + int minLevel() override final; int maxLevel() override final; float noDataValueAsFloat() override final; @@ -71,6 +72,7 @@ private: TileDepthTransform depthTransform() override final; void update() override final; void reset() override final; + int minLevel() override final; int maxLevel() override final; float noDataValueAsFloat() override final; diff --git a/modules/globebrowsing/src/tileprovider/tileindextileprovider.cpp b/modules/globebrowsing/src/tileprovider/tileindextileprovider.cpp index 30489b9500..14850548d6 100644 --- a/modules/globebrowsing/src/tileprovider/tileindextileprovider.cpp +++ b/modules/globebrowsing/src/tileprovider/tileindextileprovider.cpp @@ -54,6 +54,10 @@ TileDepthTransform TileIndexTileProvider::depthTransform() { void TileIndexTileProvider::update() {} +int TileIndexTileProvider::minLevel() { + return 1; +} + int TileIndexTileProvider::maxLevel() { return 1337; // unlimited } diff --git a/modules/globebrowsing/src/tileprovider/tileindextileprovider.h b/modules/globebrowsing/src/tileprovider/tileindextileprovider.h index 0913b59fe3..1f8fa84467 100644 --- a/modules/globebrowsing/src/tileprovider/tileindextileprovider.h +++ b/modules/globebrowsing/src/tileprovider/tileindextileprovider.h @@ -37,6 +37,7 @@ public: Tile::Status tileStatus(const TileIndex& index) override final; TileDepthTransform depthTransform() override final; void update() override final; + int minLevel() override final; int maxLevel() override final; float noDataValueAsFloat() override final; }; diff --git a/modules/globebrowsing/src/tileprovider/tileprovider.cpp b/modules/globebrowsing/src/tileprovider/tileprovider.cpp index 324dda08f5..7b58c91fd3 100644 --- a/modules/globebrowsing/src/tileprovider/tileprovider.cpp +++ b/modules/globebrowsing/src/tileprovider/tileprovider.cpp @@ -190,7 +190,8 @@ ChunkTile TileProvider::chunkTile(TileIndex tileIndex, int parents, int maxParen // Step 3. Traverse 0 or more parents up the chunkTree until we find a chunk that // has a loaded tile ready to use. - while (tileIndex.level > 1) { + int minimumLevel = minLevel(); + while (tileIndex.level > minimumLevel) { Tile t = tile(tileIndex); if (t.status != Tile::Status::OK) { if (--maxParents < 0) { diff --git a/modules/globebrowsing/src/tileprovider/tileprovider.h b/modules/globebrowsing/src/tileprovider/tileprovider.h index ce9b63aa4e..25698c9caf 100644 --- a/modules/globebrowsing/src/tileprovider/tileprovider.h +++ b/modules/globebrowsing/src/tileprovider/tileprovider.h @@ -114,6 +114,12 @@ struct TileProvider : public properties::PropertyOwner { */ virtual void reset() = 0; + /** + * \return The minimum level as defined by the TileIndex that this + * TileProvider is capable of providing. + */ + virtual int minLevel() = 0; + /** * \return The maximum level as defined by TileIndex that this * TileProvider is able provide. diff --git a/modules/globebrowsing/src/tileprovider/tileproviderbyindex.cpp b/modules/globebrowsing/src/tileprovider/tileproviderbyindex.cpp index f2e416e39d..4e651fd9f7 100644 --- a/modules/globebrowsing/src/tileprovider/tileproviderbyindex.cpp +++ b/modules/globebrowsing/src/tileprovider/tileproviderbyindex.cpp @@ -142,6 +142,10 @@ void TileProviderByIndex::reset() { _defaultTileProvider->reset(); } +int TileProviderByIndex::minLevel() { + return 1; +} + int TileProviderByIndex::maxLevel() { return _defaultTileProvider->maxLevel(); } diff --git a/modules/globebrowsing/src/tileprovider/tileproviderbyindex.h b/modules/globebrowsing/src/tileprovider/tileproviderbyindex.h index 9af02b6378..af3fad17ef 100644 --- a/modules/globebrowsing/src/tileprovider/tileproviderbyindex.h +++ b/modules/globebrowsing/src/tileprovider/tileproviderbyindex.h @@ -38,6 +38,7 @@ public: TileDepthTransform depthTransform() override final; void update() override final; void reset() override final; + int minLevel() override final; int maxLevel() override final; float noDataValueAsFloat() override final; diff --git a/modules/globebrowsing/src/tileprovider/tileproviderbylevel.cpp b/modules/globebrowsing/src/tileprovider/tileproviderbylevel.cpp index 326a5a0f09..ea2243d3e2 100644 --- a/modules/globebrowsing/src/tileprovider/tileproviderbylevel.cpp +++ b/modules/globebrowsing/src/tileprovider/tileproviderbylevel.cpp @@ -156,6 +156,10 @@ void TileProviderByLevel::reset() { } } +int TileProviderByLevel::minLevel() { + return 1; +} + int TileProviderByLevel::maxLevel() { return static_cast(_providerIndices.size() - 1); } diff --git a/modules/globebrowsing/src/tileprovider/tileproviderbylevel.h b/modules/globebrowsing/src/tileprovider/tileproviderbylevel.h index 1020c5d29d..988b1eccb2 100644 --- a/modules/globebrowsing/src/tileprovider/tileproviderbylevel.h +++ b/modules/globebrowsing/src/tileprovider/tileproviderbylevel.h @@ -38,6 +38,7 @@ public: TileDepthTransform depthTransform() override final; void update() override final; void reset() override final; + int minLevel() override final; int maxLevel() override final; float noDataValueAsFloat() override final; diff --git a/modules/spout/CMakeLists.txt b/modules/spout/CMakeLists.txt index 13cfb4e347..ae1cdfc329 100644 --- a/modules/spout/CMakeLists.txt +++ b/modules/spout/CMakeLists.txt @@ -26,14 +26,18 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES renderableplanespout.h + renderablespherespout.h screenspacespout.h spoutlibrary.h + spoutwrapper.h ) source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES renderableplanespout.cpp + renderablespherespout.cpp screenspacespout.cpp + spoutwrapper.cpp ) source_group("Source Files" FILES ${SOURCE_FILES}) diff --git a/modules/spout/ext/spout/SpoutLibrary.h b/modules/spout/ext/spout/SpoutLibrary.h index d50c0a1106..180ef779ed 100644 --- a/modules/spout/ext/spout/SpoutLibrary.h +++ b/modules/spout/ext/spout/SpoutLibrary.h @@ -5,7 +5,9 @@ // #include +#ifndef SPOUT_NO_GL_INCLUDE #include +#endif #define SPOUTLIBRARY_EXPORTS // defined for this DLL. The application imports rather than exports diff --git a/modules/spout/renderableplanespout.cpp b/modules/spout/renderableplanespout.cpp index 550edc3986..90d160e350 100644 --- a/modules/spout/renderableplanespout.cpp +++ b/modules/spout/renderableplanespout.cpp @@ -71,10 +71,7 @@ documentation::Documentation RenderablePlaneSpout::Documentation() { RenderablePlaneSpout::RenderablePlaneSpout(const ghoul::Dictionary& dictionary) : RenderablePlane(dictionary) - , _spoutName(NameInfo) - , _spoutSelection(SelectionInfo) - , _updateSelection(UpdateInfo) - , _receiver(GetSpout()) + , _spoutReceiver(*this, dictionary) { const Parameters p = codegen::bake(dictionary); @@ -96,115 +93,36 @@ RenderablePlaneSpout::RenderablePlaneSpout(const ghoul::Dictionary& dictionary) // Adding an extra space to the user-facing name as it looks nicer setGuiName("RenderablePlaneSpout " + std::to_string(iIdentifier)); } - - _spoutName = p.spoutName.value_or(_spoutName); - _spoutName.onChange([this]() { - _isSpoutDirty = true; - _isErrorMessageDisplayed = false; - - _receiver->SetActiveSender(_spoutName.value().c_str()); - }); - addProperty(_spoutName); - - _spoutSelection.onChange([this](){ - _spoutName = _spoutSelection.option().description; - }); - _spoutSelection.addOption(0, ""); - addProperty(_spoutSelection); - - _updateSelection.onChange([this]() { - const std::string& currentValue = _spoutSelection.options().empty() ? - "" : - _spoutSelection.option().description; - - _spoutSelection.clearOptions(); - _spoutSelection.addOption(0, ""); - - const int nSenders = _receiver->GetSenderCount(); - int idx = 0; - - for (int i = 0; i < nSenders; ++i) { - char Name[256]; - _receiver->GetSenderName(i, Name, 256); - - _spoutSelection.addOption(i + 1, Name); - - if (currentValue == Name) { - idx = i + 1; - } - } - - _spoutSelection = idx; - }); - addProperty(_updateSelection); } void RenderablePlaneSpout::deinitializeGL() { - _receiver->ReleaseReceiver(); - _receiver->Release(); + _spoutReceiver.release(); RenderablePlane::deinitializeGL(); } void RenderablePlaneSpout::update(const UpdateData& data) { RenderablePlane::update(data); - - if (_isFirstUpdate) { - // Trigger an update; the value is a dummy that is ignored - _updateSelection.set(0); - - // #0 is the empty string and we just pick the first one after that (if it exists) - if (_spoutSelection.options().size() > 1) { - _spoutSelection = 1; - } - - _isFirstUpdate = false; - } - - if (_spoutName.value().empty()) { - return; - } - - if (_isSpoutDirty) { - defer { _isSpoutDirty = false; }; - - std::memset(_currentSenderName, 0, 256); - unsigned int width; - unsigned int height; - - _receiver->ReleaseReceiver(); - - _receiver->GetActiveSender(_currentSenderName); - - bool hasCreated = _receiver->CreateReceiver(_currentSenderName, width, height); - if (!hasCreated) { - LWARNINGC( - LoggerCat, - fmt::format("Could not create receiver for {}", _currentSenderName) - ); - return; - } - } - - unsigned int width; - unsigned int height; - const bool hasReceived = _receiver->ReceiveTexture(_currentSenderName, width, height); - - if (!hasReceived && !_isErrorMessageDisplayed) { - LWARNINGC( - LoggerCat, - fmt::format("Could not receive texture for {}", _currentSenderName) - ); - _isErrorMessageDisplayed = true; - } + _spoutReceiver.updateReceiver(); } void RenderablePlaneSpout::bindTexture() { - _receiver->BindSharedTexture(); + if (_spoutReceiver.isReceiving()) { + _spoutReceiver.saveGLTextureState(); + glBindTexture(GL_TEXTURE_2D, static_cast(_spoutReceiver.spoutTexture())); + } + else { + RenderablePlane::bindTexture(); + } } void RenderablePlaneSpout::unbindTexture() { - _receiver->UnBindSharedTexture(); + if (_spoutReceiver.isReceiving()) { + _spoutReceiver.restoreGLTextureState(); + } + else { + RenderablePlane::unbindTexture(); + } } } // namespace openspace diff --git a/modules/spout/renderableplanespout.h b/modules/spout/renderableplanespout.h index fc52e2d7bc..0c4e6d2ae9 100644 --- a/modules/spout/renderableplanespout.h +++ b/modules/spout/renderableplanespout.h @@ -29,10 +29,7 @@ #include -#include -#include -#include -#include +#include namespace openspace { @@ -51,16 +48,7 @@ private: void bindTexture() override; void unbindTexture() override; - properties::StringProperty _spoutName; - properties::OptionProperty _spoutSelection; - properties::TriggerProperty _updateSelection; - - SPOUTHANDLE _receiver; - - bool _isSpoutDirty = true; - char _currentSenderName[256] = {}; - bool _isFirstUpdate = true; - bool _isErrorMessageDisplayed = false; + spout::SpoutReceiverPropertyProxy _spoutReceiver; }; } // namespace openspace diff --git a/modules/spout/renderablespherespout.cpp b/modules/spout/renderablespherespout.cpp new file mode 100644 index 0000000000..827f3c1a16 --- /dev/null +++ b/modules/spout/renderablespherespout.cpp @@ -0,0 +1,120 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifdef WIN32 + +#include + +#include +#include +#include +#include +#include + +namespace openspace { + +documentation::Documentation RenderableSphereSpout::Documentation() { + using namespace openspace::documentation; + return { + "Renderable Sphere Spout", + "spout_sphere_spout", + { + { + "Name", + new StringVerifier, + Optional::Yes, + "Specifies the GUI name of the RenderableSphereSpout" + }, + { + spout::SpoutReceiverPropertyProxy::NameInfoProperty().identifier, + new StringVerifier, + Optional::Yes, + spout::SpoutReceiverPropertyProxy::NameInfoProperty().description + } + } + }; +} + +RenderableSphereSpout::RenderableSphereSpout(const ghoul::Dictionary& dictionary) + : RenderableSphere(dictionary) + , _spoutReceiver(*this, dictionary) +{ + documentation::testSpecificationAndThrow( + Documentation(), + dictionary, + "RenderableSphereSpout" + ); + + int iIdentifier = 0; + if (_identifier.empty()) { + static int id = 0; + iIdentifier = id; + + if (iIdentifier == 0) { + setIdentifier("RenderableSphereSpout"); + } + else { + setIdentifier("RenderableSphereSpout" + std::to_string(iIdentifier)); + } + ++id; + } + + if (_guiName.empty()) { + // Adding an extra space to the user-facing name as it looks nicer + setGuiName("RenderableSphereSpout " + std::to_string(iIdentifier)); + } +} + +void RenderableSphereSpout::deinitializeGL() { + _spoutReceiver.release(); + RenderableSphere::deinitializeGL(); +} + +void RenderableSphereSpout::update(const UpdateData& data) { + RenderableSphere::update(data); + _spoutReceiver.updateReceiver(); +} + +void RenderableSphereSpout::bindTexture() { + if (_spoutReceiver.isReceiving()) { + _spoutReceiver.saveGLTextureState(); + glBindTexture(GL_TEXTURE_2D, _spoutReceiver.spoutTexture()); + } + else { + RenderableSphere::bindTexture(); + } +} + +void RenderableSphereSpout::unbindTexture() { + if (_spoutReceiver.isReceiving()) { + _spoutReceiver.restoreGLTextureState(); + } + else { + RenderableSphere::unbindTexture(); + } +} + +} // namespace openspace + +#endif // WIN32 diff --git a/modules/spout/renderablespherespout.h b/modules/spout/renderablespherespout.h new file mode 100644 index 0000000000..18c16b2412 --- /dev/null +++ b/modules/spout/renderablespherespout.h @@ -0,0 +1,58 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_SPOUT___RENDERABLESPHERESPOUT___H__ +#define __OPENSPACE_MODULE_SPOUT___RENDERABLESPHERESPOUT___H__ + +#ifdef WIN32 + +#include + +#include + +namespace openspace { + +namespace documentation { struct Documentation; } + +class RenderableSphereSpout : public RenderableSphere { +public: + RenderableSphereSpout(const ghoul::Dictionary& dictionary); + + void deinitializeGL() override; + void update(const UpdateData& data) override; + + static documentation::Documentation Documentation(); + +private: + void bindTexture() override; + void unbindTexture() override; + + spout::SpoutReceiverPropertyProxy _spoutReceiver; +}; + +} // namespace openspace + +#endif // WIN32 + +#endif // __OPENSPACE_MODULE_SPOUT___RENDERABLESPHERESPOUT___H__ diff --git a/modules/spout/screenspacespout.cpp b/modules/spout/screenspacespout.cpp index 898a2a443f..27d0dab270 100644 --- a/modules/spout/screenspacespout.cpp +++ b/modules/spout/screenspacespout.cpp @@ -69,13 +69,8 @@ documentation::Documentation ScreenSpaceSpout::Documentation() { ScreenSpaceSpout::ScreenSpaceSpout(const ghoul::Dictionary& dictionary) : ScreenSpaceRenderable(dictionary) - , _spoutName(NameInfo) - , _spoutSelection(SelectionInfo) - , _updateSelection(UpdateInfo) - , _receiver(GetSpout()) + , _spoutReceiver(*this, dictionary) { - const Parameters p = codegen::bake(dictionary); - std::string identifier; if (dictionary.hasValue(KeyIdentifier)) { identifier = dictionary.value(KeyIdentifier); @@ -85,127 +80,30 @@ ScreenSpaceSpout::ScreenSpaceSpout(const ghoul::Dictionary& dictionary) } identifier = makeUniqueIdentifier(identifier); setIdentifier(std::move(identifier)); - - _spoutName = p.spoutName.value_or(_spoutName); - _spoutName.onChange([this]() { - _isSpoutDirty = true; - _isErrorMessageDisplayed = false; - - _receiver->SetActiveSender(_spoutName.value().c_str()); - }); - addProperty(_spoutName); - - _spoutSelection.onChange([this]() { - _spoutName = _spoutSelection.option().description; - }); - _spoutSelection.addOption(0, ""); - addProperty(_spoutSelection); - - _updateSelection.onChange([this]() { - const std::string& currentValue = _spoutSelection.options().empty() ? - "" : - _spoutSelection.option().description; - - _spoutSelection.clearOptions(); - _spoutSelection.addOption(0, ""); - - int nSenders = _receiver->GetSenderCount(); - - int idx = 0; - - for (int i = 0; i < nSenders; ++i) { - char Name[256]; - _receiver->GetSenderName(i, Name, 256); - - _spoutSelection.addOption(i + 1, Name); - - if (currentValue == Name) { - idx = i + 1; - } - } - - _spoutSelection = idx; - }); - addProperty(_updateSelection); } bool ScreenSpaceSpout::deinitializeGL() { - _receiver->ReleaseReceiver(); - _receiver->Release(); + _spoutReceiver.release(); return ScreenSpaceRenderable::deinitializeGL(); } bool ScreenSpaceSpout::isReady() const { - return ScreenSpaceRenderable::isReady() && !_spoutName.value().empty(); + return ScreenSpaceRenderable::isReady() && !_spoutReceiver.isReceiving(); } void ScreenSpaceSpout::update() { - if (_isFirstUpdate) { - defer { _isFirstUpdate = false; }; - - // Trigger an update; the value is a dummy that is ignored - _updateSelection.set(0); - - // #0 is the empty string and we just pick the first one after that (if it exists) - if (_spoutSelection.options().size() > 1) { - _spoutSelection = 1; - } - } - - if (_spoutName.value().empty()) { - return; - } - - if (_isSpoutDirty) { - defer { _isSpoutDirty = false; }; - - std::memset(_currentSenderName, 0, 256); - - _receiver->ReleaseReceiver(); - _receiver->GetActiveSender(_currentSenderName); - - unsigned int width; - unsigned int height; - const bool hasCreated = _receiver->CreateReceiver( - _currentSenderName, - width, - height - ); - _objectSize = { width, height }; - - if (!hasCreated) { - LWARNINGC( - "ScreenSpaceSpout", - fmt::format("Could not create receiver for {}", _currentSenderName) - ); - return; - } - } - - unsigned int width; - unsigned int height; - const bool receiveSuccess = _receiver->ReceiveTexture( - _currentSenderName, - width, - height - ); - - if (!receiveSuccess && !_isErrorMessageDisplayed) { - LWARNINGC( - "ScreenSpaceSpout", - fmt::format("Could not receive texture for {}", _currentSenderName) - ); - _isErrorMessageDisplayed = true; - } + ScreenSpaceRenderable::update(); + _spoutReceiver.updateReceiver(); } void ScreenSpaceSpout::bindTexture() { - _receiver->BindSharedTexture(); + _spoutReceiver.saveGLTextureState(); + glBindTexture(GL_TEXTURE_2D, _spoutReceiver.spoutTexture()); } void ScreenSpaceSpout::unbindTexture() { - _receiver->UnBindSharedTexture(); + _spoutReceiver.restoreGLTextureState(); } } // namespace openspace diff --git a/modules/spout/screenspacespout.h b/modules/spout/screenspacespout.h index 299ac2e11a..fd4a764894 100644 --- a/modules/spout/screenspacespout.h +++ b/modules/spout/screenspacespout.h @@ -29,11 +29,7 @@ #include -#include - -#include -#include -#include +#include namespace openspace { @@ -54,17 +50,8 @@ public: private: void bindTexture() override; void unbindTexture() override; - - properties::StringProperty _spoutName; - properties::OptionProperty _spoutSelection; - properties::TriggerProperty _updateSelection; - - SPOUTHANDLE _receiver; - - bool _isSpoutDirty = true; - char _currentSenderName[256] = {}; - bool _isFirstUpdate = true; - bool _isErrorMessageDisplayed = false; + + spout::SpoutReceiverPropertyProxy _spoutReceiver; }; } // namespace openspace diff --git a/modules/spout/spoutmodule.cpp b/modules/spout/spoutmodule.cpp index 69d37205d9..55ece03384 100644 --- a/modules/spout/spoutmodule.cpp +++ b/modules/spout/spoutmodule.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -46,6 +47,7 @@ void SpoutModule::internalInitialize(const ghoul::Dictionary&) { FactoryManager::ref().factory(); ghoul_assert(fRenderable, "Renderable factory was not created"); fRenderable->registerClass("RenderablePlaneSpout"); + fRenderable->registerClass("RenderableSphereSpout"); #endif // WIN32 } diff --git a/modules/spout/spoutwrapper.cpp b/modules/spout/spoutwrapper.cpp new file mode 100644 index 0000000000..7b5ac35f53 --- /dev/null +++ b/modules/spout/spoutwrapper.cpp @@ -0,0 +1,613 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include "modules/spout/spoutwrapper.h" + +#include +#include +#include +#include +#define SPOUT_NO_GL_INCLUDE +#include + +namespace { + constexpr const char _loggerCat[] = "Spout"; + + constexpr openspace::properties::Property::PropertyInfo NameSenderInfo = { + "SpoutName", + "Spout Sender Name", + "This value sets the Spout sender to use a specific name." + }; + + constexpr openspace::properties::Property::PropertyInfo NameReceiverInfo = { + "SpoutName", + "Spout Receiver Name", + "This value explicitly sets the Spout receiver to use a specific name. If this " + "is not a valid name, an empty image is used." + }; + + constexpr openspace::properties::Property::PropertyInfo SelectionInfo = { + "SpoutSelection", + "Spout Selection", + "This property displays all available Spout sender on the system. If one them is " + "selected, its value is stored in the 'SpoutName' property, overwriting its " + "previous value." + }; + + constexpr openspace::properties::Property::PropertyInfo UpdateInfo = { + "UpdateSelection", + "Update Selection", + "If this property is trigged, the 'SpoutSelection' options will be refreshed." + }; +} // namespace + +namespace openspace::spout { + +SpoutMain::SpoutMain() { + _spoutHandle = GetSpout(); +} + +SpoutMain::~SpoutMain() {} + +void SpoutMain::release() { + if (_spoutHandle) { + _spoutHandle->Release(); + } +} + +void SpoutMain::saveGLState() { + GLint buf; + glGetIntegerv(GL_FRAMEBUFFER_BINDING, &buf); + _defaultFBO = static_cast(buf); + + glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &buf); + _defaultReadFBO = static_cast(buf); + + glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &buf); + _defaultDrawFBO = static_cast(buf); + + glGetIntegerv(GL_READ_BUFFER, &buf); + _defaultReadBuffer = static_cast(buf); + + glGetIntegerv(GL_DRAW_BUFFER0, &buf); + _defaultReadBuffer = static_cast(buf); + + saveGLTextureState(); +} + +void SpoutMain::restoreGLState() { + glBindFramebuffer(GL_FRAMEBUFFER, static_cast(_defaultFBO)); + if (_defaultFBO) { + glBindFramebuffer(GL_READ_FRAMEBUFFER, static_cast(_defaultReadFBO)); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, static_cast(_defaultDrawFBO)); + glReadBuffer(static_cast(_defaultReadBuffer)); + GLenum buf[1]; + buf[0] = static_cast(_defaultDrawBuffer[0]); + glDrawBuffers(1, buf); + } + restoreGLTextureState(); +} + +void SpoutMain::saveGLTextureState() { + GLint buf; + glGetIntegerv(GL_TEXTURE_BINDING_2D, &buf); + _defaultTexture = static_cast(buf); +} + +void SpoutMain::restoreGLTextureState() { + glBindTexture(GL_TEXTURE_2D, static_cast(_defaultTexture)); +} + +SpoutReceiver::SpoutReceiver() {} + +SpoutReceiver::~SpoutReceiver() {} + +const std::vector &SpoutReceiver::spoutReceiverList() { + if (!_spoutHandle) { + return _receiverList; + } + + const int nSenders = _spoutHandle->GetSenderCount(); + _receiverList.clear(); + + for (int i = 0; i < nSenders; ++i) { + char Name[256]; + _spoutHandle->GetSenderName(i, Name, 256); + _receiverList.push_back(Name); + } + + return _receiverList; +} + +bool SpoutReceiver::isCreated() const { + return _isCreated; +} + +bool SpoutReceiver::isReceiving() const { + return _isReceiving; +} + +bool SpoutReceiver::updateReceiver() { + unsigned int width = 10; + unsigned int height = 10; + + if (!_spoutHandle || !_isCreated) { + return false; + } + + char currentSpoutName[256] = { 0 }; + std::memcpy(currentSpoutName, _currentSpoutName.data(), _currentSpoutName.size()); + _spoutHandle->CheckReceiver(currentSpoutName, width, height, _isReceiving); + + // if spout is not connected a 10x10 texture is created + if (updateTexture(width, height) && _isReceiving) { + saveGLState(); + + _spoutHandle->ReceiveTexture( + currentSpoutName, + width, + height, + static_cast(*_spoutTexture), + static_cast(GL_TEXTURE_2D), + true + ); + + if (_onUpdateReceiverCallback) { + const GLuint t = static_cast(*_spoutTexture); + if (!_onUpdateReceiverCallback(width, height, t)) { + restoreGLState(); + return false; + } + } + + restoreGLState(); + return true; + } + + return false; +} + +bool SpoutReceiver::updateReceiverName(const std::string& name) { + unsigned int width = 0; + unsigned int height = 0; + + if (!_spoutHandle) { + return false; + } + + releaseReceiver(); + + if (_onUpdateReceiverNameCallback) { + if (!_onUpdateReceiverNameCallback(name)) { + return false; + } + } + + char nameBuf[256] = { 0 }; + std::memcpy(nameBuf, name.data(), name.size()); + bool hasCreated = _spoutHandle->CreateReceiver(nameBuf, width, height); + if (!hasCreated) { + if (!_isErrorMessageDisplayed) { + LWARNING(fmt::format( + "Could not create receiver for {} -> {}x{}", name, width, height + )); + _isErrorMessageDisplayed = true; + } + return false; + } + + _currentSpoutName = name; + _isErrorMessageDisplayed = false; + _isCreated = true; + + return true; +} + +void SpoutReceiver::releaseReceiver() { + if (!_isCreated) { + return; + } + + _isReceiving = false; + _isCreated = false; + _isErrorMessageDisplayed = false; + _currentSpoutName.clear(); + if (_onReleaseReceiverCallback) { + _onReleaseReceiverCallback(); + } + releaseTexture(); + if (_spoutHandle) { + _spoutHandle->ReleaseReceiver(); + } +} + +void SpoutReceiver::release() { + releaseReceiver(); + SpoutMain::release(); +} + +void SpoutReceiver::onUpdateReceiverName(std::function callback) +{ + _onUpdateReceiverNameCallback = std::move(callback); +} + +void SpoutReceiver::onUpdateReceiver(std::function callback) +{ + _onUpdateReceiverCallback = std::move(callback); +} + +void SpoutReceiver::onReleaseReceiver(std::function callback) { + _onReleaseReceiverCallback = std::move(callback); +} + +void SpoutReceiver::onUpdateTexture(std::function callback) { + _onUpdateTextureCallback = std::move(callback); +} + +void SpoutReceiver::onReleaseTexture(std::function callback) { + _onReleaseTextureCallback = std::move(callback); +} + +unsigned int SpoutReceiver::spoutTexture() const { + return _spoutTexture ? static_cast(*_spoutTexture) : 0; +} + +bool SpoutReceiver::updateTexture(unsigned int width, unsigned int height) { + if (width != _spoutWidth || height != _spoutHeight) { + releaseTexture(); + _spoutTexture = std::make_unique( + glm::uvec3(width, height, 1), + GL_TEXTURE_2D, + ghoul::opengl::Texture::Format::RGBA, + GL_RGBA, GL_UNSIGNED_BYTE, + ghoul::opengl::Texture::FilterMode::Linear, + ghoul::opengl::Texture::WrappingMode::Repeat, + ghoul::opengl::Texture::AllocateData::No, + ghoul::opengl::Texture::TakeOwnership::No + ); + + if (_spoutTexture) { + _spoutTexture->uploadTexture(); + if (_onUpdateTextureCallback && !_onUpdateTextureCallback(width, height)) { + LWARNING(fmt::format( + "Could not create callback texture for {} -> {}x{}", + _currentSpoutName, width, height + )); + return false; + } + _spoutWidth = width; + _spoutHeight = height; + } + else { + LWARNING(fmt::format( + "Could not create texture for {} -> {}x{}", + _currentSpoutName, width, height + )); + return false; + } + } + return true; +} + +void SpoutReceiver::releaseTexture() { + _spoutWidth = 0; + _spoutHeight = 0; + if (_onReleaseTextureCallback) { + _onReleaseTextureCallback(); + } + _spoutTexture.release(); +} + +const properties::Property::PropertyInfo& SpoutReceiverPropertyProxy::NameInfoProperty() { + return NameReceiverInfo; +} + +const properties::Property::PropertyInfo& +SpoutReceiverPropertyProxy::SelectionInfoProperty() +{ + return SelectionInfo; +} + +const properties::Property::PropertyInfo& SpoutReceiverPropertyProxy::UpdateInfoProperty() +{ + return UpdateInfo; +} + +SpoutReceiverPropertyProxy::SpoutReceiverPropertyProxy(properties::PropertyOwner& owner, + const ghoul::Dictionary& dictionary) + : _spoutName(NameReceiverInfo) + , _spoutSelection(SelectionInfo) + , _updateSelection(UpdateInfo) +{ + if (dictionary.hasKey(NameReceiverInfo.identifier)) { + _spoutName = dictionary.value(NameReceiverInfo.identifier); + } + else { + _isSelectAny = true; + } + + _spoutName.onChange([this]() { _isSpoutDirty = true; }); + owner.addProperty(_spoutName); + + _spoutSelection.onChange([this]() { + if (_spoutName.value().empty() && _spoutSelection.value() == 0) { + if (_spoutSelection.options().size() > 1) { + _spoutSelection = 1; + } + } + _spoutName = ""; + _spoutName = _spoutSelection.option().description; + }); + _spoutSelection.addOption(0, ""); + owner.addProperty(_spoutSelection); + + _updateSelection.onChange([this]() { + const std::vector receiverList = spoutReceiverList(); + + _spoutSelection.clearOptions(); + _spoutSelection.addOption(0, ""); + + int idx = 0; + for (int i = 0; i < static_cast(receiverList.size()); ++i) { + _spoutSelection.addOption(i + 1, receiverList[i]); + + LWARNING(fmt::format("List {}", receiverList[i])); + + if (!_isSelectAny && _spoutName.value() == receiverList[i]) { + idx = i + 1; + } + } + _spoutSelection = idx; + + }); + owner.addProperty(_updateSelection); + + _updateSelection.set(0); +} + +SpoutReceiverPropertyProxy::~SpoutReceiverPropertyProxy() {} + +bool SpoutReceiverPropertyProxy::updateReceiver() { + if (_isSpoutDirty) { + if (!updateReceiverName(_spoutName.value())) { + return false; + } + _isSpoutDirty = false; + } + return SpoutReceiver::updateReceiver(); +} + +void SpoutReceiverPropertyProxy::releaseReceiver() { + _isSpoutDirty = true; + SpoutReceiver::releaseReceiver(); +} + + +SpoutSender::SpoutSender() {} + +SpoutSender::~SpoutSender() {} + +bool SpoutSender::isCreated() const { + return _isCreated; +} + +bool SpoutSender::isSending() const { + return _isSending; +} + +bool SpoutSender::updateSenderStatus() { + if (!_isSending) { + if (_spoutWidth == 0 || _spoutHeight == 0) { + if (!_isErrorMessageDisplayed) { + LWARNING(fmt::format( + "Could not create sender for {}, dimensions invalid {}x{}", + _currentSpoutName, _spoutWidth, _spoutHeight + )); + _isErrorMessageDisplayed = true; + } + return false; + } + + if (_currentSpoutName.empty()) { + if (!_isErrorMessageDisplayed) { + LWARNING(fmt::format("Could not create sender, invalid name")); + _isErrorMessageDisplayed = true; + } + return false; + } + + ghoul_assert(_currentSpoutName.size() < 256, "Spout name must be < 256"); + char name[256] = { 0 }; + std::memcpy(name, _currentSpoutName.data(), _currentSpoutName.size()); + + bool hasCreated = _spoutHandle->CreateSender(name, _spoutWidth, _spoutHeight); + if (!hasCreated) { + if (!_isErrorMessageDisplayed) { + LWARNING(fmt::format( + "Could not create sender for {} -> {}x{}", + _currentSpoutName, _spoutWidth, _spoutHeight + )); + _isErrorMessageDisplayed = true; + } + return false; + } + } + + _isErrorMessageDisplayed = false; + _isSending = true; + + return true; +} + +bool SpoutSender::updateSender(unsigned int texture, unsigned int textureType) { + if (!_spoutHandle || !updateSenderStatus()) { + return false; + } + + _spoutHandle->SendTexture(texture, textureType, _spoutWidth, _spoutHeight); + + if (_onUpdateSenderCallback) { + bool s = _onUpdateSenderCallback( + _currentSpoutName, + texture, + textureType, + _spoutWidth, + _spoutHeight + ); + if (!s) { + return false; + } + } + + return true; +} + +bool SpoutSender::updateSenderName(const std::string& name) { + if (!_spoutHandle) { + return false; + } + if (name == _currentSpoutName) { + return true; + } + + releaseSender(); + + if (_onUpdateSenderNameCallback) { + if (!_onUpdateSenderNameCallback(name)) { + return false; + } + } + + _currentSpoutName = name; + _isCreated = true; + + return true; +} + +bool SpoutSender::updateSenderSize(int width, int height) { + if (!_spoutHandle) { + return false; + } + if (width == static_cast(_spoutWidth) && + height == static_cast(_spoutHeight)) + { + return true; + } + + releaseSender(); + + if (_onUpdateSenderSizeCallback) { + if (!_onUpdateSenderSizeCallback(width, height)) { + return false; + } + } + + _spoutWidth = width; + _spoutHeight = height; + _isCreated = true; + + return true; +} + +void SpoutSender::releaseSender() { + if (!_isSending) { + return; + } + + _isCreated = false; + _isSending = false; + _isErrorMessageDisplayed = false; + _currentSpoutName.clear(); + _spoutWidth = 0; + _spoutHeight = 0; + if (_onReleaseSenderCallback) { + _onReleaseSenderCallback(); + } + if (_spoutHandle) { + _spoutHandle->ReleaseReceiver(); + } +} + +void SpoutSender::release() { + releaseSender(); + SpoutMain::release(); +} + +void SpoutSender::onUpdateSenderName(std::function callback) { + _onUpdateSenderNameCallback = std::move(callback); +} + +void SpoutSender::onUpdateSenderSize(std::function callback) { + _onUpdateSenderSizeCallback = std::move(callback); +} + +void SpoutSender::onUpdateSender(std::function callback) +{ + _onUpdateSenderCallback = std::move(callback); +} + +void SpoutSender::onReleaseSender(std::function callback) { + _onReleaseSenderCallback = std::move(callback); +} + +const properties::Property::PropertyInfo& SpoutSenderPropertyProxy::NameInfoProperty() { + return NameSenderInfo; +} + +SpoutSenderPropertyProxy::SpoutSenderPropertyProxy(properties::PropertyOwner& owner, + const ghoul::Dictionary& dictionary) + : _spoutName(NameSenderInfo) +{ + if (dictionary.hasKey(NameSenderInfo.identifier)) { + _spoutName = dictionary.value(NameSenderInfo.identifier); + } + else { + LWARNING(fmt::format("Sender does not have a name")); + } + + _spoutName.onChange([this]() { _isSpoutDirty = true; }); + owner.addProperty(_spoutName); +} + +SpoutSenderPropertyProxy::~SpoutSenderPropertyProxy() {} + +bool SpoutSenderPropertyProxy::updateSender(unsigned int texture, + unsigned int textureType) +{ + if (_isSpoutDirty) { + if (!updateSenderName(_spoutName)) { + return false; + } + _isSpoutDirty = false; + } + return SpoutSender::updateSender(texture, textureType); +} + +void SpoutSenderPropertyProxy::releaseSender() { + _isSpoutDirty = true; + SpoutSender::releaseSender(); +} + +} // namespace openspace::spout diff --git a/modules/spout/spoutwrapper.h b/modules/spout/spoutwrapper.h new file mode 100644 index 0000000000..db315cccd3 --- /dev/null +++ b/modules/spout/spoutwrapper.h @@ -0,0 +1,190 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2022 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_SPOUT___SPOUTWRAPPER___H__ +#define __OPENSPACE_MODULE_SPOUT___SPOUTWRAPPER___H__ + +#include +#include +#include +#include +#include +#include + +struct SPOUTLIBRARY; +typedef SPOUTLIBRARY* SPOUTHANDLE; + +namespace ghoul::opengl { class Texture; } + +namespace openspace::spout { + +// @TODO(abock, 2022-03-02) This class should probably be outsourced into a stand-alone +// library that the SGCT version of this class then can also use +class SpoutMain { +public: + SpoutMain(); + virtual ~SpoutMain(); + + virtual void release(); + + void saveGLState(); + void restoreGLState(); + + void saveGLTextureState(); + void restoreGLTextureState(); + +protected: + unsigned int _defaultTexture; + unsigned int _defaultFBO; + unsigned int _defaultReadFBO; + unsigned int _defaultDrawFBO; + unsigned int _defaultReadBuffer; + unsigned int _defaultDrawBuffer[1] = { 0 }; + + SPOUTHANDLE _spoutHandle = nullptr; + + std::string _currentSpoutName; + unsigned int _spoutWidth = 0; + unsigned int _spoutHeight = 0; +}; + +class SpoutReceiver : public SpoutMain { +public: + SpoutReceiver(); + virtual ~SpoutReceiver(); + + void release() override; + + virtual bool updateReceiverName(const std::string& name); + virtual bool updateReceiver(); + virtual void releaseReceiver(); + + void onUpdateReceiverName(std::function callback); + void onUpdateReceiver(std::function callback); + void onReleaseReceiver(std::function callback); + void onUpdateTexture(std::function callback); + void onReleaseTexture(std::function callback); + + const std::vector& spoutReceiverList(); + bool isCreated() const; + bool isReceiving() const; + unsigned int spoutTexture() const; + +private: + bool updateTexture(unsigned int width, unsigned int height); + void releaseTexture(); + + bool _isErrorMessageDisplayed = false; + bool _isCreated = false; + bool _isReceiving = false; + std::vector _receiverList; + + std::unique_ptr _spoutTexture; + + std::function _onUpdateReceiverNameCallback = nullptr; + std::function _onUpdateReceiverCallback = nullptr; + std::function _onReleaseReceiverCallback = nullptr; + std::function _onUpdateTextureCallback = nullptr; + std::function _onReleaseTextureCallback = nullptr; +}; + + +class SpoutReceiverPropertyProxy : public SpoutReceiver { +public: + static const properties::Property::PropertyInfo& NameInfoProperty(); + static const properties::Property::PropertyInfo& SelectionInfoProperty(); + static const properties::Property::PropertyInfo& UpdateInfoProperty(); + + SpoutReceiverPropertyProxy(properties::PropertyOwner& owner, + const ghoul::Dictionary& dictionary); + virtual ~SpoutReceiverPropertyProxy(); + + bool updateReceiver() override; + void releaseReceiver() override; + +private: + properties::StringProperty _spoutName; + properties::OptionProperty _spoutSelection; + properties::TriggerProperty _updateSelection; + + bool _isSpoutDirty = true; + bool _isSelectAny = false; +}; + + +class SpoutSender : public SpoutMain { +public: + SpoutSender(); + virtual ~SpoutSender(); + + void release() override; + + virtual bool updateSenderName(const std::string& name); + virtual bool updateSenderSize(int width, int height); + virtual bool updateSender(unsigned int texture, unsigned int textureType); + virtual void releaseSender(); + + void onUpdateSenderName(std::function callback); + void onUpdateSenderSize(std::function callback); + void onUpdateSender(std::function callback); + void onReleaseSender(std::function callback); + + bool isCreated() const; + bool isSending() const; + +private: + bool updateSenderStatus(); + + bool _isErrorMessageDisplayed = false; + bool _isCreated = false; + bool _isSending = false; + + std::function _onUpdateSenderNameCallback = nullptr; + std::function _onUpdateSenderSizeCallback = nullptr; + std::function _onUpdateSenderCallback = nullptr; + std::function _onReleaseSenderCallback = nullptr; +}; + +class SpoutSenderPropertyProxy : public SpoutSender { +public: + static const properties::Property::PropertyInfo& NameInfoProperty(); + + SpoutSenderPropertyProxy(properties::PropertyOwner& owner, + const ghoul::Dictionary& dictionary); + virtual ~SpoutSenderPropertyProxy(); + + bool updateSender(unsigned int texture, unsigned int textureType) override; + void releaseSender() override; + +private: + properties::StringProperty _spoutName; + + bool _isSpoutDirty = true; +}; + +} // namespace openspace::spout + +#endif // __OPENSPACE_MODULE_SPOUT___SPOUTWRAPPER___H__ diff --git a/openspace.cfg b/openspace.cfg index 9be037a435..862f9f5c27 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -20,31 +20,44 @@ SGCTConfig = sgct.config.single{vsync=false} -- Streaming OpenSpace via Spout to OBS -- SGCTConfig = sgct.config.single{2560, 1440, shared=true, name="WV_OBS_SPOUT1"} ---for more details about sgct configuration options see: +-- Elumenati Configs +-- SGCTConfig = "${CONFIG}/spout_output_flat.json" +-- SGCTConfig = "${CONFIG}/spout_output_cubemap.json" +-- SGCTConfig = "${CONFIG}/spout_output_equirectangular.json" +-- SGCTConfig = "${CONFIG}/spout_output_fisheye.json" + +-- for more details about sgct configuration options see: -- https://sgct.github.io/configuration-files.html -- To use a sgct configuration file set the variable like below -- SGCTConfig = "${CONFIG}/single_gui.xml" -- In the config/ folder we provide the some predefined files which you can modify. --- fullscreen1080.xml: fullscreen window at 1920x1080 --- gui_projector.xml: one window for the gui and a second fullscreen window for rendering +-- fullscreen1080.json: fullscreen window at 1920x1080 +-- gui_projector.json: one window for the gui and a second fullscreen window for rendering -- on the second monitor --- openvr_htcVive.xml: window for VR on HTC Vive, only works if OpenSpace is compiled +-- openvr_htcVive.json: window for VR on HTC Vive, only works if OpenSpace is compiled -- custom with the openvr support --- openvr_oculusRiftCv1.xml: window for VR on Oculus Rift, only works if OpenSpace is +-- openvr_oculusRiftCv1.json: window for VR on Oculus Rift, only works if OpenSpace is -- compiled custom with the openvr support --- single.xml: regular window --- single_fisheye.xml: regular window with fisheye rendering --- single_fisheye_gui.xml: one window for the gui, one window for fisheye rendering --- single_gui.xml: one window for the gui, one window for rendering --- single_sbs_stereo.xml: one window with side by side rendering for stereo/3d support --- single_two_win.xml: two windows with gui and rendering --- spherical_mirror.xml: one window with a spherical mirror rendering --- spherical_mirror_gui.xml: one window for the gui, and one window with a spherical +-- single.json: regular window +-- single_fisheye.json: regular window with fisheye rendering +-- single_fisheye_gui.json: one window for the gui, one window for fisheye rendering +-- single_gui.json: one window for the gui, one window for rendering +-- single_sbs_stereo.json: one window with side by side rendering for stereo/3d support +-- single_two_win.json: two windows with gui and rendering +-- spherical_mirror.json: one window with a spherical mirror rendering +-- spherical_mirror_gui.json: one window for the gui, and one window with a spherical -- mirror rendering --- spout_out.xml: a window where the rendering is sent to spout instead of the display --- two_nodes.xml: a configuration for running two instances of openspace, used for +-- two_nodes.json: a configuration for running two instances of openspace, used for -- multiple projection systems +-- spout_output_flat.json: a window where the rendering is sent to spout instead of the +-- display +-- spout_output_cubemap.json: a window where the rendering is sent to spout (max of 6 spout +-- instances) instead of the display +-- spout_output_equirectangular.json: a window where the rendering is sent to spout +-- (equirectangular output) instead of the display +-- spout_output_fisheye.json: a window where the rendering is sent to spout (fisheye +-- output) instead of the display -- Variable: Profile -- Sets the profile that should be loaded by OpenSpace. From 235e37d2e660def301a33fe5eaf367240720f296 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Fri, 4 Mar 2022 11:09:44 +0100 Subject: [PATCH 02/14] Add min/max values for ScreenSpacerenderable background color property --- src/rendering/screenspacerenderable.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index ea7fc6fbe3..55538725ed 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -343,7 +343,12 @@ ScreenSpaceRenderable::ScreenSpaceRenderable(const ghoul::Dictionary& dictionary ) , _scale(ScaleInfo, 0.25f, 0.f, 2.f) , _multiplyColor(MultiplyColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f)) - , _backgroundColor(BackgroundColorInfo) + , _backgroundColor( + BackgroundColorInfo, + glm::vec4(0.f), + glm::vec4(0.f), + glm::vec4(1.f) + ) , _opacity(OpacityInfo, 1.f, 0.f, 1.f) , _delete(DeleteInfo) { From 99714c14fc00916b3e5ad88855ca639941e47fe9 Mon Sep 17 00:00:00 2001 From: ElonOlsson Date: Mon, 7 Mar 2022 17:38:42 -0500 Subject: [PATCH 03/14] added monitor size argument of in taskRunner for function loadConfigurationfromFile because of function now taking 3 instead of 2 arguments. --- apps/TaskRunner/main.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/apps/TaskRunner/main.cpp b/apps/TaskRunner/main.cpp index 979da435a8..6fcc1b18ee 100644 --- a/apps/TaskRunner/main.cpp +++ b/apps/TaskRunner/main.cpp @@ -55,6 +55,9 @@ #include #include #include +#ifdef WIN32 +#include +#endif // WIN32 namespace { const std::string ConfigurationFile = "openspace.cfg"; @@ -127,8 +130,21 @@ int main(int argc, char** argv) { constexpr const char* BasePathToken = "${BASE}"; FileSys.registerPathToken(BasePathToken, base); + // Using same configuration for size as in apps/OpenSpace/main.cpp + glm::ivec2 size = glm::ivec2(1920, 1080); +#ifdef WIN32 + DEVMODEW dm = { 0 }; + dm.dmSize = sizeof(DEVMODEW); + BOOL success = EnumDisplaySettingsW(nullptr, ENUM_CURRENT_SETTINGS, &dm); + if (success) { + size.x = dm.dmPelsWidth; + size.y = dm.dmPelsHeight; + } +#endif // WIN32 + *global::configuration = configuration::loadConfigurationFromFile( configFile.string(), + size, "" ); openspace::global::openSpaceEngine->registerPathTokens(); From c8753faee1c756f3ce30f1247c79fe82340d14bc Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 11 Mar 2022 01:41:20 +0100 Subject: [PATCH 04/14] Fix correct Radii for Bianca moon of Uranus --- data/assets/scene/solarsystem/planets/uranus/inner_moons.asset | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/assets/scene/solarsystem/planets/uranus/inner_moons.asset b/data/assets/scene/solarsystem/planets/uranus/inner_moons.asset index cfbc96be7f..445962443e 100644 --- a/data/assets/scene/solarsystem/planets/uranus/inner_moons.asset +++ b/data/assets/scene/solarsystem/planets/uranus/inner_moons.asset @@ -59,7 +59,7 @@ local innerMoons = { Spice = parentSpice }, Spice = "BIANCA", - Radii = { 51000, 51000, 51000 }, + Radii = { 64000, 46000, 46000 }, Tags = tags, TrailTags = trailTags, GUI = { From 4e45f6634d4913142b3a625dffc4020377cb2ae4 Mon Sep 17 00:00:00 2001 From: Emma Broman Date: Tue, 15 Mar 2022 10:06:24 +0100 Subject: [PATCH 05/14] Add helper function and timer to trigger idle behavior (#1898) * Format property infos in orbital navigator more consistently * Add helper function to trigger an idle behavior (issue #1833) * Add timer to start idle behavior when camera is idle (issue #1730) --- .../openspace/navigation/orbitalnavigator.h | 41 ++-- src/navigation/navigationhandler.cpp | 7 + src/navigation/navigationhandler_lua.inl | 16 ++ src/navigation/orbitalnavigator.cpp | 203 +++++++++++++----- 4 files changed, 201 insertions(+), 66 deletions(-) diff --git a/include/openspace/navigation/orbitalnavigator.h b/include/openspace/navigation/orbitalnavigator.h index 01150b1d4c..11333623c4 100644 --- a/include/openspace/navigation/orbitalnavigator.h +++ b/include/openspace/navigation/orbitalnavigator.h @@ -57,6 +57,26 @@ class KeyboardInputState; class OrbitalNavigator : public properties::PropertyOwner { public: + struct IdleBehavior : public properties::PropertyOwner { + enum class Behavior { + Orbit = 0, + OrbitAtConstantLat, + OrbitAroundUp + }; + + IdleBehavior(); + + properties::BoolProperty apply; + properties::BoolProperty shouldTriggerWhenIdle; + properties::FloatProperty idleWaitTime; + properties::BoolProperty abortOnCameraInteraction; + properties::FloatProperty speedScale; + properties::FloatProperty dampenInterpolationTime; + + properties::OptionProperty defaultBehavior; + std::optional chosenBehavior = std::nullopt; + }; + OrbitalNavigator(); void updateStatesFromInput(const MouseInputState& mouseInputState, @@ -72,6 +92,9 @@ public: */ void updateOnCameraInteraction(); + void tickIdleBehaviorTimer(double deltaTime); + void triggerIdleBehavior(std::string_view choice = ""); + Camera* camera() const; void setCamera(Camera* camera); void clearPreviousState(); @@ -191,22 +214,8 @@ private: Interpolator _idleBehaviorDampenInterpolator; bool _invertIdleBehaviorInterpolation = false; - struct IdleBehavior : public properties::PropertyOwner { - enum Behavior { - Orbit = 0, - OrbitAtConstantLat, - OrbitAroundUp - }; - - IdleBehavior(); - - properties::BoolProperty apply; - properties::OptionProperty chosenBehavior; - properties::FloatProperty speedScale; - properties::BoolProperty abortOnCameraInteraction; - properties::FloatProperty dampenInterpolationTime; - }; IdleBehavior _idleBehavior; + float _idleBehaviorTriggerTimer = 0.f; /** * Decomposes the camera's rotation in to a global and a local rotation defined by @@ -344,6 +353,8 @@ private: SurfacePositionHandle calculateSurfacePositionHandle(const SceneGraphNode& node, const glm::dvec3 cameraPositionWorldSpace); + void resetIdleBehavior(); + /** * Apply the currently selected idle behavior to the position and rotations */ diff --git a/src/navigation/navigationhandler.cpp b/src/navigation/navigationhandler.cpp index 39aa4bbf65..98c2114fb1 100644 --- a/src/navigation/navigationhandler.cpp +++ b/src/navigation/navigationhandler.cpp @@ -737,6 +737,13 @@ scripting::LuaLibrary NavigationHandler::luaLibrary() { &luascriptfunctions::addGlobalRoll, "double, double", "Directly adds to the global roll of the camera" + }, + { + "triggerIdleBehavior", + &luascriptfunctions::triggerIdleBehavior, + "[string]", + "Immediately start applying the chosen IdleBehavior. If none is " + "specified, use the one set to default in the OrbitalNavigator." } } }; diff --git a/src/navigation/navigationhandler_lua.inl b/src/navigation/navigationhandler_lua.inl index 9ffad40a02..afc2f3e6fc 100644 --- a/src/navigation/navigationhandler_lua.inl +++ b/src/navigation/navigationhandler_lua.inl @@ -343,4 +343,20 @@ int addGlobalRoll(lua_State* L) { return 0; } +int triggerIdleBehavior(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, {0, 1}, "lua::triggerIdleBehavior"); + std::optional choice = ghoul::lua::value>(L); + + try { + global::navigationHandler->orbitalNavigator().triggerIdleBehavior( + choice.value_or("") + ); + } + catch (ghoul::RuntimeError& e) { + return ghoul::lua::luaError(L, e.message); + } + + return 0; +} + } // namespace openspace::luascriptfunctions diff --git a/src/navigation/orbitalnavigator.cpp b/src/navigation/orbitalnavigator.cpp index 16a1f06bda..d47cc89159 100644 --- a/src/navigation/orbitalnavigator.cpp +++ b/src/navigation/orbitalnavigator.cpp @@ -23,6 +23,7 @@ ****************************************************************************************/ #include +#include #include #include #include @@ -159,26 +160,29 @@ namespace { }; constexpr openspace::properties::Property::PropertyInfo - StereoInterpolationTimeInfo = { - "StereoInterpolationTime", - "Stereo Interpolation Time", - "The time to interpolate to a new stereoscopic depth " - "when the anchor node is changed, in seconds." + StereoInterpolationTimeInfo = + { + "StereoInterpolationTime", + "Stereo Interpolation Time", + "The time to interpolate to a new stereoscopic depth " + "when the anchor node is changed, in seconds." }; constexpr openspace::properties::Property::PropertyInfo - RetargetInterpolationTimeInfo = { - "RetargetAnchorInterpolationTime", - "Retarget Interpolation Time", - "The time to interpolate the camera rotation " - "when the anchor or aim node is changed, in seconds." + RetargetInterpolationTimeInfo = + { + "RetargetAnchorInterpolationTime", + "Retarget Interpolation Time", + "The time to interpolate the camera rotation " + "when the anchor or aim node is changed, in seconds." }; constexpr openspace::properties::Property::PropertyInfo - FollowRotationInterpTimeInfo = { - "FollowRotationInterpolationTime", - "Follow Rotation Interpolation Time", - "The interpolation time when toggling following focus node rotation." + FollowRotationInterpTimeInfo = + { + "FollowRotationInterpolationTime", + "Follow Rotation Interpolation Time", + "The interpolation time when toggling following focus node rotation." }; constexpr openspace::properties::Property::PropertyInfo InvertMouseButtons = { @@ -190,31 +194,34 @@ namespace { }; constexpr openspace::properties::Property::PropertyInfo - UseAdaptiveStereoscopicDepthInfo = { - "UseAdaptiveStereoscopicDepth", - "Adaptive Steroscopic Depth", - "Dynamically adjust the view scaling based on the distance to the surface of " - "the anchor and aim nodes. If enabled, view scale will be set to " - "StereoscopicDepthOfFocusSurface / min(anchorDistance, aimDistance). " - "If disabled, view scale will be set to 10^StaticViewScaleExponent." - }; + UseAdaptiveStereoscopicDepthInfo = + { + "UseAdaptiveStereoscopicDepth", + "Adaptive Steroscopic Depth", + "Dynamically adjust the view scaling based on the distance to the surface of " + "the anchor and aim nodes. If enabled, view scale will be set to " + "StereoscopicDepthOfFocusSurface / min(anchorDistance, aimDistance). " + "If disabled, view scale will be set to 10^StaticViewScaleExponent." + }; constexpr openspace::properties::Property::PropertyInfo - StaticViewScaleExponentInfo = { - "StaticViewScaleExponent", - "Static View Scale Exponent", - "Statically scale the world by 10^StaticViewScaleExponent. " - "Only used if UseAdaptiveStereoscopicDepthInfo is set to false." - }; + StaticViewScaleExponentInfo = + { + "StaticViewScaleExponent", + "Static View Scale Exponent", + "Statically scale the world by 10^StaticViewScaleExponent. " + "Only used if UseAdaptiveStereoscopicDepthInfo is set to false." + }; constexpr openspace::properties::Property::PropertyInfo - StereoscopicDepthOfFocusSurfaceInfo = { - "StereoscopicDepthOfFocusSurface", - "Stereoscopic Depth of the Surface in Focus", - "Set the stereoscopically perceived distance (in meters) to the closest " - "point out of the surface of the anchor and the center of the aim node. " - "Only used if UseAdaptiveStereoscopicDepthInfo is set to true." - }; + StereoscopicDepthOfFocusSurfaceInfo = + { + "StereoscopicDepthOfFocusSurface", + "Stereoscopic Depth of the Surface in Focus", + "Set the stereoscopically perceived distance (in meters) to the closest " + "point out of the surface of the anchor and the center of the aim node. " + "Only used if UseAdaptiveStereoscopicDepthInfo is set to true." + }; constexpr openspace::properties::Property::PropertyInfo ApplyIdleBehaviorInfo = { "ApplyIdleBehavior", @@ -230,6 +237,22 @@ namespace { "applied. Each option represents a predefined camera behavior." }; + constexpr openspace::properties::Property::PropertyInfo + ShouldTriggerIdleBehaviorWhenIdleInfo = + { + "ShouldTriggerWhenIdle", + "Should Trigger When Idle", + "If true, the chosen idle behavior will trigger automatically after " + "a certain time (see 'IdleWaitTime' property)." + }; + + constexpr openspace::properties::Property::PropertyInfo IdleWaitTimeInfo = { + "IdleWaitTime", + "Idle Wait Time", + "The time (seconds) until idle behavior starts, if no camera interaction " + "has been performed. Note that friction counts as camera interaction." + }; + constexpr openspace::properties::Property::PropertyInfo IdleBehaviorSpeedInfo = { "SpeedFactor", "Speed Factor", @@ -238,7 +261,8 @@ namespace { }; constexpr openspace::properties::Property::PropertyInfo - AbortOnCameraInteractionInfo = { + AbortOnCameraInteractionInfo = + { "AbortOnCameraInteraction", "Abort on Camera Interaction", "If set to true, the idle behavior is aborted on camera interaction. If false, " @@ -248,12 +272,18 @@ namespace { }; constexpr openspace::properties::Property::PropertyInfo - IdleBehaviorDampenInterpolationTimeInfo = { + IdleBehaviorDampenInterpolationTimeInfo = + { "DampenInterpolationTime", "Start/End Dampen Interpolation Time", "The time to interpolate to/from full speed when an idle behavior is triggered " "or canceled, in seconds." }; + + constexpr const char IdleKeyOrbit[] = "Orbit"; + constexpr const char IdleKeyOrbitAtConstantLat[] = "OrbitAtConstantLatitude"; + constexpr const char IdleKeyOrbitAroundUp[] = "OrbitAroundUp"; + } // namespace namespace openspace::interaction { @@ -274,19 +304,25 @@ OrbitalNavigator::Friction::Friction() OrbitalNavigator::IdleBehavior::IdleBehavior() : properties::PropertyOwner({ "IdleBehavior" }) , apply(ApplyIdleBehaviorInfo, false) - , chosenBehavior(IdleBehaviorInfo) + , defaultBehavior(IdleBehaviorInfo) + , shouldTriggerWhenIdle(ShouldTriggerIdleBehaviorWhenIdleInfo, false) + , idleWaitTime(IdleWaitTimeInfo, 5.f, 0.f, 3600.f) , speedScale(IdleBehaviorSpeedInfo, 1.f, 0.01f, 5.f) , abortOnCameraInteraction(AbortOnCameraInteractionInfo, true) , dampenInterpolationTime(IdleBehaviorDampenInterpolationTimeInfo, 0.5f, 0.f, 10.f) { addProperty(apply); - chosenBehavior.addOptions({ - { IdleBehavior::Behavior::Orbit, "Orbit" }, - { IdleBehavior::Behavior::OrbitAtConstantLat, "OrbitAtConstantLatitude" }, - { IdleBehavior::Behavior::OrbitAroundUp, "OrbitAroundUp" } + using Behavior = IdleBehavior::Behavior; + defaultBehavior.addOptions({ + { static_cast(Behavior::Orbit), IdleKeyOrbit }, + { static_cast(Behavior::OrbitAtConstantLat), IdleKeyOrbitAtConstantLat }, + { static_cast(Behavior::OrbitAroundUp), IdleKeyOrbitAroundUp } }); - chosenBehavior = IdleBehavior::Behavior::Orbit; - addProperty(chosenBehavior); + defaultBehavior = static_cast(IdleBehavior::Behavior::Orbit); + addProperty(defaultBehavior); + addProperty(shouldTriggerWhenIdle); + addProperty(idleWaitTime); + idleWaitTime.setExponent(2.2f); addProperty(speedScale); addProperty(abortOnCameraInteraction); addProperty(dampenInterpolationTime); @@ -454,6 +490,13 @@ OrbitalNavigator::OrbitalNavigator() _idleBehavior.dampenInterpolationTime ); }); + _idleBehavior.shouldTriggerWhenIdle.onChange([&]() { + _idleBehaviorTriggerTimer = _idleBehavior.idleWaitTime; + }); + _idleBehavior.idleWaitTime.onChange([&]() { + _idleBehaviorTriggerTimer = _idleBehavior.idleWaitTime; + }); + addProperty(_anchor); addProperty(_aim); addProperty(_retargetAnchor); @@ -530,6 +573,9 @@ void OrbitalNavigator::updateStatesFromInput(const MouseInputState& mouseInputSt if (interactionHappened) { updateOnCameraInteraction(); } + else { + tickIdleBehaviorTimer(deltaTime); + } } void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) { @@ -699,7 +745,8 @@ void OrbitalNavigator::updateCameraScalingFromAnchor(double deltaTime) { _currentCameraToSurfaceDistance = interpolateCameraToSurfaceDistance( deltaTime, _currentCameraToSurfaceDistance, - targetCameraToSurfaceDistance); + targetCameraToSurfaceDistance + ); } _camera->setScaling( @@ -715,9 +762,19 @@ void OrbitalNavigator::updateCameraScalingFromAnchor(double deltaTime) { void OrbitalNavigator::updateOnCameraInteraction() { // Disable idle behavior if camera interaction happened if (_idleBehavior.apply && _idleBehavior.abortOnCameraInteraction) { - _idleBehavior.apply = false; - // Prevent interpolating stop, to avoid weirdness when changing anchor, etc - _idleBehaviorDampenInterpolator.setInterpolationTime(0.f); + resetIdleBehavior(); + } +} + +void OrbitalNavigator::tickIdleBehaviorTimer(double deltaTime) { + if (!_idleBehavior.shouldTriggerWhenIdle) { + return; + } + if (_idleBehaviorTriggerTimer > 0.f) { + _idleBehaviorTriggerTimer -= static_cast(deltaTime); + } + else { + triggerIdleBehavior(); } } @@ -1502,6 +1559,49 @@ const ScriptCameraStates& OrbitalNavigator::scriptStates() const { return _scriptStates; } +void OrbitalNavigator::triggerIdleBehavior(std::string_view choice) { + OpenSpaceEngine::Mode mode = global::openSpaceEngine->currentMode(); + if (mode != OpenSpaceEngine::Mode::UserControl) { + LERROR( + "Could not start idle behavior. The camera is being controlled " + "by some other part of the system" + ); + return; + } + + if (choice.empty()) { + _idleBehavior.chosenBehavior = std::nullopt; + } + else { + IdleBehavior::Behavior behavior; + if (choice == IdleKeyOrbit) { + behavior = IdleBehavior::Behavior::Orbit; + } + else if (choice == IdleKeyOrbitAtConstantLat) { + behavior = IdleBehavior::Behavior::OrbitAtConstantLat; + } + else if (choice == IdleKeyOrbitAroundUp) { + behavior = IdleBehavior::Behavior::OrbitAroundUp; + } + else { + throw ghoul::RuntimeError( + fmt::format("No existing IdleBehavior with identifier '{}'", choice) + ); + } + _idleBehavior.chosenBehavior = behavior; + } + + _idleBehavior.apply = true; +} + +void OrbitalNavigator::resetIdleBehavior() { + _idleBehavior.apply = false; + _idleBehavior.chosenBehavior = std::nullopt; + // Prevent interpolating stop, to avoid weirdness when changing anchor, etc + _idleBehaviorDampenInterpolator.setInterpolationTime(0.f); + _idleBehaviorTriggerTimer = _idleBehavior.idleWaitTime; +} + void OrbitalNavigator::applyIdleBehavior(double deltaTime, glm::dvec3& position, glm::dquat& localRotation, glm::dquat& globalRotation) @@ -1541,10 +1641,11 @@ void OrbitalNavigator::applyIdleBehavior(double deltaTime, glm::dvec3& position, speedScale *= _invertIdleBehaviorInterpolation ? (1.0 - s) : s; // Apply the chosen behavior - const IdleBehavior::Behavior chosen = - static_cast(_idleBehavior.chosenBehavior.value()); + const IdleBehavior::Behavior choice = _idleBehavior.chosenBehavior.value_or( + static_cast(_idleBehavior.defaultBehavior.value()) + ); - switch (chosen) { + switch (choice) { case IdleBehavior::Behavior::Orbit: orbitAnchor(deltaTime, position, globalRotation, speedScale); break; From 18338942646b87c64cb45b0630fa47697d943c8a Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 18 Mar 2022 14:24:36 +0100 Subject: [PATCH 06/14] Only print the error for missing shadow caster once (closes #1594) --- .../rendering/atmospheredeferredcaster.cpp | 17 +++++++++++++---- .../atmosphere/rendering/renderableatmosphere.h | 4 ++++ support/coding/codegen | 2 +- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/modules/atmosphere/rendering/atmospheredeferredcaster.cpp b/modules/atmosphere/rendering/atmospheredeferredcaster.cpp index 1cbe1bfa44..40a3d9de4f 100644 --- a/modules/atmosphere/rendering/atmospheredeferredcaster.cpp +++ b/modules/atmosphere/rendering/atmospheredeferredcaster.cpp @@ -350,7 +350,7 @@ void AtmosphereDeferredcaster::preRaycast(const RenderData& data, const Deferred // Shadow calculations.. _shadowDataArrayCache.clear(); - for (const ShadowConfiguration& shadowConf : _shadowConfArray) { + for (ShadowConfiguration& shadowConf : _shadowConfArray) { // TO REMEMBER: all distances and lengths in world coordinates are in // meters!!! We need to move this to view space... double lt; @@ -374,10 +374,19 @@ void AtmosphereDeferredcaster::preRaycast(const RenderData& data, const Deferred casterPos *= KM_TO_M; // converting to meters SceneGraphNode* sourceNode = sceneGraphNode(shadowConf.source.first); + if (!sourceNode) { + if (!shadowConf.printedSourceError) { + LERROR("Invalid scenegraph node for the shadow's receiver"); + shadowConf.printedSourceError = true; + } + return; + } SceneGraphNode* casterNode = sceneGraphNode(shadowConf.caster.first); - - if (!sourceNode || !casterNode) { - LERROR("Invalid scenegraph node for the shadow's caster or receiver"); + if (!casterNode) { + if (!shadowConf.printedCasterError) { + LERROR("Invalid scenegraph node for the shadow's caster"); + shadowConf.printedCasterError = true; + } return; } diff --git a/modules/atmosphere/rendering/renderableatmosphere.h b/modules/atmosphere/rendering/renderableatmosphere.h index c5daf1e638..cbc40ac7b1 100644 --- a/modules/atmosphere/rendering/renderableatmosphere.h +++ b/modules/atmosphere/rendering/renderableatmosphere.h @@ -53,6 +53,10 @@ struct TransformData; struct ShadowConfiguration { std::pair source; std::pair caster; + // Set to 'true' if we printed an error because we couldn't find the source or caster. + // We only want to print a message once + bool printedSourceError = false; + bool printedCasterError = false; }; namespace documentation { struct Documentation; } diff --git a/support/coding/codegen b/support/coding/codegen index f511a93fdd..c6178634f7 160000 --- a/support/coding/codegen +++ b/support/coding/codegen @@ -1 +1 @@ -Subproject commit f511a93fddee9dda92d87408d2c7587bb63746b9 +Subproject commit c6178634f7e6bcdc62a67af08f315ee384d0227d From c80c30e8ff564daeff63aeb1be9927c320b3e6a5 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 18 Mar 2022 14:35:14 +0100 Subject: [PATCH 07/14] Update Ghoul to handle detection of AMD cards (closes #1907) --- ext/ghoul | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/ghoul b/ext/ghoul index 35995e3e78..e295fd85c5 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 35995e3e78e3a96021a3d551c75a952b0d6d00c9 +Subproject commit e295fd85c5842b66f9f14d76b44b6d48a368746e From 2d7e8f99679cd5e80ad2cda9be0a328d6d708467 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 18 Mar 2022 15:19:02 +0100 Subject: [PATCH 08/14] Pass information about the operating system to the version reporter script (#1865) --- ext/ghoul | 2 +- src/engine/openspaceengine.cpp | 9 +++++---- src/util/versionchecker.cpp | 19 ++++++++++++++++--- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/ext/ghoul b/ext/ghoul index e295fd85c5..8d85f42fc3 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit e295fd85c5842b66f9f14d76b44b6d48a368746e +Subproject commit 8d85f42fc313c6ef884dfbad96d2248859eb94c2 diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 6a136ec221..f65c2372fc 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -180,6 +180,10 @@ void OpenSpaceEngine::initialize() { LTRACE("OpenSpaceEngine::initialize(begin)"); global::initialize(); + // Initialize the general capabilities component + SysCap.addComponent( + std::make_unique() + ); _printEvents = global::configuration->isPrintingEvents; @@ -403,11 +407,8 @@ void OpenSpaceEngine::initializeGL() { glbinding::Binding::initialize(global::windowDelegate->openGLProcedureAddress); //glbinding::Binding::useCurrentContext(); - LDEBUG("Adding system components"); + LDEBUG("Adding OpenGL capabilities components"); // Detect and log OpenCL and OpenGL versions and available devices - SysCap.addComponent( - std::make_unique() - ); SysCap.addComponent( std::make_unique() ); diff --git a/src/util/versionchecker.cpp b/src/util/versionchecker.cpp index 23b0c21136..6d1af19e41 100644 --- a/src/util/versionchecker.cpp +++ b/src/util/versionchecker.cpp @@ -27,10 +27,12 @@ #include #include #include +#include +#include #include namespace { - constexpr const char* _loggerCat = "VersionChecker"; + constexpr const char _loggerCat[] = "VersionChecker"; } // namespace namespace openspace { @@ -40,9 +42,20 @@ VersionChecker::~VersionChecker() { } void VersionChecker::requestLatestVersion(const std::string& url) { + using GCC = ghoul::systemcapabilities::GeneralCapabilitiesComponent; + std::string operatingSystem = SysCap.component().operatingSystemString(); + + // Need to escape non-http characters when passing the operating system in the url + for (size_t i = 0; i < operatingSystem.size(); i++) { + if (operatingSystem[i] == ' ') { + operatingSystem.erase(i, 1); + operatingSystem.insert(i, "%20"); + } + } + std::string fullUrl = fmt::format( - "{}?client_version={}&commit_hash={}", - url, OPENSPACE_VERSION_NUMBER, OPENSPACE_GIT_COMMIT + "{}?client_version={}&commit_hash={}&operating_system={}", + url, OPENSPACE_VERSION_NUMBER, OPENSPACE_GIT_COMMIT, operatingSystem ); if (_request) { From f29dee2fe3814743a83d0563a457afb8a54637fb Mon Sep 17 00:00:00 2001 From: ElonOlsson Date: Mon, 14 Mar 2022 16:09:31 -0400 Subject: [PATCH 09/14] added user agent: OpenSpace, to http-request --- src/engine/downloadmanager.cpp | 2 +- src/util/httprequest.cpp | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/engine/downloadmanager.cpp b/src/engine/downloadmanager.cpp index cba5406d7d..80bc5b19fd 100644 --- a/src/engine/downloadmanager.cpp +++ b/src/engine/downloadmanager.cpp @@ -243,7 +243,7 @@ std::future DownloadManager::fetchFile( curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // NOLINT curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // NOLINT - // NOLINTNEXTLINE + curl_easy_setopt(curl, CURLOPT_USERAGENT, "OpenSpace"); // NOLINT curl_easy_setopt(curl, CURLOPT_WRITEDATA, reinterpret_cast(&file)); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeMemoryCallback); // NOLINT curl_easy_setopt(curl, CURLOPT_TIMEOUT, 5L); // NOLINT diff --git a/src/util/httprequest.cpp b/src/util/httprequest.cpp index 7abafaeb88..a32599f80c 100644 --- a/src/util/httprequest.cpp +++ b/src/util/httprequest.cpp @@ -58,6 +58,7 @@ bool HttpRequest::perform(std::chrono::milliseconds timeout) { } curl_easy_setopt(curl, CURLOPT_URL, _url.data()); + curl_easy_setopt(curl, CURLOPT_USERAGENT, "OpenSpace"); // NOLINT curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L); // The leading + in all of the lambda expressions are to cause an implicit conversion From 86dcff62c4563f958fbf3ff28e5511ea6f35daef Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Fri, 18 Mar 2022 15:50:01 +0100 Subject: [PATCH 10/14] Provide error message when loading a speckfile that does not contain only numbers (closes #1903) --- modules/space/speckloader.cpp | 17 +++++++++++++++++ src/scene/sceneinitializer.cpp | 7 ++++++- 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/modules/space/speckloader.cpp b/modules/space/speckloader.cpp index 8327ada08f..e973b55a60 100644 --- a/modules/space/speckloader.cpp +++ b/modules/space/speckloader.cpp @@ -315,10 +315,27 @@ Dataset loadFile(std::filesystem::path path, SkipAllZeroLines skipAllZeroLines) str >> entry.position.x >> entry.position.y >> entry.position.z; allZero &= (entry.position == glm::vec3(0.0)); + if (!str.good()) { + throw ghoul::RuntimeError(fmt::format( + "Error loading position information out of data line {} in file {}. " + "Value was not a number", + res.entries.size(), path + )); + } + entry.data.resize(nDataValues); for (int i = 0; i < nDataValues; i += 1) { str >> entry.data[i]; + bool isGood = str.good(); allZero &= (entry.data[i] == 0.0); + + if (!str.good()) { + throw ghoul::RuntimeError(fmt::format( + "Error loading data value {} out of data line {} in file {}. " + "Value was not a number", + i, res.entries.size(), path + )); + } } if (skipAllZeroLines && allZero) { diff --git a/src/scene/sceneinitializer.cpp b/src/scene/sceneinitializer.cpp index b1068e27a9..5e18a523ed 100644 --- a/src/scene/sceneinitializer.cpp +++ b/src/scene/sceneinitializer.cpp @@ -65,7 +65,12 @@ void MultiThreadedSceneInitializer::initializeNode(SceneGraphNode* node) { ); } - node->initialize(); + try { + node->initialize(); + } + catch (const ghoul::RuntimeError& e) { + LERRORC(e.component, e.message); + } std::lock_guard g(_mutex); _initializedNodes.push_back(node); _initializingNodes.erase(node); From 6f25dd31e540ddbaa9fae974ed676d5e7107565f Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Sat, 19 Mar 2022 13:56:16 +0100 Subject: [PATCH 11/14] Make the Sun asset export the Sun as a light source (closes #1870) --- data/assets/examples/animation.asset | 37 +---- data/assets/examples/approachevents.asset | 9 +- .../examples/modelshader/modelshader.asset | 9 +- .../milkyway/objects/orionnebula/nebula.asset | 43 +++--- .../missions/apollo/11/apollo11.asset | 23 +-- .../solarsystem/missions/apollo/11/lem.asset | 10 +- .../missions/apollo/15/apollo15.asset | 25 +--- .../missions/apollo/17/bouldersstation2.asset | 43 +++--- .../missions/apollo/17/bouldersstation6.asset | 43 +++--- .../missions/apollo/17/bouldersstation7.asset | 25 ++-- .../solarsystem/missions/apollo/17/lem.asset | 9 +- .../missions/apollo/8/launch_model.asset | 9 +- .../solarsystem/missions/apollo/8/model.asset | 9 +- .../solarsystem/missions/dawn/dawn.asset | 9 +- .../solarsystem/missions/gaia/gaia.asset | 9 +- .../solarsystem/missions/insight/edl.asset | 9 +- .../solarsystem/missions/juno/juno.asset | 9 +- .../solarsystem/missions/jwst/jwst.asset | 8 +- .../missions/messenger/messengerSC.asset | 61 +++++--- .../missions/newhorizons/model.asset | 9 +- .../missions/osirisrex/bennu.asset | 15 +- .../missions/osirisrex/model.asset | 43 +++--- .../missions/perseverance/model.asset | 25 ++-- .../missions/pioneer/pioneermodel.asset | 11 +- .../missions/rosetta/rosetta.asset | 132 ++++++++++++++---- .../missions/voyager/voyager1.asset | 33 ++--- .../missions/voyager/voyager2.asset | 33 ++--- .../planets/earth/satellites/misc/iss.asset | 9 +- data/assets/scene/solarsystem/sun/sun.asset | 8 ++ 29 files changed, 351 insertions(+), 366 deletions(-) diff --git a/data/assets/examples/animation.asset b/data/assets/examples/animation.asset index 5805b754aa..69a3b14451 100644 --- a/data/assets/examples/animation.asset +++ b/data/assets/examples/animation.asset @@ -1,4 +1,4 @@ -local sunTransforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local transforms = asset.require("scene/solarsystem/planets/earth/transforms") local model = asset.syncedResource({ @@ -27,12 +27,7 @@ local animationLoop = { AnimationStartTime = StartTime, ModelScale = 3E7, LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - } + sun.LightSource }, PerformShading = true, DisableFaceCulling = true @@ -61,12 +56,7 @@ local animationLoopInf = { AnimationStartTime = StartTime, ModelScale = 3E7, LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - } + sun.LightSource }, PerformShading = true, DisableFaceCulling = true @@ -95,12 +85,7 @@ local animationOnce = { AnimationStartTime = StartTime, ModelScale = 3E7, LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - } + sun.LightSource }, PerformShading = true, DisableFaceCulling = true @@ -129,12 +114,7 @@ local animationBounceInf = { AnimationStartTime = StartTime, ModelScale = 3E7, LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - } + sun.LightSource }, PerformShading = true, DisableFaceCulling = true @@ -163,12 +143,7 @@ local animationBounce = { AnimationStartTime = StartTime, ModelScale = 3E7, LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - } + sun.LightSource }, PerformShading = true, DisableFaceCulling = true diff --git a/data/assets/examples/approachevents.asset b/data/assets/examples/approachevents.asset index 90b049096f..ceac006790 100644 --- a/data/assets/examples/approachevents.asset +++ b/data/assets/examples/approachevents.asset @@ -1,4 +1,4 @@ -local sunTransforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local transforms = asset.require("scene/solarsystem/planets/earth/transforms") local generic_action = { @@ -34,12 +34,7 @@ local obj = { GeometryFile = model .. "BoxAnimated.glb", ModelScale = 1.0, LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - } + sun.LightSource }, PerformShading = true, DisableFaceCulling = true diff --git a/data/assets/examples/modelshader/modelshader.asset b/data/assets/examples/modelshader/modelshader.asset index 47042e7ac3..969d3521cb 100644 --- a/data/assets/examples/modelshader/modelshader.asset +++ b/data/assets/examples/modelshader/modelshader.asset @@ -1,4 +1,4 @@ -local sunTransforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local transforms = asset.require("scene/solarsystem/planets/earth/transforms") local model = asset.syncedResource({ @@ -22,12 +22,7 @@ local model = { GeometryFile = model .. "BoxAnimated.glb", ModelScale = 3E7, LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - } + sun.LightSource }, PerformShading = true, DisableFaceCulling = true, diff --git a/data/assets/scene/milkyway/objects/orionnebula/nebula.asset b/data/assets/scene/milkyway/objects/orionnebula/nebula.asset index 2c6bf0c8cd..87d64e3bb8 100644 --- a/data/assets/scene/milkyway/objects/orionnebula/nebula.asset +++ b/data/assets/scene/milkyway/objects/orionnebula/nebula.asset @@ -1,20 +1,6 @@ -local sunTransforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local transforms = asset.require("./transforms") -local LIGHTS = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, - { - Identifier = "Camera", - Type = "CameraLightSource", - Intensity = 0.5 - } -} - local sync = asset.syncedResource({ Name = "Orion Nebula Model", Type = "HttpSynchronization", @@ -77,7 +63,14 @@ local OrionNebulaModel = { DiffuseIntensity = 1.0, --PerformShading = false, RotationVector = { 0.000000, 22.300000, 0.000000 }, - LightSources = LIGHTS; + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Orion Nebula Model", @@ -105,7 +98,14 @@ local OrionNebulaShocksModel = { DiffuseIntensity = 1.0, --PerformShading = false, RotationVector = { 0.000000, 22.300000, 0.000000 }, - LightSources = LIGHTS; + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Orion Nebula Shocks", @@ -134,7 +134,14 @@ local OrionNebulaProplydsModel = { DiffuseIntensity = 1.0, --PerformShading = false, RotationVector = { 0.000000, 22.300000, 0.000000 }, - LightSources = LIGHTS; + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Orion Nebula Proplyds", diff --git a/data/assets/scene/solarsystem/missions/apollo/11/apollo11.asset b/data/assets/scene/solarsystem/missions/apollo/11/apollo11.asset index dae3c4e762..5612b1f75e 100644 --- a/data/assets/scene/solarsystem/missions/apollo/11/apollo11.asset +++ b/data/assets/scene/solarsystem/missions/apollo/11/apollo11.asset @@ -1,4 +1,4 @@ -local sun_transforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local moon_transforms = asset.require("scene/solarsystem/planets/earth/moon/moon") local descentKeyframes = asset.require("./lem_descent.asset") @@ -68,12 +68,7 @@ local Apollo11Model = { Type = "RenderableModel", GeometryFile = models .. "Apollo_CSM_shrunk_rotated_xy_double_size.obj", LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sun_transforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, + sun.LightSource, { Identifier = "Camera", Type = "CameraLightSource", @@ -197,12 +192,7 @@ local Apollo11LemDescentModel = { SpecularIntensity = 0.0, RotationVector = { 273.750,28.0,309.85 }, LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sun_transforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, + sun.LightSource, { Identifier = "Camera", Type = "CameraLightSource", @@ -235,12 +225,7 @@ local Apollo11LemLandedModel = { SpecularIntensity = 0.0, RotationVector = { 273.750,28.0,309.85 }, LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sun_transforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, + sun.LightSource, { Identifier = "Camera", Type = "CameraLightSource", diff --git a/data/assets/scene/solarsystem/missions/apollo/11/lem.asset b/data/assets/scene/solarsystem/missions/apollo/11/lem.asset index c49cc38245..9bd947fdaf 100644 --- a/data/assets/scene/solarsystem/missions/apollo/11/lem.asset +++ b/data/assets/scene/solarsystem/missions/apollo/11/lem.asset @@ -1,5 +1,4 @@ --- a11_lem.asset -local sun_transforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local moon_asset = asset.require("scene/solarsystem/planets/earth/moon/moon") @@ -43,12 +42,7 @@ local Apollo11LemModel = { GeometryFile = lem_model .. "LM-2_ver2clean.obj", RotationVector = { 91.044090, 171.229706, 111.666664 }, LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sun_transforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, + sun.LightSource, { Identifier = "Camera", Type = "CameraLightSource", diff --git a/data/assets/scene/solarsystem/missions/apollo/15/apollo15.asset b/data/assets/scene/solarsystem/missions/apollo/15/apollo15.asset index 2b5595e354..4623d140ce 100644 --- a/data/assets/scene/solarsystem/missions/apollo/15/apollo15.asset +++ b/data/assets/scene/solarsystem/missions/apollo/15/apollo15.asset @@ -1,5 +1,5 @@ local moon_transforms = asset.require("scene/solarsystem/planets/earth/moon/moon") -local sun_transforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") asset.require("spice/base") local models = asset.syncedResource({ @@ -19,22 +19,6 @@ local kernels = asset.require("scene/solarsystem/missions/apollo/15/kernels").ke -- Version = 1 -- }) -local LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sun_transforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, --- { --- Identifier = "Camera", --- Type = "CameraLightSource", --- Intensity = 0.5, --- Enabled = false --- } -} - - local Apollo15 = { Identifier = "Apollo15", Parent = moon_transforms.Moon.Identifier, @@ -57,12 +41,7 @@ local Apollo15 = { GeometryFile = models .. "ApolloCSM.osmodel", ModelScale = 0.0001, LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sun_transforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - } + sun.LightSource }, PerformShading = true, DisableFaceCulling = true diff --git a/data/assets/scene/solarsystem/missions/apollo/17/bouldersstation2.asset b/data/assets/scene/solarsystem/missions/apollo/17/bouldersstation2.asset index 3fe739e62c..ea4b2e8cb4 100644 --- a/data/assets/scene/solarsystem/missions/apollo/17/bouldersstation2.asset +++ b/data/assets/scene/solarsystem/missions/apollo/17/bouldersstation2.asset @@ -1,4 +1,4 @@ -local sun_transforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local moon_asset = asset.require("scene/solarsystem/planets/earth/moon/moon") local models = asset.syncedResource({ @@ -8,20 +8,6 @@ local models = asset.syncedResource({ Version = 2 }) -local LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sun_transforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, - { - Identifier = "Camera", - Type = "CameraLightSource", - Intensity = 0.5 - } -} - local Station2Boulder1Holder = { Identifier = "Station_2_Boulder1", Parent = moon_asset.Moon.Identifier, @@ -54,7 +40,14 @@ local Station2Boulder1Model = { Type = "RenderableModel", GeometryFile = models .. "b1-v2.obj", RotationVector = { 243.243256 ,206.270264, 309.677429 }, - LightSources = LightSources, + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + }, PerformShading = false, DisableFaceCulling = true }, @@ -96,7 +89,14 @@ local Station2Boulder2Model = { Type = "RenderableModel", GeometryFile = models .. "b2model.obj", RotationVector = { 66.162155, 7.783780, 114.193550 }, - LightSources = LightSources, + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + }, PerformShading = false, DisableFaceCulling = true }, @@ -138,7 +138,14 @@ local Station2Boulder3Model = { Type = "RenderableModel", GeometryFile = models .. "b3model.obj", RotationVector = { 161.513519 ,243.243256, 65.806450 }, - LightSources = LightSources, + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + }, PerformShading = false, DisableFaceCulling = true }, diff --git a/data/assets/scene/solarsystem/missions/apollo/17/bouldersstation6.asset b/data/assets/scene/solarsystem/missions/apollo/17/bouldersstation6.asset index 16f8218fa8..65683ec844 100644 --- a/data/assets/scene/solarsystem/missions/apollo/17/bouldersstation6.asset +++ b/data/assets/scene/solarsystem/missions/apollo/17/bouldersstation6.asset @@ -1,4 +1,4 @@ -local sun_transforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local moon_asset = asset.require("scene/solarsystem/planets/earth/moon/moon") local models = asset.syncedResource({ @@ -8,20 +8,6 @@ local models = asset.syncedResource({ Version = 2 }) -local LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sun_transforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, - { - Identifier = "Camera", - Type = "CameraLightSource", - Intensity = 0.5 - } -} - local Station6Frag1Holder = { Identifier = "Station_6_Fragment1", @@ -65,7 +51,14 @@ local Station6Frag1Model = { Type = "RenderableModel", GeometryFile = models .. "A17-S6-frag1.obj", RotationVector = { 235.909088,165.000000,286.299194 }, - LightSources = LightSources, + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + }, PerformShading = false, DisableFaceCulling = true }, @@ -108,7 +101,14 @@ local Station6Frag2Model = { Type = "RenderableModel", GeometryFile = models .. "station6_boulder_frag2.obj", RotationVector = { 336.959991,210.239990,325.984253 }, - LightSources = LightSources, + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + }, PerformShading = false, DisableFaceCulling = true, }, @@ -139,7 +139,14 @@ local Station6Frag3Model = { Type = "RenderableModel", GeometryFile = models .. "station6_boulder_frag3.obj", RotationVector = { 293.181824,255.000000,4.090910 }, - LightSources = LightSources, + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + }, PerformShading = false, DisableFaceCulling = true }, diff --git a/data/assets/scene/solarsystem/missions/apollo/17/bouldersstation7.asset b/data/assets/scene/solarsystem/missions/apollo/17/bouldersstation7.asset index 94c253e830..f9016a794c 100644 --- a/data/assets/scene/solarsystem/missions/apollo/17/bouldersstation7.asset +++ b/data/assets/scene/solarsystem/missions/apollo/17/bouldersstation7.asset @@ -1,4 +1,4 @@ -local sun_transforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local moon_asset = asset.require("scene/solarsystem/planets/earth/moon/moon") local models = asset.syncedResource({ @@ -8,20 +8,6 @@ local models = asset.syncedResource({ Version = 2 }) -local LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sun_transforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, - { - Identifier = "Camera", - Type = "CameraLightSource", - Intensity = 0.5 - } -} - local Station7BoulderHolder = { Identifier = "Station_7_Boulder", Parent = moon_asset.Moon.Identifier, @@ -54,7 +40,14 @@ local Station7BoulderModel = { Type = "RenderableModel", GeometryFile = models .. "b7model.obj", RotationVector = { 1.945950,274.378387,212.903214 }, - LightSources = LightSources, + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + }, PerformShading = false, DisableFaceCulling = true }, diff --git a/data/assets/scene/solarsystem/missions/apollo/17/lem.asset b/data/assets/scene/solarsystem/missions/apollo/17/lem.asset index d9d6c7b76e..ace02e3cfe 100644 --- a/data/assets/scene/solarsystem/missions/apollo/17/lem.asset +++ b/data/assets/scene/solarsystem/missions/apollo/17/lem.asset @@ -1,4 +1,4 @@ -local sun_transforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local moon_asset = asset.require("scene/solarsystem/planets/earth/moon/moon") local model = asset.syncedResource({ @@ -42,12 +42,7 @@ local Apollo17LemModel = { SpecularIntensity = 0.0, RotationVector = { 110.255219,171.229706,126.666664 }, LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sun_transforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, + sun.LightSource, { Identifier = "Camera", Type = "CameraLightSource", diff --git a/data/assets/scene/solarsystem/missions/apollo/8/launch_model.asset b/data/assets/scene/solarsystem/missions/apollo/8/launch_model.asset index a2844520ce..bc1f1af1d3 100644 --- a/data/assets/scene/solarsystem/missions/apollo/8/launch_model.asset +++ b/data/assets/scene/solarsystem/missions/apollo/8/launch_model.asset @@ -1,5 +1,5 @@ local earth_transforms = asset.require("scene/solarsystem/planets/earth/transforms") -local sun_transforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local kernels = asset.require("./kernels").kernels local models = asset.syncedResource({ @@ -53,12 +53,7 @@ local Apollo8LaunchModel = { GeometryFile = models .. "ApolloCSM.osmodel", ModelScale = 0.0001, LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sun_transforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - } + sun.LightSource }, PerformShading = true, DisableFaceCulling = true diff --git a/data/assets/scene/solarsystem/missions/apollo/8/model.asset b/data/assets/scene/solarsystem/missions/apollo/8/model.asset index 4d43b54084..95686fcc26 100644 --- a/data/assets/scene/solarsystem/missions/apollo/8/model.asset +++ b/data/assets/scene/solarsystem/missions/apollo/8/model.asset @@ -1,5 +1,5 @@ local earth_transforms = asset.require("scene/solarsystem/planets/earth/transforms") -local sun_transforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local kernels = asset.require("./kernels").kernels local models = asset.syncedResource({ @@ -65,12 +65,7 @@ local Apollo8Model = { GeometryFile = models .. "ApolloCSM.osmodel", ModelScale = 0.0001, LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sun_transforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - } + sun.LightSource }, PerformShading = true, DisableFaceCulling = true diff --git a/data/assets/scene/solarsystem/missions/dawn/dawn.asset b/data/assets/scene/solarsystem/missions/dawn/dawn.asset index 2a52df35f7..9bdc24141f 100644 --- a/data/assets/scene/solarsystem/missions/dawn/dawn.asset +++ b/data/assets/scene/solarsystem/missions/dawn/dawn.asset @@ -1,5 +1,5 @@ local transforms = asset.require("scene/solarsystem/sun/transforms") -local sunTransforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local kernels = asset.syncedResource({ @@ -622,12 +622,7 @@ local KernelFiles = { } local LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, + sun.LightSource, { Identifier = "Camera", Type = "CameraLightSource", diff --git a/data/assets/scene/solarsystem/missions/gaia/gaia.asset b/data/assets/scene/solarsystem/missions/gaia/gaia.asset index 8ca3f82004..b9965f122c 100644 --- a/data/assets/scene/solarsystem/missions/gaia/gaia.asset +++ b/data/assets/scene/solarsystem/missions/gaia/gaia.asset @@ -1,5 +1,5 @@ local transforms = asset.require("./transforms") -local sunTransforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local model = asset.syncedResource({ Name = "Gaia Model", @@ -32,12 +32,7 @@ local Gaia = { Body = "GAIA", GeometryFile = model .. "gaia.obj", LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 0.3 - }, + sun.LightSource, { Identifier = "Camera", Type = "CameraLightSource", diff --git a/data/assets/scene/solarsystem/missions/insight/edl.asset b/data/assets/scene/solarsystem/missions/insight/edl.asset index 94ce725f7c..98808ab58e 100644 --- a/data/assets/scene/solarsystem/missions/insight/edl.asset +++ b/data/assets/scene/solarsystem/missions/insight/edl.asset @@ -1,5 +1,5 @@ asset.require("spice/base") -local sunTransforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local mars = asset.require("scene/solarsystem/planets/mars/mars") local models = asset.syncedResource({ @@ -31,12 +31,7 @@ local RotationMatrix = { } local LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, + sun.LightSource, { Type = "SceneGraphLightSource", Identifier = "Mars", diff --git a/data/assets/scene/solarsystem/missions/juno/juno.asset b/data/assets/scene/solarsystem/missions/juno/juno.asset index 6436bcaaae..e20ef42013 100644 --- a/data/assets/scene/solarsystem/missions/juno/juno.asset +++ b/data/assets/scene/solarsystem/missions/juno/juno.asset @@ -1,5 +1,5 @@ local transforms = asset.require("scene/solarsystem/planets/jupiter/transforms") -local sunTransforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local model = asset.syncedResource({ @@ -152,12 +152,7 @@ local Juno = { GeometryFile = model .. "Juno.obj", ModelTransform = RotationMatrix, LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, + sun.LightSource, { Identifier = "Camera", Type = "CameraLightSource", diff --git a/data/assets/scene/solarsystem/missions/jwst/jwst.asset b/data/assets/scene/solarsystem/missions/jwst/jwst.asset index f50a15b2a9..58264b8d0e 100644 --- a/data/assets/scene/solarsystem/missions/jwst/jwst.asset +++ b/data/assets/scene/solarsystem/missions/jwst/jwst.asset @@ -1,3 +1,4 @@ +local sun = asset.require("scene/solarsystem/sun/sun") local sunTransforms = asset.require("scene/solarsystem/sun/transforms") local transforms = asset.require("./transforms") asset.require("spice/base") @@ -71,12 +72,7 @@ local JWSTModel = { AnimationTimeScale = "Millisecond", AnimationMode = "Once", LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - } + sun.LightSource }, PerformShading = true, DisableFaceCulling = true diff --git a/data/assets/scene/solarsystem/missions/messenger/messengerSC.asset b/data/assets/scene/solarsystem/missions/messenger/messengerSC.asset index eca89f4eff..7f8d7597f8 100644 --- a/data/assets/scene/solarsystem/missions/messenger/messengerSC.asset +++ b/data/assets/scene/solarsystem/missions/messenger/messengerSC.asset @@ -1,3 +1,4 @@ +local sun = asset.require("scene/solarsystem/sun/sun") local sunTransforms = asset.require("scene/solarsystem/sun/transforms") local mercuryTransforms = asset.require("scene/solarsystem/planets/mercury/transforms") @@ -56,21 +57,6 @@ local RotationMatrix = { 0, 1, 0 } - -local LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, - { - Identifier = "Camera", - Type = "CameraLightSource", - Intensity = 0.5 - } -} - local Messenger = { Identifier = "Messenger", Parent = sunTransforms.SolarSystemBarycenter.Identifier, @@ -105,7 +91,14 @@ local MessengerProbeBlack = { Type = "RenderableModel", GeometryFile = models .. "MessengerProbe_black.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "MessengerProbe Black", @@ -120,7 +113,14 @@ local MessengerProbeFoil = { Type = "RenderableModel", GeometryFile = models .. "MessengerProbe_foil.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "MessengerProbe foil", @@ -135,7 +135,14 @@ local MessengerProbeHeatShield = { Type = "RenderableModel", GeometryFile = models .. "MessengerProbe_heatShield.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "MessengerProbe Heat Sheild", @@ -150,7 +157,14 @@ local MessengerProbeMetal = { Type = "RenderableModel", GeometryFile = models .. "MessengerProbe_metal.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "MessengerProbe Metal", @@ -165,7 +179,14 @@ local MessengerProbePanels = { Type = "RenderableModel", GeometryFile = models .. "MessengerProbe_panels.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "MessengerProbe Panels", diff --git a/data/assets/scene/solarsystem/missions/newhorizons/model.asset b/data/assets/scene/solarsystem/missions/newhorizons/model.asset index 465f9cdf33..ef6ce125f5 100644 --- a/data/assets/scene/solarsystem/missions/newhorizons/model.asset +++ b/data/assets/scene/solarsystem/missions/newhorizons/model.asset @@ -1,5 +1,5 @@ local transforms = asset.require("./transforms") -local sunTransforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local models = asset.syncedResource({ Name = "New Horizons Model", @@ -19,12 +19,7 @@ local NewHorizons = { DiffuseIntensity = 1.0, SpecularIntensity = 1.0, LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - } + sun.LightSource } }, GUI = { diff --git a/data/assets/scene/solarsystem/missions/osirisrex/bennu.asset b/data/assets/scene/solarsystem/missions/osirisrex/bennu.asset index 67c0350bb5..700edd5f2b 100644 --- a/data/assets/scene/solarsystem/missions/osirisrex/bennu.asset +++ b/data/assets/scene/solarsystem/missions/osirisrex/bennu.asset @@ -1,5 +1,5 @@ local transforms = asset.require("./transforms") -local sunTransforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local models = asset.syncedResource({ Name = "Bennu Models", @@ -10,15 +10,6 @@ local models = asset.syncedResource({ local BENNU_BODY = "2101955" -local LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, -} - local Bennu = { Identifier = "Bennu", Parent = transforms.BennuBarycenter.Identifier, @@ -34,7 +25,9 @@ local Bennu = { Type = "RenderableModel", Body = BENNU_BODY, GeometryFile = models .. "Bennu_v20_200k_an.obj", - LightSources = LightSources, + LightSources = { + sun.LightSource + }, SpecularIntensity = 0.0 }, GUI = { diff --git a/data/assets/scene/solarsystem/missions/osirisrex/model.asset b/data/assets/scene/solarsystem/missions/osirisrex/model.asset index e8798f5c07..2e15fc5aed 100644 --- a/data/assets/scene/solarsystem/missions/osirisrex/model.asset +++ b/data/assets/scene/solarsystem/missions/osirisrex/model.asset @@ -1,4 +1,5 @@ local transforms = asset.require("./transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local sunTransforms = asset.require("scene/solarsystem/sun/transforms") local earthTransforms = asset.require("scene/solarsystem/planets/earth/transforms") @@ -13,21 +14,6 @@ local models = asset.syncedResource({ local BENNU_BODY = "2101955" - -local LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, - { - Identifier = "Camera", - Type = "CameraLightSource", - Intensity = 0.5 - } -} - local OsirisRex = { Identifier = "OsirisRex", Parent = sunTransforms.SolarSystemBarycenter.Identifier, @@ -48,7 +34,14 @@ local OsirisRex = { Type = "RenderableModel", Body = "OSIRIS-REX", GeometryFile = models .. "orx_base_resized_12_sep_2016.obj", - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "OSIRIS REx", @@ -74,7 +67,14 @@ local PolyCam = { Type = "RenderableModel", Body = "OSIRIS-REX", GeometryFile = models .. "orx_polycam_resized_12_sep_2016.obj", - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "OCAMS POLYCAM", @@ -89,7 +89,14 @@ local Rexis = { Type = "RenderableModel", Body = "OSIRIS-REX", GeometryFile = models .. "orx_rexis_resized_12_sep_2016.obj", - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, Transform = { Translation = { diff --git a/data/assets/scene/solarsystem/missions/perseverance/model.asset b/data/assets/scene/solarsystem/missions/perseverance/model.asset index 797219ad74..5f5d928a2b 100644 --- a/data/assets/scene/solarsystem/missions/perseverance/model.asset +++ b/data/assets/scene/solarsystem/missions/perseverance/model.asset @@ -1,22 +1,8 @@ local trail = asset.require("./trail") local marsTransforms = asset.require("scene/solarsystem/planets/mars/transforms") -local sunTransforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") -- asset.require("./fov") -local LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, - { - Identifier = "Camera", - Type = "CameraLightSource", - Intensity = 0.5 - } -} - local models = asset.syncedResource({ Name = "Mars 2020 Kernels", Type = "HttpSynchronization", @@ -53,7 +39,14 @@ local Body = { Type = "RenderableModel", Body = "MARS SCIENCE LABORATORY", GeometryFile = models .. "Perseverance.obj", - LightSources = LightSources, + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + }, PerformShading = false, RotationVector = {65.940000,201.389999,263.980011} }, diff --git a/data/assets/scene/solarsystem/missions/pioneer/pioneermodel.asset b/data/assets/scene/solarsystem/missions/pioneer/pioneermodel.asset index 1efdc30dfa..7a2d34f884 100644 --- a/data/assets/scene/solarsystem/missions/pioneer/pioneermodel.asset +++ b/data/assets/scene/solarsystem/missions/pioneer/pioneermodel.asset @@ -1,4 +1,4 @@ -local sunTransforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local modelFolder = asset.syncedResource({ Name = "Pioneer 10/11 Models", @@ -11,12 +11,7 @@ local ModelRenderable = { Type = "RenderableModel", GeometryFile = modelFolder .. "pioneer.fbx", LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, + sun.LightSource, { Identifier = "Camera", Type = "CameraLightSource", @@ -35,4 +30,4 @@ asset.meta = { Author = "NASA", URL = "https://nasa3d.arc.nasa.gov/detail/eoss-pioneer", License = "NASA" -} \ No newline at end of file +} diff --git a/data/assets/scene/solarsystem/missions/rosetta/rosetta.asset b/data/assets/scene/solarsystem/missions/rosetta/rosetta.asset index 3b195a7201..6b9280501a 100644 --- a/data/assets/scene/solarsystem/missions/rosetta/rosetta.asset +++ b/data/assets/scene/solarsystem/missions/rosetta/rosetta.asset @@ -1,3 +1,4 @@ +local sun = asset.require("scene/solarsystem/sun/sun") local sunTransforms = asset.require("scene/solarsystem/sun/transforms") local transforms = asset.require("./67p") @@ -65,20 +66,6 @@ local RosettaKernels = { kernels .. "ROS_CGS_RSOC_V03.TPC" } -local LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, - { - Identifier = "Camera", - Type = "CameraLightSource", - Intensity = 0.5 - } -} - local RotationMatrix = { 0, 1, 0, 0, 0, 1, @@ -130,7 +117,14 @@ local RosettaBlackFoil = { Body = "ROSETTA", GeometryFile = models .. "black_foil.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Rosetta Model Part Black Foil", @@ -146,7 +140,14 @@ local RosettaBlackParts = { Body = "ROSETTA", GeometryFile = models .. "black_parts.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Rosetta Model Part Black Parts", @@ -162,7 +163,14 @@ local RosettaDish = { Body = "ROSETTA", GeometryFile = models .. "dish.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Rosetta Model Part Dish", @@ -178,7 +186,14 @@ local RosettaParts = { Body = "ROSETTA", GeometryFile = models .. "parts.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Rosetta Model Part Parts", @@ -194,7 +209,14 @@ local RosettaSilverFoil = { Body = "ROSETTA", GeometryFile = models .. "silver_foil.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Rosetta Model Part Silver Foil", @@ -210,7 +232,14 @@ local RosettaVents = { Body = "ROSETTA", GeometryFile = models .. "vents.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Rosetta Model Part Vents", @@ -226,7 +255,14 @@ local RosettaWingA = { Body = "ROSETTA", GeometryFile = models .."wingA.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Rosetta Model Part Wing A", @@ -242,7 +278,14 @@ local RosettaWingB = { Body = "ROSETTA", GeometryFile = models .. "wingB.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Rosetta Model Part Wing B", @@ -258,7 +301,14 @@ local RosettaYellowFoil = { Body = "ROSETTA", GeometryFile = models .. "yellow_foil.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Rosetta Model Part Yellow Foil", @@ -303,7 +353,14 @@ local PhilaeFoil = { Body = "ROSETTA", GeometryFile = models .. "lander_foil.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Philae Model Part Foil", @@ -319,7 +376,14 @@ local PhilaeLids = { Body = "ROSETTA", GeometryFile = models .. "lander_lids.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Philae Model Part Lids", @@ -335,7 +399,14 @@ local PhilaeParts = { Body = "ROSETTA", GeometryFile = models .. "lander_parts.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Philae Model Part Parts", @@ -351,7 +422,14 @@ local PhilaeSolarPanels = { Body = "ROSETTA", GeometryFile = models .. "lander_solarp.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Philae Model Parts Solar Panels", diff --git a/data/assets/scene/solarsystem/missions/voyager/voyager1.asset b/data/assets/scene/solarsystem/missions/voyager/voyager1.asset index e690425bd2..768a42bcfb 100644 --- a/data/assets/scene/solarsystem/missions/voyager/voyager1.asset +++ b/data/assets/scene/solarsystem/missions/voyager/voyager1.asset @@ -1,3 +1,4 @@ +local sun = asset.require("scene/solarsystem/sun/sun") local sunTransforms = asset.require("scene/solarsystem/sun/transforms") local models = asset.syncedResource({ @@ -31,20 +32,6 @@ local RotationMatrix = { 0, -1, 0 } -local LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, - { - Identifier = "Camera", - Type = "CameraLightSource", - Intensity = 0.5 - } -} - local Voyager1 = { Identifier = "Voyager_1", Parent = sunTransforms.SolarSystemBarycenter.Identifier, @@ -79,7 +66,14 @@ local Voyager1Main = { Type = "RenderableModel", GeometryFile = models .. "voyager-main.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Voyager 1 Main", @@ -94,7 +88,14 @@ local Voyager1Antenna = { Type = "RenderableModel", GeometryFile = models .. "voyager-antenna.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Voyager 1 Antenna", diff --git a/data/assets/scene/solarsystem/missions/voyager/voyager2.asset b/data/assets/scene/solarsystem/missions/voyager/voyager2.asset index a392b37528..e90d726106 100644 --- a/data/assets/scene/solarsystem/missions/voyager/voyager2.asset +++ b/data/assets/scene/solarsystem/missions/voyager/voyager2.asset @@ -1,3 +1,4 @@ +local sun = asset.require("scene/solarsystem/sun/sun") local sunTransforms = asset.require("scene/solarsystem/sun/transforms") @@ -35,20 +36,6 @@ local RotationMatrix = { } -local LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - }, - { - Identifier = "Camera", - Type = "CameraLightSource", - Intensity = 0.5 - } -} - local Voyager2 = { Identifier = "Voyager_2", Parent = sunTransforms.SolarSystemBarycenter.Identifier, @@ -83,7 +70,14 @@ local Voyager2Main = { Type = "RenderableModel", GeometryFile = models .. "voyager-main.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Voyager 2 Main", @@ -98,7 +92,14 @@ local Voyager2Antenna = { Type = "RenderableModel", GeometryFile = models .. "voyager-antenna.obj", ModelTransform = RotationMatrix, - LightSources = LightSources + LightSources = { + sun.LightSource, + { + Identifier = "Camera", + Type = "CameraLightSource", + Intensity = 0.5 + } + } }, GUI = { Name = "Voyager 2 Antenna", diff --git a/data/assets/scene/solarsystem/planets/earth/satellites/misc/iss.asset b/data/assets/scene/solarsystem/planets/earth/satellites/misc/iss.asset index 647d348b00..94390fd943 100644 --- a/data/assets/scene/solarsystem/planets/earth/satellites/misc/iss.asset +++ b/data/assets/scene/solarsystem/planets/earth/satellites/misc/iss.asset @@ -1,6 +1,6 @@ local satelliteHelper = asset.require("util/tle_helper") local transforms = asset.require("scene/solarsystem/planets/earth/transforms") -local sunTransforms = asset.require("scene/solarsystem/sun/transforms") +local sun = asset.require("scene/solarsystem/sun/sun") local url = "http://celestrak.com/satcat/tle.php?CATNR=25544" local identifier = "ISS" @@ -62,12 +62,7 @@ local initializeAndAddNodes = function() GeometryFile = models .. "ISS.fbx", ModelScale = "Centimeter", LightSources = { - { - Type = "SceneGraphLightSource", - Identifier = "Sun", - Node = sunTransforms.SolarSystemBarycenter.Identifier, - Intensity = 1.0 - } + sun.LightSource }, PerformShading = true, DisableFaceCulling = true diff --git a/data/assets/scene/solarsystem/sun/sun.asset b/data/assets/scene/solarsystem/sun/sun.asset index f494cd04d0..0c6964a694 100644 --- a/data/assets/scene/solarsystem/sun/sun.asset +++ b/data/assets/scene/solarsystem/sun/sun.asset @@ -44,6 +44,13 @@ local SunLabel = { } } +local LightSource = { + Type = "SceneGraphLightSource", + Identifier = "Sun", + Node = transforms.SolarSystemBarycenter.Identifier, + Intensity = 1.0 +} + asset.onInitialize(function() openspace.addSceneGraphNode(Sun) openspace.addSceneGraphNode(SunLabel) @@ -56,6 +63,7 @@ end) asset.export(Sun) asset.export(SunLabel) +asset.export("LightSource", LightSource) From 3844df20c94e1d1999245ee4d2413dff0e64f319 Mon Sep 17 00:00:00 2001 From: Alexander Bock Date: Mon, 21 Mar 2022 09:05:37 +0100 Subject: [PATCH 12/14] Feature/codegen lua (#1906) Adapting Lua functions to new codegen functionality Improve the documentation itself Add some styling to generated documentation Have parameter names for Lua-defined Lua function documentation Co-authored-by: Emma Broman --- apps/OpenSpace/ext/sgct | 2 +- data/web/documentation/scripting.hbs | 17 +- data/web/documentation/style.css | 17 + include/openspace/engine/openspaceengine.h | 7 +- include/openspace/scene/scene.h | 4 +- include/openspace/scripting/lualibrary.h | 26 +- include/openspace/util/time.h | 2 - .../base/rendering/screenspacedashboard.cpp | 14 +- .../rendering/screenspacedashboard_lua.inl | 48 +- modules/debugging/debuggingmodule.cpp | 58 +-- modules/debugging/debuggingmodule_lua.inl | 224 ++++----- modules/exoplanets/exoplanetsmodule.cpp | 61 ++- modules/exoplanets/exoplanetsmodule_lua.inl | 169 +++---- modules/gaia/scripts/filtering.lua | 10 +- modules/globebrowsing/globebrowsingmodule.cpp | 174 ++----- .../globebrowsing/globebrowsingmodule_lua.inl | 424 ++++++++--------- .../globebrowsing/scripts/layer_support.lua | 16 +- .../src/tileprovider/spoutimageprovider.cpp | 4 + modules/iswa/util/iswamanager.cpp | 58 +-- modules/iswa/util/iswamanager_lua.inl | 155 ++----- modules/space/spacemodule.cpp | 24 +- modules/space/spacemodule_lua.inl | 66 +-- modules/statemachine/statemachinemodule.cpp | 85 +--- .../statemachine/statemachinemodule_lua.inl | 124 ++--- modules/sync/syncmodule.cpp | 27 +- modules/sync/syncmodule_lua.inl | 39 +- scripts/core_scripts.lua | 12 +- src/CMakeLists.txt | 1 + src/engine/moduleengine.cpp | 8 +- src/engine/moduleengine_lua.inl | 34 +- src/engine/openspaceengine.cpp | 68 +-- src/engine/openspaceengine_lua.inl | 167 +++---- src/events/eventengine.cpp | 26 +- src/events/eventengine_lua.inl | 36 +- src/interaction/actionmanager.cpp | 56 +-- src/interaction/actionmanager_lua.inl | 212 ++++----- src/interaction/keybindingmanager.cpp | 31 +- src/interaction/keybindingmanager_lua.inl | 81 ++-- src/interaction/sessionrecording.cpp | 131 +----- src/interaction/sessionrecording_lua.inl | 230 +++++---- src/mission/missionmanager.cpp | 29 +- src/mission/missionmanager_lua.inl | 54 +-- src/navigation/navigationhandler.cpp | 190 +------- src/navigation/navigationhandler_lua.inl | 390 ++++++++-------- src/navigation/pathnavigator.cpp | 112 +---- src/navigation/pathnavigator_lua.inl | 207 ++++----- src/network/parallelpeer.cpp | 28 +- src/network/parallelpeer_lua.inl | 30 +- src/rendering/dashboard.cpp | 23 +- src/rendering/dashboard_lua.inl | 71 +-- src/rendering/renderengine.cpp | 25 +- src/rendering/renderengine_lua.inl | 65 ++- src/scene/assetmanager.cpp | 39 +- src/scene/assetmanager_lua.inl | 63 +-- src/scene/profile.cpp | 28 +- src/scene/profile_lua.inl | 58 +-- src/scene/scene.cpp | 137 ++---- src/scene/scene_lua.inl | 343 +++++--------- src/scripting/scriptengine.cpp | 317 +++++++------ src/scripting/scriptengine_lua.inl | 279 ++++------- src/scripting/scriptscheduler.cpp | 53 +-- src/scripting/scriptscheduler_lua.inl | 82 ++-- src/scripting/systemcapabilitiesbinding.cpp | 351 +------------- .../systemcapabilitiesbinding_lua.inl | 226 +++++++++ src/util/spicemanager.cpp | 61 +-- src/util/spicemanager_lua.inl | 159 ++----- src/util/time.cpp | 219 ++------- src/util/time_lua.inl | 438 +++++++----------- tests/test_lua_createsinglecolorimage.cpp | 105 +---- 69 files changed, 2656 insertions(+), 4474 deletions(-) create mode 100644 src/scripting/systemcapabilitiesbinding_lua.inl 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 @@ - {{/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 { '', '