diff --git a/.gitignore b/.gitignore index d80ea9cee9..e75af825e0 100644 --- a/.gitignore +++ b/.gitignore @@ -38,3 +38,4 @@ Thumbs.db customization.lua # The COMMIT info is generated everytime CMake is run COMMIT.md +*_codegen.cpp diff --git a/.gitmodules b/.gitmodules index 0bfcb7f59d..112e7a1300 100644 --- a/.gitmodules +++ b/.gitmodules @@ -29,3 +29,6 @@ [submodule "ext/date"] path = ext/date url = https://github.com/HowardHinnant/date +[submodule "support/coding/codegen"] + path = support/coding/codegen + url = https://github.com/OpenSpace/codegen diff --git a/CMakeLists.txt b/CMakeLists.txt index 800fe645df..a3c2a8c767 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -139,12 +139,29 @@ if (UNIX AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++ -lc++abi") endif () -# Add external dependencies -add_subdirectory(${OPENSPACE_BASE_DIR}/ext) +add_subdirectory(ext) -# include(src/CMakeLists.txt) add_subdirectory(src) +add_subdirectory(support/coding/codegen) +# It is important that the __codegen.h do not actually exist so +# that this target is never considered as finished +add_custom_target( + run_codegen + ALL DEPENDS + "${CMAKE_CURRENT_BINARY_DIR}/__codegen.h" +) +add_dependencies(run_codegen codegen) +add_custom_command( + OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/__codegen.h" + COMMAND codegen ARGS "${OPENSPACE_BASE_DIR}/modules" "${OPENSPACE_BASE_DIR}/src" + VERBATIM +) +set_folder_location(codegen-lib "support") +set_folder_location(codegen "support") +set_folder_location(run_codegen "support") + + # Qt # Unfortunately, we have to set this value manually; sigh # In the future, if the Qt version is updated, just add to this variable ---abock @@ -176,6 +193,12 @@ begin_header("Configuring Modules") add_subdirectory("${CMAKE_CURRENT_SOURCE_DIR}/modules") end_header("End: Configuring Modules") + +add_subdirectory(support/coding/codegen/tests) +set_folder_location(run_test_codegen "Unit Tests/support") +set_folder_location(codegentest "Unit Tests") + + begin_header("Configuring Applications") add_subdirectory("${OPENSPACE_APPS_DIR}") end_header("End: Configuring Applications") diff --git a/Jenkinsfile b/Jenkinsfile index f4de007c31..5fc5351950 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -114,6 +114,7 @@ linux_gcc_make: { } stage('linux-gcc-make/test') { // testHelper.runUnitTests('build/OpenSpaceTest'); + // testHelper.runUnitTests('bin/codegentest') } cleanWs() } // node('linux') @@ -134,6 +135,7 @@ linux_gcc_ninja: { } stage('linux-gcc-ninja/test') { // testHelper.runUnitTests('build/OpenSpaceTest'); + // testHelper.runUnitTests('bin/codegentest') } cleanWs() } // node('linux') @@ -155,6 +157,7 @@ linux_clang_make: { } stage('linux-clang-make/test') { // testHelper.runUnitTests('build/OpenSpaceTest'); + // testHelper.runUnitTests('bin/codegentest') } cleanWs() } // node('linux') @@ -175,6 +178,7 @@ linux_clang_ninja: { } stage('linux-clang-ninja/test') { // testHelper.runUnitTests('build/OpenSpaceTest'); + // testHelper.runUnitTests('bin/codegentest') } cleanWs() } // node('linux') @@ -194,6 +198,7 @@ windows_msvc: { stage('windows-msvc/test') { // Currently, the unit tests are failing on Windows // testHelper.runUnitTests('bin\\Debug\\OpenSpaceTest') + testHelper.runUnitTests('bin\\Debug\\codegentest') } cleanWs() } // node('windows') diff --git a/apps/OpenSpace/ext/launcher/CMakeLists.txt b/apps/OpenSpace/ext/launcher/CMakeLists.txt index 2ab5cf90ac..460f486412 100644 --- a/apps/OpenSpace/ext/launcher/CMakeLists.txt +++ b/apps/OpenSpace/ext/launcher/CMakeLists.txt @@ -90,3 +90,11 @@ set_openspace_compile_settings(openspace-ui-launcher) target_include_directories(openspace-ui-launcher PUBLIC include) target_link_libraries(openspace-ui-launcher PUBLIC Qt5::Core Qt5::Gui Qt5::Widgets openspace-core) +if (MSVC) +set(MSVC_WARNINGS + "/wd4619" # #pragma warning: there is no warning number (raised by Qt headers) + "/wd4946" # reinterpret_cast used between related classes: +) +target_compile_options(openspace-ui-launcher INTERFACE ${MSVC_WARNINGS}) + +endif () diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index 8272be8ef4..b370da39e6 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -41,11 +41,11 @@ #include #include #include -//#include -#include +#include #ifdef WIN32 #define GLFW_EXPOSE_NATIVE_WIN32 #endif +#include #include #include #include @@ -576,7 +576,7 @@ void mainPostDrawFunc() { glBindTexture(GL_TEXTURE_2D, texId); w.leftOrMain.handle->SendTexture( texId, - GL_TEXTURE_2D, + GLuint(GL_TEXTURE_2D), window.framebufferResolution().x, window.framebufferResolution().y ); @@ -587,7 +587,7 @@ void mainPostDrawFunc() { glBindTexture(GL_TEXTURE_2D, tId); w.right.handle->SendTexture( tId, - GL_TEXTURE_2D, + GLuint(GL_TEXTURE_2D), window.framebufferResolution().x, window.framebufferResolution().y ); @@ -1013,7 +1013,6 @@ std::string selectedSgctProfileFromLauncher(LauncherWindow& lw, bool hasCliSGCTC } int main(int argc, char* argv[]) { - #ifdef WIN32 SetUnhandledExceptionFilter(generateMiniDump); #endif // WIN32 diff --git a/data/assets/base.asset b/data/assets/base.asset index 9932559be7..98c832a00e 100644 --- a/data/assets/base.asset +++ b/data/assets/base.asset @@ -8,11 +8,10 @@ asset.require('examples/pointscloud') -- Specifying which other assets should be loaded in this scene asset.require('scene/solarsystem/sun/sun') asset.require('scene/solarsystem/sun/glare') +asset.require('scene/solarsystem/sun/habitablezone') asset.require('scene/solarsystem/sun/default_layers') asset.require('scene/solarsystem/planets/planets') asset.require('scene/solarsystem/planets/default_layers') -asset.require('scene/solarsystem/planets/mars/moons/phobos') -asset.require('scene/solarsystem/planets/mars/moons/deimos') asset.require('scene/solarsystem/dwarf_planets/pluto/system') asset.require('scene/solarsystem/dwarf_planets/pluto/default_layers') asset.require('scene/solarsystem/dwarf_planets/pluto/charon/default_layers') @@ -22,9 +21,11 @@ asset.require('scene/milkyway/constellations/constellation_keybinds') asset.require('scene/milkyway/objects/orionnebula/orionnebula') asset.require('util/launcher_images') -local assetHelper = asset.require('util/asset_helper') +-- For exoplanet system visualizations asset.require('scene/milkyway/exoplanets/exoplanets_data') asset.require('scene/milkyway/exoplanets/exoplanets_textures') + +local assetHelper = asset.require('util/asset_helper') asset.require('scene/digitaluniverse/2dF') asset.require('scene/digitaluniverse/2mass') asset.require('scene/digitaluniverse/6dF') diff --git a/data/assets/examples/discs.asset b/data/assets/examples/discs.asset new file mode 100644 index 0000000000..0b15b2115b --- /dev/null +++ b/data/assets/examples/discs.asset @@ -0,0 +1,25 @@ +local assetHelper = asset.require('util/asset_helper') + +local color = {0.0, 1.0, 1.0} + +-- @TODO (emmbr 2020-02-03) Potential threading issue later on? This will run on the main thread +local singeColorTexturePath = openspace.createSingeColorImage("example_ring_color", color) + +local BasicDisc = { + Identifier = "BasicDisc", + Parent = "Root", + Renderable = { + Type = "RenderableDisc", + Texture = singeColorTexturePath, + Size = 1e10, + Width = 0.5 + }, + GUI = { + Name = "Basic Disc", + Path = "/Examples/Discs" + } +} + +assetHelper.registerSceneGraphNodesAndExport(asset, { + BasicDisc +}) diff --git a/data/assets/scene/milkyway/exoplanets/exoplanets_data.asset b/data/assets/scene/milkyway/exoplanets/exoplanets_data.asset index b75b5aa1a5..0d2ab171e8 100644 --- a/data/assets/scene/milkyway/exoplanets/exoplanets_data.asset +++ b/data/assets/scene/milkyway/exoplanets/exoplanets_data.asset @@ -5,3 +5,14 @@ local DataPath = asset.syncedResource({ Version = 2 }) asset.export("DataPath", DataPath) + +asset.meta = { + Name = "Exoplanet Data", + Version = "2.0", + Description = [[ The data that is used for the exoplanet systems. The data has been + derived from the 'Planetary Systems Composite Data' dataset from the NASA Exoplanet + Archive]], + Author = "OpenSpace Team", + URL = "https://exoplanetarchive.ipac.caltech.edu/docs/data.html", + License = "MIT license", +} diff --git a/data/assets/scene/milkyway/exoplanets/exoplanets_textures.asset b/data/assets/scene/milkyway/exoplanets/exoplanets_textures.asset index 287b29d61e..9efd63b65c 100644 --- a/data/assets/scene/milkyway/exoplanets/exoplanets_textures.asset +++ b/data/assets/scene/milkyway/exoplanets/exoplanets_textures.asset @@ -1,7 +1,19 @@ +asset.require('./../habitable_zones/habitable_zone_textures') + local TexturesPath = asset.syncedResource({ Name = "Exoplanet Textures", Type = "HttpSynchronization", Identifier = "exoplanets_textures", - Version = 1 + Version = 2 }) asset.export("TexturesPath", TexturesPath) + +asset.meta = { + Name = "Exoplanet Textures", + Version = "2.0", + Description = [[ Adds all textures that are required for the exoplanet system + visualizations]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license", +} diff --git a/data/assets/scene/milkyway/habitable_zones/habitable_zone_textures.asset b/data/assets/scene/milkyway/habitable_zones/habitable_zone_textures.asset new file mode 100644 index 0000000000..0687c70693 --- /dev/null +++ b/data/assets/scene/milkyway/habitable_zones/habitable_zone_textures.asset @@ -0,0 +1,17 @@ +local TexturesPath = asset.syncedResource({ + Name = "Habitable Zone Textures", + Type = "HttpSynchronization", + Identifier = "habitable_zone_textures", + Version = 1 +}) +asset.export("TexturesPath", TexturesPath) + +asset.meta = { + Name = "Habitable Zone Textures", + Version = "1.0", + Description = [[ Default textures that can be used for the habitable zone + rendering]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license", +} diff --git a/data/assets/scene/solarsystem/dwarf_planets/pluto/charon/charon.asset b/data/assets/scene/solarsystem/dwarf_planets/pluto/charon/charon.asset index 35e6fe6436..4b6aa574c2 100644 --- a/data/assets/scene/solarsystem/dwarf_planets/pluto/charon/charon.asset +++ b/data/assets/scene/solarsystem/dwarf_planets/pluto/charon/charon.asset @@ -31,16 +31,17 @@ local Charon = { Enable = false, FileName = labelsPath .. "/charon.labels", LabelAlignmentOption = "Horizontally", -- or Circularly - LabelsFontSize = 14.0, + LabelsFontSize = 40.0, LabelsSize = 8.0, LabelsMinSize = 1.0, LabelsMaxSize = 1500.0, ProximityEnabled = false, LabelsFadeInEnabled = true, - FadeInStartingDistance = 500000.0, - FadeOutStartingDistance = 1000000.0, + LabelsFadeOutEnabled = true, + FadeInStartingDistance = 2000000.0, + FadeOutStartingDistance = 800000.0, LabelsForceDomeRendering = true, - LabelsDistanceEPS = 1350000.0, + LabelsDistanceEPS = 250000.0, LabelsColor = { 1.0, 1.0, 0.0 } } }, diff --git a/data/assets/scene/solarsystem/dwarf_planets/pluto/pluto.asset b/data/assets/scene/solarsystem/dwarf_planets/pluto/pluto.asset index 667c201781..5299ebc5dd 100644 --- a/data/assets/scene/solarsystem/dwarf_planets/pluto/pluto.asset +++ b/data/assets/scene/solarsystem/dwarf_planets/pluto/pluto.asset @@ -31,16 +31,17 @@ local Pluto = { Enable = false, FileName = labelsPath .. "/pluto.labels", LabelAlignmentOption = "Horizontally", -- or Circularly - LabelsFontSize = 14.0, + LabelsFontSize = 28.0, LabelsSize = 8.0, LabelsMinSize = 1.0, LabelsMaxSize = 1500.0, ProximityEnabled = false, LabelsFadeInEnabled = true, - FadeInStartingDistance = 500000.0, - FadeOutStartingDistance = 1000000.0, + LabelsFadeOutEnabled = true, + FadeInStartingDistance = 4000000.0, + FadeOutStartingDistance = 650000.0, LabelsForceDomeRendering = true, - LabelsDistanceEPS = 1350000.0, + LabelsDistanceEPS = 500000.0, LabelsColor = { 1.0, 1.0, 0.0 } } }, diff --git a/data/assets/scene/solarsystem/missions/pioneer/pioneer10.asset b/data/assets/scene/solarsystem/missions/pioneer/pioneer10.asset index f76730f83c..8f7ad17c31 100644 --- a/data/assets/scene/solarsystem/missions/pioneer/pioneer10.asset +++ b/data/assets/scene/solarsystem/missions/pioneer/pioneer10.asset @@ -15,7 +15,7 @@ local kernelsList = {kernelsFolder .. '/p10-a.bsp'} local Pioneer10NAIF = "-23" local Pioneer10 = { - Identifier = "Pioneer10", + Identifier = "Pioneer_10", Parent = sunTransforms.SolarSystemBarycenter.Identifier, Transform = { Translation = { @@ -27,13 +27,15 @@ local Pioneer10 = { }, Renderable = model.PioneerModel, GUI = { - Name = "Pioneer 10", - Path = "/Solar System/Missions/Pioneer/10" + Name = "Pioneer 10 Spacecraft", + Path = "/Solar System/Missions/Pioneer", + Description = [[Pioneer 10 Spacecraft. Positioned by SPICE data.]] + } } local Pioneer10Trail = { - Identifier = "Pioneer10Trail", + Identifier = "Pioneer_10Trail", Parent = sunTransforms.SolarSystemBarycenter.Identifier, Renderable = { Type = "RenderableTrailTrajectory", @@ -51,8 +53,10 @@ local Pioneer10Trail = { -- 6545 is the number of days between the Start and End time (aka sample every 2d) }, GUI = { - Name = "Pioneer 10 Trail", - Path = "/Solar System/Missions/Pioneer/10" + Name = "Pioneer 10 Trail (SPICE)", + Path = "/Solar System/Missions/Pioneer", + Description = [[Pioneer 10 Trail, spanning March 3rd, 1972 to January 2nd, 1990. + Data from SPICE]] } } @@ -60,3 +64,15 @@ assetHelper.registerSceneGraphNodesAndExport(asset, { Pioneer10, Pioneer10Trail, }) + + +asset.meta = { + Name = "Pioneer 10", + Version = "1.0", + Description = [[ Pioneer 10 Model and Trail. Driven by SPICE data for high accuracy + from March 3rd, 1972 to January 2nd, 1990.]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license", + Identifiers = {"Pioneer_10", "Pioneer_10Trail"} +} diff --git a/data/assets/scene/solarsystem/missions/pioneer/pioneer11.asset b/data/assets/scene/solarsystem/missions/pioneer/pioneer11.asset index 5e69367ae1..ae51e753a8 100644 --- a/data/assets/scene/solarsystem/missions/pioneer/pioneer11.asset +++ b/data/assets/scene/solarsystem/missions/pioneer/pioneer11.asset @@ -30,13 +30,14 @@ local Pioneer11 = { }, Renderable = model.PioneerModel, GUI = { - Name = "Pioneer 11", - Path = "/Solar System/Missions/Pioneer/11" + Name = "Pioneer 11 Spacecraft", + Path = "/Solar System/Missions/Pioneer", + Description = [[Pioneer 11 Spacecraft. Positioned by SPICE data.]] } } local Pioneer11Trail = { - Identifier = "Pioneer11Trail", + Identifier = "Pioneer_11Trail", Parent = sunTransforms.SolarSystemBarycenter.Identifier, Renderable = { Type = "RenderableTrailTrajectory", @@ -54,8 +55,10 @@ local Pioneer11Trail = { --6087 is the number of days between the Start and End time (so sample every 2d) }, GUI = { - Name = "Pioneer 11 Trail", - Path = "/Solar System/Missions/Pioneer/11" + Name = "Pioneer 11 Trail (SPICE)", + Path = "/Solar System/Missions/Pioneer", + Description = [[Pioneer 11 Trail, spanning April 6th, 1973 to January 2nd, 1990. + Data from SPICE.]] } } @@ -63,3 +66,15 @@ assetHelper.registerSceneGraphNodesAndExport(asset, { Pioneer11, Pioneer11Trail, }) + + +asset.meta = { + Name = "Pioneer 11", + Version = "1.0", + Description = [[ Pioneer 11 Model and Trail. Driven by SPICE data for high accuracy + from April 6th, 1973 to January 2nd, 1990.]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license", + Identifiers = {"Pioneer_11", "Pioneer_11Trail"} +} diff --git a/data/assets/scene/solarsystem/missions/pioneer/pioneermodel.asset b/data/assets/scene/solarsystem/missions/pioneer/pioneermodel.asset index 1903e5bb71..a0b1b632ff 100644 --- a/data/assets/scene/solarsystem/missions/pioneer/pioneermodel.asset +++ b/data/assets/scene/solarsystem/missions/pioneer/pioneermodel.asset @@ -1,5 +1,5 @@ local assetHelper = asset.require('util/asset_helper') - +local sunTransforms = asset.require('scene/solarsystem/sun/transforms') local modelFolder = asset.syncedResource({ Name = "Pioneer 10/11 Models", @@ -21,3 +21,13 @@ local ModelRenderable = { } asset.export("PioneerModel", ModelRenderable) + +asset.meta = { + Name = "Pioneer Model", + Version = "1.0", + Description = [[ Pioneer model asset. Used by both pioneer 10 and pioneer 11 asset. + Untextured version of model from NASA 3D resources.]], + 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/voyagerpioneer/voyager1_2__pioneer10_11.asset b/data/assets/scene/solarsystem/missions/voyagerpioneer/voyager1_2__pioneer10_11.asset index b609658789..02be5ab03e 100644 --- a/data/assets/scene/solarsystem/missions/voyagerpioneer/voyager1_2__pioneer10_11.asset +++ b/data/assets/scene/solarsystem/missions/voyagerpioneer/voyager1_2__pioneer10_11.asset @@ -20,8 +20,10 @@ local voyager1 = { TimeStampSubsampleFactor = 1 }, GUI = { - Name = "Voyager 1", - Path = "/Solar System/Missions" + Name = "Voyager 1 Trail", + Path = "/Solar System/Missions/Voyager", + Description = [[Voyager 1 Trail, spanning September 6th, 1977 to December 31st, + 2030. Data from JPL Horizons.]] } } @@ -43,8 +45,10 @@ local voyager2 = { TimeStampSubsampleFactor = 1 }, GUI = { - Name = "Voyager 2", - Path = "/Solar System/Missions" + Name = "Voyager 2 Trail", + Path = "/Solar System/Missions/Voyager", + Description = [[Voyager 2 Trail, spanning August 21st, 1977 to December 31st, 2030. + Data from JPL Horizons.]] } } @@ -66,8 +70,10 @@ local pioneer10 = { TimeStampSubsampleFactor = 1 }, GUI = { - Name = "Pioneer 10", - Path = "/Solar System/Missions" + Name = "Pioneer 10 Trail", + Path = "/Solar System/Missions/Pioneer", + Description = [[Pioneer 10 Trail, spanning March 4th, 1972 to December 31st, 2030. + Data from JPL Horizons.]] } } @@ -89,9 +95,24 @@ local pioneer11 ={ TimeStampSubsampleFactor = 1 }, GUI = { - Name = "Pioneer 11", - Path = "/Solar System/Missions" + Name = "Pioneer 11 Trail", + Path = "/Solar System/Missions/Pioneer", + Description = [[Pioneer 11 Trail, spanning April 7th, 1973 to December 31st, 2030. + Data from JPL Horizons.]] } } assetHelper.registerSceneGraphNodesAndExport(asset, { voyager1, voyager2, pioneer10, pioneer11 }) + + +asset.meta = { + Name = "Pioneer and Voyager Trails", + Version = "1.0", + Description = [[ Pioneer 10, Pioneer 11, Voyager 1 and Voyager 2 trails. Driven by JPL + Horizons data for better performance then spice but lower resolution. Data is from + shortly after mission launches until December 31st, 2030.]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license", + Identifiers = {"Pioneer10", "Pioneer11", "Voyager1", "Voyager2"} +} \ No newline at end of file diff --git a/data/assets/scene/solarsystem/planets/default_layers.asset b/data/assets/scene/solarsystem/planets/default_layers.asset index 4fc2b0ada0..37649a9ed0 100644 --- a/data/assets/scene/solarsystem/planets/default_layers.asset +++ b/data/assets/scene/solarsystem/planets/default_layers.asset @@ -8,6 +8,8 @@ asset.require('./jupiter/ganymede/default_layers') asset.require('./jupiter/io/default_layers') asset.require('./mars/default_layers') +asset.require('./mars/moons/layers/colorlayers/deimos_viking') +asset.require('./mars/moons/layers/colorlayers/phobos_viking') asset.require('./mercury/default_layers') diff --git a/data/assets/scene/solarsystem/planets/earth/earth.asset b/data/assets/scene/solarsystem/planets/earth/earth.asset index b4f793cc69..e66cb53329 100644 --- a/data/assets/scene/solarsystem/planets/earth/earth.asset +++ b/data/assets/scene/solarsystem/planets/earth/earth.asset @@ -26,15 +26,15 @@ local Earth = { Enable = false, FileName = labelsPath .. "/Earth.labels", LabelAlignmentOption = "Horizontally", -- or Circularly - LabelsFontSize = 41.0, - LabelsSize = 0.52, + LabelsFontSize = 40.0, + LabelsSize = 4.0, LabelsMinSize = 1.0, LabelsMaxSize = 1500.0, ProximityEnabled = false, LabelsFadeInEnabled = true, - LabelsFadeOutEnabled = false, - FadeInStartingDistance = 50000.0, - FadeOutStartingDistance = 80000.0, + LabelsFadeOutEnabled = true, + FadeInStartingDistance = 300000.0, + FadeOutStartingDistance = 10000.0, LabelsForceDomeRendering = true, LabelsDistanceEPS = 1500000.0, LabelsColor = { 1.0, 0.0, 0.0 } diff --git a/data/assets/scene/solarsystem/planets/earth/moon/moon.asset b/data/assets/scene/solarsystem/planets/earth/moon/moon.asset index ace7442735..160b880246 100644 --- a/data/assets/scene/solarsystem/planets/earth/moon/moon.asset +++ b/data/assets/scene/solarsystem/planets/earth/moon/moon.asset @@ -43,8 +43,9 @@ local Moon = { LabelsMaxSize = 1500.0, ProximityEnabled = false, LabelsFadeInEnabled = true, + LabelsFadeOutEnabled = true, FadeInStartingDistance = 500000.0, - FadeOutStartingDistance = 1000000.0, + FadeOutStartingDistance = 100000.0, LabelsForceDomeRendering = true, LabelsDistanceEPS = 1350000.0, LabelsColor = { 1.0, 1.0, 0.0 } diff --git a/data/assets/scene/solarsystem/planets/jupiter/callisto/callisto.asset b/data/assets/scene/solarsystem/planets/jupiter/callisto/callisto.asset index 09c2888303..580e6c72ca 100644 --- a/data/assets/scene/solarsystem/planets/jupiter/callisto/callisto.asset +++ b/data/assets/scene/solarsystem/planets/jupiter/callisto/callisto.asset @@ -37,8 +37,9 @@ local Callisto = { LabelsMaxSize = 1500.0, ProximityEnabled = false, LabelsFadeInEnabled = true, + LabelsFadeOutEnabled = true, FadeInStartingDistance = 15000000.0, - FadeOutStartingDistance = 1000000.0, + FadeOutStartingDistance = 5000000.0, LabelsForceDomeRendering = true, LabelsDistanceEPS = 1350000.0, LabelsColor = { 1.0, 1.0, 0.0 } diff --git a/data/assets/scene/solarsystem/planets/jupiter/europa/europa.asset b/data/assets/scene/solarsystem/planets/jupiter/europa/europa.asset index 6be8e60814..d3e29eba08 100644 --- a/data/assets/scene/solarsystem/planets/jupiter/europa/europa.asset +++ b/data/assets/scene/solarsystem/planets/jupiter/europa/europa.asset @@ -32,15 +32,16 @@ local Europa = { FileName = labelsPath .. "/europa.labels", LabelAlignmentOption = "Horizontally", -- or Circularly LabelsFontSize = 40.0, - LabelsSize = 10.5, + LabelsSize = 10.0, LabelsMinSize = 1.0, LabelsMaxSize = 1500.0, ProximityEnabled = false, LabelsFadeInEnabled = true, - FadeInStartingDistance = 15000000.0, - FadeOutStartingDistance = 1000000.0, + LabelsFadeOutEnabled = true, + FadeInStartingDistance = 8000000.0, + FadeOutStartingDistance = 5000000.0, LabelsForceDomeRendering = true, - LabelsDistanceEPS = 1350000.0, + LabelsDistanceEPS = 700000.0, LabelsColor = { 1.0, 1.0, 0.0 } } }, diff --git a/data/assets/scene/solarsystem/planets/jupiter/ganymede/ganymede.asset b/data/assets/scene/solarsystem/planets/jupiter/ganymede/ganymede.asset index c93b359f3e..0e53d189d1 100644 --- a/data/assets/scene/solarsystem/planets/jupiter/ganymede/ganymede.asset +++ b/data/assets/scene/solarsystem/planets/jupiter/ganymede/ganymede.asset @@ -37,10 +37,11 @@ local Ganymede = { LabelsMaxSize = 1500.0, ProximityEnabled = false, LabelsFadeInEnabled = true, - FadeInStartingDistance = 15000000.0, - FadeOutStartingDistance = 1000000.0, + LabelsFadeOutEnabled = true, + FadeInStartingDistance = 8000000.0, + FadeOutStartingDistance = 2250000.0, LabelsForceDomeRendering = true, - LabelsDistanceEPS = 1350000.0, + LabelsDistanceEPS = 1750000.0, LabelsColor = {1.0, 1.0, 0.0} } }, diff --git a/data/assets/scene/solarsystem/planets/jupiter/io/io.asset b/data/assets/scene/solarsystem/planets/jupiter/io/io.asset index e64cbfe431..20f2d5a2b6 100644 --- a/data/assets/scene/solarsystem/planets/jupiter/io/io.asset +++ b/data/assets/scene/solarsystem/planets/jupiter/io/io.asset @@ -32,15 +32,16 @@ local Io = { FileName = labelsPath .. "/io.labels", LabelAlignmentOption = "Horizontally", -- or Circularly LabelsFontSize = 40.0, - LabelsSize = 10.5, + LabelsSize = 10.0, LabelsMinSize = 1.0, LabelsMaxSize = 1500.0, ProximityEnabled = false, LabelsFadeInEnabled = true, - FadeInStartingDistance = 15000000.0, - FadeOutStartingDistance = 1000000.0, + LabelsFadeOutEnabled = true, + FadeInStartingDistance = 8500000.0, + FadeOutStartingDistance = 4000000.0, LabelsForceDomeRendering = true, - LabelsDistanceEPS = 1350000.0, + LabelsDistanceEPS = 1000000.0, LabelsColor = { 1.0, 1.0, 0.0 } } }, diff --git a/data/assets/scene/solarsystem/planets/mars/layers/heightlayers/hirisels.asset b/data/assets/scene/solarsystem/planets/mars/layers/heightlayers/hirisels.asset index 0fa9c56943..01adfc48b6 100644 --- a/data/assets/scene/solarsystem/planets/mars/layers/heightlayers/hirisels.asset +++ b/data/assets/scene/solarsystem/planets/mars/layers/heightlayers/hirisels.asset @@ -4,7 +4,7 @@ local globeIdentifier = asset.require("./../../mars").Mars.Identifier local layer = { Identifier = "HiRISE-LS-DEM", Name = "HiRISE Local Set DEM", - FilePath = mapServiceConfigs .. "/ESRI/HiRISE/HiRISE_DEM.wms", + FilePath = mapServiceConfigs .. "/ESRI/HiRISE/HiRISE_DEM.dem", Description = [[ HiRISE (High Resolution Imaging Science Experiment) is the most powerful camera ever sent to another planet, one of six instruments onboard the Mars Reconnaissance Orbiter. We launched in 2005, arrived at Mars in 2006 and have diff --git a/data/assets/scene/solarsystem/planets/mars/map_service_configs/ESRI/HiRISE/HiRISE_DEM.tif b/data/assets/scene/solarsystem/planets/mars/map_service_configs/ESRI/HiRISE/HiRISE_DEM.dem similarity index 87% rename from data/assets/scene/solarsystem/planets/mars/map_service_configs/ESRI/HiRISE/HiRISE_DEM.tif rename to data/assets/scene/solarsystem/planets/mars/map_service_configs/ESRI/HiRISE/HiRISE_DEM.dem index f557be2ac1..8446fe69d3 100644 --- a/data/assets/scene/solarsystem/planets/mars/map_service_configs/ESRI/HiRISE/HiRISE_DEM.tif +++ b/data/assets/scene/solarsystem/planets/mars/map_service_configs/ESRI/HiRISE/HiRISE_DEM.dem @@ -1,6 +1,6 @@ - http://astro.arcgis.com/arcgis/rest/services/OnMars/HiRISE_DEM/ImageServer/tile/${z}/${y}/${x} + http://astro.arcgis.com/arcgis/rest/services/OnMars/HiRISE_DEM/raw/tile/${z}/${y}/${x} -180 90 @@ -11,7 +11,7 @@ GEOGCS["GCS_Mars_2000_Sphere",DATUM["D_Mars_2000_Sphere",SPHEROID["Mars_2000_Sphere_IAU_IAG",3396190,0]],PRIMEM["Reference_Meridian",0],UNIT["Degree",0.0174532925199433]] 512 512 1 Int16 - + 5 404,400 diff --git a/data/assets/scene/solarsystem/planets/mars/map_service_configs/ESRI/HiRISE/HiRISE_DEM.wms b/data/assets/scene/solarsystem/planets/mars/map_service_configs/ESRI/HiRISE/HiRISE_DEM.wms deleted file mode 100644 index bedcb068e0..0000000000 --- a/data/assets/scene/solarsystem/planets/mars/map_service_configs/ESRI/HiRISE/HiRISE_DEM.wms +++ /dev/null @@ -1,17 +0,0 @@ - - - http://astro.arcgis.com/arcgis/rest/services/OnMars/HiRISE_DEM/ImageServer/tile/${z}/${y}/${x} - - - -180 90 - 180 -90 - 20971520 10485760 - 15 top - - GEOGCS["GCS_Mars_2000_Sphere",DATUM["D_Mars_2000_Sphere",SPHEROID["Mars_2000_Sphere_IAU_IAG",3396190,0]],PRIMEM["Reference_Meridian",0],UNIT["Degree",0.0174532925199433]] - 512 512 - 1 Int16 - - 5 - 404,400 - diff --git a/data/assets/scene/solarsystem/planets/mars/mars.asset b/data/assets/scene/solarsystem/planets/mars/mars.asset index 8bdd08008d..e96320563a 100644 --- a/data/assets/scene/solarsystem/planets/mars/mars.asset +++ b/data/assets/scene/solarsystem/planets/mars/mars.asset @@ -27,15 +27,16 @@ local Mars = { FileName = labelsPath .. "/mars.labels", LabelAlignmentOption = "Horizontally", -- or Circularly LabelsFontSize = 14.0, - LabelsSize = 8.0, + LabelsSize = 9.0, LabelsMinSize = 1.0, LabelsMaxSize = 1500.0, ProximityEnabled = false, LabelsFadeInEnabled = true, - FadeInStartingDistance = 500000.0, - FadeOutStartingDistance = 1000000.0, + LabelsFadeOutEnabled = true, + FadeInStartingDistance = 2000000.0, + FadeOutStartingDistance = 750000.0, LabelsForceDomeRendering = true, - LabelsDistanceEPS = 1350000.0, + LabelsDistanceEPS = 2500000.0, LabelsColor = { 1.0, 1.0, 0.0 } } }, diff --git a/data/assets/scene/solarsystem/planets/mars/moons/layers/colorlayers/deimos_viking.asset b/data/assets/scene/solarsystem/planets/mars/moons/layers/colorlayers/deimos_viking.asset new file mode 100644 index 0000000000..a339e5b425 --- /dev/null +++ b/data/assets/scene/solarsystem/planets/mars/moons/layers/colorlayers/deimos_viking.asset @@ -0,0 +1,29 @@ +local globeIdentifier = asset.require("./../../deimos").Deimos.Identifier + +local layer = { + Identifier = "Deimos_Global_Mosaic_USGS", + Name = "Deimos Global Mosaic [USGS]", + Enabled = true, + FilePath = "WMS:https://wms.wr.usgs.gov/cgi-bin/mapserv?map=/maps/mars/deimos_simp_cyl.map&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&LAYERS=Deimos_Simple_Cylindrical_Rasters&SRS=EPSG:4326&BBOX=-180,-90,360,90", + Description = [[ This Viking-based cylindrical map of Deimos was created by Philip + Stooke with the assistance of Chris Jongkind and Megan Arntz. Control is based on a + shape model and mosaic by Peter Thomas and colleagues at Cornell University. Date + released 26 October 2001. (Description from URL)]] +} + +asset.onInitialize(function () + openspace.globebrowsing.addLayer(globeIdentifier, "ColorLayers", layer) +end) + +asset.export("layer", layer) + + +asset.meta = { + Name = "Deimos Global Mosaic [USGS]", + Version = "1.0", + Author = "Philip Stooke/NASA", + URL = "https://astrowebmaps.wr.usgs.gov/webmapatlas/Layers/maps.html", + License = "NASA/PDS", + Identifiers = {'Deimos_Global_Mosaic_USGS'} + +} diff --git a/data/assets/scene/solarsystem/planets/mars/moons/layers/colorlayers/phobos_viking.asset b/data/assets/scene/solarsystem/planets/mars/moons/layers/colorlayers/phobos_viking.asset new file mode 100644 index 0000000000..6a0c5b8d9a --- /dev/null +++ b/data/assets/scene/solarsystem/planets/mars/moons/layers/colorlayers/phobos_viking.asset @@ -0,0 +1,26 @@ +local globeIdentifier = asset.require("./../../phobos").Phobos.Identifier + +local layer = { + Identifier = "Phobos_Global_Shaded_Relief_USGS", + Name = "Phobos Global Shaded Relief [USGS]", + Enabled = true, + FilePath = "WMS:https://wms.wr.usgs.gov/cgi-bin/mapserv?map=/maps/mars/phobos_simp_cyl.map&SERVICE=WMS&VERSION=1.1.1&REQUEST=GetMap&LAYERS=Phobos_Simple_Cylindrical_Rasters&SRS=EPSG:4326&BBOX=-180,-90,360,90", + Description = [[ Viking-base Phobos shaded relief created by USGS.]] +} + +asset.onInitialize(function () + openspace.globebrowsing.addLayer(globeIdentifier, "ColorLayers", layer) +end) + +asset.export("layer", layer) + + +asset.meta = { + Name = "Phobos Global Shaded Relief [USGS]", + Version = "1.0", + Author = "USGS/NASA", + URL = "https://astrowebmaps.wr.usgs.gov/webmapatlas/Layers/maps.html", + License = "NASA/PDS", + Identifiers = {'Phobos_Global_Shaded_Relief_USGS'} + +} diff --git a/data/assets/scene/solarsystem/planets/mercury/mercury.asset b/data/assets/scene/solarsystem/planets/mercury/mercury.asset index c2a9ca1584..4ce1efa083 100644 --- a/data/assets/scene/solarsystem/planets/mercury/mercury.asset +++ b/data/assets/scene/solarsystem/planets/mercury/mercury.asset @@ -27,13 +27,15 @@ local Mercury = { Enable = false, FileName = labelsPath .. "/Mercury.labels", LabelAlignmentOption = "Horizontally", -- or Circularly - LabelsFontSize = 40.0, + LabelsFontSize = 22.0, LabelsSize = 10.0, LabelsMinSize = 1.0, LabelsMaxSize = 1500.0, ProximityEnabled = false, - FadeInStartingDistance = 40000000.0, - FadeOutStartingDistance = 80000.0, + LabelsFadeInEnabled = true, + LabelsFadeOutEnabled = true, + FadeInStartingDistance = 5000000.0, + FadeOutStartingDistance = 1800000.0, LabelsForceDomeRendering = true, LabelsDistanceEPS = 1500000.0, LabelsColor = { 1.0, 1.0, 0.0 } diff --git a/data/assets/scene/solarsystem/planets/planets.asset b/data/assets/scene/solarsystem/planets/planets.asset index d7ea310c0b..2c80f258c5 100644 --- a/data/assets/scene/solarsystem/planets/planets.asset +++ b/data/assets/scene/solarsystem/planets/planets.asset @@ -14,6 +14,8 @@ asset.require('./earth/moon/trail') asset.require('./mars/mars') asset.require('./mars/atmosphere') +asset.require('./mars/moons/phobos') +asset.require('./mars/moons/deimos') asset.require('./jupiter/jupiter') asset.require('./jupiter/major_moons') diff --git a/data/assets/scene/solarsystem/planets/saturn/dione/dione.asset b/data/assets/scene/solarsystem/planets/saturn/dione/dione.asset index bee85a6396..34b711430c 100644 --- a/data/assets/scene/solarsystem/planets/saturn/dione/dione.asset +++ b/data/assets/scene/solarsystem/planets/saturn/dione/dione.asset @@ -29,16 +29,17 @@ local Dione = { Enable = false, FileName = labelsPath .. "/dione.labels", LabelAlignmentOption = "Horizontally", -- or Circularly - LabelsFontSize = 14.0, + LabelsFontSize = 32.0, LabelsSize = 8.0, LabelsMinSize = 1.0, LabelsMaxSize = 1500.0, ProximityEnabled = false, LabelsFadeInEnabled = true, - FadeInStartingDistance = 500000.0, + LabelsFadeOutEnabled = true, + FadeInStartingDistance = 3500000.0, FadeOutStartingDistance = 1000000.0, LabelsForceDomeRendering = true, - LabelsDistanceEPS = 1350000.0, + LabelsDistanceEPS = 200000.0, LabelsColor = { 1.0, 1.0, 0.0 } } }, diff --git a/data/assets/scene/solarsystem/planets/saturn/enceladus/enceladus.asset b/data/assets/scene/solarsystem/planets/saturn/enceladus/enceladus.asset index bb66e85ba2..4dd5e1cff5 100644 --- a/data/assets/scene/solarsystem/planets/saturn/enceladus/enceladus.asset +++ b/data/assets/scene/solarsystem/planets/saturn/enceladus/enceladus.asset @@ -29,16 +29,17 @@ local Enceladus = { Enable = false, FileName = labelsPath .. "/enceladus.labels", LabelAlignmentOption = "Horizontally", -- or Circularly - LabelsFontSize = 14.0, + LabelsFontSize = 22.0, LabelsSize = 8.0, LabelsMinSize = 1.0, LabelsMaxSize = 1500.0, ProximityEnabled = false, LabelsFadeInEnabled = true, - FadeInStartingDistance = 500000.0, - FadeOutStartingDistance = 1000000.0, + LabelsFadeOutEnabled = true, + FadeInStartingDistance = 1000000.0, + FadeOutStartingDistance = 500000.0, LabelsForceDomeRendering = true, - LabelsDistanceEPS = 1350000.0, + LabelsDistanceEPS = 100000.0, LabelsColor = { 1.0, 1.0, 0.0 } } }, diff --git a/data/assets/scene/solarsystem/planets/saturn/iapetus/iapetus.asset b/data/assets/scene/solarsystem/planets/saturn/iapetus/iapetus.asset index ec01d7b69a..fbe22a9aec 100644 --- a/data/assets/scene/solarsystem/planets/saturn/iapetus/iapetus.asset +++ b/data/assets/scene/solarsystem/planets/saturn/iapetus/iapetus.asset @@ -29,16 +29,17 @@ local Iapetus = { Enable = false, FileName = labelsPath .. "/iapetus.labels", LabelAlignmentOption = "Horizontally", -- or Circularly - LabelsFontSize = 14.0, + LabelsFontSize = 30.0, LabelsSize = 8.0, LabelsMinSize = 1.0, LabelsMaxSize = 1500.0, ProximityEnabled = false, LabelsFadeInEnabled = true, - FadeInStartingDistance = 500000.0, - FadeOutStartingDistance = 1000000.0, + LabelsFadeOutEnabled = true, + FadeInStartingDistance = 3500000.0, + FadeOutStartingDistance = 600000.0, LabelsForceDomeRendering = true, - LabelsDistanceEPS = 1350000.0, + LabelsDistanceEPS = 250000.0, LabelsColor = { 1.0, 1.0, 0.0 } } }, diff --git a/data/assets/scene/solarsystem/planets/saturn/mimas/mimas.asset b/data/assets/scene/solarsystem/planets/saturn/mimas/mimas.asset index 1ba8d19d3f..7f1b4efab1 100644 --- a/data/assets/scene/solarsystem/planets/saturn/mimas/mimas.asset +++ b/data/assets/scene/solarsystem/planets/saturn/mimas/mimas.asset @@ -35,10 +35,11 @@ local Mimas = { LabelsMaxSize = 1500.0, ProximityEnabled = false, LabelsFadeInEnabled = true, - FadeInStartingDistance = 500000.0, - FadeOutStartingDistance = 1000000.0, + LabelsFadeOutEnabled = true, + FadeInStartingDistance = 1000000.0, + FadeOutStartingDistance = 400000.0, LabelsForceDomeRendering = true, - LabelsDistanceEPS = 1350000.0, + LabelsDistanceEPS = 25000.0, LabelsColor = { 1.0, 1.0, 0.0 } } }, diff --git a/data/assets/scene/solarsystem/planets/saturn/rhea/rhea.asset b/data/assets/scene/solarsystem/planets/saturn/rhea/rhea.asset index fbbe12a40d..83792b1a33 100644 --- a/data/assets/scene/solarsystem/planets/saturn/rhea/rhea.asset +++ b/data/assets/scene/solarsystem/planets/saturn/rhea/rhea.asset @@ -29,16 +29,17 @@ local Rhea = { Enable = false, FileName = labelsPath .. "/rhea.labels", LabelAlignmentOption = "Horizontally", -- or Circularly - LabelsFontSize = 14.0, + LabelsFontSize = 40.0, LabelsSize = 8.0, LabelsMinSize = 1.0, LabelsMaxSize = 1500.0, ProximityEnabled = false, LabelsFadeInEnabled = true, - FadeInStartingDistance = 500000.0, + LabelsFadeOutEnabled = true, + FadeInStartingDistance = 2500000.0, FadeOutStartingDistance = 1000000.0, LabelsForceDomeRendering = true, - LabelsDistanceEPS = 1350000.0, + LabelsDistanceEPS = 250000.0, LabelsColor = { 1.0, 1.0, 0.0 } } }, diff --git a/data/assets/scene/solarsystem/planets/saturn/tethys/tethys.asset b/data/assets/scene/solarsystem/planets/saturn/tethys/tethys.asset index e4440665df..18a97e75c3 100644 --- a/data/assets/scene/solarsystem/planets/saturn/tethys/tethys.asset +++ b/data/assets/scene/solarsystem/planets/saturn/tethys/tethys.asset @@ -29,16 +29,17 @@ local Tethys = { Enable = false, FileName = labelsPath .. "/tethys.labels", LabelAlignmentOption = "Horizontally", -- or Circularly - LabelsFontSize = 14.0, + LabelsFontSize = 24.0, LabelsSize = 8.0, LabelsMinSize = 1.0, LabelsMaxSize = 1500.0, ProximityEnabled = false, LabelsFadeInEnabled = true, - FadeInStartingDistance = 500000.0, - FadeOutStartingDistance = 1000000.0, + LabelsFadeOutEnabled = true, + FadeInStartingDistance = 1500000.0, + FadeOutStartingDistance = 500000.0, LabelsForceDomeRendering = true, - LabelsDistanceEPS = 1350000.0, + LabelsDistanceEPS = 200000.0, LabelsColor = { 1.0, 1.0, 0.0 } } }, diff --git a/data/assets/scene/solarsystem/planets/saturn/titan/titan.asset b/data/assets/scene/solarsystem/planets/saturn/titan/titan.asset index dd947f3214..eaa851c833 100644 --- a/data/assets/scene/solarsystem/planets/saturn/titan/titan.asset +++ b/data/assets/scene/solarsystem/planets/saturn/titan/titan.asset @@ -30,13 +30,14 @@ local Titan = { FileName = labelsPath .. "/titan.labels", LabelAlignmentOption = "Horizontally", -- or Circularly LabelsFontSize = 14.0, - LabelsSize = 8.0, + LabelsSize = 10.0, LabelsMinSize = 1.0, LabelsMaxSize = 1500.0, ProximityEnabled = false, LabelsFadeInEnabled = true, - FadeInStartingDistance = 500000.0, - FadeOutStartingDistance = 1000000.0, + LabelsFadeOutEnabled = true, + FadeInStartingDistance = 7500000.0, + FadeOutStartingDistance = 6000000.0, LabelsForceDomeRendering = true, LabelsDistanceEPS = 1350000.0, LabelsColor = { 1.0, 1.0, 0.0 } diff --git a/data/assets/scene/solarsystem/planets/venus/venus.asset b/data/assets/scene/solarsystem/planets/venus/venus.asset index 0f4c1cbe9f..b1bb529e58 100644 --- a/data/assets/scene/solarsystem/planets/venus/venus.asset +++ b/data/assets/scene/solarsystem/planets/venus/venus.asset @@ -30,15 +30,17 @@ local Venus = { FileName = labelsPath .. "/venus.labels", LabelAlignmentOption = "Horizontally", -- or Circularly LabelsFontSize = 40.0, - LabelsSize = 12.0, + LabelsSize = 10.0, LabelsMinSize = 1.0, LabelsMaxSize = 1500.0, ProximityEnabled = false, LabelsFadeInEnabled = true, - FadeInStartingDistance = 500000.0, - FadeOutStartingDistance = 1000000.0, + LabelsFadeInEnabled = true, + LabelsFadeOutEnabled = true, + FadeInStartingDistance = 7000000.0, + FadeOutStartingDistance = 2000000.0, LabelsForceDomeRendering = true, - LabelsDistanceEPS = 3500000.0, + LabelsDistanceEPS = 4000000.0, LabelsColor = { 1.0, 1.0, 0.0 } } }, diff --git a/data/assets/scene/solarsystem/sun/habitablezone.asset b/data/assets/scene/solarsystem/sun/habitablezone.asset new file mode 100644 index 0000000000..9727e641fa --- /dev/null +++ b/data/assets/scene/solarsystem/sun/habitablezone.asset @@ -0,0 +1,34 @@ +local assetHelper = asset.require("util/asset_helper") +local transforms = asset.require("./transforms") +local textures = asset.require('scene/milkyway/habitable_zones/habitable_zone_textures').TexturesPath + +local HabitableZone = { + Identifier = "SunHabitableZone", + Parent = transforms.SunECLIPJ2000.Identifier, + Renderable = { + Type = "RenderableHabitableZone", + Enabled = false, + Texture = textures .. "/hot_to_cold_faded.png", + EffectiveTemperature = 5780, -- Kelvin + Luminosity = 1, -- solar + Opacity = 0.1 + }, + GUI = { + Name = "Sun Habitable Zone", + Path = "/Solar System/Sun", + Description = "Habitable zone for the sun in our solar system." + } +} + +assetHelper.registerSceneGraphNodesAndExport(asset, { HabitableZone }) + +asset.meta = { + Name = "Sun Habitable Zone", + Version = "1.0", + Description = [[ The habitable zone around our sun, computed using formula and + coefficients by Kopparapu et al. (2015) https://arxiv.org/abs/1404.5292]], + Author = "OpenSpace Team", + URL = "http://openspaceproject.com", + License = "MIT license", + Identifiers = {"SunHabitableZone"} +} diff --git a/data/profiles/mars.profile b/data/profiles/mars.profile index 56d2dd82a6..87493a7562 100644 --- a/data/profiles/mars.profile +++ b/data/profiles/mars.profile @@ -39,7 +39,7 @@ "is_local": false, "key": "I", "name": "Setup scene for insight EDL", - "script": "openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.Mola_Utah.Settings.Offset', -469.300000);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.OnMarsHiRISE-LS-DEM.Settings.Offset', -470.800006);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.OnMarsHiRISE-LS-DEM.Enabled', true);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.ColorLayers.OnMarsHiRISE-LS.Enabled', true);openspace.time.setPause(true);openspace.time.setTime('2018 NOV 26 19:39:03.68');openspace.navigation.setNavigationState({Anchor = 'Insight',Pitch = 0.567457E-4,Position = { 1.240506E1,-1.369270E1,-2.423553E0 },ReferenceFrame = 'Root',Up = { 0.441211E0,0.247019E0,0.862737E0 },Yaw = -0.446853E-4});" + "script": "openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.Mola_Utah.Settings.Offset', -469.300000);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Settings.Offset', -470.800006);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Enabled', true);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-LS.Enabled', true);openspace.time.setPause(true);openspace.time.setTime('2018 NOV 26 19:39:03.68');openspace.navigation.setNavigationState({Anchor = 'Insight',Pitch = 0.567457E-4,Position = { 1.240506E1,-1.369270E1,-2.423553E0 },ReferenceFrame = 'Root',Up = { 0.441211E0,0.247019E0,0.862737E0 },Yaw = -0.446853E-4});" }, { "documentation": "Disable Mars layer settings used for insight EDL", @@ -47,7 +47,7 @@ "is_local": false, "key": "SHIFT+I", "name": "Unset Insight Landing", - "script": "openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.Mola_Utah.Settings.Offset', 0);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.OnMarsHiRISE-LS-DEM.Settings.Offset', 0);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.OnMarsHiRISE-LS-DEM.Enabled', false);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.ColorLayers.OnMarsHiRISE-LS.Enabled', false);" + "script": "openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.Mola_Utah.Settings.Offset', 0);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Settings.Offset', 0);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Enabled', false);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-LS.Enabled', false);" }, { "documentation": "Sets time and layers for Perseverance landing", @@ -55,7 +55,7 @@ "is_local": false, "key": "P", "name": "Setup and Goto Perseverance", - "script": "openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.Mola_Utah.Settings.Offset', -1677.088867);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.OnMarsHiRISE-LS-DEM.Settings.Offset', -1677.088867);openspace.time.setPause(true);openspace.time.setTime('2021 FEB 18 20:32:16');openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.OnMarsHiRISE-LS-DEM.Enabled', true);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.ColorLayers.OnMarsHiRISE-LS.Enabled', true);openspace.navigation.setNavigationState({Anchor = 'Perseverance',Pitch = 0.567457E-4,Position = { 1.240506E1,-1.369270E1,-2.423553E0 },ReferenceFrame = 'Root',Up = { 0.441211E0,0.247019E0,0.862737E0 },Yaw = -0.446853E-4});" + "script": "openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.Mola_Utah.Settings.Offset', -1677.088867);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Settings.Offset', -1677.088867);openspace.time.setPause(true);openspace.time.setTime('2021 FEB 18 20:32:16');openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.HeightLayers.HiRISE-LS-DEM.Enabled', true);openspace.setPropertyValueSingle('Scene.Mars.Renderable.Layers.ColorLayers.HiRISE-LS.Enabled', true);openspace.navigation.setNavigationState({Anchor = 'Perseverance',Pitch = 0.567457E-4,Position = { 1.240506E1,-1.369270E1,-2.423553E0 },ReferenceFrame = 'Root',Up = { 0.441211E0,0.247019E0,0.862737E0 },Yaw = -0.446853E-4});" } ], "mark_nodes": [ @@ -77,6 +77,6 @@ }, "version": { "major": 1, - "minor": 0 + "minor": 1 } } \ No newline at end of file diff --git a/ext/ghoul b/ext/ghoul index e42b3f58c4..2f1bb7c483 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit e42b3f58c493d57afde415cf5be8af88585c320b +Subproject commit 2f1bb7c483f4792317b8f1a3da17e2270c0d0ae7 diff --git a/include/openspace/documentation/documentation.h b/include/openspace/documentation/documentation.h index d01bcd1c82..f40ebb1d06 100644 --- a/include/openspace/documentation/documentation.h +++ b/include/openspace/documentation/documentation.h @@ -323,4 +323,11 @@ std::string to_string(const openspace::documentation::TestResult::Warning::Reaso } // namespace ghoul +// The verifier header depends on the classes defined in here, but we want to make it +// easier for consumers of this header to just have access to all verifiers without +// needing to include this file separately. Particularly with the use of the codegen, it +// might lead to some unexcepted error messages about recognized identifiers in the +// generated code which look scary +#include + #endif // __OPENSPACE_CORE___DOCUMENTATION___H__ diff --git a/include/openspace/documentation/verifier.inl b/include/openspace/documentation/verifier.inl index bcab502137..d61169dd2c 100644 --- a/include/openspace/documentation/verifier.inl +++ b/include/openspace/documentation/verifier.inl @@ -29,6 +29,18 @@ namespace openspace::documentation { +template <> +TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const; + +template <> +TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const; + +template <> +TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const; + template TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dict, const std::string& key) const @@ -122,7 +134,22 @@ TestResult OperatorVerifier::operator()(const ghoul::Dictionary& di { TestResult res = T::operator()(dict, key); if (res.success) { - if (Operator()(dict.value(key), value)) { + typename T::Type val; + if constexpr (std::is_same_v) { + const double d = dict.value(key); + double intPart; + bool isInt = modf(d, &intPart) == 0.0; + if (isInt) { + val = static_cast(d); + } + else { + return { false, { { key, TestResult::Offense::Reason::WrongType } }, {} }; + } + } + else { + val = dict.value(key); + } + if (Operator()(val, value)) { return { true, {}, {} }; } else { @@ -270,7 +297,21 @@ TestResult InRangeVerifier::operator()(const ghoul::Dictionary& dict, { TestResult res = T::operator()(dict, key); if (res.success) { - typename T::Type val = dict.value(key); + typename T::Type val; + if constexpr (std::is_same_v) { + const double d = dict.value(key); + double intPart; + bool isInt = modf(d, &intPart) == 0.0; + if (isInt) { + val = static_cast(d); + } + else { + return { false, { { key, TestResult::Offense::Reason::WrongType } }, {} }; + } + } + else { + val = dict.value(key); + } if (val >= lower && val <= upper) { return { true, {}, {} }; @@ -303,7 +344,21 @@ TestResult NotInRangeVerifier::operator()(const ghoul::Dictionary& dict, const std::string& key) const { TestResult res = T::operator()(dict, key); if (res.success) { - typename T::Type val = dict.value(key); + typename T::Type val; + if constexpr (std::is_same_v) { + const double d = dict.value(key); + double intPart; + bool isInt = modf(d, &intPart) == 0.0; + if (isInt) { + val = static_cast(d); + } + else { + return { false, { { key, TestResult::Offense::Reason::WrongType } }, {} }; + } + } + else { + val = dict.value(key); + } if (val >= lower && val <= upper) { return { false, { { key, TestResult::Offense::Reason::Verification } }, {} }; diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index a2204ace37..42612a9368 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -139,4 +139,11 @@ private: } // namespace openspace +// Lua functions - exposed for testing +namespace openspace::luascriptfunctions { + +int createSingeColorImage(lua_State* L); + +} // openspace::luascriptfunctions + #endif // __OPENSPACE_CORE___OPENSPACEENGINE___H__ diff --git a/include/openspace/properties/propertyowner.h b/include/openspace/properties/propertyowner.h index d37c6d7b9b..d20257fe9d 100644 --- a/include/openspace/properties/propertyowner.h +++ b/include/openspace/properties/propertyowner.h @@ -294,7 +294,6 @@ public: // Generate JSON for documentation std::string generateJson() const override; - protected: /// The unique identifier of this PropertyOwner std::string _identifier; diff --git a/include/openspace/rendering/renderable.h b/include/openspace/rendering/renderable.h index 884d10bee1..3fa96880d4 100644 --- a/include/openspace/rendering/renderable.h +++ b/include/openspace/rendering/renderable.h @@ -61,7 +61,7 @@ public: }; static ghoul::mm_unique_ptr createFromDictionary( - const ghoul::Dictionary& dictionary); + ghoul::Dictionary dictionary); Renderable(const ghoul::Dictionary& dictionary); virtual ~Renderable() = default; diff --git a/include/openspace/rendering/texturecomponent.h b/include/openspace/rendering/texturecomponent.h new file mode 100644 index 0000000000..5c4d905a7c --- /dev/null +++ b/include/openspace/rendering/texturecomponent.h @@ -0,0 +1,72 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___TEXTURECOMPONENT___H__ +#define __OPENSPACE_CORE___TEXTURECOMPONENT___H__ + +#include + +namespace ghoul::filesystem { class File; } +namespace ghoul::opengl {class Texture; } + +namespace openspace { + +class TextureComponent { +public: + using Texture = ghoul::opengl::Texture; + + const Texture* texture() const; + Texture* texture(); + + void setFilterMode(Texture::FilterMode filterMode); + void setWrapping(Texture::WrappingMode wrapping); + void setShouldWatchFileForChanges(bool value); + void setShouldPurgeFromRAM(bool value); + + void bind(); + void uploadToGpu(); + + // Loads a texture from a file on disk + void loadFromFile(const std::string& path); + + // Function to call in a renderable's update function to make sure + // the texture is kept up to date + void update(); + +private: + std::unique_ptr _textureFile; + std::unique_ptr _texture; + + Texture::FilterMode _filterMode = Texture::FilterMode::LinearMipMap; + Texture::WrappingMode _wrappingMode = Texture::WrappingMode::Repeat; + bool _shouldWatchFile = true; + bool _shouldPurgeFromRAM = true; + + bool _fileIsDirty = false; + bool _textureIsDirty = false; +}; + +} // namespace openspace + +#endif // __OPENSPACE_CORE___TEXTURECOMPONENT___H__ diff --git a/include/openspace/util/planegeometry.h b/include/openspace/util/planegeometry.h new file mode 100644 index 0000000000..2b29302c79 --- /dev/null +++ b/include/openspace/util/planegeometry.h @@ -0,0 +1,57 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___PLANEGEOMETRY___H__ +#define __OPENSPACE_CORE___PLANEGEOMETRY___H__ + +#include +#include + +namespace openspace { + +class PlaneGeometry { +public: + PlaneGeometry(glm::vec2 size); + PlaneGeometry(float size); + + ~PlaneGeometry(); + + void initialize(); + void deinitialize(); + void render(); + + void updateSize(const glm::vec2& size); + void updateSize(const float size); + +private: + void updateGeometry(); + + GLuint _vaoId = 0; + GLuint _vBufferId = 0; + glm::vec2 _size = glm::vec2(0.f); +}; + +} // namespace openspace + +#endif // __OPENSPACE_CORE___PLANEGEOMETRY___H__ diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index 330ad3664b..b08c0bf7e5 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -288,6 +288,8 @@ foreach (val RANGE ${enabled_module_count}) list(APPEND all_enabled_modules "${library_name}") begin_header("Module ${name} (${library_name})") add_subdirectory(${path}) + # Make sure that the code generator always runs before a module + add_dependencies(${library_name} run_codegen) end_header("End: Module ${name}") message(STATUS "") diff --git a/modules/atmosphere/rendering/renderableatmosphere.cpp b/modules/atmosphere/rendering/renderableatmosphere.cpp index cbeb0a028a..4859a00628 100644 --- a/modules/atmosphere/rendering/renderableatmosphere.cpp +++ b/modules/atmosphere/rendering/renderableatmosphere.cpp @@ -47,6 +47,7 @@ #include #include #include +#include #ifdef WIN32 #define _USE_MATH_DEFINES @@ -54,27 +55,6 @@ #include namespace { - static const char* _loggerCat = "RenderableAtmosphere"; - - constexpr const char* KeyShadowGroup = "ShadowGroup"; - constexpr const char* KeyShadowSource = "Source"; - constexpr const char* KeyShadowCaster = "Caster"; - - constexpr const char* KeyPlanetRadius = "PlanetRadius"; - constexpr const char* KeyAverageGroundReflectance = "PlanetAverageGroundReflectance"; - constexpr const char* KeyRayleigh = "Rayleigh"; - constexpr const char* KeyRayleighHeightScale = "H_R"; - constexpr const char* KeyOzone = "Ozone"; - constexpr const char* KeyOzoneHeightScale = "H_O"; - constexpr const char* KeyMie = "Mie"; - constexpr const char* KeyMieHeightScale = "H_M"; - constexpr const char* KeyMiePhaseConstant = "G"; - constexpr const char* KeyImage = "Image"; - constexpr const char* KeyToneMappingOp = "ToneMapping"; - constexpr const char* KeyATMDebug = "Debug"; - constexpr const char* KeyTextureScale = "PreCalculatedTextureScale"; - constexpr const char* KeySaveTextures = "SaveCalculatedTextures"; - constexpr openspace::properties::Property::PropertyInfo AtmosphereHeightInfo = { "AtmosphereHeight", "Atmosphere Height (KM)", @@ -174,238 +154,97 @@ namespace { "Enable Hard Shadows for Eclipses", "Enable/Disables hard shadows through the atmosphere" }; + + + struct [[codegen::Dictionary(RenderableAtmosphere)]] Parameters { + struct ShadowGroup { + // Individual light sources + struct SourceElement { + // The scene graph node name of the source + std::string name; + // The radius of the object in meters + double radius; + }; + // A list of light sources + std::vector sources; + + // Individual shadow casters + struct CasterElement { + // The scene graph node name of the source + std::string name; + // The radius of the object in meters + double radius; + }; + + // A list of objects that cast light on this atmosphere + std::vector casters; + }; + // Declares shadow groups, meaning which nodes are considered in shadow calculations + std::optional shadowGroup; + + // [[codegen::verbatim(AtmosphereHeightInfo.description)]] + float atmosphereHeight; + + // The radius of the planet in meters + float planetRadius; + + float planetAverageGroundReflectance; + + // [[codegen::verbatim(SunIntensityInfo.description)]] + std::optional sunIntensity; + + // [[codegen::verbatim(MieScatteringExtinctionPropCoeffInfo.description)]] + std::optional mieScatteringExtinctionPropCoefficient; + + // [[codegen::verbatim(GroundRadianceEmittioninfo.description)]] + float groundRadianceEmission; + + struct Rayleigh { + struct Coefficients { + glm::dvec3 wavelengths; + glm::dvec3 scattering; + }; + Coefficients coefficients; + float heightScale [[codegen::key("H_R")]]; + }; + Rayleigh rayleigh; + + struct Ozone { + struct Coefficients { + std::optional extinction; + }; + std::optional coefficients; + std::optional heightScale [[codegen::key("H_O")]]; + }; + std::optional ozone; + + struct Mie { + struct Coefficients { + glm::dvec3 scattering; + glm::dvec3 extinction; + }; + Coefficients coefficients; + float heightScale [[codegen::key("H_M")]]; + float phaseConstant [[codegen::key("G"), codegen::inrange(-1.0, 1.0)]]; + }; + Mie mie; + + struct ATMDebug { + std::optional preCalculatedTextureScale [[codegen::inrange(0.0, 1.0)]]; + std::optional saveCalculatedTextures; + }; + std::optional debug; + }; +#include "renderableatmosphere_codegen.cpp" + } // namespace namespace openspace { documentation::Documentation RenderableAtmosphere::Documentation() { - using namespace documentation; - - TableVerifier* shadowGroupTable = new TableVerifier({ - { - "Sources", - new TableVerifier({ - { - "*", - new TableVerifier({ - { - "Name", - new StringVerifier, - Optional::No, - "The scene graph node name of the source" - }, - { - "Radius", - new DoubleVerifier, - Optional::No, - "The radius of the object in meters" - } - }), - Optional::Yes, - "Individual light sources" - } - }), - Optional::No, - "A list of light sources" - }, - { - "Casters", - new TableVerifier({ - { - "*", - new TableVerifier({ - { - "Name", - new StringVerifier, - Optional::No, - "The scene graph node name of the caster" - }, - { - "Radius", - new DoubleVerifier, - Optional::No, - "The radius of the object in meters" - } - }), - Optional::Yes, - "Individual shadow casters" - } - }), - Optional::No, - "A list of objects that cast light on this atmosphere" - } - }); - - TableVerifier* rayleighTable = new TableVerifier({ - { - "Coefficients", - new TableVerifier({ - { - "Wavelengths", - new DoubleVector3Verifier, - Optional::Yes, - "" - }, - { - "Scattering", - new DoubleVector3Verifier, - Optional::No, - "" - } - }), - Optional::No, - "" - }, - { - KeyRayleighHeightScale, - new DoubleVerifier, - Optional::No, - "" - }, - }); - - TableVerifier* ozoneTable = new TableVerifier({ - { - KeyOzoneHeightScale, - new DoubleVerifier, - Optional::Yes, - "" - }, - { - "Coefficients", - new TableVerifier({ - { - "Extinction", - new DoubleVector4Verifier, - Optional::Yes, - "" - } - }), - Optional::Yes, - "" - } - }); - - TableVerifier* mieTable = new TableVerifier({ - { - KeyMieHeightScale, - new DoubleVerifier, - Optional::No, - "" - }, - { - "Coefficients", - new TableVerifier({ - { - "Scattering", - new DoubleVector3Verifier, - Optional::No, - "" - }, - { - "Extinction", - new DoubleVector3Verifier, - Optional::No, - "" - } - }), - Optional::No, - "" - }, - { - KeyMiePhaseConstant, - new DoubleInRangeVerifier(-1.0, 1.0), - Optional::No, - "" - } - }); - - return { - "RenderableAtmosphere", - "atmosphere_renderable_atmosphere", - { - { - KeyShadowGroup, - shadowGroupTable, - Optional::Yes, - "Declares shadow groups, meaning which nodes are considered in shadow " - "calculations" - }, - { - AtmosphereHeightInfo.identifier, - new DoubleVerifier, - Optional::No, - AtmosphereHeightInfo.description - }, - { - KeyPlanetRadius, - new DoubleVerifier, - Optional::No, - "The radius of the planet in meters" - }, - { - KeyAverageGroundReflectance, - new DoubleVerifier, - Optional::No, - "" - }, - { - SunIntensityInfo.identifier, - new DoubleVerifier, - Optional::Yes, - SunIntensityInfo.description - }, - { - MieScatteringExtinctionPropCoeffInfo.identifier, - new DoubleVerifier, - Optional::Yes, - MieScatteringExtinctionPropCoeffInfo.description - }, - { - GroundRadianceEmittioninfo.identifier, - new DoubleVerifier, - Optional::No, - GroundRadianceEmittioninfo.description - }, - { - KeyRayleigh, - rayleighTable, - Optional::No, - "" - }, - { - KeyOzone, - ozoneTable, - Optional::Yes, - "" - }, - { - KeyMie, - mieTable, - Optional::No, - "" - }, - { - KeyATMDebug, - new TableVerifier({ - { - KeyTextureScale, - new DoubleInRangeVerifier(0.0, 1.0), - Optional::Yes, - "" - }, - { - KeySaveTextures, - new BoolVerifier, - Optional::Yes, - "" - } - }), - Optional::Yes, - "" - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "atmosphere_renderable_atmosphere"; + return doc; } RenderableAtmosphere::RenderableAtmosphere(const ghoul::Dictionary& dictionary) @@ -438,139 +277,6 @@ RenderableAtmosphere::RenderableAtmosphere(const ghoul::Dictionary& dictionary) , _sunFollowingCameraEnabled(EnableSunOnCameraPositionInfo, false) , _hardShadowsEnabled(EclipseHardShadowsInfo, false) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableAtmosphere" - ); - - //================================================================ - //======== Reads Shadow (Eclipses) Entries in asset file ========= - //================================================================ - if (dictionary.hasKey(KeyShadowGroup)) { - ghoul::Dictionary shadowDictionary = - dictionary.value(KeyShadowGroup); - - std::vector> sourceArray; - ghoul::Dictionary sources = shadowDictionary.value("Sources"); - for (std::string_view k : sources.keys()) { - ghoul::Dictionary source = sources.value(k); - - std::string name = source.value("Name"); - double radius = source.value("Radius"); - sourceArray.emplace_back(name, radius); - } - - std::vector> casterArray; - ghoul::Dictionary casters = shadowDictionary.value("Casters"); - for (std::string_view k : casters.keys()) { - ghoul::Dictionary caster = casters.value(k); - - std::string name = caster.value("Name"); - double radius = caster.value("Radius"); - casterArray.emplace_back(name, radius); - } - - _shadowEnabled = !sourceArray.empty() && !casterArray.empty(); - for (const std::pair& source : sourceArray) { - for (const std::pair& caster : casterArray) { - ShadowConfiguration sc; - sc.source = source; - sc.caster = caster; - _shadowConfArray.push_back(sc); - } - } - } - - //================================================================ - //========== Reads Atmosphere Entries from asset file ============ - //================================================================ - _atmosphereHeight = static_cast( - dictionary.value(AtmosphereHeightInfo.identifier) - ); - _planetRadius = static_cast(dictionary.value(KeyPlanetRadius)); - _groundAverageReflectance = static_cast( - dictionary.value(KeyAverageGroundReflectance) - ); - _groundRadianceEmission = static_cast( - dictionary.value(GroundRadianceEmittioninfo.identifier) - ); - - if (dictionary.hasKey(SunIntensityInfo.identifier)) { - _sunIntensity = static_cast( - dictionary.value(SunIntensityInfo.identifier) - ); - } - - if (dictionary.hasKey(MieScatteringExtinctionPropCoeffInfo.identifier)) { - _mieScattExtPropCoefProp = static_cast( - dictionary.value(MieScatteringExtinctionPropCoeffInfo.identifier) - ); - } - - { - ghoul::Dictionary rayleighDict = dictionary.value(KeyRayleigh); - - ghoul::Dictionary coeffs = rayleighDict.value("Coefficients"); - _rayleighScatteringCoeff = coeffs.value("Scattering"); - - _rayleighHeightScale = static_cast( - rayleighDict.value(KeyRayleighHeightScale) - ); - } - - if (dictionary.hasValue(KeyOzone)) { - ghoul::Dictionary ozoneDict = dictionary.value(KeyOzone); - - if (ozoneDict.hasValue(KeyOzoneHeightScale)) { - _ozoneHeightScale = static_cast( - ozoneDict.value(KeyOzoneHeightScale) - ); - _ozoneEnabled = true; - } - - if (ozoneDict.hasValue("Coefficients")) { - ghoul::Dictionary coeff = ozoneDict.value("Coefficients"); - if (coeff.hasValue("Extinction")) { - _ozoneCoeff = coeff.value("Extinction"); - } - } - } - - { - ghoul::Dictionary mieDict = dictionary.value(KeyMie); - _mieHeightScale = static_cast(mieDict.value(KeyMieHeightScale)); - - ghoul::Dictionary coeffs = mieDict.value("Coefficients"); - - _mieScatteringCoeff = coeffs.value("Scattering"); - _mieExtinctionCoeff = coeffs.value("Extinction"); - - _miePhaseConstant = static_cast( - mieDict.value(KeyMiePhaseConstant) - ); - } - - if (dictionary.hasValue(KeyATMDebug)) { - ghoul::Dictionary debugDict = dictionary.value(KeyATMDebug); - if (debugDict.hasKey(KeyTextureScale)) { - _preCalculatedTexturesScale = static_cast( - debugDict.value(KeyTextureScale) - ); - LDEBUG(fmt::format( - "Atmosphere Texture Scaled to {}", _preCalculatedTexturesScale - )); - } - - if (debugDict.hasKey(KeySaveTextures)) { - _saveCalculationsToTexture = debugDict.value(KeySaveTextures); - LDEBUG("Saving Precalculated Atmosphere Textures"); - } - } - - //======================================================== - //============== Atmosphere Properties =================== - //======================================================== auto updateWithCalculation = [this]() { _deferredCasterNeedsUpdate = true; _deferredCasterNeedsCalculation = true; @@ -579,48 +285,93 @@ RenderableAtmosphere::RenderableAtmosphere(const ghoul::Dictionary& dictionary) _deferredCasterNeedsUpdate = true; }; + const Parameters p = codegen::bake(dictionary); + + _shadowEnabled = p.shadowGroup.has_value(); + if (_shadowEnabled) { + for (const Parameters::ShadowGroup::SourceElement& s : p.shadowGroup->sources) { + for (const Parameters::ShadowGroup::CasterElement& c : + p.shadowGroup->casters) + { + ShadowConfiguration sc; + sc.source = std::pair(s.name, s.radius); + sc.caster = std::pair(c.name, c.radius); + _shadowConfArray.push_back(sc); + } + } + } + + _atmosphereHeight = p.atmosphereHeight; _atmosphereHeight.onChange(updateWithCalculation); addProperty(_atmosphereHeight); + _planetRadius = p.planetRadius; + + _groundAverageReflectance = p.planetAverageGroundReflectance; _groundAverageReflectance.onChange(updateWithCalculation); addProperty(_groundAverageReflectance); - _groundRadianceEmission.onChange(updateWithoutCalculation); - addProperty(_groundRadianceEmission); + _sunIntensity = p.sunIntensity.value_or(_sunIntensity); + _sunIntensity.onChange(updateWithoutCalculation); + addProperty(_sunIntensity); - _rayleighHeightScale.onChange(updateWithCalculation); - addProperty(_rayleighHeightScale); + _mieScattExtPropCoefProp = + p.mieScatteringExtinctionPropCoefficient.value_or(_mieScattExtPropCoefProp); + _rayleighScatteringCoeff = p.rayleigh.coefficients.scattering; _rayleighScatteringCoeff.onChange(updateWithCalculation); addProperty(_rayleighScatteringCoeff); + _rayleighHeightScale = p.rayleigh.heightScale; + _rayleighHeightScale.onChange(updateWithCalculation); + addProperty(_rayleighHeightScale); + + if (p.ozone.has_value()) { + _ozoneHeightScale = p.ozone->heightScale.value_or(_ozoneHeightScale); + _ozoneEnabled = p.ozone->heightScale.has_value(); + + if (p.ozone->coefficients.has_value()) { + _ozoneCoeff = p.ozone->coefficients->extinction.value_or(_ozoneCoeff); + } + } _ozoneEnabled.onChange(updateWithCalculation); addProperty(_ozoneEnabled); - _ozoneHeightScale.onChange(updateWithCalculation); addProperty(_ozoneHeightScale); - _ozoneCoeff.onChange(updateWithCalculation); addProperty(_ozoneCoeff); + _mieHeightScale = p.mie.heightScale; _mieHeightScale.onChange(updateWithCalculation); addProperty(_mieHeightScale); + _mieScatteringCoeff = p.mie.coefficients.scattering; _mieScatteringCoeff.onChange(updateWithCalculation); addProperty(_mieScatteringCoeff); + _mieExtinctionCoeff = p.mie.coefficients.extinction; + _miePhaseConstant = p.mie.phaseConstant; + _miePhaseConstant.onChange(updateWithCalculation); + addProperty(_miePhaseConstant); + _mieScatteringExtinctionPropCoefficient = _mieScattExtPropCoefProp != 1.f ? _mieScattExtPropCoefProp : _mieScatteringCoeff.value().x / _mieExtinctionCoeff.x; _mieScatteringExtinctionPropCoefficient.onChange(updateWithCalculation); addProperty(_mieScatteringExtinctionPropCoefficient); + + if (p.debug.has_value()) { + _preCalculatedTexturesScale = + p.debug->preCalculatedTextureScale.value_or(_preCalculatedTexturesScale); - _miePhaseConstant.onChange(updateWithCalculation); - addProperty(_miePhaseConstant); + _saveCalculationsToTexture = + p.debug->saveCalculatedTextures.value_or(_saveCalculationsToTexture); + } - _sunIntensity.onChange(updateWithoutCalculation); - addProperty(_sunIntensity); + _groundRadianceEmission = p.groundRadianceEmission; + _groundRadianceEmission.onChange(updateWithoutCalculation); + addProperty(_groundRadianceEmission); _sunFollowingCameraEnabled.onChange(updateWithoutCalculation); addProperty(_sunFollowingCameraEnabled); diff --git a/modules/base/CMakeLists.txt b/modules/base/CMakeLists.txt index 55519e8c01..521cf3f950 100644 --- a/modules/base/CMakeLists.txt +++ b/modules/base/CMakeLists.txt @@ -45,6 +45,7 @@ set(HEADER_FILES rendering/grids/renderableradialgrid.h rendering/grids/renderablesphericalgrid.h rendering/renderablecartesianaxes.h + rendering/renderabledisc.h rendering/renderablelabels.h rendering/renderablemodel.h rendering/renderablenodeline.h @@ -73,7 +74,6 @@ set(HEADER_FILES translation/luatranslation.h translation/statictranslation.h translation/timelinetranslation.h - ) source_group("Header Files" FILES ${HEADER_FILES}) @@ -98,6 +98,7 @@ set(SOURCE_FILES rendering/grids/renderableradialgrid.cpp rendering/grids/renderablesphericalgrid.cpp rendering/renderablecartesianaxes.cpp + rendering/renderabledisc.cpp rendering/renderablelabels.cpp rendering/renderablemodel.cpp rendering/renderablenodeline.cpp @@ -132,6 +133,8 @@ source_group("Source Files" FILES ${SOURCE_FILES}) set(SHADER_FILES shaders/axes_fs.glsl shaders/axes_vs.glsl + shaders/disc_fs.glsl + shaders/disc_vs.glsl shaders/grid_vs.glsl shaders/grid_fs.glsl shaders/imageplane_fs.glsl diff --git a/modules/base/basemodule.cpp b/modules/base/basemodule.cpp index 6a9ebdce24..09ef673631 100644 --- a/modules/base/basemodule.cpp +++ b/modules/base/basemodule.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -129,6 +130,7 @@ void BaseModule::internalInitialize(const ghoul::Dictionary&) { fRenderable->registerClass("RenderableBoxGrid"); fRenderable->registerClass("RenderableCartesianAxes"); + fRenderable->registerClass("RenderableDisc"); fRenderable->registerClass("RenderableGrid"); fRenderable->registerClass("RenderableLabels"); fRenderable->registerClass("RenderableModel"); @@ -206,6 +208,7 @@ std::vector BaseModule::documentations() const { RenderableNodeLine::Documentation(), RenderablePlane::Documentation(), RenderableRadialGrid::Documentation(), + RenderableDisc::Documentation(), RenderableSphere::Documentation(), RenderableSphericalGrid::Documentation(), RenderableTrailOrbit::Documentation(), diff --git a/modules/base/dashboard/dashboarditemangle.cpp b/modules/base/dashboard/dashboarditemangle.cpp index 42ae2afbf4..5034b763dc 100644 --- a/modules/base/dashboard/dashboarditemangle.cpp +++ b/modules/base/dashboard/dashboarditemangle.cpp @@ -85,66 +85,36 @@ namespace { "If a scene graph node is selected as type, this value specifies the name of the " "node that is to be used as the destination for computing the angle." }; + + struct [[codegen::Dictionary(DashboardItemAngle)]] Parameters { + enum class Type { + Node, + Focus, + Camera + }; + + // [[codegen::verbatim(SourceTypeInfo.description)]] + std::optional sourceType; + // [[codegen::verbatim(SourceNodeNameInfo.description)]] + std::optional sourceNodeName; + // [[codegen::verbatim(ReferenceTypeInfo.description)]] + Type referenceType; + // [[codegen::verbatim(ReferenceNodeNameInfo.description)]] + std::optional referenceNodeName; + // [[codegen::verbatim(DestinationTypeInfo.description)]] + std::optional destinationType; + // [[codegen::verbatim(DestinationNodeNameInfo.description)]] + std::optional destinationNodeName; + }; +#include "dashboarditemangle_codegen.cpp" } // namespace namespace openspace { documentation::Documentation DashboardItemAngle::Documentation() { - using namespace documentation; - - return { - "DashboardItem Angle", - "base_dashboarditem_angle", - { - { - "Type", - new StringEqualVerifier("DashboardItemAngle"), - Optional::No - }, - { - SourceTypeInfo.identifier, - new StringInListVerifier({ - "Node", "Focus", "Camera" - }), - Optional::Yes, - SourceTypeInfo.description - }, - { - SourceNodeNameInfo.identifier, - new StringVerifier, - Optional::Yes, - SourceNodeNameInfo.description - }, - { - ReferenceTypeInfo.identifier, - new StringInListVerifier({ - "Node", "Focus", "Camera" - }), - Optional::No, - ReferenceTypeInfo.description - }, - { - ReferenceNodeNameInfo.identifier, - new StringVerifier, - Optional::Yes, - ReferenceNodeNameInfo.description - }, - { - DestinationTypeInfo.identifier, - new StringInListVerifier({ - "Node", "Focus", "Camera" - }), - Optional::Yes, - DestinationTypeInfo.description - }, - { - DestinationNodeNameInfo.identifier, - new StringVerifier, - Optional::Yes, - DestinationNodeNameInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_dashboarditem_angle"; + return doc; } DashboardItemAngle::DashboardItemAngle(const ghoul::Dictionary& dictionary) @@ -174,11 +144,7 @@ DashboardItemAngle::DashboardItemAngle(const ghoul::Dictionary& dictionary) nullptr } { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "DashboardItemAngle" - ); + const Parameters p = codegen::bake(dictionary); _source.type.addOptions({ { Type::Node, "Node" }, @@ -190,16 +156,17 @@ DashboardItemAngle::DashboardItemAngle(const ghoul::Dictionary& dictionary) properties::Property::Visibility(_source.type == Type::Node) ); }); - if (dictionary.hasKey(SourceTypeInfo.identifier)) { - std::string value = dictionary.value(SourceTypeInfo.identifier); - if (value == "Node") { - _source.type = Type::Node; - } - else if (value == "Focus") { - _source.type = Type::Focus; - } - else { - _source.type = Type::Camera; + if (p.sourceType.has_value()) { + switch (*p.sourceType) { + case Parameters::Type::Node: + _source.type = Type::Node; + break; + case Parameters::Type::Focus: + _source.type = Type::Focus; + break; + default: + _source.type = Type::Camera; + break; } } else { @@ -209,10 +176,8 @@ DashboardItemAngle::DashboardItemAngle(const ghoul::Dictionary& dictionary) _source.nodeName.onChange([this]() { _source.node = nullptr; }); if (_source.type == Type::Node) { - if (dictionary.hasKey(SourceNodeNameInfo.identifier)) { - _source.nodeName = dictionary.value( - SourceNodeNameInfo.identifier - ); + if (p.sourceNodeName.has_value()) { + _source.nodeName = *p.sourceNodeName; } else { LERRORC( @@ -234,24 +199,23 @@ DashboardItemAngle::DashboardItemAngle(const ghoul::Dictionary& dictionary) properties::Property::Visibility(_reference.type == Type::Node) ); }); - std::string value = dictionary.value(ReferenceTypeInfo.identifier); - if (value == "Node") { - _reference.type = Type::Node; - } - else if (value == "Focus") { - _reference.type = Type::Focus; - } - else { - _reference.type = Type::Camera; + switch (p.referenceType) { + case Parameters::Type::Node: + _reference.type = Type::Node; + break; + case Parameters::Type::Focus: + _reference.type = Type::Focus; + break; + default: + _reference.type = Type::Camera; + break; } addProperty(_reference.type); _reference.nodeName.onChange([this]() { _reference.node = nullptr; }); if (_reference.type == Type::Node) { - if (dictionary.hasKey(ReferenceNodeNameInfo.identifier)) { - _reference.nodeName = dictionary.value( - ReferenceNodeNameInfo.identifier - ); + if (p.referenceNodeName.has_value()) { + _reference.nodeName = *p.referenceNodeName; } else { LERRORC( @@ -272,16 +236,17 @@ DashboardItemAngle::DashboardItemAngle(const ghoul::Dictionary& dictionary) properties::Property::Visibility(_source.type == Type::Node) ); }); - if (dictionary.hasKey(DestinationTypeInfo.identifier)) { - std::string type = dictionary.value(DestinationTypeInfo.identifier); - if (type == "Node") { - _destination.type = Type::Node; - } - else if (type == "Focus") { - _destination.type = Type::Focus; - } - else { - _destination.type = Type::Camera; + if (p.destinationType.has_value()) { + switch (*p.destinationType) { + case Parameters::Type::Node: + _destination.type = Type::Node; + break; + case Parameters::Type::Focus: + _destination.type = Type::Focus; + break; + default: + _destination.type = Type::Camera; + break; } } else { @@ -290,10 +255,8 @@ DashboardItemAngle::DashboardItemAngle(const ghoul::Dictionary& dictionary) addProperty(_destination.type); _destination.nodeName.onChange([this]() { _destination.node = nullptr; }); if (_destination.type == Type::Node) { - if (dictionary.hasKey(DestinationNodeNameInfo.identifier)) { - _destination.nodeName = dictionary.value( - DestinationNodeNameInfo.identifier - ); + if (p.destinationNodeName.has_value()) { + _destination.nodeName = *p.destinationNodeName; } else { LERRORC( diff --git a/modules/base/dashboard/dashboarditemdate.cpp b/modules/base/dashboard/dashboarditemdate.cpp index f47f5b9b44..87dc11ac6c 100644 --- a/modules/base/dashboard/dashboarditemdate.cpp +++ b/modules/base/dashboard/dashboarditemdate.cpp @@ -51,35 +51,23 @@ namespace { "https://naif.jpl.nasa.gov/pub/naif/toolkit_docs/C/cspice/timout_c.html for full " "information about how to structure this format" }; + + struct [[codegen::Dictionary(DashboardItemDate)]] Parameters { + // [[codegen::verbatim(FormatStringInfo.description)]] + std::optional formatString; + + // [[codegen::verbatim(TimeFormatInfo.description)]] + std::optional timeFormat; + }; +#include "dashboarditemdate_codegen.cpp" } // namespace namespace openspace { documentation::Documentation DashboardItemDate::Documentation() { - using namespace documentation; - return { - "DashboardItem Date", - "base_dashboarditem_date", - { - { - "Type", - new StringEqualVerifier("DashboardItemDate"), - Optional::No - }, - { - FormatStringInfo.identifier, - new StringVerifier, - Optional::Yes, - FormatStringInfo.description - }, - { - TimeFormatInfo.identifier, - new StringVerifier, - Optional::Yes, - TimeFormatInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_dashboarditem_date"; + return doc; } DashboardItemDate::DashboardItemDate(const ghoul::Dictionary& dictionary) @@ -87,20 +75,12 @@ DashboardItemDate::DashboardItemDate(const ghoul::Dictionary& dictionary) , _formatString(FormatStringInfo, "Date: {} UTC") , _timeFormat(TimeFormatInfo, "YYYY MON DDTHR:MN:SC.### ::RND") { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "DashboardItemDate" - ); + const Parameters p = codegen::bake(dictionary); - if (dictionary.hasKey(FormatStringInfo.identifier)) { - _formatString = dictionary.value(FormatStringInfo.identifier); - } + _formatString = p.formatString.value_or(_formatString); addProperty(_formatString); - if (dictionary.hasKey(TimeFormatInfo.identifier)) { - _timeFormat = dictionary.value(TimeFormatInfo.identifier); - } + _timeFormat = p.timeFormat.value_or(_timeFormat); addProperty(_timeFormat); } diff --git a/modules/base/dashboard/dashboarditemdistance.cpp b/modules/base/dashboard/dashboarditemdistance.cpp index f973743453..bcca68c879 100644 --- a/modules/base/dashboard/dashboarditemdistance.cpp +++ b/modules/base/dashboard/dashboarditemdistance.cpp @@ -104,69 +104,45 @@ namespace { ); return res; } + + struct [[codegen::Dictionary(DashboardItemDistance)]] Parameters { + enum class TypeInfo { + Node, + NodeSurface [[codegen::key("Node Surface")]], + Focus, + Camera + }; + + // [[codegen::verbatim(SourceTypeInfo.description)]] + std::optional sourceType; + + // [[codegen::verbatim(SourceNodeNameInfo.description)]] + std::optional sourceNodeName; + + // [[codegen::verbatim(DestinationTypeInfo.description)]] + std::optional destinationType; + + // [[codegen::verbatim(DestinationNodeNameInfo.description)]] + std::optional destinationNodeName; + + // [[codegen::verbatim(SimplificationInfo.description)]] + std::optional simplification; + + // [[codegen::verbatim(RequestedUnitInfo.description)]] + std::optional requestedUnit [[codegen::inlist(unitList())]]; + + // [[codegen::verbatim(FormatStringInfo.description)]] + std::optional formatString; + }; +#include "dashboarditemdistance_codegen.cpp" } // namespace namespace openspace { documentation::Documentation DashboardItemDistance::Documentation() { - using namespace documentation; - return { - "DashboardItem Distance", - "base_dashboarditem_distance", - { - { - "Type", - new StringEqualVerifier("DashboardItemDistance"), - Optional::No - }, - { - SourceTypeInfo.identifier, - new StringInListVerifier({ - "Node", "Node Surface", "Focus", "Camera" - }), - Optional::Yes, - SourceTypeInfo.description - }, - { - SourceNodeNameInfo.identifier, - new StringVerifier, - Optional::Yes, - SourceNodeNameInfo.description - }, - { - DestinationTypeInfo.identifier, - new StringInListVerifier({ - "Node", "Node Surface", "Focus", "Camera" - }), - Optional::Yes, - DestinationTypeInfo.description - }, - { - DestinationNodeNameInfo.identifier, - new StringVerifier, - Optional::Yes, - DestinationNodeNameInfo.description - }, - { - SimplificationInfo.identifier, - new BoolVerifier, - Optional::Yes, - SimplificationInfo.description - }, - { - RequestedUnitInfo.identifier, - new StringInListVerifier(unitList()), - Optional::Yes, - RequestedUnitInfo.description - }, - { - FormatStringInfo.identifier, - new StringVerifier, - Optional::Yes, - FormatStringInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_dashboarditem_distance"; + return doc; } DashboardItemDistance::DashboardItemDistance(const ghoul::Dictionary& dictionary) @@ -191,11 +167,7 @@ DashboardItemDistance::DashboardItemDistance(const ghoul::Dictionary& dictionary nullptr } { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "DashboardItemDistance" - ); + const Parameters p = codegen::bake(dictionary); _source.type.addOptions({ { Type::Node, "Node" }, @@ -210,22 +182,20 @@ DashboardItemDistance::DashboardItemDistance(const ghoul::Dictionary& dictionary ) ); }); - if (dictionary.hasKey(SourceTypeInfo.identifier)) { - const std::string& value = dictionary.value( - SourceTypeInfo.identifier - ); - - if (value == "Node") { - _source.type = Type::Node; - } - else if (value == "Node Surface") { - _source.type = Type::NodeSurface; - } - else if (value == "Focus") { - _source.type = Type::Focus; - } - else { - _source.type = Type::Camera; + if (p.sourceType.has_value()) { + switch (*p.sourceType) { + case Parameters::TypeInfo::Node: + _source.type = Type::Node; + break; + case Parameters::TypeInfo::NodeSurface: + _source.type = Type::NodeSurface; + break; + case Parameters::TypeInfo::Focus: + _source.type = Type::Focus; + break; + case Parameters::TypeInfo::Camera: + _source.type = Type::Camera; + break; } } else { @@ -235,10 +205,8 @@ DashboardItemDistance::DashboardItemDistance(const ghoul::Dictionary& dictionary _source.nodeName.onChange([this]() { _source.node = nullptr; }); if (_source.type == Type::Node || _source.type == Type::NodeSurface) { - if (dictionary.hasKey(SourceNodeNameInfo.identifier)) { - _source.nodeName = dictionary.value( - SourceNodeNameInfo.identifier - ); + if (p.sourceNodeName.has_value()) { + _source.nodeName = *p.sourceNodeName; } else { LERRORC( @@ -262,21 +230,20 @@ DashboardItemDistance::DashboardItemDistance(const ghoul::Dictionary& dictionary ) ); }); - if (dictionary.hasKey(DestinationTypeInfo.identifier)) { - const std::string& value = dictionary.value( - DestinationTypeInfo.identifier - ); - if (value == "Node") { - _destination.type = Type::Node; - } - else if (value == "Node Surface") { - _destination.type = Type::NodeSurface; - } - else if (value == "Focus") { - _destination.type = Type::Focus; - } - else { - _destination.type = Type::Camera; + if (p.destinationType.has_value()) { + switch (*p.destinationType) { + case Parameters::TypeInfo::Node: + _destination.type = Type::Node; + break; + case Parameters::TypeInfo::NodeSurface: + _destination.type = Type::NodeSurface; + break; + case Parameters::TypeInfo::Focus: + _destination.type = Type::Focus; + break; + case Parameters::TypeInfo::Camera: + _destination.type = Type::Camera; + break; } } else { @@ -285,10 +252,8 @@ DashboardItemDistance::DashboardItemDistance(const ghoul::Dictionary& dictionary addProperty(_destination.type); _destination.nodeName.onChange([this]() { _destination.node = nullptr; }); if (_destination.type == Type::Node || _destination.type == Type::NodeSurface) { - if (dictionary.hasKey(DestinationNodeNameInfo.identifier)) { - _destination.nodeName = dictionary.value( - DestinationNodeNameInfo.identifier - ); + if (p.destinationNodeName.has_value()) { + _destination.nodeName = *p.destinationNodeName; } else { LERRORC( @@ -299,9 +264,7 @@ DashboardItemDistance::DashboardItemDistance(const ghoul::Dictionary& dictionary } addProperty(_destination.nodeName); - if (dictionary.hasKey(SimplificationInfo.identifier)) { - _doSimplification = dictionary.value(SimplificationInfo.identifier); - } + _doSimplification = p.simplification.value_or(_doSimplification); _doSimplification.onChange([this]() { _requestedUnit.setVisibility( _doSimplification ? @@ -315,19 +278,14 @@ DashboardItemDistance::DashboardItemDistance(const ghoul::Dictionary& dictionary _requestedUnit.addOption(static_cast(u), nameForDistanceUnit(u)); } _requestedUnit = static_cast(DistanceUnit::Meter); - if (dictionary.hasKey(RequestedUnitInfo.identifier)) { - const std::string& value = dictionary.value( - RequestedUnitInfo.identifier - ); - DistanceUnit unit = distanceUnitFromString(value.c_str()); + if (p.requestedUnit.has_value()) { + DistanceUnit unit = distanceUnitFromString(p.requestedUnit->c_str()); _requestedUnit = static_cast(unit); } _requestedUnit.setVisibility(properties::Property::Visibility::Hidden); addProperty(_requestedUnit); - if (dictionary.hasKey(FormatStringInfo.identifier)) { - _formatString = dictionary.value(FormatStringInfo.identifier); - } + _formatString = p.formatString.value_or(_formatString); addProperty(_formatString); _buffer.resize(256); diff --git a/modules/base/dashboard/dashboarditemframerate.cpp b/modules/base/dashboard/dashboarditemframerate.cpp index eab94b2e45..9405cac2c6 100644 --- a/modules/base/dashboard/dashboarditemframerate.cpp +++ b/modules/base/dashboard/dashboarditemframerate.cpp @@ -32,6 +32,7 @@ #include #include #include +#include namespace { constexpr openspace::properties::Property::PropertyInfo FrametimeInfo = { @@ -47,14 +48,6 @@ namespace { "does not use any caching, this trigger does not do anything." }; - constexpr const char* ValueDtAvg = "Average Deltatime"; - constexpr const char* ValueDtExtremes = "Deltatime extremes"; - constexpr const char* ValueDtStandardDeviation = "Deltatime standard deviation"; - constexpr const char* ValueDtCov = "Deltatime coefficient of variation"; - constexpr const char* ValueFps = "Frames per second"; - constexpr const char* ValueFpsAvg = "Average frames per second"; - constexpr const char* ValueNone = "None"; - [[ nodiscard ]] char* formatDt(std::vector& buffer) { return fmt::format_to( buffer.data(), @@ -133,32 +126,30 @@ namespace { throw ghoul::MissingCaseException(); } } + + struct [[codegen::Dictionary(DashboardItemFramerate)]] Parameters { + enum class Type { + DtAvg [[codegen::key("Average Deltatime")]], + DtExtremes [[codegen::key("Deltatime extremes")]], + DtStandardDeviation [[codegen::key("Deltatime standard deviation")]], + DtCoefficientOfVariation [[codegen::key("Deltatime coefficient of variation")]], + FPS [[codegen::key("Frames per second")]], + FPSAvg [[codegen::key("Average frames per second")]] + }; + + // [[codegen::verbatim(FrametimeInfo.description)]] + std::optional frametimeType; + }; +#include "dashboarditemframerate_codegen.cpp" + } // namespace namespace openspace { documentation::Documentation DashboardItemFramerate::Documentation() { - using namespace documentation; - - return { - "DashboardItem Framerate", - "base_dashboarditem_framerate", - { - { - "Type", - new StringEqualVerifier("DashboardItemFramerate"), - Optional::No - }, - { - FrametimeInfo.identifier, - new StringInListVerifier({ ValueDtAvg, ValueDtExtremes, - ValueDtStandardDeviation, ValueDtCov, ValueFps, ValueFpsAvg, ValueNone - }), - Optional::Yes, - FrametimeInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_dashboarditem_framerate"; + return doc; } DashboardItemFramerate::DashboardItemFramerate(const ghoul::Dictionary& dictionary) @@ -166,52 +157,44 @@ DashboardItemFramerate::DashboardItemFramerate(const ghoul::Dictionary& dictiona , _frametimeType(FrametimeInfo, properties::OptionProperty::DisplayType::Dropdown) , _clearCache(ClearCacheInfo) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "DashboardItemFramerate" - ); + const Parameters p = codegen::bake(dictionary); _frametimeType.addOptions({ - { static_cast(FrametimeType::DtTimeAvg), ValueDtAvg }, - { static_cast(FrametimeType::DtTimeExtremes), ValueDtExtremes }, + { static_cast(FrametimeType::DtTimeAvg), "Average Deltatime" }, + { static_cast(FrametimeType::DtTimeExtremes), "Deltatime extremes" }, { static_cast(FrametimeType::DtStandardDeviation), - ValueDtStandardDeviation + "Deltatime standard deviation" }, { static_cast(FrametimeType::DtCoefficientOfVariation), - ValueDtCov + "Deltatime coefficient of variation" }, - { static_cast(FrametimeType::FPS), ValueFps }, - { static_cast(FrametimeType::FPSAvg), ValueFpsAvg }, - { static_cast(FrametimeType::None), ValueNone } + { static_cast(FrametimeType::FPS), "Frames per second" }, + { static_cast(FrametimeType::FPSAvg), "Average frames per second" }, + { static_cast(FrametimeType::None), "None" } }); - if (dictionary.hasKey(FrametimeInfo.identifier)) { - const std::string& v = dictionary.value(FrametimeInfo.identifier); - if (v == ValueDtAvg) { - _frametimeType = static_cast(FrametimeType::DtTimeAvg); - } - else if (v == ValueDtExtremes) { - _frametimeType = static_cast(FrametimeType::DtTimeExtremes); - } - else if (v == ValueDtStandardDeviation) { - _frametimeType = - static_cast(FrametimeType::DtStandardDeviation); - } - else if (v == ValueDtCov) { - _frametimeType = - static_cast(FrametimeType::DtCoefficientOfVariation); - } - else if (v == ValueFps) { - _frametimeType = static_cast(FrametimeType::FPS); - } - else if (v == ValueFpsAvg) { - _frametimeType = static_cast(FrametimeType::FPSAvg); - } - else { - _frametimeType = static_cast(FrametimeType::None); + if (p.frametimeType.has_value()) { + switch (*p.frametimeType) { + case Parameters::Type::DtAvg: + _frametimeType = static_cast(FrametimeType::DtTimeAvg); + break; + case Parameters::Type::DtExtremes: + _frametimeType = static_cast(FrametimeType::DtTimeExtremes); + break; + case Parameters::Type::DtStandardDeviation: + _frametimeType = static_cast(FrametimeType::DtStandardDeviation); + break; + case Parameters::Type::DtCoefficientOfVariation: + _frametimeType = static_cast(FrametimeType::DtCoefficientOfVariation); + break; + case Parameters::Type::FPS: + _frametimeType = static_cast(FrametimeType::FPS); + break; + case Parameters::Type::FPSAvg: + _frametimeType = static_cast(FrametimeType::FPSAvg); + break; } } else { diff --git a/modules/base/dashboard/dashboarditemmission.cpp b/modules/base/dashboard/dashboarditemmission.cpp index 19493f2046..97b2131d85 100644 --- a/modules/base/dashboard/dashboarditemmission.cpp +++ b/modules/base/dashboard/dashboarditemmission.cpp @@ -51,7 +51,6 @@ namespace { progress.append("|"); return progress; } - } // namespace namespace openspace { diff --git a/modules/base/dashboard/dashboarditempropertyvalue.cpp b/modules/base/dashboard/dashboarditempropertyvalue.cpp index f39bfaafbe..663ff6d68f 100644 --- a/modules/base/dashboard/dashboarditempropertyvalue.cpp +++ b/modules/base/dashboard/dashboarditempropertyvalue.cpp @@ -48,35 +48,23 @@ namespace { "the value itself will be displayed), or it must contain extact one instance of " "{}, which will be replaced with the value of the property during rendering." }; + + struct [[codegen::Dictionary(DashboardItemPropertyValue)]] Parameters { + // [[codegen::verbatim(PropertyUriInfo.description)]] + std::optional uri [[codegen::key("URI")]]; + + // [[codegen::verbatim(DisplayStringInfo.description)]] + std::optional displayString; + }; +#include "dashboarditempropertyvalue_codegen.cpp" } // namespace namespace openspace { documentation::Documentation DashboardItemPropertyValue::Documentation() { - using namespace documentation; - return { - "DashboardItem PropertyValue", - "base_dashboarditem_propertyvalue", - { - { - "Type", - new StringEqualVerifier("DashboardItemPropertyValue"), - Optional::No - }, - { - PropertyUriInfo.identifier, - new StringVerifier, - Optional::Yes, - PropertyUriInfo.description - }, - { - DisplayStringInfo.identifier, - new StringVerifier, - Optional::Yes, - DisplayStringInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_dashboarditem_propertyvalue"; + return doc; } DashboardItemPropertyValue::DashboardItemPropertyValue( @@ -85,21 +73,13 @@ DashboardItemPropertyValue::DashboardItemPropertyValue( , _propertyUri(PropertyUriInfo) , _displayString(DisplayStringInfo) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "DashboardItemPropertyValue" - ); + const Parameters p = codegen::bake(dictionary); - if (dictionary.hasKey(PropertyUriInfo.identifier)) { - _propertyUri = dictionary.value(PropertyUriInfo.identifier); - } + _propertyUri = p.uri.value_or(_propertyUri); _propertyUri.onChange([this]() { _propertyIsDirty = true; }); addProperty(_propertyUri); - if (dictionary.hasKey(DisplayStringInfo.identifier)) { - _displayString = dictionary.value(DisplayStringInfo.identifier); - } + _displayString = p.displayString.value_or(_displayString); addProperty(_displayString); } diff --git a/modules/base/dashboard/dashboarditemsimulationincrement.cpp b/modules/base/dashboard/dashboarditemsimulationincrement.cpp index 8df0a80ac8..6648503c41 100644 --- a/modules/base/dashboard/dashboarditemsimulationincrement.cpp +++ b/modules/base/dashboard/dashboarditemsimulationincrement.cpp @@ -81,47 +81,29 @@ namespace { ); return res; } + + struct [[codegen::Dictionary(DashboardItemSimulationIncrement)]] Parameters { + // [[codegen::verbatim(SimplificationInfo.description)]] + std::optional simplification; + + // [[codegen::verbatim(RequestedUnitInfo.description)]] + std::optional requestedUnit [[codegen::inlist(unitList())]]; + + // [[codegen::verbatim(TransitionFormatInfo.description)]] + std::optional transitionFormat; + + // [[codegen::verbatim(RegularFormatInfo.description)]] + std::optional regularFormat; + }; +#include "dashboarditemsimulationincrement_codegen.cpp" } // namespace namespace openspace { documentation::Documentation DashboardItemSimulationIncrement::Documentation() { - using namespace documentation; - return { - "DashboardItem Simulation Increment", - "base_dashboarditem_simulationincrement", - { - { - "Type", - new StringEqualVerifier("DashboardItemSimulationIncrement"), - Optional::No - }, - { - SimplificationInfo.identifier, - new BoolVerifier, - Optional::Yes, - SimplificationInfo.description - }, - { - RequestedUnitInfo.identifier, - new StringInListVerifier(unitList()), - Optional::Yes, - RequestedUnitInfo.description - }, - { - TransitionFormatInfo.identifier, - new StringVerifier, - Optional::Yes, - TransitionFormatInfo.description - }, - { - RegularFormatInfo.identifier, - new StringVerifier, - Optional::Yes, - RegularFormatInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_dashboarditem_simulationincrement"; + return doc; } DashboardItemSimulationIncrement::DashboardItemSimulationIncrement( @@ -135,15 +117,9 @@ DashboardItemSimulationIncrement::DashboardItemSimulationIncrement( ) , _regularFormat(RegularFormatInfo, "Simulation increment: {:.1f} {:s} / second{:s}") { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "DashboardItemSimulationIncrement" - ); + const Parameters p = codegen::bake(dictionary); - if (dictionary.hasKey(SimplificationInfo.identifier)) { - _doSimplification = dictionary.value(SimplificationInfo.identifier); - } + _doSimplification = p.simplification.value_or(_doSimplification); _doSimplification.onChange([this]() { _requestedUnit.setVisibility( _doSimplification ? @@ -157,24 +133,17 @@ DashboardItemSimulationIncrement::DashboardItemSimulationIncrement( _requestedUnit.addOption(static_cast(u), nameForTimeUnit(u)); } _requestedUnit = static_cast(TimeUnit::Second); - if (dictionary.hasKey(RequestedUnitInfo.identifier)) { - std::string value = dictionary.value(RequestedUnitInfo.identifier); - TimeUnit unit = timeUnitFromString(value.c_str()); + if (p.requestedUnit.has_value()) { + TimeUnit unit = timeUnitFromString(p.requestedUnit->c_str()); _requestedUnit = static_cast(unit); } _requestedUnit.setVisibility(properties::Property::Visibility::Hidden); addProperty(_requestedUnit); - if (dictionary.hasKey(TransitionFormatInfo.identifier)) { - _transitionFormat = dictionary.value( - TransitionFormatInfo.identifier - ); - } + _transitionFormat = p.transitionFormat.value_or(_transitionFormat); addProperty(_transitionFormat); - if (dictionary.hasKey(RegularFormatInfo.identifier)) { - _regularFormat = dictionary.value(RegularFormatInfo.identifier); - } + _regularFormat = p.regularFormat.value_or(_regularFormat); addProperty(_regularFormat); } diff --git a/modules/base/dashboard/dashboarditemspacing.cpp b/modules/base/dashboard/dashboarditemspacing.cpp index b1719cf894..5b615f769b 100644 --- a/modules/base/dashboard/dashboarditemspacing.cpp +++ b/modules/base/dashboard/dashboarditemspacing.cpp @@ -26,6 +26,7 @@ #include #include +#include namespace { constexpr openspace::properties::Property::PropertyInfo SpacingInfo = { @@ -34,44 +35,29 @@ namespace { "This value determines the spacing (in pixels) that this item represents. The " "default value is 15." }; + + struct [[codegen::Dictionary(DashboardItemSpacing)]] Parameters { + // [[codegen::verbatim(SpacingInfo.description)]] + std::optional spacing; + }; +#include "dashboarditemspacing_codegen.cpp" } // namespace namespace openspace { documentation::Documentation DashboardItemSpacing::Documentation() { - using namespace documentation; - return { - "DashboardItem Spacing", - "base_dashboarditem_spacing", - { - { - "Type", - new StringEqualVerifier("DashboardItemSpacing"), - Optional::No - }, - { - SpacingInfo.identifier, - new DoubleVerifier, - Optional::Yes, - SpacingInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_dashboarditem_spacing"; + return doc; } DashboardItemSpacing::DashboardItemSpacing(const ghoul::Dictionary& dictionary) : DashboardItem(dictionary) , _spacing(SpacingInfo, 15.f, 0.f, 2048.f) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "DashboardItemSpacing" - ); + const Parameters p = codegen::bake(dictionary); - if (dictionary.hasKey(SpacingInfo.identifier)) { - _spacing = static_cast(dictionary.value(SpacingInfo.identifier)); - } + _spacing = p.spacing.value_or(_spacing); addProperty(_spacing); } diff --git a/modules/base/dashboard/dashboarditemtext.cpp b/modules/base/dashboard/dashboarditemtext.cpp index 9a461db605..690da61c6a 100644 --- a/modules/base/dashboard/dashboarditemtext.cpp +++ b/modules/base/dashboard/dashboarditemtext.cpp @@ -31,6 +31,7 @@ #include #include #include +#include namespace { constexpr openspace::properties::Property::PropertyInfo TextInfo = { @@ -38,44 +39,28 @@ namespace { "Text", "The text to be displayed" }; + + struct [[codegen::Dictionary(DashboardItemText)]] Parameters { + // [[codegen::verbatim(TextInfo.description)]] + std::optional text; + }; +#include "dashboarditemtext_codegen.cpp" } // namespace namespace openspace { documentation::Documentation DashboardItemText::Documentation() { - using namespace documentation; - return { - "DashboardItem Text", - "base_dashboarditem_text", - { - { - "Type", - new StringEqualVerifier("DashboardItemText"), - Optional::No - }, - { - TextInfo.identifier, - new StringVerifier, - Optional::Yes, - TextInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_dashboarditem_text"; + return doc; } DashboardItemText::DashboardItemText(const ghoul::Dictionary& dictionary) : DashboardTextItem(dictionary) , _text(TextInfo, "") { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "DashboardItemText" - ); - - if (dictionary.hasKey(TextInfo.identifier)) { - _text = dictionary.value(TextInfo.identifier); - }; + const Parameters p = codegen::bake(dictionary); + _text = p.text.value_or(_text); addProperty(_text); } diff --git a/modules/base/dashboard/dashboarditemvelocity.cpp b/modules/base/dashboard/dashboarditemvelocity.cpp index 4de13a891c..d71e4c585d 100644 --- a/modules/base/dashboard/dashboarditemvelocity.cpp +++ b/modules/base/dashboard/dashboarditemvelocity.cpp @@ -68,35 +68,24 @@ namespace { ); return res; } + + struct [[codegen::Dictionary(DashboardItemVelocity)]] Parameters { + // [[codegen::verbatim(SimplificationInfo.description)]] + std::optional simplification; + + // [[codegen::verbatim(RequestedUnitInfo.description)]] + std::optional requestedUnit [[codegen::inlist(unitList())]]; + }; +#include "dashboarditemvelocity_codegen.cpp" + } // namespace namespace openspace { documentation::Documentation DashboardItemVelocity::Documentation() { - using namespace documentation; - return { - "DashboardItem Velocity", - "base_dashboarditem_velocity", - { - { - "Type", - new StringEqualVerifier("DashboardItemVelocity"), - Optional::No - }, - { - SimplificationInfo.identifier, - new BoolVerifier, - Optional::Yes, - SimplificationInfo.description - }, - { - RequestedUnitInfo.identifier, - new StringInListVerifier(unitList()), - Optional::Yes, - RequestedUnitInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_dashboarditem_velocity"; + return doc; } DashboardItemVelocity::DashboardItemVelocity(const ghoul::Dictionary& dictionary) @@ -104,15 +93,8 @@ DashboardItemVelocity::DashboardItemVelocity(const ghoul::Dictionary& dictionary , _doSimplification(SimplificationInfo, true) , _requestedUnit(RequestedUnitInfo, properties::OptionProperty::DisplayType::Dropdown) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "DashboardItemVelocity" - ); - - if (dictionary.hasKey(SimplificationInfo.identifier)) { - _doSimplification = dictionary.value(SimplificationInfo.identifier); - } + const Parameters p = codegen::bake(dictionary); + _doSimplification = p.simplification.value_or(_doSimplification); _doSimplification.onChange([this]() { _requestedUnit.setVisibility( _doSimplification ? @@ -126,11 +108,8 @@ DashboardItemVelocity::DashboardItemVelocity(const ghoul::Dictionary& dictionary _requestedUnit.addOption(static_cast(u), nameForDistanceUnit(u)); } _requestedUnit = static_cast(DistanceUnit::Meter); - if (dictionary.hasKey(RequestedUnitInfo.identifier)) { - const std::string& value = dictionary.value( - RequestedUnitInfo.identifier - ); - DistanceUnit unit = distanceUnitFromString(value.c_str()); + if (p.requestedUnit.has_value()) { + DistanceUnit unit = distanceUnitFromString(p.requestedUnit->c_str()); _requestedUnit = static_cast(unit); } _requestedUnit.setVisibility(properties::Property::Visibility::Hidden); @@ -162,7 +141,7 @@ void DashboardItemVelocity::render(glm::vec2& penPosition) { *_font, penPosition, fmt::format( - "Camera velocity: {} {}/s", dist.first, dist.second + "Camera velocity: {:.4f} {}/s", dist.first, dist.second ) ); penPosition.y -= _font->height(); diff --git a/modules/base/lightsource/cameralightsource.cpp b/modules/base/lightsource/cameralightsource.cpp index 03028c9717..d878e5cf45 100644 --- a/modules/base/lightsource/cameralightsource.cpp +++ b/modules/base/lightsource/cameralightsource.cpp @@ -27,6 +27,7 @@ #include #include #include +#include namespace { constexpr openspace::properties::Property::PropertyInfo IntensityInfo = { @@ -34,30 +35,20 @@ namespace { "Intensity", "The intensity of this light source" }; + + struct [[codegen::Dictionary(CameraLightSource)]] Parameters { + // [[codegen::verbatim(IntensityInfo.description)]] + std::optional intensity; + }; +#include "cameralightsource_codegen.cpp" } // namespace namespace openspace { documentation::Documentation CameraLightSource::Documentation() { - using namespace openspace::documentation; - return { - "Camera Light Source", - "base_camera_light_source", - { - { - "Type", - new StringEqualVerifier("CameraLightSource"), - Optional::No, - "The type of this light source" - }, - { - IntensityInfo.identifier, - new DoubleVerifier, - Optional::Yes, - IntensityInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_camera_light_source"; + return doc; } CameraLightSource::CameraLightSource() @@ -70,18 +61,9 @@ CameraLightSource::CameraLightSource(const ghoul::Dictionary& dictionary) : LightSource(dictionary) , _intensity(IntensityInfo, 1.f, 0.f, 1.f) { + const Parameters p = codegen::bake(dictionary); + _intensity = p.intensity.value_or(_intensity); addProperty(_intensity); - - documentation::testSpecificationAndThrow(Documentation(), - dictionary, - "CameraLightSource"); - - - if (dictionary.hasValue(IntensityInfo.identifier)) { - _intensity = static_cast( - dictionary.value(IntensityInfo.identifier) - ); - } } float CameraLightSource::intensity() const { diff --git a/modules/base/lightsource/scenegraphlightsource.cpp b/modules/base/lightsource/scenegraphlightsource.cpp index 7b8a2742a6..671f7efd75 100644 --- a/modules/base/lightsource/scenegraphlightsource.cpp +++ b/modules/base/lightsource/scenegraphlightsource.cpp @@ -31,6 +31,7 @@ #include #include #include +#include namespace { constexpr openspace::properties::Property::PropertyInfo IntensityInfo = { @@ -44,36 +45,23 @@ namespace { "Node", "The identifier of the scene graph node to follow" }; + + struct [[codegen::Dictionary(SceneGraphLightSource)]] Parameters { + // [[codegen::verbatim(IntensityInfo.description)]] + std::optional intensity; + + // [[codegen::verbatim(NodeInfo.description)]] + std::string node; + }; +#include "scenegraphlightsource_codegen.cpp" } // namespace namespace openspace { documentation::Documentation SceneGraphLightSource::Documentation() { - using namespace openspace::documentation; - return { - "Scene Graph Light Source", - "base_scene_graph_light_source", - { - { - "Type", - new StringEqualVerifier("SceneGraphLightSource"), - Optional::No, - "The type of this light source" - }, - { - IntensityInfo.identifier, - new DoubleVerifier, - Optional::Yes, - IntensityInfo.description - }, - { - NodeInfo.identifier, - new StringVerifier, - Optional::No, - NodeInfo.description - }, - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_scene_graph_light_source"; + return doc; } SceneGraphLightSource::SceneGraphLightSource() @@ -89,30 +77,17 @@ SceneGraphLightSource::SceneGraphLightSource(const ghoul::Dictionary& dictionary , _intensity(IntensityInfo, 1.f, 0.f, 1.f) , _sceneGraphNodeReference(NodeInfo, "") { + const Parameters p = codegen::bake(dictionary); + + _intensity = p.intensity.value_or(_intensity); addProperty(_intensity); - addProperty(_sceneGraphNodeReference); - - documentation::testSpecificationAndThrow(Documentation(), - dictionary, - "SceneGraphLightSource"); - - - if (dictionary.hasValue(IntensityInfo.identifier)) { - _intensity = static_cast( - dictionary.value(IntensityInfo.identifier) - ); - } - - if (dictionary.hasValue(NodeInfo.identifier)) { - _sceneGraphNodeReference = - dictionary.value(NodeInfo.identifier); - } + _sceneGraphNodeReference = p.node; _sceneGraphNodeReference.onChange([this]() { _sceneGraphNode = global::renderEngine->scene()->sceneGraphNode(_sceneGraphNodeReference); }); - + addProperty(_sceneGraphNodeReference); } bool SceneGraphLightSource::initialize() { diff --git a/modules/base/rendering/grids/renderableboxgrid.cpp b/modules/base/rendering/grids/renderableboxgrid.cpp index a9d5c855c4..518f87b248 100644 --- a/modules/base/rendering/grids/renderableboxgrid.cpp +++ b/modules/base/rendering/grids/renderableboxgrid.cpp @@ -55,36 +55,26 @@ namespace { "Grid Size", "This value species the size of each dimensions of the box" }; + + struct [[codegen::Dictionary(RenderableBoxGrid)]] Parameters { + // [[codegen::verbatim(ColorInfo.description)]] + std::optional color; + + // [[codegen::verbatim(LineWidthInfo.description)]] + std::optional lineWidth; + + // [[codegen::verbatim(SizeInfo.description)]] + std::optional size; + }; +#include "renderableboxgrid_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableBoxGrid::Documentation() { - using namespace documentation; - return { - "RenderableBoxGrid", - "base_renderable_boxgrid", - { - { - ColorInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - ColorInfo.description - }, - { - LineWidthInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LineWidthInfo.description - }, - { - SizeInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - SizeInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_renderable_boxgrid"; + return doc; } RenderableBoxGrid::RenderableBoxGrid(const ghoul::Dictionary& dictionary) @@ -93,31 +83,19 @@ RenderableBoxGrid::RenderableBoxGrid(const ghoul::Dictionary& dictionary) , _lineWidth(LineWidthInfo, 0.5f, 0.f, 20.f) , _size(SizeInfo, glm::vec3(1.f), glm::vec3(1.f), glm::vec3(100.f)) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableBoxGrid" - ); + const Parameters p = codegen::bake(dictionary); addProperty(_opacity); registerUpdateRenderBinFromOpacity(); - if (dictionary.hasKey(ColorInfo.identifier)) { - _color = dictionary.value(ColorInfo.identifier); - } + _color = p.color.value_or(_color); _color.setViewOption(properties::Property::ViewOptions::Color); addProperty(_color); - if (dictionary.hasKey(LineWidthInfo.identifier)) { - _lineWidth = static_cast( - dictionary.value(LineWidthInfo.identifier) - ); - } + _lineWidth = p.lineWidth.value_or(_lineWidth); addProperty(_lineWidth); - if (dictionary.hasKey(SizeInfo.identifier)) { - _size = dictionary.value(SizeInfo.identifier); - } + _size = p.size.value_or(_size); _size.onChange([&]() { _gridIsDirty = true; }); addProperty(_size); } diff --git a/modules/base/rendering/grids/renderablegrid.cpp b/modules/base/rendering/grids/renderablegrid.cpp index 9f8a8114db..861b54598b 100644 --- a/modules/base/rendering/grids/renderablegrid.cpp +++ b/modules/base/rendering/grids/renderablegrid.cpp @@ -62,43 +62,29 @@ namespace { "Grid Size", "This value species the size of each dimensions of the grid" }; + + struct [[codegen::Dictionary(RenderableGrid)]] Parameters { + // [[codegen::verbatim(ColorInfo.description)]] + std::optional color; + + // [[codegen::verbatim(SegmentsInfo.description)]] + std::optional segments; + + // [[codegen::verbatim(LineWidthInfo.description)]] + std::optional lineWidth; + + // [[codegen::verbatim(SizeInfo.description)]] + std::optional size; + }; +#include "renderablegrid_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableGrid::Documentation() { - using namespace documentation; - return { - "RenderableGrid", - "base_renderable_grid", - { - { - ColorInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - ColorInfo.description - }, - { - SegmentsInfo.identifier, - // @TODO (emmbr 2020-07-07): should be Int, but specification test fails.. - new DoubleVector2Verifier, - Optional::Yes, - SegmentsInfo.description - }, - { - LineWidthInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LineWidthInfo.description - }, - { - SizeInfo.identifier, - new DoubleVector2Verifier, - Optional::Yes, - SizeInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_renderable_grid"; + return doc; } RenderableGrid::RenderableGrid(const ghoul::Dictionary& dictionary) @@ -108,39 +94,23 @@ RenderableGrid::RenderableGrid(const ghoul::Dictionary& dictionary) , _lineWidth(LineWidthInfo, 0.5f, 0.f, 20.f) , _size(SizeInfo, glm::vec2(1e20f), glm::vec2(1.f), glm::vec2(1e35f)) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableGrid" - ); + const Parameters p = codegen::bake(dictionary); addProperty(_opacity); registerUpdateRenderBinFromOpacity(); - if (dictionary.hasKey(ColorInfo.identifier)) { - _color = dictionary.value(ColorInfo.identifier); - } + _color = p.color.value_or(_color); _color.setViewOption(properties::Property::ViewOptions::Color); addProperty(_color); - if (dictionary.hasKey(SegmentsInfo.identifier)) { - _segments = static_cast( - dictionary.value(SegmentsInfo.identifier) - ); - } + _segments = p.segments.value_or(_segments); _segments.onChange([&]() { _gridIsDirty = true; }); addProperty(_segments); - if (dictionary.hasKey(LineWidthInfo.identifier)) { - _lineWidth = static_cast( - dictionary.value(LineWidthInfo.identifier) - ); - } + _lineWidth = p.lineWidth.value_or(_lineWidth); addProperty(_lineWidth); - if (dictionary.hasKey(SizeInfo.identifier)) { - _size = dictionary.value(SizeInfo.identifier); - } + _size = p.size.value_or(_size); _size.onChange([&]() { _gridIsDirty = true; }); addProperty(_size); } diff --git a/modules/base/rendering/grids/renderablegrid.h b/modules/base/rendering/grids/renderablegrid.h index 6c6dbade4c..c630265517 100644 --- a/modules/base/rendering/grids/renderablegrid.h +++ b/modules/base/rendering/grids/renderablegrid.h @@ -28,8 +28,8 @@ #include #include +#include #include -#include #include #include #include @@ -61,7 +61,9 @@ protected: ghoul::opengl::ProgramObject* _gridProgram = nullptr; properties::Vec3Property _color; - properties::UVec2Property _segments; + // @TODO (abock, 2021-01-28) This was a UVec2Property before, but it wasn't supported + // be the codegen. As soon as it does, this should be changed back + properties::IVec2Property _segments; properties::FloatProperty _lineWidth; properties::Vec2Property _size; diff --git a/modules/base/rendering/grids/renderableradialgrid.cpp b/modules/base/rendering/grids/renderableradialgrid.cpp index 979622e8a2..1c90c090a1 100644 --- a/modules/base/rendering/grids/renderableradialgrid.cpp +++ b/modules/base/rendering/grids/renderableradialgrid.cpp @@ -34,6 +34,7 @@ #include #include #include +#include namespace { constexpr const char* ProgramName = "GridProgram"; @@ -76,54 +77,35 @@ namespace { "The inner radius of the circular grid, that is the radius of the inmost ring. " "Must be smaller than the outer radius." }; + + struct [[codegen::Dictionary(RenderableRadialGrid)]] Parameters { + // [[codegen::verbatim(ColorInfo.description)]] + std::optional color; + + // [[codegen::verbatim(GridSegmentsInfo.description)]] + std::optional gridSegments; + + // [[codegen::verbatim(CircleSegmentsInfo.description)]] + std::optional circleSegments; + + // [[codegen::verbatim(LineWidthInfo.description)]] + std::optional lineWidth; + + // [[codegen::verbatim(OuterRadiusInfo.description)]] + std::optional outerRadius; + + // [[codegen::verbatim(InnerRadiusInfo.description)]] + std::optional innerRadius; + }; +#include "renderableradialgrid_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableRadialGrid::Documentation() { - using namespace documentation; - return { - "RenderableRadialGrid", - "base_renderable_radialgrid", - { - { - ColorInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - ColorInfo.description - }, - { - GridSegmentsInfo.identifier, - new DoubleVector2Verifier, - Optional::Yes, - GridSegmentsInfo.description - }, - { - CircleSegmentsInfo.identifier, - new IntVerifier, - Optional::Yes, - CircleSegmentsInfo.description - }, - { - LineWidthInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LineWidthInfo.description - }, - { - OuterRadiusInfo.identifier, - new DoubleVerifier, - Optional::Yes, - OuterRadiusInfo.description - }, - { - InnerRadiusInfo.identifier, - new DoubleVerifier, - Optional::Yes, - InnerRadiusInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_renderable_radialgrid"; + return doc; } RenderableRadialGrid::RenderableRadialGrid(const ghoul::Dictionary& dictionary) @@ -135,34 +117,20 @@ RenderableRadialGrid::RenderableRadialGrid(const ghoul::Dictionary& dictionary) , _maxRadius(OuterRadiusInfo, 1.f, 0.f, 20.f) , _minRadius(InnerRadiusInfo, 0.f, 0.f, 20.f) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableRadialGrid" - ); + const Parameters p = codegen::bake(dictionary); addProperty(_opacity); registerUpdateRenderBinFromOpacity(); - if (dictionary.hasKey(ColorInfo.identifier)) { - _color = dictionary.value(ColorInfo.identifier); - } + _color = p.color.value_or(_color); _color.setViewOption(properties::Property::ViewOptions::Color); addProperty(_color); - if (dictionary.hasKey(GridSegmentsInfo.identifier)) { - _gridSegments = static_cast( - dictionary.value(GridSegmentsInfo.identifier) - ); - } + _gridSegments = p.gridSegments.value_or(_gridSegments); _gridSegments.onChange([&]() { _gridIsDirty = true; }); addProperty(_gridSegments); - if (dictionary.hasKey(CircleSegmentsInfo.identifier)) { - _circleSegments = static_cast( - dictionary.value(CircleSegmentsInfo.identifier) - ); - } + _circleSegments = p.circleSegments.value_or(_circleSegments); _circleSegments.onChange([&]() { if (_circleSegments.value() % 2 == 1) { _circleSegments = _circleSegments - 1; @@ -171,24 +139,11 @@ RenderableRadialGrid::RenderableRadialGrid(const ghoul::Dictionary& dictionary) }); addProperty(_circleSegments); - if (dictionary.hasKey(LineWidthInfo.identifier)) { - _lineWidth = static_cast( - dictionary.value(LineWidthInfo.identifier) - ); - } + _lineWidth = p.lineWidth.value_or(_lineWidth); addProperty(_lineWidth); - if (dictionary.hasKey(OuterRadiusInfo.identifier)) { - _maxRadius = static_cast( - dictionary.value(OuterRadiusInfo.identifier) - ); - } - - if (dictionary.hasKey(InnerRadiusInfo.identifier)) { - _minRadius = static_cast( - dictionary.value(InnerRadiusInfo.identifier) - ); - } + _minRadius = p.innerRadius.value_or(_minRadius); + _maxRadius = p.outerRadius.value_or(_maxRadius); _maxRadius.setMinValue(_minRadius); _minRadius.setMaxValue(_maxRadius); diff --git a/modules/base/rendering/grids/renderablesphericalgrid.cpp b/modules/base/rendering/grids/renderablesphericalgrid.cpp index da56a19f17..1580276c27 100644 --- a/modules/base/rendering/grids/renderablesphericalgrid.cpp +++ b/modules/base/rendering/grids/renderablesphericalgrid.cpp @@ -33,6 +33,7 @@ #include #include #include +#include namespace { constexpr const char* ProgramName = "GridProgram"; @@ -55,36 +56,26 @@ namespace { "Line Width", "This value specifies the line width of the spherical grid." }; + + struct [[codegen::Dictionary(RenderableSphericalGrid)]] Parameters { + // [[codegen::verbatim(ColorInfo.description)]] + std::optional color; + + // [[codegen::verbatim(SegmentsInfo.description)]] + std::optional segments; + + // [[codegen::verbatim(LineWidthInfo.description)]] + std::optional lineWidth; + }; +#include "renderablesphericalgrid_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableSphericalGrid::Documentation() { - using namespace documentation; - return { - "RenderableSphericalGrid", - "base_renderable_sphericalgrid", - { - { - ColorInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - ColorInfo.description - }, - { - SegmentsInfo.identifier, - new IntVerifier, - Optional::Yes, - SegmentsInfo.description - }, - { - LineWidthInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LineWidthInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_renderable_sphericalgrid"; + return doc; } RenderableSphericalGrid::RenderableSphericalGrid(const ghoul::Dictionary& dictionary) @@ -94,24 +85,16 @@ RenderableSphericalGrid::RenderableSphericalGrid(const ghoul::Dictionary& dictio , _segments(SegmentsInfo, 36, 4, 200) , _lineWidth(LineWidthInfo, 0.5f, 0.f, 20.f) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableSphericalGrid" - ); + const Parameters p = codegen::bake(dictionary); addProperty(_opacity); registerUpdateRenderBinFromOpacity(); - if (dictionary.hasKey(ColorInfo.identifier)) { - _color = dictionary.value(ColorInfo.identifier); - } + _color = p.color.value_or(_color); _color.setViewOption(properties::Property::ViewOptions::Color); addProperty(_color); - if (dictionary.hasKey(SegmentsInfo.identifier)) { - _segments = static_cast(dictionary.value(SegmentsInfo.identifier)); - } + _segments = p.segments.value_or(_segments); _segments.onChange([&]() { if (_segments.value() % 2 == 1) { _segments = _segments - 1; @@ -120,11 +103,7 @@ RenderableSphericalGrid::RenderableSphericalGrid(const ghoul::Dictionary& dictio }); addProperty(_segments); - if (dictionary.hasKey(LineWidthInfo.identifier)) { - _lineWidth = static_cast( - dictionary.value(LineWidthInfo.identifier) - ); - } + _lineWidth = p.lineWidth.value_or(_lineWidth); addProperty(_lineWidth); } diff --git a/modules/base/rendering/renderablecartesianaxes.cpp b/modules/base/rendering/renderablecartesianaxes.cpp index 1e2e2d208a..67b4f00783 100644 --- a/modules/base/rendering/renderablecartesianaxes.cpp +++ b/modules/base/rendering/renderablecartesianaxes.cpp @@ -34,6 +34,7 @@ #include #include #include +#include namespace { constexpr const char* ProgramName = "CartesianAxesProgram"; @@ -56,39 +57,29 @@ namespace { "Z Color", "This value determines the color of the z axis." }; + + struct [[codegen::Dictionary(RenderableCartesianAxes)]] Parameters { + // [[codegen::verbatim(XColorInfo.description)]] + std::optional xColor; + + // [[codegen::verbatim(YColorInfo.description)]] + std::optional yColor; + + // [[codegen::verbatim(ZColorInfo.description)]] + std::optional zColor; + + }; +#include "renderablecartesianaxes_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableCartesianAxes::Documentation() { - using namespace documentation; - return { - "CartesianAxesProgram", - "base_renderable_cartesianaxes", - { - { - XColorInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - XColorInfo.description - }, - { - YColorInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - YColorInfo.description - }, - { - ZColorInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - ZColorInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_renderable_cartesianaxes"; + return doc; } - RenderableCartesianAxes::RenderableCartesianAxes(const ghoul::Dictionary& dictionary) : Renderable(dictionary) , _program(nullptr) @@ -111,27 +102,16 @@ RenderableCartesianAxes::RenderableCartesianAxes(const ghoul::Dictionary& dictio glm::vec3(1.f) ) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableCartesianAxes" - ); - - if (dictionary.hasKey(XColorInfo.identifier)) { - _xColor = dictionary.value(XColorInfo.identifier); - } + const Parameters p = codegen::bake(dictionary); + _xColor = p.xColor.value_or(_xColor); _xColor.setViewOption(properties::Property::ViewOptions::Color); addProperty(_xColor); - if (dictionary.hasKey(XColorInfo.identifier)) { - _yColor = dictionary.value(YColorInfo.identifier); - } + _yColor = p.yColor.value_or(_yColor); _yColor.setViewOption(properties::Property::ViewOptions::Color); addProperty(_yColor); - if (dictionary.hasKey(ZColorInfo.identifier)) { - _zColor = dictionary.value(ZColorInfo.identifier); - } + _zColor = p.zColor.value_or(_zColor); _zColor.setViewOption(properties::Property::ViewOptions::Color); addProperty(_zColor); } diff --git a/modules/base/rendering/renderabledisc.cpp b/modules/base/rendering/renderabledisc.cpp new file mode 100644 index 0000000000..c3de8be2b1 --- /dev/null +++ b/modules/base/rendering/renderabledisc.cpp @@ -0,0 +1,230 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + constexpr const char _loggerCat[] = "RenderableDisc"; + + constexpr const std::array UniformNames = { + "modelViewProjectionTransform", "opacity", "width", "colorTexture" + }; + + constexpr openspace::properties::Property::PropertyInfo TextureInfo = { + "Texture", + "Texture", + "This value is the path to a texture on disk that contains a one-dimensional " + "texture to be used for the color." + }; + + constexpr openspace::properties::Property::PropertyInfo SizeInfo = { + "Size", + "Size", + "This value specifies the outer radius of the disc in meter." + }; + + constexpr openspace::properties::Property::PropertyInfo WidthInfo = { + "Width", + "Width", + "This value is used to set the width of the disc. The actual width is set " + "based on the given size and this value should be set between 0 and 1. A value " + "of 1 results in a full circle and 0.5 a disc with an inner radius of 0.5*size." + }; +} // namespace + +namespace openspace { + +documentation::Documentation RenderableDisc::Documentation() { + using namespace documentation; + return { + "Renderable Disc", + "renderable_disc", + { + { + TextureInfo.identifier, + new StringVerifier, + Optional::No, + TextureInfo.description + }, + { + SizeInfo.identifier, + new DoubleVerifier, + Optional::Yes, + SizeInfo.description + }, + { + WidthInfo.identifier, + new DoubleVerifier, + Optional::Yes, + WidthInfo.description + } + } + }; +} + +RenderableDisc::RenderableDisc(const ghoul::Dictionary& dictionary) + : Renderable(dictionary) + , _texturePath(TextureInfo) + , _size(SizeInfo, 1.f, 0.f, 1e13f) + , _width(WidthInfo, 0.5f, 0.f, 1.f) +{ + documentation::testSpecificationAndThrow( + Documentation(), + dictionary, + "RenderableDisc" + ); + + _texturePath = absPath(dictionary.value(TextureInfo.identifier)); + _texturePath.onChange([&]() { _texture->loadFromFile(_texturePath); }); + addProperty(_texturePath); + + if (dictionary.hasKey(SizeInfo.identifier)) { + _size = static_cast(dictionary.value(SizeInfo.identifier)); + } + setBoundingSphere(_size); + _size.onChange([&]() { _planeIsDirty = true; }); + addProperty(_size); + + if (dictionary.hasKey(WidthInfo.identifier)) { + _width = static_cast(dictionary.value(WidthInfo.identifier)); + } + addProperty(_width); + addProperty(_opacity); + + setRenderBin(Renderable::RenderBin::PostDeferredTransparent); +} + +bool RenderableDisc::isReady() const { + return _shader && _texture && _plane; +} + +void RenderableDisc::initialize() { + _texture = std::make_unique(); + _texture->setFilterMode(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + _texture->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge); + _texture->setShouldWatchFileForChanges(true); + + _plane = std::make_unique(planeSize()); +} + +void RenderableDisc::initializeGL() { + initializeShader(); + + _texture->loadFromFile(_texturePath); + _texture->uploadToGpu(); + + _plane->initialize(); +} + +void RenderableDisc::deinitializeGL() { + _plane->deinitialize(); + _plane = nullptr; + _texture = nullptr; + + global::renderEngine->removeRenderProgram(_shader.get()); + _shader = nullptr; +} + +void RenderableDisc::render(const RenderData& data, RendererTasks&) { + _shader->activate(); + + glm::dmat4 modelTransform = + glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * + glm::dmat4(data.modelTransform.rotation) * + glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); + + glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform; + + _shader->setUniform( + _uniformCache.modelViewProjection, + data.camera.projectionMatrix() * glm::mat4(modelViewTransform) + ); + _shader->setUniform(_uniformCache.width, _width); + + _shader->setUniform(_uniformCache.opacity, _opacity); + + ghoul::opengl::TextureUnit unit; + unit.activate(); + _texture->bind(); + _shader->setUniform(_uniformCache.texture, unit); + + glEnablei(GL_BLEND, 0); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthMask(false); + glDisable(GL_CULL_FACE); + + _plane->render(); + + _shader->deactivate(); + + // Restores GL State + global::renderEngine->openglStateCache().resetBlendState(); + global::renderEngine->openglStateCache().resetDepthState(); + global::renderEngine->openglStateCache().resetPolygonAndClippingState(); +} + +void RenderableDisc::update(const UpdateData&) { + if (_shader->isDirty()) { + _shader->rebuildFromFile(); + updateUniformLocations(); + } + + if (_planeIsDirty) { + _plane->updateSize(planeSize()); + _planeIsDirty = false; + } + + _texture->update(); +} + +void RenderableDisc::initializeShader() { + _shader = global::renderEngine->buildRenderProgram( + "DiscProgram", + absPath("${MODULE_BASE}/shaders/disc_vs.glsl"), + absPath("${MODULE_BASE}/shaders/disc_fs.glsl") + ); + updateUniformLocations(); +} + +void RenderableDisc::updateUniformLocations() { + ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames); +} + +float RenderableDisc::planeSize() const { + return _size; +} + +} // namespace openspace diff --git a/modules/base/rendering/renderabledisc.h b/modules/base/rendering/renderabledisc.h new file mode 100644 index 0000000000..ccd5d52288 --- /dev/null +++ b/modules/base/rendering/renderabledisc.h @@ -0,0 +1,81 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_BASE___RENDERABLEDISC___H__ +#define __OPENSPACE_MODULE_BASE___RENDERABLEDISC___H__ + +#include +#include +#include +#include +#include +#include +#include + +namespace ghoul::filesystem { class File; } +namespace ghoul::opengl { class ProgramObject; } + +namespace openspace { + +namespace documentation { struct Documentation; } + +class RenderableDisc : public Renderable { +public: + RenderableDisc(const ghoul::Dictionary& dictionary); + + void initialize() override; + void initializeGL() override; + void deinitializeGL() override; + + bool isReady() const override; + + void render(const RenderData& data, RendererTasks& rendererTask) override; + void update(const UpdateData& data) override; + + static documentation::Documentation Documentation(); + +protected: + virtual void initializeShader(); + virtual void updateUniformLocations(); + + virtual float planeSize() const; + + properties::StringProperty _texturePath; + properties::FloatProperty _size; + properties::FloatProperty _width; + + std::unique_ptr _shader; + + std::unique_ptr _plane; + std::unique_ptr _texture; + +private: + UniformCache(modelViewProjection, opacity, width, texture) _uniformCache; + + bool _planeIsDirty = false; +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_BASE___RENDERABLEDISC___H__ diff --git a/modules/base/rendering/renderablelabels.cpp b/modules/base/rendering/renderablelabels.cpp index 85f686dc93..d5a240cc74 100644 --- a/modules/base/rendering/renderablelabels.cpp +++ b/modules/base/rendering/renderablelabels.cpp @@ -46,10 +46,9 @@ #include #include #include +#include namespace { - constexpr const char* _loggerCat = "base::RenderableLabels"; - constexpr const char* MeterUnit = "m"; constexpr const char* KilometerUnit = "Km"; constexpr const char* MegameterUnit = "Mm"; @@ -176,122 +175,91 @@ namespace { "Fade-In/-Out ending speed.", "Fade-In/-Out ending speed." }; + + struct [[codegen::Dictionary(RenderableLabels)]] Parameters { + enum class BlendMode { + Normal, + Additive + }; + + // [[codegen::verbatim(BlendModeInfo.description)]] + std::optional blendMode; + + enum class Orientation { + ViewDirection [[codegen::key("Camera View Direction")]], + PositionNormal [[codegen::key("Camera Position Normal")]] + }; + + // [[codegen::verbatim(LabelOrientationOptionInfo.description)]] + std::optional labelOrientationOption; + + // [[codegen::verbatim(LabelColorInfo.description)]] + std::optional labelColor; + + // [[codegen::verbatim(LabelTextInfo.description)]] + std::optional labelText; + + // [[codegen::verbatim(FontSizeInfo.description)]] + std::optional fontSize; + + // [[codegen::verbatim(LabelSizeInfo.description)]] + std::optional labelSize; + + // [[codegen::verbatim(LabelMinSizeInfo.description)]] + std::optional labelMinSize; + + // [[codegen::verbatim(LabelMaxSizeInfo.description)]] + std::optional labelMaxSize; + + // [[codegen::verbatim(EnableFadingEffectInfo.description)]] + std::optional enableFading; + + // [[codegen::verbatim(PixelSizeControlInfo.description)]] + std::optional enablePixelControl; + + // [[codegen::verbatim(TransformationMatrixInfo.description)]] + std::optional transformationMatrix; + + enum class Unit { + Meter [[codegen::key("m")]], + Kilometer [[codegen::key("Km")]], + Megameter [[codegen::key("Mm")]], + Gigameter [[codegen::key("Gm")]], + Terameter [[codegen::key("Tm")]], + Petameter [[codegen::key("Pm")]], + AstronomicalUnit [[codegen::key("au")]], + Parsec [[codegen::key("pc")]], + KiloParsec [[codegen::key("Kpc")]], + MegaParsec [[codgen::key("Mpc")]], + GigaParsec [[codegen::key("Gpc")]], + GigaLightyear [[codegen::key("Gly")]] + }; + + // [[codegen::verbatim(FadeStartUnitOptionInfo.description)]] + std::optional fadeStartUnit; + + // [[codegen::verbatim(FadeEndUnitOptionInfo.description)]] + std::optional fadeEndUnit; + + // [[codegen::verbatim(FadeStartDistInfo.description)]] + std::optional fadeStartDistance; + + // [[codegen::verbatim(FadeEndDistInfo.description)]] + std::optional fadeEndDistance; + + // [[codegen::verbatim(FadeStartSpeedInfo.description)]] + std::optional fadeStartSpeed; + + // [[codegen::verbatim(FadeEndSpeedInfo.description)]] + std::optional fadeEndSpeed; + }; +#include "renderablelabels_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableLabels::Documentation() { - using namespace documentation; - return { - "Renderable Labels", - "base_renderable_labels", - { - { - BlendModeInfo.identifier, - new StringInListVerifier({ "Normal", "Additive" }), - Optional::Yes, - BlendModeInfo.description, // + " The default value is 'Normal'.", - }, - { - LabelOrientationOptionInfo.identifier, - new StringInListVerifier( - { "Camera View Direction", "Camera Position Normal" } - ), - Optional::Yes, - LabelOrientationOptionInfo.description, - }, - { - LabelColorInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - LabelColorInfo.description, - }, - { - LabelTextInfo.identifier, - new StringVerifier, - Optional::Yes, - LabelTextInfo.description - }, - { - FontSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - FontSizeInfo.description - }, - { - LabelSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LabelSizeInfo.description - }, - { - LabelMinSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LabelMinSizeInfo.description - }, - { - LabelMaxSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LabelMaxSizeInfo.description - }, - { - EnableFadingEffectInfo.identifier, - new BoolVerifier, - Optional::Yes, - EnableFadingEffectInfo.description - }, - { - PixelSizeControlInfo.identifier, - new BoolVerifier, - Optional::Yes, - PixelSizeControlInfo.description - }, - { - FadeStartUnitOptionInfo.identifier, - new StringInListVerifier( - { "m", "Km", "Mm", "Gm", "au", "Tm", "Pm", "pc", "Kpc", "Mpc", - "Gpc", "Gly"} - ), - Optional::Yes, - FadeStartUnitOptionInfo.description, - }, - { - FadeEndUnitOptionInfo.identifier, - new StringInListVerifier( - {"m", "Km", "Mm", "Gm", "au", "Tm", "Pm", "pc", "Kpc", "Mpc", - "Gpc", "Gly"} - ), - Optional::Yes, - FadeEndUnitOptionInfo.description, - }, - { - FadeStartDistInfo.identifier, - new DoubleVerifier, - Optional::Yes, - FadeStartDistInfo.description - }, - { - FadeEndDistInfo.identifier, - new DoubleVerifier, - Optional::Yes, - FadeEndDistInfo.description - }, - { - FadeStartSpeedInfo.identifier, - new DoubleVerifier, - Optional::Yes, - FadeStartSpeedInfo.description - }, - { - FadeEndSpeedInfo.identifier, - new DoubleVerifier, - Optional::Yes, - FadeEndSpeedInfo.description - }, - } - }; + return codegen::doc(); } RenderableLabels::RenderableLabels(const ghoul::Dictionary& dictionary) @@ -327,11 +295,7 @@ RenderableLabels::RenderableLabels(const ghoul::Dictionary& dictionary) properties::OptionProperty::DisplayType::Dropdown ) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableLabels" - ); + const Parameters p = codegen::bake(dictionary); addProperty(_opacity); registerUpdateRenderBinFromOpacity(); @@ -353,13 +317,14 @@ RenderableLabels::RenderableLabels(const ghoul::Dictionary& dictionary) } }); - if (dictionary.hasKey(BlendModeInfo.identifier)) { - const std::string v = dictionary.value(BlendModeInfo.identifier); - if (v == "Normal") { - _blendMode = BlendModeNormal; - } - else if (v == "Additive") { - _blendMode = BlendModeAdditive; + if (p.blendMode.has_value()) { + switch (*p.blendMode) { + case Parameters::BlendMode::Normal: + _blendMode = BlendModeNormal; + break; + case Parameters::BlendMode::Additive: + _blendMode = BlendModeAdditive; + break; } } @@ -369,35 +334,26 @@ RenderableLabels::RenderableLabels(const ghoul::Dictionary& dictionary) _labelOrientationOption.addOption(NormalDirection, "Camera Position Normal"); _labelOrientationOption = NormalDirection; - if (dictionary.hasValue(LabelOrientationOptionInfo.identifier)) { - const std::string o = dictionary.value( - LabelOrientationOptionInfo.identifier - ); - - if (o == "Camera View Direction") { - _labelOrientationOption = ViewDirection; - } - else if (o == "Camera Position Normal") { - _labelOrientationOption = NormalDirection; + if (p.labelOrientationOption.has_value()) { + switch (*p.labelOrientationOption) { + case Parameters::Orientation::ViewDirection: + _labelOrientationOption = ViewDirection; + break; + case Parameters::Orientation::PositionNormal: + _labelOrientationOption = NormalDirection; + break; } } - - if (dictionary.hasKey(LabelTextInfo.identifier)) { - _labelText = dictionary.value(LabelTextInfo.identifier); - } - addProperty(_labelText); - addProperty(_labelOrientationOption); + _labelText = p.labelText.value_or(_labelText); + addProperty(_labelText); + + _labelColor = p.labelColor.value_or(_labelColor); _labelColor.setViewOption(properties::Property::ViewOptions::Color); - if (dictionary.hasKey(LabelColorInfo.identifier)) { - _labelColor = dictionary.value(LabelColorInfo.identifier); - } addProperty(_labelColor); - if (dictionary.hasKey(FontSizeInfo.identifier)) { - _fontSize = static_cast(dictionary.value(FontSizeInfo.identifier)); - } + _fontSize = p.fontSize.value_or(_fontSize); _fontSize.onChange([&]() { _font = global::fontManager->font( "Mono", @@ -408,49 +364,28 @@ RenderableLabels::RenderableLabels(const ghoul::Dictionary& dictionary) }); addProperty(_fontSize); - if (dictionary.hasKey(LabelSizeInfo.identifier)) { - _labelSize = static_cast( - dictionary.value(LabelSizeInfo.identifier) - ); - } + _labelSize = p.labelSize.value_or(_labelSize); addProperty(_labelSize); - if (dictionary.hasKey(LabelMinSizeInfo.identifier)) { - _labelMinSize = static_cast( - dictionary.value(LabelMinSizeInfo.identifier) - ); - } + _labelMinSize = p.labelMinSize.value_or(_labelMinSize); addProperty(_labelMinSize); - if (dictionary.hasKey(LabelMaxSizeInfo.identifier)) { - _labelMaxSize = static_cast( - dictionary.value(LabelMaxSizeInfo.identifier) - ); - } + _labelMaxSize = p.labelMaxSize.value_or(_labelMaxSize); addProperty(_labelMaxSize); - if (dictionary.hasKey(TransformationMatrixInfo.identifier)) { - _transformationMatrix = dictionary.value( - TransformationMatrixInfo.identifier - ); - } + _transformationMatrix = p.transformationMatrix.value_or(_transformationMatrix); - if (dictionary.hasKey(PixelSizeControlInfo.identifier)) { - _pixelSizeControl = dictionary.value(PixelSizeControlInfo.identifier); + _pixelSizeControl = p.enablePixelControl.value_or(_pixelSizeControl); + if (_pixelSizeControl) { + // @TODO (abock, 2021-01-28) I don't know why we only add the property if the + // pixel control is enabled, but I think this is an error addProperty(_pixelSizeControl); } - if (dictionary.hasKey(EnableFadingEffectInfo.identifier)) { - _enableFadingEffect = dictionary.value(EnableFadingEffectInfo.identifier); - } + _enableFadingEffect = p.enableFading.value_or(_enableFadingEffect); addProperty(_enableFadingEffect); - if (dictionary.hasKey(FadeStartDistInfo.identifier)) { - _fadeStartDistance = static_cast( - dictionary.value(FadeStartDistInfo.identifier) - ); - } - + _fadeStartDistance = p.fadeStartDistance.value_or(_fadeStartDistance); addProperty(_fadeStartDistance); _fadeStartUnitOption.addOption(Meter, MeterUnit); @@ -466,72 +401,56 @@ RenderableLabels::RenderableLabels(const ghoul::Dictionary& dictionary) _fadeStartUnitOption.addOption(Gigaparsec, GigaparsecUnit); _fadeStartUnitOption.addOption(GigalightYears, GigalightyearUnit); - _fadeStartUnitOption = AU; - if (dictionary.hasKey(FadeStartUnitOptionInfo.identifier)) { - std::string unit = dictionary.value( - FadeStartUnitOptionInfo.identifier - ); - if (unit == MeterUnit) { - _fadeStartUnitOption = Meter; - } - else if (unit == KilometerUnit) { - _fadeStartUnitOption = Kilometer; - } - else if (unit == MegameterUnit) { - _fadeStartUnitOption = Megameter; - } - else if (unit == GigameterUnit) { - _fadeStartUnitOption = Gigameter; - } - else if (unit == AstronomicalUnit) { - _fadeStartUnitOption = AU; - } - else if (unit == TerameterUnit) { - _fadeStartUnitOption = Terameter; - } - else if (unit == PetameterUnit) { - _fadeStartUnitOption = Petameter; - } - else if (unit == ParsecUnit) { - _fadeStartUnitOption = Parsec; - } - else if (unit == KiloparsecUnit) { - _fadeStartUnitOption = Kiloparsec; - } - else if (unit == MegaparsecUnit) { - _fadeStartUnitOption = Megaparsec; - } - else if (unit == GigaparsecUnit) { - _fadeStartUnitOption = Gigaparsec; - } - else if (unit == GigalightyearUnit) { - _fadeStartUnitOption = GigalightYears; - } - else { - LWARNING( - "No unit given for RenderableLabels. Using kilometer as units." - ); - _fadeStartUnitOption = Kilometer; + if (p.fadeStartUnit.has_value()) { + switch (*p.fadeStartUnit) { + case Parameters::Unit::Meter: + _fadeStartUnitOption = Meter; + break; + case Parameters::Unit::Kilometer: + _fadeStartUnitOption = Kilometer; + break; + case Parameters::Unit::Megameter: + _fadeStartUnitOption = Megameter; + break; + case Parameters::Unit::Gigameter: + _fadeStartUnitOption = Gigameter; + break; + case Parameters::Unit::Terameter: + _fadeStartUnitOption = Terameter; + break; + case Parameters::Unit::Petameter: + _fadeStartUnitOption = Petameter; + break; + case Parameters::Unit::AstronomicalUnit: + _fadeStartUnitOption = AU; + break; + case Parameters::Unit::Parsec: + _fadeStartUnitOption = Parsec; + break; + case Parameters::Unit::KiloParsec: + _fadeStartUnitOption = Kiloparsec; + break; + case Parameters::Unit::MegaParsec: + _fadeStartUnitOption = Megaparsec; + break; + case Parameters::Unit::GigaParsec: + _fadeStartUnitOption = Gigaparsec; + break; + case Parameters::Unit::GigaLightyear: + _fadeStartUnitOption = GigalightYears; + break; } } - + else { + _fadeStartUnitOption = AU; + } addProperty(_fadeStartUnitOption); - if (dictionary.hasKey(FadeStartSpeedInfo.identifier)) { - _fadeStartSpeed = static_cast( - dictionary.value(FadeStartSpeedInfo.identifier) - ); - } - + _fadeStartSpeed = p.fadeStartSpeed.value_or(_fadeStartSpeed); addProperty(_fadeStartSpeed); - if (dictionary.hasKey(FadeEndDistInfo.identifier)) { - _fadeEndDistance = static_cast( - dictionary.value(FadeEndDistInfo.identifier) - ); - } - + _fadeEndDistance = p.fadeEndDistance.value_or(_fadeEndDistance); addProperty(_fadeEndDistance); _fadeEndUnitOption.addOption(Meter, MeterUnit); @@ -547,64 +466,53 @@ RenderableLabels::RenderableLabels(const ghoul::Dictionary& dictionary) _fadeEndUnitOption.addOption(Gigaparsec, GigaparsecUnit); _fadeEndUnitOption.addOption(GigalightYears, GigalightyearUnit); - _fadeEndUnitOption = AU; - if (dictionary.hasKey(FadeEndUnitOptionInfo.identifier)) { - std::string unit = dictionary.value( - FadeEndUnitOptionInfo.identifier - ); - if (unit == MeterUnit) { - _fadeEndUnitOption = Meter; - } - else if (unit == KilometerUnit) { - _fadeEndUnitOption = Kilometer; - } - else if (unit == MegameterUnit) { - _fadeEndUnitOption = Megameter; - } - else if (unit == GigameterUnit) { - _fadeEndUnitOption = Gigameter; - } - else if (unit == AstronomicalUnit) { - _fadeEndUnitOption = AU; - } - else if (unit == TerameterUnit) { - _fadeEndUnitOption = Terameter; - } - else if (unit == PetameterUnit) { - _fadeEndUnitOption = Petameter; - } - else if (unit == ParsecUnit) { - _fadeEndUnitOption = Parsec; - } - else if (unit == KiloparsecUnit) { - _fadeEndUnitOption = Kiloparsec; - } - else if (unit == MegaparsecUnit) { - _fadeEndUnitOption = Megaparsec; - } - else if (unit == GigaparsecUnit) { - _fadeEndUnitOption = Gigaparsec; - } - else if (unit == GigalightyearUnit) { - _fadeEndUnitOption = GigalightYears; - } - else { - LWARNING( - "No unit given for RenderableLabels. Using kilometer as units." - ); - _fadeEndUnitOption = Kilometer; + if (p.fadeEndUnit.has_value()) { + switch (*p.fadeEndUnit) { + case Parameters::Unit::Meter: + _fadeStartUnitOption = Meter; + break; + case Parameters::Unit::Kilometer: + _fadeStartUnitOption = Kilometer; + break; + case Parameters::Unit::Megameter: + _fadeStartUnitOption = Megameter; + break; + case Parameters::Unit::Gigameter: + _fadeStartUnitOption = Gigameter; + break; + case Parameters::Unit::Terameter: + _fadeStartUnitOption = Terameter; + break; + case Parameters::Unit::Petameter: + _fadeStartUnitOption = Petameter; + break; + case Parameters::Unit::AstronomicalUnit: + _fadeStartUnitOption = AU; + break; + case Parameters::Unit::Parsec: + _fadeStartUnitOption = Parsec; + break; + case Parameters::Unit::KiloParsec: + _fadeEndUnitOption = Kiloparsec; + break; + case Parameters::Unit::MegaParsec: + _fadeEndUnitOption = Megaparsec; + break; + case Parameters::Unit::GigaParsec: + _fadeEndUnitOption = Gigaparsec; + break; + case Parameters::Unit::GigaLightyear: + _fadeEndUnitOption = GigalightYears; + break; } } - + else { + _fadeEndUnitOption = AU; + } addProperty(_fadeEndUnitOption); - - if (dictionary.hasKey(FadeEndSpeedInfo.identifier)) { - _fadeEndSpeed = static_cast( - dictionary.value(FadeEndSpeedInfo.identifier) - ); - } - + + _fadeEndSpeed = p.fadeEndSpeed.value_or(_fadeEndSpeed); addProperty(_fadeEndSpeed); } diff --git a/modules/base/rendering/renderablenodeline.cpp b/modules/base/rendering/renderablenodeline.cpp index 21218e13f4..779c28e226 100644 --- a/modules/base/rendering/renderablenodeline.cpp +++ b/modules/base/rendering/renderablenodeline.cpp @@ -84,42 +84,29 @@ namespace { glm::dvec3 diffPos = worldPos - anchorNodePos; return diffPos; } + + struct [[codegen::Dictionary(RenderableNodeLine)]] Parameters { + // [[codegen::verbatim(StartNodeInfo.description)]] + std::optional startNode; + + // [[codegen::verbatim(EndNodeInfo.description)]] + std::optional endNode; + + // [[codegen::verbatim(LineColorInfo.description)]] + std::optional color; + + // [[codegen::verbatim(LineWidthInfo.description)]] + std::optional lineWidth; + }; +#include "renderablenodeline_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableNodeLine::Documentation() { - using namespace documentation; - return { - "Renderable Node Line", - "base_renderable_renderablenodeline", - { - { - StartNodeInfo.identifier, - new StringVerifier, - Optional::Yes, - StartNodeInfo.description - }, - { - EndNodeInfo.identifier, - new StringVerifier, - Optional::Yes, - EndNodeInfo.description - }, - { - LineColorInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - LineColorInfo.description - }, - { - LineWidthInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LineWidthInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_renderable_renderablenodeline"; + return doc; } RenderableNodeLine::RenderableNodeLine(const ghoul::Dictionary& dictionary) @@ -129,36 +116,22 @@ RenderableNodeLine::RenderableNodeLine(const ghoul::Dictionary& dictionary) , _lineColor(LineColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f)) , _lineWidth(LineWidthInfo, 2.f, 1.f, 20.f) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableNodeLine" - ); - - if (dictionary.hasKey(StartNodeInfo.identifier)) { - _start = dictionary.value(StartNodeInfo.identifier); - } - - if (dictionary.hasKey(EndNodeInfo.identifier)) { - _end = dictionary.value(EndNodeInfo.identifier); - } - - if (dictionary.hasKey(LineColorInfo.identifier)) { - _lineColor = dictionary.value(LineColorInfo.identifier); - } - if (dictionary.hasKey(LineWidthInfo.identifier)) { - _lineWidth = static_cast( - dictionary.value(LineWidthInfo.identifier) - ); - } + const Parameters p = codegen::bake(dictionary); + _start = p.startNode.value_or(_start); _start.onChange([&]() { validateNodes(); }); - _end.onChange([&]() { validateNodes(); }); - addProperty(_start); + + _end = p.endNode.value_or(_end); + _end.onChange([&]() { validateNodes(); }); addProperty(_end); + + _lineColor = p.color.value_or(_lineColor); addProperty(_lineColor); + + _lineWidth = p.lineWidth.value_or(_lineWidth); addProperty(_lineWidth); + addProperty(_opacity); } diff --git a/modules/base/rendering/renderableplane.cpp b/modules/base/rendering/renderableplane.cpp index 37277bd6d0..b718506c3e 100644 --- a/modules/base/rendering/renderableplane.cpp +++ b/modules/base/rendering/renderableplane.cpp @@ -40,6 +40,7 @@ #include #include #include +#include namespace { constexpr const char* ProgramName = "Plane"; @@ -68,36 +69,30 @@ namespace { "Blending Mode", "This determines the blending mode that is applied to this plane." }; + + struct [[codegen::Dictionary(RenderablePlane)]] Parameters { + // [[codegen::verbatim(BillboardInfo.description)]] + std::optional billboard; + + // [[codegen::verbatim(SizeInfo.description)]] + float size; + + enum class BlendMode { + Normal, + Additive + }; + // [[codegen::verbatim(BlendModeInfo.description)]] + std::optional blendMode; + }; +#include "renderableplane_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderablePlane::Documentation() { - using namespace documentation; - return { - "Renderable Plane", - "base_renderable_plane", - { - { - SizeInfo.identifier, - new DoubleVerifier, - Optional::No, - SizeInfo.description - }, - { - BillboardInfo.identifier, - new BoolVerifier, - Optional::Yes, - BillboardInfo.description - }, - { - BlendModeInfo.identifier, - new StringInListVerifier({ "Normal", "Additive" }), - Optional::Yes, - BlendModeInfo.description, // + " The default value is 'Normal'.", - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_renderable_plane"; + return doc; } RenderablePlane::RenderablePlane(const ghoul::Dictionary& dictionary) @@ -106,20 +101,13 @@ RenderablePlane::RenderablePlane(const ghoul::Dictionary& dictionary) , _billboard(BillboardInfo, false) , _size(SizeInfo, 10.f, 0.f, 1e25f) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderablePlane" - ); + Parameters p = codegen::bake(dictionary); addProperty(_opacity); registerUpdateRenderBinFromOpacity(); - _size = static_cast(dictionary.value(SizeInfo.identifier)); - - if (dictionary.hasKey(BillboardInfo.identifier)) { - _billboard = dictionary.value(BillboardInfo.identifier); - } + _size = p.size; + _billboard = p.billboard.value_or(_billboard); _blendMode.addOptions({ { BlendModeNormal, "Normal" }, @@ -144,12 +132,11 @@ RenderablePlane::RenderablePlane(const ghoul::Dictionary& dictionary) } }); - if (dictionary.hasKey(BlendModeInfo.identifier)) { - const std::string v = dictionary.value(BlendModeInfo.identifier); - if (v == "Normal") { + if (p.blendMode.has_value()) { + if (*p.blendMode == Parameters::BlendMode::Normal) { _blendMode = BlendModeNormal; } - else if (v == "Additive") { + else if (*p.blendMode == Parameters::BlendMode::Additive) { _blendMode = BlendModeAdditive; } } diff --git a/modules/base/rendering/renderableplaneimagelocal.cpp b/modules/base/rendering/renderableplaneimagelocal.cpp index cd37175f72..c3a7279bde 100644 --- a/modules/base/rendering/renderableplaneimagelocal.cpp +++ b/modules/base/rendering/renderableplaneimagelocal.cpp @@ -35,10 +35,9 @@ #include #include #include +#include namespace { - constexpr const char* KeyLazyLoading = "LazyLoading"; - constexpr openspace::properties::Property::PropertyInfo TextureInfo = { "Texture", "Texture", @@ -52,54 +51,47 @@ namespace { "This value specifies if the plane should be rendered in the Background," "Opaque, Transparent, or Overlay rendering step." }; + + struct [[codegen::Dictionary(RenderablePlaneImageLocal)]] Parameters { + // [[codegen::verbatim(TextureInfo.description)]] + std::string texture; + + enum class RenderType { + Background, + Opaque, + PreDeferredTransparency, + PostDeferredTransparency, + Overlay + }; + + // [[codegen::verbatim(RenderableTypeInfo.description)]] + std::optional renderType [[codegen::key("RenderableType")]]; + + // If this value is set to 'true', the image for this plane will not be loaded at + // startup but rather when image is shown for the first time. Additionally, if the + // plane is hidden, the image will automatically be unloaded + std::optional lazyLoading; + }; +#include "renderableplaneimagelocal_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderablePlaneImageLocal::Documentation() { - using namespace documentation; - return { - "Renderable Plane Image Local", - "base_renderable_plane_image_local", - { - { - TextureInfo.identifier, - new StringVerifier, - Optional::No, - TextureInfo.description - }, - { - RenderableTypeInfo.identifier, - new StringVerifier, - Optional::Yes, - RenderableTypeInfo.description - }, - { - KeyLazyLoading, - new BoolVerifier, - Optional::Yes, - "If this value is set to 'true', the image for this plane will not be " - "loaded at startup but rather when image is shown for the first time. " - "Additionally, if the plane is hidden, the image will automatically be " - "unloaded" - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_renderable_plane_image_local"; + return doc; } RenderablePlaneImageLocal::RenderablePlaneImageLocal(const ghoul::Dictionary& dictionary) : RenderablePlane(dictionary) , _texturePath(TextureInfo) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderablePlaneImageLocal" - ); + const Parameters p = codegen::bake(dictionary); addProperty(_blendMode); - _texturePath = absPath(dictionary.value(TextureInfo.identifier)); + _texturePath = absPath(p.texture); _textureFile = std::make_unique(_texturePath); addProperty(_texturePath); @@ -108,44 +100,40 @@ RenderablePlaneImageLocal::RenderablePlaneImageLocal(const ghoul::Dictionary& di [this](const ghoul::filesystem::File&) { _textureIsDirty = true; } ); - if (dictionary.hasKey(RenderableTypeInfo.identifier)) { - std::string renderType = dictionary.value( - RenderableTypeInfo.identifier - ); - if (renderType == "Background") { - setRenderBin(Renderable::RenderBin::Background); - } - else if (renderType == "Opaque") { - setRenderBin(Renderable::RenderBin::Opaque); - } - else if (renderType == "PreDeferredTransparent") { - setRenderBin(Renderable::RenderBin::PreDeferredTransparent); - } - else if (renderType == "PostDeferredTransparent") { - setRenderBin(Renderable::RenderBin::PostDeferredTransparent); - } - else if (renderType == "Overlay") { - setRenderBin(Renderable::RenderBin::Overlay); + if (p.renderType.has_value()) { + switch (*p.renderType) { + case Parameters::RenderType::Background: + setRenderBin(Renderable::RenderBin::Background); + break; + case Parameters::RenderType::Opaque: + setRenderBin(Renderable::RenderBin::Opaque); + break; + case Parameters::RenderType::PreDeferredTransparency: + setRenderBin(Renderable::RenderBin::PreDeferredTransparent); + break; + case Parameters::RenderType::PostDeferredTransparency: + setRenderBin(Renderable::RenderBin::PostDeferredTransparent); + break; + case Parameters::RenderType::Overlay: + setRenderBin(Renderable::RenderBin::Overlay); + break; } } else { setRenderBin(Renderable::RenderBin::Opaque); } - if (dictionary.hasKey(KeyLazyLoading)) { - _isLoadingLazily = dictionary.value(KeyLazyLoading); - - if (_isLoadingLazily) { - _enabled.onChange([this]() { - if (!_enabled) { - BaseModule::TextureManager.release(_texture); - _texture = nullptr; - } - if (_enabled) { - _textureIsDirty = true; - } - }); - } + _isLoadingLazily = p.lazyLoading.value_or(_isLoadingLazily); + if (_isLoadingLazily) { + _enabled.onChange([this]() { + if (!_enabled) { + BaseModule::TextureManager.release(_texture); + _texture = nullptr; + } + if (_enabled) { + _textureIsDirty = true; + } + }); } } diff --git a/modules/base/rendering/renderableplaneimageonline.cpp b/modules/base/rendering/renderableplaneimageonline.cpp index 50d8d7d6ec..c99eb90755 100644 --- a/modules/base/rendering/renderableplaneimageonline.cpp +++ b/modules/base/rendering/renderableplaneimageonline.cpp @@ -41,24 +41,20 @@ namespace { "this value is changed, the image at the new path will automatically be loaded " "and displayed." }; + + struct [[codegen::Dictionary(RenderablePlaneImageOnline)]] Parameters { + // [[codegen::verbatim(TextureInfo.description)]] + std::string url [[codegen::key("URL")]]; + }; +#include "renderableplaneimageonline_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderablePlaneImageOnline::Documentation() { - using namespace documentation; - return { - "Renderable Plane Image Online", - "base_renderable_plane_image_online", - { - { - TextureInfo.identifier, - new StringVerifier, - Optional::No, - TextureInfo.description, - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_renderable_plane_image_online"; + return doc; } RenderablePlaneImageOnline::RenderablePlaneImageOnline( @@ -66,20 +62,12 @@ RenderablePlaneImageOnline::RenderablePlaneImageOnline( : RenderablePlane(dictionary) , _texturePath(TextureInfo) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderablePlaneImageOnline" - ); + const Parameters p = codegen::bake(dictionary); _texturePath.onChange([this]() { _textureIsDirty = true; }); addProperty(_texturePath); - std::string texturePath; - if (dictionary.hasKey(TextureInfo.identifier)) { - _texturePath = dictionary.value(TextureInfo.identifier); - } - + _texturePath = p.url; addProperty(_texturePath); } diff --git a/modules/base/rendering/renderablesphere.cpp b/modules/base/rendering/renderablesphere.cpp index fdde7eeea7..4f20d37fc2 100644 --- a/modules/base/rendering/renderablesphere.cpp +++ b/modules/base/rendering/renderablesphere.cpp @@ -38,6 +38,7 @@ #include #include #include +#include namespace { constexpr const char* ProgramName = "Sphere"; @@ -117,81 +118,55 @@ namespace { "Sets the current sphere rendering as a background rendering type", "Enables/Disables background rendering." }; + + struct [[codegen::Dictionary(RenderableSphere)]] Parameters { + // [[codegen::verbatim(SizeInfo.description)]] + float size; + + // [[codegen::verbatim(SegmentsInfo.description)]] + int segments; + + // [[codegen::verbatim(TextureInfo.description)]] + std::string texture; + + enum class Orientation { + Outside, + Inside, + Both + }; + + // [[codegen::verbatim(OrientationInfo.description)]] + std::optional orientation; + + // [[codegen::verbatim(UseAdditiveBlendingInfo.description)]] + std::optional useAdditiveBlending; + + // [[codegen::verbatim(MirrorTextureInfo.description)]] + std::optional mirrorTexture; + + // [[codegen::verbatim(FadeOutThresholdInfo.description)]] + std::optional fadeOutThreshold [[codegen::inrange(0.0, 1.0)]]; + + // [[codegen::verbatim(FadeInThresholdInfo.description)]] + std::optional fadeInThreshold; + + // [[codegen::verbatim(DisableFadeInOutInfo.description)]] + std::optional disableFadeInOut; + + // [[codegen::verbatim(BackgroundInfo.description)]] + std::optional background; + }; +#include "renderablesphere_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableSphere::Documentation() { - using namespace documentation; - return { - "RenderableSphere", - "base_renderable_sphere", - { - { - SizeInfo.identifier, - new DoubleVerifier, - Optional::No, - SizeInfo.description - }, - { - SegmentsInfo.identifier, - new IntVerifier, - Optional::No, - SegmentsInfo.description - }, - { - TextureInfo.identifier, - new StringVerifier, - Optional::No, - TextureInfo.description - }, - { - OrientationInfo.identifier, - new StringInListVerifier({ "Inside", "Outside", "Both" }), - Optional::Yes, - OrientationInfo.description - }, - { - UseAdditiveBlendingInfo.identifier, - new BoolVerifier, - Optional::Yes, - UseAdditiveBlendingInfo.description - }, - { - MirrorTextureInfo.identifier, - new BoolVerifier, - Optional::Yes, - MirrorTextureInfo.description - }, - { - FadeOutThresholdInfo.identifier, - new DoubleInRangeVerifier(0.0, 1.0), - Optional::Yes, - FadeOutThresholdInfo.description - }, - { - FadeInThresholdInfo.identifier, - new DoubleVerifier, - Optional::Yes, - FadeInThresholdInfo.description - }, - { - DisableFadeInOutInfo.identifier, - new BoolVerifier, - Optional::Yes, - DisableFadeInOutInfo.description - }, - { - BackgroundInfo.identifier, - new BoolVerifier, - Optional::Yes, - BackgroundInfo.description - }, - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_renderable_sphere"; + return doc; } - RenderableSphere::RenderableSphere(const ghoul::Dictionary& dictionary) : Renderable(dictionary) , _texturePath(TextureInfo) @@ -205,18 +180,14 @@ RenderableSphere::RenderableSphere(const ghoul::Dictionary& dictionary) , _fadeInThreshold(FadeInThresholdInfo, -1.f, 0.f, 1.f) , _fadeOutThreshold(FadeOutThresholdInfo, -1.f, 0.f, 1.f) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableSphere" - ); + const Parameters p = codegen::bake(dictionary); addProperty(_opacity); registerUpdateRenderBinFromOpacity(); - _size = static_cast(dictionary.value(SizeInfo.identifier)); - _segments = static_cast(dictionary.value(SegmentsInfo.identifier)); - _texturePath = absPath(dictionary.value(TextureInfo.identifier)); + _size = p.size; + _segments = p.segments; + _texturePath = p.texture; _orientation.addOptions({ { static_cast(Orientation::Outside), "Outside" }, @@ -224,19 +195,19 @@ RenderableSphere::RenderableSphere(const ghoul::Dictionary& dictionary) { static_cast(Orientation::Both), "Both" } }); - if (dictionary.hasKey(OrientationInfo.identifier)) { - const std::string& v = dictionary.value(OrientationInfo.identifier); - if (v == "Inside") { - _orientation = static_cast(Orientation::Inside); - } - else if (v == "Outside") { - _orientation = static_cast(Orientation::Outside); - } - else if (v == "Both") { - _orientation = static_cast(Orientation::Both); - } - else { - throw ghoul::MissingCaseException(); + if (p.orientation.has_value()) { + switch (*p.orientation) { + case Parameters::Orientation::Inside: + _orientation = static_cast(Orientation::Inside); + break; + case Parameters::Orientation::Outside: + _orientation = static_cast(Orientation::Outside); + break; + case Parameters::Orientation::Both: + _orientation = static_cast(Orientation::Both); + break; + default: + throw ghoul::MissingCaseException(); } } else { @@ -256,44 +227,34 @@ RenderableSphere::RenderableSphere(const ghoul::Dictionary& dictionary) addProperty(_mirrorTexture); addProperty(_useAdditiveBlending); + _mirrorTexture = p.mirrorTexture.value_or(_mirrorTexture); + _useAdditiveBlending = p.useAdditiveBlending.value_or(_useAdditiveBlending); - if (dictionary.hasKey(MirrorTextureInfo.identifier)) { - _mirrorTexture = dictionary.value(MirrorTextureInfo.identifier); - } - if (dictionary.hasKey(UseAdditiveBlendingInfo.identifier)) { - _useAdditiveBlending = dictionary.value(UseAdditiveBlendingInfo.identifier); - - if (_useAdditiveBlending) { - setRenderBin(Renderable::RenderBin::PreDeferredTransparent); - } + if (_useAdditiveBlending) { + setRenderBin(Renderable::RenderBin::PreDeferredTransparent); } - if (dictionary.hasKey(FadeOutThresholdInfo.identifier)) { - _fadeOutThreshold = static_cast( - dictionary.value(FadeOutThresholdInfo.identifier) - ); + bool hasGivenFadeOut = p.fadeOutThreshold.has_value(); + if (hasGivenFadeOut) { + _fadeOutThreshold = *p.fadeOutThreshold; addProperty(_fadeOutThreshold); } - if (dictionary.hasKey(FadeInThresholdInfo.identifier)) { - _fadeInThreshold = static_cast( - dictionary.value(FadeInThresholdInfo.identifier) - ); + bool hasGivenFadeIn = p.fadeInThreshold.has_value(); + if (hasGivenFadeIn) { + _fadeInThreshold = *p.fadeInThreshold; addProperty(_fadeInThreshold); } - if (dictionary.hasKey(FadeInThresholdInfo.identifier) || - dictionary.hasKey(FadeOutThresholdInfo.identifier)) { - _disableFadeInDistance.set(false); + if (hasGivenFadeIn || hasGivenFadeOut) { + _disableFadeInDistance = false; addProperty(_disableFadeInDistance); } - if (dictionary.hasKey(BackgroundInfo.identifier)) { - _backgroundRendering = dictionary.value(BackgroundInfo.identifier); + _backgroundRendering = p.background.value_or(_backgroundRendering); - if (_backgroundRendering) { - setRenderBin(Renderable::RenderBin::Background); - } + if (_backgroundRendering) { + setRenderBin(Renderable::RenderBin::Background); } setRenderBinFromOpacity(); diff --git a/modules/base/rendering/renderabletrail.cpp b/modules/base/rendering/renderabletrail.cpp index 0a033b2afc..12fd349498 100644 --- a/modules/base/rendering/renderabletrail.cpp +++ b/modules/base/rendering/renderabletrail.cpp @@ -34,7 +34,6 @@ #include #include #include - #include namespace { diff --git a/modules/base/rendering/screenspacedashboard.cpp b/modules/base/rendering/screenspacedashboard.cpp index 437af84538..4cb9cf591b 100644 --- a/modules/base/rendering/screenspacedashboard.cpp +++ b/modules/base/rendering/screenspacedashboard.cpp @@ -34,6 +34,7 @@ #include #include #include +#include namespace { constexpr openspace::properties::Property::PropertyInfo UseMainInfo = { @@ -42,6 +43,15 @@ namespace { "If this value is set to 'true', this ScreenSpaceDashboard will use the " "main dashboard instead of creating an independent one." }; + + struct [[codegen::Dictionary(ScreenSpaceDashboard)]] Parameters { + // Specifies the GUI name of the ScreenSpaceDashboard + std::optional name; + + // [[codegen::verbatim(UseMainInfo.description)]] + std::optional useMainDashboard; + }; +#include "screenspacedashboard_codegen.cpp" } // namespace namespace openspace { @@ -115,42 +125,22 @@ int removeDashboardItemsFromScreenSpace(lua_State* L) { dash->dashboard().clearDashboardItems(); return 0; } - } // namespace luascriptfunctions - documentation::Documentation ScreenSpaceDashboard::Documentation() { - using namespace openspace::documentation; - return { - "ScreenSpace Dashboard", - "base_screenspace_dashboard", - { - { - KeyName, - new StringVerifier, - Optional::Yes, - "Specifies the GUI name of the ScreenSpaceDashboard" - }, - { - UseMainInfo.identifier, - new BoolVerifier, - Optional::Yes, - UseMainInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_screenspace_dashboard"; + return doc; } ScreenSpaceDashboard::ScreenSpaceDashboard(const ghoul::Dictionary& dictionary) : ScreenSpaceFramebuffer(dictionary) , _useMainDashboard(UseMainInfo, false) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "ScreenSpaceDashboard" - ); + const Parameters p = codegen::bake(dictionary); + // @TODO (abock, 2021-01-29) Should this be the name variable? The identifier wasn't + // declared in the documentation std::string identifier; if (dictionary.hasValue(KeyIdentifier)) { identifier = dictionary.value(KeyIdentifier); @@ -161,9 +151,7 @@ ScreenSpaceDashboard::ScreenSpaceDashboard(const ghoul::Dictionary& dictionary) identifier = makeUniqueIdentifier(identifier); setIdentifier(std::move(identifier)); - if (dictionary.hasKey(UseMainInfo.identifier)) { - _useMainDashboard = dictionary.value(UseMainInfo.identifier); - } + _useMainDashboard = p.useMainDashboard.value_or(_useMainDashboard); addProperty(_useMainDashboard); _scale = 1.f; diff --git a/modules/base/rendering/screenspaceimagelocal.cpp b/modules/base/rendering/screenspaceimagelocal.cpp index 058789cf43..3c74143c2f 100644 --- a/modules/base/rendering/screenspaceimagelocal.cpp +++ b/modules/base/rendering/screenspaceimagelocal.cpp @@ -32,6 +32,7 @@ #include #include #include +#include namespace { constexpr openspace::properties::Property::PropertyInfo TexturePathInfo = { @@ -42,42 +43,33 @@ namespace { "and displayed. The size of the image will also automatically set the default " "size of this plane." }; + + struct [[codegen::Dictionary(ScreenSpaceImageLocal)]] Parameters { + // Specifies the GUI name of the ScreenspaceImage + std::optional name; + + // [[codegen::verbatim(TexturePathInfo.description)]] + std::optional texturePath; + }; +#include "screenspaceimagelocal_codegen.cpp" } // namespace namespace openspace { documentation::Documentation ScreenSpaceImageLocal::Documentation() { - using namespace openspace::documentation; - return { - "ScreenSpace Local Image", - "base_screenspace_image_local", - { - { - KeyName, - new StringVerifier, - Optional::Yes, - "Specifies the GUI name of the ScreenspaceImage" - }, - { - TexturePathInfo.identifier, - new StringVerifier, - Optional::Yes, - TexturePathInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_screenspace_image_local"; + return doc; } ScreenSpaceImageLocal::ScreenSpaceImageLocal(const ghoul::Dictionary& dictionary) : ScreenSpaceRenderable(dictionary) , _texturePath(TexturePathInfo) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "ScreenSpaceImageLocal" - ); + const Parameters p = codegen::bake(dictionary); + // @TODO (abock, 2021-02-02) Should this be the name variable? The identifier wasn't + // declared in the documentation std::string identifier; if (dictionary.hasValue(KeyIdentifier)) { identifier = dictionary.value(KeyIdentifier); @@ -101,16 +93,15 @@ ScreenSpaceImageLocal::ScreenSpaceImageLocal(const ghoul::Dictionary& dictionary }); addProperty(_texturePath); - if (dictionary.hasKey(TexturePathInfo.identifier)) { - std::string path = dictionary.value(TexturePathInfo.identifier); - if (!FileSys.fileExists(FileSys.absolutePath(path))) { - LWARNINGC( - "ScreenSpaceImageLocal", - fmt::format("Image {} did not exist for {}", path, _identifier) - ); + if (p.texturePath.has_value()) { + if (FileSys.fileExists(FileSys.absolutePath(*p.texturePath))) { + _texturePath = FileSys.absolutePath(*p.texturePath); } else { - _texturePath = path; + LWARNINGC( + "ScreenSpaceImageLocal", + fmt::format("Image {} did not exist for {}", *p.texturePath, _identifier) + ); } } } diff --git a/modules/base/rendering/screenspaceimageonline.cpp b/modules/base/rendering/screenspaceimageonline.cpp index 4a138b5fa9..ef5c527175 100644 --- a/modules/base/rendering/screenspaceimageonline.cpp +++ b/modules/base/rendering/screenspaceimageonline.cpp @@ -33,6 +33,7 @@ #include #include #include +#include namespace { constexpr openspace::properties::Property::PropertyInfo TextureInfo = { @@ -43,30 +44,23 @@ namespace { "and displayed. The size of the image will also automatically set the default " "size of this plane." }; + + struct [[codegen::Dictionary(ScreenSpaceImageOnline)]] Parameters { + // Specifies the GUI name of the ScreenspaceImage + std::optional name; + + // [[codegen::verbatim(TextureInfo.description)]] + std::optional url [[codegen::key("URL")]]; + }; +#include "screenspaceimageonline_codegen.cpp" } // namespace namespace openspace { documentation::Documentation ScreenSpaceImageOnline::Documentation() { - using namespace openspace::documentation; - return { - "ScreenSpace Online Image", - "base_screenspace_image_online", - { - { - KeyName, - new StringVerifier, - Optional::Yes, - "Specifies the GUI name of the ScreenspaceImage" - }, - { - TextureInfo.identifier, - new StringVerifier, - Optional::Yes, - TextureInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_screenspace_image_online"; + return doc; } ScreenSpaceImageOnline::ScreenSpaceImageOnline(const ghoul::Dictionary& dictionary) @@ -74,11 +68,7 @@ ScreenSpaceImageOnline::ScreenSpaceImageOnline(const ghoul::Dictionary& dictiona , _textureIsDirty(false) , _texturePath(TextureInfo) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "ScreenSpaceImageOnline" - ); + const Parameters p = codegen::bake(dictionary); std::string identifier; if (dictionary.hasValue(KeyIdentifier)) { @@ -92,11 +82,7 @@ ScreenSpaceImageOnline::ScreenSpaceImageOnline(const ghoul::Dictionary& dictiona _texturePath.onChange([this]() { _textureIsDirty = true; }); addProperty(_texturePath); - - std::string texturePath; - if (dictionary.hasKey(TextureInfo.identifier)) { - _texturePath = dictionary.value(TextureInfo.identifier); - } + _texturePath = p.url.value_or(_texturePath); } ScreenSpaceImageOnline::~ScreenSpaceImageOnline() {} // NOLINT diff --git a/modules/base/rotation/constantrotation.cpp b/modules/base/rotation/constantrotation.cpp index bbf4f98a9c..d72f524f40 100644 --- a/modules/base/rotation/constantrotation.cpp +++ b/modules/base/rotation/constantrotation.cpp @@ -28,6 +28,7 @@ #include #include #include +#include namespace { constexpr openspace::properties::Property::PropertyInfo RotationInfo = { @@ -41,35 +42,22 @@ namespace { "Rotation Rate", "This value determines the number of revolutions per in-game second" }; + + struct [[codegen::Dictionary(ConstantRotation)]] Parameters { + // [[codegen::verbatim(RotationInfo.description)]] + std::optional rotationAxis; + // [[codegen::verbatim(RotationRateInfo.description)]] + std::optional rotationRate; + }; +#include "constantrotation_codegen.cpp" } // namespace namespace openspace { documentation::Documentation ConstantRotation::Documentation() { - using namespace openspace::documentation; - return { - "Static Rotation", - "base_transform_rotation_constant", - { - { - "Type", - new StringEqualVerifier("ConstantRotation"), - Optional::No - }, - { - RotationInfo.identifier, - new DoubleVector3Verifier(), - Optional::Yes, - RotationInfo.description - }, - { - RotationRateInfo.identifier, - new DoubleVerifier(), - Optional::Yes, - RotationRateInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_transform_rotation_constant"; + return doc; } ConstantRotation::ConstantRotation(const ghoul::Dictionary& dictionary) @@ -81,18 +69,13 @@ ConstantRotation::ConstantRotation(const ghoul::Dictionary& dictionary) ) , _rotationRate(RotationRateInfo, 1.f, -1000.f, 1000.f) { + const Parameters p = codegen::bake(dictionary); + + _rotationAxis = p.rotationAxis.value_or(_rotationAxis); addProperty(_rotationAxis); + + _rotationRate = p.rotationRate.value_or(_rotationRate); addProperty(_rotationRate); - - if (dictionary.hasKey(RotationInfo.identifier)) { - _rotationAxis = dictionary.value(RotationInfo.identifier); - } - - if (dictionary.hasKey(RotationRateInfo.identifier)) { - _rotationRate = static_cast( - dictionary.value(RotationRateInfo.identifier) - ); - } } glm::dmat3 ConstantRotation::matrix(const UpdateData& data) const { diff --git a/modules/base/rotation/fixedrotation.cpp b/modules/base/rotation/fixedrotation.cpp index 00cbbae1e2..5d0d864ad0 100644 --- a/modules/base/rotation/fixedrotation.cpp +++ b/modules/base/rotation/fixedrotation.cpp @@ -32,16 +32,11 @@ #include #include #include +#include #include +#include namespace { - constexpr const char* KeyXAxis = "XAxis"; - constexpr const char* KeyXAxisOrthogonal = "XAxisOrthogonal"; - constexpr const char* KeyYAxis = "YAxis"; - constexpr const char* KeyYAxisOrthogonal = "YAxisOrthogonal"; - constexpr const char* KeyZAxis = "ZAxis"; - constexpr const char* KeyZAxisOrthogonal = "ZAxisOrthogonal"; - constexpr const openspace::properties::Property::PropertyInfo EnableInfo = { "Enable", "Enabled", @@ -186,98 +181,59 @@ namespace { "only needed if any of the three axis uses the Object type. In this case, the " "location of the attached node is required to compute the relative direction." }; + + struct [[codegen::Dictionary(FixedRotation)]] Parameters { + // This value specifies the direction of the new X axis. If this value is not + // specified, it will be computed by completing a right handed coordinate system + // from the Y and Z axis, which must be specified instead. If this value is a + // string, it is interpreted as the identifier of another scenegraph node. If this + // value is a 3-vector, it is interpreted as a direction vector + std::optional> xAxis; + + // [[codegen::verbatim(XAxisOrthogonalVectorInfo.description)]] + std::optional xAxisOrthogonal; + + // [[codegen::verbatim(XAxisInvertObjectInfo.description)]] + std::optional xAxisInvert [[codegen::key("xAxis - InvertObject")]]; + + // This value specifies the direction of the new Y axis. If this value is not + // specified, it will be computed by completing a right handed coordinate system + // from the X and Z axis, which must be specified instead. If this value is a + // string, it is interpreted as the identifier of another scenegraph node. If this + // value is a 3-vector, it is interpreted as a direction vector + std::optional> yAxis; + + // [[codegen::verbatim(YAxisOrthogonalVectorInfo.description)]] + std::optional yAxisOrthogonal; + + // [[codegen::verbatim(YAxisInvertObjectInfo.description)]] + std::optional yAxisInvert [[codegen::key("yAxis - InvertObject")]]; + + // This value specifies the direction of the new Z axis. If this value is not + // specified, it will be computed by completing a right handed coordinate system + // from the X and Y axis, which must be specified instead. If this value is a + // string, it is interpreted as the identifier of another scenegraph node. If this + // value is a 3-vector, it is interpreted as a direction vector + std::optional> zAxis; + + // [[codegen::verbatim(ZAxisOrthogonalVectorInfo.description)]] + std::optional zAxisOrthogonal; + + // [[codegen::verbatim(ZAxisInvertObjectInfo.description)]] + std::optional zAxisInvert [[codegen::key("zAxis - InvertObject")]]; + + // [[codegen::verbatim(AttachedInfo.description)]] + std::optional attached; + }; +#include "fixedrotation_codegen.cpp" } // namespace namespace openspace { documentation::Documentation FixedRotation::Documentation() { - using namespace openspace::documentation; - return { - "Fixed Rotation", - "base_transform_rotation_fixed", - { - { - "Type", - new StringEqualVerifier("FixedRotation"), - Optional::No - }, - { - KeyXAxis, - new OrVerifier({ new StringVerifier, new DoubleVector3Verifier, }), - Optional::Yes, - "This value specifies the direction of the new X axis. If this value is " - "not specified, it will be computed by completing a right handed " - "coordinate system from the Y and Z axis, which must be specified " - "instead. If this value is a string, it is interpreted as the identifier " - "of another scenegraph node. If this value is a 3-vector, it is " - "interpreted as a direction vector." - }, - { - KeyXAxisOrthogonal, - new BoolVerifier, - Optional::Yes, - XAxisOrthogonalVectorInfo.description - }, - { - XAxisInvertObjectInfo.identifier, - new BoolVerifier, - Optional::Yes, - XAxisInvertObjectInfo.description - }, - { - KeyYAxis, - new OrVerifier({ new StringVerifier, new DoubleVector3Verifier, }), - Optional::Yes, - "This value specifies the direction of the new Y axis. If this value is " - "not specified, it will be computed by completing a right handed " - "coordinate system from the X and Z axis, which must be specified " - "instead. If this value is a string, it is interpreted as the identifier " - "of another scenegraph node. If this value is a 3-vector, it is " - "interpreted as a direction vector." - }, - { - KeyYAxisOrthogonal, - new BoolVerifier, - Optional::Yes, - YAxisOrthogonalVectorInfo.description - }, - { - YAxisInvertObjectInfo.identifier, - new BoolVerifier, - Optional::Yes, - YAxisInvertObjectInfo.description - }, - { - KeyZAxis, - new OrVerifier({ new StringVerifier, new DoubleVector3Verifier, }), - Optional::Yes, - "This value specifies the direction of the new Z axis. If this value is " - "not specified, it will be computed by completing a right handed " - "coordinate system from the X and Y axis, which must be specified " - "instead. If this value is a string, it is interpreted as the identifier " - "of another scenegraph node. If this value is a 3-vector, it is " - "interpreted as a direction vector." - }, - { - KeyZAxisOrthogonal, - new BoolVerifier, - Optional::Yes, - ZAxisOrthogonalVectorInfo.description - }, - { - ZAxisInvertObjectInfo.identifier, - new BoolVerifier, - Optional::Yes, - ZAxisInvertObjectInfo.description - }, - { - AttachedInfo.identifier, - new StringVerifier, - Optional::Yes, - AttachedInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_transform_rotation_fixed"; + return doc; } FixedRotation::FixedRotation(const ghoul::Dictionary& dictionary) @@ -332,6 +288,9 @@ FixedRotation::FixedRotation(const ghoul::Dictionary& dictionary) } , _attachedObject(AttachedInfo, "") { + // We check the Dictionary here in order to detect the errors early + codegen::bake(dictionary); + documentation::testSpecificationAndThrow( Documentation(), dictionary, @@ -447,103 +406,79 @@ FixedRotation::FixedRotation(const ghoul::Dictionary& dictionary) bool FixedRotation::initialize() { ZoneScoped + // We have already checked this before, but still + const Parameters p = codegen::bake(_constructorDictionary); + // We need to do this in the initialize and not the constructor as the scene graph // nodes referenced in the dictionary might not exist yet at construction time. At // initialization time, however, we know that they already have been created const bool res = Rotation::initialize(); - if (_constructorDictionary.hasKey(AttachedInfo.identifier)) { - _attachedObject = _constructorDictionary.value( - AttachedInfo.identifier - ); - } + _attachedObject = p.attached.value_or(_attachedObject); - const bool hasXAxis = _constructorDictionary.hasKey(KeyXAxis); - if (hasXAxis) { - if (_constructorDictionary.hasValue(KeyXAxis)) { + if (p.xAxis.has_value()) { + if (std::holds_alternative(*p.xAxis)) { _xAxis.type = Axis::Type::Object; - _xAxis.object = _constructorDictionary.value(KeyXAxis); + _xAxis.object = std::get(*p.xAxis); } else { - // We know it has to be a vector now + ghoul_assert(std::holds_alternative(*p.xAxis), ""); _xAxis.type = Axis::Type::Vector; - _xAxis.vector = _constructorDictionary.value(KeyXAxis); + _xAxis.vector = std::get(*p.xAxis); } } - - if (_constructorDictionary.hasKey(KeyXAxisOrthogonal)) { - _xAxis.isOrthogonal = _constructorDictionary.value(KeyXAxisOrthogonal); - } - if (_constructorDictionary.hasKey(XAxisInvertObjectInfo.identifier)) { - _xAxis.invertObject = _constructorDictionary.value( - XAxisInvertObjectInfo.identifier - ); - } + _xAxis.isOrthogonal = p.xAxisOrthogonal.value_or(_xAxis.isOrthogonal); if (_xAxis.isOrthogonal) { _xAxis.type = Axis::Type::OrthogonalVector; } + _xAxis.invertObject = p.xAxisInvert.value_or(_xAxis.invertObject); - const bool hasYAxis = _constructorDictionary.hasKey(KeyYAxis); - if (hasYAxis) { - if (_constructorDictionary.hasValue(KeyYAxis)) { + if (p.yAxis.has_value()) { + if (std::holds_alternative(*p.yAxis)) { _yAxis.type = Axis::Type::Object; - _yAxis.object = _constructorDictionary.value(KeyYAxis); + _yAxis.object = std::get(*p.yAxis); } else { - // We know it has to be a vector now + ghoul_assert(std::holds_alternative(*p.yAxis), ""); _yAxis.type = Axis::Type::Vector; - _yAxis.vector = _constructorDictionary.value(KeyYAxis); + _yAxis.vector = std::get(*p.yAxis); } } - - if (_constructorDictionary.hasKey(KeyYAxisOrthogonal)) { - _yAxis.isOrthogonal = _constructorDictionary.value(KeyYAxisOrthogonal); - } - if (_constructorDictionary.hasKey(YAxisInvertObjectInfo.identifier)) { - _yAxis.invertObject = _constructorDictionary.value( - YAxisInvertObjectInfo.identifier - ); - } + _yAxis.isOrthogonal = p.yAxisOrthogonal.value_or(_yAxis.isOrthogonal); if (_yAxis.isOrthogonal) { _yAxis.type = Axis::Type::OrthogonalVector; } + _yAxis.invertObject = p.yAxisInvert.value_or(_yAxis.invertObject); - const bool hasZAxis = _constructorDictionary.hasKey(KeyZAxis); - if (hasZAxis) { - if (_constructorDictionary.hasValue(KeyZAxis)) { + if (p.zAxis.has_value()) { + if (std::holds_alternative(*p.zAxis)) { _zAxis.type = Axis::Type::Object; - _zAxis.object = _constructorDictionary.value(KeyZAxis); + _zAxis.object = std::get(*p.zAxis); } else { - // We know it has to be a vector now + ghoul_assert(std::holds_alternative(*p.zAxis), ""); _zAxis.type = Axis::Type::Vector; - _zAxis.vector = _constructorDictionary.value(KeyZAxis); + _zAxis.vector = std::get(*p.zAxis); } } - - if (_constructorDictionary.hasKey(KeyZAxisOrthogonal)) { - _zAxis.isOrthogonal = _constructorDictionary.value(KeyZAxisOrthogonal); - } - if (_constructorDictionary.hasKey(ZAxisInvertObjectInfo.identifier)) { - _yAxis.invertObject = _constructorDictionary.value( - ZAxisInvertObjectInfo.identifier - ); - } + _zAxis.isOrthogonal = p.zAxisOrthogonal.value_or(_zAxis.isOrthogonal); if (_zAxis.isOrthogonal) { _zAxis.type = Axis::Type::OrthogonalVector; } + _zAxis.invertObject = p.zAxisInvert.value_or(_zAxis.invertObject); - if (!hasXAxis && hasYAxis && hasZAxis) { + + if (!p.xAxis.has_value() && p.yAxis.has_value() && p.zAxis.has_value()) { _xAxis.type = Axis::Type::CoordinateSystemCompletion; } - if (hasXAxis && !hasYAxis && hasZAxis) { + if (p.xAxis.has_value() && !p.yAxis.has_value() && p.zAxis.has_value()) { _yAxis.type = Axis::Type::CoordinateSystemCompletion; } - if (hasXAxis && hasYAxis && !hasZAxis) { + if (p.xAxis.has_value() && p.yAxis.has_value() && !p.zAxis.has_value()) { _zAxis.type = Axis::Type::CoordinateSystemCompletion; } diff --git a/modules/base/rotation/luarotation.cpp b/modules/base/rotation/luarotation.cpp index 7feb62b165..f6f0f822a5 100644 --- a/modules/base/rotation/luarotation.cpp +++ b/modules/base/rotation/luarotation.cpp @@ -45,29 +45,20 @@ namespace { "J2000 epoch as the second argument and computes the rotation returned as 9 " "values." }; + + struct [[codegen::Dictionary(LuaRotation)]] Parameters { + // [[codegen::verbatim(ScriptInfo.description)]] + std::string script; + }; +#include "luarotation_codegen.cpp" } // namespace namespace openspace { documentation::Documentation LuaRotation::Documentation() { - using namespace openspace::documentation; - return { - "Lua Rotation", - "base_transform_rotation_lua", - { - { - "Type", - new StringEqualVerifier("LuaRotation"), - Optional::No - }, - { - ScriptInfo.identifier, - new StringVerifier, - Optional::No, - ScriptInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_transform_rotation_lua"; + return doc; } LuaRotation::LuaRotation() @@ -86,13 +77,9 @@ LuaRotation::LuaRotation() } LuaRotation::LuaRotation(const ghoul::Dictionary& dictionary) : LuaRotation() { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "LuaRotation" - ); + const Parameters p = codegen::bake(dictionary); - _luaScriptFile = absPath(dictionary.value(ScriptInfo.identifier)); + _luaScriptFile = absPath(p.script); } glm::dmat3 LuaRotation::matrix(const UpdateData& data) const { diff --git a/modules/base/rotation/staticrotation.cpp b/modules/base/rotation/staticrotation.cpp index e42acfa361..1da7e72f6f 100644 --- a/modules/base/rotation/staticrotation.cpp +++ b/modules/base/rotation/staticrotation.cpp @@ -55,34 +55,21 @@ namespace { } return res; } + + struct [[codegen::Dictionary(StaticRotation)]] Parameters { + // Stores the static rotation as a vector containing Euler angles, a quaternion + // or a rotation matrix + std::variant rotation; + }; +#include "staticrotation_codegen.cpp" } // namespace namespace openspace { documentation::Documentation StaticRotation::Documentation() { - using namespace openspace::documentation; - return { - "Static Rotation", - "base_transform_rotation_static", - { - { - "Type", - new StringEqualVerifier("StaticRotation"), - Optional::No - }, - { - RotationInfo.identifier, - new OrVerifier({ - new DoubleVector3Verifier(), - new DoubleVector4Verifier(), - new DoubleMatrix3Verifier() - }), - Optional::No, - "Stores the static rotation as a vector containing Euler angles, " - " a quaternion or a rotation matrix." - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_transform_rotation_static"; + return doc; } StaticRotation::StaticRotation() @@ -101,31 +88,21 @@ StaticRotation::StaticRotation() } StaticRotation::StaticRotation(const ghoul::Dictionary& dictionary) : StaticRotation() { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "StaticRotation" - ); + const Parameters p = codegen::bake(dictionary); - if (dictionary.hasValue(RotationInfo.identifier)) { - _eulerRotation = static_cast( - dictionary.value(RotationInfo.identifier) - ); - _matrixIsDirty = true; + if (std::holds_alternative(p.rotation)) { + _eulerRotation = std::get(p.rotation); } - else if (dictionary.hasValue(RotationInfo.identifier)) { - glm::dvec4 data = dictionary.value(RotationInfo.identifier); + else if (std::holds_alternative(p.rotation)) { + glm::dvec4 data = std::get(p.rotation); _eulerRotation = rotationMatrixToEulerAngles( glm::mat3_cast(glm::dquat(data.w, data.x, data.y, data.z)) ); - _matrixIsDirty = true; } - else if (dictionary.hasValue(RotationInfo.identifier)) { - _eulerRotation = rotationMatrixToEulerAngles( - dictionary.value(RotationInfo.identifier) - ); - _matrixIsDirty = true; + else if (std::holds_alternative(p.rotation)) { + _eulerRotation = rotationMatrixToEulerAngles(std::get(p.rotation)); } + _matrixIsDirty = true; } glm::dmat3 StaticRotation::matrix(const UpdateData&) const { diff --git a/modules/base/rotation/timelinerotation.cpp b/modules/base/rotation/timelinerotation.cpp index 46aeb0431a..39ef1dec06 100644 --- a/modules/base/rotation/timelinerotation.cpp +++ b/modules/base/rotation/timelinerotation.cpp @@ -30,7 +30,6 @@ #include namespace { - constexpr const char* KeyType = "Type"; constexpr const char* KeyKeyframes = "Keyframes"; } // namespace @@ -42,11 +41,6 @@ documentation::Documentation TimelineRotation::Documentation() { "Timeline Rotation", "base_transform_rotation_keyframe", { - { - KeyType, - new StringEqualVerifier("TimelineRotation"), - Optional::No - }, { KeyKeyframes, new TableVerifier({ diff --git a/modules/base/scale/luascale.cpp b/modules/base/scale/luascale.cpp index 204a0205f8..8ea195e15c 100644 --- a/modules/base/scale/luascale.cpp +++ b/modules/base/scale/luascale.cpp @@ -32,7 +32,6 @@ #include #include #include - #include namespace { @@ -45,24 +44,20 @@ namespace { "as the first argument, the current wall time as milliseconds past the J2000 " "epoch the second argument and computes the three scaling factors." }; + + struct [[codegen::Dictionary(LuaScale)]] Parameters { + // [[codegen::verbatim(ScriptInfo.description)]] + std::string script; + }; +#include "luascale_codegen.cpp" } // namespace namespace openspace { documentation::Documentation LuaScale::Documentation() { - using namespace openspace::documentation; - return { - "Lua Scaling", - "base_scale_lua", - { - { - ScriptInfo.identifier, - new StringVerifier, - Optional::No, - ScriptInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_scale_lua"; + return doc; } LuaScale::LuaScale() @@ -81,9 +76,8 @@ LuaScale::LuaScale() } LuaScale::LuaScale(const ghoul::Dictionary& dictionary) : LuaScale() { - documentation::testSpecificationAndThrow(Documentation(), dictionary, "LuaScale"); - - _luaScriptFile = absPath(dictionary.value(ScriptInfo.identifier)); + const Parameters p = codegen::bake(dictionary); + _luaScriptFile = absPath(p.script); } glm::dvec3 LuaScale::scaleValue(const UpdateData& data) const { diff --git a/modules/base/scale/nonuniformstaticscale.cpp b/modules/base/scale/nonuniformstaticscale.cpp index b83a3c81b5..19bc7ca349 100644 --- a/modules/base/scale/nonuniformstaticscale.cpp +++ b/modules/base/scale/nonuniformstaticscale.cpp @@ -34,24 +34,20 @@ namespace { "These values are used as scaling factors for the scene graph node that this " "transformation is attached to relative to its parent." }; + + struct [[codegen::Dictionary(NonUniformStaticScale)]] Parameters { + // [[codegen::verbatim(ScaleInfo.description)]] + glm::dvec3 scale; + }; +#include "nonuniformstaticscale_codegen.cpp" } // namespace namespace openspace { documentation::Documentation NonUniformStaticScale::Documentation() { - using namespace openspace::documentation; - return { - "Static Scaling", - "base_scale_static", - { - { - ScaleInfo.identifier, - new DoubleVector3Verifier, - Optional::No, - ScaleInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_scale_nonuniformstatic"; + return doc; } glm::dvec3 NonUniformStaticScale::scaleValue(const UpdateData&) const { @@ -71,9 +67,8 @@ NonUniformStaticScale::NonUniformStaticScale() NonUniformStaticScale::NonUniformStaticScale(const ghoul::Dictionary& dictionary) : NonUniformStaticScale() { - documentation::testSpecificationAndThrow(Documentation(), dictionary, "StaticScale"); - - _scaleValue = dictionary.value(ScaleInfo.identifier); + const Parameters p = codegen::bake(dictionary); + _scaleValue = p.scale; } } // namespace openspace diff --git a/modules/base/scale/staticscale.cpp b/modules/base/scale/staticscale.cpp index a246ab4ad9..59b5a96c57 100644 --- a/modules/base/scale/staticscale.cpp +++ b/modules/base/scale/staticscale.cpp @@ -34,24 +34,20 @@ namespace { "This value is used as a scaling factor for the scene graph node that this " "transformation is attached to relative to its parent." }; + + struct [[codegen::Dictionary(StaticScale)]] Parameters { + // [[codegen::verbatim(ScaleInfo.description)]] + float scale; + }; +#include "staticscale_codegen.cpp" } // namespace namespace openspace { documentation::Documentation StaticScale::Documentation() { - using namespace openspace::documentation; - return { - "Static Scaling", - "base_scale_static", - { - { - ScaleInfo.identifier, - new DoubleVerifier, - Optional::No, - ScaleInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_scale_static"; + return doc; } glm::dvec3 StaticScale::scaleValue(const UpdateData&) const { @@ -67,9 +63,8 @@ StaticScale::StaticScale() : _scaleValue(ScaleInfo, 1.f, 0.1f, 100.f) { } StaticScale::StaticScale(const ghoul::Dictionary& dictionary) : StaticScale() { - documentation::testSpecificationAndThrow(Documentation(), dictionary, "StaticScale"); - - _scaleValue = static_cast(dictionary.value(ScaleInfo.identifier)); + const Parameters p = codegen::bake(dictionary); + _scaleValue = p.scale; } } // namespace openspace diff --git a/modules/base/scale/timedependentscale.cpp b/modules/base/scale/timedependentscale.cpp index 255e9a3ad0..168146ef0c 100644 --- a/modules/base/scale/timedependentscale.cpp +++ b/modules/base/scale/timedependentscale.cpp @@ -28,6 +28,7 @@ #include #include #include +#include namespace { constexpr openspace::properties::Property::PropertyInfo ReferenceDateInfo = { @@ -53,36 +54,26 @@ namespace { "negative values. This is useful for instantaneous events that only propagate " "forwards. The default value is 'true'." }; + + struct [[codegen::Dictionary(TimeDependentScale)]] Parameters { + // [[codegen::verbatim(ReferenceDateInfo.description)]] + std::string referenceDate; + + // [[codegen::verbatim(SpeedInfo.description)]] + std::optional speed; + + // [[codegen::verbatim(ClampToPositiveInfo.description)]] + std::optional clampToPositive; + }; +#include "timedependentscale_codegen.cpp" } // namespace namespace openspace { documentation::Documentation TimeDependentScale::Documentation() { - using namespace openspace::documentation; - return { - "Timedependent Scaling", - "base_scale_timedependent", - { - { - ReferenceDateInfo.identifier, - new StringVerifier, - Optional::No, - ReferenceDateInfo.description - }, - { - SpeedInfo.identifier, - new DoubleVerifier, - Optional::Yes, - SpeedInfo.description - }, - { - ClampToPositiveInfo.identifier, - new BoolVerifier, - Optional::Yes, - ClampToPositiveInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_scale_timedependent"; + return doc; } TimeDependentScale::TimeDependentScale(const ghoul::Dictionary& dictionary) @@ -90,21 +81,17 @@ TimeDependentScale::TimeDependentScale(const ghoul::Dictionary& dictionary) , _speed(SpeedInfo, 1.0, 0.0, 1e12) , _clampToPositive(ClampToPositiveInfo, true) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "TimeDependentScale" - ); + const Parameters p = codegen::bake(dictionary); - _referenceDate = dictionary.value(ReferenceDateInfo.identifier); + _referenceDate = p.referenceDate; _referenceDate.onChange([this]() { _cachedReferenceDirty = true; }); addProperty(_referenceDate); - if (dictionary.value(SpeedInfo.identifier)) { - _speed = dictionary.value(SpeedInfo.identifier); - } + _speed = p.speed.value_or(_speed); addProperty(_speed); + // @TODO (abock, 2021-01-09) The clamp to positive value from the dictionary was never + // actually read. I think this should probably be done here? addProperty(_clampToPositive); } diff --git a/modules/base/shaders/disc_fs.glsl b/modules/base/shaders/disc_fs.glsl new file mode 100644 index 0000000000..839d6464f5 --- /dev/null +++ b/modules/base/shaders/disc_fs.glsl @@ -0,0 +1,58 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include "fragment.glsl" + +in vec2 vs_st; +in float vs_screenSpaceDepth; + +uniform sampler1D colorTexture; +uniform float width; +uniform float opacity; + +Fragment getFragment() { + // The length of the texture coordinates vector is our distance from the center + float radius = length(vs_st); + + // We only want to consider ring-like objects so we need to discard everything else + if (radius > 1.0) { + discard; + } + + // Remapping the texture coordinates + // Radius \in [0,1], + float inner = 1.0 - width; + float texCoord = (radius - inner) / (1.0 - inner); + if (texCoord < 0.0 || texCoord > 1.0) { + discard; + } + + vec4 diffuse = texture(colorTexture, texCoord); + diffuse.a *= opacity; + + Fragment frag; + frag.color = diffuse; + frag.depth = vs_screenSpaceDepth; + return frag; +} diff --git a/modules/base/shaders/disc_vs.glsl b/modules/base/shaders/disc_vs.glsl new file mode 100644 index 0000000000..d5796d62d9 --- /dev/null +++ b/modules/base/shaders/disc_vs.glsl @@ -0,0 +1,47 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version __CONTEXT__ + +#include "PowerScaling/powerScaling_vs.hglsl" + +layout(location = 0) in vec2 in_position; +layout(location = 1) in vec2 in_st; + +out vec2 vs_st; +out float vs_screenSpaceDepth; + +uniform mat4 modelViewProjectionTransform; + +void main() { + vec4 position = vec4(in_position.xy, 0.0, 1.0); + vec4 positionScreenSpace = z_normalization(modelViewProjectionTransform * position); + + // Moving the origin to the center + vs_st = (in_st - vec2(0.5)) * 2.0; + + vs_screenSpaceDepth = positionScreenSpace.w; + + gl_Position = positionScreenSpace; +} diff --git a/modules/base/timeframe/timeframeinterval.cpp b/modules/base/timeframe/timeframeinterval.cpp index 1d194527a8..e0a18079b2 100644 --- a/modules/base/timeframe/timeframeinterval.cpp +++ b/modules/base/timeframe/timeframeinterval.cpp @@ -28,6 +28,7 @@ #include #include #include +#include namespace { constexpr const openspace::properties::Property::PropertyInfo HasStartInfo = { @@ -53,42 +54,23 @@ namespace { "End", "Specifies the time when this TimeFrame becomes inactive" }; + + struct [[codegen::Dictionary(TimeFrameInterval)]] Parameters { + // [[codegen::verbatim(StartInfo.description)]] + std::optional> start; + + // [[codegen::verbatim(EndInfo.description)]] + std::optional> end; + }; +#include "timeframeinterval_codegen.cpp" } // namespace namespace openspace { documentation::Documentation TimeFrameInterval::Documentation() { - using namespace openspace::documentation; - return { - "Time Frame Interval", - "base_time_frame_interval", - { - { - HasStartInfo.identifier, - new BoolVerifier, - Optional::Yes, - HasStartInfo.description - }, - { - StartInfo.identifier, - new OrVerifier({ new DoubleVerifier, new StringVerifier }), - Optional::Yes, - StartInfo.description - }, - { - HasEndInfo.identifier, - new BoolVerifier, - Optional::Yes, - HasEndInfo.description - }, - { - EndInfo.identifier, - new OrVerifier({ new DoubleVerifier, new StringVerifier }), - Optional::Yes, - EndInfo.description - }, - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_time_frame_interval"; + return doc; } bool TimeFrameInterval::isActive(const Time& time) const { @@ -119,38 +101,35 @@ TimeFrameInterval::TimeFrameInterval(const ghoul::Dictionary& dictionary) , _hasEnd(HasEndInfo, false) , _end(EndInfo, 0, 0, 1E9) { + const Parameters p = codegen::bake(dictionary); + + if (p.start.has_value()) { + if (std::holds_alternative(*p.start)) { + _start = std::get(*p.start); + } + else { + _start = SpiceManager::ref().ephemerisTimeFromDate( + std::get(*p.start) + ); + } + } + _hasStart = p.start.has_value(); addProperty(_hasStart); addProperty(_start); + + if (p.end.has_value()) { + if (std::holds_alternative(*p.end)) { + _end = std::get(*p.end); + } + else { + _end = SpiceManager::ref().ephemerisTimeFromDate( + std::get(*p.end) + ); + } + } + _hasEnd = p.end.has_value(); addProperty(_hasEnd); addProperty(_end); - - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "TimeFrameInterval" - ); - - if (dictionary.hasValue(StartInfo.identifier)) { - _start = SpiceManager::ref().ephemerisTimeFromDate( - dictionary.value(StartInfo.identifier) - ); - _hasStart = true; - } - else if (dictionary.hasValue(StartInfo.identifier)) { - _start = dictionary.value(StartInfo.identifier); - _hasStart = true; - } - - if (dictionary.hasValue(EndInfo.identifier)) { - _end = SpiceManager::ref().ephemerisTimeFromDate( - dictionary.value(EndInfo.identifier) - ); - _hasEnd = true; - } - else if (dictionary.hasValue(EndInfo.identifier)) { - _end = dictionary.value(EndInfo.identifier); - _hasEnd = true; - } } } // namespace openspace diff --git a/modules/base/timeframe/timeframeunion.cpp b/modules/base/timeframe/timeframeunion.cpp index 885888db68..05f7da7028 100644 --- a/modules/base/timeframe/timeframeunion.cpp +++ b/modules/base/timeframe/timeframeunion.cpp @@ -38,30 +38,20 @@ namespace { "The time frame is active when any of the contained time frames are, " "but not in gaps between contained time frames." }; + + struct [[codegen::Dictionary(TimeFrameUnion)]] Parameters { + // [[codegen::verbatim(TimeFramesInfo.description)]] + std::vector timeFrames [[codegen::reference("core_time_frame")]]; + }; +#include "timeframeunion_codegen.cpp" } // namespace namespace openspace { documentation::Documentation TimeFrameUnion::Documentation() { - using namespace openspace::documentation; - return { - "Time Frame Union", - "base_time_frame_union", - { - { - TimeFramesInfo.identifier, - new TableVerifier({ - { - "*", - new ReferencingVerifier("core_time_frame"), - Optional::Yes - } - }), - Optional::No, - TimeFramesInfo.description - }, - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_time_frame_union"; + return doc; } bool TimeFrameUnion::isActive(const Time& time) const { @@ -76,9 +66,10 @@ bool TimeFrameUnion::isActive(const Time& time) const { TimeFrameUnion::TimeFrameUnion(const ghoul::Dictionary& dictionary) : TimeFrame() { - documentation::testSpecificationAndThrow(Documentation(), - dictionary, - "TimeFrameUnion"); + // I don't know how we can actually help the reference attribute properly. Since the + // Parameter list only contains the monostate, there is no need to actually create + // the object here + codegen::bake(dictionary); ghoul::Dictionary frames = dictionary.value(TimeFramesInfo.identifier); diff --git a/modules/base/translation/luatranslation.cpp b/modules/base/translation/luatranslation.cpp index 8268b30928..8f850d1f28 100644 --- a/modules/base/translation/luatranslation.cpp +++ b/modules/base/translation/luatranslation.cpp @@ -33,7 +33,6 @@ #include #include #include - #include namespace { @@ -46,32 +45,22 @@ namespace { "epoch as the first argument, the current wall time as milliseconds past the " "J2000 epoch as the second argument and computes the translation." }; + + struct [[codegen::Dictionary(LuaTranslation)]] Parameters { + // [[codegen::verbatim(ScriptInfo.description)]] + std::string script; + }; +#include "luatranslation_codegen.cpp" } // namespace namespace openspace { documentation::Documentation LuaTranslation::Documentation() { - using namespace documentation; - return { - "Lua Translation", - "base_transform_translation_lua", - { - { - "Type", - new StringEqualVerifier("LuaTranslation"), - Optional::No - }, - { - ScriptInfo.identifier, - new StringVerifier, - Optional::No, - ScriptInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_transform_translation_lua"; + return doc; } - LuaTranslation::LuaTranslation() : _luaScriptFile(ScriptInfo) , _state(ghoul::lua::LuaState::IncludeStandardLibrary::No) @@ -89,13 +78,8 @@ LuaTranslation::LuaTranslation() } LuaTranslation::LuaTranslation(const ghoul::Dictionary& dictionary) : LuaTranslation() { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "StaticTranslation" - ); - - _luaScriptFile = absPath(dictionary.value(ScriptInfo.identifier)); + const Parameters p = codegen::bake(dictionary); + _luaScriptFile = absPath(p.script); } glm::dvec3 LuaTranslation::position(const UpdateData& data) const { diff --git a/modules/base/translation/statictranslation.cpp b/modules/base/translation/statictranslation.cpp index 616185556d..7cdaa8cee6 100644 --- a/modules/base/translation/statictranslation.cpp +++ b/modules/base/translation/statictranslation.cpp @@ -34,32 +34,22 @@ namespace { "This value is used as a static offset (in meters) that is applied to the scene " "graph node that this transformation is attached to relative to its parent." }; + + struct [[codegen::Dictionary(StaticTranslation)]] Parameters { + // [[codegen::verbatim(PositionInfo.description)]] + glm::dvec3 position; + }; +#include "statictranslation_codegen.cpp" } // namespace namespace openspace { documentation::Documentation StaticTranslation::Documentation() { - using namespace documentation; - return { - "Static Translation", - "base_transform_translation_static", - { - { - "Type", - new StringEqualVerifier("StaticTranslation"), - Optional::No - }, - { - PositionInfo.identifier, - new DoubleVector3Verifier, - Optional::No, - PositionInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_transform_translation_static"; + return doc; } - StaticTranslation::StaticTranslation() : _position( PositionInfo, @@ -79,13 +69,8 @@ StaticTranslation::StaticTranslation() StaticTranslation::StaticTranslation(const ghoul::Dictionary& dictionary) : StaticTranslation() { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "StaticTranslation" - ); - - _position = dictionary.value(PositionInfo.identifier); + const Parameters p = codegen::bake(dictionary); + _position = p.position; } glm::dvec3 StaticTranslation::position(const UpdateData&) const { diff --git a/modules/base/translation/timelinetranslation.cpp b/modules/base/translation/timelinetranslation.cpp index 1479825ec3..fb6dafb14e 100644 --- a/modules/base/translation/timelinetranslation.cpp +++ b/modules/base/translation/timelinetranslation.cpp @@ -30,7 +30,6 @@ #include namespace { - constexpr const char* KeyType = "Type"; constexpr const char* KeyKeyframes = "Keyframes"; } // namespace @@ -42,11 +41,6 @@ documentation::Documentation TimelineTranslation::Documentation() { "Timeline Translation", "base_transform_translation_keyframe", { - { - KeyType, - new StringEqualVerifier("TimelineTranslation"), - Optional::No - }, { KeyKeyframes, new TableVerifier({ diff --git a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp index c7a0d77cc5..7ee516e26b 100644 --- a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp +++ b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp @@ -50,6 +50,7 @@ #include #include #include +#include #include namespace { @@ -65,17 +66,6 @@ namespace { "hasColorMap", "enabledRectSizeControl", "hasDvarScaling" }; - constexpr const char* KeyFile = "File"; - constexpr const char* keyColor = "Color"; - constexpr const char* keyUnit = "Unit"; - constexpr const char* MeterUnit = "m"; - constexpr const char* KilometerUnit = "Km"; - constexpr const char* ParsecUnit = "pc"; - constexpr const char* KiloparsecUnit = "Kpc"; - constexpr const char* MegaparsecUnit = "Mpc"; - constexpr const char* GigaparsecUnit = "Gpc"; - constexpr const char* GigalightyearUnit = "Gly"; - constexpr int8_t CurrentCacheVersion = 1; constexpr double PARSEC = 0.308567756E17; @@ -107,26 +97,6 @@ namespace { "The path to the color map file of the astronomical object." }; - constexpr openspace::properties::Property::PropertyInfo ExactColorMapInfo = { - "ExactColorMap", - "Exact Color Map File", - "Set a 1 to 1 relationship between the color index variable and the colormap" - " entrered value." - }; - - constexpr openspace::properties::Property::PropertyInfo ColorRangeInfo = { - "ColorRange", - "Color Range", - "This value determines the colormap ranges for the color parameters of the " - "astronomical objects." - }; - - constexpr openspace::properties::Property::PropertyInfo PolygonSidesInfo = { - "PolygonSides", - "Polygon Sides", - "The number of sides for the polygon used to represent the astronomical object." - }; - constexpr openspace::properties::Property::PropertyInfo TextColorInfo = { "TextColor", "Text Color", @@ -146,13 +116,6 @@ namespace { "The text size for the astronomical object labels." }; - constexpr openspace::properties::Property::PropertyInfo LabelFileInfo = { - "LabelFile", - "Label File", - "The path to the label file that contains information about the astronomical " - "objects being rendered." - }; - constexpr openspace::properties::Property::PropertyInfo LabelMinSizeInfo = { "TextMinSize", "Text Min Size", @@ -199,12 +162,6 @@ namespace { "of the astronomical objects." }; - constexpr openspace::properties::Property::PropertyInfo TransformationMatrixInfo = { - "TransformationMatrix", - "Transformation Matrix", - "Transformation matrix to be applied to each astronomical object." - }; - constexpr openspace::properties::Property::PropertyInfo RenderOptionInfo = { "RenderOption", "Render Option", @@ -270,180 +227,120 @@ namespace { "Set Data Range from Data", "Set the data range based on the available data" }; + + struct [[codegen::Dictionary(RenderableBillboardsCloud)]] Parameters { + // The path to the SPECK file that contains information about the astronomical + // object being rendered + std::optional file; + + // [[codegen::verbatim(ColorInfo.description)]] + glm::vec3 color; + + // [[codegen::verbatim(SpriteTextureInfo.description)]] + std::optional texture; + + // [[codegen::verbatim(DrawElementsInfo.description)]] + std::optional drawElements; + + enum class RenderOption { + ViewDirection [[codegen::key("Camera View Direction")]], + PositionNormal [[codegen::key("Camera Position Normal")]] + }; + // [[codegen::verbatim(RenderOptionInfo.description)]] + std::optional renderOption; + + enum class Unit { + Meter [[codegen::key("m")]], + Kilometer [[codegen::key("Km")]], + Parsec [[codegen::key("pc")]], + Kiloparsec [[codegen::key("Kpc")]], + Megaparsec [[codegen::key("Mpc")]], + Gigaparsec [[codegen::key("Gpc")]], + GigalightYears [[codegen::key("Gly")]] + }; + std::optional unit; + + // [[codegen::verbatim(ScaleFactorInfo.description)]] + std::optional scaleFactor; + + // [[codegen::verbatim(ColorMapInfo.description)]] + std::optional colorMap; + + // Set a 1 to 1 relationship between the color index variable and the colormap + // entrered value + std::optional exactColorMap; + + // The number of sides for the polygon used to represent the astronomical object + std::optional polygonSides; + + // [[codgen::verbatim(DrawLabelInfo.description)]] + std::optional drawLabels; + + // [[codgen::verbatim(TextColorInfo.description)]] + std::optional textColor; + + // [[codgen::verbatim(TextOpacityInfo.description)]] + std::optional textOpacity; + + // [[codgen::verbatim(TextSizeInfo.description)]] + std::optional textSize; + + // The path to the label file that contains information about the astronomical + // objects being rendered + std::optional labelFile; + + // [[codgen::verbatim(LabelMinSizeInfo.description)]] + std::optional textMinSize; + + // [[codgen::verbatim(LabelMaxSizeInfo.description)]] + std::optional textMaxSize; + + // [[codgen::verbatim(ColorOptionInfo.description)]] + std::optional> colorOption; + + // [[codgen::verbatim(SizeOptionInfo.description)]] + std::optional> sizeOption; + + // This value determines the colormap ranges for the color parameters of the + // astronomical objects + std::optional> colorRange; + + // Transformation matrix to be applied to each astronomical object + std::optional transformationMatrix; + + // [[codgen::verbatim(FadeInDistancesInfo.description)]] + std::optional fadeInDistances; + + // [[codgen::verbatim(DisableFadeInInfo.description)]] + std::optional disableFadeIn; + + // [[codgen::verbatim(BillboardMaxSizeInfo.description)]] + std::optional billboardMaxSize; + + // [[codgen::verbatim(BillboardMinSizeInfo.description)]] + std::optional billboardMinSize; + + // [[codgen::verbatim(CorrectionSizeEndDistanceInfo.description)]] + std::optional correctionSizeEndDistance; + + // [[codgen::verbatim(CorrectionSizeFactorInfo.description)]] + std::optional correctionSizeFactor; + + // [[codgen::verbatim(PixelSizeControlInfo.description)]] + std::optional enablePixelSizeControl; + + // [[codgen::verbatim(UseLinearFiltering.description)]] + std::optional useLinearFiltering; + }; +#include "renderablebillboardscloud_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableBillboardsCloud::Documentation() { - using namespace documentation; - return { - "RenderableBillboardsCloud", - "digitaluniverse_RenderableBillboardsCloud", - { - { - "Type", - new StringEqualVerifier("RenderableBillboardsCloud"), - Optional::No - }, - { - KeyFile, - new StringVerifier, - Optional::Yes, - "The path to the SPECK file that contains information about the " - "astronomical object being rendered." - }, - { - keyColor, - new DoubleVector3Verifier, - Optional::No, - "Astronomical Object Color (r,g,b)." - }, - { - SpriteTextureInfo.identifier, - new StringVerifier, - Optional::Yes, - SpriteTextureInfo.description - }, - { - ScaleFactorInfo.identifier, - new DoubleVerifier, - Optional::Yes, - ScaleFactorInfo.description - }, - { - ColorMapInfo.identifier, - new StringVerifier, - Optional::Yes, - ColorMapInfo.description - }, - { - ExactColorMapInfo.identifier, - new BoolVerifier, - Optional::Yes, - ExactColorMapInfo.description - }, - { - PolygonSidesInfo.identifier, - new IntVerifier, - Optional::Yes, - PolygonSidesInfo.description - }, - { - DrawLabelInfo.identifier, - new BoolVerifier, - Optional::Yes, - DrawLabelInfo.description - }, - { - TextColorInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - TextColorInfo.description - }, - { - TextOpacityInfo.identifier, - new DoubleVerifier, - Optional::Yes, - TextOpacityInfo.description - }, - { - TextSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - TextSizeInfo.description - }, - { - LabelFileInfo.identifier, - new StringVerifier, - Optional::Yes, - LabelFileInfo.description - }, - { - LabelMinSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LabelMinSizeInfo.description - }, - { - LabelMaxSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LabelMaxSizeInfo.description - }, - { - ColorOptionInfo.identifier, - new StringListVerifier, - Optional::Yes, - ColorOptionInfo.description - }, - { - SizeOptionInfo.identifier, - new StringListVerifier, - Optional::Yes, - SizeOptionInfo.description - }, - { - ColorRangeInfo.identifier, - new Vector2ListVerifier, - Optional::Yes, - ColorRangeInfo.description - }, - { - TransformationMatrixInfo.identifier, - new Matrix4x4Verifier, - Optional::Yes, - TransformationMatrixInfo.description - }, - { - FadeInDistancesInfo.identifier, - new Vector2Verifier, - Optional::Yes, - FadeInDistancesInfo.description - }, - { - DisableFadeInInfo.identifier, - new BoolVerifier, - Optional::Yes, - DisableFadeInInfo.description - }, - { - BillboardMaxSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - BillboardMaxSizeInfo.description - }, - { - BillboardMinSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - BillboardMinSizeInfo.description - }, - { - CorrectionSizeEndDistanceInfo.identifier, - new DoubleVerifier, - Optional::Yes, - CorrectionSizeEndDistanceInfo.description - }, - { - CorrectionSizeFactorInfo.identifier, - new DoubleVerifier, - Optional::Yes, - CorrectionSizeFactorInfo.description - }, - { - PixelSizeControlInfo.identifier, - new BoolVerifier, - Optional::Yes, - PixelSizeControlInfo.description - }, - { - UseLinearFiltering.identifier, - new BoolVerifier, - Optional::Yes, - UseLinearFiltering.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "digitaluniverse_RenderableBillboardsCloud"; + return doc; } RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& dictionary) @@ -481,98 +378,87 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di , _setRangeFromData(SetRangeFromData) , _renderOption(RenderOptionInfo, properties::OptionProperty::DisplayType::Dropdown) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableBillboardsCloud" - ); + const Parameters p = codegen::bake(dictionary); - if (dictionary.hasKey(KeyFile)) { - _speckFile = absPath(dictionary.value(KeyFile)); - _hasSpeckFile = true; - } - - if (dictionary.hasKey(DrawElementsInfo.identifier)) { - _drawElements = dictionary.value(DrawElementsInfo.identifier); + if (p.file.has_value()) { + _speckFile = absPath(*p.file); } + _hasSpeckFile = p.file.has_value(); + _drawElements = p.drawElements.value_or(_drawElements); _drawElements.onChange([&]() { _hasSpeckFile = !_hasSpeckFile; }); addProperty(_drawElements); _renderOption.addOption(RenderOptionViewDirection, "Camera View Direction"); _renderOption.addOption(RenderOptionPositionNormal, "Camera Position Normal"); - _renderOption = RenderOptionViewDirection; - if (dictionary.hasValue(RenderOptionInfo.identifier)) { - const std::string o = dictionary.value(RenderOptionInfo.identifier); - - if (o == "Camera View Direction") { - _renderOption = RenderOptionViewDirection; - } - else if (o == "Camera Position Normal") { - _renderOption = RenderOptionPositionNormal; + if (p.renderOption.has_value()) { + switch (*p.renderOption) { + case Parameters::RenderOption::ViewDirection: + _renderOption = RenderOptionViewDirection; + break; + case Parameters::RenderOption::PositionNormal: + _renderOption = RenderOptionPositionNormal; + break; } } - + else { + _renderOption = RenderOptionViewDirection; + } addProperty(_renderOption); - if (dictionary.hasKey(keyUnit)) { - std::string unit = dictionary.value(keyUnit); - if (unit == MeterUnit) { - _unit = Meter; - } - else if (unit == KilometerUnit) { - _unit = Kilometer; - } - else if (unit == ParsecUnit) { - _unit = Parsec; - } - else if (unit == KiloparsecUnit) { - _unit = Kiloparsec; - } - else if (unit == MegaparsecUnit) { - _unit = Megaparsec; - } - else if (unit == GigaparsecUnit) { - _unit = Gigaparsec; - } - else if (unit == GigalightyearUnit) { - _unit = GigalightYears; - } - else { - LWARNING( - "No unit given for RenderableBillboardsCloud. Using meters as units." - ); - _unit = Meter; + if (p.unit.has_value()) { + switch (*p.unit) { + case Parameters::Unit::Meter: + _unit = Meter; + break; + case Parameters::Unit::Kilometer: + _unit = Kilometer; + break; + case Parameters::Unit::Parsec: + _unit = Parsec; + break; + case Parameters::Unit::Kiloparsec: + _unit = Kiloparsec; + break; + case Parameters::Unit::Megaparsec: + _unit = Megaparsec; + break; + case Parameters::Unit::Gigaparsec: + _unit = Gigaparsec; + break; + case Parameters::Unit::GigalightYears: + _unit = GigalightYears; + break; } } + else { + LWARNING("No unit given for RenderableBillboardsCloud. Using meters as units."); + _unit = Meter; + } - if (dictionary.hasKey(SpriteTextureInfo.identifier)) { - _spriteTexturePath = absPath(dictionary.value( - SpriteTextureInfo.identifier - )); - + if (p.texture.has_value()) { + _spriteTexturePath = absPath(*p.texture); _spriteTexturePath.onChange([&]() { _spriteTextureIsDirty = true; }); + + // @TODO (abock, 2021-01-31) I don't know why we only add this property if the + // texture is given, but I think it's a bug addProperty(_spriteTexturePath); - _hasSpriteTexture = true; } + _hasSpriteTexture = p.texture.has_value(); - if (dictionary.hasKey(ColorMapInfo.identifier)) { - _colorMapFile = absPath(dictionary.value(ColorMapInfo.identifier)); + + if (p.colorMap.has_value()) { + _colorMapFile = absPath(*p.colorMap); _hasColorMapFile = true; - if (dictionary.hasKey(ColorOptionInfo.identifier)) { - ghoul::Dictionary colorOptionDataDic = dictionary.value( - ColorOptionInfo.identifier - ); - for (int i = 0; i < static_cast(colorOptionDataDic.size()); ++i) { - std::string colorMapInUseName( - colorOptionDataDic.value(std::to_string(i + 1)) - ); - _colorOption.addOption(i, colorMapInUseName); - _optionConversionMap.insert({ i, colorMapInUseName }); - _colorOptionString = colorMapInUseName; + if (p.colorOption.has_value()) { + std::vector opts = *p.colorOption; + for (size_t i = 0; i < opts.size(); ++i) { + _colorOption.addOption(static_cast(i), opts[i]); + _optionConversionMap.insert({ static_cast(i), opts[i] }); + _colorOptionString = opts[i]; } } _colorOption.onChange([&]() { @@ -583,15 +469,8 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di }); addProperty(_colorOption); - if (dictionary.hasKey(ColorRangeInfo.identifier)) { - ghoul::Dictionary rangeDataDict = dictionary.value( - ColorRangeInfo.identifier - ); - for (size_t i = 0; i < rangeDataDict.size(); ++i) { - _colorRangeData.push_back( - rangeDataDict.value(std::to_string(i + 1)) - ); - } + _colorRangeData = p.colorRange.value_or(_colorRangeData); + if (!_colorRangeData.empty()) { _optionColorRangeData = _colorRangeData[_colorRangeData.size() - 1]; } _optionColorRangeData.onChange([&]() { @@ -601,36 +480,25 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di }); addProperty(_optionColorRangeData); - if (dictionary.hasKey(ExactColorMapInfo.identifier)) { - _isColorMapExact = dictionary.value(ExactColorMapInfo.identifier); - } + _isColorMapExact = p.exactColorMap.value_or(_isColorMapExact); } - else if (dictionary.hasKey(keyColor)) { - _pointColor = dictionary.value(keyColor); + else { + _pointColor = p.color; _pointColor.setViewOption(properties::Property::ViewOptions::Color); addProperty(_pointColor); } addProperty(_opacity); - if (dictionary.hasKey(ScaleFactorInfo.identifier)) { - _scaleFactor = static_cast( - dictionary.value(ScaleFactorInfo.identifier) - ); - } + _scaleFactor = p.scaleFactor.value_or(_scaleFactor); addProperty(_scaleFactor); - if (dictionary.hasKey(SizeOptionInfo.identifier)) { - ghoul::Dictionary sizeOptionDataDic = dictionary.value( - SizeOptionInfo.identifier - ); - for (int i = 0; i < static_cast(sizeOptionDataDic.size()); ++i) { - std::string datavarSizeInUseName( - sizeOptionDataDic.value(std::to_string(i + 1)) - ); - _datavarSizeOption.addOption(i, datavarSizeInUseName); - _optionConversionSizeMap.insert({ i, datavarSizeInUseName }); - _datavarSizeOptionString = datavarSizeInUseName; + if (p.sizeOption.has_value()) { + std::vector opts = *p.sizeOption; + for (size_t i = 0; i < opts.size(); ++i) { + _datavarSizeOption.addOption(static_cast(i), opts[i]); + _optionConversionSizeMap.insert({ static_cast(i), opts[i] }); + _datavarSizeOptionString = opts[i]; } _datavarSizeOption.onChange([&]() { @@ -642,104 +510,62 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di _hasDatavarSize = true; } - if (dictionary.hasKey(PolygonSidesInfo.identifier)) { - _polygonSides = static_cast( - dictionary.value(PolygonSidesInfo.identifier) - ); - _hasPolygon = true; - } + _polygonSides = p.polygonSides.value_or(_polygonSides); + _hasPolygon = p.polygonSides.has_value(); - if (dictionary.hasKey(LabelFileInfo.identifier)) { - if (dictionary.hasKey(DrawLabelInfo.identifier)) { - _drawLabels = dictionary.value(DrawLabelInfo.identifier); - } + if (p.labelFile.has_value()) { + _drawLabels = p.drawLabels.value_or(_drawLabels); addProperty(_drawLabels); - _labelFile = absPath(dictionary.value(LabelFileInfo.identifier)); + _labelFile = absPath(*p.labelFile); _hasLabel = true; - if (dictionary.hasKey(TextColorInfo.identifier)) { - _textColor = dictionary.value(TextColorInfo.identifier); - _hasLabel = true; - } + _textColor = p.textColor.value_or(_textColor); + _hasLabel = p.textColor.has_value(); _textColor.setViewOption(properties::Property::ViewOptions::Color); addProperty(_textColor); _textColor.onChange([&]() { _textColorIsDirty = true; }); - if (dictionary.hasKey(TextOpacityInfo.identifier)) { - _textOpacity = static_cast( - dictionary.value(TextOpacityInfo.identifier) - ); - } + _textOpacity = p.textOpacity.value_or(_textOpacity); addProperty(_textOpacity); - if (dictionary.hasKey(TextSizeInfo.identifier)) { - _textSize = static_cast( - dictionary.value(TextSizeInfo.identifier) - ); - } + _textSize = p.textSize.value_or(_textSize); addProperty(_textSize); - if (dictionary.hasKey(LabelMinSizeInfo.identifier)) { - _textMinSize = static_cast( - dictionary.value(LabelMinSizeInfo.identifier) - ); - } + _textMinSize = p.textMinSize.value_or(_textMinSize); addProperty(_textMinSize); - if (dictionary.hasKey(LabelMaxSizeInfo.identifier)) { - _textMaxSize = static_cast( - dictionary.value(LabelMaxSizeInfo.identifier) - ); - } + _textMaxSize = p.textMaxSize.value_or(_textMaxSize); addProperty(_textMaxSize); } - if (dictionary.hasKey(TransformationMatrixInfo.identifier)) { - _transformationMatrix = dictionary.value( - TransformationMatrixInfo.identifier - ); - } + _transformationMatrix = p.transformationMatrix.value_or(_transformationMatrix); - if (dictionary.hasKey(FadeInDistancesInfo.identifier)) { - glm::dvec2 v = dictionary.value(FadeInDistancesInfo.identifier); - _fadeInDistance = v; - _disableFadeInDistance = false; + if (p.fadeInDistances.has_value()) { + _fadeInDistance = *p.fadeInDistances; addProperty(_fadeInDistance); + + _disableFadeInDistance = false; addProperty(_disableFadeInDistance); } - if (dictionary.hasKey(BillboardMaxSizeInfo.identifier)) { - _billboardMaxSize = static_cast( - dictionary.value(BillboardMaxSizeInfo.identifier) - ); - } + _billboardMaxSize = p.billboardMaxSize.value_or(_billboardMaxSize); addProperty(_billboardMaxSize); - if (dictionary.hasKey(BillboardMinSizeInfo.identifier)) { - _billboardMinSize = static_cast( - dictionary.value(BillboardMinSizeInfo.identifier) - ); - } + _billboardMinSize = p.billboardMinSize.value_or(_billboardMinSize); addProperty(_billboardMinSize); - if (dictionary.hasKey(CorrectionSizeEndDistanceInfo.identifier)) { - _correctionSizeEndDistance = static_cast( - dictionary.value(CorrectionSizeEndDistanceInfo.identifier) - ); - } + _correctionSizeEndDistance = + p.correctionSizeEndDistance.value_or(_correctionSizeEndDistance); addProperty(_correctionSizeEndDistance); - if (dictionary.hasKey(CorrectionSizeFactorInfo.identifier)) { - _correctionSizeFactor = static_cast( - dictionary.value(CorrectionSizeFactorInfo.identifier) - ); - + _correctionSizeFactor = p.correctionSizeFactor.value_or(_correctionSizeFactor); + if (p.correctionSizeFactor.has_value()) { addProperty(_correctionSizeFactor); } - if (dictionary.hasKey(PixelSizeControlInfo.identifier)) { - _pixelSizeControl = dictionary.value(PixelSizeControlInfo.identifier); + _pixelSizeControl = p.enablePixelSizeControl.value_or(_pixelSizeControl); + if (p.enablePixelSizeControl.has_value()) { addProperty(_pixelSizeControl); } @@ -759,9 +585,7 @@ RenderableBillboardsCloud::RenderableBillboardsCloud(const ghoul::Dictionary& di }); addProperty(_setRangeFromData); - if (dictionary.hasKey(UseLinearFiltering.identifier)) { - _useLinearFiltering = dictionary.value(UseLinearFiltering.identifier); - } + _useLinearFiltering = p.useLinearFiltering.value_or(_useLinearFiltering); _useLinearFiltering.onChange([&]() { _dataIsDirty = true; }); addProperty(_useLinearFiltering); } diff --git a/modules/digitaluniverse/rendering/renderabledumeshes.cpp b/modules/digitaluniverse/rendering/renderabledumeshes.cpp index f18785a193..64b6dbc467 100644 --- a/modules/digitaluniverse/rendering/renderabledumeshes.cpp +++ b/modules/digitaluniverse/rendering/renderabledumeshes.cpp @@ -43,8 +43,9 @@ #include #include #include -#include #include +#include +#include namespace { constexpr const char* _loggerCat = "RenderableDUMeshes"; @@ -54,16 +55,6 @@ namespace { "modelViewTransform", "projectionTransform", "alphaValue", "color" }; - constexpr const char* KeyFile = "File"; - constexpr const char* keyUnit = "Unit"; - constexpr const char* MeterUnit = "m"; - constexpr const char* KilometerUnit = "Km"; - constexpr const char* ParsecUnit = "pc"; - constexpr const char* KiloparsecUnit = "Kpc"; - constexpr const char* MegaparsecUnit = "Mpc"; - constexpr const char* GigaparsecUnit = "Gpc"; - constexpr const char* GigalightyearUnit = "Gly"; - constexpr const int RenderOptionViewDirection = 0; constexpr const int RenderOptionPositionNormal = 1; @@ -139,84 +130,59 @@ namespace { "Render Option", "Debug option for rendering of billboards and texts." }; + + struct [[codegen::Dictionary(RenderableDUMeshes)]] Parameters { + // The path to the SPECK file that contains information about the astronomical + // object being rendered + std::string file; + + // [[codegen::verbatim(DrawLabelInfo.description)]] + std::optional drawLabels; + + enum class Unit { + Meter [[codegen::key("m")]], + Kilometer [[codegen::key("Km")]], + Parsec [[codegen::key("pc")]], + Kiloparsec [[codegen::key("Kpc")]], + MegaParsec [[codegen::key("Mpc")]], + Gigaparsec [[codegen::key("Gpc")]], + Gigalightyears [[codegen::key("Gly")]] + }; + std::optional unit; + + // [[codegen::verbatim(TextColorInfo.description)]] + std::optional textColor; + + // [[codegen::verbatim(TextOpacityInfo.description)]] + std::optional textOpacity; + + // [[codegen::verbatim(TextSizeInfo.description)]] + std::optional textSize; + + // [[codegen::verbatim(LabelFileInfo.description)]] + std::optional labelFile; + + // [[codegen::verbatim(LabelMinSizeInfo.description)]] + std::optional textMinSize; + + // [[codegen::verbatim(LabelMaxSizeInfo.description)]] + std::optional textMaxSize; + + // [[codegen::verbatim(LineWidthInfo.description)]] + std::optional lineWidth; + + // [[codegen::verbatim(MeshColorInfo.description)]] + std::optional> meshColor; + }; +#include "renderabledumeshes_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableDUMeshes::Documentation() { - using namespace documentation; - return { - "RenderableDUMeshes", - "digitaluniverse_renderabledumeshes", - { - { - "Type", - new StringEqualVerifier("RenderableDUMeshes"), - Optional::No - }, - { - KeyFile, - new StringVerifier, - Optional::No, - "The path to the SPECK file that contains information about the " - "astronomical object being rendered." - }, - { - DrawLabelInfo.identifier, - new BoolVerifier, - Optional::Yes, - DrawLabelInfo.description - }, - { - TextColorInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - TextColorInfo.description - }, - { - TextOpacityInfo.identifier, - new DoubleVerifier, - Optional::Yes, - TextOpacityInfo.description - }, - { - TextSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - TextSizeInfo.description - }, - { - LabelFileInfo.identifier, - new StringVerifier, - Optional::Yes, - LabelFileInfo.description - }, - { - LabelMinSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LabelMinSizeInfo.description - }, - { - LabelMaxSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LabelMaxSizeInfo.description - }, - { - LineWidthInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LineWidthInfo.description - }, - { - MeshColorInfo.identifier, - new Vector3ListVerifier, - Optional::No, - MeshColorInfo.description - }, - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "digitaluniverse_renderabledumeshes"; + return doc; } RenderableDUMeshes::RenderableDUMeshes(const ghoul::Dictionary& dictionary) @@ -231,24 +197,20 @@ RenderableDUMeshes::RenderableDUMeshes(const ghoul::Dictionary& dictionary) , _lineWidth(LineWidthInfo, 2.f, 0.f, 16.f) , _renderOption(RenderOptionInfo, properties::OptionProperty::DisplayType::Dropdown) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableDUMeshes" - ); + const Parameters p = codegen::bake(dictionary); addProperty(_opacity); registerUpdateRenderBinFromOpacity(); - if (dictionary.hasKey(KeyFile)) { - _speckFile = absPath(dictionary.value(KeyFile)); - _hasSpeckFile = true; - _drawElements.onChange([&]() { _hasSpeckFile = !_hasSpeckFile; }); - addProperty(_drawElements); - } + _speckFile = absPath(p.file); + _hasSpeckFile = true; + _drawElements.onChange([&]() { _hasSpeckFile = !_hasSpeckFile; }); + addProperty(_drawElements); _renderOption.addOption(RenderOptionViewDirection, "Camera View Direction"); _renderOption.addOption(RenderOptionPositionNormal, "Camera Position Normal"); + // @TODO (abock. 2021-01-31) In the other DU classes, this is done with an enum, and + // doing it based on the fisheye rendering seems a bit brittle? if (global::windowDelegate->isFisheyeRendering()) { _renderOption = RenderOptionPositionNormal; } @@ -257,96 +219,69 @@ RenderableDUMeshes::RenderableDUMeshes(const ghoul::Dictionary& dictionary) } addProperty(_renderOption); - if (dictionary.hasKey(keyUnit)) { - std::string unit = dictionary.value(keyUnit); - if (unit == MeterUnit) { - _unit = Meter; - } - else if (unit == KilometerUnit) { - _unit = Kilometer; - } - else if (unit == ParsecUnit) { - _unit = Parsec; - } - else if (unit == KiloparsecUnit) { - _unit = Kiloparsec; - } - else if (unit == MegaparsecUnit) { - _unit = Megaparsec; - } - else if (unit == GigaparsecUnit) { - _unit = Gigaparsec; - } - else if (unit == GigalightyearUnit) { - _unit = GigalightYears; - } - else { - LWARNING("No unit given for RenderableDUMeshes. Using meters as units."); - _unit = Meter; + if (p.unit.has_value()) { + switch (*p.unit) { + case Parameters::Unit::Meter: + _unit = Meter; + break; + case Parameters::Unit::Kilometer: + _unit = Kilometer; + break; + case Parameters::Unit::Parsec: + _unit = Parsec; + break; + case Parameters::Unit::Kiloparsec: + _unit = Kiloparsec; + break; + case Parameters::Unit::MegaParsec: + _unit = Megaparsec; + break; + case Parameters::Unit::Gigaparsec: + _unit = Gigaparsec; + break; + case Parameters::Unit::Gigalightyears: + _unit = GigalightYears; + break; } } + else { + LWARNING("No unit given for RenderableDUMeshes. Using meters as units."); + _unit = Meter; + } - if (dictionary.hasValue(LineWidthInfo.identifier)) { - _lineWidth = static_cast( - dictionary.value(LineWidthInfo.identifier) - ); - } + _lineWidth = p.lineWidth.value_or(_lineWidth); addProperty(_lineWidth); - if (dictionary.hasKey(DrawLabelInfo.identifier)) { - _drawLabels = dictionary.value(DrawLabelInfo.identifier); - } + _drawLabels = p.drawLabels.value_or(_drawLabels); addProperty(_drawLabels); - if (dictionary.hasKey(LabelFileInfo.identifier)) { - _labelFile = absPath(dictionary.value(LabelFileInfo.identifier)); + if (p.labelFile.has_value()) { + _labelFile = absPath(*p.labelFile); _hasLabel = true; - if (dictionary.hasKey(TextColorInfo.identifier)) { - _textColor = dictionary.value(TextColorInfo.identifier); - _hasLabel = true; - } + _textColor = p.textColor.value_or(_textColor); + _hasLabel = p.textColor.has_value(); _textColor.setViewOption(properties::Property::ViewOptions::Color); addProperty(_textColor); _textColor.onChange([&]() { _textColorIsDirty = true; }); - if (dictionary.hasKey(TextOpacityInfo.identifier)) { - _textOpacity = static_cast( - dictionary.value(TextOpacityInfo.identifier) - ); - } + _textOpacity = p.textOpacity.value_or(_textOpacity); addProperty(_textOpacity); - if (dictionary.hasKey(TextSizeInfo.identifier)) { - _textSize = static_cast( - dictionary.value(TextSizeInfo.identifier) - ); - } + _textSize = p.textSize.value_or(_textSize); addProperty(_textSize); - if (dictionary.hasKey(LabelMinSizeInfo.identifier)) { - _textMinSize = static_cast( - floor(dictionary.value(LabelMinSizeInfo.identifier)) - ); - } + _textMinSize = p.textMinSize.value_or(_textMinSize); addProperty(_textMinSize); - if (dictionary.hasKey(LabelMaxSizeInfo.identifier)) { - _textMaxSize = static_cast( - floor(dictionary.value(LabelMaxSizeInfo.identifier)) - ); - } + _textMaxSize = p.textMaxSize.value_or(_textMaxSize); addProperty(_textMaxSize); } - if (dictionary.hasKey(MeshColorInfo.identifier)) { - ghoul::Dictionary colorDict = dictionary.value( - MeshColorInfo.identifier - ); - for (int i = 0; i < static_cast(colorDict.size()); ++i) { - _meshColorMap.insert( - { i + 1, colorDict.value(std::to_string(i + 1)) } - ); + if (p.meshColor.has_value()) { + std::vector ops = *p.meshColor; + for (size_t i = 0; i < ops.size(); ++i) { + _meshColorMap.insert({ static_cast(i) + 1, ops[i] }); } } } diff --git a/modules/digitaluniverse/rendering/renderableplanescloud.cpp b/modules/digitaluniverse/rendering/renderableplanescloud.cpp index 71d7dc33bf..97f27b3264 100644 --- a/modules/digitaluniverse/rendering/renderableplanescloud.cpp +++ b/modules/digitaluniverse/rendering/renderableplanescloud.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include namespace { @@ -52,16 +53,6 @@ namespace { "modelViewProjectionTransform", "alphaValue", "fadeInValue", "galaxyTexture" }; - constexpr const char* KeyFile = "File"; - constexpr const char* keyUnit = "Unit"; - constexpr const char* MeterUnit = "m"; - constexpr const char* KilometerUnit = "Km"; - constexpr const char* ParsecUnit = "pc"; - constexpr const char* KiloparsecUnit = "Kpc"; - constexpr const char* MegaparsecUnit = "Mpc"; - constexpr const char* GigaparsecUnit = "Gpc"; - constexpr const char* GigalightyearUnit = "Gly"; - constexpr int8_t CurrentCacheVersion = 2; constexpr double PARSEC = 0.308567756E17; @@ -180,123 +171,83 @@ namespace { "object." }; + struct [[codegen::Dictionary(RenderablePlanesCloud)]] Parameters { + // The path to the SPECK file that contains information about the astronomical + // object being rendered + std::optional file; + + // [[codegen::verbatim(ScaleFactorInfo.description)]] + std::optional scaleFactor; + + // [[codegen::verbatim(TextColorInfo.description)]] + std::optional textColor; + + // [[codegen::verbatim(TextOpacityInfo.description)]] + std::optional textOpacity; + + // [[codegen::verbatim(TextSizeInfo.description)]] + std::optional textSize; + + // [[codegen::verbatim(LabelFileInfo.description)]] + std::optional labelFile; + + // [[codegen::verbatim(LabelMinSizeInfo.description)]] + std::optional textMinSize; + + // [[codegen::verbatim(LabelMaxSizeInfo.description)]] + std::optional textMaxSize; + + // [[codegen::verbatim(TransformationMatrixInfo.description)]] + std::optional transformationMatrix; + + enum class BlendMode { + Normal, + Additive + }; + + // [[codegen::verbatim(BlendModeInfo.description)]] + std::optional blendMode; + + enum class Unit { + Meter [[codegen::key("m")]], + Kilometer [[codegen::key("Km")]], + Parsec [[codegen::key("pc")]], + Kiloparsec [[codegen::key("Kpc")]], + Megaparsec [[codegen::key("Mpc")]], + Gigaparsec [[codegen::key("Gpc")]], + Gigalightyears [[codegen::key("Gly")]] + }; + std::optional unit; + + // [[codegen::verbatim(TexturePathInfo.description)]] + std::string texturePath; + + // [[codegen::verbatim(LuminosityInfo.description)]] + std::optional luminosity; + + // [[codegen::verbatim(ScaleLuminosityInfo.description)]] + std::optional scaleLuminosity; + + // [[codegen::verbatim(FadeInDistancesInfo.description)]] + std::optional fadeInDistances; + + // [[codegen::verbatim(DisableFadeInInfo.description)]] + std::optional disableFadeIn; + + // [[codegen::verbatim(PlaneMinSizeInfo.description)]] + std::optional planeMinSize; + }; +#include "renderableplanescloud_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderablePlanesCloud::Documentation() { - using namespace documentation; - return { - "RenderablePlanesCloud", - "digitaluniverse_RenderablePlanesCloud", - { - { - "Type", - new StringEqualVerifier("RenderablePlanesCloud"), - Optional::No - }, - { - KeyFile, - new StringVerifier, - Optional::Yes, - "The path to the SPECK file that contains information about the " - "astronomical object being rendered." - }, - { - ScaleFactorInfo.identifier, - new DoubleVerifier, - Optional::Yes, - ScaleFactorInfo.description - }, - { - TextColorInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - TextColorInfo.description - }, - { - TextOpacityInfo.identifier, - new DoubleVerifier, - Optional::Yes, - TextOpacityInfo.description - }, - { - TextSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - TextSizeInfo.description - }, - { - LabelFileInfo.identifier, - new StringVerifier, - Optional::Yes, - LabelFileInfo.description - }, - { - LabelMinSizeInfo.identifier, - new IntVerifier, - Optional::Yes, - LabelMinSizeInfo.description - }, - { - LabelMaxSizeInfo.identifier, - new IntVerifier, - Optional::Yes, - LabelMaxSizeInfo.description - }, - { - TransformationMatrixInfo.identifier, - new Matrix4x4Verifier, - Optional::Yes, - TransformationMatrixInfo.description - }, - { - BlendModeInfo.identifier, - new StringInListVerifier({ "Normal", "Additive" }), - Optional::Yes, - BlendModeInfo.description, // + " The default value is 'Normal'.", - }, - { - TexturePathInfo.identifier, - new StringVerifier, - Optional::No, - TexturePathInfo.description, - }, - { - LuminosityInfo.identifier, - new StringVerifier, - Optional::Yes, - LuminosityInfo.description, - }, - { - ScaleFactorInfo.identifier, - new DoubleVerifier, - Optional::Yes, - ScaleFactorInfo.description, - }, - { - FadeInDistancesInfo.identifier, - new DoubleVector2Verifier, - Optional::Yes, - FadeInDistancesInfo.description - }, - { - DisableFadeInInfo.identifier, - new BoolVerifier, - Optional::Yes, - DisableFadeInInfo.description - }, - { - PlaneMinSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - PlaneMinSizeInfo.description - }, - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "digitaluniverse_RenderablePlanesCloud"; + return doc; } - RenderablePlanesCloud::RenderablePlanesCloud(const ghoul::Dictionary& dictionary) : Renderable(dictionary) , _scaleFactor(ScaleFactorInfo, 1.f, 0.f, 300000.f) @@ -315,16 +266,12 @@ RenderablePlanesCloud::RenderablePlanesCloud(const ghoul::Dictionary& dictionary , _planeMinSize(PlaneMinSizeInfo, 0.5, 0.0, 500.0) , _renderOption(RenderOptionInfo, properties::OptionProperty::DisplayType::Dropdown) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderablePlanesCloud" - ); + const Parameters p = codegen::bake(dictionary); addProperty(_opacity); - if (dictionary.hasKey(KeyFile)) { - _speckFile = absPath(dictionary.value(KeyFile)); + if (p.file.has_value()) { + _speckFile = absPath(*p.file); _hasSpeckFile = true; _drawElements.onChange([&]() { _hasSpeckFile = !_hasSpeckFile; }); addProperty(_drawElements); @@ -337,32 +284,29 @@ RenderablePlanesCloud::RenderablePlanesCloud(const ghoul::Dictionary& dictionary addProperty(_renderOption); //_renderOption.set(1); - if (dictionary.hasKey(keyUnit)) { - const std::string& unit = dictionary.value(keyUnit); - if (unit == MeterUnit) { - _unit = Meter; - } - else if (unit == KilometerUnit) { - _unit = Kilometer; - } - else if (unit == ParsecUnit) { - _unit = Parsec; - } - else if (unit == KiloparsecUnit) { - _unit = Kiloparsec; - } - else if (unit == MegaparsecUnit) { - _unit = Megaparsec; - } - else if (unit == GigaparsecUnit) { - _unit = Gigaparsec; - } - else if (unit == GigalightyearUnit) { - _unit = GigalightYears; - } - else { - LWARNING("No unit given for RenderablePlanesCloud. Using meters as units."); - _unit = Meter; + if (p.unit.has_value()) { + switch (*p.unit) { + case Parameters::Unit::Meter: + _unit = Meter; + break; + case Parameters::Unit::Kilometer: + _unit = Kilometer; + break; + case Parameters::Unit::Parsec: + _unit = Parsec; + break; + case Parameters::Unit::Kiloparsec: + _unit = Kiloparsec; + break; + case Parameters::Unit::Megaparsec: + _unit = Megaparsec; + break; + case Parameters::Unit::Gigaparsec: + _unit = Gigaparsec; + break; + case Parameters::Unit::Gigalightyears: + _unit = GigalightYears; + break; } } else { @@ -370,60 +314,30 @@ RenderablePlanesCloud::RenderablePlanesCloud(const ghoul::Dictionary& dictionary _unit = Meter; } - if (dictionary.hasKey(ScaleFactorInfo.identifier)) { - _scaleFactor = static_cast( - dictionary.value(ScaleFactorInfo.identifier) - ); - } + _scaleFactor = p.scaleFactor.value_or(_scaleFactor); addProperty(_scaleFactor); - _scaleFactor.onChange([&]() { - _dataIsDirty = true; - }); + _scaleFactor.onChange([&]() { _dataIsDirty = true; }); - if (dictionary.hasKey(LabelFileInfo.identifier)) { - _labelFile = absPath(dictionary.value(LabelFileInfo.identifier)); + if (p.labelFile.has_value()) { + _labelFile = absPath(*p.labelFile); _hasLabel = true; - if (dictionary.hasKey(TextColorInfo.identifier)) { - _textColor = dictionary.value(TextColorInfo.identifier); - _hasLabel = true; - } + _textColor = p.textColor.value_or(_textColor); _textColor.setViewOption(properties::Property::ViewOptions::Color); addProperty(_textColor); _textColor.onChange([&]() { _textColorIsDirty = true; }); - if (dictionary.hasKey(TextOpacityInfo.identifier)) { - _textOpacity = static_cast( - dictionary.value(TextOpacityInfo.identifier) - ); - } + _textOpacity = p.textOpacity.value_or(_textOpacity); addProperty(_textOpacity); - if (dictionary.hasKey(TextSizeInfo.identifier)) { - _textSize = static_cast( - dictionary.value(TextSizeInfo.identifier) - ); - } + _textSize = p.textSize.value_or(_textSize); addProperty(_textSize); - if (dictionary.hasKey(LabelMinSizeInfo.identifier)) { - _textMinSize = static_cast( - dictionary.value(LabelMinSizeInfo.identifier) - ); - } - - if (dictionary.hasKey(LabelMaxSizeInfo.identifier)) { - _textMaxSize = static_cast( - dictionary.value(LabelMaxSizeInfo.identifier) - ); - } + _textMinSize = p.textMinSize.value_or(_textMinSize); + _textMaxSize = p.textMaxSize.value_or(_textMaxSize); } - if (dictionary.hasKey(TransformationMatrixInfo.identifier)) { - _transformationMatrix = dictionary.value( - TransformationMatrixInfo.identifier - ); - } + _transformationMatrix = p.transformationMatrix.value_or(_transformationMatrix); _blendMode.addOptions({ { BlendModeNormal, "Normal" }, @@ -442,39 +356,33 @@ RenderablePlanesCloud::RenderablePlanesCloud(const ghoul::Dictionary& dictionary } }); - if (dictionary.hasKey(BlendModeInfo.identifier)) { - const std::string& v = dictionary.value(BlendModeInfo.identifier); - if (v == "Normal") { - _blendMode = BlendModeNormal; - } - else if (v == "Additive") { - _blendMode = BlendModeAdditive; + if (p.blendMode.has_value()) { + switch (*p.blendMode) { + case Parameters::BlendMode::Normal: + _blendMode = BlendModeNormal; + break; + case Parameters::BlendMode::Additive: + _blendMode = BlendModeAdditive; + break; } } - _texturesPath = absPath(dictionary.value(TexturePathInfo.identifier)); + _texturesPath = absPath(p.texturePath); - if (dictionary.hasKey(LuminosityInfo.identifier)) { - _luminosityVar = dictionary.value(LuminosityInfo.identifier); - } + _luminosityVar = p.luminosity.value_or(_luminosityVar); + _sluminosity = p.scaleLuminosity.value_or(_sluminosity); - if (dictionary.hasKey(ScaleLuminosityInfo.identifier)) { - _sluminosity = static_cast( - dictionary.value(ScaleLuminosityInfo.identifier) - ); - } - if (dictionary.hasKey(FadeInDistancesInfo.identifier)) { - _fadeInDistance = dictionary.value(FadeInDistancesInfo.identifier); + if (p.fadeInDistances.has_value()) { + _fadeInDistance = *p.fadeInDistances; _disableFadeInDistance = false; addProperty(_fadeInDistance); addProperty(_disableFadeInDistance); } - if (dictionary.hasKey(PlaneMinSizeInfo.identifier)) { - _planeMinSize = static_cast( - dictionary.value(PlaneMinSizeInfo.identifier) - ); + _planeMinSize = p.planeMinSize.value_or(_planeMinSize); + + if (p.planeMinSize.has_value()) { addProperty(_planeMinSize); } } diff --git a/modules/digitaluniverse/rendering/renderablepoints.cpp b/modules/digitaluniverse/rendering/renderablepoints.cpp index cb9332404b..e56a454603 100644 --- a/modules/digitaluniverse/rendering/renderablepoints.cpp +++ b/modules/digitaluniverse/rendering/renderablepoints.cpp @@ -44,6 +44,7 @@ #include #include #include +#include namespace { constexpr const char* _loggerCat = "RenderablePoints"; @@ -53,17 +54,6 @@ namespace { "spriteTexture", "hasColorMap" }; - constexpr const char* KeyFile = "File"; - constexpr const char* keyColor = "Color"; - constexpr const char* keyUnit = "Unit"; - constexpr const char* MeterUnit = "m"; - constexpr const char* KilometerUnit = "Km"; - constexpr const char* ParsecUnit = "pc"; - constexpr const char* KiloparsecUnit = "Kpc"; - constexpr const char* MegaparsecUnit = "Mpc"; - constexpr const char* GigaparsecUnit = "Gpc"; - constexpr const char* GigalightyearUnit = "Gly"; - constexpr int8_t CurrentCacheVersion = 1; constexpr double PARSEC = 0.308567756E17; @@ -91,58 +81,46 @@ namespace { "Color Map File", "The path to the color map file of the astronomical onject." }; + + struct [[codegen::Dictionary(RenderablePoints)]] Parameters { + // The path to the SPECK file that contains information about the astronomical + // object being rendered + std::string file; + + // Astronomical Object Color (r,g,b) + glm::vec3 color; + + enum class Unit { + Meter [[codegen::key("m")]], + Kilometer [[codegen::key("Km")]], + Parsec [[codegen::key("pc")]], + Kiloparsec [[codegen::key("Kpc")]], + Megaparsec [[codegen::key("Mpc")]], + Gigaparsec [[codegen::key("Gpc")]], + Gigalightyears [[codegen::key("Gly")]] + }; + std::optional unit; + + // [[codegen::verbatim(SpriteTextureInfo.description)]] + std::optional texture; + + // [[codegen::verbatim(ScaleFactorInfo.description)]] + std::optional scaleFactor; + + // [[codegen::verbatim(ColorMapInfo.description)]] + std::optional colorMap; + }; +#include "renderablepoints_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderablePoints::Documentation() { - using namespace documentation; - return { - "RenderablePoints", - "digitaluniverse_renderablepoints", - { - { - "Type", - new StringEqualVerifier("RenderablePoints"), - Optional::No - }, - { - KeyFile, - new StringVerifier, - Optional::No, - "The path to the SPECK file that contains information about the " - "astronomical object being rendered." - }, - { - keyColor, - new Vector3Verifier, - Optional::No, - "Astronomical Object Color (r,g,b)." - }, - { - SpriteTextureInfo.identifier, - new StringVerifier, - Optional::Yes, - SpriteTextureInfo.description - }, - { - ScaleFactorInfo.identifier, - new DoubleVerifier, - Optional::Yes, - ScaleFactorInfo.description - }, - { - ColorMapInfo.identifier, - new StringVerifier, - Optional::Yes, - ColorMapInfo.description - }, - - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "digitaluniverse_renderablepoints"; + return doc; } - RenderablePoints::RenderablePoints(const ghoul::Dictionary& dictionary) : Renderable(dictionary) , _scaleFactor(ScaleFactorInfo, 1.f, 0.f, 64.f) @@ -150,59 +128,52 @@ RenderablePoints::RenderablePoints(const ghoul::Dictionary& dictionary) ColorInfo, glm::vec3(1.f, 0.4f, 0.2f), glm::vec3(0.f, 0.f, 0.f), - glm::vec3(1.0f, 1.0f, 1.0f) + glm::vec3(1.f, 1.f, 1.f) ) , _spriteTexturePath(SpriteTextureInfo) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderablePoints" - ); + const Parameters p = codegen::bake(dictionary); addProperty(_opacity); registerUpdateRenderBinFromOpacity(); - _speckFile = absPath(dictionary.value(KeyFile)); + _speckFile = absPath(p.file); - if (dictionary.hasKey(keyUnit)) { - const std::string& unit = dictionary.value(keyUnit); - if (unit == MeterUnit) { - _unit = Meter; - } - else if (unit == KilometerUnit) { - _unit = Kilometer; - } - else if (unit == ParsecUnit) { - _unit = Parsec; - } - else if (unit == KiloparsecUnit) { - _unit = Kiloparsec; - } - else if (unit == MegaparsecUnit) { - _unit = Megaparsec; - } - else if (unit == GigaparsecUnit) { - _unit = Gigaparsec; - } - else if (unit == GigalightyearUnit) { - _unit = GigalightYears; - } - else { - LWARNING("No unit given for RenderablePoints. Using meters as units."); - _unit = Meter; + if (p.unit.has_value()) { + switch (*p.unit) { + case Parameters::Unit::Meter: + _unit = Meter; + break; + case Parameters::Unit::Kilometer: + _unit = Kilometer; + break; + case Parameters::Unit::Parsec: + _unit = Parsec; + break; + case Parameters::Unit::Kiloparsec: + _unit = Kiloparsec; + break; + case Parameters::Unit::Megaparsec: + _unit = Megaparsec; + break; + case Parameters::Unit::Gigaparsec: + _unit = Gigaparsec; + break; + case Parameters::Unit::Gigalightyears: + _unit = GigalightYears; + break; } } - - if (dictionary.hasKey(keyColor)) { - _pointColor = dictionary.value(keyColor); + else { + LWARNING("No unit given for RenderablePoints. Using meters as units."); + _unit = Meter; } + + _pointColor = p.color; addProperty(_pointColor); - if (dictionary.hasKey(SpriteTextureInfo.identifier)) { - _spriteTexturePath = absPath(dictionary.value( - SpriteTextureInfo.identifier - )); + if (p.texture.has_value()) { + _spriteTexturePath = absPath(*p.texture); _spriteTextureFile = std::make_unique( _spriteTexturePath ); @@ -216,18 +187,12 @@ RenderablePoints::RenderablePoints(const ghoul::Dictionary& dictionary) _hasSpriteTexture = true; } - if (dictionary.hasKey(ColorMapInfo.identifier)) { - _colorMapFile = absPath(dictionary.value( - ColorMapInfo.identifier - )); + if (p.colorMap.has_value()) { + _colorMapFile = absPath(*p.colorMap); _hasColorMapFile = true; } - if (dictionary.hasKey(ScaleFactorInfo.identifier)) { - _scaleFactor = static_cast( - dictionary.value(ScaleFactorInfo.identifier) - ); - } + _scaleFactor = p.scaleFactor.value_or(_scaleFactor); addProperty(_scaleFactor); } diff --git a/modules/exoplanets/exoplanetshelper.cpp b/modules/exoplanets/exoplanetshelper.cpp index d0becf0cc9..17bf9b5fe8 100644 --- a/modules/exoplanets/exoplanetshelper.cpp +++ b/modules/exoplanets/exoplanetshelper.cpp @@ -136,50 +136,6 @@ glm::dmat3 computeSystemRotation(glm::dvec3 starPosition) { ); } -glm::vec2 computeHabitableZone(float teff, float luminosity) { - // Kopparapu's formula only considers stars with teff in range [2600, 7200] K. - // However, we want to use the formula for more stars, so add some flexibility to - // the teff boundaries - if (teff > 8000.f || teff < 2000.f) { - // For the other stars, use a method by Tom E. Morris: - // https://www.planetarybiology.com/calculating_habitable_zone.html - float inner = std::sqrt(luminosity / 1.1f); - float outer = std::sqrt(luminosity / 0.53f); - return glm::vec2(inner, outer); - } - - struct Coefficients { - float seffSun; - float a; - float b; - float c; - float d; - }; - - // Coefficients for planets of 1 Earth mass. Received from: - // https://depts.washington.edu/naivpl/sites/default/files/HZ_coefficients.dat - constexpr const Coefficients coefficients[] = { - // Inner boundary - Runaway greenhouse - {1.10700E+00f, 1.33200E-04f, 1.58000E-08f, -8.30800E-12f, -1.93100E-15f}, - // Outer boundary - Maximum greenhouse - {3.56000E-01f, 6.17100E-05f, 1.69800E-09f, -3.19800E-12f, -5.57500E-16f} - }; - - const float tstar = teff - 5780.f; - const float tstar2 = tstar * tstar; - - glm::vec2 distances; - for (int i = 0; i < 2; ++i) { - const Coefficients& coeffs = coefficients[i]; - float seff = coeffs.seffSun + (coeffs.a * tstar) + (coeffs.b * tstar2) + - (coeffs.c * tstar * tstar2) + (coeffs.d * tstar2 * tstar2); - - distances[i] = std::pow(luminosity / seff, 0.5f); - } - - return distances; -} - std::string createIdentifier(std::string name) { std::replace(name.begin(), name.end(), ' ', '_'); std::replace(name.begin(), name.end(), '.', '-'); diff --git a/modules/exoplanets/exoplanetshelper.h b/modules/exoplanets/exoplanetshelper.h index 43bf96e66a..527bdf4b01 100644 --- a/modules/exoplanets/exoplanetshelper.h +++ b/modules/exoplanets/exoplanetshelper.h @@ -108,17 +108,6 @@ glm::dmat4 computeOrbitPlaneRotationMatrix(float i, float bigom = 180.f, // so that x is pointing from star to the sun. glm::dmat3 computeSystemRotation(glm::dvec3 starPosition); -/** - * Compute the inner and outer boundary of the habitable zone of a star, accordring to - * formula and coefficients by Kopparapu et al. (2015) https://arxiv.org/abs/1404.5292 - * - * \param teff The effective temperature of the star, in Kelvin - * \param luminosity The luminosity of the star, in solar luminosities - * \return A vec2 with the lower and upper boundary in atronomical units, if a habitable - zone could be computed. Otherwise an std::nullopt - */ -glm::vec2 computeHabitableZone(float teff, float luminosity); - // Create an identifier without whitespaces std::string createIdentifier(std::string name); diff --git a/modules/exoplanets/exoplanetsmodule_lua.inl b/modules/exoplanets/exoplanetsmodule_lua.inl index bd12c170e1..a92408f154 100644 --- a/modules/exoplanets/exoplanetsmodule_lua.inl +++ b/modules/exoplanets/exoplanetsmodule_lua.inl @@ -39,22 +39,24 @@ #include namespace { - constexpr const char* _loggerCat = "ExoplanetsModule"; + constexpr const char _loggerCat[] = "ExoplanetsModule"; } // namespace namespace openspace::exoplanets::luascriptfunctions { -constexpr const char* ExoplanetsGuiPath = "/Milky Way/Exoplanets/Exoplanet Systems/"; +constexpr const char ExoplanetsGuiPath[] = "/Milky Way/Exoplanets/Exoplanet Systems/"; -constexpr const char* LookUpTablePath = "${SYNC}/http/exoplanets_data/2/lookup.txt"; -constexpr const char* ExoplanetsDataPath = +constexpr const char LookUpTablePath[] = "${SYNC}/http/exoplanets_data/2/lookup.txt"; +constexpr const char ExoplanetsDataPath[] = "${SYNC}/http/exoplanets_data/2/exoplanets_data.bin"; -constexpr const char* StarTextureFile = "${SYNC}/http/exoplanets_textures/1/sun.jpg"; -constexpr const char* NoDataTextureFile = - "${SYNC}/http/exoplanets_textures/1/grid-32.png"; -constexpr const char* DiscTextureFile = - "${SYNC}/http/exoplanets_textures/1/disc_texture.png"; +constexpr const char StarTextureFile[] = "${SYNC}/http/exoplanets_textures/2/sun.jpg"; +constexpr const char NoDataTextureFile[] = + "${SYNC}/http/exoplanets_textures/2/grid-32.png"; +constexpr const char DiscTextureFile[] = + "${SYNC}/http/exoplanets_textures/2/disc_bw_texture.png"; +constexpr const char HabitableZoneTextureFile[] = + "${SYNC}/http/habitable_zone_textures/1/hot_to_cold_faded.png"; constexpr const float AU = static_cast(distanceconstants::AstronomicalUnit); constexpr const float SolarRadius = static_cast(distanceconstants::SolarRadius); @@ -387,7 +389,7 @@ void createExoplanetSystem(const std::string& starName) { std::to_string(lowerOffset) + ", " + std::to_string(upperOffset) + "}," //min / max extend - "Opacity = 0.3" + "Opacity = 0.25" "}," "Transform = {" "Rotation = {" @@ -451,16 +453,6 @@ void createExoplanetSystem(const std::string& starName) { bool hasLuminosity = !std::isnan(system.starData.luminosity); if (hasTeff && hasLuminosity) { - const glm::vec2 zone = computeHabitableZone( - system.starData.teff, - system.starData.luminosity - ); - - glm::vec2 limitsInMeter = zone * AU; - float half = 0.5f * (limitsInMeter[1] - limitsInMeter[0]); - float center = limitsInMeter[0] + half; - float relativeOffset = half / center; - constexpr const char* description = "The habitable zone is the region around a star in which an Earth-like " "planet can potentially have liquid water on its surface." @@ -476,17 +468,12 @@ void createExoplanetSystem(const std::string& starName) { "Parent = '" + starIdentifier + "'," "Enabled = true," "Renderable = {" - "Type = 'RenderableOrbitDisc'," - "Texture = openspace.absPath(" - "openspace.createPixelImage('exo_habitable_zone', {0, 0.92, 0.81})" - ")," - "Size = " + std::to_string(center) + "," - "Eccentricity = 0," - "Offset = { " + - std::to_string(relativeOffset) + ", " + - std::to_string(relativeOffset) + - "}," //min / max extend - "Opacity = 0.05" + "Type = 'RenderableHabitableZone'," + "Texture = openspace.absPath('" + HabitableZoneTextureFile + "')," + "Luminosity = " + std::to_string(system.starData.luminosity) + "," + "EffectiveTemperature = " + std::to_string(system.starData.teff) + "," + "Optimistic = true," + "Opacity = 0.07" "}," "Transform = {" "Rotation = {" diff --git a/modules/exoplanets/include.cmake b/modules/exoplanets/include.cmake index ffea0ac430..c186634837 100644 --- a/modules/exoplanets/include.cmake +++ b/modules/exoplanets/include.cmake @@ -1 +1,4 @@ set(DEFAULT_MODULE ON) +set (OPENSPACE_DEPENDENCIES + space +) diff --git a/modules/exoplanets/rendering/renderableorbitdisc.cpp b/modules/exoplanets/rendering/renderableorbitdisc.cpp index 2887a6bae9..1ad0e6a85b 100644 --- a/modules/exoplanets/rendering/renderableorbitdisc.cpp +++ b/modules/exoplanets/rendering/renderableorbitdisc.cpp @@ -33,10 +33,8 @@ #include #include #include -#include #include #include -#include #include namespace { @@ -49,7 +47,7 @@ namespace { "Texture", "Texture", "This value is the path to a texture on disk that contains a one-dimensional " - "texture which is used for these rings." + "texture which is used for the color." }; static const openspace::properties::Property::PropertyInfo SizeInfo = { @@ -83,11 +81,6 @@ documentation::Documentation RenderableOrbitDisc::Documentation() { "Renderable Orbit Disc", "exoplanets_renderable_orbit_disc", { - { - "Type", - new StringEqualVerifier("RenderableOrbitDisc"), - Optional::No - }, { TextureInfo.identifier, new StringVerifier, @@ -123,8 +116,6 @@ RenderableOrbitDisc::RenderableOrbitDisc(const ghoul::Dictionary& dictionary) , _eccentricity(EccentricityInfo, 0.f, 0.f, 1.f) , _offset(OffsetInfo, glm::vec2(0.f), glm::vec2(0.f), glm::vec2(1.f)) { - using ghoul::filesystem::File; - documentation::testSpecificationAndThrow( Documentation(), dictionary, @@ -144,13 +135,9 @@ RenderableOrbitDisc::RenderableOrbitDisc(const ghoul::Dictionary& dictionary) setBoundingSphere(_size + _offset.value().y * _size); _texturePath = absPath(dictionary.value(TextureInfo.identifier)); - _textureFile = std::make_unique(_texturePath); - - _texturePath.onChange([&]() { _textureIsDirty = true; }); + _texturePath.onChange([&]() { _texture->loadFromFile(_texturePath); }); addProperty(_texturePath); - _textureFile->setCallback([&](const File&) { _textureIsDirty = true; }); - _eccentricity = static_cast( dictionary.value(EccentricityInfo.identifier) ); @@ -161,33 +148,34 @@ RenderableOrbitDisc::RenderableOrbitDisc(const ghoul::Dictionary& dictionary) } bool RenderableOrbitDisc::isReady() const { - return _shader && _texture; + return _shader && _texture && _plane; +} + +void RenderableOrbitDisc::initialize() { + _texture = std::make_unique(); + _texture->setFilterMode(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); + _texture->setWrapping(ghoul::opengl::Texture::WrappingMode::ClampToEdge); + _plane = std::make_unique(planeSize()); } void RenderableOrbitDisc::initializeGL() { _shader = global::renderEngine->buildRenderProgram( - "OrbitdiscProgram", + "OrbitDiscProgram", absPath("${BASE}/modules/exoplanets/shaders/orbitdisc_vs.glsl"), absPath("${BASE}/modules/exoplanets/shaders/orbitdisc_fs.glsl") ); ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames); - glGenVertexArrays(1, &_quad); - glGenBuffers(1, &_vertexPositionBuffer); + _texture->loadFromFile(_texturePath); + _texture->uploadToGpu(); - createPlane(); - loadTexture(); + _plane->initialize(); } void RenderableOrbitDisc::deinitializeGL() { - glDeleteVertexArrays(1, &_quad); - _quad = 0; - - glDeleteBuffers(1, &_vertexPositionBuffer); - _vertexPositionBuffer = 0; - - _textureFile = nullptr; + _plane->deinitialize(); + _plane = nullptr; _texture = nullptr; global::renderEngine->removeRenderProgram(_shader.get()); @@ -223,8 +211,7 @@ void RenderableOrbitDisc::render(const RenderData& data, RendererTasks&) { glDepthMask(false); glDisable(GL_CULL_FACE); - glBindVertexArray(_quad); - glDrawArrays(GL_TRIANGLES, 0, 6); + _plane->render(); _shader->deactivate(); @@ -241,80 +228,17 @@ void RenderableOrbitDisc::update(const UpdateData&) { } if (_planeIsDirty) { - createPlane(); + _plane->updateSize(planeSize()); _planeIsDirty = false; } - if (_textureIsDirty) { - loadTexture(); - _textureIsDirty = false; - } + _texture->update(); } -void RenderableOrbitDisc::loadTexture() { - if (!_texturePath.value().empty()) { - std::unique_ptr texture = - ghoul::io::TextureReader::ref().loadTexture(absPath(_texturePath)); - - if (texture) { - LDEBUGC( - "RenderableOrbitDisc", - fmt::format("Loaded texture from '{}'", absPath(_texturePath)) - ); - _texture = std::move(texture); - - _texture->uploadTexture(); - _texture->setFilter(ghoul::opengl::Texture::FilterMode::AnisotropicMipMap); - - _textureFile = std::make_unique(_texturePath); - _textureFile->setCallback( - [&](const ghoul::filesystem::File&) { _textureIsDirty = true; } - ); - } - } -} - -void RenderableOrbitDisc::createPlane() { - const GLfloat outerDistance = (_size + _offset.value().y * _size); - const GLfloat size = outerDistance * (1.f + _eccentricity); - - struct VertexData { - GLfloat x; - GLfloat y; - GLfloat s; - GLfloat t; - }; - - VertexData data[] = { - { -size, -size, 0.f, 0.f }, - { size, size, 1.f, 1.f }, - { -size, size, 0.f, 1.f }, - { -size, -size, 0.f, 0.f }, - { size, -size, 1.f, 0.f }, - { size, size, 1.f, 1.f }, - }; - - glBindVertexArray(_quad); - glBindBuffer(GL_ARRAY_BUFFER, _vertexPositionBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); - glEnableVertexAttribArray(0); - glVertexAttribPointer( - 0, - 2, - GL_FLOAT, - GL_FALSE, - sizeof(VertexData), - nullptr - ); - glEnableVertexAttribArray(1); - glVertexAttribPointer( - 1, - 2, - GL_FLOAT, - GL_FALSE, - sizeof(VertexData), - reinterpret_cast(offsetof(VertexData, s)) - ); +float RenderableOrbitDisc::planeSize() const { + float maxRadius = _size + _offset.value().y * _size; + maxRadius *= (1.f + _eccentricity); + return maxRadius; } } // namespace openspace diff --git a/modules/exoplanets/rendering/renderableorbitdisc.h b/modules/exoplanets/rendering/renderableorbitdisc.h index 5a94a2bfc1..b467a9cb90 100644 --- a/modules/exoplanets/rendering/renderableorbitdisc.h +++ b/modules/exoplanets/rendering/renderableorbitdisc.h @@ -29,14 +29,13 @@ #include #include #include +#include +#include #include -#include #include namespace ghoul::filesystem { class File; } -namespace ghoul::opengl { - class ProgramObject; -} // namespace ghoul::opengl +namespace ghoul::opengl { class ProgramObject; } // namespace ghoul::opengl namespace openspace { @@ -46,6 +45,7 @@ class RenderableOrbitDisc : public Renderable { public: RenderableOrbitDisc(const ghoul::Dictionary& dictionary); + void initialize() override; void initializeGL() override; void deinitializeGL() override; @@ -57,8 +57,8 @@ public: static documentation::Documentation Documentation(); private: - void loadTexture(); - void createPlane(); + // Computes the size of the plane quad using the relevant properties + float planeSize() const; properties::StringProperty _texturePath; properties::FloatProperty _size; @@ -68,13 +68,11 @@ private: std::unique_ptr _shader = nullptr; UniformCache(modelViewProjection, offset, opacity, texture, eccentricity, semiMajorAxis) _uniformCache; - std::unique_ptr _texture = nullptr; - std::unique_ptr _textureFile; - bool _textureIsDirty = false; + std::unique_ptr _plane; + std::unique_ptr _texture; + bool _planeIsDirty = false; - GLuint _quad = 0; - GLuint _vertexPositionBuffer = 0; }; } // namespace openspace diff --git a/modules/exoplanets/tasks/exoplanetsdatapreparationtask.cpp b/modules/exoplanets/tasks/exoplanetsdatapreparationtask.cpp index 46b8953f9c..e4fb0a4801 100644 --- a/modules/exoplanets/tasks/exoplanetsdatapreparationtask.cpp +++ b/modules/exoplanets/tasks/exoplanetsdatapreparationtask.cpp @@ -447,12 +447,6 @@ documentation::Documentation ExoplanetsDataPreparationTask::documentation() { "ExoplanetsDataPreparationTask", "exoplanets_data_preparation_task", { - { - "Type", - new StringEqualVerifier("ExoplanetsDataPreparationTask"), - Optional::No, - "" - }, { KeyInputDataFile, new StringAnnotationVerifier("A valid filepath"), diff --git a/modules/gaia/rendering/renderablegaiastars.cpp b/modules/gaia/rendering/renderablegaiastars.cpp index 4c2bc9cdcc..722f90f8b2 100644 --- a/modules/gaia/rendering/renderablegaiastars.cpp +++ b/modules/gaia/rendering/renderablegaiastars.cpp @@ -310,11 +310,6 @@ documentation::Documentation RenderableGaiaStars::Documentation() { "RenderableGaiaStars", "gaiamission_renderablegaiastars", { - { - "Type", - new StringEqualVerifier("RenderableGaiaStars"), - Optional::No - }, { FilePathInfo.identifier, new StringVerifier, diff --git a/modules/gaia/tasks/constructoctreetask.cpp b/modules/gaia/tasks/constructoctreetask.cpp index 7d1e5621e0..a4edef1372 100644 --- a/modules/gaia/tasks/constructoctreetask.cpp +++ b/modules/gaia/tasks/constructoctreetask.cpp @@ -548,11 +548,6 @@ documentation::Documentation ConstructOctreeTask::Documentation() { "ConstructOctreeTask", "gaiamission_constructoctreefrombin", { - { - "Type", - new StringEqualVerifier("ConstructOctreeTask"), - Optional::No - }, { KeyInFileOrFolderPath, new StringVerifier, diff --git a/modules/gaia/tasks/readfitstask.cpp b/modules/gaia/tasks/readfitstask.cpp index 461d352f34..5139ab6366 100644 --- a/modules/gaia/tasks/readfitstask.cpp +++ b/modules/gaia/tasks/readfitstask.cpp @@ -327,11 +327,6 @@ documentation::Documentation ReadFitsTask::Documentation() { "ReadFitsFile", "gaiamission_fitsfiletorawdata", { - { - "Type", - new StringEqualVerifier("ReadFitsTask"), - Optional::No - }, { KeyInFileOrFolderPath, new StringVerifier, diff --git a/modules/gaia/tasks/readspecktask.cpp b/modules/gaia/tasks/readspecktask.cpp index 89f2970fba..8db543c2de 100644 --- a/modules/gaia/tasks/readspecktask.cpp +++ b/modules/gaia/tasks/readspecktask.cpp @@ -98,11 +98,6 @@ documentation::Documentation ReadSpeckTask::Documentation() { "ReadSpeckTask", "gaiamission_speckfiletorawdata", { - { - "Type", - new StringEqualVerifier("ReadSpeckTask"), - Optional::No - }, { KeyInFilePath, new StringVerifier, diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index 9e02310d84..ffc5aa159b 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -35,9 +35,10 @@ #include #include #include +#include +#include #include #include -#include #include #include #include @@ -158,6 +159,29 @@ namespace { return result; } + + struct [[codegen::Dictionary(GlobeBrowsingModule)]] Parameters { + // [[codegen::verbatim(WMSCacheEnabledInfo.description)]] + std::optional cacheEnabled [[codegen::key("WMSCacheEnabled")]]; + + // [[codegen::verbatim(OfflineModeInfo.description)]] + std::optional offlineMode; + + // [[codegen::verbatim(WMSCacheLocationInfo.description)]] + std::optional cacheLocation [[codegen::key("WMSCacheLocation")]]; + + // [[codegen::verbatim(WMSCacheSizeInfo.description)]] + std::optional wmsCacheSize [[codegen::key("WMSCacheSize")]]; + + // [[codegen::verbatim(TileCacheSizeInfo.description)]] + std::optional tileCacheSize; + + // If you know what you are doing and you have WMS caching *disabled* but offline + // mode *enabled*, you can set this value to 'true' to silence a warning that you + // would otherwise get at startup + std::optional noWarning; + }; +#include "globebrowsingmodule_codegen.cpp" } // namespace namespace openspace { @@ -180,30 +204,13 @@ GlobeBrowsingModule::GlobeBrowsingModule() void GlobeBrowsingModule::internalInitialize(const ghoul::Dictionary& dict) { using namespace globebrowsing; - if (dict.hasValue(WMSCacheEnabledInfo.identifier)) { - _wmsCacheEnabled = dict.value(WMSCacheEnabledInfo.identifier); - } - if (dict.hasValue(OfflineModeInfo.identifier)) { - _offlineMode = dict.value(OfflineModeInfo.identifier); - } - if (dict.hasValue(WMSCacheLocationInfo.identifier)) { - _wmsCacheLocation = dict.value(WMSCacheLocationInfo.identifier); - } - if (dict.hasValue(WMSCacheSizeInfo.identifier)) { - _wmsCacheSizeMB = static_cast( - dict.value(WMSCacheSizeInfo.identifier) - ); - } - if (dict.hasValue(TileCacheSizeInfo.identifier)) { - _tileCacheSizeMB = static_cast( - dict.value(TileCacheSizeInfo.identifier) - ); - } - - // Sanity check - const bool noWarning = dict.hasValue("NoWarning") ? - dict.value("NoWarning") : - false; + const Parameters p = codegen::bake(dict); + _wmsCacheEnabled = p.cacheEnabled.value_or(_wmsCacheEnabled); + _offlineMode = p.offlineMode.value_or(_offlineMode); + _wmsCacheLocation = p.cacheLocation.value_or(_wmsCacheLocation); + _wmsCacheSizeMB = p.wmsCacheSize.value_or(_wmsCacheSizeMB); + _tileCacheSizeMB = p.tileCacheSize.value_or(_tileCacheSizeMB); + const bool noWarning = p.noWarning.value_or(false); if (!_wmsCacheEnabled && _offlineMode && !noWarning) { LWARNINGC( diff --git a/modules/globebrowsing/src/dashboarditemglobelocation.cpp b/modules/globebrowsing/src/dashboarditemglobelocation.cpp index 18d02e3a76..8c53564982 100644 --- a/modules/globebrowsing/src/dashboarditemglobelocation.cpp +++ b/modules/globebrowsing/src/dashboarditemglobelocation.cpp @@ -72,11 +72,6 @@ documentation::Documentation DashboardItemGlobeLocation::Documentation() { "DashboardItem Globe Location", "globebrowsing_dashboarditem_globelocation", { - { - "Type", - new StringEqualVerifier("DashboardItemGlobeLocation"), - Optional::No - }, { FontNameInfo.identifier, new StringVerifier, diff --git a/modules/globebrowsing/src/globelabelscomponent.cpp b/modules/globebrowsing/src/globelabelscomponent.cpp index 549f4d5a4d..7632011bbd 100644 --- a/modules/globebrowsing/src/globelabelscomponent.cpp +++ b/modules/globebrowsing/src/globelabelscomponent.cpp @@ -50,7 +50,7 @@ namespace { constexpr const char* KeyLabelsFileName = "FileName"; - constexpr const double LabelFadeRangeConst = 1500.0; + constexpr const double LabelFadeOutLimitAltitudeMeters = 25000.0; constexpr const double RangeAngularCoefConst = 0.8; constexpr const float MinOpacityValueConst = 0.009f; @@ -674,10 +674,10 @@ void GlobeLabelsComponent::draw(const RenderData& data) { if (_labelsFadeOutEnabled) { glm::dvec2 fadeRange = glm::dvec2( - averageRadius + _labelsMinHeight + LabelFadeRangeConst + averageRadius + _labelsMinHeight + LabelFadeOutLimitAltitudeMeters ); fadeRange.x += _labelsFadeOutDist; - double a = RangeAngularCoefConst / (fadeRange.x - fadeRange.y); + double a = 1.0 / (fadeRange.x - fadeRange.y); double b = -(fadeRange.y / (fadeRange.x - fadeRange.y)); double funcValue = a * distanceCameraGlobeWorld + b; varyingOpacity *= static_cast(std::min(funcValue, 1.0)); diff --git a/modules/globebrowsing/src/globetranslation.cpp b/modules/globebrowsing/src/globetranslation.cpp index 2ae998fa73..633198ba48 100644 --- a/modules/globebrowsing/src/globetranslation.cpp +++ b/modules/globebrowsing/src/globetranslation.cpp @@ -85,11 +85,6 @@ documentation::Documentation GlobeTranslation::Documentation() { "Globe Translation", "space_translation_globetranslation", { - { - "Type", - new StringEqualVerifier("GlobeTranslation"), - Optional::No - }, { GlobeInfo.identifier, new StringAnnotationVerifier( diff --git a/modules/globebrowsing/src/layer.cpp b/modules/globebrowsing/src/layer.cpp index e28d8e68d7..51a3ebc990 100644 --- a/modules/globebrowsing/src/layer.cpp +++ b/modules/globebrowsing/src/layer.cpp @@ -42,15 +42,7 @@ namespace { constexpr const char* KeyName = "Name"; constexpr const char* KeyDesc = "Description"; constexpr const char* KeyLayerGroupID = "LayerGroupID"; - constexpr const char* KeySettings = "Settings"; constexpr const char* KeyAdjustment = "Adjustment"; - constexpr const char* KeyPadTiles = "PadTiles"; - - constexpr const char* KeyOpacity = "Opacity"; - constexpr const char* KeyGamma = "Gamma"; - constexpr const char* KeyMultiplier = "Multiplier"; - constexpr const char* KeyOffset = "Offset"; - constexpr openspace::properties::Property::PropertyInfo TypeInfo = { "Type", @@ -102,114 +94,94 @@ namespace { "example: Earth is a special place", openspace::properties::Property::Visibility::Hidden }; + + struct [[codegen::Dictionary(Layer), codegen::noexhaustive()]] Parameters { + // The unique identifier for this layer. May not contain '.' or spaces + std::string identifier; + + // A human-readable name for the user interface. If this is omitted, the + // identifier is used instead + std::optional name; + + // A human-readable description of the layer to be used in informational texts + // presented to the user + std::optional description; + + // [[codegen::verbatim(ColorInfo.description)]] + std::optional color; + + // Specifies the type of layer that is to be added. If this value is not + // specified, the layer is a DefaultTileLayer + std::optional type [[codegen::inlist("DefaultTileLayer", + "SingleImageTileLayer", "SizeReferenceTileLayer", "TemporalTileLayer", + "TileIndexTileLayer", "ByIndexTileLayer", "ByLevelTileLayer", "SolidColor")]]; + + // Determine whether the layer is enabled or not. If this value is not specified, + // the layer is disabled + std::optional enabled; + + // Determines whether the downloaded tiles should have a padding added to the + // borders + std::optional padTiles; + + struct Settings { + // The opacity value of the layer + std::optional opacity [[codegen::inrange(0.0, 1.0)]]; + + // The gamma value that is applied to each pixel of the layer + std::optional gamma; + + // The multiplicative factor that is applied to each pixel of the layer + std::optional multiplier; + + // An additive offset that is applied to each pixel of the layer + std::optional offset; + }; + // Specifies the render settings that should be applied to this layer + std::optional settings; + + struct LayerAdjustment { + enum class Type { + None, + ChromaKey, + TransferFunction + }; + + // Specifies the type of the adjustment that is applied + std::optional type; + + // Specifies the chroma key used when selecting 'ChromaKey' for the 'Type' + std::optional chromaKeyColor; + + // Specifies the tolerance to match the color to the chroma key when the + // 'ChromaKey' type is selected for the 'Type' + std::optional chromaKeyTolerance; + }; + // Parameters that set individual adjustment parameters for this layer + std::optional adjustment; + + enum class BlendMode { + Normal, + Multiply, + Add, + Subtract, + Color + }; + // Sets the blend mode of this layer to determine how it interacts with other + // layers on top of this + std::optional blendMode; + + // If the primary layer creation fails, this layer is used as a fallback + std::optional + fallback [[codegen::reference("globebrowsing_layer")]]; + }; +#include "layer_codegen.cpp" } // namespace documentation::Documentation Layer::Documentation() { - using namespace documentation; - return { - "Layer", - "globebrowsing_layer", - { - { - KeyIdentifier, - new StringVerifier, - Optional::No, - "The unique identifier for this layer. May not contain '.' or spaces." - }, - { - KeyName, - new StringVerifier, - Optional::Yes, - "A human-readable name for the user interface. If this is omitted, the " - "identifier is used instead." - }, - { - KeyDesc, - new StringVerifier, - Optional::Yes, - "A human-readable description of the layer to be used in informational " - "texts presented to the user." - }, - { - "Type", - new StringInListVerifier({ - "DefaultTileLayer", "SingleImageTileLayer", "SizeReferenceTileLayer", - "TemporalTileLayer", "TileIndexTileLayer", "ByIndexTileLayer", - "ByLevelTileLayer", "SolidColor" - }), - Optional::Yes, - "Specifies the type of layer that is to be added. If this value is not " - "specified, the layer is a DefaultTileLayer." - }, - { - EnabledInfo.identifier, - new BoolVerifier, - Optional::Yes, - "Determine whether the layer is enabled or not. If this value is not " - "specified, the layer is disabled." - }, - { - KeyPadTiles, - new BoolVerifier, - Optional::Yes, - "Determines whether the downloaded tiles should have a padding added to " - "the borders." - }, - { - KeySettings, - new TableVerifier({ - { - KeyOpacity, - new DoubleInRangeVerifier(0.0, 1.0), - Optional::Yes, - "The opacity value of the layer." - }, - { - KeyGamma, - new DoubleVerifier, - Optional::Yes, - "The gamma value that is applied to each pixel of the layer." - }, - { - KeyMultiplier, - new DoubleVerifier, - Optional::Yes, - "The multiplicative factor that is applied to each pixel of the " - "layer." - }, - { - KeyOffset, - new DoubleVerifier, - Optional::Yes, - "An additive offset that is applied to each pixel of the layer." - } - }), - Optional::Yes, - "Specifies the render settings that should be applied to this layer." - }, - { - KeyAdjustment, - new ReferencingVerifier("globebrowsing_layeradjustment"), - Optional::Yes, - "" - }, - { - BlendModeInfo.identifier, - new StringInListVerifier({ - "Normal", "Multiply", "Add", "Subtract", "Color" - }), - Optional::Yes, - "Sets the blend mode of this layer to determine how it interacts with " - "other layers on top of this." - }, - { - "Fallback", - new ReferencingVerifier("globebrowsing_layer"), - Optional::Yes, - "If the primary layer creation fails, this layer is used as a fallback" - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "globebrowsing_layer"; + return doc; } Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict, @@ -230,59 +202,40 @@ Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict, , _layerGroupId(id) { - documentation::testSpecificationAndThrow(Documentation(), layerDict, "Layer"); + const Parameters p = codegen::bake(layerDict); layergroupid::TypeID typeID; - if (layerDict.hasValue("Type")) { - const std::string& typeString = layerDict.value("Type"); - typeID = ghoul::from_string(typeString); + if (p.type.has_value()) { + typeID = ghoul::from_string(*p.type); + if (typeID == layergroupid::TypeID::Unknown) { + throw ghoul::RuntimeError("Unknown layer type!"); + } } else { typeID = layergroupid::TypeID::DefaultTileLayer; } - if (typeID == layergroupid::TypeID::Unknown) { - throw ghoul::RuntimeError("Unknown layer type!"); - } initializeBasedOnType(typeID, layerDict); - if (layerDict.hasValue(EnabledInfo.identifier)) { - _enabled = layerDict.value(EnabledInfo.identifier); - } + _enabled = p.enabled.value_or(_enabled); - if (layerDict.hasKey(KeyDesc)) { + if (p.description.has_value()) { _guiDescription = description(); addProperty(_guiDescription); } - bool padTiles = true; - if (layerDict.hasValue(KeyPadTiles)) { - padTiles = layerDict.value(KeyPadTiles); - } + const bool padTiles = p.padTiles.value_or(true); TileTextureInitData initData = tileTextureInitData(_layerGroupId, padTiles); _padTilePixelStartOffset = initData.tilePixelStartOffset; _padTilePixelSizeDifference = initData.tilePixelSizeDifference; - if (layerDict.hasValue(KeySettings)) { - ghoul::Dictionary dict = layerDict.value(KeySettings); - if (dict.hasValue(KeyOpacity)) { - _renderSettings.opacity = static_cast(dict.value(KeyOpacity)); - } - - if (dict.hasValue(KeyGamma)) { - _renderSettings.gamma = static_cast(dict.value(KeyGamma)); - } - - if (dict.hasValue(KeyMultiplier)) { - _renderSettings.multiplier = static_cast( - dict.value(KeyMultiplier) - ); - } - - if (dict.hasValue(KeyOffset)) { - _renderSettings.offset = static_cast(dict.value(KeyOffset)); - } + if (p.settings.has_value()) { + _renderSettings.opacity = p.settings->opacity.value_or(_renderSettings.opacity); + _renderSettings.gamma = p.settings->gamma.value_or(_renderSettings.gamma); + _renderSettings.multiplier = + p.settings->multiplier.value_or(_renderSettings.multiplier); + _renderSettings.offset = p.settings->offset.value_or(_renderSettings.offset); } if (layerDict.hasValue(KeyAdjustment)) { _layerAdjustment.setValuesFromDictionary( @@ -302,11 +255,24 @@ Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict, } // Initialize blend mode - if (layerDict.hasValue(BlendModeInfo.identifier)) { - using namespace layergroupid; - std::string blendMode = layerDict.value(BlendModeInfo.identifier); - BlendModeID blendModeID = ghoul::from_string(blendMode); - _blendModeOption = static_cast(blendModeID); + if (p.blendMode.has_value()) { + switch (*p.blendMode) { + case Parameters::BlendMode::Normal: + _blendModeOption = static_cast(layergroupid::BlendModeID::Normal); + break; + case Parameters::BlendMode::Multiply: + _blendModeOption = static_cast(layergroupid::BlendModeID::Multiply); + break; + case Parameters::BlendMode::Add: + _blendModeOption = static_cast(layergroupid::BlendModeID::Add); + break; + case Parameters::BlendMode::Subtract: + _blendModeOption = static_cast(layergroupid::BlendModeID::Subtract); + break; + case Parameters::BlendMode::Color: + _blendModeOption = static_cast(layergroupid::BlendModeID::Color); + break; + } } else { _blendModeOption = static_cast(layergroupid::BlendModeID::Normal); diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp index a87e2a3372..9f089d8a46 100644 --- a/modules/globebrowsing/src/renderableglobe.cpp +++ b/modules/globebrowsing/src/renderableglobe.cpp @@ -82,8 +82,6 @@ namespace { constexpr const char* KeyRadii = "Radii"; constexpr const char* KeyLayers = "Layers"; constexpr const char* KeyShadowGroup = "ShadowGroup"; - constexpr const char* KeyShadowSource = "Source"; - constexpr const char* KeyShadowCaster = "Caster"; constexpr const char* KeyLabels = "Labels"; const openspace::globebrowsing::AABB3 CullingFrustum{ @@ -468,12 +466,6 @@ documentation::Documentation RenderableGlobe::Documentation() { "RenderableGlobe", "globebrowsing_renderableglobe", { - { - "Type", - new StringEqualVerifier("RenderableGlobe"), - Optional::No, - "" - }, { KeyRadii, new OrVerifier({ new DoubleVector3Verifier, new DoubleVerifier }), diff --git a/modules/kameleon/ext/kameleon b/modules/kameleon/ext/kameleon index 8a5e966659..606edb945b 160000 --- a/modules/kameleon/ext/kameleon +++ b/modules/kameleon/ext/kameleon @@ -1 +1 @@ -Subproject commit 8a5e9666599e9578d50bf3801dd07a9edf95ccdb +Subproject commit 606edb945b62d0151f20270ddb2db4a9f558aaa1 diff --git a/modules/kameleonvolume/tasks/kameleondocumentationtask.cpp b/modules/kameleonvolume/tasks/kameleondocumentationtask.cpp index 54678d14cd..9e4cac12a5 100644 --- a/modules/kameleonvolume/tasks/kameleondocumentationtask.cpp +++ b/modules/kameleonvolume/tasks/kameleondocumentationtask.cpp @@ -152,12 +152,6 @@ documentation::Documentation KameleonDocumentationTask::documentation() { "KameleonDocumentationTask", "kameleon_documentation_task", { - { - "Type", - new StringEqualVerifier("KameleonDocumentationTask"), - Optional::No, - "The type of this task" - }, { KeyInput, new StringAnnotationVerifier("A file path to a cdf file"), diff --git a/modules/kameleonvolume/tasks/kameleonmetadatatojsontask.cpp b/modules/kameleonvolume/tasks/kameleonmetadatatojsontask.cpp index dc94504423..ecd1bcccf5 100644 --- a/modules/kameleonvolume/tasks/kameleonmetadatatojsontask.cpp +++ b/modules/kameleonvolume/tasks/kameleonmetadatatojsontask.cpp @@ -75,12 +75,6 @@ documentation::Documentation KameleonMetadataToJsonTask::documentation() { "KameleonMetadataToJsonTask", "kameleon_metadata_to_json_task", { - { - "Type", - new StringEqualVerifier("KameleonMetadataToJsonTask"), - Optional::No, - "The type of this task" - }, { KeyInput, new StringAnnotationVerifier("A file path to a cdf file"), diff --git a/modules/kameleonvolume/tasks/kameleonvolumetorawtask.cpp b/modules/kameleonvolume/tasks/kameleonvolumetorawtask.cpp index 4eb568c56e..fd9c342afe 100644 --- a/modules/kameleonvolume/tasks/kameleonvolumetorawtask.cpp +++ b/modules/kameleonvolume/tasks/kameleonvolumetorawtask.cpp @@ -56,12 +56,6 @@ documentation::Documentation KameleonVolumeToRawTask::documentation() { "KameleonVolumeToRawTask", "kameleon_metadata_to_json_task", { - { - "Type", - new StringEqualVerifier("KameleonVolumeToRawTask"), - Optional::No, - "The type of this task", - }, { KeyInput, new StringAnnotationVerifier("A file path to a cdf file"), diff --git a/modules/server/include/topics/topic.h b/modules/server/include/topics/topic.h index de00c28452..f982514c43 100644 --- a/modules/server/include/topics/topic.h +++ b/modules/server/include/topics/topic.h @@ -34,7 +34,7 @@ class Connection; class Topic { public: Topic() {}; - virtual ~Topic() = default; + virtual ~Topic(); void initialize(Connection* connection, size_t topicId); nlohmann::json wrappedPayload(const nlohmann::json& payload) const; diff --git a/modules/server/src/topics/luascripttopic.cpp b/modules/server/src/topics/luascripttopic.cpp index b85b2d6f67..b718ea4838 100644 --- a/modules/server/src/topics/luascripttopic.cpp +++ b/modules/server/src/topics/luascripttopic.cpp @@ -101,7 +101,7 @@ namespace { return formatArrayAsLuaTable(it->get()); } if (it->is_number()) { - return fmt::format("{:E}", it->get()); + return fmt::format("{}", it->get()); } if (it->is_string()) { return formatLuaString(it->get()); @@ -180,9 +180,11 @@ void LuaScriptTopic::runScript(const std::string& script, bool shouldReturn) { scripting::ScriptEngine::ScriptCallback callback; if (shouldReturn) { callback = [this](ghoul::Dictionary data) { - nlohmann::json j = data; - _connection->sendJson(wrappedPayload(j)); - _waitingForReturnValue = false; + if (_connection) { + nlohmann::json j = data; + _connection->sendJson(wrappedPayload(j)); + _waitingForReturnValue = false; + } }; _waitingForReturnValue = true; } diff --git a/modules/server/src/topics/topic.cpp b/modules/server/src/topics/topic.cpp index 0415ad1d63..b69ee91939 100644 --- a/modules/server/src/topics/topic.cpp +++ b/modules/server/src/topics/topic.cpp @@ -30,6 +30,10 @@ namespace openspace { +Topic::~Topic() { + _connection = nullptr; +} + void Topic::initialize(Connection* connection, size_t topicId) { _connection = connection; _topicId = topicId; diff --git a/modules/space/CMakeLists.txt b/modules/space/CMakeLists.txt index 2c1a4e5e48..583e3e89ab 100644 --- a/modules/space/CMakeLists.txt +++ b/modules/space/CMakeLists.txt @@ -27,6 +27,7 @@ include(${OPENSPACE_CMAKE_EXT_DIR}/module_definition.cmake) set(HEADER_FILES rendering/planetgeometry.h rendering/renderableconstellationbounds.h + rendering/renderablehabitablezone.h rendering/renderablerings.h rendering/renderableorbitalkepler.h rendering/renderablesatellites.h @@ -44,6 +45,7 @@ source_group("Header Files" FILES ${HEADER_FILES}) set(SOURCE_FILES rendering/planetgeometry.cpp rendering/renderableconstellationbounds.cpp + rendering/renderablehabitablezone.cpp rendering/renderablerings.cpp rendering/renderableorbitalkepler.cpp rendering/renderablesatellites.cpp @@ -63,6 +65,8 @@ set(SHADER_FILES shaders/constellationbounds_vs.glsl shaders/debrisViz_fs.glsl shaders/debrisViz_vs.glsl + shaders/habitablezone_vs.glsl + shaders/habitablezone_fs.glsl shaders/rings_vs.glsl shaders/rings_fs.glsl shaders/star_fs.glsl diff --git a/modules/space/include.cmake b/modules/space/include.cmake index ffea0ac430..f5adeba225 100644 --- a/modules/space/include.cmake +++ b/modules/space/include.cmake @@ -1 +1,4 @@ set(DEFAULT_MODULE ON) +set (OPENSPACE_DEPENDENCIES + base +) diff --git a/modules/space/rendering/planetgeometry.cpp b/modules/space/rendering/planetgeometry.cpp index a021da2cbb..ec68224b61 100644 --- a/modules/space/rendering/planetgeometry.cpp +++ b/modules/space/rendering/planetgeometry.cpp @@ -30,40 +30,29 @@ #include namespace { - constexpr const char* KeyType = "Type"; + struct [[codegen::Dictionary(PlanetGeometry)]] Parameters { + // The type of the PlanetGeometry that will can be constructed + std::string type; + }; +#include "planetgeometry_codegen.cpp" } // namespace namespace openspace::planetgeometry { documentation::Documentation PlanetGeometry::Documentation() { - using namespace documentation; - return { - "Planet Geometry", - "space_geometry_planet", - { - { - KeyType, - new StringVerifier, - Optional::No, - "The type of the PlanetGeometry that will can be constructed." - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "space_geometry_planet"; + return doc; } std::unique_ptr PlanetGeometry::createFromDictionary( const ghoul::Dictionary& dictionary) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "PlanetGeometry" - ); + const Parameters p = codegen::bake(dictionary); - std::string geometryType = dictionary.value(KeyType); auto factory = FactoryManager::ref().factory(); - PlanetGeometry* result = factory->create(geometryType, dictionary); + PlanetGeometry* result = factory->create(p.type, dictionary); return std::unique_ptr(result); } diff --git a/modules/space/rendering/renderableconstellationbounds.cpp b/modules/space/rendering/renderableconstellationbounds.cpp index 14e8dc60b4..4fe8e5a9cc 100644 --- a/modules/space/rendering/renderableconstellationbounds.cpp +++ b/modules/space/rendering/renderableconstellationbounds.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include "SpiceUsr.h" namespace { @@ -74,51 +75,33 @@ namespace { "Constellation Selection", "The constellations that are selected are displayed on the celestial sphere." }; + + struct [[codegen::Dictionary(RenderableConstellationBounds)]] Parameters { + // [[codegen::verbatim(VertexInfo.description)]] + std::string file; + + // [[codegen::verbatim(ConstellationInfo.description)]] + std::optional constellationFile; + + // [[codegen::verbatim(ColorInfo.description)]] + std::optional color; + + // [[codegen::verbatim(LineWidthInfo.description)]] + std::optional lineWidth; + + // [[codegen::verbatim(SelectionInfo.description)]] + std::optional> constellationSelection; + }; +#include "renderableconstellationbounds_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableConstellationBounds::Documentation() { - using namespace documentation; - return { - "RenderableConstellationBounds", - "space_renderable_constellationbounds", - { - { - VertexInfo.identifier, - new StringVerifier, - Optional::No, - VertexInfo.description - }, - { - ConstellationInfo.identifier, - new StringVerifier, - Optional::Yes, - "Specifies the file that contains the mapping between constellation " - "abbreviations and full name of the constellation. If the file is " - "omitted, the abbreviations are used as the full names." - }, - { - ColorInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - ColorInfo.description - }, - { - LineWidthInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LineWidthInfo.description - }, - { - SelectionInfo.identifier, - new StringListVerifier, - Optional::Yes, - SelectionInfo.description - } - } - }; -} + documentation::Documentation doc = codegen::doc(); + doc.id = "space_renderable_constellationbounds"; + return doc; +} // namespace RenderableConstellationBounds::RenderableConstellationBounds( @@ -130,53 +113,33 @@ RenderableConstellationBounds::RenderableConstellationBounds( , _lineWidth(LineWidthInfo, 2.f, 1.f, 32.f) , _constellationSelection(SelectionInfo) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableConstellationBounds" - ); + const Parameters p = codegen::bake(dictionary); _vertexFilename.onChange([&](){ loadVertexFile(); }); addProperty(_vertexFilename); - _vertexFilename = dictionary.value(VertexInfo.identifier); + _vertexFilename = p.file; _constellationFilename.onChange([&](){ loadConstellationFile(); }); + _constellationFilename = p.constellationFile.value_or(_constellationFilename); addProperty(_constellationFilename); - if (dictionary.hasKey(ConstellationInfo.identifier)) { - _constellationFilename = dictionary.value( - ConstellationInfo.identifier - ); - } _color.setViewOption(properties::Property::ViewOptions::Color); + _color = p.color.value_or(_color); addProperty(_color); - if (dictionary.hasKey(ColorInfo.identifier)) { - _color = glm::vec3(dictionary.value(ColorInfo.identifier)); - } + _lineWidth = p.lineWidth.value_or(_lineWidth); addProperty(_lineWidth); - if (dictionary.hasKey(LineWidthInfo.identifier)) { - _lineWidth = static_cast( - dictionary.value(LineWidthInfo.identifier) - ); - } fillSelectionProperty(); _constellationSelection.onChange([this]() { selectionPropertyHasChanged(); }); addProperty(_constellationSelection); - if (dictionary.hasKey(SelectionInfo.identifier)) { - const ghoul::Dictionary& selection = dictionary.value( - SelectionInfo.identifier - ); - + if (p.constellationSelection.has_value()) { std::vector options = _constellationSelection.options(); + std::vector selectedIndices; - - for (size_t i = 1; i <= selection.size(); ++i) { - const std::string& s = selection.value(std::to_string(i)); - + for (const std::string& s : *p.constellationSelection) { const auto it = std::find_if( options.begin(), options.end(), diff --git a/modules/space/rendering/renderablehabitablezone.cpp b/modules/space/rendering/renderablehabitablezone.cpp new file mode 100644 index 0000000000..f2888a28c0 --- /dev/null +++ b/modules/space/rendering/renderablehabitablezone.cpp @@ -0,0 +1,302 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace { + constexpr const char _loggerCat[] = "RenderableHabitableZone"; + + constexpr const std::array UniformNames = { + "modelViewProjectionTransform", "opacity", "width", "transferFunctionTexture", + "conservativeBounds", "showOptimistic" + }; + + constexpr openspace::properties::Property::PropertyInfo EffectiveTemperatureInfo = { + "EffectiveTemperature", + "Effective Temperature", + "The effective temperature of the corresponding star, in Kelvin. " + "Used to compute the width and size of the disc." + }; + + constexpr openspace::properties::Property::PropertyInfo LuminosityInfo = { + "Luminosity", + "Luminosity", + "The luminosity of the corresponding star, in units of solar luminosities. " + "Used to compute the width and size of the disc." + }; + + constexpr openspace::properties::Property::PropertyInfo OptimisticInfo = { + "Optimistic", + "Optimistic" , + "If true, the habitable zone disc is rendered with the optimistic boundaries " + "rather than the conservative ones." + }; + + constexpr openspace::properties::Property::PropertyInfo KopparapuTeffIntervalInfo = { + "KopparapuTeffInterval", + "Effective Temperature Interval (Kopparapu's formula)" , + "The range for which Kopparapu's formula is used for the habitable zone " + "computation. For stars with effective temperatures outside the range, a " + "simpler method by Tom E. Harris is used. This method only uses the star " + "luminosity and does not include computation of the optimistic boundaries." + }; +} // namespace + +namespace openspace { + +documentation::Documentation RenderableHabitableZone::Documentation() { + using namespace documentation; + documentation::Documentation doc { + "Renderable Habitable Zone", + "exoplanets_renderable_habitable_zone", + { + { + EffectiveTemperatureInfo.identifier, + new DoubleVerifier, + Optional::No, + EffectiveTemperatureInfo.description + }, + { + LuminosityInfo.identifier, + new DoubleVerifier, + Optional::No, + LuminosityInfo.description + }, + { + OptimisticInfo.identifier, + new BoolVerifier, + Optional::Yes, + OptimisticInfo.description + }, + { + KopparapuTeffIntervalInfo.identifier, + new DoubleVector2Verifier, + Optional::Yes, + KopparapuTeffIntervalInfo.description + } + } + }; + + // @TODO cleanup + // Insert the parents documentation entries until we have a verifier that can deal + // with class hierarchy + documentation::Documentation parentDoc = RenderableDisc::Documentation(); + doc.entries.insert( + doc.entries.end(), + parentDoc.entries.begin(), + parentDoc.entries.end() + ); + + return doc; +} + +RenderableHabitableZone::RenderableHabitableZone(const ghoul::Dictionary& dictionary) + : RenderableDisc(dictionary) + , _teff(EffectiveTemperatureInfo, 5780.f, 0.f, 7.5e4f) + , _luminosity(LuminosityInfo, 1.f, 0.f, 1e8f) + , _showOptimistic(OptimisticInfo, false) + , _kopparapuTeffInterval(KopparapuTeffIntervalInfo, glm::vec2(2000.f, 8000.f)) +{ + documentation::testSpecificationAndThrow( + Documentation(), + dictionary, + "RenderableHabitableZone" + ); + + if (dictionary.hasKey(EffectiveTemperatureInfo.identifier)) { + _teff = static_cast( + dictionary.value(EffectiveTemperatureInfo.identifier) + ); + } + _teff.onChange([this]() { computeZone(); }); + addProperty(_teff); + + if (dictionary.hasKey(LuminosityInfo.identifier)) { + _luminosity = static_cast( + dictionary.value(LuminosityInfo.identifier) + ); + } + _luminosity.onChange([this]() { computeZone(); }); + addProperty(_luminosity); + + if (dictionary.hasKey(OptimisticInfo.identifier)) { + _showOptimistic = dictionary.value(OptimisticInfo.identifier); + } + addProperty(_showOptimistic); + + // The user should not be able to change this property. It's just used to communicate + // the different rendering that happens outside of this interval + addProperty(_kopparapuTeffInterval); + _kopparapuTeffInterval.setReadOnly(true); + + // Make parent's size related properties read only. We want to set them based on the + // given temperature and luminosity + _size.setReadOnly(true); + _width.setReadOnly(true); + + computeZone(); +} + +void RenderableHabitableZone::render(const RenderData& data, RendererTasks&) { + _shader->activate(); + + glm::dmat4 modelTransform = + glm::translate(glm::dmat4(1.0), data.modelTransform.translation) * + glm::dmat4(data.modelTransform.rotation) * + glm::scale(glm::dmat4(1.0), glm::dvec3(data.modelTransform.scale)); + + glm::dmat4 modelViewTransform = data.camera.combinedViewMatrix() * modelTransform; + + _shader->setUniform( + _uniformCache.modelViewProjection, + data.camera.projectionMatrix() * glm::mat4(modelViewTransform) + ); + _shader->setUniform(_uniformCache.width, _width); + _shader->setUniform(_uniformCache.opacity, _opacity); + _shader->setUniform(_uniformCache.conservativeBounds, _conservativeBounds); + _shader->setUniform(_uniformCache.showOptimistic, _showOptimistic); + + ghoul::opengl::TextureUnit unit; + unit.activate(); + _texture->bind(); + _shader->setUniform(_uniformCache.texture, unit); + + glEnablei(GL_BLEND, 0); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDepthMask(false); + glDisable(GL_CULL_FACE); + + _plane->render(); + + _shader->deactivate(); + + // Restores GL State + global::renderEngine->openglStateCache().resetBlendState(); + global::renderEngine->openglStateCache().resetDepthState(); + global::renderEngine->openglStateCache().resetPolygonAndClippingState(); +} + +void RenderableHabitableZone::initializeShader() { + _shader = global::renderEngine->buildRenderProgram( + "HabitableZoneProgram", + absPath("${MODULE_SPACE}/shaders/habitablezone_vs.glsl"), + absPath("${MODULE_SPACE}/shaders/habitablezone_fs.glsl") + ); + ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames); +} + +void RenderableHabitableZone::updateUniformLocations() { + ghoul::opengl::updateUniformLocations(*_shader, _uniformCache, UniformNames); +} + +void RenderableHabitableZone::computeZone() { + glm::dvec4 distancesInAu = computeKopparapuZoneBoundaries(_teff, _luminosity); + constexpr const double AU = distanceconstants::AstronomicalUnit; + const double inner = distancesInAu[0] * AU; + const double innerConservative = distancesInAu[1] * AU; + const double outerConservative = distancesInAu[2] * AU; + const double outer = distancesInAu[3] * AU; + + double discWidth = 0.0; + if (outer > 0.0) { + discWidth = (outer - inner) / outer; + } + + _size = static_cast(outer); + _width = static_cast(discWidth); + + // Compute the coservative bounds normalized by the size of the disc, i.e. in [0, 1] + _conservativeBounds = glm::vec2(innerConservative, outerConservative); + _conservativeBounds /= _size; +} + +glm::dvec4 RenderableHabitableZone::computeKopparapuZoneBoundaries(float teff, + float luminosity) +{ + // Kopparapu's formula only considers stars with teff in range [2600, 7200] K. + // However, we want to use the formula for more stars, so add some flexibility to + // the teff boundaries (see constructor). + // OBS! This also prevents problems with too large teff values in the computation + const glm::vec2 teffBounds = _kopparapuTeffInterval; + if (teff > teffBounds.y || teff < teffBounds.x) { + // For the other stars, use a method by Tom E. Morris: + // https://www.planetarybiology.com/calculating_habitable_zone.html + const double L = static_cast(luminosity); + double inner = std::sqrt(L / 1.1); + double outer = std::sqrt(L / 0.53); + return glm::dvec4(inner, inner, outer, outer); + } + + struct Coefficients { + double seffSun; + double a; + double b; + double c; + double d; + }; + + // Coefficients for planets of 1 Earth mass. Received from: + // https://depts.washington.edu/naivpl/sites/default/files/HZ_coefficients.dat + constexpr const Coefficients coefficients[] = { + // Optimistic Inner boundary - Recent Venus + {1.77600E+00, 2.13600E-04, 2.53300E-08, -1.33200E-11, -3.09700E-15}, + // Conservative Inner boundary - Runaway greenhouse + {1.10700E+00, 1.33200E-04, 1.58000E-08, -8.30800E-12, -1.93100E-15}, + // Conservative Outer boundary - Maximum greenhouse + {3.56000E-01, 6.17100E-05, 1.69800E-09, -3.19800E-12, -5.57500E-16}, + // Optimistic Outer boundary - Early Mars + {3.20000E-01, 5.54700E-05, 1.52600E-09, -2.87400E-12, -5.01100E-16} + }; + + const double tstar = static_cast(teff - 5780.f); + const double tstar2 = tstar * tstar; + const double L = static_cast(luminosity); + + glm::dvec4 distances; + for (int i = 0; i < 4; ++i) { + const Coefficients& coeffs = coefficients[i]; + double seff = coeffs.seffSun + (coeffs.a * tstar) + (coeffs.b * tstar2) + + (coeffs.c * tstar * tstar2) + (coeffs.d * tstar2 * tstar2); + + distances[i] = std::pow(L / seff, 0.5); + } + + return distances; +} + +} // namespace openspace diff --git a/modules/space/rendering/renderablehabitablezone.h b/modules/space/rendering/renderablehabitablezone.h new file mode 100644 index 0000000000..6aa5d7f31b --- /dev/null +++ b/modules/space/rendering/renderablehabitablezone.h @@ -0,0 +1,75 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_MODULE_EXOPLANETS___RENDERABLEHABITABLEZONE___H__ +#define __OPENSPACE_MODULE_EXOPLANETS___RENDERABLEHABITABLEZONE___H__ + +#include +#include +#include +#include + +namespace openspace { + +namespace documentation { struct Documentation; } + +class RenderableHabitableZone : public RenderableDisc { +public: + RenderableHabitableZone(const ghoul::Dictionary& dictionary); + + void render(const RenderData& data, RendererTasks& rendererTask) override; + + static documentation::Documentation Documentation(); + +private: + void initializeShader() override; + void updateUniformLocations() override; + void computeZone(); + + /** + * Compute the inner and outer boundary of the habitable zone of a star, according to + * formula and coefficients by Kopparapu et al. (2015) https://arxiv.org/abs/1404.5292 + * + * \param teff The effective temperature of the star, in Kelvin + * \param luminosity The luminosity of the star, in solar luminosities + * \return A vec4 with the boundaries in atronomical units, in the order: + optimistic inner, conservative inner, conservative outer, optimistic outer + */ + glm::dvec4 computeKopparapuZoneBoundaries(float teff, float luminosity); + + properties::FloatProperty _teff; + properties::FloatProperty _luminosity; + properties::BoolProperty _showOptimistic; + + properties::Vec2Property _kopparapuTeffInterval; + + glm::vec2 _conservativeBounds; + + UniformCache(modelViewProjection, opacity, width, texture, + conservativeBounds, showOptimistic) _uniformCache; +}; + +} // namespace openspace + +#endif // __OPENSPACE_MODULE_EXOPLANETS___RENDERABLEHABITABLEZONE___H__ diff --git a/modules/space/rendering/renderablerings.cpp b/modules/space/rendering/renderablerings.cpp index a8684960ea..6e45f719b6 100644 --- a/modules/space/rendering/renderablerings.cpp +++ b/modules/space/rendering/renderablerings.cpp @@ -36,6 +36,7 @@ #include #include #include +#include namespace { constexpr const std::array UniformNames = { @@ -79,53 +80,32 @@ namespace { "This value affects the filtering out of part of the rings depending on the " "color values of the texture. The higher value, the more rings are filtered out." }; + + struct [[codegen::Dictionary(RenderableRings)]] Parameters { + // [[codegen::verbatim(TextureInfo.description)]] + std::string texture; + + // [[codegen::verbatim(SizeInfo.description)]] + float size; + + // [[codegen::verbatim(OffsetInfo.description)]] + std::optional offset; + + // [[codegen::verbatim(NightFactorInfo.description)]] + std::optional nightFactor; + + // [[codegen::verbatim(ColorFilterInfo.description)]] + std::optional colorFilter; + }; +#include "renderablerings_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableRings::Documentation() { - using namespace documentation; - return { - "Renderable Rings", - "space_renderable_rings", - { - { - "Type", - new StringEqualVerifier("RenderableRings"), - Optional::No - }, - { - TextureInfo.identifier, - new StringVerifier, - Optional::No, - TextureInfo.description - }, - { - SizeInfo.identifier, - new DoubleVerifier, - Optional::No, - SizeInfo.description - }, - { - OffsetInfo.identifier, - new DoubleVector2Verifier, - Optional::Yes, - OffsetInfo.description - }, - { - NightFactorInfo.identifier, - new DoubleVerifier, - Optional::Yes, - NightFactorInfo.description - }, - { - ColorFilterInfo.identifier, - new DoubleVerifier, - Optional::Yes, - ColorFilterInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "space_renderable_rings"; + return doc; } RenderableRings::RenderableRings(const ghoul::Dictionary& dictionary) @@ -138,23 +118,17 @@ RenderableRings::RenderableRings(const ghoul::Dictionary& dictionary) { using ghoul::filesystem::File; - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableRings" - ); + const Parameters p = codegen::bake(dictionary); - _size = static_cast(dictionary.value(SizeInfo.identifier)); + _size = p.size; setBoundingSphere(_size); _size.onChange([&]() { _planeIsDirty = true; }); addProperty(_size); - _texturePath = absPath(dictionary.value(TextureInfo.identifier)); + _texturePath = absPath(p.texture); _textureFile = std::make_unique(_texturePath); - if (dictionary.hasValue(OffsetInfo.identifier)) { - _offset = dictionary.value(OffsetInfo.identifier); - } + _offset = p.offset.value_or(_offset); addProperty(_offset); _texturePath.onChange([&]() { loadTexture(); }); @@ -162,18 +136,10 @@ RenderableRings::RenderableRings(const ghoul::Dictionary& dictionary) _textureFile->setCallback([&](const File&) { _textureIsDirty = true; }); - if (dictionary.hasValue(NightFactorInfo.identifier)) { - _nightFactor = static_cast( - dictionary.value(NightFactorInfo.identifier) - ); - } + _nightFactor = p.nightFactor.value_or(_nightFactor); addProperty(_nightFactor); - if (dictionary.hasValue(ColorFilterInfo.identifier)) { - _colorFilter = static_cast( - dictionary.value(ColorFilterInfo.identifier) - ); - } + _colorFilter = p.colorFilter.value_or(_colorFilter); addProperty(_colorFilter); } diff --git a/modules/space/rendering/renderablesatellites.cpp b/modules/space/rendering/renderablesatellites.cpp index 19430ce7ca..c50736ad34 100644 --- a/modules/space/rendering/renderablesatellites.cpp +++ b/modules/space/rendering/renderablesatellites.cpp @@ -74,53 +74,42 @@ namespace { "Trail Fade", "This value determines how fast the trail fades and is an appearance property. " }; + + struct [[codegen::Dictionary(RenderableSatellites)]] Parameters { + // [[codegen::verbatim(SegmentsInfo.description)]] + double segments; + + // [[codegen::verbatim(PathInfo.description)]] + std::string path; + + // [[codegen::verbatim(LineWidthInfo.description)]] + std::optional lineWidth; + + // [[codegen::verbatim(LineColorInfo.description)]] + glm::dvec3 color; + + // [[codegen::verbatim(TrailFadeInfo.description)]] + std::optional trailFade; + }; +#include "renderablesatellites_codegen.cpp" } namespace openspace { documentation::Documentation RenderableSatellites::Documentation() { - using namespace documentation; - return { - "RenderableSatellites", - "space_renderable_satellites", - { - { - SegmentsInfo.identifier, - new DoubleVerifier, - Optional::No, - SegmentsInfo.description - }, - { - PathInfo.identifier, - new StringVerifier, - Optional::No, - PathInfo.description - }, - { - LineWidthInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LineWidthInfo.description - }, - { - LineColorInfo.identifier, - new DoubleVector3Verifier, - Optional::No, - LineColorInfo.description - }, - { - TrailFadeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - TrailFadeInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "space_renderable_satellites"; + return doc; } RenderableSatellites::RenderableSatellites(const ghoul::Dictionary& dictionary) : RenderableOrbitalKepler(dictionary) -{} +{ + // Commented out right now as its not super clear how it works with inheritance. We'd + // probably want a codegen::check function that only does the checking without + // actually creating a Parameter objects + // codegen::bake(dictionary); +} void RenderableSatellites::readDataFile(const std::string& filename) { if (!FileSys.fileExists(filename)) { diff --git a/modules/space/rendering/renderablesmallbody.cpp b/modules/space/rendering/renderablesmallbody.cpp index 49fc5633a3..6963d03a9c 100644 --- a/modules/space/rendering/renderablesmallbody.cpp +++ b/modules/space/rendering/renderablesmallbody.cpp @@ -104,59 +104,42 @@ namespace { name.erase(name.find_last_not_of(trimChars) + 1); return name; } + + struct [[codegen::Dictionary(RenderableSmallBody)]] Parameters { + // [[codegen::verbatim(SegmentQualityInfo.description)]] + double segmentQuality; + + // [[codegen::verbatim(UpperLimitInfo.description)]] + std::optional upperLimit; + + // [[codegen::verbatim(PathInfo.description)]] + std::string path; + + // [[codegen::verbatim(LineWidthInfo.description)]] + std::optional lineWidth; + + // [[codegen::verbatim(LineColorInfo.description)]] + glm::dvec3 color; + + // [[codegen::verbatim(TrailFadeInfo.description)]] + std::optional trailFade; + }; +#include "renderablesmallbody_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableSmallBody::Documentation() { - using namespace documentation; - return { - "RenderableSmallBody", - "space_renderable_small_body", - { - { - SegmentQualityInfo.identifier, - new DoubleVerifier, - Optional::No, - SegmentQualityInfo.description - }, - { - UpperLimitInfo.identifier, - new IntVerifier, - Optional::Yes, - UpperLimitInfo.description - }, - { - PathInfo.identifier, - new StringVerifier, - Optional::No, - PathInfo.description - }, - { - LineWidthInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LineWidthInfo.description - }, - { - LineColorInfo.identifier, - new DoubleVector3Verifier, - Optional::No, - LineColorInfo.description - }, - { - TrailFadeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - TrailFadeInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "space_renderable_small_body"; + return doc; } RenderableSmallBody::RenderableSmallBody(const ghoul::Dictionary& dictionary) : RenderableOrbitalKepler(dictionary) { + codegen::bake(dictionary); + _upperLimitCallbackHandle = _upperLimit.onChange(_reinitializeTrailBuffers); addProperty(_upperLimit); } diff --git a/modules/space/rendering/renderablestars.cpp b/modules/space/rendering/renderablestars.cpp index 8233058ea5..c1d159cb8e 100644 --- a/modules/space/rendering/renderablestars.cpp +++ b/modules/space/rendering/renderablestars.cpp @@ -51,10 +51,6 @@ namespace { constexpr const char* _loggerCat = "RenderableStars"; - constexpr const char* KeyFile = "File"; - constexpr const char* KeyStaticFilterValue = "StaticFilter"; - constexpr const char* KeyStaticFilterReplacement = "StaticFilterReplacement"; - constexpr const std::array UniformNames = { "modelMatrix", "cameraUp", "cameraViewProjectionMatrix", "colorOption", "magnitudeExponent", "eyePosition", "psfParamConf", @@ -309,120 +305,71 @@ namespace { "Disable Fade-in effect", "Enables/Disables the Fade-in effect." }; + + struct [[codegen::Dictionary(RenderableStars)]] Parameters { + // The path to the SPECK file containing information about the stars being rendered + std::string speckFile [[codegen::key("File")]]; + + // [[codegen::verbatim(ColorTextureInfo.description)]] + std::string colorMap; + + enum class ColorOption { + Color, + Velocity, + Speed, + OtherData [[codegen::key("Other Data")]], + FixedColor [[codegen::key("Fixed Color")]] + }; + // [[codegen::verbatim(ColorOptionInfo.description)]] + std::optional colorOption; + + // [[codegen::verbatim(OtherDataOptionInfo.description)]] + std::optional otherData; + + // [[codegen::verbatim(OtherDataColorMapInfo.description)]] + std::optional otherDataColorMap; + + // [[codegen::verbatim(FilterOutOfRangeInfo.description)]] + std::optional filterOutOfRange; + + // This value specifies a value that is always filtered out of the value ranges on + // loading. This can be used to trim the dataset's automatic value range + std::optional staticFilter; + + // This is the value that is used to replace statically filtered values. Setting this + // value only makes sense if 'StaticFilter' is 'true', as well + std::optional staticFilterReplacement; + + // [[codegen::verbatim(MagnitudeExponentInfo.description)]] + std::optional magnitudeExponent; + + // [[codegen::verbatim(EnableTestGridInfo.description)]] + std::optional enableTestGrid; + + // [[codegen::verbatim(RenderMethodOptionInfo.description)]] + std::string renderMethod; + + // [[codegen::verbatim(PsfTextureInfo.description)]] + std::string texture; + + // [[codegen::verbatim(SizeCompositionOptionInfo.description)]] + std::optional sizeComposition; + + // [[codegen::verbatim(FadeInDistancesInfo.description)]] + std::optional fadeInDistances; + + // [[codegen::verbatim(DisableFadeInInfo.description)]] + std::optional distableFadeIn; + }; +#include "renderablestars_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableStars::Documentation() { - using namespace documentation; - return { - "RenderableStars", - "space_renderablestars", - { - { - "Type", - new StringEqualVerifier("RenderableStars"), - Optional::No - }, - { - KeyFile, - new StringVerifier, - Optional::No, - "The path to the SPECK file that contains information about the stars " - "being rendered." - }, - { - ColorTextureInfo.identifier, - new StringVerifier, - Optional::No, - ColorTextureInfo.description - }, - /*{ - ShapeTextureInfo.identifier, - new StringVerifier, - Optional::No, - ShapeTextureInfo.description - },*/ - { - ColorOptionInfo.identifier, - new StringInListVerifier({ - "Color", "Velocity", "Speed", "Other Data", "Fixed Color" - }), - Optional::Yes, - ColorOptionInfo.description - }, - { - OtherDataOptionInfo.identifier, - new StringVerifier, - Optional::Yes, - OtherDataOptionInfo.description - }, - { - OtherDataColorMapInfo.identifier, - new StringVerifier, - Optional::Yes, - OtherDataColorMapInfo.description - }, - { - FilterOutOfRangeInfo.identifier, - new BoolVerifier, - Optional::Yes, - FilterOutOfRangeInfo.description - }, - { - KeyStaticFilterValue, - new DoubleVerifier, - Optional::Yes, - "This value specifies a value that is always filtered out of the value " - "ranges on loading. This can be used to trim the dataset's automatic " - "value range." - }, - { - KeyStaticFilterReplacement, - new DoubleVerifier, - Optional::Yes, - "This is the value that is used to replace statically filtered values. " - "Setting this value only makes sense if 'StaticFilter' is 'true', as " - "well." - }, - { - MagnitudeExponentInfo.identifier, - new DoubleVerifier, - Optional::Yes, - MagnitudeExponentInfo.description - }, - { - EnableTestGridInfo.identifier, - new BoolVerifier, - Optional::Yes, - EnableTestGridInfo.description - }, - { - RenderMethodOptionInfo.identifier, - new StringVerifier, - Optional::No, - RenderMethodOptionInfo.description - }, - { - SizeCompositionOptionInfo.identifier, - new StringVerifier, - Optional::No, - SizeCompositionOptionInfo.description - }, - { - FadeInDistancesInfo.identifier, - new Vector2Verifier, - Optional::Yes, - FadeInDistancesInfo.description - }, - { - DisableFadeInInfo.identifier, - new BoolVerifier, - Optional::Yes, - DisableFadeInInfo.description - }, - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "space_renderablestars"; + return doc; } RenderableStars::RenderableStars(const ghoul::Dictionary& dictionary) @@ -482,22 +429,16 @@ RenderableStars::RenderableStars(const ghoul::Dictionary& dictionary) { using File = ghoul::filesystem::File; - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableStars" - ); + const Parameters p = codegen::bake(dictionary); addProperty(_opacity); registerUpdateRenderBinFromOpacity(); - _speckFile = absPath(dictionary.value(KeyFile)); + _speckFile = absPath(p.speckFile); _speckFile.onChange([&]() { _speckFileIsDirty = true; }); addProperty(_speckFile); - _colorTexturePath = absPath( - dictionary.value(ColorTextureInfo.identifier) - ); + _colorTexturePath = absPath(p.colorMap); _colorTextureFile = std::make_unique(_colorTexturePath); /*_shapeTexturePath = absPath(dictionary.value( @@ -505,10 +446,8 @@ RenderableStars::RenderableStars(const ghoul::Dictionary& dictionary) )); _shapeTextureFile = std::make_unique(_shapeTexturePath);*/ - if (dictionary.hasKey(OtherDataColorMapInfo.identifier)) { - _otherDataColorMapPath = absPath( - dictionary.value(OtherDataColorMapInfo.identifier) - ); + if (p.otherDataColorMap.has_value()) { + _otherDataColorMapPath = absPath(*p.otherDataColorMap); } _fixedColor.setViewOption(properties::Property::ViewOptions::Color, true); @@ -521,24 +460,23 @@ RenderableStars::RenderableStars(const ghoul::Dictionary& dictionary) { ColorOption::OtherData, "Other Data" }, { ColorOption::FixedColor, "Fixed Color" } }); - if (dictionary.hasKey(ColorOptionInfo.identifier)) { - const std::string colorOption = dictionary.value( - ColorOptionInfo.identifier - ); - if (colorOption == "Color") { - _colorOption = ColorOption::Color; - } - else if (colorOption == "Velocity") { - _colorOption = ColorOption::Velocity; - } - else if (colorOption == "Speed") { - _colorOption = ColorOption::Speed; - } - else if (colorOption == "OtherData") { - _colorOption = ColorOption::OtherData; - } - else { - _colorOption = ColorOption::FixedColor; + if (p.colorOption.has_value()) { + switch (*p.colorOption) { + case Parameters::ColorOption::Color: + _colorOption = ColorOption::Color; + break; + case Parameters::ColorOption::Velocity: + _colorOption = ColorOption::Velocity; + break; + case Parameters::ColorOption::Speed: + _colorOption = ColorOption::Speed; + break; + case Parameters::ColorOption::OtherData: + _colorOption = ColorOption::OtherData; + break; + case Parameters::ColorOption::FixedColor: + _colorOption = ColorOption::FixedColor; + break; } } _colorOption.onChange([&] { _dataIsDirty = true; }); @@ -556,13 +494,8 @@ RenderableStars::RenderableStars(const ghoul::Dictionary& dictionary) }); addProperty(_shapeTexturePath);*/ - if (dictionary.hasKey(EnableTestGridInfo.identifier)) { - _enableTestGrid = dictionary.value(EnableTestGridInfo.identifier); - } - - if (dictionary.hasKey(OtherDataOptionInfo.identifier)) { - _queuedOtherData = dictionary.value(OtherDataOptionInfo.identifier); - } + _enableTestGrid = p.enableTestGrid.value_or(_enableTestGrid); + _queuedOtherData = p.otherData.value_or(_queuedOtherData); _otherDataOption.onChange([&]() { _dataIsDirty = true; }); addProperty(_otherDataOption); @@ -572,16 +505,9 @@ RenderableStars::RenderableStars(const ghoul::Dictionary& dictionary) addProperty(_otherDataColorMapPath); _otherDataColorMapPath.onChange([&]() { _otherDataColorMapIsDirty = true; }); - if (dictionary.hasKey(KeyStaticFilterValue)) { - _staticFilterValue = static_cast( - dictionary.value(KeyStaticFilterValue) - ); - } - if (dictionary.hasKey(KeyStaticFilterReplacement)) { - _staticFilterReplacementValue = static_cast( - dictionary.value(KeyStaticFilterReplacement) - ); - } + _staticFilterValue = p.staticFilter; + _staticFilterReplacementValue = + p.staticFilterReplacement.value_or(_staticFilterReplacementValue); addProperty(_filterOutOfRange); @@ -592,23 +518,14 @@ RenderableStars::RenderableStars(const ghoul::Dictionary& dictionary) _renderingMethodOption.addOption(RenderOptionTexture, "Textured Based"); addProperty(_renderingMethodOption); - if (dictionary.hasKey(RenderMethodOptionInfo.identifier)) { - std::string renderingMethod = - dictionary.value(RenderMethodOptionInfo.identifier); - if (renderingMethod == "PSF") { - _renderingMethodOption = RenderOptionPointSpreadFunction; - } - else if (renderingMethod == "Texture Based") { - _renderingMethodOption = RenderOptionTexture; - } + if (p.renderMethod == "PSF") { + _renderingMethodOption = RenderOptionPointSpreadFunction; } - else { + else if (p.renderMethod == "Texture Based") { _renderingMethodOption = RenderOptionTexture; } - _pointSpreadFunctionTexturePath = absPath(dictionary.value( - PsfTextureInfo.identifier - )); + _pointSpreadFunctionTexturePath = absPath(p.texture); _pointSpreadFunctionFile = std::make_unique(_pointSpreadFunctionTexturePath); _pointSpreadFunctionTexturePath.onChange([&]() { _pointSpreadFunctionTextureIsDirty = true; @@ -631,26 +548,24 @@ RenderableStars::RenderableStars(const ghoul::Dictionary& dictionary) _psfMultiplyOption.addOption(4, "Apparent Magnitude"); _psfMultiplyOption.addOption(5, "Distance Modulus"); - if (dictionary.hasKey(MagnitudeExponentInfo.identifier)) { - std::string sizeCompositionOption = - dictionary.value(SizeCompositionOptionInfo.identifier); - if (sizeCompositionOption == "App Brightness") { + if (p.sizeComposition.has_value()) { + if (*p.sizeComposition == "App Brightness") { _psfMultiplyOption = 0; } - else if (sizeCompositionOption == "Lum and Size") { + else if (*p.sizeComposition == "Lum and Size") { _psfMultiplyOption = 1; } - else if (sizeCompositionOption == "Lum, Size and App Brightness") { + else if (*p.sizeComposition == "Lum, Size and App Brightness") { _psfMultiplyOption = 2; } - else if (sizeCompositionOption == "Abs Magnitude") { + else if (*p.sizeComposition == "Abs Magnitude") { _psfMultiplyOption = 3; } - else if (sizeCompositionOption == "App Maginitude") { + else if (*p.sizeComposition == "App Maginitude") { _psfMultiplyOption = 4; } - else if (sizeCompositionOption == "Distance Modulus") { + else if (*p.sizeComposition == "Distance Modulus") { _psfMultiplyOption = 5; } } @@ -663,11 +578,7 @@ RenderableStars::RenderableStars(const ghoul::Dictionary& dictionary) _parametersOwner.addProperty(_radiusCent); _parametersOwner.addProperty(_brightnessCent); - if (dictionary.hasKey(MagnitudeExponentInfo.identifier)) { - _magnitudeExponent = static_cast( - dictionary.value(MagnitudeExponentInfo.identifier) - ); - } + _magnitudeExponent = p.magnitudeExponent.value_or(_magnitudeExponent); _parametersOwner.addProperty(_magnitudeExponent); auto renderPsf = [&]() { renderPSFToTexture(); }; @@ -693,8 +604,8 @@ RenderableStars::RenderableStars(const ghoul::Dictionary& dictionary) addPropertySubOwner(_parametersOwner); addPropertySubOwner(_moffatMethodOwner); - if (dictionary.hasKey(FadeInDistancesInfo.identifier)) { - glm::vec2 v = dictionary.value(FadeInDistancesInfo.identifier); + if (p.fadeInDistances.has_value()) { + glm::vec2 v = *p.fadeInDistances; _fadeInDistance = v; _disableFadeInDistance = false; addProperty(_fadeInDistance); diff --git a/modules/space/rendering/simplespheregeometry.cpp b/modules/space/rendering/simplespheregeometry.cpp index 0f39776640..5c4ed12ef9 100644 --- a/modules/space/rendering/simplespheregeometry.cpp +++ b/modules/space/rendering/simplespheregeometry.cpp @@ -1,4 +1,4 @@ -/**************************************************************************************** +/**************************************************************************************** * * * OpenSpace * * * @@ -41,30 +41,23 @@ namespace { "Segments", "This value specifies the number of segments that this sphere is split into." }; + + struct [[codegen::Dictionary(SimpleSphereGeometry)]] Parameters { + // [[codegen::verbatim(RadiusInfo.description)]] + std::variant radius; + + // [[codegen::verbatim(SegmentsInfo.description)]] + int segments; + }; +#include "simplespheregeometry_codegen.cpp" } // namespace namespace openspace::planetgeometry { documentation::Documentation SimpleSphereGeometry::Documentation() { - using namespace documentation; - return { - "SimpleSphereGeometry", - "space_geometry_simplesphere", - { - { - RadiusInfo.identifier, - new OrVerifier({ new DoubleVerifier, new DoubleVector3Verifier }), - Optional::No, - RadiusInfo.description - }, - { - SegmentsInfo.identifier, - new IntVerifier, - Optional::No, - SegmentsInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "space_geometry_simplesphere"; + return doc; } SimpleSphereGeometry::SimpleSphereGeometry(const ghoul::Dictionary& dictionary) @@ -72,23 +65,17 @@ SimpleSphereGeometry::SimpleSphereGeometry(const ghoul::Dictionary& dictionary) , _segments(SegmentsInfo, 20, 1, 5000) , _sphere(nullptr) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "SimpleSphereGeometry" - ); + const Parameters p = codegen::bake(dictionary); - if (dictionary.hasValue(RadiusInfo.identifier)) { - const float r = static_cast( - dictionary.value(RadiusInfo.identifier) - ); - _radius = { r, r, r }; + if (std::holds_alternative(p.radius)) { + const float radius = std::get(p.radius); + _radius = glm::dvec3(radius, radius, radius); } else { - _radius = dictionary.value(RadiusInfo.identifier); + _radius = std::get(p.radius); } - _segments = static_cast(dictionary.value(SegmentsInfo.identifier)); + _segments = p.segments; // The shader need the radii values but they are not changeable runtime // TODO: Possibly add a scaling property @AA diff --git a/modules/space/rotation/spicerotation.cpp b/modules/space/rotation/spicerotation.cpp index 3e1f0d51cc..02b1b025c0 100644 --- a/modules/space/rotation/spicerotation.cpp +++ b/modules/space/rotation/spicerotation.cpp @@ -29,10 +29,9 @@ #include #include #include +#include namespace { - constexpr const char* KeyKernels = "Kernels"; - constexpr openspace::properties::Property::PropertyInfo SourceInfo = { "SourceFrame", "Source", @@ -52,76 +51,49 @@ namespace { "Time Frame", "The time frame in which the spice kernels are valid." }; + + struct [[codegen::Dictionary(SpiceRotation)]] Parameters { + // [[codegen::verbatim(SourceInfo.description)]] + std::string sourceFrame + [[codegen::annotation("A valid SPICE NAIF name or integer")]]; + + // [[codegen::verbatim(DestinationInfo.description)]] + std::string destinationFrame; + + // [[codegen::verbatim(DestinationInfo.description)]] + std::optional, std::string>> kernels; + + // [[codegen::verbatim(TimeFrameInfo.description)]] + std::optional timeFrame [[codegen::reference("core_time_frame")]]; + }; +#include "spicerotation_codegen.cpp" } // namespace namespace openspace { documentation::Documentation SpiceRotation::Documentation() { - using namespace openspace::documentation; - return { - "Spice Rotation", - "space_transform_rotation_spice", - { - { - "Type", - new StringEqualVerifier("SpiceRotation"), - Optional::No - }, - { - SourceInfo.identifier, - new StringAnnotationVerifier("A valid SPICE NAIF name or integer"), - Optional::No, - SourceInfo.description - }, - { - DestinationInfo.identifier, - new StringAnnotationVerifier("A valid SPICE NAIF name or integer"), - Optional::No, - DestinationInfo.description - }, - { - KeyKernels, - new OrVerifier({ new StringListVerifier, new StringVerifier }), - Optional::Yes, - "A single kernel or list of kernels that this SpiceTranslation depends " - "on. All provided kernels will be loaded before any other operation is " - "performed." - }, - { - TimeFrameInfo.identifier, - new ReferencingVerifier("core_time_frame"), - Optional::Yes, - TimeFrameInfo.description - }, - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "space_transform_rotation_spice"; + return doc; } SpiceRotation::SpiceRotation(const ghoul::Dictionary& dictionary) : _sourceFrame(SourceInfo) , _destinationFrame(DestinationInfo) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "SpiceRotation" - ); + const Parameters p = codegen::bake(dictionary); - _sourceFrame = dictionary.value(SourceInfo.identifier); - _destinationFrame = dictionary.value(DestinationInfo.identifier); + _sourceFrame = p.sourceFrame; + _destinationFrame = p.destinationFrame; - if (dictionary.hasValue(KeyKernels)) { - SpiceManager::ref().loadKernel(dictionary.value(KeyKernels)); - } - else if (dictionary.hasValue(KeyKernels)) { - ghoul::Dictionary kernels = dictionary.value(KeyKernels); - for (size_t i = 1; i <= kernels.size(); ++i) { - if (!kernels.hasValue(std::to_string(i))) { - throw ghoul::RuntimeError("Kernels has to be an array-style table"); + if (p.kernels.has_value()) { + if (std::holds_alternative(*p.kernels)) { + SpiceManager::ref().loadKernel(std::get(*p.kernels)); + } + else { + for (const std::string& s : std::get>(*p.kernels)) { + SpiceManager::ref().loadKernel(s); } - - std::string kernel = kernels.value(std::to_string(i)); - SpiceManager::ref().loadKernel(kernel); } } @@ -130,7 +102,7 @@ SpiceRotation::SpiceRotation(const ghoul::Dictionary& dictionary) dictionary.value(TimeFrameInfo.identifier); _timeFrame = TimeFrame::createFromDictionary(timeFrameDictionary); if (_timeFrame == nullptr) { - throw ghoul::RuntimeError("Invalid dictionary for TimeFrame."); + throw ghoul::RuntimeError("Invalid dictionary for TimeFrame"); } addPropertySubOwner(_timeFrame.get()); } diff --git a/modules/space/shaders/habitablezone_fs.glsl b/modules/space/shaders/habitablezone_fs.glsl new file mode 100644 index 0000000000..11bcca4f3b --- /dev/null +++ b/modules/space/shaders/habitablezone_fs.glsl @@ -0,0 +1,87 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include "fragment.glsl" + +in vec2 vs_st; +in float vs_screenSpaceDepth; + +uniform sampler1D transferFunctionTexture; +uniform float width; +uniform float opacity; +uniform vec2 conservativeBounds; +uniform bool showOptimistic; + +// Remap the radius to texture coordinates in the trasfer function texture. The texture +// is treated as a linear scale where the color represent too cold to too hot. Account +// for the conservative bounds my mapping one third of the texture ouside each boundary. +// All parameters \in [0,1], where 1.0 corresponds to the max radius. +float computeTextureCoord(float radius, float innerRadius, + float conservativeInner, float conservativeOuter) +{ + const float t1 = 1.0 / 3.0; + const float t2 = 2.0 / 3.0; + + if (radius < conservativeInner) { + float t = (radius - innerRadius) / (conservativeInner - innerRadius); + return mix(0.0, t1, t); + } + else if (radius > conservativeOuter) { + float t = (radius - conservativeOuter) / (1.0 - conservativeOuter); + return mix(t2, 1.0, t); + } + else { + float t = (radius - conservativeInner) / (conservativeOuter - conservativeInner); + return mix(t1, t2, t); + } +} + +Fragment getFragment() { + // The length of the texture coordinates vector is our distance from the center + float radius = length(vs_st); + float innerRadius = 1.0 - width; + + // We only want to consider ring-like objects so we need to discard everything else + if (radius > 1.0 || radius < innerRadius) { + discard; + } + + float consInner = conservativeBounds.x; + float consOuter = conservativeBounds.y; + bool outsideConservative = (radius < consInner) || (radius > consOuter); + + if (!showOptimistic && outsideConservative) { + discard; + } + + float texCoord = computeTextureCoord(radius, innerRadius, consInner, consOuter); + + vec4 diffuse = texture(transferFunctionTexture, texCoord); + diffuse.a *= opacity; + + Fragment frag; + frag.color = diffuse; + frag.depth = vs_screenSpaceDepth; + return frag; +} diff --git a/modules/space/shaders/habitablezone_vs.glsl b/modules/space/shaders/habitablezone_vs.glsl new file mode 100644 index 0000000000..d5796d62d9 --- /dev/null +++ b/modules/space/shaders/habitablezone_vs.glsl @@ -0,0 +1,47 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#version __CONTEXT__ + +#include "PowerScaling/powerScaling_vs.hglsl" + +layout(location = 0) in vec2 in_position; +layout(location = 1) in vec2 in_st; + +out vec2 vs_st; +out float vs_screenSpaceDepth; + +uniform mat4 modelViewProjectionTransform; + +void main() { + vec4 position = vec4(in_position.xy, 0.0, 1.0); + vec4 positionScreenSpace = z_normalization(modelViewProjectionTransform * position); + + // Moving the origin to the center + vs_st = (in_st - vec2(0.5)) * 2.0; + + vs_screenSpaceDepth = positionScreenSpace.w; + + gl_Position = positionScreenSpace; +} diff --git a/modules/space/spacemodule.cpp b/modules/space/spacemodule.cpp index cdc90d3768..0ebba746cd 100644 --- a/modules/space/spacemodule.cpp +++ b/modules/space/spacemodule.cpp @@ -24,14 +24,13 @@ #include -#include #include +#include #include #include #include #include #include -//#include #include #include #include @@ -80,7 +79,7 @@ void SpaceModule::internalInitialize(const ghoul::Dictionary& dictionary) { fRenderable->registerClass( "RenderableConstellationBounds" ); - + fRenderable->registerClass("RenderableHabitableZone"); fRenderable->registerClass("RenderableRings"); fRenderable->registerClass("RenderableSatellites"); fRenderable->registerClass("RenderableSmallBody"); @@ -119,6 +118,7 @@ void SpaceModule::internalDeinitializeGL() { std::vector SpaceModule::documentations() const { return { RenderableConstellationBounds::Documentation(), + RenderableHabitableZone::Documentation(), RenderableRings::Documentation(), RenderableSatellites::Documentation(), RenderableSmallBody::Documentation(), diff --git a/modules/space/translation/horizonstranslation.cpp b/modules/space/translation/horizonstranslation.cpp index 3c71906207..6f294d3055 100644 --- a/modules/space/translation/horizonstranslation.cpp +++ b/modules/space/translation/horizonstranslation.cpp @@ -46,32 +46,22 @@ namespace { "This value is the path to the text file generated by Horizons with observer " "range and Galactiv longitude and latitude for different timestamps." }; + + struct [[codegen::Dictionary(HorizonsTranslation)]] Parameters { + // [[codegen::verbatim(HorizonsTextFileInfo.description)]] + std::string horizonsTextFile; + }; +#include "horizonstranslation_codegen.cpp" } // namespace namespace openspace { documentation::Documentation HorizonsTranslation::Documentation() { - using namespace documentation; - return { - "Horizons Translation", - "base_transform_translation_horizons", - { - { - "Type", - new StringEqualVerifier("HorizonsTranslation"), - Optional::No - }, - { - HorizonsTextFileInfo.identifier, - new StringVerifier, - Optional::No, - HorizonsTextFileInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_transform_translation_horizons"; + return doc; } - HorizonsTranslation::HorizonsTranslation() : _horizonsTextFile(HorizonsTextFileInfo) { @@ -91,15 +81,8 @@ HorizonsTranslation::HorizonsTranslation() HorizonsTranslation::HorizonsTranslation(const ghoul::Dictionary& dictionary) : HorizonsTranslation() { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "HorizonsTranslation" - ); - - _horizonsTextFile = absPath( - dictionary.value(HorizonsTextFileInfo.identifier) - ); + const Parameters p = codegen::bake(dictionary); + _horizonsTextFile = absPath(p.horizonsTextFile); } glm::dvec3 HorizonsTranslation::position(const UpdateData& data) const { diff --git a/modules/space/translation/keplertranslation.cpp b/modules/space/translation/keplertranslation.cpp index 33ea61adeb..2dcedbe797 100644 --- a/modules/space/translation/keplertranslation.cpp +++ b/modules/space/translation/keplertranslation.cpp @@ -31,7 +31,6 @@ #include namespace { - template T solveIteration(const Func& function, T x0, const T& err = 0.0, int maxIter = 100) { T x2 = x0; @@ -105,6 +104,33 @@ namespace { "Orbit period", "Specifies the orbital period (in seconds)." }; + + struct [[codegen::Dictionary(KeplerTranslation)]] Parameters { + // [[codegen::verbatim(EccentricityInfo.description)]] + double eccentricity [[codegen::inrange(0.0, 1.0)]]; + + // [[codegen::verbatim(SemiMajorAxisInfo.description)]] + double semiMajorAxis; + + // [[codegen::verbatim(InclinationInfo.description)]] + double inclination [[codegen::inrange(0.0, 360.0)]]; + + // [[codegen::verbatim(AscendingNodeInfo.description)]] + double ascendingNode [[codegen::inrange(0.0, 360.0)]]; + + // [[codegen::verbatim(ArgumentOfPeriapsisInfo.description)]] + double argumentOfPeriapsis [[codegen::inrange(0.0, 360.0)]]; + + // [[codegen::verbatim(MeanAnomalyAtEpochInfo.description)]] + double meanAnomaly [[codegen::inrange(0.0, 360.0)]]; + + // [[codegen::verbatim(EpochInfo.description)]] + std::string epoch; + + // [[codegen::verbatim(PeriodInfo.description)]] + double period [[codegen::greater(0.0)]]; + }; +#include "keplertranslation_codegen.cpp" } // namespace namespace openspace { @@ -115,66 +141,9 @@ KeplerTranslation::RangeError::RangeError(std::string off) {} documentation::Documentation KeplerTranslation::Documentation() { - using namespace openspace::documentation; - return { - "Kepler Translation", - "space_transform_kepler", - { - { - "Type", - new StringEqualVerifier("KeplerTranslation"), - Optional::No - }, - { - EccentricityInfo.identifier, - new DoubleInRangeVerifier(0.0, 1.0), - Optional::No, - EccentricityInfo.description - }, - { - SemiMajorAxisInfo.identifier, - new DoubleVerifier, - Optional::No, - SemiMajorAxisInfo.description - }, - { - InclinationInfo.identifier, - new DoubleInRangeVerifier(0.0, 360.0), - Optional::No, - InclinationInfo.description - }, - { - AscendingNodeInfo.identifier, - new DoubleInRangeVerifier(0.0, 360.0), - Optional::No, - AscendingNodeInfo.description - }, - { - ArgumentOfPeriapsisInfo.identifier, - new DoubleInRangeVerifier(0.0, 360.0), - Optional::No, - ArgumentOfPeriapsisInfo.description - }, - { - MeanAnomalyAtEpochInfo.identifier, - new DoubleInRangeVerifier(0.0, 360.0), - Optional::No, - MeanAnomalyAtEpochInfo.description - }, - { - EpochInfo.identifier, - new StringVerifier, - Optional::No, - EpochInfo.description - }, - { - PeriodInfo.identifier, - new DoubleGreaterVerifier(0.0), - Optional::No, - PeriodInfo.description - }, - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "space_transform_kepler"; + return doc; } KeplerTranslation::KeplerTranslation() @@ -218,21 +187,17 @@ KeplerTranslation::KeplerTranslation() KeplerTranslation::KeplerTranslation(const ghoul::Dictionary& dictionary) : KeplerTranslation() { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "KeplerTranslation" - ); + const Parameters p = codegen::bake(dictionary); setKeplerElements( - dictionary.value(EccentricityInfo.identifier), - dictionary.value(SemiMajorAxisInfo.identifier), - dictionary.value(InclinationInfo.identifier), - dictionary.value(AscendingNodeInfo.identifier), - dictionary.value(ArgumentOfPeriapsisInfo.identifier), - dictionary.value(MeanAnomalyAtEpochInfo.identifier), - dictionary.value(PeriodInfo.identifier), - dictionary.value(EpochInfo.identifier) + p.eccentricity, + p.semiMajorAxis, + p.inclination, + p.ascendingNode, + p.argumentOfPeriapsis, + p.meanAnomaly, + p.period, + p.epoch ); } diff --git a/modules/space/translation/spicetranslation.cpp b/modules/space/translation/spicetranslation.cpp index f286a1d904..519539d9d6 100644 --- a/modules/space/translation/spicetranslation.cpp +++ b/modules/space/translation/spicetranslation.cpp @@ -33,10 +33,9 @@ #include #include #include +#include namespace { - constexpr const char* KeyKernels = "Kernels"; - constexpr const char* DefaultReferenceFrame = "GALACTIC"; constexpr openspace::properties::Property::PropertyInfo TargetInfo = { @@ -61,54 +60,32 @@ namespace { "This is the SPICE NAIF name for the reference frame in which the position " "should be retrieved. The default value is GALACTIC." }; + + struct [[codegen::Dictionary(SpiceTranslation)]] Parameters { + // [[codegen::verbatim(TargetInfo.description)]] + std::string target + [[codegen::annotation("A valid SPICE NAIF name or identifier")]]; + + // [[codegen::verbatim(ObserverInfo.description)]] + std::string observer + [[codegen::annotation("A valid SPICE NAIF name or identifier")]]; + + std::optional frame + [[codegen::annotation("A valid SPICE NAIF name for a reference frame")]]; + + // A single kernel or list of kernels that this SpiceTranslation depends on. All + // provided kernels will be loaded before any other operation is performed + std::optional, std::string>> kernels; + }; +#include "spicetranslation_codegen.cpp" } // namespace namespace openspace { documentation::Documentation SpiceTranslation::Documentation() { - using namespace openspace::documentation; - - return { - "Spice Translation", - "space_translation_spicetranslation", - { - { - "Type", - new StringEqualVerifier("SpiceTranslation"), - Optional::No - }, - { - TargetInfo.identifier, - new StringAnnotationVerifier("A valid SPICE NAIF name or identifier"), - Optional::No, - "This is the SPICE NAIF name for the body whose translation is to be " - "computed by the SpiceTranslation. It can either be a fully qualified " - "name (such as 'EARTH') or a NAIF integer id code (such as '399')." - }, - { - ObserverInfo.identifier, - new StringAnnotationVerifier("A valid SPICE NAIF name or identifier"), - Optional::No, - ObserverInfo.description - }, - { - FrameInfo.identifier, - new StringAnnotationVerifier( - "A valid SPICE NAIF name for a reference frame" - ), - Optional::Yes, - FrameInfo.description - }, - { - KeyKernels, - new OrVerifier({ new StringListVerifier, new StringVerifier }), - Optional::Yes, - "A single kernel or list of kernels that this SpiceTranslation depends " - "on. All provided kernels will be loaded before any other operation is " - "performed." - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "space_translation_spicetranslation"; + return doc; } SpiceTranslation::SpiceTranslation(const ghoul::Dictionary& dictionary) @@ -117,15 +94,13 @@ SpiceTranslation::SpiceTranslation(const ghoul::Dictionary& dictionary) , _frame(FrameInfo, DefaultReferenceFrame) , _cachedFrame(DefaultReferenceFrame) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "SpiceTranslation" - ); + const Parameters p = codegen::bake(dictionary); auto loadKernel = [](const std::string& kernel) { if (!FileSys.fileExists(kernel)) { - throw SpiceManager::SpiceException("Kernel '" + kernel + "' does not exist"); + throw SpiceManager::SpiceException(fmt::format( + "Kernel '{}' does not exist", kernel + )); } try { @@ -136,17 +111,13 @@ SpiceTranslation::SpiceTranslation(const ghoul::Dictionary& dictionary) } }; - if (dictionary.hasKey(KeyKernels)) { - // Due to the specification, we can be sure it is either a Dictionary or a string - if (dictionary.hasValue(KeyKernels)) { - std::string kernel = dictionary.value(KeyKernels); - loadKernel(absPath(kernel)); + if (p.kernels.has_value()) { + if (std::holds_alternative(*p.kernels)) { + loadKernel(absPath(std::get(*p.kernels))); } else { - ghoul::Dictionary kernels = dictionary.value(KeyKernels); - for (size_t i = 1; i <= kernels.size(); ++i) { - std::string kernel = kernels.value(std::to_string(i)); - loadKernel(absPath(kernel)); + for (const std::string& k : std::get>(*p.kernels)) { + loadKernel(absPath(k)); } } } @@ -172,12 +143,9 @@ SpiceTranslation::SpiceTranslation(const ghoul::Dictionary& dictionary) }); addProperty(_frame); - _target = dictionary.value(TargetInfo.identifier); - _observer = dictionary.value(ObserverInfo.identifier); - - if (dictionary.hasKey(FrameInfo.identifier)) { - _frame = dictionary.value(FrameInfo.identifier); - } + _target = p.target; + _observer = p.observer; + _frame = p.frame.value_or(_frame); } glm::dvec3 SpiceTranslation::position(const UpdateData& data) const { diff --git a/modules/space/translation/tletranslation.cpp b/modules/space/translation/tletranslation.cpp index 4d6698b7a5..83f5794355 100644 --- a/modules/space/translation/tletranslation.cpp +++ b/modules/space/translation/tletranslation.cpp @@ -29,12 +29,10 @@ #include #include #include +#include #include namespace { - constexpr const char* KeyFile = "File"; - constexpr const char* KeyLineNumber = "LineNumber"; - // The list of leap years only goes until 2056 as we need to touch this file then // again anyway ;) const std::vector LeapYears = { @@ -211,52 +209,32 @@ namespace { // We need the semi major axis in km instead of m return semiMajorAxis / 1000.0; } -} // namespace + struct [[codegen::Dictionary(TLETranslation)]] Parameters { + // Specifies the filename of the Two-Line-Element file + std::string file; + + // Specifies the line number within the file where the group of 3 TLE lines begins + // (1-based). Defaults to 1 + std::optional lineNumber [[codegen::greater(0)]]; + }; +#include "tletranslation_codegen.cpp" +} // namespace namespace openspace { documentation::Documentation TLETranslation::Documentation() { - using namespace openspace::documentation; - return { - "TLE Translation", - "space_transform_tle", - { - { - "Type", - new StringEqualVerifier("TLETranslation"), - Optional::No - }, - { - KeyFile, - new StringVerifier, - Optional::No, - "Specifies the filename of the Two-Line-Element file" - }, - { - KeyLineNumber, - new DoubleGreaterVerifier(0), - Optional::Yes, - "Specifies the line number within the file where the group of 3 TLE " - "lines begins (1-based). Defaults to 1." - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "space_transform_tle"; + return doc; } TLETranslation::TLETranslation(const ghoul::Dictionary& dictionary) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "TLETranslation" - ); + const Parameters p = codegen::bake(dictionary); - const std::string& file = dictionary.value(KeyFile); - int lineNum = 1; - if (dictionary.hasValue(KeyLineNumber)) { - lineNum = static_cast(dictionary.value(KeyLineNumber)); - } - readTLEFile(file, lineNum); + + int lineNum = p.lineNumber.value_or(1); + readTLEFile(p.file, lineNum); } void TLETranslation::readTLEFile(const std::string& filename, int lineNum) { diff --git a/modules/spacecraftinstruments/dashboard/dashboarditeminstruments.cpp b/modules/spacecraftinstruments/dashboard/dashboarditeminstruments.cpp index 30496b6822..b8371ac55e 100644 --- a/modules/spacecraftinstruments/dashboard/dashboarditeminstruments.cpp +++ b/modules/spacecraftinstruments/dashboard/dashboarditeminstruments.cpp @@ -87,47 +87,29 @@ namespace { glm::vec2 addToBoundingbox(glm::vec2 lhs, glm::vec2 rhs) { return { std::max(lhs.x, rhs.x), lhs.y + rhs.y }; } + + struct [[codegen::Dictionary(DashboardItemInstruments)]] Parameters { + // [[codegen::verbatim(FontNameInfo.description)]] + std::optional fontName; + + // [[codegen::verbatim(FontSizeInfo.description)]] + std::optional fontSize; + + // [[codegen::verbatim(ActiveColorInfo.description)]] + std::optional activeColor; + + // [[codegen::verbatim(FlashColorInfo.description)]] + std::optional flashColor; + }; +#include "dashboarditeminstruments_codegen.cpp" } // namespace namespace openspace { documentation::Documentation DashboardItemInstruments::Documentation() { - using namespace documentation; - return { - "DashboardItem Instruments", - "spacecraftinstruments_dashboarditem_instuments", - { - { - "Type", - new StringEqualVerifier("DashboardItemInstruments"), - Optional::No - }, - { - FontNameInfo.identifier, - new StringVerifier, - Optional::Yes, - FontNameInfo.description - }, - { - FontSizeInfo.identifier, - new IntVerifier, - Optional::Yes, - FontSizeInfo.description - }, - { - ActiveColorInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - ActiveColorInfo.description - }, - { - FlashColorInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - FlashColorInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "spacecraftinstruments_dashboarditem_instuments"; + return doc; } DashboardItemInstruments::DashboardItemInstruments(const ghoul::Dictionary& dictionary) @@ -147,24 +129,15 @@ DashboardItemInstruments::DashboardItemInstruments(const ghoul::Dictionary& dict ) , _font(global::fontManager->font(KeyFontMono, 10)) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "DashboardItemInstruments" - ); - - if (dictionary.hasKey(FontNameInfo.identifier)) { - _fontName = dictionary.value(FontNameInfo.identifier); - } - if (dictionary.hasKey(FontSizeInfo.identifier)) { - _fontSize = static_cast(dictionary.value(FontSizeInfo.identifier)); - } + const Parameters p = codegen::bake(dictionary); + _fontName = p.fontName.value_or(_fontName); _fontName.onChange([this]() { _font = global::fontManager->font(_fontName, _fontSize); }); addProperty(_fontName); + _fontSize = p.fontSize.value_or(_fontSize); _fontSize.onChange([this]() { _font = global::fontManager->font(_fontName, _fontSize); }); diff --git a/modules/spacecraftinstruments/rendering/renderablefov.cpp b/modules/spacecraftinstruments/rendering/renderablefov.cpp index b3c4cf58d8..25111acf83 100644 --- a/modules/spacecraftinstruments/rendering/renderablefov.cpp +++ b/modules/spacecraftinstruments/rendering/renderablefov.cpp @@ -152,6 +152,48 @@ namespace { return 0.5 * bisect(p1, half, testFunction, half); } } + // Needs support for std::map first for the frameConversions +// struct [[codegen::Dictionary(RenderableFov)]] Parameters { +// // The SPICE name of the source body for which the field of view should be +// // rendered +// std::string body; +// +// // The SPICE name of the source body's frame in which the field of view should be +// // rendered +// std::string frame; +// +// struct Instrument { +// // The SPICE name of the instrument that is rendered +// std::string name; +// +// // The aberration correction that is used for this field of view. The default +// // is 'NONE' +// std::optional aberration [[codegen::inlist("NONE", +// "LT", "LT+S", "CN", "CN+S", "XLT", "XLT+S", "XCN", "XCN+S")]]; +// }; +// // A table describing the instrument whose field of view should be rendered +// Instrument instrument; +// +// // A list of potential targets (specified as SPICE names) that the field of view +// // should be tested against +// std::vector potentialTargets; +// +// // A list of frame conversions that should be registered with the SpiceManager +// std::optional> frameConversions; +// +// // [[codegen::verbatim(LineWidthInfo.description)]] +// std::optional lineWidth; +// +// // [[codegen::verbatim(StandoffDistanceInfo.description)]] +// std::optional standOffDistance; +// +// // If this value is set to 'true' the field-of-views bounds values will be +// // simplified on load. Bound vectors will be removed if they are the strict linear +// // interpolation between the two neighboring vectors. This value is disabled on +// // default +// std::optional simplifyBounds; +// }; +//#include "renderablefov_codegen.cpp" } // namespace namespace openspace { diff --git a/modules/spacecraftinstruments/rendering/renderablemodelprojection.cpp b/modules/spacecraftinstruments/rendering/renderablemodelprojection.cpp index 6f960ce5c6..7e4222cf2a 100644 --- a/modules/spacecraftinstruments/rendering/renderablemodelprojection.cpp +++ b/modules/spacecraftinstruments/rendering/renderablemodelprojection.cpp @@ -81,11 +81,6 @@ documentation::Documentation RenderableModelProjection::Documentation() { "Renderable Model Projection", "newhorizons_renderable_modelprojection", { - { - "Type", - new StringEqualVerifier("RenderableModelProjection"), - Optional::No - }, { keyGeometry, new ReferencingVerifier("base_geometry_model"), diff --git a/modules/spacecraftinstruments/rendering/renderableplaneprojection.cpp b/modules/spacecraftinstruments/rendering/renderableplaneprojection.cpp index b93893b9e2..a165d84c5d 100644 --- a/modules/spacecraftinstruments/rendering/renderableplaneprojection.cpp +++ b/modules/spacecraftinstruments/rendering/renderableplaneprojection.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -40,6 +41,7 @@ #include #include #include +#include namespace { constexpr const char* _loggerCat = "RenderablePlaneProjection"; @@ -50,6 +52,16 @@ namespace { constexpr const char* KeyName = "Name"; constexpr const char* KeyTarget = "DefaultTarget"; constexpr const char* GalacticFrame = "GALACTIC"; + + struct [[codegen::Dictionary(RenderablePlaneProjection)]] Parameters { + std::optional spacecraft; + std::optional instrument; + std::optional moving; + std::optional name; + std::optional defaultTarget; + std::optional texture; + }; +#include "renderableplaneprojection_codegen.cpp" } // namespace namespace openspace { @@ -57,24 +69,15 @@ namespace openspace { RenderablePlaneProjection::RenderablePlaneProjection(const ghoul::Dictionary& dict) : Renderable(dict) { - if (dict.hasValue(KeySpacecraft)) { - _spacecraft = dict.value(KeySpacecraft); - } - if (dict.hasValue(KeyInstrument)) { - _instrument = dict.value(KeyInstrument); - } - if (dict.hasValue(KeyMoving)) { - _moving = dict.value(KeyMoving); - } - if (dict.hasValue(KeyName)) { - _name = dict.value(KeyName); - } - if (dict.hasValue(KeyTarget)) { - _defaultTarget = dict.value(KeyTarget); - } - if (dict.hasValue(KeyTexture)) { - _texturePath = dict.value(KeyTexture); - _texturePath = absPath(_texturePath); + const Parameters p = codegen::bake(dict); + _spacecraft = p.spacecraft.value_or(_spacecraft); + _instrument = p.instrument.value_or(_instrument); + _moving = p.moving.value_or(_moving); + _name = p.name.value_or(_name); + _defaultTarget = p.defaultTarget.value_or(_defaultTarget); + + if (p.texture.has_value()) { + _texturePath = absPath(*p.texture); _textureFile = std::make_unique(_texturePath); } } diff --git a/modules/spacecraftinstruments/rendering/renderableplanetprojection.cpp b/modules/spacecraftinstruments/rendering/renderableplanetprojection.cpp index cfcf3c0270..23ac686770 100644 --- a/modules/spacecraftinstruments/rendering/renderableplanetprojection.cpp +++ b/modules/spacecraftinstruments/rendering/renderableplanetprojection.cpp @@ -145,12 +145,6 @@ documentation::Documentation RenderablePlanetProjection::Documentation() { "Renderable Planet Projection", "newhorizons_renderable_planetprojection", { - { - "Type", - new StringEqualVerifier("RenderablePlanetProjection"), - Optional::No, - "" - }, { KeyGeometry, new ReferencingVerifier("space_geometry_planet"), diff --git a/modules/spacecraftinstruments/rendering/renderableshadowcylinder.cpp b/modules/spacecraftinstruments/rendering/renderableshadowcylinder.cpp index 32a766f256..4857d8d23d 100644 --- a/modules/spacecraftinstruments/rendering/renderableshadowcylinder.cpp +++ b/modules/spacecraftinstruments/rendering/renderableshadowcylinder.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include namespace { constexpr const char* ProgramName = "ShadowCylinderProgram"; @@ -104,85 +104,49 @@ namespace { "Aberration", "This value determines the aberration method that is used to compute the shadow " "cylinder." + }; + + struct [[codegen::Dictionary(RenderableShadowCylinder)]] Parameters { + // [[codegen::verbatim(NumberPointsInfo.description)]] + std::optional numberOfPoints [[codegen::key("AmountOfPoints")]]; + + // [[codegen::verbatim(ShadowLengthInfo.description)]] + std::optional shadowLength; + + // [[codegen::verbatim(ShadowColorInfo.description)]] + std::optional shadowColor; + + enum class TerminatorType { + Umbral [[codegen::key("UMBRAL")]], + Penumbral [[codegen::key("PENUMBRAL")]] + }; + // [[codegen::verbatim(TerminatorTypeInfo.description)]] + TerminatorType terminatorType; + + // [[codegen::verbatim(LightSourceInfo.description)]] + std::string lightSource; + + // [[codegen::verbatim(ObserverInfo.description)]] + std::string observer; + + // [[codegen::verbatim(BodyInfo.description)]] + std::string body; + + // [[codegen::verbatim(BodyFrameInfo.description)]] + std::string bodyFrame; + + // [[codegen::verbatim(AberrationInfo.description)]] + std::string aberration [[codegen::inlist("NONE", "LT", "LT+S", "CN", "CN+S")]]; }; +#include "renderableshadowcylinder_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableShadowCylinder::Documentation() { - using namespace documentation; - return { - "RenderableShadowCylinder", - "newhorizons_renderable_shadowcylinder", - { - { - "Type", - new StringEqualVerifier("RenderableShadowCylinder"), - Optional::No, - "" - }, - { - NumberPointsInfo.identifier, - new IntVerifier, - Optional::Yes, - NumberPointsInfo.description - }, - { - ShadowLengthInfo.identifier, - new DoubleVerifier, - Optional::Yes, - ShadowLengthInfo.description - }, - { - ShadowColorInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - ShadowColorInfo.description - }, - { - TerminatorTypeInfo.identifier, - new StringInListVerifier({ - // Synchronized with SpiceManager::terminatorTypeFromString - "UMBRAL", "PENUMBRAL" - }), - Optional::No, - TerminatorTypeInfo.description - }, - { - LightSourceInfo.identifier, - new StringVerifier, - Optional::No, - LightSourceInfo.description - }, - { - ObserverInfo.identifier, - new StringVerifier, - Optional::No, - ObserverInfo.description - }, - { - BodyInfo.identifier, - new StringVerifier, - Optional::No, - BodyInfo.description - }, - { - BodyFrameInfo.identifier, - new StringVerifier, - Optional::No, - BodyFrameInfo.description - }, - { - AberrationInfo.identifier, - new StringInListVerifier({ - // SpiceManager::AberrationCorrection::AberrationCorrection - "NONE", "LT", "LT+S", "CN", "CN+S" - }), - Optional::No, - AberrationInfo.description - }, - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "newhorizons_renderable_shadowcylinder"; + return doc; } RenderableShadowCylinder::RenderableShadowCylinder(const ghoul::Dictionary& dictionary) @@ -200,34 +164,18 @@ RenderableShadowCylinder::RenderableShadowCylinder(const ghoul::Dictionary& dict , _bodyFrame(BodyFrameInfo) , _aberration(AberrationInfo) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableShadowCylinder" - ); + const Parameters p = codegen::bake(dictionary); addProperty(_opacity); registerUpdateRenderBinFromOpacity(); - if (dictionary.hasKey(NumberPointsInfo.identifier)) { - _numberOfPoints = static_cast( - dictionary.value(NumberPointsInfo.identifier) - ); - } + _numberOfPoints = p.numberOfPoints.value_or(_numberOfPoints); addProperty(_numberOfPoints); - - if (dictionary.hasKey(ShadowLengthInfo.identifier)) { - _shadowLength = static_cast( - dictionary.value(ShadowLengthInfo.identifier) - ); - } + _shadowLength = p.shadowLength.value_or(_shadowLength); addProperty(_shadowLength); - - if (dictionary.hasKey(ShadowColorInfo.identifier)) { - _shadowColor = dictionary.value(ShadowLengthInfo.identifier); - } + _shadowColor = p.shadowColor.value_or(_shadowColor); _shadowColor.setViewOption(properties::Property::ViewOptions::Color); addProperty(_shadowColor); @@ -236,16 +184,21 @@ RenderableShadowCylinder::RenderableShadowCylinder(const ghoul::Dictionary& dict { static_cast(SpiceManager::TerminatorType::Umbral), "Umbral" }, { static_cast(SpiceManager::TerminatorType::Penumbral), "Penumbral" } }); - _terminatorType = static_cast(SpiceManager::terminatorTypeFromString( - dictionary.value(TerminatorTypeInfo.identifier) - )); + switch (p.terminatorType) { + case Parameters::TerminatorType::Umbral: + _terminatorType = static_cast(SpiceManager::TerminatorType::Umbral); + break; + case Parameters::TerminatorType::Penumbral: + _terminatorType = static_cast(SpiceManager::TerminatorType::Penumbral); + break; + } addProperty(_terminatorType); - _lightSource = dictionary.value(LightSourceInfo.identifier); - _observer = dictionary.value(ObserverInfo.identifier); - _body = dictionary.value(BodyInfo.identifier); - _bodyFrame = dictionary.value(BodyFrameInfo.identifier); + _lightSource = p.lightSource; + _observer = p.observer; + _body = p.body; + _bodyFrame = p.bodyFrame; using T = SpiceManager::AberrationCorrection::Type; _aberration.addOptions({ @@ -257,7 +210,7 @@ RenderableShadowCylinder::RenderableShadowCylinder(const ghoul::Dictionary& dict }); SpiceManager::AberrationCorrection aberration = SpiceManager::AberrationCorrection( - dictionary.value(AberrationInfo.identifier) + p.aberration ); _aberration = static_cast(aberration.type); } diff --git a/modules/spacecraftinstruments/util/instrumentdecoder.cpp b/modules/spacecraftinstruments/util/instrumentdecoder.cpp index 9527dd3f9e..a17d11f1f2 100644 --- a/modules/spacecraftinstruments/util/instrumentdecoder.cpp +++ b/modules/spacecraftinstruments/util/instrumentdecoder.cpp @@ -24,53 +24,43 @@ #include +#include +#include #include #include #include +#include namespace { constexpr const char* _loggerCat = "InstrumentDecoder"; - constexpr const char* KeyDetector = "DetectorType"; - constexpr const char* KeySpice = "Spice"; - constexpr const char* KeyStopCommand = "StopCommand"; + + struct [[codegen::Dictionary(InstrumentDecoder)]] Parameters { + std::string detectorType; + std::optional stopCommand; + std::vector spice; + }; +#include "instrumentdecoder_codegen.cpp" } // namespace namespace openspace { InstrumentDecoder::InstrumentDecoder(const ghoul::Dictionary& dictionary) { - if (dictionary.hasValue(KeyDetector)) { - _type = dictionary.value(KeyDetector); - std::for_each( - _type.begin(), - _type.end(), - [](char& in) { in = static_cast(toupper(in)); } - ); - } - else { - ghoul_assert(false, "Instrument has not provided detector type"); - throw ghoul::RuntimeError("Instrument has not provided detector type"); - } + const Parameters p = codegen::bake(dictionary); + _type = p.detectorType; + std::for_each( + _type.begin(), + _type.end(), + [](char& in) { in = static_cast(toupper(in)); } + ); - if (dictionary.hasValue(KeyStopCommand) && _type == "SCANNER") { - _stopCommand = dictionary.value(KeyStopCommand); + if (p.stopCommand.has_value() && _type == "SCANNER") { + _stopCommand = *p.stopCommand; } else { LWARNING("Scanner must provide stop command, please check mod file."); } - if (dictionary.hasValue(KeySpice)) { - ghoul::Dictionary spiceDictionary = dictionary.value(KeySpice); - - _spiceIDs.resize(spiceDictionary.size()); - for (size_t i = 0; i < _spiceIDs.size(); ++i) { - std::string id = spiceDictionary.value(std::to_string(i + 1)); - _spiceIDs[i] = std::move(id); - } - } - else { - ghoul_assert(false, "Instrument did not provide spice ids"); - throw ghoul::RuntimeError("Instrument has not provided detector type"); - } + _spiceIDs = p.spice; } const std::string& InstrumentDecoder::stopCommand() { diff --git a/modules/spacecraftinstruments/util/projectioncomponent.cpp b/modules/spacecraftinstruments/util/projectioncomponent.cpp index 472351fd74..83ef37f558 100644 --- a/modules/spacecraftinstruments/util/projectioncomponent.cpp +++ b/modules/spacecraftinstruments/util/projectioncomponent.cpp @@ -42,36 +42,12 @@ #include #include #include +#include +#include namespace { - constexpr const char* keyPotentialTargets = "PotentialTargets"; - - constexpr const char* keyInstrument = "Instrument.Name"; - constexpr const char* keyInstrumentFovy = "Instrument.Fovy"; - constexpr const char* keyInstrumentAspect = "Instrument.Aspect"; - constexpr const char* keyTranslation = "DataInputTranslation"; constexpr const char* keyTimesTranslation = "TimesDataInputTranslation"; - - constexpr const char* keyProjObserver = "Observer"; - constexpr const char* keyProjTarget = "Target"; - constexpr const char* keyProjAberration = "Aberration"; - - constexpr const char* keySequenceDir = "Sequence"; - constexpr const char* keyTimesSequenceDir = "TimesSequence"; - constexpr const char* keySequenceType = "SequenceType"; - - constexpr const char* keyNeedsTextureMapDilation = "TextureMap"; - constexpr const char* keyNeedsShadowing = "ShadowMap"; - constexpr const char* keyTextureMapAspectRatio = "AspectRatio"; - - constexpr const char* sequenceTypeImage = "image-sequence"; - constexpr const char* sequenceTypePlaybook = "playbook"; - constexpr const char* sequenceTypeHybrid = "hybrid"; - constexpr const char* sequenceTypeInstrumentTimes = "instrument-times"; - constexpr const char* sequenceTypeImageAndInstrumentTimes = - "image-and-instrument-times"; - constexpr const char* placeholderFile = "${DATA}/placeholder.png"; constexpr const char* _loggerCat = "ProjectionComponent"; @@ -113,115 +89,84 @@ namespace { "Triggering this property applies a new size to the underlying projection " "texture. The old texture is resized and interpolated to fit the new size." }; + + struct [[codegen::Dictionary(ProjectionComponent)]] Parameters { + // This value specifies one or more directories from which images are being used + // for image projections. If the sequence type is set to 'playbook', this value is + // ignored + std::optional>> sequence; + + struct Instrument { + // The instrument that is used to perform the projections + std::string name [[codegen::annotation("A SPICE name of an instrument")]]; + + // The field of view in degrees along the y axis + float fovy; + + // The aspect ratio of the instrument in relation between x and y axis + float aspect; + }; + Instrument instrument; + + enum class Type { + ImageSequence [[codegen::key("image-sequence")]], + Playbook [[codegen::key("playbook")]], + Hybrid [[codegen::key("hybrid")]], + InstrumentTimes [[codegen::key("instrument-times")]], + ImageAndInstrumentTimes [[codegen::key("image-and-instrument-times")]] + }; + // This value determines which type of sequencer is used for generating image + // schedules. The 'playbook' is using a custom format designed by the New Horizons + // team, the 'image-sequence' uses lbl files from a directory, and the 'hybrid' + // uses both methods + std::optional sequenceType; + + std::optional eventFile; + + // The observer that is doing the projection. This has to be a valid SPICE name + // or SPICE integer + std::string observer + [[codegen::annotation("A SPICE name of the observing object")]]; + + std::optional timesSequence; + + // The observed object that is projected on. This has to be a valid SPICE name or + // SPICE integer + std::string target [[codegen::annotation("A SPICE name of the observed object")]]; + + // The aberration correction that is supposed to be used for the projection. The + // values for the correction correspond to the SPICE definition as described in + // ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/IDL/cspice/spkezr_c.html + std::string aberration [[codegen::inlist("NONE", "LT", "LT+S", "CN", "CN+S", + "XLT", "XLT+S", "XCN", "XCN+S")]]; + + // The list of potential targets that are involved with the image projection + std::optional> potentialTargets; + + // Determines whether the object requires a self-shadowing algorithm. This is + // necessary if the object is concave and might cast a shadow on itself during + // presentation. The default value is 'false' + std::optional textureMap; + + // Determines whether the object requires a self-shadowing algorithm. This is + // necessary if the object is concave and might cast a shadow on itself during + // presentation. The default value is 'false' + std::optional shadowMap; + + // Sets the desired aspect ratio of the projected texture. This might be necessary + // as planets usually have 2x1 aspect ratios, whereas this does not hold for + // non-planet objects (comets, asteroids, etc). The default value is '1.0' + std::optional aspectRatio; + }; +#include "projectioncomponent_codegen.cpp" } // namespace namespace openspace { documentation::Documentation ProjectionComponent::Documentation() { - using namespace documentation; - return { - "Projection Component", - "newhorizons_projectioncomponent", - { - { - keySequenceDir, - new OrVerifier({ new StringVerifier, new StringListVerifier }), - Optional::Yes, - "This value specifies one or more directories from which images are " - "being used for image projections. If the sequence type is set to " - "'playbook', this value is ignored" - }, - { - keyInstrument, - new StringAnnotationVerifier("A SPICE name of an instrument"), - Optional::No, - "The instrument that is used to perform the projections" - }, - { - keyInstrumentFovy, - new DoubleVerifier, - Optional::No, - "The field of view in degrees along the y axis" - }, - { - keyInstrumentAspect, - new DoubleVerifier, - Optional::No, - "The aspect ratio of the instrument in relation between x and y axis" - }, - { - keySequenceType, - new StringInListVerifier( - { sequenceTypeImage, sequenceTypePlaybook, sequenceTypeHybrid, - sequenceTypeInstrumentTimes, sequenceTypeImageAndInstrumentTimes } - ), - Optional::Yes, - "This value determines which type of sequencer is used for generating " - "image schedules. The 'playbook' is using a custom format designed by " - "the New Horizons team, the 'image-sequence' uses lbl files from a " - "directory, and the 'hybrid' uses both methods." - }, - { - keyProjObserver, - new StringAnnotationVerifier("A SPICE name of the observing object"), - Optional::No, - "The observer that is doing the projection. This has to be a valid SPICE " - "name or SPICE integer." - }, - { - keyProjTarget, - new StringAnnotationVerifier("A SPICE name of the observed object"), - Optional::No, - "The observed object that is projected on. This has to be a valid SPICE " - "name or SPICE integer." - }, - { - keyProjAberration, - new StringInListVerifier({ - // from SpiceManager::AberrationCorrection::AberrationCorrection - "NONE", "LT", "LT+S", "CN", "CN+S", "XLT", "XLT+S", "XCN", "XCN+S" - }), - Optional::No, - "The aberration correction that is supposed to be used for the " - "projection. The values for the correction correspond to the SPICE " - "definition as described in " - "ftp://naif.jpl.nasa.gov/pub/naif/toolkit_docs/IDL/cspice/spkezr_c.html" - }, - { - keyPotentialTargets, - new StringListVerifier, - Optional::Yes, - "The list of potential targets that are involved with the image " - "projection" - }, - { - keyNeedsTextureMapDilation, - new BoolVerifier, - Optional::Yes, - "Determines whether a dilation step of the texture map has to be " - "performed after each projection. This is necessary if the texture of " - "the projected object is a texture map where the borders are not " - "touching. The default value is 'false'." - }, - { - keyNeedsShadowing, - new BoolVerifier, - Optional::Yes, - "Determines whether the object requires a self-shadowing algorithm. This " - "is necessary if the object is concave and might cast a shadow on itself " - "during presentation. The default value is 'false'." - }, - { - keyTextureMapAspectRatio, - new DoubleVerifier, - Optional::Yes, - "Sets the desired aspect ratio of the projected texture. This might be " - "necessary as planets usually have 2x1 aspect ratios, whereas this does " - "not hold for non-planet objects (comets, asteroids, etc). The default " - "value is '1.0'." - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "newhorizons_projectioncomponent"; + return doc; } ProjectionComponent::ProjectionComponent() @@ -244,162 +189,143 @@ ProjectionComponent::ProjectionComponent() void ProjectionComponent::initialize(const std::string& identifier, const ghoul::Dictionary& dictionary) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "ProjectionComponent" - ); - _instrumentID = dictionary.value(keyInstrument); - _projectorID = dictionary.value(keyProjObserver); - _projecteeID = dictionary.value(keyProjTarget); - _fovy = static_cast(dictionary.value(keyInstrumentFovy)); - _aspectRatio = static_cast(dictionary.value(keyInstrumentAspect)); + const Parameters p = codegen::bake(dictionary); - _aberration = SpiceManager::AberrationCorrection( - dictionary.value(keyProjAberration) - ); + _instrumentID = p.instrument.name; + _projectorID = p.observer; + _projecteeID = p.target; + _fovy = p.instrument.fovy; + _aspectRatio = p.instrument.aspect; - if (dictionary.hasValue(keyPotentialTargets)) { - const ghoul::Dictionary& potentialTargets = dictionary.value( - keyPotentialTargets - ); + _aberration = SpiceManager::AberrationCorrection(p.aberration); - _potentialTargets.reserve(potentialTargets.size()); - for (size_t i = 1; i <= potentialTargets.size(); ++i) { - _potentialTargets.emplace_back( - potentialTargets.value(std::to_string(i)) - ); - } - } - - if (dictionary.hasValue(keyNeedsTextureMapDilation)) { - _dilation.isEnabled = dictionary.value(keyNeedsTextureMapDilation); - } - - if (dictionary.hasValue(keyNeedsShadowing)) { - _shadowing.isEnabled = dictionary.value(keyNeedsShadowing); - } - - if (dictionary.hasValue(keyTextureMapAspectRatio)) { - _projectionTextureAspectRatio = - static_cast(dictionary.value(keyTextureMapAspectRatio)); - } + _potentialTargets = p.potentialTargets.value_or(_potentialTargets); + _dilation.isEnabled = p.textureMap.value_or(_dilation.isEnabled); + _shadowing.isEnabled = p.shadowMap.value_or(_shadowing.isEnabled); + _projectionTextureAspectRatio = p.aspectRatio.value_or(_projectionTextureAspectRatio); - if (!dictionary.hasKey(keySequenceDir)) { + if (!p.sequence.has_value()) { + // we are done here, the rest only applies if we do have a sequence return; } + std::variant> sequence = *p.sequence; + std::vector sequenceSources; - // Due to the documentation check above it must either be one or the other - if (dictionary.hasValue(keySequenceDir)) { - sequenceSources.push_back(absPath(dictionary.value(keySequenceDir))); + if (std::holds_alternative(sequence)) { + sequenceSources.push_back(absPath(std::get(sequence))); } else { - ghoul::Dictionary sourcesDict = dictionary.value( - keySequenceDir + ghoul_assert( + std::holds_alternative>(sequence), + "Something is wrong with the generated documentation" ); - for (int i = 1; i <= static_cast(sourcesDict.size()); ++i) { - sequenceSources.push_back( - absPath(sourcesDict.value(std::to_string(i))) - ); + sequenceSources = std::get>(sequence); + for (std::string& s : sequenceSources) { + s = absPath(s); } } - const std::string& sequenceType = dictionary.value(keySequenceType); - // Important: client must define translation-list in mod file IFF playbook - if (!dictionary.hasKey(keyTranslation)) { - LWARNING("No playbook translation provided, spice calls must match playbook!"); - return; + + if (!p.sequenceType.has_value()) { + throw ghoul::RuntimeError("Missing SequenceType"); } ghoul::Dictionary translationDictionary; if (dictionary.hasValue(keyTranslation)) { translationDictionary = dictionary.value(keyTranslation); } + else { + LWARNING("No playbook translation provided, spice calls must match playbook!"); + return; + } std::vector> parsers; for (std::string& sequenceSource : sequenceSources) { - if (sequenceType == sequenceTypePlaybook) { - parsers.push_back( - std::make_unique( - identifier, - std::move(sequenceSource), - _projectorID, - translationDictionary, - _potentialTargets - ) - ); - } - else if (sequenceType == sequenceTypeImage) { - parsers.push_back( - std::make_unique( - identifier, - std::move(sequenceSource), - translationDictionary - ) - ); - } - else if (sequenceType == sequenceTypeHybrid) { - //first read labels - parsers.push_back( - std::make_unique( - identifier, - std::move(sequenceSource), - translationDictionary - ) - ); - - if (dictionary.hasKey("EventFile")) { - std::string eventFile = dictionary.value("EventFile"); + switch (*p.sequenceType) { + case Parameters::Type::Playbook: parsers.push_back( std::make_unique( identifier, - absPath(eventFile), + std::move(sequenceSource), _projectorID, translationDictionary, _potentialTargets ) ); - } - else { - LWARNING("No eventfile has been provided, please check modfiles"); - } - } - else if (sequenceType == sequenceTypeInstrumentTimes) { - parsers.push_back( - std::make_unique( - identifier, - std::move(sequenceSource), - translationDictionary - ) - ); - } - else if (sequenceType == sequenceTypeImageAndInstrumentTimes) { - parsers.push_back( - std::make_unique( - identifier, - std::move(sequenceSource), - translationDictionary + break; + case Parameters::Type::ImageSequence: + parsers.push_back( + std::make_unique( + identifier, + std::move(sequenceSource), + translationDictionary ) - ); + ); + break; + case Parameters::Type::Hybrid: + // first read labels + parsers.push_back( + std::make_unique( + identifier, + std::move(sequenceSource), + translationDictionary + ) + ); - std::string timesSequenceSource = absPath( - dictionary.value(keyTimesSequenceDir) - ); - ghoul::Dictionary timesTranslationDictionary; - if (dictionary.hasValue(keyTimesTranslation)) { - timesTranslationDictionary = - dictionary.value(keyTimesTranslation); + if (p.eventFile.has_value()) { + parsers.push_back( + std::make_unique( + identifier, + absPath(*p.eventFile), + _projectorID, + translationDictionary, + _potentialTargets + ) + ); + } + else { + LWARNING("No eventfile has been provided, please check modfiles"); + } + break; + case Parameters::Type::InstrumentTimes: + parsers.push_back( + std::make_unique( + identifier, + std::move(sequenceSource), + translationDictionary + ) + ); + break; + case Parameters::Type::ImageAndInstrumentTimes: + { + parsers.push_back( + std::make_unique( + identifier, + std::move(sequenceSource), + translationDictionary + ) + ); + + if (!p.timesSequence.has_value()) { + throw ghoul::RuntimeError("Could not find required TimesSequence"); + } + ghoul::Dictionary timesTranslationDictionary; + if (dictionary.hasValue(keyTimesTranslation)) { + timesTranslationDictionary = + dictionary.value(keyTimesTranslation); + } + + parsers.push_back( + std::make_unique( + identifier, + absPath(*p.timesSequence), + timesTranslationDictionary + ) + ); + break; } - - parsers.push_back( - std::make_unique( - identifier, - std::move(timesSequenceSource), - timesTranslationDictionary - ) - ); } } diff --git a/modules/sync/tasks/syncassettask.cpp b/modules/sync/tasks/syncassettask.cpp index 777a7bf9ad..b670301dff 100644 --- a/modules/sync/tasks/syncassettask.cpp +++ b/modules/sync/tasks/syncassettask.cpp @@ -56,12 +56,6 @@ documentation::Documentation SyncAssetTask::documentation() { "SyncAssetTask", "sync_asset_task", { - { - "Type", - new StringEqualVerifier("SyncAssetTask"), - Optional::No, - "The type of this task" - }, { KeyAsset, new StringAnnotationVerifier("A file path to an asset"), diff --git a/modules/volume/tasks/generaterawvolumetask.cpp b/modules/volume/tasks/generaterawvolumetask.cpp index 0eed96877b..68e889fc72 100644 --- a/modules/volume/tasks/generaterawvolumetask.cpp +++ b/modules/volume/tasks/generaterawvolumetask.cpp @@ -182,12 +182,6 @@ documentation::Documentation GenerateRawVolumeTask::documentation() { "GenerateRawVolumeTask", "generate_raw_volume_task", { - { - "Type", - new StringEqualVerifier("GenerateRawVolumeTask"), - Optional::No, - "The type of this task", - }, { KeyValueFunction, new StringAnnotationVerifier("A lua expression that returns a function " diff --git a/modules/webbrowser/codegentest.exe.manifest b/modules/webbrowser/codegentest.exe.manifest new file mode 100644 index 0000000000..d36f084b65 --- /dev/null +++ b/modules/webbrowser/codegentest.exe.manifest @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index bdd8c0b8b2..6f62fad495 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -143,6 +143,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/rendering/renderengine.cpp ${OPENSPACE_BASE_DIR}/src/rendering/renderengine_lua.inl ${OPENSPACE_BASE_DIR}/src/rendering/screenspacerenderable.cpp + ${OPENSPACE_BASE_DIR}/src/rendering/texturecomponent.cpp ${OPENSPACE_BASE_DIR}/src/rendering/transferfunction.cpp ${OPENSPACE_BASE_DIR}/src/rendering/volumeraycaster.cpp ${OPENSPACE_BASE_DIR}/src/scene/asset.cpp @@ -178,6 +179,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/util/httprequest.cpp ${OPENSPACE_BASE_DIR}/src/util/keys.cpp ${OPENSPACE_BASE_DIR}/src/util/openspacemodule.cpp + ${OPENSPACE_BASE_DIR}/src/util/planegeometry.cpp ${OPENSPACE_BASE_DIR}/src/util/progressbar.cpp ${OPENSPACE_BASE_DIR}/src/util/resourcesynchronization.cpp ${OPENSPACE_BASE_DIR}/src/util/screenlog.cpp @@ -322,6 +324,7 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/rendering/dashboard.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/dashboarditem.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/framebufferrenderer.h + ${OPENSPACE_BASE_DIR}/include/openspace/rendering/deferredcaster.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/deferredcasterlistener.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/deferredcastermanager.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/loadingscreen.h @@ -332,11 +335,11 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/rendering/renderable.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/renderer.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/renderengine.h - ${OPENSPACE_BASE_DIR}/include/openspace/rendering/volume.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/screenspacerenderable.h - ${OPENSPACE_BASE_DIR}/include/openspace/rendering/deferredcaster.h - ${OPENSPACE_BASE_DIR}/include/openspace/rendering/volumeraycaster.h + ${OPENSPACE_BASE_DIR}/include/openspace/rendering/texturecomponent.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/transferfunction.h + ${OPENSPACE_BASE_DIR}/include/openspace/rendering/volume.h + ${OPENSPACE_BASE_DIR}/include/openspace/rendering/volumeraycaster.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/asset.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/assetlistener.h ${OPENSPACE_BASE_DIR}/include/openspace/scene/assetloader.h @@ -373,6 +376,7 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/util/memorymanager.h ${OPENSPACE_BASE_DIR}/include/openspace/util/mouse.h ${OPENSPACE_BASE_DIR}/include/openspace/util/openspacemodule.h + ${OPENSPACE_BASE_DIR}/include/openspace/util/planegeometry.h ${OPENSPACE_BASE_DIR}/include/openspace/util/progressbar.h ${OPENSPACE_BASE_DIR}/include/openspace/util/resourcesynchronization.h ${OPENSPACE_BASE_DIR}/include/openspace/util/screenlog.h @@ -472,6 +476,8 @@ target_precompile_headers(openspace-core PRIVATE ) +add_dependencies(openspace-core run_codegen) + configure_file( ${OPENSPACE_CMAKE_EXT_DIR}/openspace_header.template ${CMAKE_BINARY_DIR}/_generated/include/openspace/openspace.h diff --git a/src/documentation/documentation.cpp b/src/documentation/documentation.cpp index 04ba4bf594..ef1bfc8843 100644 --- a/src/documentation/documentation.cpp +++ b/src/documentation/documentation.cpp @@ -239,7 +239,7 @@ void testSpecificationAndThrow(const Documentation& documentation, // Perform testing against the documentation/specification TestResult testResult = testSpecification(documentation, dictionary); if (!testResult.success) { - throw SpecificationError(std::move(testResult), std::move(component)); + throw SpecificationError(testResult, component); } } diff --git a/src/documentation/verifier.cpp b/src/documentation/verifier.cpp index 6cd31004f5..3cea6786bc 100644 --- a/src/documentation/verifier.cpp +++ b/src/documentation/verifier.cpp @@ -133,11 +133,11 @@ std::string DoubleVerifier::type() const { return "Double"; } -TestResult IntVerifier::operator()(const ghoul::Dictionary & dict, +TestResult IntVerifier::operator()(const ghoul::Dictionary& dict, const std::string & key) const { if (dict.hasValue(key)) { - // We we have a key and the value is int, we are done + // We have a key and the value is int, we are done return { true, {}, {} }; } else { @@ -177,6 +177,120 @@ std::string StringVerifier::type() const { return "String"; } +template <> +TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const +{ + if (dict.hasValue(key)) { + return { true, {}, {} }; + } + else { + if (dict.hasKey(key)) { + if (dict.hasValue(key)) { + glm::dvec2 value = dict.value(key); + glm::dvec2 intPart; + glm::bvec2 isInt = { + modf(value.x, &intPart.x) == 0.0, + modf(value.y, &intPart.y) == 0.0 + }; + if (isInt.x && isInt.y) { + return { true, {}, {} }; + } + else { + return { + false, + {{ key, TestResult::Offense::Reason::WrongType }}, + {} + }; + } + } + else { + return { false, {{ key, TestResult::Offense::Reason::WrongType }}, {} }; + } + } + else { + return { false, {{ key, TestResult::Offense::Reason::MissingKey }}, {} }; + } + } +} + +template <> +TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const +{ + if (dict.hasValue(key)) { + return { true, {}, {} }; + } + else { + if (dict.hasKey(key)) { + if (dict.hasValue(key)) { + glm::dvec3 value = dict.value(key); + glm::dvec3 intPart; + glm::bvec3 isInt = { + modf(value.x, &intPart.x) == 0.0, + modf(value.y, &intPart.y) == 0.0, + modf(value.z, &intPart.z) == 0.0 + }; + if (isInt.x && isInt.y && isInt.z) { + return { true, {}, {} }; + } + else { + return { + false, + {{ key, TestResult::Offense::Reason::WrongType }}, + {} + }; + } + } + else { + return { false, {{ key, TestResult::Offense::Reason::WrongType }}, {} }; + } + } + else { + return { false, {{ key, TestResult::Offense::Reason::MissingKey }}, {} }; + } + } +} + +template <> +TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dict, + const std::string& key) const +{ + if (dict.hasValue(key)) { + return { true, {}, {} }; + } + else { + if (dict.hasKey(key)) { + if (dict.hasValue(key)) { + glm::dvec4 value = dict.value(key); + glm::dvec4 intPart; + glm::bvec4 isInt = { + modf(value.x, &intPart.x) == 0.0, + modf(value.y, &intPart.y) == 0.0, + modf(value.z, &intPart.z) == 0.0, + modf(value.w, &intPart.w) == 0.0 + }; + if (isInt.x && isInt.y && isInt.z && isInt.w) { + return { true, {}, {} }; + } + else { + return { + false, + {{ key, TestResult::Offense::Reason::WrongType }}, + {} + }; + } + } + else { + return { false, {{ key, TestResult::Offense::Reason::WrongType }}, {} }; + } + } + else { + return { false, {{ key, TestResult::Offense::Reason::MissingKey }}, {} }; + } + } +} + TableVerifier::TableVerifier(std::vector documentationEntries) : documentations(std::move(documentationEntries)) {} diff --git a/src/engine/configuration.cpp b/src/engine/configuration.cpp index 9b948e911c..35727a3790 100644 --- a/src/engine/configuration.cpp +++ b/src/engine/configuration.cpp @@ -147,7 +147,7 @@ namespace { for (size_t i = 1; i <= d.size(); ++i) { res.push_back(d.value(std::to_string(i))); } - value = res; + value = std::move(res); } // NOLINTNEXTLINE else if constexpr (std::is_same_v>) { @@ -160,7 +160,7 @@ namespace { std::string v = d.value(key); res[std::string(key)] = std::move(v); } - value = res; + value = std::move(res); } // NOLINTNEXTLINE else if constexpr (std::is_same_v>) { @@ -173,7 +173,7 @@ namespace { ghoul::Dictionary v = d.value(key); res[std::string(key)] = std::move(v); } - value = res; + value = std::move(res); } // NOLINTNEXTLINE else if constexpr (std::is_same_v) { @@ -256,7 +256,10 @@ namespace { filter.type = fi.value(KeyType); } - res.push_back(filter); + auto fff = filter; + const auto ffg = filter; + + res.push_back(std::move(filter)); } v.identifierFilters = res; diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index b9512adff6..00c135152d 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -1540,8 +1540,8 @@ scripting::LuaLibrary OpenSpaceEngine::luaLibrary() { "Removes a tag (second argument) from a scene graph node (first argument)" }, { - "createPixelImage", - &luascriptfunctions::createPixelImage, + "createSingeColorImage", + &luascriptfunctions::createSingeColorImage, {}, "string, vec3", "Creates a 1 pixel image with a certain color in the cache folder and " diff --git a/src/engine/openspaceengine_lua.inl b/src/engine/openspaceengine_lua.inl index d19a6aab6c..2b4636a66f 100644 --- a/src/engine/openspaceengine_lua.inl +++ b/src/engine/openspaceengine_lua.inl @@ -294,14 +294,15 @@ int downloadFile(lua_State* L) { /** * \ingroup LuaScripts -* createPixelImage(): -* Creates a one pixel image with a given color and returns the p +* createSingeColorImage(): +* Creates a one pixel image with a given color and returns the path to the cached file */ -int createPixelImage(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::createPixelImage"); +int createSingeColorImage(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::createSingeColorImage"); const std::string& name = ghoul::lua::value(L, 1); const ghoul::Dictionary& d = ghoul::lua::value(L, 2); + lua_settop(L, 0); // @TODO (emmbr 2020-12-18) Verify that the input dictionary is a vec3 // Would like to clean this up with a more direct use of the Verifier in the future @@ -311,6 +312,9 @@ int createPixelImage(lua_State* L) { colorDict.setValue(key, d); TestResult res = DoubleVector3Verifier()(colorDict, key); + // @TODO (emmbr 2020-02-04) A 'ColorVerifier' would be really useful here, to easily + // check that we have a vector with values in [0, 1] + if (!res.success) { return ghoul::lua::luaError( L, diff --git a/src/interaction/tasks/convertrecfileversiontask.cpp b/src/interaction/tasks/convertrecfileversiontask.cpp index 8bfaac639f..83eea9640c 100644 --- a/src/interaction/tasks/convertrecfileversiontask.cpp +++ b/src/interaction/tasks/convertrecfileversiontask.cpp @@ -107,12 +107,6 @@ documentation::Documentation ConvertRecFileVersionTask::documentation() { "ConvertRecFileVersionTask", "convert_file_version_task", { - { - "Type", - new StringEqualVerifier("ConvertRecFileVersionTask"), - Optional::No, - "The type of this task", - }, { KeyInFilePath, new StringAnnotationVerifier("A valid filename to convert"), diff --git a/src/interaction/tasks/convertrecformattask.cpp b/src/interaction/tasks/convertrecformattask.cpp index cc759a2a99..3651d49868 100644 --- a/src/interaction/tasks/convertrecformattask.cpp +++ b/src/interaction/tasks/convertrecformattask.cpp @@ -314,12 +314,6 @@ documentation::Documentation ConvertRecFormatTask::documentation() { "ConvertRecFormatTask", "convert_format_task", { - { - "Type", - new StringEqualVerifier("ConvertRecFormatTask"), - Optional::No, - "The type of this task", - }, { KeyInFilePath, new StringAnnotationVerifier("A valid filename to convert"), diff --git a/src/properties/property.cpp b/src/properties/property.cpp index 5e4189811d..157aa6d261 100644 --- a/src/properties/property.cpp +++ b/src/properties/property.cpp @@ -217,6 +217,9 @@ void Property::setViewOption(std::string option, bool value) { } bool Property::viewOption(const std::string& option, bool defaultValue) const { + if (!_metaData.hasValue(_metaDataKeyViewPrefix)) { + return defaultValue; + } ghoul::Dictionary d = _metaData.value(_metaDataKeyViewPrefix); if (d.hasKey(option)) { return d.value(option); diff --git a/src/rendering/renderable.cpp b/src/rendering/renderable.cpp index d474297c04..9236c2850a 100644 --- a/src/rendering/renderable.cpp +++ b/src/rendering/renderable.cpp @@ -33,10 +33,10 @@ #include #include #include +#include namespace { constexpr const char* KeyType = "Type"; - constexpr const char* KeyTag = "Tag"; constexpr openspace::properties::Property::PropertyInfo EnabledInfo = { "Enabled", @@ -63,49 +63,47 @@ namespace { "Bounding Sphere", "The size of the bounding sphere radius." }; + struct [[codegen::Dictionary(Renderable)]] Parameters { + // [[codegen::verbatim(EnabledInfo.description)]] + std::optional enabled; + // [[codegen::verbatim(OpacityInfo.description)]] + std::optional opacity [[codegen::inrange(0.0, 1.0)]]; + + // A single tag or a list of tags that this renderable will respond to when + // setting properties + std::optional, std::string>> tag; + + // [[codegen::verbatim(RenderableTypeInfo.description)]] + std::optional type; + + // [[codegen::verbatim(BoundingSphereInfo.description)]] + std::optional boundingSphere; + }; +#include "renderable_codegen.cpp" } // namespace namespace openspace { documentation::Documentation Renderable::Documentation() { - using namespace openspace::documentation; - - return { - "Renderable", - "renderable", - { - { - KeyType, - new StringAnnotationVerifier("A valid Renderable created by a factory"), - Optional::No, - "This key specifies the type of Renderable that gets created. It has to " - "be one of the valid Renderables that are available for creation (see " - "the FactoryDocumentation for a list of possible Renderables), which " - "depends on the configration of the application" - }, - { - EnabledInfo.identifier, - new BoolVerifier, - Optional::Yes, - EnabledInfo.description - }, - { - OpacityInfo.identifier, - new DoubleInRangeVerifier(0.0, 1.0), - Optional::Yes, - OpacityInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "renderable"; + return doc; } ghoul::mm_unique_ptr Renderable::createFromDictionary( - const ghoul::Dictionary& dictionary) + ghoul::Dictionary dictionary) { + if (!dictionary.hasKey(KeyType)) { + throw ghoul::RuntimeError("Tried to create Renderable but no 'Type' was found"); + } + + // This should be done in the constructor instead with noexhaustive documentation::testSpecificationAndThrow(Documentation(), dictionary, "Renderable"); std::string renderableType = dictionary.value(KeyType); + // Now we no longer need the type variable + dictionary.removeValue(KeyType); auto factory = FactoryManager::ref().factory(); ghoul_assert(factory, "Renderable factory did not exist"); @@ -130,46 +128,34 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary) // I can't come up with a good reason not to do this for all renderables registerUpdateRenderBinFromOpacity(); - if (dictionary.hasValue(KeyTag)) { - std::string tagName = dictionary.value(KeyTag); - if (!tagName.empty()) { - addTag(std::move(tagName)); + const Parameters p = codegen::bake(dictionary); + + if (p.tag.has_value()) { + if (std::holds_alternative(*p.tag)) { + if (!std::get(*p.tag).empty()) { + addTag(std::get(*p.tag)); + } } - } - else if (dictionary.hasValue(KeyTag)) { - const ghoul::Dictionary& tagNames = dictionary.value(KeyTag); - for (std::string_view key : tagNames.keys()) { - std::string tagName = tagNames.value(key); - if (!tagName.empty()) { - addTag(std::move(tagName)); + else { + ghoul_assert(std::holds_alternative>(*p.tag), ""); + for (std::string tag : std::get>(*p.tag)) { + addTag(std::move(tag)); } } } - if (dictionary.hasKey(EnabledInfo.identifier)) { - _enabled = dictionary.value(EnabledInfo.identifier); - } - - if (dictionary.hasKey(OpacityInfo.identifier)) { - _opacity = static_cast(dictionary.value(OpacityInfo.identifier)); - } - + _enabled = p.enabled.value_or(_enabled); addProperty(_enabled); - //set type for UI - if (dictionary.hasKey(RenderableTypeInfo.identifier)) { - _renderableType = dictionary.value( - RenderableTypeInfo.identifier - ); - } - - if (dictionary.hasKey(BoundingSphereInfo.identifier)) { - _boundingSphere = static_cast( - dictionary.value(BoundingSphereInfo.identifier) - ); - } + _opacity = p.opacity.value_or(_opacity); + // We don't add the property here as subclasses should decide on their own whether + // they to expose the opacity or not + // set type for UI + _renderableType = p.type.value_or(_renderableType); addProperty(_renderableType); + + _boundingSphere = p.boundingSphere.value_or(_boundingSphere); addProperty(_boundingSphere); } @@ -198,7 +184,7 @@ SurfacePositionHandle Renderable::calculateSurfacePositionHandle( { const glm::dvec3 directionFromCenterToTarget = glm::normalize(targetModelSpace); return { - directionFromCenterToTarget * static_cast(boundingSphere()), + directionFromCenterToTarget * boundingSphere(), directionFromCenterToTarget, 0.0 }; diff --git a/src/rendering/texturecomponent.cpp b/src/rendering/texturecomponent.cpp new file mode 100644 index 0000000000..ce771887f8 --- /dev/null +++ b/src/rendering/texturecomponent.cpp @@ -0,0 +1,115 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include + +namespace { + constexpr const char _loggerCat[] = "TextureComponent"; +} // namespace + +namespace openspace { + +const ghoul::opengl::Texture* TextureComponent::texture() const { + return _texture.get(); +} + +ghoul::opengl::Texture* TextureComponent::texture() { + return _texture.get(); +} + +void TextureComponent::setFilterMode(Texture::FilterMode filterMode) { + _filterMode = filterMode; +} + +void TextureComponent::setWrapping(Texture::WrappingMode wrapping) { + _wrappingMode = wrapping; +} + +void TextureComponent::setShouldWatchFileForChanges(bool value) { + _shouldWatchFile = value; +} + +void TextureComponent::setShouldPurgeFromRAM(bool value) { + _shouldPurgeFromRAM = value; +} + +void TextureComponent::bind() { + ghoul_assert(_texture, "Texture must be loaded before binding"); + _texture->bind(); +} + +void TextureComponent::uploadToGpu() { + if (!_texture) { + LERROR("Could not upload texture to GPU. Texture not loaded"); + return; + } + _texture->uploadTexture(); + _texture->setFilter(_filterMode); + _texture->setWrapping(_wrappingMode); + if (_shouldPurgeFromRAM) { + _texture->purgeFromRAM(); + } +} + +void TextureComponent::loadFromFile(const std::string& path) { + if (!path.empty()) { + using namespace ghoul::io; + using namespace ghoul::opengl; + std::unique_ptr texture = TextureReader::ref().loadTexture( + absPath(path) + ); + + if (texture) { + LDEBUG(fmt::format("Loaded texture from '{}'", absPath(path))); + _texture = std::move(texture); + + _textureFile = std::make_unique(path); + if (_shouldWatchFile) { + _textureFile->setCallback( + [&](const ghoul::filesystem::File&) { _fileIsDirty = true; } + ); + } + + _fileIsDirty = false; + _textureIsDirty = true; + } + } +} + +void TextureComponent::update() { + if (_fileIsDirty) { + loadFromFile(_textureFile->path()); + } + + if (_textureIsDirty) { + uploadToGpu(); + _textureIsDirty = false; + } +} +} // namespace openspace diff --git a/src/scene/scenegraphnode.cpp b/src/scene/scenegraphnode.cpp index 9eafbe0650..38ddc471bf 100644 --- a/src/scene/scenegraphnode.cpp +++ b/src/scene/scenegraphnode.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include "scenegraphnode_doc.inl" @@ -263,16 +264,8 @@ ghoul::mm_unique_ptr SceneGraphNode::createFromDictionary( ghoul::Dictionary renderableDictionary = dictionary.value(KeyRenderable); - renderableDictionary.setValue(KeyIdentifier, result->_identifier); - result->_renderable = Renderable::createFromDictionary(renderableDictionary); - if (result->_renderable == nullptr) { - LERROR(fmt::format( - "Failed to create renderable for SceneGraphNode '{}'", - result->identifier() - )); - return nullptr; - } + ghoul_assert(result->_renderable, "Failed to create Renderable"); result->addPropertySubOwner(result->_renderable.get()); LDEBUG(fmt::format( "Successfully created renderable for '{}'", result->identifier() @@ -689,7 +682,7 @@ void SceneGraphNode::computeScreenSpaceData(RenderData& newData) { glm::ivec2 res = global::windowDelegate->currentSubwindowSize(); // Get the radius of node - double nodeRadius = static_cast(this->boundingSphere()); + double nodeRadius = boundingSphere(); // Distance from the camera to the node double distFromCamToNode = glm::distance(cam.positionVec3(), worldPos) - nodeRadius; diff --git a/src/util/planegeometry.cpp b/src/util/planegeometry.cpp new file mode 100644 index 0000000000..69a8c92317 --- /dev/null +++ b/src/util/planegeometry.cpp @@ -0,0 +1,108 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include + +namespace { + constexpr const char* _loggerCat = "PlaneGeometry"; +} // namespace + +namespace openspace { + +PlaneGeometry::PlaneGeometry(glm::vec2 size) : _size(std::move(size)) {} + +PlaneGeometry::PlaneGeometry(float size) : PlaneGeometry(glm::vec2(size, size)) {} + +PlaneGeometry::~PlaneGeometry() { + glDeleteBuffers(1, &_vBufferId); + glDeleteVertexArrays(1, &_vaoId); +} + +void PlaneGeometry::initialize() { + glGenVertexArrays(1, &_vaoId); + glGenBuffers(1, &_vBufferId); + updateGeometry(); +} + +void PlaneGeometry::deinitialize() { + glDeleteVertexArrays(1, &_vaoId); + _vaoId = 0; + + glDeleteBuffers(1, &_vBufferId); + _vBufferId = 0; +} + +void PlaneGeometry::render() { + glBindVertexArray(_vaoId); + glDrawArrays(GL_TRIANGLES, 0, 6); + glBindVertexArray(0); +} + +void PlaneGeometry::updateSize(const glm::vec2& size) { + _size = size; + updateGeometry(); +} + +void PlaneGeometry::updateSize(const float size) { + updateSize(glm::vec2(size)); +} + +void PlaneGeometry::updateGeometry() { + const glm::vec2 size = _size; + struct VertexData { + GLfloat x; + GLfloat y; + GLfloat s; + GLfloat t; + }; + + VertexData vertices[] = { + { -size.x, -size.y, 0.f, 0.f }, + { size.x, size.y, 1.f, 1.f }, + { -size.x, size.y, 0.f, 1.f }, + { -size.x, -size.y, 0.f, 0.f }, + { size.x, -size.y, 1.f, 0.f }, + { size.x, size.y, 1.f, 1.f } + }; + + glBindVertexArray(_vaoId); + glBindBuffer(GL_ARRAY_BUFFER, _vBufferId); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), &vertices, GL_STATIC_DRAW); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(VertexData), nullptr); + glEnableVertexAttribArray(1); + glVertexAttribPointer( + 1, + 2, + GL_FLOAT, + GL_FALSE, + sizeof(VertexData), + reinterpret_cast(offsetof(VertexData, s)) // NOLINT + ); +} + +} // namespace openspace diff --git a/support/cmake/set_openspace_compile_settings.cmake b/support/cmake/set_openspace_compile_settings.cmake index 3154376b7f..3dee265c93 100644 --- a/support/cmake/set_openspace_compile_settings.cmake +++ b/support/cmake/set_openspace_compile_settings.cmake @@ -31,6 +31,7 @@ function (set_openspace_compile_settings target) "/w44062" # enumerator 'identifier' in a switch of enum 'enumeration' is not handled "/wd4127" # conditional expression is constant "/wd4201" # nonstandard extension used : nameless struct/union + "/wd5030" # attribute 'attribute' is not recognized "/w44255" # 'function': no function prototype given: converting '()' to '(void)' "/w44263" # 'function': member function does not override any base class virtual member function "/w44264" # 'virtual_function': no override available for virtual member function from base 'class'; function is hidden @@ -173,6 +174,7 @@ function (set_openspace_compile_settings target) "-Wvla" "-Wzero-length-array" "-Wno-missing-braces" + "-Wno-unknown-attributes" ) if (OPENSPACE_WARNINGS_AS_ERRORS) set(CLANG_WARNINGS ${CLANG_WARNINGS} "-Werror") @@ -206,6 +208,8 @@ function (set_openspace_compile_settings target) "-Wold-style-cast" "-Woverloaded-virtual" "-Wno-long-long" + "-Wno-ignored-attributes" + "-Wno-attributes" ) if (OPENSPACE_WARNINGS_AS_ERRORS) set(GCC_WARNINGS ${CLANG_WARNINGS} "-Werror") diff --git a/support/coding/codegen b/support/coding/codegen new file mode 160000 index 0000000000..1e942f53f1 --- /dev/null +++ b/support/coding/codegen @@ -0,0 +1 @@ +Subproject commit 1e942f53f1e9543bc5040c2a8d52eeea1559b788 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f68b8d0b3b..522b4509c8 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -33,6 +33,7 @@ add_executable( test_latlonpatch.cpp test_lrucache.cpp test_luaconversions.cpp + test_lua_createsinglecolorimage.cpp test_optionproperty.cpp test_profile.cpp test_rawvolumeio.cpp diff --git a/tests/test_lua_createsinglecolorimage.cpp b/tests/test_lua_createsinglecolorimage.cpp new file mode 100644 index 0000000000..e2311a5cf9 --- /dev/null +++ b/tests/test_lua_createsinglecolorimage.cpp @@ -0,0 +1,162 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include "catch2/catch.hpp" + +#include +#include +#include +#include +#include +#include + +TEST_CASE("CreateSingleColorImage: Create image and check return value", + "[createsinglecolorimage]") +{ + ghoul::lua::LuaState L; + ghoul::lua::push(L, "colorFile"); + ghoul::lua::push(L, std::vector{ 1.0, 0.0, 0.0 }); + + int res = openspace::luascriptfunctions::createSingeColorImage(L); + + // One return value + CHECK(res == 1); + CHECK(lua_gettop(L) == 1); + CHECK(lua_isstring(L, 1)); + + std::string path = ghoul::lua::value(L, 1); + CHECK_THAT( + path, + Catch::Matchers::Contains("OpenSpace\\cache\\colorFile.ppm") + ); +} + +TEST_CASE("CreateSingleColorImage: Faulty 1st input type", "[createsinglecolorimage]") { + ghoul::lua::LuaState L; + ghoul::lua::push(L, std::vector{ 1.0, 0.0, 0.0 }); + ghoul::lua::push(L, std::vector{ 1.0, 0.0, 0.0 }); + + CHECK_THROWS_WITH( + openspace::luascriptfunctions::createSingeColorImage(L), + Catch::Matchers::Contains("parameter 1 was not the expected type") + ); +} + +TEST_CASE("CreateSingleColorImage: Faulty 2nd input type", "[createsinglecolorimage]") { + ghoul::lua::LuaState L; + ghoul::lua::push(L, "notCreatedColorFile"); + ghoul::lua::push(L, "not a vector"); + + CHECK_THROWS_WITH( + openspace::luascriptfunctions::createSingeColorImage(L), + Catch::Matchers::Contains("parameter 2 was not the expected type") + ); +} + +TEST_CASE("CreateSingleColorImage: Invalid number of inputs", "[createsinglecolorimage]") +{ + ghoul::lua::LuaState L; + ghoul::lua::push(L, std::vector{ 1.0, 0.0, 0.0 }); + + CHECK_THROWS_WITH( + openspace::luascriptfunctions::createSingeColorImage(L), + Catch::Matchers::Contains("Expected 2 arguments, got 1") + ); +} + +TEST_CASE("CreateSingleColorImage: Faulty color value (vec4)", + "[createsinglecolorimage]") +{ + ghoul::lua::LuaState L; + ghoul::lua::push(L, "notCreatedColorFile"); + ghoul::lua::push(L, std::vector{ 1.0, 0.0, 0.0, 0.0 }); + + CHECK_THROWS_WITH( + openspace::luascriptfunctions::createSingeColorImage(L), + Catch::Matchers::Contains( + "Invalid color. Expected three double values {r, g, b} in range 0 to 1" + ) + ); +} + +TEST_CASE("CreateSingleColorImage: Faulty color value (invalid values)", + "[createsinglecolorimage]") +{ + ghoul::lua::LuaState L; + ghoul::lua::push(L, "notCreatedColorFile"); + ghoul::lua::push(L, std::vector{ 255.0, 0.0, 0.0 }); + + // @TODO (emmbr 2020-02-04) This test case should be here, but as of now this case is + // not handled. Finish it up when we have a better way of verifying that a dictionary + // is a color + + //CHECK_THROWS_WITH( + // openspace::luascriptfunctions::createSingeColorImage(L), + // Catch::Matchers::Contains( + // "Invalid color. Expected three double values {r, g, b} in range 0 to 1" + // ) + //); +} + +TEST_CASE("CreateSingleColorImage: Check if file was created", + "[createsinglecolorimage]") +{ + ghoul::lua::LuaState L; + ghoul::lua::push(L, "colorFile2"); + ghoul::lua::push(L, std::vector{ 0.0, 1.0, 0.0 }); + + int res = openspace::luascriptfunctions::createSingeColorImage(L); + + CHECK(res == 1); + std::string path = ghoul::lua::value(L, 1); + CHECK(FileSys.fileExists(path)); +} + +TEST_CASE("CreateSingleColorImage: Load created image", "[createsinglecolorimage]") { + ghoul::lua::LuaState L; + ghoul::lua::push(L, "colorFile"); + ghoul::lua::push(L, std::vector{ 1.0, 0.0, 0.0 }); + + // Loads the same file that was created in a previous test case + int res = openspace::luascriptfunctions::createSingeColorImage(L); + CHECK(res == 1); + CHECK(lua_gettop(L) == 1); + + std::string path = ghoul::lua::value(L, 1); + + // Read the PPM file and check the image dimensions + // (maybe too hard coded, but cannot load a texture here...) + std::ifstream ppmFile(path, std::ifstream::binary); + REQUIRE(ppmFile.is_open()); + + std::string version; + unsigned int width; + unsigned int height; + + ppmFile >> version >> width >> height; + + REQUIRE(width == 1); + REQUIRE(height == 1); +} +