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/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/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/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/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 fb284650ab..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); 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/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/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/rendering/renderableorbitdisc.cpp b/modules/exoplanets/rendering/renderableorbitdisc.cpp index 15bd28072f..1ad0e6a85b 100644 --- a/modules/exoplanets/rendering/renderableorbitdisc.cpp +++ b/modules/exoplanets/rendering/renderableorbitdisc.cpp @@ -81,11 +81,6 @@ documentation::Documentation RenderableOrbitDisc::Documentation() { "Renderable Orbit Disc", "exoplanets_renderable_orbit_disc", { - { - "Type", - new StringEqualVerifier("RenderableOrbitDisc"), - Optional::No - }, { TextureInfo.identifier, new StringVerifier, 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/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/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/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/spacemodule.cpp b/modules/space/spacemodule.cpp index 95c576e14f..0ebba746cd 100644 --- a/modules/space/spacemodule.cpp +++ b/modules/space/spacemodule.cpp @@ -31,7 +31,6 @@ #include #include #include -//#include #include #include #include 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 f095c64271..6f62fad495 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -476,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/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/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/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/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