diff --git a/CMakeLists.txt b/CMakeLists.txt index 96ab1ca6c9..c3e35daafc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,9 +134,19 @@ endif () option(OPENSPACE_WITH_ABUFFER_RENDERER "Compile ABuffer Renderer" OFF) -if (UNIX AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -stdlib=libc++") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++ -lc++abi") +if (UNIX) + if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++17 -stdlib=libc++") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++ -lc++ -lc++abi") + else () + if(NOT CMAKE_BUILD_TYPE) + #Can set to "RelWithDebInfo" or "Debug" also, but problems occur if this is blank by default + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Default build type" FORCE) + endif() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGLM_ENABLE_EXPERIMENTAL" CACHE STRING "" FORCE) + set(OpenGL_GL_PREFERENCE "GLVND" CACHE STRING "OpenGL Preference setting necessary for linux" FORCE) + set(ASSIMP_BUILD_MINIZIP ON CACHE BOOL "Set to have assimp build minizip" FORCE) + endif () endif () add_subdirectory(ext) diff --git a/Jenkinsfile b/Jenkinsfile index 5fc5351950..c29f718631 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -107,7 +107,8 @@ linux_gcc_make: { } stage('linux-gcc-make/build') { def cmakeCompileOptions = moduleCMakeFlags(); - cmakeCompileOptions += ' -DMAKE_BUILD_TYPE=Release'; + cmakeCompileOptions += ' -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_FLAGS:STRING="-DGLM_ENABLE_EXPERIMENTAL"'; + cmakeCompileOptions += ' -DOpenGL_GL_PREFERENCE:STRING=GLVND -DASSIMP_BUILD_MINIZIP=1'; // Not sure why the linking of OpenSpaceTest takes so long compileHelper.build(compileHelper.Make(), compileHelper.Gcc(), cmakeCompileOptions, 'OpenSpace', 'build-make'); compileHelper.recordCompileIssues(compileHelper.Gcc()); diff --git a/apps/OpenSpace/ext/launcher/CMakeLists.txt b/apps/OpenSpace/ext/launcher/CMakeLists.txt index 460f486412..f8cbd26db7 100644 --- a/apps/OpenSpace/ext/launcher/CMakeLists.txt +++ b/apps/OpenSpace/ext/launcher/CMakeLists.txt @@ -34,6 +34,7 @@ set(HEADER_FILES include/profile/cameradialog.h include/profile/deltatimesdialog.h include/profile/keybindingsdialog.h + include/profile/scriptlogdialog.h include/profile/line.h include/profile/marknodesdialog.h include/profile/metadialog.h @@ -53,6 +54,7 @@ set(SOURCE_FILES src/profile/cameradialog.cpp src/profile/deltatimesdialog.cpp src/profile/keybindingsdialog.cpp + src/profile/scriptlogdialog.cpp src/profile/line.cpp src/profile/marknodesdialog.cpp src/profile/metadialog.cpp @@ -74,6 +76,7 @@ qt5_wrap_cpp( include/profile/cameradialog.h include/profile/deltatimesdialog.h include/profile/keybindingsdialog.h + include/profile/scriptlogdialog.h include/profile/marknodesdialog.h include/profile/metadialog.h include/profile/modulesdialog.h diff --git a/apps/OpenSpace/ext/launcher/include/profile/keybindingsdialog.h b/apps/OpenSpace/ext/launcher/include/profile/keybindingsdialog.h index f242f19e42..488b560155 100644 --- a/apps/OpenSpace/ext/launcher/include/profile/keybindingsdialog.h +++ b/apps/OpenSpace/ext/launcher/include/profile/keybindingsdialog.h @@ -58,6 +58,13 @@ public: */ virtual void keyPressEvent(QKeyEvent* evt) override; + /** + * Adds scripts to the _scriptEdit from outside dialogs + * + * \param scripts #std::string scripts to be appended + */ + void appendScriptsToKeybind(const std::string& scripts); + private slots: void listItemSelected(); void listItemAdded(); @@ -66,6 +73,7 @@ private slots: void listItemCancelSave(); void transitionToEditMode(); void parseSelections(); + void chooseScripts(); void keySelected(int index); private: @@ -99,6 +107,7 @@ private: QPushButton* _addButton = nullptr; QPushButton* _removeButton = nullptr; + QPushButton* _chooseScriptsButton = nullptr; QPushButton* _saveButton = nullptr; QPushButton* _cancelButton = nullptr; QDialogButtonBox* _buttonBox = nullptr; diff --git a/apps/OpenSpace/ext/launcher/include/profile/scriptlogdialog.h b/apps/OpenSpace/ext/launcher/include/profile/scriptlogdialog.h new file mode 100644 index 0000000000..49de2deee8 --- /dev/null +++ b/apps/OpenSpace/ext/launcher/include/profile/scriptlogdialog.h @@ -0,0 +1,53 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_UI_LAUNCHER___SCRIPTLOG___H__ +#define __OPENSPACE_UI_LAUNCHER___SCRIPTLOG___H__ + +#include "profile/keybindingsdialog.h" +#include +#include + +class ScriptlogDialog : public QDialog { +Q_OBJECT +public: + /** + * Constructor for ScriptlogDialog class + * + * \param bindingDialog keybindingDialog that openend this window. + * \param parent Pointer to parent Qt widget + */ + ScriptlogDialog(KeybindingsDialog* bindingDialog, QWidget* parent); + +private slots: + void saveChosenScripts(); + +private: + void createWidgets(); + + KeybindingsDialog* _bindingDialog = nullptr; + QListWidget* _scriptlogList = nullptr; +}; + +#endif // __OPENSPACE_UI_LAUNCHER___SCRIPTLOG___H__ diff --git a/apps/OpenSpace/ext/launcher/src/profile/assettreemodel.cpp b/apps/OpenSpace/ext/launcher/src/profile/assettreemodel.cpp index b33b9c216f..53521995f6 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/assettreemodel.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/assettreemodel.cpp @@ -149,7 +149,9 @@ void AssetTreeModel::importModelData(const std::string& assetBasePath, const std::string& userAssetBasePath) { FileSystemAccess assets( ".asset", - { "scene", "global", "customization", "examples", "util" }, + // @TODO (abock, 2021-03-24) We need some better solution for this; what is the + // problem of just including all subfolders instead? + { "scene", "global", "customization", "dashboard", "examples", "util" }, true, true ); diff --git a/apps/OpenSpace/ext/launcher/src/profile/keybindingsdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/keybindingsdialog.cpp index 8ea5dcf272..dc373a6a01 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/keybindingsdialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/keybindingsdialog.cpp @@ -25,6 +25,8 @@ #include "profile/keybindingsdialog.h" #include "profile/line.h" +#include "profile/scriptlogdialog.h" + #include #include #include @@ -106,6 +108,10 @@ KeybindingsDialog::KeybindingsDialog(Profile& profile, QWidget *parent) transitionFromEditMode(); } +void KeybindingsDialog::appendScriptsToKeybind(const std::string& scripts) { + _scriptEdit->append(QString::fromStdString(scripts)); +} + void KeybindingsDialog::createWidgets() { QBoxLayout* layout = new QVBoxLayout(this); { @@ -220,6 +226,14 @@ void KeybindingsDialog::createWidgets() { _scriptLabel = new QLabel("Script"); box->addWidget(_scriptLabel, 6, 0, 1, 2); + + _chooseScriptsButton = new QPushButton("Choose Scripts"); + connect( + _chooseScriptsButton, &QPushButton::clicked, + this, &KeybindingsDialog::chooseScripts + ); + box->addWidget(_chooseScriptsButton, 6, 1, 1, 1); + _scriptEdit = new QTextEdit; _scriptEdit->setAcceptRichText(false); _scriptEdit->setToolTip("Command(s) to execute at keypress event"); @@ -497,6 +511,7 @@ void KeybindingsDialog::editBoxDisabled(bool disabled) { _scriptEdit->setDisabled(disabled); _cancelButton->setDisabled(disabled); _saveButton->setDisabled(disabled); + _chooseScriptsButton->setDisabled(disabled); } void KeybindingsDialog::parseSelections() { @@ -508,6 +523,11 @@ void KeybindingsDialog::parseSelections() { accept(); } +void KeybindingsDialog::chooseScripts() { + _errorMsg->clear(); + ScriptlogDialog(this, this).exec(); +} + void KeybindingsDialog::keyPressEvent(QKeyEvent* evt) { if (evt->key() == Qt::Key_Enter || evt->key() == Qt::Key_Return) { return; diff --git a/apps/OpenSpace/ext/launcher/src/profile/scriptlogdialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/scriptlogdialog.cpp new file mode 100644 index 0000000000..dab9689dd8 --- /dev/null +++ b/apps/OpenSpace/ext/launcher/src/profile/scriptlogdialog.cpp @@ -0,0 +1,99 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include "profile/scriptlogdialog.h" +#include "profile/line.h" +#include +#include +#include +#include +#include +#include +#include +#include + +ScriptlogDialog::ScriptlogDialog(KeybindingsDialog* bindingDialog, + QWidget* parent) + : QDialog(parent) + , _bindingDialog(bindingDialog) +{ + setWindowTitle("Scriptlog"); + createWidgets(); + + QFile file(QString::fromStdString(absPath("${LOGS}/scriptLog.txt"))); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream in(&file); + while (!in.atEnd()) { + QString line = in.readLine(); + // removing return from a few statments + // these are usually generated by gui panels + line.remove(QRegularExpression("^return ")); + if (!line.isEmpty()) { + _scriptlogList->addItem(line); + } + } + } +} + +void ScriptlogDialog::createWidgets() { + QBoxLayout* layout = new QVBoxLayout(this); + { + QLabel* heading = new QLabel("Choose commands from log/scriptLog.txt"); + heading->setObjectName("heading"); + layout->addWidget(heading); + } + + _scriptlogList = new QListWidget; + _scriptlogList->setSelectionMode(QAbstractItemView::SelectionMode::MultiSelection); + layout->addWidget(_scriptlogList); + + layout->addWidget(new Line); + { + QDialogButtonBox* buttons = new QDialogButtonBox; + buttons->setStandardButtons(QDialogButtonBox::Save | QDialogButtonBox::Cancel); + connect( + buttons, &QDialogButtonBox::accepted, + this, &ScriptlogDialog::saveChosenScripts + ); + connect( + buttons, &QDialogButtonBox::rejected, + this, &ScriptlogDialog::reject + ); + layout->addWidget(buttons); + } +} + +void ScriptlogDialog::saveChosenScripts() { + std::string chosenScripts; + QList itemList = _scriptlogList->selectedItems(); + for (int i = 0; i < itemList.size(); ++i) { + chosenScripts += itemList.at(i)->text().toStdString(); + if (i < itemList.size()) { + chosenScripts += "\n"; + } + } + _bindingDialog->appendScriptsToKeybind(chosenScripts); + + accept(); +} diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index fed1f55a0b..669fbc16a9 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit fed1f55a0b259a70a5ad8461a4e56f07990609f1 +Subproject commit 669fbc16a9910b28333427f5e07235baa43ea7a6 diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index 6330167b4a..9adc728a07 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -218,6 +218,15 @@ void mainInitFunc(GLFWwindow*) { LTRACE("main::mainInitFunc(begin)"); + // + // Screenshots + // + // We save the startup value of the screenshots just in case we want to add a date + // to them later in the RenderEngine + std::string screenshotPath = absPath("${SCREENSHOTS}"); + FileSys.registerPathToken("${STARTUP_SCREENSHOT}", screenshotPath); + Settings::instance().setCapturePath(screenshotPath); + LDEBUG("Initializing OpenSpace Engine started"); global::openSpaceEngine->initialize(); LDEBUG("Initializing OpenSpace Engine finished"); @@ -321,27 +330,6 @@ void mainInitFunc(GLFWwindow*) { #endif // OPENSPACE_HAS_SPOUT } - - // - // Screenshots - // - std::string screenshotPath = "${SCREENSHOTS}"; - if (global::configuration->shouldUseScreenshotDate) { - std::time_t now = std::time(nullptr); - std::tm* nowTime = std::localtime(&now); - char mbstr[128]; - strftime(mbstr, sizeof(mbstr), "%Y-%m-%d-%H-%M", nowTime); - - FileSys.registerPathToken( - "${SCREENSHOTS}", - absPath(screenshotPath + '/' + std::string(mbstr)), - ghoul::filesystem::FileSystem::Override::Yes - ); - } - - Settings::instance().setCapturePath(absPath(screenshotPath)); - - LTRACE("main::mainInitFunc(end)"); } @@ -1117,22 +1105,17 @@ int main(int argc, char* argv[]) { } LINFO(fmt::format("Configuration Path: '{}'", configurationFilePath)); + // Register the base path as the directory where the configuration file lives + std::string base = ghoul::filesystem::File(configurationFilePath).directoryName(); + constexpr const char* BasePathToken = "${BASE}"; + FileSys.registerPathToken(BasePathToken, base); + // Loading configuration from disk LDEBUG("Loading configuration from disk"); *global::configuration = configuration::loadConfigurationFromFile( - configurationFilePath + configurationFilePath, + commandlineArguments.configurationOverride ); - // If the user requested a commandline-based configuration script that should - // overwrite some of the values, this is the time to do it - if (!commandlineArguments.configurationOverride.empty()) { - LDEBUG("Executing Lua script passed through the commandline:"); - LDEBUG(commandlineArguments.configurationOverride); - ghoul::lua::runScript( - global::configuration->state, - commandlineArguments.configurationOverride - ); - parseLuaState(*global::configuration); - } // Determining SGCT configuration file LDEBUG("SGCT Configuration file: " + global::configuration->windowConfiguration); diff --git a/apps/TaskRunner/main.cpp b/apps/TaskRunner/main.cpp index 76b37e0f5e..7e038fe34d 100644 --- a/apps/TaskRunner/main.cpp +++ b/apps/TaskRunner/main.cpp @@ -122,7 +122,13 @@ int main(int argc, char** argv) { ); std::string configFile = configuration::findConfiguration(); - *global::configuration = configuration::loadConfigurationFromFile(configFile); + + // Register the base path as the directory where the configuration file lives + std::string base = ghoul::filesystem::File(configFile).directoryName(); + constexpr const char* BasePathToken = "${BASE}"; + FileSys.registerPathToken(BasePathToken, base); + + *global::configuration = configuration::loadConfigurationFromFile(configFile, ""); openspace::global::openSpaceEngine->registerPathTokens(); global::openSpaceEngine->initialize(); @@ -131,7 +137,7 @@ int main(int argc, char** argv) { ghoul::cmdparser::CommandlineParser::AllowUnknownCommands::Yes ); - std::string tasksPath = ""; + std::string tasksPath; commandlineParser.addCommand( std::make_unique>( tasksPath, @@ -146,7 +152,7 @@ int main(int argc, char** argv) { //FileSys.setCurrentDirectory(launchDirectory); - if (tasksPath != "") { + if (!tasksPath.empty()) { performTasks(tasksPath); return 0; } diff --git a/config/gui_projector.xml b/config/gui_projector.xml index 21e9d09a9f..9ac213193b 100644 --- a/config/gui_projector.xml +++ b/config/gui_projector.xml @@ -4,7 +4,7 @@ - + @@ -17,7 +17,7 @@ - + diff --git a/config/spherical_mirror.xml b/config/spherical_mirror.xml index fc98729758..f15de39d45 100644 --- a/config/spherical_mirror.xml +++ b/config/spherical_mirror.xml @@ -19,7 +19,7 @@ --> - + diff --git a/data/assets/base_blank.asset b/data/assets/base_blank.asset index 46736f0e37..41720dc915 100644 --- a/data/assets/base_blank.asset +++ b/data/assets/base_blank.asset @@ -8,8 +8,8 @@ local propertyHelper = asset.require('util/property_helper') asset.require('spice/base') -- Load default key bindings applicable to most scenes +asset.require('dashboard/default_dashboard') asset.require('util/default_keybindings') -asset.require('util/default_dashboard') asset.require('util/default_joystick') -- Load web gui diff --git a/data/assets/dashboard/date.asset b/data/assets/dashboard/date.asset new file mode 100644 index 0000000000..d92dec9632 --- /dev/null +++ b/data/assets/dashboard/date.asset @@ -0,0 +1,13 @@ +local item = { + Type = "DashboardItemDate", + Identifier = "Date", + GuiName = "Date" +} + +asset.onInitialize(function() + openspace.dashboard.addDashboardItem(item) +end) + +asset.onDeinitialize(function() + openspace.dashboard.removeDashboardItem(item.Identifier) +end) diff --git a/data/assets/dashboard/default_dashboard.asset b/data/assets/dashboard/default_dashboard.asset new file mode 100644 index 0000000000..af524db703 --- /dev/null +++ b/data/assets/dashboard/default_dashboard.asset @@ -0,0 +1,8 @@ +local assetHelper = asset.require('util/asset_helper') + +asset.require('./date') +asset.require('./simulationincrement') +asset.require('./distance') +asset.require('./framerate') +asset.require('./parallelconnection') +asset.require('./globelocation') diff --git a/data/assets/dashboard/distance.asset b/data/assets/dashboard/distance.asset new file mode 100644 index 0000000000..b05f79520d --- /dev/null +++ b/data/assets/dashboard/distance.asset @@ -0,0 +1,13 @@ +local item = { + Type = "DashboardItemDistance", + Identifier = "Distance", + GuiName = "Distance" +} + +asset.onInitialize(function() + openspace.dashboard.addDashboardItem(item) +end) + +asset.onDeinitialize(function() + openspace.dashboard.removeDashboardItem(item.Identifier) +end) diff --git a/data/assets/dashboard/framerate.asset b/data/assets/dashboard/framerate.asset new file mode 100644 index 0000000000..ea95484f7d --- /dev/null +++ b/data/assets/dashboard/framerate.asset @@ -0,0 +1,13 @@ +local item = { + Type = "DashboardItemFramerate", + Identifier = "Framerate", + GuiName = "Framerate" +} + +asset.onInitialize(function() + openspace.dashboard.addDashboardItem(item) +end) + +asset.onDeinitialize(function() + openspace.dashboard.removeDashboardItem(item.Identifier) +end) diff --git a/data/assets/dashboard/globelocation.asset b/data/assets/dashboard/globelocation.asset new file mode 100644 index 0000000000..da36c97a46 --- /dev/null +++ b/data/assets/dashboard/globelocation.asset @@ -0,0 +1,13 @@ +local item = { + Type = "DashboardItemGlobeLocation", + Identifier = "GlobeLocation", + GuiName = "Globe Location" +} + +asset.onInitialize(function() + openspace.dashboard.addDashboardItem(item) +end) + +asset.onDeinitialize(function() + openspace.dashboard.removeDashboardItem(item.Identifier) +end) diff --git a/data/assets/dashboard/parallelconnection.asset b/data/assets/dashboard/parallelconnection.asset new file mode 100644 index 0000000000..6bc13dc818 --- /dev/null +++ b/data/assets/dashboard/parallelconnection.asset @@ -0,0 +1,13 @@ +local item = { + Type = "DashboardItemParallelConnection", + Identifier = "ParallelConnection", + GuiName = "Parallel Connection" +} + +asset.onInitialize(function() + openspace.dashboard.addDashboardItem(item) +end) + +asset.onDeinitialize(function() + openspace.dashboard.removeDashboardItem(item.Identifier) +end) diff --git a/data/assets/dashboard/simulationincrement.asset b/data/assets/dashboard/simulationincrement.asset new file mode 100644 index 0000000000..6431e403bd --- /dev/null +++ b/data/assets/dashboard/simulationincrement.asset @@ -0,0 +1,13 @@ +local item = { + Type = "DashboardItemSimulationIncrement", + Identifier = "SimulationIncrement", + GuiName = "Simulation Increment" +} + +asset.onInitialize(function() + openspace.dashboard.addDashboardItem(item) +end) + +asset.onDeinitialize(function() + openspace.dashboard.removeDashboardItem(item.Identifier) +end) diff --git a/data/assets/dashboard/velocity.asset b/data/assets/dashboard/velocity.asset new file mode 100644 index 0000000000..89655ce60f --- /dev/null +++ b/data/assets/dashboard/velocity.asset @@ -0,0 +1,14 @@ +local item = { + Type = "DashboardItemVelocity", + Identifier = "GlobeLocation", + Simplification = true, + GuiName = "Velocity" +} + +asset.onInitialize(function() + openspace.dashboard.addDashboardItem(item) +end) + +asset.onDeinitialize(function() + openspace.dashboard.removeDashboardItem(item.Identifier) +end) diff --git a/data/assets/examples/spheres.asset b/data/assets/examples/spheres.asset index 2510084d70..f19458eacd 100644 --- a/data/assets/examples/spheres.asset +++ b/data/assets/examples/spheres.asset @@ -18,7 +18,7 @@ for z=1,3 do Size = 0.20 + i * 0.01, Segments = 80, Opacity = 1, - Texture = "${DATA}/test2.jpg", + Texture = openspace.absPath("${DATA}/test2.jpg"), Orientation = "Both", }, GUI = { diff --git a/data/assets/scene/digitaluniverse/grids.asset b/data/assets/scene/digitaluniverse/grids.asset index 16f4afd20b..55dc314238 100644 --- a/data/assets/scene/digitaluniverse/grids.asset +++ b/data/assets/scene/digitaluniverse/grids.asset @@ -104,12 +104,6 @@ local ecliptic = { local eclipticLabels = { Identifier = "EclipticSphereLabels", Parent = transforms.SolarSystemBarycenter.Name, - Transform = { - Rotation = { - Type = "StaticRotation", - Rotation = eclipticRotationMatrix - } - }, Renderable = { Type = "RenderableBillboardsCloud", Enabled = false, @@ -122,6 +116,12 @@ local eclipticLabels = { TextMinSize = 1.3, TextMaxSize = 50.0, Unit = "pc", + TransformationMatrix = { + -0.05487554, 0.4941095, -0.8676661, 0.0, + -0.9938214 , -0.1109906, -0.0003515167, 0.0, + -0.09647644, 0.8622859, 0.4971472, 0.0, + 0.0, 0.0, 0.0, 1.0 + } }, GUI = { Name = "Ecliptic Sphere Labels", @@ -158,12 +158,6 @@ local equatorial = { local equatorialLabels = { Identifier = "EquatorialSphereLabels", Parent = transforms.SolarSystemBarycenter.Name, - Transform = { - Rotation = { - Type = "StaticRotation", - Rotation = equatorialRotationMatrix - } - }, Renderable = { Type = "RenderableBillboardsCloud", Enabled = false, @@ -176,6 +170,12 @@ local equatorialLabels = { TextMinSize = 1.7, TextMaxSize = 70.0, Unit = "pc", + TransformationMatrix = { + -0.05487554, 0.4941095, -0.8676661, 0.0, + -0.8734371 , -0.4448296, -0.1980764, 0.0, + -0.483835 , 0.7469823, 0.4559838, 0.0, + 0.0 , 0.0 , 0.0 , 1.0 + } }, GUI = { Name = "Equatorial Sphere Labels", diff --git a/data/assets/scene/digitaluniverse/kepler.asset b/data/assets/scene/digitaluniverse/kepler.asset index 04fc503c77..1d5834487a 100644 --- a/data/assets/scene/digitaluniverse/kepler.asset +++ b/data/assets/scene/digitaluniverse/kepler.asset @@ -13,7 +13,7 @@ local speck = asset.syncedResource({ Name = "Kepler Speck Files", Type = "HttpSynchronization", Identifier = "digitaluniverse_kepler_speck", - Version = 2 + Version = 3 }) local object = { diff --git a/data/assets/scene/digitaluniverse/stars.asset b/data/assets/scene/digitaluniverse/stars.asset index e269202667..d4b114322e 100644 --- a/data/assets/scene/digitaluniverse/stars.asset +++ b/data/assets/scene/digitaluniverse/stars.asset @@ -1,6 +1,6 @@ local assetHelper = asset.require('util/asset_helper') - +local colorLUT = asset.require('./stars_colormap').BvColorLUT local textures = asset.syncedResource({ Name = "Stars Textures", @@ -23,13 +23,6 @@ local sunspeck = asset.syncedResource({ Version = 1 }) -local colorLUT = asset.syncedResource({ - Name = "Stars Color Table", - Type = "HttpSynchronization", - Identifier = "stars_colormap", - Version = 2 -}) - local stars = { Identifier = "Stars", Renderable = { diff --git a/data/assets/scene/digitaluniverse/stars_colormap.asset b/data/assets/scene/digitaluniverse/stars_colormap.asset new file mode 100644 index 0000000000..f7f6432f7d --- /dev/null +++ b/data/assets/scene/digitaluniverse/stars_colormap.asset @@ -0,0 +1,22 @@ +local assetHelper = asset.require('util/asset_helper') + +local BvColorLUT = asset.syncedResource({ + Name = "Stars Color Table", + Type = "HttpSynchronization", + Identifier = "stars_colormap", + Version = 2 +}) + +asset.export("BvColorLUT", BvColorLUT) + +asset.meta = { + Name = "Stars B-V Colormap", + Version = "2.0", + Description = [[A lookup table that maps a B-V color index to an RGB color. + The B-V values are in the range (-0.4, 2.0) and each line maps a value + in that range to a color]], + Author = "OpenSpace Team", + URL = "https://www.amnh.org/research/hayden-planetarium/digital-universe", + License = "AMNH Digital Universe" +} + diff --git a/data/assets/scene/milkyway/constellations/constellation_art.asset b/data/assets/scene/milkyway/constellations/constellation_art.asset index c77fa2e29f..cc0db4c8d9 100644 --- a/data/assets/scene/milkyway/constellations/constellation_art.asset +++ b/data/assets/scene/milkyway/constellations/constellation_art.asset @@ -5,7 +5,7 @@ local images = asset.syncedResource({ Name = "Constellation Images", Type = "HttpSynchronization", Identifier = "constellation_images", - Version = 2 + Version = 3 }) --function that reads the file diff --git a/data/assets/scene/milkyway/constellations/constellation_extrakeybinds.asset b/data/assets/scene/milkyway/constellations/constellation_extrakeybinds.asset new file mode 100644 index 0000000000..35ea29873f --- /dev/null +++ b/data/assets/scene/milkyway/constellations/constellation_extrakeybinds.asset @@ -0,0 +1,40 @@ +local scene_helper = asset.require('util/scene_helper') + +local Keybindings = { + + { + Key = "v", + Name = "Show Constellation Art", + Command = "openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Opacity', 0);" .. + "openspace.setPropertyValue('{zodiac}.Renderable.Enabled',true);" .. + "openspace.setPropertyValue('{zodiac}.Renderable.Opacity', 1, 2);", + Documentation = "Enables and fades up zodiac art work", + GuiPath = "/Rendering", + Local = false + }, + { + Key = "Shift+v", + Name = "Show Constellation Art", + Command = "openspace.setPropertyValue('{zodiac}.Renderable.Opacity', 0, 2);", + Documentation = "fades down zodiac art work", + GuiPath = "/Rendering", + Local = false + }, +} + +asset.onInitialize(function () + scene_helper.bindKeys(Keybindings) +end) + +asset.onDeinitialize(function () + scene_helper.unbindKeys(Keybindings) +end) + +asset.meta = { + Name = "Constellation Image Extra Keybinds", + Version = "1.0", + Description = "Artistic images depicting the constellations", + Author = "James Hedberg", + URL = "http://jameshedberg.com", + License = "CC-BY" +} diff --git a/data/assets/scene/milkyway/constellations/constellation_keybinds.asset b/data/assets/scene/milkyway/constellations/constellation_keybinds.asset index ac310f24a2..08765add84 100644 --- a/data/assets/scene/milkyway/constellations/constellation_keybinds.asset +++ b/data/assets/scene/milkyway/constellations/constellation_keybinds.asset @@ -6,7 +6,7 @@ local Keybindings = { Name = "Show Constellation Art", Command = "openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Opacity', 0);" .. "openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Enabled', true);" .. - "openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Opacity', 0.1, 2);", + "openspace.setPropertyValue('Scene.ConstellationArt*.Renderable.Opacity', 0.2, 2);", Documentation = "Enables and fades up constellation art work", GuiPath = "/Rendering", Local = false @@ -39,10 +39,10 @@ end) asset.meta = { - Name = "Constellation Image Keybinds", - Version = "1.0", - Description = "Keybinds for fading in and out the constellations", - Author = "OpenSpace Team", - URL = "http://openspaceproject.com", - License = "MIT License" + Name = "Constellation Image Keybinds", + Version = "1.0", + Description = "Artistic images depicting the constellations", + Author = "James Hedberg", + URL = "http://jameshedberg.com", + License = "CC-BY" } diff --git a/data/assets/scene/milkyway/exoplanets/exoplanets_data.asset b/data/assets/scene/milkyway/exoplanets/exoplanets_data.asset index 934d276c5c..76d4cddbdc 100644 --- a/data/assets/scene/milkyway/exoplanets/exoplanets_data.asset +++ b/data/assets/scene/milkyway/exoplanets/exoplanets_data.asset @@ -1,3 +1,5 @@ +local bvColorLUT = asset.require('scene/digitaluniverse/stars_colormap').BvColorLUT + local DataPath = asset.syncedResource({ Name = "Exoplanet Data Files", Type = "HttpSynchronization", @@ -7,9 +9,14 @@ local DataPath = asset.syncedResource({ asset.onInitialize(function () local p = "Modules.Exoplanets.DataFolder"; - if(openspace.getPropertyValue(p) == "") then + if (openspace.getPropertyValue(p) == "") then openspace.setPropertyValueSingle(p, DataPath) end + + p = "Modules.Exoplanets.BvColormap"; + if (openspace.getPropertyValue(p) == "") then + openspace.setPropertyValueSingle(p, bvColorLUT .. "/colorbv.cmap") + end end) asset.export("DataPath", DataPath) @@ -22,5 +29,5 @@ asset.meta = { Archive]], Author = "OpenSpace Team", URL = "https://exoplanetarchive.ipac.caltech.edu/docs/data.html", - License = "MIT license", + License = "MIT license" } diff --git a/data/assets/scene/solarsystem/dwarf_planets/pluto/charon/charon.asset b/data/assets/scene/solarsystem/dwarf_planets/pluto/charon/charon.asset index 4b6aa574c2..0d45b5abd9 100644 --- a/data/assets/scene/solarsystem/dwarf_planets/pluto/charon/charon.asset +++ b/data/assets/scene/solarsystem/dwarf_planets/pluto/charon/charon.asset @@ -13,8 +13,7 @@ local Charon = { Translation = { Type = "SpiceTranslation", Target = "CHARON", - Observer = "PLUTO BARYCENTER", - Kernels = NewHorizonsKernels + Observer = "PLUTO BARYCENTER" }, Rotation = { Type = "SpiceRotation", diff --git a/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/kerberos.asset b/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/kerberos.asset index 0434de709b..fb2ddb43a6 100644 --- a/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/kerberos.asset +++ b/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/kerberos.asset @@ -11,8 +11,7 @@ local Kerberos = { Translation = { Type = "SpiceTranslation", Target = "KERBEROS", - Observer = "PLUTO BARYCENTER", - Kernels = PlutoKernels + Observer = "PLUTO BARYCENTER" } }, Renderable = { diff --git a/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/nix.asset b/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/nix.asset index bea389470d..c5f7e03923 100644 --- a/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/nix.asset +++ b/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/nix.asset @@ -11,8 +11,7 @@ local Nix = { Translation = { Type = "SpiceTranslation", Target = "NIX", - Observer = "PLUTO BARYCENTER", - Kernels = PlutoKernels + Observer = "PLUTO BARYCENTER" } }, Renderable = { diff --git a/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/styx.asset b/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/styx.asset index 25c369e4e7..bc54df433a 100644 --- a/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/styx.asset +++ b/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/styx.asset @@ -3,7 +3,6 @@ local transforms = asset.require('../transforms') local kernels = asset.require('../kernels').PlutoKernels - local Styx = { Identifier = "Styx", Parent = transforms.PlutoBarycenter.Identifier, @@ -11,8 +10,7 @@ local Styx = { Translation = { Type = "SpiceTranslation", Target = "STYX", - Observer = "PLUTO BARYCENTER", - Kernels = PlutoKernels + Observer = "PLUTO BARYCENTER" } }, Renderable = { diff --git a/data/assets/scene/solarsystem/dwarf_planets/pluto/pluto.asset b/data/assets/scene/solarsystem/dwarf_planets/pluto/pluto.asset index 5299ebc5dd..968a7edd86 100644 --- a/data/assets/scene/solarsystem/dwarf_planets/pluto/pluto.asset +++ b/data/assets/scene/solarsystem/dwarf_planets/pluto/pluto.asset @@ -13,8 +13,7 @@ local Pluto = { Translation = { Type = "SpiceTranslation", Target = "PLUTO", - Observer = "PLUTO BARYCENTER", - Kernels = NewHorizonsKernels + Observer = "PLUTO BARYCENTER" }, Rotation = { Type = "SpiceRotation", diff --git a/data/assets/scene/solarsystem/missions/apollo/11/lem_flipbook.asset b/data/assets/scene/solarsystem/missions/apollo/11/lem_flipbook.asset index a716eb4626..06e4259d50 100644 --- a/data/assets/scene/solarsystem/missions/apollo/11/lem_flipbook.asset +++ b/data/assets/scene/solarsystem/missions/apollo/11/lem_flipbook.asset @@ -18,13 +18,8 @@ asset.onInitialize(function () openspace.globebrowsing.addBlendingLayersFromDirectory(vrts, assetGlobe); flipbook = helper.createFlipbook(assetPrefix, assetGlobe, 19); - function nextFlip() - helper.nextFlipbookPage(flipbook); - end - - function previousFlip() - helper.previousFlipbookPage(flipbook); - end + rawset(_G, "nextFlip", function() helper.nextFlipbookPage(flipbook) end) + rawset(_G, "previousFlip", function() helper.previousFlipbookPage(flipbook) end) openspace.bindKey("p", "nextFlip()", "Show the next Apollo 11 flipbook image.", "Next A11 flip", "/Missions/Apollo/11") openspace.bindKey("o", "previousFlip()","Show the previous Apollo 11 flipbook image.", "Prev A11 flip", "/Missions/Apollo/11") diff --git a/data/assets/scene/solarsystem/missions/apollo/15/apollo15.asset b/data/assets/scene/solarsystem/missions/apollo/15/apollo15.asset index 7e6001679f..900a9631af 100644 --- a/data/assets/scene/solarsystem/missions/apollo/15/apollo15.asset +++ b/data/assets/scene/solarsystem/missions/apollo/15/apollo15.asset @@ -1,8 +1,8 @@ local assetHelper = asset.require('util/asset_helper') local moon_transforms = asset.require('scene/solarsystem/planets/earth/moon/moon') local sun_transforms = asset.require('scene/solarsystem/sun/transforms') -local csm = asset.require('../apollo_csm') asset.require('spice/base') +local models = asset.require('scene/solarsystem/missions/apollo/csm_model').models local kernels = asset.require('scene/solarsystem/missions/apollo/15/kernels').kernels @@ -47,6 +47,20 @@ local Apollo15 = { DestinationFrame = "GALACTIC" } }, + Renderable = { + Type = "RenderableModel", + GeometryFile = models .. "/ApolloCSM.fbx", + LightSources = { + { + Type = "SceneGraphLightSource", + Identifier = "Sun", + Node = sun_transforms.SolarSystemBarycenter.Identifier, + Intensity = 1.0 + } + }, + PerformShading = true, + DisableFaceCulling = true + }, TimeFrame = { Type = "TimeFrameInterval", Start = "1971-07-30T02:22:00.00", @@ -101,13 +115,6 @@ local Apollo15Trail = { } } - -local model_part = csm.createCsmModel(Apollo15.Identifier) - local list = { Apollo15, Apollo15Trail } -for k,v in pairs(model_part) do - v.GUI.Path = "/Solar System/Missions/Apollo/15/Model" - table.insert(list, v) -end assetHelper.registerSceneGraphNodesAndExport(asset, list) diff --git a/data/assets/scene/solarsystem/missions/apollo/8/launch_model.asset b/data/assets/scene/solarsystem/missions/apollo/8/launch_model.asset index 1e76c60931..9e5b749c17 100644 --- a/data/assets/scene/solarsystem/missions/apollo/8/launch_model.asset +++ b/data/assets/scene/solarsystem/missions/apollo/8/launch_model.asset @@ -1,7 +1,8 @@ local asset_helper = asset.require('util/asset_helper') local earth_transforms = asset.require('scene/solarsystem/planets/earth/transforms') +local sun_transforms = asset.require('scene/solarsystem/sun/transforms') local kernels = asset.require('./kernels').kernels -local csm = asset.require('../apollo_csm') +local models = asset.require('scene/solarsystem/missions/apollo/csm_model').models local apolloSpiceId = "-908" @@ -47,6 +48,20 @@ local Apollo8LaunchModel = { Rotation = {0.0, 0.0, -3.1415 / 2} } }, + Renderable = { + Type = "RenderableModel", + GeometryFile = models .. "/ApolloCSM.fbx", + LightSources = { + { + Type = "SceneGraphLightSource", + Identifier = "Sun", + Node = sun_transforms.SolarSystemBarycenter.Identifier, + Intensity = 1.0 + } + }, + PerformShading = true, + DisableFaceCulling = true + }, GUI = { Hidden = true, Name = "Apollo 8 Launch Model", @@ -54,12 +69,6 @@ local Apollo8LaunchModel = { } } -local launch_model_part = csm.createCsmModel(Apollo8LaunchModel.Identifier) - local list = { Apollo8Launch, Apollo8LaunchModel } -for k,v in pairs(launch_model_part) do - v.GUI.Path = "/Solar System/Missions/Apollo/8/Model" - table.insert(list, v) -end asset_helper.registerSceneGraphNodesAndExport(asset, list) diff --git a/data/assets/scene/solarsystem/missions/apollo/8/model.asset b/data/assets/scene/solarsystem/missions/apollo/8/model.asset index 4b677cc818..00036a697a 100644 --- a/data/assets/scene/solarsystem/missions/apollo/8/model.asset +++ b/data/assets/scene/solarsystem/missions/apollo/8/model.asset @@ -1,7 +1,8 @@ local asset_helper = asset.require('util/asset_helper') local earth_transforms = asset.require('scene/solarsystem/planets/earth/transforms') +local sun_transforms = asset.require('scene/solarsystem/sun/transforms') local kernels = asset.require('./kernels').kernels -local csm = asset.require('../apollo_csm') +local models = asset.require('scene/solarsystem/missions/apollo/csm_model').models local apolloSpiceId = "-908" @@ -59,6 +60,20 @@ local Apollo8Model = { Rotation = {0.0, 0.0, -3.1415 / 2} } }, + Renderable = { + Type = "RenderableModel", + GeometryFile = models .. "/ApolloCSM.fbx", + LightSources = { + { + Type = "SceneGraphLightSource", + Identifier = "Sun", + Node = sun_transforms.SolarSystemBarycenter.Identifier, + Intensity = 1.0 + } + }, + PerformShading = true, + DisableFaceCulling = true + }, GUI = { Hidden = true, Name = "Apollo 8 Model", @@ -82,12 +97,6 @@ local Apollo8Pivot = { } } -local model_part = csm.createCsmModel(Apollo8Model.Identifier) - local list = { Apollo8, Apollo8Model, Apollo8Pivot } -for k,v in pairs(model_part) do - v.GUI.Path = "/Solar System/Missions/Apollo/8/Model" - table.insert(list, v) -end asset_helper.registerSceneGraphNodesAndExport(asset, list) diff --git a/data/assets/scene/solarsystem/missions/apollo/apollo_csm.asset b/data/assets/scene/solarsystem/missions/apollo/apollo_csm.asset deleted file mode 100644 index 32581a1597..0000000000 --- a/data/assets/scene/solarsystem/missions/apollo/apollo_csm.asset +++ /dev/null @@ -1,280 +0,0 @@ --- This asset exports a function to create an Apollo Command and Service Module (CSM). --- Instead of hard-coding the scene graph node parent, --- client assets can decide which object that the CSM should be attached to. --- Usage example: createCsmModel(asset, Apollo8.Idenfitier) --- ...where Apollo8 is the scene graph node identifier to attach the CSM to. - -local asset_helper = asset.require('util/asset_helper') -local sun_transforms = asset.require('scene/solarsystem/sun/transforms') - -local models = asset.syncedResource({ - Name = "Apollo Models", - Type = "HttpSynchronization", - Identifier = "apollo_models", - Version = 1 -}) - -local partsInfo = { - -- Data is structured as: Geometry file name (except .obj suffix), texture file name, shading - - -- Exterior - { "AP08_cone_command_module", "Command_module_diff.png", true }, - { "AP08_cone_hatchdoor_handle_scratched_metal", "scratched_metal_gloss.png", true }, - { "AP08_cone_vent_ports_black", "black.png", true }, - { "AP08_cone_vent_ports_red", "red.png", true }, - { "AP08_cone_hatchdoor_interior", "apollo_hatchdoor_interior.jpg", false }, - - { "AP08_service_black", "black.png", true }, - { "AP08_service_brown", "brown.png", true }, - { "AP08_service_grey", "gray.png", true }, - { "AP08_service_high_gain_antenna", "Antenna_diff.png", true }, - { "AP08_service_module", "Service_module_diff.png", true }, - { "AP08_service_nozzle", "Nozzle_diff.png", true }, - { "AP08_service_pink", "pink.png", true }, - { "AP08_service_red", "red.png", true }, - { "AP08_service_scratched_metal", "scratched_metal_gloss.png", true }, - { "AP08_service_white", "white.png", true }, - - -- Interior - -- { "AP11_int_back_wall_left", "AP11_int_back_wall_left.png", false}, - -- { "AP11_int_back_wall_right", "AP11_int_back_wall_right.png", false }, - -- { "AP11_interior_back_wall_top_0Shape3", "back_wall_top_0Shape3_tpAmbient_paint_03.png", false }, - -- { "AP11_interior_belt_buckles_02_L2", "belt_buckles_02_L2Shape_tpAmbient.png", false }, - -- { "AP11_interior_belt_straps_02", "belt_straps_02Shape_tpAmbient_paint_01.png", false }, - -- { "AP11_interior_black_push_buttons", "push_buttonsShape_tpAmbient.png", false }, - -- { "AP11_interior_bottom_boxes_03", "bottom_boxes_03_paint_01.png", false }, - -- { "AP11_interior_bottom_floor_tp", "bottom_floor_tpAmbient_paint_v002.png", false }, - -- { "AP11_interior_box_back_01", "box_back_01_paint_v001.png", false }, - -- { "AP11_interior_box_back_02", "box_back_02_paint_v001.png", false }, - -- { "AP11_interior_box_back_04", "box_back_04_paint_v001.png", false }, - -- { "AP11_interior_box_lft_lower_01", "box_lft_lower_01Shape_Diffuse_paint_v002.png", false }, - -- { "AP11_interior_box_lft_top", "box_lft_topShape_Diffuse_paint_v009.png", false }, - -- { "AP11_interior_box_mid_tp", "box_mid_tpDiffuse_paint_v001.png", false }, - -- { "AP11_interior_box_rt_top_02", "box_rt_top_02_paint_04.png", false }, - -- { "AP11_interior_brushed_blue_ano", "brushed_blue_ano_paint_01.png", false }, - -- { "AP11_interior_brushed_brass", "brushed_brass_paint_01.png", false }, - -- { "AP11_interior_brushed_grey_ano", "brushed_grey_ano_paint_02.png", false }, - -- { "AP11_interior_canvas_cover", "canvas_coverShape_tpAmbient_paint_01.png", false }, - -- { "AP11_interior_Channel_attachment", "Channel_attachment_Diffuse.png", false }, - -- { "AP11_interior_Channel_baseMetal", "Channel_baseMetal_Diffuse.png", false }, - -- { "AP11_interior_Channel_Material", "Channel_Material_Diffuse.png", false }, - -- { "AP11_interior_Channel_rsMaterial2", "Channel_rsMaterial2_Diffuse.png", false }, - -- { "AP11_interior_cloth_01", "cloth_01Shape_tpAmbient_paint_01.png", false }, - -- { "AP11_interior_coiled_hose", "coiled_hoseShape_tpAmbient.png", false }, - -- { "AP11_interior_control_panel_left_win_plates", "control_panel_left_win_platesShape_tpAmbient.png", false }, - -- { "AP11_interior_control_panel_rt_win_plates", "control_panel_rt_win_platesShape_tpAmbient.png", false }, - -- { "AP11_interior_copper_parts_main_cp", "copper_parts_main_cpShape_tpAmbient.png", false }, - -- { "AP11_interior_dials_main2", "dials_main2Shape_tpAmbient.png", false }, - -- { "AP11_interior_dials_t2", "dials_t2Shape_tpAmbient.png", false }, - -- { "AP11_interior_dial_fixes_01", "dial_fixes_01Shape_tpAmbient.png", false }, - -- { "AP11_interior_fire_ex_02", "fire_ex_02_paint_v001.png", false }, - -- { "AP11_interior_floor_panels_3", "floor_panels_3Shape_tpAmbient_paint_01.png", false }, - -- { "AP11_interior_floor_tile_tex_01", "floor_tile_tex_01.png", false }, - -- { "AP11_interior_grey", "gray.png", false }, - -- { "AP11_interior_handholds_cp", "handholds_cpShape_tpAmbient_paint_05.png", false }, - -- { "AP11_interior_hatch_release_0Shape5", "hatch_release_0Shape5_tpAmbient_paint_02.png", false }, - -- { "AP11_interior_headrests_02", "headrests_02Shape_tpAmbient_paint_01.png", false }, - -- { "AP11_interior_hoses_black_01", "hoses_black_01Shape_tpAmbient_paint_01.png", false }, - -- { "AP11_interior_hoses_white_0Shape1", "hoses_white_0Shape1_tpAmbient_paint_01.png", false }, - -- { "AP11_interior_josticks1", "joysticks1Shape_tpAmbient_paint_01.png", false }, - -- { "AP11_interior_joysticks_fabric1", "joysticks_fabric1_Shape_tpAmbient_paint_01.png", false }, - -- { "AP11_interior_joystick_poles_lft_05", "joystick_poles_lft_05_paint_v002.png", false }, - -- { "AP11_interior_joystick_poles_lft_long_05", "joystick_poles_lft_long_05_paint_v002.png", false }, - -- { "AP11_interior_joystick_poles_rt_05", "joystick_poles_rt_05_paint_v002.png", false }, - -- { "AP11_interior_latch_mechanisms_01", "latch_mechanisms_01Shape_tpAmbient.png", false }, - -- { "AP11_interior_lower_push_buttons", "lower_push_buttonsShape_tpAmbient.png", false }, - -- { "AP11_interior_lower_walls_back", "lower_walls_back_paint_04.png", false }, - -- { "AP11_interior_lower_walls_boxes_head", "lower_walls_boxes_headShape_tpAmbient_paint_v001.png", false }, - -- { "AP11_interior_main_cp_left_smth_03", "main_cp_left_0Shape3_tpAmbient_paint_02.png", false }, - -- { "AP11_interior_main_cp_mid_smth_02", "main_cp_mid_smth_02Shape_tpAmbient_paint_02.png", false }, - -- { "AP11_interior_main_cp_rt_smth", "main_cp_rt_smthShape_tpAmbient_paint_02.png", false }, - -- { "AP11_interior_main_cp_wheels", "main_cp_wheelsShape_tpAmbient.png", false }, - -- { "AP11_interior_metal_brackets_under_hatch", "metal_brackets_under_hatchShape_tpAmbient.png", false }, - -- { "AP11_interior_metal_tunnel_parts", "metal_tunnel_partsShape_tpAmbient_paint_01.png", false }, - -- { "AP11_interior_metal_window_parts", "metal_window_partsShape_tpAmbient_paint_01.png", false }, - -- { "AP11_interior_middle_walls_05", "middle_walls_05_tpAmbient_paint_02.png", false }, - -- { "AP11_interior_middle_walls_0Shape8", "middle_walls_0Shape8_tpAmbient_paint_01.png", false }, - -- { "AP11_interior_mid_tunnel_parts", "mid_tunnel_parts_03Shape_tpAmbient_paint_02.png", false }, - -- { "AP11_interior_new_switch_rails1", "new_switch_rails1Shape_tpAmbient.png", false }, - -- { "AP11_interior_nozzles_02", "nozzles_02Shape_tpAmbient_paint_01.png", false }, - -- { "AP11_interior_outlet_fabric3", "outlet_fabric3Shape_tpAmbient_paint_02.png", false }, - -- { "AP11_interior_pole_end_02", "pole_end_02.png", false }, - -- { "AP11_interior_pole_end_03", "pole_end_03.png", false }, - -- { "AP11_interior_pole_tex_03", "pole_tex_03.png", false }, - -- { "AP11_interior_pole_tex_04", "pole_tex_04.png", false }, - -- { "AP11_interior_pole_tex_05", "pole_tex_05.png", false }, - -- { "AP11_interior_pole_tex_lower_01", "pole_tex_lower_01.png", false }, - -- { "AP11_interior_pole_under_seat_paint_01", "pole_under_seat_paint_01.png", false }, - -- { "AP11_interior_pole_under_seat_square_bar", "pole_under_seat_square_bar_paint_01.png", false }, - -- { "AP11_interior_push_switches_lft1", "push_switches_lft1Shape_tpAmbient.png", false }, - -- { "AP11_interior_random_small_parts_01", "random_small_parts_01Shape_tpAmbient_paint_02.png", false }, - -- { "AP11_interior_red", "red.png", false }, - -- { "AP11_interior_reticle_wheel_tp", "reticle_wheel_tpAmbient_paint_01.png", false }, - -- { "AP11_interior_rivet_paint_v001", "rivet_paint_v001.png", false }, - -- { "AP11_interior_seats_fabric", "seats_fabric_paint_01.png", false }, - -- { "AP11_interior_seat_left_tp", "seat_left_tpAmbient_paint_v001.png", false }, - -- { "AP11_interior_seat_lights_left", "seat_lights_left_Shape_tpAmbient_paint_v001.png", false }, - -- { "AP11_interior_seat_lights_rt", "seat_lights_rt_Shape_tpAmbient_paint_v001.png", false }, - -- { "AP11_interior_seat_middle_tp", "seat_middle_tpAmbient_paint_v001.png", false }, - -- { "AP11_interior_seat_poles_0Shape1", "seat_poles_0Shape1_tpAmbient_paint_01.png", false }, - -- { "AP11_interior_seat_pole_mirror_0Shape1", "seat_pole_mirror_0Shape1_tpAmbient_paint_01.png", false }, - -- { "AP11_interior_seat_rt_tp", "seat_rt_tpAmbient_paint_v001.png", false }, - -- { "AP11_interior_sextant_0Shape2", "sextant_0Shape2_tpAmbient.png", false }, - -- { "AP11_interior_switch_covers_main_middle1", "switch_covers_main_middle1Shape_tpAmbient.png", false }, - -- { "AP11_interior_switch_rails_lft", "switch_rails_lftShape_tpAmbient.png", false }, - -- { "AP11_interior_tunnel_main_cylinder1", "switch_rails_lftShape_tpAmbient.png", false }, - -- { "AP11_interior_tunnel_switches_01", "tunnel_switches_01Shape_tpAmbient.png", false }, - -- { "AP11_interior_tunnel_wheelsShape", "tunnel_wheelsShape_tpAmbient.png", false }, - -- { "AP11_interior_walls_mid_left", "walls_mid_leftShape_tpAmbient_paint_01.png", false }, - -- { "AP11_interior_windows_front_0Shape4", "windows_front_0Shape4_tpAmbient_paint_01.png", false } -} - - -local partsInfoFull = { - -- Data is structured as: Geometry file name (except .obj suffix), texture file name, shading - - -- Exterior - { "AP08_cone_command_module", "Command_module_diff.png", true }, - { "AP08_cone_hatchdoor_handle_scratched_metal", "scratched_metal_gloss.png", true }, - { "AP08_cone_vent_ports_black", "black.png", true }, - { "AP08_cone_vent_ports_red", "red.png", true }, - { "AP08_cone_hatchdoor_interior", "apollo_hatchdoor_interior.jpg", false }, - - { "AP08_service_black", "black.png", true }, - { "AP08_service_brown", "brown.png", true }, - { "AP08_service_grey", "gray.png", true }, - { "AP08_service_high_gain_antenna", "Antenna_diff.png", true }, - { "AP08_service_module", "Service_module_diff.png", true }, - { "AP08_service_nozzle", "Nozzle_diff.png", true }, - { "AP08_service_pink", "pink.png", true }, - { "AP08_service_red", "red.png", true }, - { "AP08_service_scratched_metal", "scratched_metal_gloss.png", true }, - { "AP08_service_white", "white.png", true }, - - -- Interior - { "AP11_int_back_wall_left", "AP11_int_back_wall_left.png", false }, - { "AP11_int_back_wall_right", "AP11_int_back_wall_right.png", false }, - { "AP11_interior_back_wall_top_0Shape3", "back_wall_top_0Shape3_tpAmbient_paint_03.png", false }, - { "AP11_interior_belt_buckles_02_L2", "belt_buckles_02_L2Shape_tpAmbient.png", false }, - { "AP11_interior_belt_straps_02", "belt_straps_02Shape_tpAmbient_paint_01.png", false }, - { "AP11_interior_black_push_buttons", "push_buttonsShape_tpAmbient.png", false }, - { "AP11_interior_bottom_boxes_03", "bottom_boxes_03_paint_01.png", false }, - { "AP11_interior_bottom_floor_tp", "bottom_floor_tpAmbient_paint_v002.png", false }, - { "AP11_interior_box_back_01", "box_back_01_paint_v001.png", false }, - { "AP11_interior_box_back_02", "box_back_02_paint_v001.png", false }, - { "AP11_interior_box_back_04", "box_back_04_paint_v001.png", false }, - { "AP11_interior_box_lft_lower_01", "box_lft_lower_01Shape_Diffuse_paint_v002.png", false }, - { "AP11_interior_box_lft_top", "box_lft_topShape_Diffuse_paint_v009.png", false }, - { "AP11_interior_box_mid_tp", "box_mid_tpDiffuse_paint_v001.png", false }, - { "AP11_interior_box_rt_top_02", "box_rt_top_02_paint_04.png", false }, - { "AP11_interior_brushed_blue_ano", "brushed_blue_ano_paint_01.png", false }, - { "AP11_interior_brushed_brass", "brushed_brass_paint_01.png", false }, - { "AP11_interior_brushed_grey_ano", "brushed_grey_ano_paint_02.png", false }, - { "AP11_interior_canvas_cover", "canvas_coverShape_tpAmbient_paint_01.png", false }, - { "AP11_interior_Channel_attachment", "Channel_attachment_Diffuse.png", false }, - { "AP11_interior_Channel_baseMetal", "Channel_baseMetal_Diffuse.png", false }, - { "AP11_interior_Channel_Material", "Channel_Material_Diffuse.png", false }, - { "AP11_interior_Channel_rsMaterial2", "Channel_rsMaterial2_Diffuse.png", false }, - { "AP11_interior_cloth_01", "cloth_01Shape_tpAmbient_paint_01.png", false }, - { "AP11_interior_coiled_hose", "coiled_hoseShape_tpAmbient.png", false }, - { "AP11_interior_control_panel_left_win_plates", "control_panel_left_win_platesShape_tpAmbient.png", false }, - { "AP11_interior_control_panel_rt_win_plates", "control_panel_rt_win_platesShape_tpAmbient.png", false }, - { "AP11_interior_copper_parts_main_cp", "copper_parts_main_cpShape_tpAmbient.png", false }, - { "AP11_interior_dials_main2", "dials_main2Shape_tpAmbient.png", false }, - { "AP11_interior_dials_t2", "dials_t2Shape_tpAmbient.png", false }, - { "AP11_interior_dial_fixes_01", "dial_fixes_01Shape_tpAmbient.png", false }, - { "AP11_interior_fire_ex_02", "fire_ex_02_paint_v001.png", false }, - { "AP11_interior_floor_panels_3", "floor_panels_3Shape_tpAmbient_paint_01.png", false }, - { "AP11_interior_floor_tile_tex_01", "floor_tile_tex_01.png", false }, - { "AP11_interior_grey", "gray.png", false }, - { "AP11_interior_handholds_cp", "handholds_cpShape_tpAmbient_paint_05.png", false }, - { "AP11_interior_hatch_release_0Shape5", "hatch_release_0Shape5_tpAmbient_paint_02.png", false }, - { "AP11_interior_headrests_02", "headrests_02Shape_tpAmbient_paint_01.png", false }, - { "AP11_interior_hoses_black_01", "hoses_black_01Shape_tpAmbient_paint_01.png", false }, - { "AP11_interior_hoses_white_0Shape1", "hoses_white_0Shape1_tpAmbient_paint_01.png", false }, - { "AP11_interior_josticks1", "joysticks1Shape_tpAmbient_paint_01.png", false }, - { "AP11_interior_joysticks_fabric1", "joysticks_fabric1_Shape_tpAmbient_paint_01.png", false }, - { "AP11_interior_joystick_poles_lft_05", "joystick_poles_lft_05_paint_v002.png", false }, - { "AP11_interior_joystick_poles_lft_long_05", "joystick_poles_lft_long_05_paint_v002.png", false }, - { "AP11_interior_joystick_poles_rt_05", "joystick_poles_rt_05_paint_v002.png", false }, - { "AP11_interior_latch_mechanisms_01", "latch_mechanisms_01Shape_tpAmbient.png", false }, - { "AP11_interior_lower_push_buttons", "lower_push_buttonsShape_tpAmbient.png", false }, - { "AP11_interior_lower_walls_back", "lower_walls_back_paint_04.png", false }, - { "AP11_interior_lower_walls_boxes_head", "lower_walls_boxes_headShape_tpAmbient_paint_v001.png", false }, - { "AP11_interior_main_cp_left_smth_03", "main_cp_left_0Shape3_tpAmbient_paint_02.png", false }, - { "AP11_interior_main_cp_mid_smth_02", "main_cp_mid_smth_02Shape_tpAmbient_paint_02.png", false }, - { "AP11_interior_main_cp_rt_smth", "main_cp_rt_smthShape_tpAmbient_paint_02.png", false }, - { "AP11_interior_main_cp_wheels", "main_cp_wheelsShape_tpAmbient.png", false }, - { "AP11_interior_metal_brackets_under_hatch", "metal_brackets_under_hatchShape_tpAmbient.png", false }, - { "AP11_interior_metal_tunnel_parts", "metal_tunnel_partsShape_tpAmbient_paint_01.png", false }, - { "AP11_interior_metal_window_parts", "metal_window_partsShape_tpAmbient_paint_01.png", false }, - { "AP11_interior_middle_walls_05", "middle_walls_05_tpAmbient_paint_02.png", false }, - { "AP11_interior_middle_walls_0Shape8", "middle_walls_0Shape8_tpAmbient_paint_01.png", false }, - { "AP11_interior_mid_tunnel_parts", "mid_tunnel_parts_03Shape_tpAmbient_paint_02.png", false }, - { "AP11_interior_new_switch_rails1", "new_switch_rails1Shape_tpAmbient.png", false }, - { "AP11_interior_nozzles_02", "nozzles_02Shape_tpAmbient_paint_01.png", false }, - { "AP11_interior_outlet_fabric3", "outlet_fabric3Shape_tpAmbient_paint_02.png", false }, - { "AP11_interior_pole_end_02", "pole_end_02.png", false }, - { "AP11_interior_pole_end_03", "pole_end_03.png", false }, - { "AP11_interior_pole_tex_03", "pole_tex_03.png", false }, - { "AP11_interior_pole_tex_04", "pole_tex_04.png", false }, - { "AP11_interior_pole_tex_05", "pole_tex_05.png", false }, - { "AP11_interior_pole_tex_lower_01", "pole_tex_lower_01.png", false }, - { "AP11_interior_pole_under_seat_paint_01", "pole_under_seat_paint_01.png", false }, - { "AP11_interior_pole_under_seat_square_bar", "pole_under_seat_square_bar_paint_01.png", false }, - { "AP11_interior_push_switches_lft1", "push_switches_lft1Shape_tpAmbient.png", false }, - { "AP11_interior_random_small_parts_01", "random_small_parts_01Shape_tpAmbient_paint_02.png", false }, - { "AP11_interior_red", "red.png", false }, - { "AP11_interior_reticle_wheel_tp", "reticle_wheel_tpAmbient_paint_01.png", false }, - { "AP11_interior_rivet_paint_v001", "rivet_paint_v001.png", false }, - { "AP11_interior_seats_fabric", "seats_fabric_paint_01.png", false }, - { "AP11_interior_seat_left_tp", "seat_left_tpAmbient_paint_v001.png", false }, - { "AP11_interior_seat_lights_left", "seat_lights_left_Shape_tpAmbient_paint_v001.png", false }, - { "AP11_interior_seat_lights_rt", "seat_lights_rt_Shape_tpAmbient_paint_v001.png", false }, - { "AP11_interior_seat_middle_tp", "seat_middle_tpAmbient_paint_v001.png", false }, - { "AP11_interior_seat_poles_0Shape1", "seat_poles_0Shape1_tpAmbient_paint_01.png", false }, - { "AP11_interior_seat_pole_mirror_0Shape1", "seat_pole_mirror_0Shape1_tpAmbient_paint_01.png", false }, - { "AP11_interior_seat_rt_tp", "seat_rt_tpAmbient_paint_v001.png", false }, - { "AP11_interior_sextant_0Shape2", "sextant_0Shape2_tpAmbient.png", false }, - { "AP11_interior_switch_covers_main_middle1", "switch_covers_main_middle1Shape_tpAmbient.png", false }, - { "AP11_interior_switch_rails_lft", "switch_rails_lftShape_tpAmbient.png", false }, - { "AP11_interior_tunnel_main_cylinder1", "switch_rails_lftShape_tpAmbient.png", false }, - { "AP11_interior_tunnel_switches_01", "tunnel_switches_01Shape_tpAmbient.png", false }, - { "AP11_interior_tunnel_wheelsShape", "tunnel_wheelsShape_tpAmbient.png", false }, - { "AP11_interior_walls_mid_left", "walls_mid_leftShape_tpAmbient_paint_01.png", false }, - { "AP11_interior_windows_front_0Shape4", "windows_front_0Shape4_tpAmbient_paint_01.png", false } -} - - - -asset.export("createCsmModel", function (parentNodeIdentifier) - local parts = {} - for i, info in ipairs(partsInfo) do - parts[#parts + 1] = asset_helper.createModelPart( - parentNodeIdentifier, - sun_transforms.SolarSystemBarycenter.Identifier, - models, - info[1], - info[2], - info[3] - ) - end - return parts -end) - - - -asset.export("createCsmModelFull", function (parentNodeIdentifier) - local parts = {} - for i, info in ipairs(partsInfoFull) do - parts[#parts + 1] = asset_helper.createModelPart( - parentNodeIdentifier, - sun_transforms.SolarSystemBarycenter.Identifier, - models, - info[1], - info[2], - info[3] - ) - end - return parts -end) diff --git a/data/assets/scene/solarsystem/missions/apollo/csm_model.asset b/data/assets/scene/solarsystem/missions/apollo/csm_model.asset new file mode 100644 index 0000000000..298640354c --- /dev/null +++ b/data/assets/scene/solarsystem/missions/apollo/csm_model.asset @@ -0,0 +1,8 @@ +local models = asset.syncedResource({ + Name = "Apollo Models", + Type = "HttpSynchronization", + Identifier = "apollo_models", + Version = 2 +}) + +asset.export('models', models) diff --git a/data/assets/scene/solarsystem/missions/messenger/messengerSC.asset b/data/assets/scene/solarsystem/missions/messenger/messengerSC.asset index ce2f3b32bc..68e23b4742 100644 --- a/data/assets/scene/solarsystem/missions/messenger/messengerSC.asset +++ b/data/assets/scene/solarsystem/missions/messenger/messengerSC.asset @@ -172,7 +172,7 @@ local MessengerTrail = { Type = "SpiceTranslation", Target = "MESSENGER", Observer = "MERCURY BARYCENTER", - Kernels = Kernels + Kernels = LocalKernels }, Color = { 0.288, 0.375, 0.934 }, EnableFade = false, diff --git a/data/assets/scene/solarsystem/missions/newhorizons/fov.asset b/data/assets/scene/solarsystem/missions/newhorizons/fov.asset index 1b46601397..093ee19356 100644 --- a/data/assets/scene/solarsystem/missions/newhorizons/fov.asset +++ b/data/assets/scene/solarsystem/missions/newhorizons/fov.asset @@ -348,8 +348,8 @@ local Rex = { Target = "EARTH", Instrument = "NH_REX", Color = { - Start = { 1.0, 0.7, 0.0, 1.0}, - End = {0.0, 0.0, 0.0, 0.0 } + Start = { 1.0, 0.7, 0.0, 1.0 }, + End = { 0.0, 0.0, 0.0, 0.0 } } }, Transform = { diff --git a/data/assets/scene/solarsystem/missions/newhorizons/pluto.asset b/data/assets/scene/solarsystem/missions/newhorizons/pluto.asset index 3a963722e2..35210c0e09 100644 --- a/data/assets/scene/solarsystem/missions/newhorizons/pluto.asset +++ b/data/assets/scene/solarsystem/missions/newhorizons/pluto.asset @@ -1,6 +1,7 @@ local assetHelper = asset.require('util/asset_helper') local transforms = asset.require('./transforms') local sunTransforms = asset.require('scene/solarsystem/sun/transforms') +local NewHorizonsKernels = asset.require('./kernels').NewHorizonsKernels local assets = asset.syncedResource({ Name = "Pluto Assets", diff --git a/data/assets/scene/solarsystem/missions/voyager/model.asset b/data/assets/scene/solarsystem/missions/voyager/model.asset index cb565ad315..e1d17adda6 100644 --- a/data/assets/scene/solarsystem/missions/voyager/model.asset +++ b/data/assets/scene/solarsystem/missions/voyager/model.asset @@ -1,5 +1,5 @@ local models = asset.syncedResource({ - Name = "New Horizons Model", + Name = "Voyager Model", Type = "HttpSynchronization", Identifier = "voyager_model", Version = 1 diff --git a/data/assets/scene/solarsystem/planets/earth/moon/layers/overlays/size_reference.asset b/data/assets/scene/solarsystem/planets/earth/moon/layers/overlays/size_reference.asset new file mode 100644 index 0000000000..030be3572d --- /dev/null +++ b/data/assets/scene/solarsystem/planets/earth/moon/layers/overlays/size_reference.asset @@ -0,0 +1,15 @@ +local moonAsset = asset.require("./../../moon").Moon +local globeIdentifier = moonAsset.Identifier + +local layer ={ + Identifier = "Size_Reference", + Name = "Size Reference", + Type = "SizeReferenceTileLayer", + Radii = moonAsset.Renderable.Radii +} + +asset.onInitialize(function () + openspace.globebrowsing.addLayer(globeIdentifier, "Overlays", layer) +end) + +asset.export("layer", layer) diff --git a/data/assets/scene/solarsystem/planets/earth/satellites/misc/iss.asset b/data/assets/scene/solarsystem/planets/earth/satellites/misc/iss.asset index e0de97af2a..4d3ae8016b 100644 --- a/data/assets/scene/solarsystem/planets/earth/satellites/misc/iss.asset +++ b/data/assets/scene/solarsystem/planets/earth/satellites/misc/iss.asset @@ -13,7 +13,7 @@ local models = asset.syncedResource({ Name = "ISS Models", Type = "HttpSynchronization", Identifier = "iss_model", - Version = 2 + Version = 3 }) local initializeAndAddNodes = function() @@ -59,37 +59,7 @@ local initializeAndAddNodes = function() }, Renderable = { Type = "RenderableModel", - GeometryFile = { - models .. "/0.obj", - models .. "/1.obj", - models .. "/2.obj", - models .. "/3.obj", - models .. "/4.obj", - models .. "/5.obj", - models .. "/6.obj", - models .. "/7.obj", - models .. "/8.obj", - models .. "/10.obj", - models .. "/11.obj", - models .. "/13.obj", - models .. "/14.obj", - models .. "/15.obj", - models .. "/16.obj", - models .. "/17.obj", - models .. "/19.obj", - models .. "/21.obj", - models .. "/22.obj", - models .. "/23.obj", - models .. "/24.obj", - models .. "/25.obj", - models .. "/foilsilver.obj", - models .. "/olive.obj", - models .. "/basemetal.obj", - models .. "/white_20.obj", - models .. "/plasticblack.obj", - models .. "/ecostresswhite.obj", - models .. "/plain.obj" - }, + GeometryFile = models .. "/ISS.fbx", LightSources = { { Type = "SceneGraphLightSource", diff --git a/data/assets/scene/solarsystem/planets/neptune/irregular_prograde_moons.asset b/data/assets/scene/solarsystem/planets/neptune/irregular_prograde_moons.asset index 632ebd6859..826e6366c4 100644 --- a/data/assets/scene/solarsystem/planets/neptune/irregular_prograde_moons.asset +++ b/data/assets/scene/solarsystem/planets/neptune/irregular_prograde_moons.asset @@ -3,7 +3,7 @@ local proceduralGlobes = asset.require('util/procedural_globe') local transforms = asset.require('./transforms') local kernels = asset.require('./kernels') local kernel081 = kernels.nep081 -local kernel087 = kernels.nep087 +local kernel086 = kernels.nep086 local kernel088 = kernels.nep088 diff --git a/data/assets/util/asset_helper.asset b/data/assets/util/asset_helper.asset index 77a28382f1..e5cf1582e6 100644 --- a/data/assets/util/asset_helper.asset +++ b/data/assets/util/asset_helper.asset @@ -13,7 +13,7 @@ local registerSpiceKernels = function (spiceAsset, kernels) end) spiceAsset.onDeinitialize(function () for i = #kernels, 1, -1 do - kernel = kernels[i] + local kernel = kernels[i] openspace.spice.unloadKernel(kernel) end end) @@ -75,7 +75,7 @@ local registerDashboardItems = function (dashboardAsset, items) ) dashboardAsset.onDeinitialize(function () for i = #items, 1, -1 do - item = items[i] + local item = items[i] openspace.dashboard.removeDashboardItem(item.Identifier) end end) @@ -103,7 +103,7 @@ local registerSceneGraphNodesAndExport = function (sceneAsset, nodes, override) end) sceneAsset.onDeinitialize(function () for i = #nodes, 1, -1 do - node = nodes[i] + local node = nodes[i] openspace.removeSceneGraphNode(node.Identifier) end end) diff --git a/data/assets/util/default_dashboard.asset b/data/assets/util/default_dashboard.asset deleted file mode 100644 index 935aae0956..0000000000 --- a/data/assets/util/default_dashboard.asset +++ /dev/null @@ -1,34 +0,0 @@ -local assetHelper = asset.require('util/asset_helper') - -assetHelper.registerDashboardItems(asset, { - { - Type = "DashboardItemDate", - Identifier = "Date", - GuiName = "Date" - }, - { - Type = "DashboardItemSimulationIncrement", - Identifier = "SimulationIncrement", - GuiName = "Simulation Increment" - }, - { - Type = "DashboardItemDistance", - Identifier = "Distance", - GuiName = "Distance" - }, - { - Type = "DashboardItemFramerate", - Identifier = "Framerate", - GuiName = "Framerate" - }, - { - Type = "DashboardItemParallelConnection", - Identifier = "ParallelConnection", - GuiName = "Parallel Connection" - }, - { - Type = "DashboardItemGlobeLocation", - Identifier = "GlobeLocation", - GuiName = "Globe Location" - } -}) diff --git a/data/assets/util/procedural_globe.asset b/data/assets/util/procedural_globe.asset index 23198f2e65..4c34de326a 100644 --- a/data/assets/util/procedural_globe.asset +++ b/data/assets/util/procedural_globe.asset @@ -68,7 +68,7 @@ local createGlobes = function(t) end end - result = {} + local result = {} for i, v in ipairs(t) do local globe = nil diff --git a/data/assets/util/static_server.asset b/data/assets/util/static_server.asset index 3e98da9fdd..936f18277f 100644 --- a/data/assets/util/static_server.asset +++ b/data/assets/util/static_server.asset @@ -10,7 +10,7 @@ local backend = asset.syncedResource({ asset.onInitialize(function () -- Unzip the server bundle - dest = backend .. "/backend" + local dest = backend .. "/backend" if not openspace.directoryExists(dest) then openspace.unzipFile(backend .. "/backend.zip", dest, true) end diff --git a/data/assets/util/tle_helper.asset b/data/assets/util/tle_helper.asset index fdcccdbb43..6a80121695 100644 --- a/data/assets/util/tle_helper.asset +++ b/data/assets/util/tle_helper.asset @@ -24,7 +24,7 @@ end -- Check format of a set of 3 TLE file lines and return nonzero if there is a format error function isValidTLEFileFormat(lineArr) - function isEmpty(s) return s == nil or s == '' end + local function isEmpty(s) return s == nil or s == '' end if isEmpty(lineArr[1]) or isEmpty(lineArr[2]) or isEmpty(lineArr[3]) then return false diff --git a/ext/ghoul b/ext/ghoul index 2180f32860..bddc5370d7 160000 --- a/ext/ghoul +++ b/ext/ghoul @@ -1 +1 @@ -Subproject commit 2180f32860131b08831f9d4c2be5839b5aa48672 +Subproject commit bddc5370d7dd8bc8ab05f2a234a12f2d0e266ca4 diff --git a/include/openspace/documentation/verifier.h b/include/openspace/documentation/verifier.h index 0126a804f7..7cde68a2aa 100644 --- a/include/openspace/documentation/verifier.h +++ b/include/openspace/documentation/verifier.h @@ -29,6 +29,7 @@ #include #include #include +#include namespace openspace::documentation { @@ -155,7 +156,17 @@ struct IntVerifier : public TemplateVerifier { * std::string. No implicit conversion is considered in this testing. */ struct StringVerifier : public TemplateVerifier { + StringVerifier(bool mustBeNotEmpty = false); + + TestResult operator()(const ghoul::Dictionary& dictionary, + const std::string& key) const override; + std::string type() const override; + + bool mustBeNotEmpty() const; + +private: + bool _mustBeNotEmpty = false; }; /** @@ -994,8 +1005,15 @@ struct OrVerifier : public Verifier { * \param values The list of Verifiers that are to be tested * * \pre values must contain at least two values + * + * \todo: The use of the variant to use both raw pointers and shared pointers is + * definitely undesired. At the momement we are not handling the ownership of + * the verifiers very well and this must be cleaned up when doing a pass over + * the entire ownership model of the documentation/verifiers. For now it was + * necessary to make the codegen work in all cases without complications there */ - OrVerifier(const std::vector values); + OrVerifier(const std::vector>> values); /** * Checks whether the \p dictionary contains the \p key and whether this key passes diff --git a/include/openspace/documentation/verifier.inl b/include/openspace/documentation/verifier.inl index d61169dd2c..7363b325ec 100644 --- a/include/openspace/documentation/verifier.inl +++ b/include/openspace/documentation/verifier.inl @@ -45,17 +45,27 @@ template TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dict, const std::string& key) const { + TestResult res; if (dict.hasValue(key)) { - return { true, {}, {} }; + res.success = true; } else { + res.success = false; + if (dict.hasKey(key)) { - return { false, { { key, TestResult::Offense::Reason::WrongType } }, {} }; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::WrongType; + res.offenses.push_back(o); } else { - return { false, { { key, TestResult::Offense::Reason::MissingKey } }, {} }; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::MissingKey; + res.offenses.push_back(o); } } + return res; } template @@ -143,7 +153,13 @@ TestResult OperatorVerifier::operator()(const ghoul::Dictionary& di val = static_cast(d); } else { - return { false, { { key, TestResult::Offense::Reason::WrongType } }, {} }; + TestResult r; + r.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::WrongType; + r.offenses.push_back(o); + return r; } } else { @@ -153,7 +169,13 @@ TestResult OperatorVerifier::operator()(const ghoul::Dictionary& di return { true, {}, {} }; } else { - return { false, { { key, TestResult::Offense::Reason::Verification } }, {} }; + TestResult r; + r.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::Verification; + r.offenses.push_back(o); + return r; } } else { @@ -210,7 +232,13 @@ TestResult InListVerifier::operator()(const ghoul::Dictionary& dict, return { true, {}, {} }; } else { - return { false, { { key, TestResult::Offense::Reason::Verification } }, {} }; + TestResult r; + r.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::Verification; + r.offenses.push_back(o); + return r; } } else { @@ -256,7 +284,13 @@ TestResult NotInListVerifier::operator()(const ghoul::Dictionary& dict, return { true, {}, {} }; } else { - return { false, { { key, TestResult::Offense::Reason::Verification } }, {} }; + TestResult r; + r.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::Verification; + r.offenses.push_back(o); + return r; } } else { @@ -306,7 +340,13 @@ TestResult InRangeVerifier::operator()(const ghoul::Dictionary& dict, val = static_cast(d); } else { - return { false, { { key, TestResult::Offense::Reason::WrongType } }, {} }; + TestResult r; + r.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::WrongType; + r.offenses.push_back(o); + return r; } } else { @@ -317,7 +357,13 @@ TestResult InRangeVerifier::operator()(const ghoul::Dictionary& dict, return { true, {}, {} }; } else { - return { false, { { key, TestResult::Offense::Reason::Verification } }, {} }; + TestResult r; + r.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::Verification; + r.offenses.push_back(o); + return r; } } else { @@ -353,7 +399,13 @@ TestResult NotInRangeVerifier::operator()(const ghoul::Dictionary& dict, val = static_cast(d); } else { - return { false, { { key, TestResult::Offense::Reason::WrongType } }, {} }; + TestResult r; + r.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::WrongType; + r.offenses.push_back(o); + return r; } } else { @@ -361,7 +413,13 @@ TestResult NotInRangeVerifier::operator()(const ghoul::Dictionary& dict, } if (val >= lower && val <= upper) { - return { false, { { key, TestResult::Offense::Reason::Verification } }, {} }; + TestResult r; + r.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::Verification; + r.offenses.push_back(o); + return r; } else { return { true, {}, {} }; @@ -396,9 +454,10 @@ TestResult DeprecatedVerifier::operator()(const ghoul::Dictionary& dict, const std::string& key) const { TestResult res = T::operator()(dict, key); - res.warnings.push_back( - TestResult::Warning{ key, TestResult::Warning::Reason::Deprecated } - ); + TestResult::Warning w; + w.offender = key; + w.reason = TestResult::Warning::Reason::Deprecated; + res.warnings.push_back(w); return res; } diff --git a/include/openspace/engine/configuration.h b/include/openspace/engine/configuration.h index 5ba443cf7e..98fbb8518c 100644 --- a/include/openspace/engine/configuration.h +++ b/include/openspace/engine/configuration.h @@ -43,7 +43,6 @@ struct Configuration { Configuration& operator=(Configuration&&) = default; std::string windowConfiguration = "${CONFIG}/single.xml"; - std::string sgctConfigNameInitialized; std::string asset; std::string profile; std::vector readOnlyProfiles; @@ -93,7 +92,6 @@ struct Configuration { glm::dvec3 screenSpaceRotation = glm::dvec3(0.0); glm::dvec3 masterRotation = glm::dvec3(0.0); bool isConsoleDisabled = false; - bool usingProfile = false; bool bypassLauncher = false; std::map moduleConfigurations; @@ -123,6 +121,9 @@ struct Configuration { }; HTTPProxy httpProxy; + // Values not read from the openspace.cfg file + bool usingProfile = false; + std::string sgctConfigNameInitialized; static documentation::Documentation Documentation; ghoul::lua::LuaState state; @@ -130,9 +131,8 @@ struct Configuration { std::string findConfiguration(const std::string& filename = "openspace.cfg"); -Configuration loadConfigurationFromFile(const std::string& filename); - -void parseLuaState(Configuration& configuration); +Configuration loadConfigurationFromFile(const std::string& filename, + const std::string& overrideScript); } // namespace openspace::configuration diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index 68843243ca..473641efb3 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -144,7 +144,7 @@ private: // Lua functions - exposed for testing namespace openspace::luascriptfunctions { -int createSingeColorImage(lua_State* L); +int createSingleColorImage(lua_State* L); } // openspace::luascriptfunctions diff --git a/include/openspace/rendering/dashboarditem.h b/include/openspace/rendering/dashboarditem.h index 11013a5d28..6e5d28060d 100644 --- a/include/openspace/rendering/dashboarditem.h +++ b/include/openspace/rendering/dashboarditem.h @@ -28,12 +28,9 @@ #include #include -#include -#include #include namespace ghoul { class Dictionary; } -namespace ghoul::fontrendering { class Font; } namespace openspace { @@ -58,22 +55,6 @@ protected: properties::BoolProperty _isEnabled; }; - - -class DashboardTextItem : public DashboardItem { -public: - static documentation::Documentation Documentation(); - - DashboardTextItem(const ghoul::Dictionary& dictionary, float fontSize = 10.f, - const std::string& fontName = "Mono"); - -protected: - properties::StringProperty _fontName; - properties::FloatProperty _fontSize; - - std::shared_ptr _font; -}; - } // openspace #endif // __OPENSPACE_CORE___DASHBOARDITEM___H__ diff --git a/include/openspace/rendering/dashboardtextitem.h b/include/openspace/rendering/dashboardtextitem.h new file mode 100644 index 0000000000..d3b0e20a79 --- /dev/null +++ b/include/openspace/rendering/dashboardtextitem.h @@ -0,0 +1,56 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#ifndef __OPENSPACE_CORE___DASHBOARDTEXTITEM___H__ +#define __OPENSPACE_CORE___DASHBOARDTEXTITEM___H__ + +#include + +#include +#include + +namespace ghoul { class Dictionary; } +namespace ghoul::fontrendering { class Font; } + +namespace openspace { + +namespace documentation { struct Documentation; } + +class DashboardTextItem : public DashboardItem { +public: + static documentation::Documentation Documentation(); + + DashboardTextItem(const ghoul::Dictionary& dictionary, float fontSize = 10.f, + const std::string& fontName = "Mono"); + +protected: + properties::StringProperty _fontName; + properties::FloatProperty _fontSize; + + std::shared_ptr _font; +}; + +} // openspace + +#endif // __OPENSPACE_CORE___DASHBOARDTEXTITEM___H__ diff --git a/include/openspace/rendering/renderengine.h b/include/openspace/rendering/renderengine.h index 000595f69e..f698af2248 100644 --- a/include/openspace/rendering/renderengine.h +++ b/include/openspace/rendering/renderengine.h @@ -201,6 +201,7 @@ private: properties::BoolProperty _showCameraInfo; properties::BoolProperty _applyWarping; + properties::BoolProperty _screenshotUseDate; properties::BoolProperty _showFrameInformation; properties::BoolProperty _disableMasterRendering; diff --git a/include/openspace/scripting/scriptscheduler.h b/include/openspace/scripting/scriptscheduler.h index 0375a38f11..a7ec3405d8 100644 --- a/include/openspace/scripting/scriptscheduler.h +++ b/include/openspace/scripting/scriptscheduler.h @@ -47,6 +47,8 @@ struct LuaLibrary; class ScriptScheduler { public: struct ScheduledScript { + ScheduledScript() = default; + ScheduledScript(const ghoul::Dictionary& dict); double time = -std::numeric_limits::max(); std::string forwardScript; diff --git a/modules/atmosphere/rendering/renderableatmosphere.cpp b/modules/atmosphere/rendering/renderableatmosphere.cpp index 4859a00628..a2ca9476bf 100644 --- a/modules/atmosphere/rendering/renderableatmosphere.cpp +++ b/modules/atmosphere/rendering/renderableatmosphere.cpp @@ -179,7 +179,8 @@ namespace { // A list of objects that cast light on this atmosphere std::vector casters; }; - // Declares shadow groups, meaning which nodes are considered in shadow calculations + // Declares shadow groups, meaning which nodes are considered in shadow + // calculations std::optional shadowGroup; // [[codegen::verbatim(AtmosphereHeightInfo.description)]] @@ -360,7 +361,7 @@ RenderableAtmosphere::RenderableAtmosphere(const ghoul::Dictionary& dictionary) _mieScatteringExtinctionPropCoefficient.onChange(updateWithCalculation); addProperty(_mieScatteringExtinctionPropCoefficient); - + if (p.debug.has_value()) { _preCalculatedTexturesScale = p.debug->preCalculatedTextureScale.value_or(_preCalculatedTexturesScale); diff --git a/modules/base/dashboard/dashboarditemangle.h b/modules/base/dashboard/dashboarditemangle.h index b6d234d862..69c7e41a65 100644 --- a/modules/base/dashboard/dashboarditemangle.h +++ b/modules/base/dashboard/dashboarditemangle.h @@ -25,7 +25,7 @@ #ifndef __OPENSPACE_MODULE_BASE___DASHBOARDITEMANGLE___H__ #define __OPENSPACE_MODULE_BASE___DASHBOARDITEMANGLE___H__ -#include +#include #include #include diff --git a/modules/base/dashboard/dashboarditemdate.cpp b/modules/base/dashboard/dashboarditemdate.cpp index 87dc11ac6c..3a1a611f6d 100644 --- a/modules/base/dashboard/dashboarditemdate.cpp +++ b/modules/base/dashboard/dashboarditemdate.cpp @@ -55,7 +55,7 @@ namespace { struct [[codegen::Dictionary(DashboardItemDate)]] Parameters { // [[codegen::verbatim(FormatStringInfo.description)]] std::optional formatString; - + // [[codegen::verbatim(TimeFormatInfo.description)]] std::optional timeFormat; }; diff --git a/modules/base/dashboard/dashboarditemdate.h b/modules/base/dashboard/dashboarditemdate.h index 602de7b2c9..6e2acd9c43 100644 --- a/modules/base/dashboard/dashboarditemdate.h +++ b/modules/base/dashboard/dashboarditemdate.h @@ -25,7 +25,7 @@ #ifndef __OPENSPACE_MODULE_BASE___DASHBOARDITEMDATE___H__ #define __OPENSPACE_MODULE_BASE___DASHBOARDITEMDATE___H__ -#include +#include #include diff --git a/modules/base/dashboard/dashboarditemdistance.h b/modules/base/dashboard/dashboarditemdistance.h index bb3b7037ef..dc0cd2a64c 100644 --- a/modules/base/dashboard/dashboarditemdistance.h +++ b/modules/base/dashboard/dashboarditemdistance.h @@ -25,7 +25,7 @@ #ifndef __OPENSPACE_MODULE_BASE___DASHBOARDITEMDISTANCE___H__ #define __OPENSPACE_MODULE_BASE___DASHBOARDITEMDISTANCE___H__ -#include +#include #include #include diff --git a/modules/base/dashboard/dashboarditemframerate.cpp b/modules/base/dashboard/dashboarditemframerate.cpp index 9405cac2c6..f16db9e6fb 100644 --- a/modules/base/dashboard/dashboarditemframerate.cpp +++ b/modules/base/dashboard/dashboarditemframerate.cpp @@ -132,7 +132,8 @@ namespace { DtAvg [[codegen::key("Average Deltatime")]], DtExtremes [[codegen::key("Deltatime extremes")]], DtStandardDeviation [[codegen::key("Deltatime standard deviation")]], - DtCoefficientOfVariation [[codegen::key("Deltatime coefficient of variation")]], + DtCoefficientOfVariation + [[codegen::key("Deltatime coefficient of variation")]], FPS [[codegen::key("Frames per second")]], FPSAvg [[codegen::key("Average frames per second")]] }; @@ -187,7 +188,8 @@ DashboardItemFramerate::DashboardItemFramerate(const ghoul::Dictionary& dictiona _frametimeType = static_cast(FrametimeType::DtStandardDeviation); break; case Parameters::Type::DtCoefficientOfVariation: - _frametimeType = static_cast(FrametimeType::DtCoefficientOfVariation); + _frametimeType = + static_cast(FrametimeType::DtCoefficientOfVariation); break; case Parameters::Type::FPS: _frametimeType = static_cast(FrametimeType::FPS); diff --git a/modules/base/dashboard/dashboarditemframerate.h b/modules/base/dashboard/dashboarditemframerate.h index 17038cc572..226d488dd8 100644 --- a/modules/base/dashboard/dashboarditemframerate.h +++ b/modules/base/dashboard/dashboarditemframerate.h @@ -25,7 +25,7 @@ #ifndef __OPENSPACE_MODULE_BASE___DASHBOARDITEMFRAMERATE___H__ #define __OPENSPACE_MODULE_BASE___DASHBOARDITEMFRAMERATE___H__ -#include +#include #include #include diff --git a/modules/base/dashboard/dashboarditemmission.h b/modules/base/dashboard/dashboarditemmission.h index bb02551fdf..1156cebe4f 100644 --- a/modules/base/dashboard/dashboarditemmission.h +++ b/modules/base/dashboard/dashboarditemmission.h @@ -25,7 +25,7 @@ #ifndef __OPENSPACE_MODULE_BASE___DASHBOARDITEMMISSION___H__ #define __OPENSPACE_MODULE_BASE___DASHBOARDITEMMISSION___H__ -#include +#include namespace openspace { diff --git a/modules/base/dashboard/dashboarditemparallelconnection.h b/modules/base/dashboard/dashboarditemparallelconnection.h index 7e13459850..687eb3734b 100644 --- a/modules/base/dashboard/dashboarditemparallelconnection.h +++ b/modules/base/dashboard/dashboarditemparallelconnection.h @@ -25,7 +25,7 @@ #ifndef __OPENSPACE_MODULE_BASE___DASHBOARDITEMPARALLELCONNECTION___H__ #define __OPENSPACE_MODULE_BASE___DASHBOARDITEMPARALLELCONNECTION___H__ -#include +#include namespace openspace { diff --git a/modules/base/dashboard/dashboarditempropertyvalue.h b/modules/base/dashboard/dashboarditempropertyvalue.h index 2f14a3aeff..73f2191ba1 100644 --- a/modules/base/dashboard/dashboarditempropertyvalue.h +++ b/modules/base/dashboard/dashboarditempropertyvalue.h @@ -25,7 +25,7 @@ #ifndef __OPENSPACE_MODULE_BASE___DASHBOARDITEMPROPERTYVALUE___H__ #define __OPENSPACE_MODULE_BASE___DASHBOARDITEMPROPERTYVALUE___H__ -#include +#include #include diff --git a/modules/base/dashboard/dashboarditemsimulationincrement.h b/modules/base/dashboard/dashboarditemsimulationincrement.h index 7b3367811f..2f214de3f9 100644 --- a/modules/base/dashboard/dashboarditemsimulationincrement.h +++ b/modules/base/dashboard/dashboarditemsimulationincrement.h @@ -25,7 +25,7 @@ #ifndef __OPENSPACE_MODULE_BASE___DASHBOARDITEMSIMULATIONINCREMENT___H__ #define __OPENSPACE_MODULE_BASE___DASHBOARDITEMSIMULATIONINCREMENT___H__ -#include +#include #include #include diff --git a/modules/base/dashboard/dashboarditemtext.h b/modules/base/dashboard/dashboarditemtext.h index 648b501805..a5be0355fd 100644 --- a/modules/base/dashboard/dashboarditemtext.h +++ b/modules/base/dashboard/dashboarditemtext.h @@ -25,7 +25,7 @@ #ifndef __OPENSPACE_MODULE_BASE___DASHBOARDITEMTEXT___H__ #define __OPENSPACE_MODULE_BASE___DASHBOARDITEMTEXT___H__ -#include +#include #include diff --git a/modules/base/dashboard/dashboarditemvelocity.h b/modules/base/dashboard/dashboarditemvelocity.h index fa2664b2cf..827ab6dc91 100644 --- a/modules/base/dashboard/dashboarditemvelocity.h +++ b/modules/base/dashboard/dashboarditemvelocity.h @@ -25,7 +25,7 @@ #ifndef __OPENSPACE_MODULE_BASE___DASHBOARDITEMVELOCITY___H__ #define __OPENSPACE_MODULE_BASE___DASHBOARDITEMVELOCITY___H__ -#include +#include #include #include diff --git a/modules/base/rendering/grids/renderableboxgrid.cpp b/modules/base/rendering/grids/renderableboxgrid.cpp index c9a474306b..9f35f6541b 100644 --- a/modules/base/rendering/grids/renderableboxgrid.cpp +++ b/modules/base/rendering/grids/renderableboxgrid.cpp @@ -80,7 +80,7 @@ documentation::Documentation RenderableBoxGrid::Documentation() { RenderableBoxGrid::RenderableBoxGrid(const ghoul::Dictionary& dictionary) : Renderable(dictionary) , _color(ColorInfo, glm::vec3(0.5f), glm::vec3(0.f), glm::vec3(1.f)) - , _lineWidth(LineWidthInfo, 0.5f, 0.f, 20.f) + , _lineWidth(LineWidthInfo, 0.5f, 1.f, 20.f) , _size(SizeInfo, glm::vec3(1.f), glm::vec3(1.f), glm::vec3(100.f)) { const Parameters p = codegen::bake(dictionary); diff --git a/modules/base/rendering/grids/renderablegrid.cpp b/modules/base/rendering/grids/renderablegrid.cpp index 4c7b1e598c..1f364157f1 100644 --- a/modules/base/rendering/grids/renderablegrid.cpp +++ b/modules/base/rendering/grids/renderablegrid.cpp @@ -91,7 +91,7 @@ RenderableGrid::RenderableGrid(const ghoul::Dictionary& dictionary) : Renderable(dictionary) , _color(ColorInfo, glm::vec3(0.5f), glm::vec3(0.f), glm::vec3(1.f)) , _segments(SegmentsInfo, glm::uvec2(10), glm::uvec2(1), glm::uvec2(200)) - , _lineWidth(LineWidthInfo, 0.5f, 0.f, 20.f) + , _lineWidth(LineWidthInfo, 0.5f, 1.f, 20.f) , _size(SizeInfo, glm::vec2(1e20f), glm::vec2(1.f), glm::vec2(1e35f)) { const Parameters p = codegen::bake(dictionary); diff --git a/modules/base/rendering/grids/renderableradialgrid.cpp b/modules/base/rendering/grids/renderableradialgrid.cpp index 73993cd951..fd2150e178 100644 --- a/modules/base/rendering/grids/renderableradialgrid.cpp +++ b/modules/base/rendering/grids/renderableradialgrid.cpp @@ -113,7 +113,7 @@ RenderableRadialGrid::RenderableRadialGrid(const ghoul::Dictionary& dictionary) , _color(ColorInfo, glm::vec3(0.5f), glm::vec3(0.f), glm::vec3(1.f)) , _gridSegments(GridSegmentsInfo, glm::ivec2(1), glm::ivec2(1), glm::ivec2(200)) , _circleSegments(CircleSegmentsInfo, 36, 4, 200) - , _lineWidth(LineWidthInfo, 0.5f, 0.f, 20.f) + , _lineWidth(LineWidthInfo, 0.5f, 1.f, 20.f) , _maxRadius(OuterRadiusInfo, 1.f, 0.f, 20.f) , _minRadius(InnerRadiusInfo, 0.f, 0.f, 20.f) { diff --git a/modules/base/rendering/grids/renderablesphericalgrid.cpp b/modules/base/rendering/grids/renderablesphericalgrid.cpp index 878e05972d..75a2b27fbf 100644 --- a/modules/base/rendering/grids/renderablesphericalgrid.cpp +++ b/modules/base/rendering/grids/renderablesphericalgrid.cpp @@ -83,7 +83,7 @@ RenderableSphericalGrid::RenderableSphericalGrid(const ghoul::Dictionary& dictio , _gridProgram(nullptr) , _color(ColorInfo, glm::vec3(0.5f), glm::vec3(0.f), glm::vec3(1.f)) , _segments(SegmentsInfo, 36, 4, 200) - , _lineWidth(LineWidthInfo, 0.5f, 0.f, 20.f) + , _lineWidth(LineWidthInfo, 0.5f, 1.f, 20.f) { const Parameters p = codegen::bake(dictionary); diff --git a/modules/base/rendering/renderabletrail.cpp b/modules/base/rendering/renderabletrail.cpp index 42147ba54e..daab021b50 100644 --- a/modules/base/rendering/renderabletrail.cpp +++ b/modules/base/rendering/renderabletrail.cpp @@ -148,7 +148,8 @@ namespace { struct [[codegen::Dictionary(RenderableTrail)]] Parameters { // This object is used to compute locations along the path. Any Translation object // can be used here - std::monostate translation [[codegen::reference("core_transform_translation")]]; + ghoul::Dictionary translation + [[codegen::reference("core_transform_translation")]]; // [[codegen::verbatim(LineColorInfo.description)]] glm::vec3 color [[codegen::color()]]; diff --git a/modules/base/rendering/renderabletrailorbit.cpp b/modules/base/rendering/renderabletrailorbit.cpp index 7430b52092..681c4e14d0 100644 --- a/modules/base/rendering/renderabletrailorbit.cpp +++ b/modules/base/rendering/renderabletrailorbit.cpp @@ -30,6 +30,7 @@ #include #include #include +#include // This class is using a VBO ring buffer + a constantly updated point as follows: // Structure of the array with a _resolution of 16. FF denotes the floating position that @@ -104,36 +105,32 @@ namespace { "Opaque, Transparent, or Overlay rendering step. Default is Transparent." }; + struct [[codegen::Dictionary(RenderableTrailOrbit)]] Parameters { + // [[codegen::verbatim(PeriodInfo.description)]] + double period; + + // [[codegen::verbatim(ResolutionInfo.description)]] + int resolution; + + enum class RenderableType { + Background, + Opaque, + PreDeferredTransparent, + PostDeferredTransparent, + Overlay + }; + + // [[codegen::verbatim(RenderableTypeInfo.description)]] + std::optional renderableType; + }; +#include "renderabletrailorbit_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableTrailOrbit::Documentation() { - using namespace documentation; - documentation::Documentation doc { - "RenderableTrailOrbit", - "base_renderable_renderabletrailorbit", - { - { - PeriodInfo.identifier, - new DoubleVerifier, - Optional::No, - PeriodInfo.description - }, - { - ResolutionInfo.identifier, - new IntVerifier, - Optional::No, - ResolutionInfo.description - }, - { - RenderableTypeInfo.identifier, - new StringVerifier, - Optional::Yes, - RenderableTypeInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_renderable_renderabletrailorbit"; // Insert the parents documentation entries until we have a verifier that can deal // with class hierarchy @@ -152,46 +149,42 @@ RenderableTrailOrbit::RenderableTrailOrbit(const ghoul::Dictionary& dictionary) , _period(PeriodInfo, 0.0, 0.0, 1e9) , _resolution(ResolutionInfo, 10000, 1, 1000000) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableTrailOrbit" - ); + const Parameters p = codegen::bake(dictionary); _translation->onParameterChange([this]() { _needsFullSweep = true; }); // Period is in days using namespace std::chrono; - const long long sph = duration_cast(hours(24)).count(); - _period = dictionary.value(PeriodInfo.identifier) * sph; + _period = p.period * duration_cast(hours(24)).count(); _period.onChange([&] { _needsFullSweep = true; _indexBufferDirty = true; }); addProperty(_period); - _resolution = static_cast(dictionary.value(ResolutionInfo.identifier)); + _resolution = p.resolution; _resolution.onChange([&] { _needsFullSweep = true; _indexBufferDirty = true; }); addProperty(_resolution); // We store the vertices with (excluding the wrapping) decending temporal order _primaryRenderInformation.sorting = RenderInformation::VertexSorting::NewestFirst; - 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.renderableType.has_value()) { + switch (*p.renderableType) { + case Parameters::RenderableType::Background: + setRenderBin(Renderable::RenderBin::Background); + break; + case Parameters::RenderableType::Opaque: + setRenderBin(Renderable::RenderBin::Opaque); + break; + case Parameters::RenderableType::PreDeferredTransparent: + setRenderBin(Renderable::RenderBin::PreDeferredTransparent); + break; + case Parameters::RenderableType::PostDeferredTransparent: + setRenderBin(Renderable::RenderBin::PostDeferredTransparent); + break; + case Parameters::RenderableType::Overlay: + setRenderBin(Renderable::RenderBin::Overlay); + break; + default: + throw ghoul::MissingCaseException(); } } else { diff --git a/modules/base/rendering/renderabletrailtrajectory.cpp b/modules/base/rendering/renderabletrailtrajectory.cpp index 1a5284650a..ecd770c3ea 100644 --- a/modules/base/rendering/renderabletrailtrajectory.cpp +++ b/modules/base/rendering/renderabletrailtrajectory.cpp @@ -29,6 +29,7 @@ #include #include #include +#include // This class creates the entire trajectory at once and keeps it in memory the entire // time. This means that there is no need for updating the trail at runtime, but also that @@ -81,49 +82,31 @@ namespace { "If this value is set to 'true', the entire trail will be rendered; if it is " "'false', only the trail until the current time in the application will be shown." }; + + struct [[codegen::Dictionary(RenderableTrailTrajectory)]] Parameters { + // [[codegen::verbatim(StartTimeInfo.description)]] + std::string startTime [[codegen::annotation("A valid date in ISO 8601 format")]]; + + // [[codegen::verbatim(EndTimeInfo.description)]] + std::string endTime [[codegen::annotation("A valid date in ISO 8601 format")]]; + + // [[codegen::verbatim(SampleIntervalInfo.description)]] + double sampleInterval; + + // [[codegen::verbatim(TimeSubSampleInfo.description)]] + std::optional timeStampSubsampleFactor; + + // [[codegen::verbatim(RenderFullPathInfo.description)]] + std::optional showFullTrail; + }; +#include "renderabletrailtrajectory_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableTrailTrajectory::Documentation() { - using namespace documentation; - - documentation::Documentation doc { - "RenderableTrailTrajectory", - "base_renderable_renderabletrailtrajectory", - { - { - StartTimeInfo.identifier, - new StringAnnotationVerifier("A valid date in ISO 8601 format"), - Optional::No, - StartTimeInfo.description - }, - { - EndTimeInfo.identifier, - new StringAnnotationVerifier("A valid date in ISO 8601 format"), - Optional::No, - EndTimeInfo.description - }, - { - SampleIntervalInfo.identifier, - new DoubleVerifier, - Optional::No, - SampleIntervalInfo.description - }, - { - TimeSubSampleInfo.identifier, - new IntVerifier, - Optional::Yes, - TimeSubSampleInfo.description - }, - { - RenderFullPathInfo.identifier, - new BoolVerifier, - Optional::Yes, - RenderFullPathInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_renderable_renderabletrailtrajectory"; // @TODO cleanup // Insert the parents documentation entries until we have a verifier that can deal @@ -146,37 +129,28 @@ RenderableTrailTrajectory::RenderableTrailTrajectory(const ghoul::Dictionary& di , _timeStampSubsamplingFactor(TimeSubSampleInfo, 1, 1, 1000000000) , _renderFullTrail(RenderFullPathInfo, false) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableTrailTrajectory" - ); + const Parameters p = codegen::bake(dictionary); _translation->onParameterChange([this]() { _needsFullSweep = true; }); - _startTime = dictionary.value(StartTimeInfo.identifier); + _startTime = p.startTime; _startTime.onChange([this] { _needsFullSweep = true; }); addProperty(_startTime); - _endTime = dictionary.value(EndTimeInfo.identifier); + _endTime = p.endTime; _endTime.onChange([this] { _needsFullSweep = true; }); addProperty(_endTime); - _sampleInterval = dictionary.value(SampleIntervalInfo.identifier); + _sampleInterval = p.sampleInterval; _sampleInterval.onChange([this] { _needsFullSweep = true; }); addProperty(_sampleInterval); - if (dictionary.hasValue(TimeSubSampleInfo.identifier)) { - _timeStampSubsamplingFactor = static_cast( - dictionary.value(TimeSubSampleInfo.identifier) - ); - } + _timeStampSubsamplingFactor = + p.timeStampSubsampleFactor.value_or(_timeStampSubsamplingFactor); _timeStampSubsamplingFactor.onChange([this] { _subsamplingIsDirty = true; }); addProperty(_timeStampSubsamplingFactor); - if (dictionary.hasValue(RenderFullPathInfo.identifier)) { - _renderFullTrail = dictionary.value(RenderFullPathInfo.identifier); - } + _renderFullTrail = p.showFullTrail.value_or(_renderFullTrail); addProperty(_renderFullTrail); // We store the vertices with ascending temporal order diff --git a/modules/base/rotation/fixedrotation.cpp b/modules/base/rotation/fixedrotation.cpp index 5d0d864ad0..c89e4dc489 100644 --- a/modules/base/rotation/fixedrotation.cpp +++ b/modules/base/rotation/fixedrotation.cpp @@ -185,7 +185,7 @@ namespace { 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 + // 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; diff --git a/modules/base/rotation/timelinerotation.cpp b/modules/base/rotation/timelinerotation.cpp index 39ef1dec06..8a60f99c8b 100644 --- a/modules/base/rotation/timelinerotation.cpp +++ b/modules/base/rotation/timelinerotation.cpp @@ -30,48 +30,32 @@ #include namespace { - constexpr const char* KeyKeyframes = "Keyframes"; + struct [[codegen::Dictionary(TimelineRotation)]] Parameters { + // A table of keyframes, with keys formatted as YYYY-MM-DDTHH:MM:SS and values + // that are valid Rotation objects + std::map keyframes + [[codegen::reference("core_transform_rotation")]]; + }; +#include "timelinerotation_codegen.cpp" } // namespace namespace openspace { documentation::Documentation TimelineRotation::Documentation() { - using namespace documentation; - return { - "Timeline Rotation", - "base_transform_rotation_keyframe", - { - { - KeyKeyframes, - new TableVerifier({ - { "*", new TableVerifier(), Optional::No, "Any translation object" } - }), - Optional::No, - "A table of keyframes, with keys formatted as YYYY-MM-DDTHH:MM:SS" - "and values that are valid Rotation objects." - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_transform_rotation_keyframe"; + return doc; } TimelineRotation::TimelineRotation(const ghoul::Dictionary& dictionary) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "TimelineTranslation" - ); + const Parameters p = codegen::bake(dictionary); - const ghoul::Dictionary& keyframes = - dictionary.value(KeyKeyframes); - - for (std::string_view timeString : keyframes.keys()) { - const double t = Time::convertTime(std::string(timeString)); - - ghoul::mm_unique_ptr rotation = - Rotation::createFromDictionary( - keyframes.value(timeString) - ); + for (const std::pair& kf : p.keyframes) { + const double t = Time::convertTime(kf.first); + ghoul::mm_unique_ptr rotation = Rotation::createFromDictionary( + kf.second + ); if (rotation) { _timeline.addKeyframe(t, std::move(rotation)); } diff --git a/modules/base/timeframe/timeframeunion.cpp b/modules/base/timeframe/timeframeunion.cpp index 05f7da7028..b630f940ea 100644 --- a/modules/base/timeframe/timeframeunion.cpp +++ b/modules/base/timeframe/timeframeunion.cpp @@ -41,7 +41,8 @@ namespace { struct [[codegen::Dictionary(TimeFrameUnion)]] Parameters { // [[codegen::verbatim(TimeFramesInfo.description)]] - std::vector timeFrames [[codegen::reference("core_time_frame")]]; + std::vector timeFrames + [[codegen::reference("core_time_frame")]]; }; #include "timeframeunion_codegen.cpp" } // namespace diff --git a/modules/base/translation/timelinetranslation.cpp b/modules/base/translation/timelinetranslation.cpp index fb6dafb14e..6067f91c5b 100644 --- a/modules/base/translation/timelinetranslation.cpp +++ b/modules/base/translation/timelinetranslation.cpp @@ -30,48 +30,31 @@ #include namespace { - constexpr const char* KeyKeyframes = "Keyframes"; + struct [[codegen::Dictionary(TimelineTranslation)]] Parameters { + // A table of keyframes, with keys formatted as YYYY-MM-DDTHH:MM:SS and values + // that are valid Translation objects + std::map keyframes + [[codegen::reference("core_transform_translation")]]; + }; +#include "timelinetranslation_codegen.cpp" } // namespace namespace openspace { documentation::Documentation TimelineTranslation::Documentation() { - using namespace documentation; - return { - "Timeline Translation", - "base_transform_translation_keyframe", - { - { - KeyKeyframes, - new TableVerifier({ - { "*", new TableVerifier(), Optional::No, "Any translation object" } - }), - Optional::No, - "A table of keyframes, with keys formatted as YYYY-MM-DDTHH:MM:SS" - "and values that are valid Translation objects." - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "base_transform_translation_keyframe"; + return doc; } TimelineTranslation::TimelineTranslation(const ghoul::Dictionary& dictionary) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "TimelineTranslation" - ); + const Parameters p = codegen::bake(dictionary); - const ghoul::Dictionary& keyframes = - dictionary.value(KeyKeyframes); - - for (std::string_view timeString : keyframes.keys()) { - const double t = Time::convertTime(std::string(timeString)); + for (const std::pair& kf : p.keyframes) { + const double t = Time::convertTime(kf.first); ghoul::mm_unique_ptr translation = - Translation::createFromDictionary( - keyframes.value(timeString) - ); - + Translation::createFromDictionary(kf.second); if (translation) { _timeline.addKeyframe(t, std::move(translation)); } diff --git a/modules/debugging/rendering/renderabledebugplane.cpp b/modules/debugging/rendering/renderabledebugplane.cpp index 3b2d0767a5..723458ed8a 100644 --- a/modules/debugging/rendering/renderabledebugplane.cpp +++ b/modules/debugging/rendering/renderabledebugplane.cpp @@ -37,6 +37,7 @@ #include #include #include +#include namespace { enum Origin { @@ -72,47 +73,38 @@ namespace { "Texture Coordinate Origin", "The origin of the texture coorinate system." }; + + struct [[codegen::Dictionary(RenderableDebugPlane)]] Parameters { + // [[codegen::verbatim(TextureInfo.description)]] + std::optional texture; + + // [[codegen::verbatim(BillboardInfo.description)]] + std::optional billboard; + + // [[codegen::verbatim(SizeInfo.description)]] + std::optional size; + + enum class Origin { + LowerLeft, + LowerRight, + UpperLeft, + UpperRight, + Center + }; + // [[codegen::verbatim(OriginInfo.description)]] + std::optional origin; + }; +#include "renderabledebugplane_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableDebugPlane::Documentation() { - using namespace documentation; - return { - "RenderableDebugPlane", - "debugging_renderable_debugplane", - { - { - TextureInfo.identifier, - new IntVerifier, - Optional::Yes, - TextureInfo.description - }, - { - BillboardInfo.identifier, - new BoolVerifier, - Optional::Yes, - BillboardInfo.description - }, - { - SizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - SizeInfo.description - }, - { - OriginInfo.identifier, - new StringInListVerifier( - { "LowerLeft", "LowerRight", "UpperLeft", "UpperRight", "Center" } - ), - Optional::Yes, - OriginInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "debugging_renderable_debugplane"; + return doc; } - RenderableDebugPlane::RenderableDebugPlane(const ghoul::Dictionary& dictionary) : Renderable(dictionary) , _texture(TextureInfo, -1, -1, 512) @@ -120,17 +112,18 @@ RenderableDebugPlane::RenderableDebugPlane(const ghoul::Dictionary& dictionary) , _size(SizeInfo, 10.f, 0.f, 1e25f) , _origin(OriginInfo, properties::OptionProperty::DisplayType::Dropdown) { - if (dictionary.hasKey(TextureInfo.identifier)) { - _texture = static_cast(dictionary.value(TextureInfo.identifier)); - } + const Parameters p = codegen::bake(dictionary); - if (dictionary.hasKey(SizeInfo.identifier)) { - _size = static_cast(dictionary.value(SizeInfo.identifier)); - } - - if (dictionary.hasKey(BillboardInfo.identifier)) { - _billboard = dictionary.value(BillboardInfo.identifier); - } + _texture = p.texture.value_or(_texture); + addProperty(_texture); + + _size.onChange([this](){ _planeIsDirty = true; }); + _size = p.size.value_or(_size); + setBoundingSphere(_size); + addProperty(_size); + + _billboard = p.billboard.value_or(_billboard); + addProperty(_billboard); _origin.addOptions({ { LowerLeft, "LowerLeft" }, @@ -141,36 +134,30 @@ RenderableDebugPlane::RenderableDebugPlane(const ghoul::Dictionary& dictionary) }); _origin.setValue(Center); - if (dictionary.hasKey(OriginInfo.identifier)) { - const std::string origin = dictionary.value(OriginInfo.identifier); - if (origin == "LowerLeft") { - _origin = LowerLeft; - } - else if (origin == "LowerRight") { - _origin = LowerRight; - } - else if (origin == "UpperLeft") { - _origin = UpperLeft; - } - else if (origin == "UpperRight") { - _origin = UpperRight; - } - else if (origin == "Center") { - _origin = Center; + if (p.origin.has_value()) { + switch (*p.origin) { + case Parameters::Origin::LowerLeft: + _origin = LowerLeft; + break; + case Parameters::Origin::LowerRight: + _origin = LowerRight; + break; + case Parameters::Origin::UpperLeft: + _origin = UpperLeft; + break; + case Parameters::Origin::UpperRight: + _origin = UpperRight; + break; + case Parameters::Origin::Center: + _origin = Center; + break; + default: + throw ghoul::MissingCaseException(); } } else { _origin = Center; } - - addProperty(_texture); - - addProperty(_billboard); - - addProperty(_size); - _size.onChange([this](){ _planeIsDirty = true; }); - - setBoundingSphere(_size); } bool RenderableDebugPlane::isReady() const { diff --git a/modules/debugging/rendering/renderabledebugplane.h b/modules/debugging/rendering/renderabledebugplane.h index 27294e2a02..321604073e 100644 --- a/modules/debugging/rendering/renderabledebugplane.h +++ b/modules/debugging/rendering/renderabledebugplane.h @@ -68,7 +68,7 @@ private: properties::FloatProperty _size; properties::OptionProperty _origin; - bool _planeIsDirty; + bool _planeIsDirty = true; std::unique_ptr _shader; diff --git a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp index d49e7682f8..01a28f5214 100644 --- a/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp +++ b/modules/digitaluniverse/rendering/renderablebillboardscloud.cpp @@ -273,32 +273,32 @@ namespace { // The number of sides for the polygon used to represent the astronomical object std::optional polygonSides; - // [[codgen::verbatim(DrawLabelInfo.description)]] + // [[codegen::verbatim(DrawLabelInfo.description)]] std::optional drawLabels; - // [[codgen::verbatim(TextColorInfo.description)]] + // [[codegen::verbatim(TextColorInfo.description)]] std::optional textColor [[codegen::color()]]; - // [[codgen::verbatim(TextOpacityInfo.description)]] + // [[codegen::verbatim(TextOpacityInfo.description)]] std::optional textOpacity; - // [[codgen::verbatim(TextSizeInfo.description)]] + // [[codegen::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)]] + // [[codegen::verbatim(LabelMinSizeInfo.description)]] std::optional textMinSize; - // [[codgen::verbatim(LabelMaxSizeInfo.description)]] + // [[codegen::verbatim(LabelMaxSizeInfo.description)]] std::optional textMaxSize; - // [[codgen::verbatim(ColorOptionInfo.description)]] + // [[codegen::verbatim(ColorOptionInfo.description)]] std::optional> colorOption; - // [[codgen::verbatim(SizeOptionInfo.description)]] + // [[codegen::verbatim(SizeOptionInfo.description)]] std::optional> sizeOption; // This value determines the colormap ranges for the color parameters of the @@ -308,28 +308,28 @@ namespace { // Transformation matrix to be applied to each astronomical object std::optional transformationMatrix; - // [[codgen::verbatim(FadeInDistancesInfo.description)]] + // [[codegen::verbatim(FadeInDistancesInfo.description)]] std::optional fadeInDistances; - // [[codgen::verbatim(DisableFadeInInfo.description)]] + // [[codegen::verbatim(DisableFadeInInfo.description)]] std::optional disableFadeIn; - // [[codgen::verbatim(BillboardMaxSizeInfo.description)]] + // [[codegen::verbatim(BillboardMaxSizeInfo.description)]] std::optional billboardMaxSize; - // [[codgen::verbatim(BillboardMinSizeInfo.description)]] + // [[codegen::verbatim(BillboardMinSizeInfo.description)]] std::optional billboardMinSize; - // [[codgen::verbatim(CorrectionSizeEndDistanceInfo.description)]] + // [[codegen::verbatim(CorrectionSizeEndDistanceInfo.description)]] std::optional correctionSizeEndDistance; - // [[codgen::verbatim(CorrectionSizeFactorInfo.description)]] + // [[codegen::verbatim(CorrectionSizeFactorInfo.description)]] std::optional correctionSizeFactor; - // [[codgen::verbatim(PixelSizeControlInfo.description)]] + // [[codegen::verbatim(PixelSizeControlInfo.description)]] std::optional enablePixelSizeControl; - // [[codgen::verbatim(UseLinearFiltering.description)]] + // [[codegen::verbatim(UseLinearFiltering.description)]] std::optional useLinearFiltering; }; #include "renderablebillboardscloud_codegen.cpp" @@ -1492,6 +1492,11 @@ void RenderableBillboardsCloud::createDataSlice() { ZoneScoped _slicedData.clear(); + + if (_fullData.empty() || _nValuesPerAstronomicalObject == 0) { + return; + } + if (_hasColorMapFile) { _slicedData.reserve(8 * (_fullData.size() / _nValuesPerAstronomicalObject)); } diff --git a/modules/digitaluniverse/rendering/renderabledumeshes.cpp b/modules/digitaluniverse/rendering/renderabledumeshes.cpp index 661de9600d..d73465cc19 100644 --- a/modules/digitaluniverse/rendering/renderabledumeshes.cpp +++ b/modules/digitaluniverse/rendering/renderabledumeshes.cpp @@ -194,7 +194,7 @@ RenderableDUMeshes::RenderableDUMeshes(const ghoul::Dictionary& dictionary) , _drawLabels(DrawLabelInfo, false) , _textMinSize(LabelMinSizeInfo, 8.f, 0.5f, 24.f) , _textMaxSize(LabelMaxSizeInfo, 500.f, 0.f, 1000.f) - , _lineWidth(LineWidthInfo, 2.f, 0.f, 16.f) + , _lineWidth(LineWidthInfo, 2.f, 1.f, 16.f) , _renderOption(RenderOptionInfo, properties::OptionProperty::DisplayType::Dropdown) { const Parameters p = codegen::bake(dictionary); diff --git a/modules/exoplanets/exoplanetshelper.cpp b/modules/exoplanets/exoplanetshelper.cpp index 580dd7b5cd..f538f73f6f 100644 --- a/modules/exoplanets/exoplanetshelper.cpp +++ b/modules/exoplanets/exoplanetshelper.cpp @@ -24,6 +24,9 @@ #include +#include +#include +#include #include #include #include @@ -36,8 +39,6 @@ namespace { constexpr const char* _loggerCat = "ExoplanetsModule"; - - constexpr const char* BvColormapPath = "${SYNC}/http/stars_colormap/2/colorbv.cmap"; } namespace openspace::exoplanets { @@ -57,19 +58,37 @@ bool hasSufficientData(const ExoplanetDataEntry& p) { } glm::vec3 computeStarColor(float bv) { - std::ifstream colorMap(absPath(BvColormapPath), std::ios::in); + const ExoplanetsModule* module = global::moduleEngine->module(); + const std::string bvColormapPath = module->bvColormapPath(); + + std::ifstream colorMap(absPath(bvColormapPath), std::ios::in); if (!colorMap.good()) { LERROR(fmt::format( "Failed to open colormap data file: '{}'", - absPath(BvColormapPath) + absPath(bvColormapPath) )); - return glm::vec3(0.f, 0.f, 0.f); + return glm::vec3(0.f); } - const int t = static_cast(round(((bv + 0.4) / (2.0 + 0.4)) * 255)); + // Interpret the colormap cmap file + std::string line; + while (std::getline(colorMap, line)) { + if (line.empty() || (line[0] == '#')) { + continue; + } + break; + } + + // The first line is the width of the image, i.e number of values + std::istringstream ss(line); + int nValues; + ss >> nValues; + + // Find the line matching the input B-V value (B-V is in [-0.4,2.0]) + const int t = static_cast(round(((bv + 0.4) / (2.0 + 0.4)) * (nValues - 1))); std::string color; - for (int i = 0; i < t + 12; i++) { + for (int i = 0; i < t + 1; i++) { getline(colorMap, color); } colorMap.close(); diff --git a/modules/exoplanets/exoplanetsmodule.cpp b/modules/exoplanets/exoplanetsmodule.cpp index 6b2c4258be..a918bb6ca1 100644 --- a/modules/exoplanets/exoplanetsmodule.cpp +++ b/modules/exoplanets/exoplanetsmodule.cpp @@ -44,6 +44,12 @@ namespace { "The path to the folder containing the exoplanets data and lookup table" }; + constexpr const openspace::properties::Property::PropertyInfo BvColorMapInfo = { + "BvColormap", + "B-V Colormap", + "The path to a cmap file that maps a B-V color index to an RGB color" + }; + constexpr const openspace::properties::Property::PropertyInfo StarTextureInfo = { "StarTexture", "Star Texture", @@ -123,6 +129,9 @@ namespace { // [[codegen::verbatim(DataFolderInfo.description)]] std::optional dataFolder [[codegen::directory()]]; + // [[codegen::verbatim(BvColorMapInfo.description)]] + std::optional bvColormap; + // [[codegen::verbatim(StarTextureInfo.description)]] std::optional starTexture; @@ -160,6 +169,7 @@ using namespace exoplanets; ExoplanetsModule::ExoplanetsModule() : OpenSpaceModule(Name) , _exoplanetsDataFolder(DataFolderInfo) + , _bvColorMapPath(BvColorMapInfo) , _starTexturePath(StarTextureInfo) , _starGlareTexturePath(StarGlareTextureInfo) , _noDataTexturePath(NoDataTextureInfo) @@ -173,6 +183,7 @@ ExoplanetsModule::ExoplanetsModule() _exoplanetsDataFolder.setReadOnly(true); addProperty(_exoplanetsDataFolder); + addProperty(_bvColorMapPath); addProperty(_starTexturePath); addProperty(_starGlareTexturePath); addProperty(_noDataTexturePath); @@ -198,6 +209,10 @@ std::string ExoplanetsModule::lookUpTablePath() const { ); }; +std::string ExoplanetsModule::bvColormapPath() const { + return _bvColorMapPath; +} + std::string ExoplanetsModule::starTexturePath() const { return _starTexturePath; } @@ -280,6 +295,10 @@ void ExoplanetsModule::internalInitialize(const ghoul::Dictionary& dict) { _exoplanetsDataFolder = p.dataFolder.value().string(); } + if (p.bvColormap.has_value()) { + _bvColorMapPath = p.bvColormap.value().string(); + } + if (p.starTexture.has_value()) { _starTexturePath = p.starTexture.value().string(); } diff --git a/modules/exoplanets/exoplanetsmodule.h b/modules/exoplanets/exoplanetsmodule.h index fd2ef956f1..c089651587 100644 --- a/modules/exoplanets/exoplanetsmodule.h +++ b/modules/exoplanets/exoplanetsmodule.h @@ -43,6 +43,7 @@ public: std::string exoplanetsDataPath() const; std::string lookUpTablePath() const; + std::string bvColormapPath() const; std::string starTexturePath() const; std::string starGlareTexturePath() const; std::string noDataTexturePath() const; @@ -60,6 +61,7 @@ protected: void internalInitialize(const ghoul::Dictionary& dict) override; properties::StringProperty _exoplanetsDataFolder; + properties::StringProperty _bvColorMapPath; properties::StringProperty _starTexturePath; properties::StringProperty _starGlareTexturePath; properties::StringProperty _noDataTexturePath; diff --git a/modules/exoplanets/exoplanetsmodule_lua.inl b/modules/exoplanets/exoplanetsmodule_lua.inl index 26d40cde45..5843cec267 100644 --- a/modules/exoplanets/exoplanetsmodule_lua.inl +++ b/modules/exoplanets/exoplanetsmodule_lua.inl @@ -56,7 +56,8 @@ namespace openspace::exoplanets::luascriptfunctions { constexpr const float AU = static_cast(distanceconstants::AstronomicalUnit); constexpr const float SolarRadius = static_cast(distanceconstants::SolarRadius); -constexpr const float JupiterRadius = static_cast(distanceconstants::JupiterRadius); +constexpr const float JupiterRadius = + static_cast(distanceconstants::JupiterRadius); ExoplanetSystem findExoplanetSystemInData(std::string_view starName) { const ExoplanetsModule* module = global::moduleEngine->module(); diff --git a/modules/fieldlines/rendering/renderablefieldlines.cpp b/modules/fieldlines/rendering/renderablefieldlines.cpp index 78a3e8dd51..e71c1e4bb3 100644 --- a/modules/fieldlines/rendering/renderablefieldlines.cpp +++ b/modules/fieldlines/rendering/renderablefieldlines.cpp @@ -126,7 +126,7 @@ RenderableFieldlines::RenderableFieldlines(const ghoul::Dictionary& dictionary) else { _vectorFieldInfo = dictionary.value(KeyVectorField); } - + if (!dictionary.hasValue(KeyFieldlines)) { LERROR(fmt::format("Renderable does not contain a key for '{}'", KeyFieldlines)); } diff --git a/modules/gaia/rendering/renderablegaiastars.cpp b/modules/gaia/rendering/renderablegaiastars.cpp index 722f90f8b2..e89dc71d06 100644 --- a/modules/gaia/rendering/renderablegaiastars.cpp +++ b/modules/gaia/rendering/renderablegaiastars.cpp @@ -300,199 +300,123 @@ namespace { "Report GL Errors", "If set to true, any OpenGL errors will be reported if encountered" }; + + struct [[codegen::Dictionary(RenderableGaiaStars)]] Parameters { + // [[codegen::verbatim(FilePathInfo.description)]] + std::string file; + + enum class FileReader { + Fits, + Speck, + BinaryRaw, + BinaryOctree, + StreamOctree + }; + // [[codegen::verbatim(FileReaderOptionInfo.description)]] + FileReader fileReaderOption; + + enum class RenderOption { + Static, + Color, + Motion + }; + // [[codegen::verbatim(RenderOptionInfo.description)]] + std::optional renderOption; + + enum class ShaderOption { + PointSSBO [[codegen::key("Point_SSBO")]], + PointVBO [[codegen::key("Point_VBO")]], + BillboardSSBO [[codegen::key("Billboard_SSBO")]], + BillboardVBO [[codegen::key("Billboard_VBO")]], + BillboardSSBONoFBO [[codegen::key("Billboard_SSBO_noFBO")]] + }; + // [codegen::verbatim(ShaderOptionInfo.description)]] + std::optional shaderOption; + + // [codegen::verbatim(PsfTextureInfo.description)]] + std::string texture; + + // [codegen::verbatim(ColorTextureInfo.description)]] + std::string colorMap; + + // [codegen::verbatim(LuminosityMultiplierInfo.description)]] + std::optional luminosityMultiplier; + + // [codegen::verbatim(MagnitudeBoostInfo.description)]] + std::optional magnitudeBoost; + + // [codegen::verbatim(CutOffThresholdInfo.description)]] + std::optional cutOffThreshold; + + // [codegen::verbatim(SharpnessInfo.description)]] + std::optional sharpness; + + // [codegen::verbatim(BillboardSizeInfo.description)]] + std::optional billboardSize; + + // [codegen::verbatim(CloseUpBoostDistInfo.description)]] + std::optional closeUpBoostDist; + + // [codegen::verbatim(TmPointFilterSizeInfo.description)]] + std::optional filterSize; + + // [codegen::verbatim(TmPointSigmaInfo.description)]] + std::optional sigma; + + // [codegen::verbatim(AdditionalNodesInfo.description)]] + std::optional additionalNodes; + + // [codegen::verbatim(TmPointPxThresholdInfo.description)]] + std::optional pixelWeightThreshold; + + // [codegen::verbatim(FirstRowInfo.description)]] + std::optional firstRow; + + // [codegen::verbatim(LastRowInfo.description)]] + std::optional lastRow; + + // [codegen::verbatim(ColumnNamesInfo.description)]] + std::optional> columnNames; + + // [codegen::verbatim(LodPixelThresholdInfo.description)]] + std::optional lodPixelThreshold; + + // [codegen::verbatim(MaxGpuMemoryPercentInfo.description)]] + std::optional maxGpuMemoryPercent; + + // [codegen::verbatim(MaxCpuMemoryPercentInfo.description)]] + std::optional maxCpuMemoryPercent; + + // [codegen::verbatim(FilterPosXInfo.description)]] + std::optional filterPosX; + + // [codegen::verbatim(FilterPosYInfo.description)]] + std::optional filterPosY; + + // [codegen::verbatim(FilterPosZInfo.description)]] + std::optional filterPosZ; + + // [codegen::verbatim(FilterGMagInfo.description)]] + std::optional filterGMag; + + // [codegen::verbatim(FilterBpRpInfo.description)]] + std::optional filterBpRp; + + // [codegen::verbatim(FilterDistInfo.description)]] + std::optional filterDist; + + // [codegen::verbatim(ReportGlErrorsInfo.description)]] + std::optional reportGlErrors; + }; +#include "renderablegaiastars_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderableGaiaStars::Documentation() { - using namespace documentation; - return { - "RenderableGaiaStars", - "gaiamission_renderablegaiastars", - { - { - FilePathInfo.identifier, - new StringVerifier, - Optional::No, - FilePathInfo.description - }, - { - FileReaderOptionInfo.identifier, - new StringInListVerifier({ - "Fits", "Speck", "BinaryRaw", "BinaryOctree", "StreamOctree" - }), - Optional::No, - FileReaderOptionInfo.description - }, - { - RenderOptionInfo.identifier, - new StringInListVerifier({ - "Static", "Color", "Motion" - }), - Optional::Yes, - RenderOptionInfo.description - }, - { - ShaderOptionInfo.identifier, - new StringInListVerifier({ - "Point_SSBO", "Point_VBO", "Billboard_SSBO", "Billboard_VBO", - "Billboard_SSBO_noFBO" - }), - Optional::Yes, - ShaderOptionInfo.description - }, - { - PsfTextureInfo.identifier, - new StringVerifier, - Optional::No, - PsfTextureInfo.description - }, - { - ColorTextureInfo.identifier, - new StringVerifier, - Optional::No, - ColorTextureInfo.description - }, - { - LuminosityMultiplierInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LuminosityMultiplierInfo.description - }, - { - MagnitudeBoostInfo.identifier, - new DoubleVerifier, - Optional::Yes, - MagnitudeBoostInfo.description - }, - { - CutOffThresholdInfo.identifier, - new DoubleVerifier, - Optional::Yes, - CutOffThresholdInfo.description - }, - { - SharpnessInfo.identifier, - new DoubleVerifier, - Optional::Yes, - SharpnessInfo.description - }, - { - BillboardSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - BillboardSizeInfo.description - }, - { - CloseUpBoostDistInfo.identifier, - new DoubleVerifier, - Optional::Yes, - CloseUpBoostDistInfo.description - }, - { - TmPointFilterSizeInfo.identifier, - new IntVerifier, - Optional::Yes, - TmPointFilterSizeInfo.description - }, - { - TmPointSigmaInfo.identifier, - new DoubleVerifier, - Optional::Yes, - TmPointSigmaInfo.description - }, - { - AdditionalNodesInfo.identifier, - new Vector2Verifier, - Optional::Yes, - AdditionalNodesInfo.description - }, - { - TmPointPxThresholdInfo.identifier, - new DoubleVerifier, - Optional::Yes, - TmPointPxThresholdInfo.description - }, - { - FirstRowInfo.identifier, - new IntVerifier, - Optional::Yes, - FirstRowInfo.description - }, - { - LastRowInfo.identifier, - new IntVerifier, - Optional::Yes, - LastRowInfo.description - }, - { - ColumnNamesInfo.identifier, - new StringListVerifier, - Optional::Yes, - ColumnNamesInfo.description - }, - { - LodPixelThresholdInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LodPixelThresholdInfo.description - }, - { - MaxGpuMemoryPercentInfo.identifier, - new DoubleVerifier, - Optional::Yes, - MaxGpuMemoryPercentInfo.description - }, - { - MaxCpuMemoryPercentInfo.identifier, - new DoubleVerifier, - Optional::Yes, - MaxCpuMemoryPercentInfo.description - }, - { - FilterPosXInfo.identifier, - new Vector2Verifier, - Optional::Yes, - FilterPosXInfo.description - }, - { - FilterPosYInfo.identifier, - new Vector2Verifier, - Optional::Yes, - FilterPosYInfo.description - }, - { - FilterPosZInfo.identifier, - new Vector2Verifier, - Optional::Yes, - FilterPosZInfo.description - }, - { - FilterGMagInfo.identifier, - new Vector2Verifier, - Optional::Yes, - FilterGMagInfo.description - }, - { - FilterBpRpInfo.identifier, - new Vector2Verifier, - Optional::Yes, - FilterBpRpInfo.description - }, - { - FilterDistInfo.identifier, - new Vector2Verifier, - Optional::Yes, - FilterDistInfo.description - }, - { - ReportGlErrorsInfo.identifier, - new BoolVerifier, - Optional::Yes, - ReportGlErrorsInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "gaiamission_renderablegaiastars"; + return doc; } RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary) @@ -536,13 +460,9 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary) { using File = ghoul::filesystem::File; - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableGaiaStars" - ); + const Parameters p = codegen::bake(dictionary); - _filePath = absPath(dictionary.value(FilePathInfo.identifier)); + _filePath = absPath(p.file); _dataFile = std::make_unique(_filePath); _dataFile->setCallback([&](const File&) { _dataIsDirty = true; }); @@ -556,25 +476,24 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary) { gaia::FileReaderOption::BinaryOctree, "BinaryOctree" }, { gaia::FileReaderOption::StreamOctree, "StreamOctree" } }); - if (dictionary.hasKey(FileReaderOptionInfo.identifier)) { - const std::string fileReaderOption = dictionary.value( - FileReaderOptionInfo.identifier - ); - if (fileReaderOption == "Fits") { + switch (p.fileReaderOption) { + case Parameters::FileReader::Fits: _fileReaderOption = gaia::FileReaderOption::Fits; - } - else if (fileReaderOption == "Speck") { + break; + case Parameters::FileReader::Speck: _fileReaderOption = gaia::FileReaderOption::Speck; - } - else if (fileReaderOption == "BinaryRaw") { + break; + case Parameters::FileReader::BinaryRaw: _fileReaderOption = gaia::FileReaderOption::BinaryRaw; - } - else if (fileReaderOption == "BinaryOctree") { + break; + case Parameters::FileReader::BinaryOctree: _fileReaderOption = gaia::FileReaderOption::BinaryOctree; - } - else { + break; + case Parameters::FileReader::StreamOctree: _fileReaderOption = gaia::FileReaderOption::StreamOctree; - } + break; + default: + throw ghoul::MissingCaseException(); } _renderOption.addOptions({ @@ -582,18 +501,19 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary) { gaia::RenderOption::Color, "Color" }, { gaia::RenderOption::Motion, "Motion" } }); - if (dictionary.hasKey(RenderOptionInfo.identifier)) { - const std::string renderOption = dictionary.value( - RenderOptionInfo.identifier - ); - if (renderOption == "Static") { - _renderOption = gaia::RenderOption::Static; - } - else if (renderOption == "Color") { - _renderOption = gaia::RenderOption::Color; - } - else { - _renderOption = gaia::RenderOption::Motion; + if (p.renderOption.has_value()) { + switch (*p.renderOption) { + case Parameters::RenderOption::Static: + _renderOption = gaia::RenderOption::Static; + break; + case Parameters::RenderOption::Color: + _renderOption = gaia::RenderOption::Color; + break; + case Parameters::RenderOption::Motion: + _renderOption = gaia::RenderOption::Motion; + break; + default: + throw ghoul::MissingCaseException(); } } _renderOption.onChange([&]() { _buffersAreDirty = true; }); @@ -614,31 +534,31 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary) }); #endif // __APPLE__ - if (dictionary.hasKey(ShaderOptionInfo.identifier)) { - // Default shader option: - _shaderOption = gaia::ShaderOption::Billboard_VBO; - - const std::string shaderOption = dictionary.value( - ShaderOptionInfo.identifier - ); - -#ifndef __APPLE__ - if (shaderOption == "Point_SSBO") { - _shaderOption = gaia::ShaderOption::Point_SSBO; - } - else if (shaderOption == "Billboard_SSBO") { - _shaderOption = gaia::ShaderOption::Billboard_SSBO; - } - else if (shaderOption == "Billboard_SSBO_noFBO") { - _shaderOption = gaia::ShaderOption::Billboard_SSBO_noFBO; - } + if (p.shaderOption.has_value()) { + switch (*p.shaderOption) { + case Parameters::ShaderOption::PointSSBO: + _shaderOption = gaia::ShaderOption::Point_SSBO; + break; + case Parameters::ShaderOption::PointVBO: +#ifdef __APPLE__ + throw ghoul::RuntimeError("Shader option is not supported on MacOS"); #endif // __APPLE__ - - if (shaderOption == "Point_VBO") { - _shaderOption = gaia::ShaderOption::Point_VBO; - } - else if (shaderOption == "Billboard_VBO") { - _shaderOption = gaia::ShaderOption::Billboard_VBO; + _shaderOption = gaia::ShaderOption::Point_VBO; + break; + case Parameters::ShaderOption::BillboardSSBO: + _shaderOption = gaia::ShaderOption::Billboard_SSBO; + break; + case Parameters::ShaderOption::BillboardVBO: +#ifdef __APPLE__ + throw ghoul::RuntimeError("Shader option is not supported on MacOS"); +#endif // __APPLE__ + _shaderOption = gaia::ShaderOption::Billboard_VBO; + break; + case Parameters::ShaderOption::BillboardSSBONoFBO: + _shaderOption = gaia::ShaderOption::Billboard_SSBO_noFBO; + break; + default: + throw ghoul::MissingCaseException(); } } _shaderOption.onChange([&]() { @@ -647,95 +567,34 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary) }); addProperty(_shaderOption); - _pointSpreadFunctionTexturePath = absPath(dictionary.value( - PsfTextureInfo.identifier - )); - _pointSpreadFunctionFile = std::make_unique(_pointSpreadFunctionTexturePath); - + _pointSpreadFunctionTexturePath = absPath(p.texture); _pointSpreadFunctionTexturePath.onChange( [&](){ _pointSpreadFunctionTextureIsDirty = true; } ); + _pointSpreadFunctionFile = std::make_unique(_pointSpreadFunctionTexturePath); _pointSpreadFunctionFile->setCallback( [&](const File&) { _pointSpreadFunctionTextureIsDirty = true; } ); - _colorTexturePath = absPath(dictionary.value( - ColorTextureInfo.identifier - )); + _colorTexturePath = absPath(p.colorMap); _colorTextureFile = std::make_unique(_colorTexturePath); _colorTexturePath.onChange([&]() { _colorTextureIsDirty = true; }); _colorTextureFile->setCallback([&](const File&) { _colorTextureIsDirty = true; }); - if (dictionary.hasKey(LuminosityMultiplierInfo.identifier)) { - _luminosityMultiplier = static_cast( - dictionary.value(LuminosityMultiplierInfo.identifier) - ); - } + _luminosityMultiplier = p.luminosityMultiplier.value_or(_luminosityMultiplier); + _magnitudeBoost = p.magnitudeBoost.value_or(_magnitudeBoost); + _cutOffThreshold = p.cutOffThreshold.value_or(_cutOffThreshold); + _sharpness = p.sharpness.value_or(_sharpness); + _billboardSize = p.billboardSize.value_or(_billboardSize); + _closeUpBoostDist = p.closeUpBoostDist.value_or(_closeUpBoostDist); + _tmPointFilterSize = p.filterSize.value_or(_tmPointFilterSize); + _tmPointSigma = p.sigma.value_or(_tmPointSigma); + _tmPointPixelWeightThreshold = + p.pixelWeightThreshold.value_or(_tmPointPixelWeightThreshold); + _additionalNodes = p.additionalNodes.value_or(_additionalNodes); + _lodPixelThreshold = p.lodPixelThreshold.value_or(_lodPixelThreshold); - if (dictionary.hasKey(MagnitudeBoostInfo.identifier)) { - _magnitudeBoost = static_cast( - dictionary.value(MagnitudeBoostInfo.identifier) - ); - } - - if (dictionary.hasKey(CutOffThresholdInfo.identifier)) { - _cutOffThreshold = static_cast( - dictionary.value(CutOffThresholdInfo.identifier) - ); - } - - if (dictionary.hasKey(SharpnessInfo.identifier)) { - _sharpness = static_cast( - dictionary.value(SharpnessInfo.identifier) - ); - } - - if (dictionary.hasKey(BillboardSizeInfo.identifier)) { - _billboardSize = static_cast( - dictionary.value(BillboardSizeInfo.identifier) - ); - } - - if (dictionary.hasKey(CloseUpBoostDistInfo.identifier)) { - _closeUpBoostDist = static_cast( - dictionary.value(CloseUpBoostDistInfo.identifier) - ); - } - - if (dictionary.hasKey(TmPointFilterSizeInfo.identifier)) { - _tmPointFilterSize = static_cast( - dictionary.value(TmPointFilterSizeInfo.identifier) - ); - } - - if (dictionary.hasKey(TmPointSigmaInfo.identifier)) { - _tmPointSigma = static_cast( - dictionary.value(TmPointSigmaInfo.identifier) - ); - } - if (dictionary.hasKey(TmPointPxThresholdInfo.identifier)) { - _tmPointPixelWeightThreshold = static_cast( - dictionary.value(TmPointPxThresholdInfo.identifier) - ); - } - - if (dictionary.hasKey(AdditionalNodesInfo.identifier)) { - _additionalNodes = static_cast( - dictionary.value(AdditionalNodesInfo.identifier) - ); - } - - if (dictionary.hasKey(LodPixelThresholdInfo.identifier)) { - _lodPixelThreshold = static_cast( - dictionary.value(LodPixelThresholdInfo.identifier) - ); - } - - if (dictionary.hasKey(MaxGpuMemoryPercentInfo.identifier)) { - _maxGpuMemoryPercent = static_cast( - dictionary.value(MaxGpuMemoryPercentInfo.identifier) - ); - } + _maxGpuMemoryPercent = p.maxGpuMemoryPercent.value_or(_maxGpuMemoryPercent); _maxGpuMemoryPercent.onChange([&]() { if (_ssboData != 0) { glDeleteBuffers(1, &_ssboData); @@ -761,59 +620,36 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary) _maxStreamingBudgetInBytes = 0; }); - if (dictionary.hasKey(MaxCpuMemoryPercentInfo.identifier)) { - _maxCpuMemoryPercent = static_cast( - dictionary.value(MaxCpuMemoryPercentInfo.identifier) - ); - } - - if (dictionary.hasKey(FilterPosXInfo.identifier)) { - _posXThreshold = dictionary.value(FilterPosXInfo.identifier); - } + _maxCpuMemoryPercent = p.maxCpuMemoryPercent.value_or(_maxCpuMemoryPercent); + _posXThreshold = p.filterPosX.value_or(_posXThreshold); addProperty(_posXThreshold); - if (dictionary.hasKey(FilterPosYInfo.identifier)) { - _posXThreshold = dictionary.value(FilterPosYInfo.identifier); - } + _posYThreshold = p.filterPosY.value_or(_posYThreshold); addProperty(_posYThreshold); - if (dictionary.hasKey(FilterPosZInfo.identifier)) { - _posZThreshold = dictionary.value(FilterPosZInfo.identifier); - } + _posZThreshold = p.filterPosZ.value_or(_posZThreshold); addProperty(_posZThreshold); - if (dictionary.hasKey(FilterGMagInfo.identifier)) { - _gMagThreshold = dictionary.value(FilterGMagInfo.identifier); - } + _gMagThreshold = p.filterGMag.value_or(_gMagThreshold); addProperty(_gMagThreshold); - if (dictionary.hasKey(FilterBpRpInfo.identifier)) { - _bpRpThreshold = dictionary.value(FilterBpRpInfo.identifier); - } + _bpRpThreshold = p.filterBpRp.value_or(_bpRpThreshold); addProperty(_bpRpThreshold); - if (dictionary.hasKey(FilterDistInfo.identifier)) { - _distThreshold = dictionary.value(FilterDistInfo.identifier); - } + _distThreshold = p.filterDist.value_or(_distThreshold); addProperty(_distThreshold); // Only add properties correlated to fits files if we're reading from a fits file. if (_fileReaderOption == gaia::FileReaderOption::Fits) { - if (dictionary.hasKey(FirstRowInfo.identifier)) { - _firstRow = static_cast( - dictionary.value(FirstRowInfo.identifier) - ); - } + _firstRow = p.firstRow.value_or(_firstRow); _firstRow.onChange([&]() { _dataIsDirty = true; }); addProperty(_firstRow); - if (dictionary.hasKey(LastRowInfo.identifier)) { - _lastRow = static_cast(dictionary.value(LastRowInfo.identifier)); - } + _lastRow = p.lastRow.value_or(_lastRow); _lastRow.onChange([&]() { _dataIsDirty = true; }); addProperty(_lastRow); - if (dictionary.hasKey(ColumnNamesInfo.identifier)) { + if (p.columnNames.has_value()) { ghoul::Dictionary tmpDict = dictionary.value( ColumnNamesInfo.identifier ); @@ -834,13 +670,11 @@ RenderableGaiaStars::RenderableGaiaStars(const ghoul::Dictionary& dictionary) } if (_firstRow > _lastRow) { - throw ghoul::RuntimeError("User defined FirstRow is bigger than LastRow."); + throw ghoul::RuntimeError("User defined FirstRow is bigger than LastRow"); } } - if (dictionary.hasKey(ReportGlErrorsInfo.identifier)) { - _reportGlErrors = dictionary.value(ReportGlErrorsInfo.identifier); - } + _reportGlErrors = p.reportGlErrors.value_or(_reportGlErrors); addProperty(_reportGlErrors); // Add a read-only property for the number of rendered stars per frame. diff --git a/modules/gaia/tasks/constructoctreetask.cpp b/modules/gaia/tasks/constructoctreetask.cpp index a4edef1372..7fefa17517 100644 --- a/modules/gaia/tasks/constructoctreetask.cpp +++ b/modules/gaia/tasks/constructoctreetask.cpp @@ -35,164 +35,263 @@ #include namespace { - constexpr const char* KeyInFileOrFolderPath = "InFileOrFolderPath"; - constexpr const char* KeyOutFileOrFolderPath = "OutFileOrFolderPath"; - constexpr const char* KeyMaxDist = "MaxDist"; - constexpr const char* KeyMaxStarsPerNode = "MaxStarsPerNode"; - constexpr const char* KeySingleFileInput = "SingleFileInput"; - - constexpr const char* KeyFilterPosX = "FilterPosX"; - constexpr const char* KeyFilterPosY = "FilterPosY"; - constexpr const char* KeyFilterPosZ = "FilterPosZ"; - constexpr const char* KeyFilterGMag = "FilterGMag"; - constexpr const char* KeyFilterBpRp = "FilterBpRp"; - constexpr const char* KeyFilterVelX = "FilterVelX"; - constexpr const char* KeyFilterVelY = "FilterVelY"; - constexpr const char* KeyFilterVelZ = "FilterVelZ"; - constexpr const char* KeyFilterBpMag = "FilterBpMag"; - constexpr const char* KeyFilterRpMag = "FilterRpMag"; - constexpr const char* KeyFilterBpG = "FilterBpG"; - constexpr const char* KeyFilterGRp = "FilterGRp"; - constexpr const char* KeyFilterRa = "FilterRa"; - constexpr const char* KeyFilterRaError = "FilterRaError"; - constexpr const char* KeyFilterDec = "FilterDec"; - constexpr const char* KeyFilterDecError = "FilterDecError"; - constexpr const char* KeyFilterParallax = "FilterParallax"; - constexpr const char* KeyFilterParallaxError = "FilterParallaxError"; - constexpr const char* KeyFilterPmra = "FilterPmra"; - constexpr const char* KeyFilterPmraError = "FilterPmraError"; - constexpr const char* KeyFilterPmdec = "FilterPmdec"; - constexpr const char* KeyFilterPmdecError = "FilterPmdecError"; - constexpr const char* KeyFilterRv = "FilterRv"; - constexpr const char* KeyFilterRvError = "FilterRvError"; - constexpr const char* _loggerCat = "ConstructOctreeTask"; + + struct [[codegen::Dictionary(ConstructOctreeTask)]] Parameters { + // If SingleFileInput is set to true then this specifies the path to a single BIN + // file containing a full dataset. Otherwise this specifies the path to a folder + // with multiple BIN files containing subsets of sorted star data + std::string inFileOrFolderPath; + + // If SingleFileInput is set to true then this specifies the output file name + // (including full path). Otherwise this specifies the path to the folder which to + // save all files + std::string outFileOrFolderPath; + + // If set it determines what MAX_DIST to use when creating Octree + std::optional maxDist; + + // If set it determines what MAX_STAR_PER_NODE to use when creating Octree + std::optional maxStarsPerNode; + + // If true then task will read from a single file and output a single binary file + // with the full Octree. If false then task will read all files in specified + // folder and output multiple files for the Octree + std::optional singleFileInput; + + // If defined then only stars with Position X values between [min, max] will be + // inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to + // 0.0 it is read as +Inf). If min = max then all values equal min|max will be + // filtered away + std::optional filterPosX; + + // If defined then only stars with Position Y values between [min, max] will be + // inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to + // 0.0 it is read as +Inf). If min = max then all values equal min|max will be + // filtered away + std::optional filterPosY; + + // If defined then only stars with Position Z values between [min, max] will be + // inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to + // 0.0 it is read as +Inf). If min = max then all values equal min|max will be + // filtered away + std::optional filterPosZ; + + // If defined then only stars with G mean magnitude values between [min, max] will + // be inserted into Octree (if min is set to 20.0 it is read as -Inf, if max is + // set to 20.0 it is read as +Inf). If min = max then all values equal min|max + // will be filtered away. Default GMag = 20.0 if no value existed + std::optional filterGMag; + + // If defined then only stars with Bp-Rp color values between [min, max] will be + // inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to + // 0.0 it is read as +Inf). If min = max then all values equal min|max will be + // filtered away + std::optional filterBpRp; + + // If defined then only stars with Velocity X values between [min, max] will be + // inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to + // 0.0 it is read as +Inf). If min = max then all values equal min|max will be + // filtered away + std::optional filterVelX; + + // If defined then only stars with Velocity Y values between [min, max] will be + // inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to + // 0.0 it is read as +Inf). If min = max then all values equal min|max will be + // filtered away + std::optional filterVelY; + + // If defined then only stars with Velocity Z values between [min, max] will be + // inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to + // 0.0 it is read as +Inf). If min = max then all values equal min|max will be + // filtered away + std::optional filterVelZ; + + // If defined then only stars with Bp mean magnitude values between [min, max] + // will be inserted into Octree (if min is set to 20.0 it is read as -Inf, if max + // is set to 20.0 it is read as +Inf). If min = max then all values equal min|max + // will be filtered away. Default BpMag = 20.0 if no value existed + std::optional filterBpMag; + + // If defined then only stars with Rp mean magnitude values between [min, max] + // will be inserted into Octree (if min is set to 20.0 it is read as -Inf, if max + // is set to 20.0 it is read as +Inf). If min = max then all values equal min|max + // will be filtered away. Default RpMag = 20.0 if no value existed + std::optional filterRpMag; + + // If defined then only stars with Bp-G color values between [min, max] will be + // inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to + // 0.0 it is read as +Inf). If min = max then all values equal min|max will be + // filtered away + std::optional filterBpG; + + // If defined then only stars with G-Rp color values between [min, max] will be + // inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to + // 0.0 it is read as +Inf). If min = max then all values equal min|max will be + // filtered away + std::optional filterGRp; + + // If defined then only stars with RA values between [min, max] will be inserted + // into Octree (if min is set to 0.0 it is read as -Inf, if max is set to 0.0 it + // is read as +Inf). If min = max then all values equal min|max will be filtered + // away + std::optional filterRa; + + // If defined then only stars with RA Error values between [min, max] will be + // inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to + // 0.0 it is read as +Inf). If min = max then all values equal min|max will be + // filtered away + std::optional filterRaError; + + // If defined then only stars with DEC values between [min, max] will be inserted + // into Octree (if min is set to 0.0 it is read as -Inf, if max is set to 0.0 it + // is read as +Inf). If min = max then all values equal min|max will be filtered + // away + std::optional filterDec; + + // If defined then only stars with DEC Error values between [min, max] will be + // inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to + // 0.0 it is read as +Inf). If min = max then all values equal min|max will be + // filtered away + std::optional filterDecError; + + // If defined then only stars with Parallax values between [min, max] will be + // inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set to + // 0.0 it is read as +Inf). If min = max then all values equal min|max will be + // filtered away + std::optional filterParallax; + + // If defined then only stars with Parallax Error values between [min, max] will + // be inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set + // to 0.0 it is read as +Inf). If min = max then all values equal min|max will be + // filtered away + std::optional filterParallaxError; + + // If defined then only stars with Proper Motion RA values between [min, max] will + // be inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set + // to 0.0 it is read as +Inf). If min = max then all values equal min|max will be + // filtered away + std::optional filterPmra; + + // If defined then only stars with Proper Motion RA Error values between + // [min, max] will be inserted into Octree (if min is set to 0.0 it is read as + // -Inf, if max is set to 0.0 it is read as +Inf). If min = max then all values + // equal min|max will be filtered away + std::optional filterPmraError; + + // If defined then only stars with Proper Motion DEC values between [min, max] + // will be inserted into Octree (if min is set to 0.0 it is read as -Inf, if max + // is set to 0.0 it is read as +Inf). If min = max then all values equal min|max + // will be filtered away + std::optional filterPmdec; + + // If defined then only stars with Proper Motion DEC Error values between + // [min, max] will be inserted into Octree (if min is set to 0.0 it is read as + // -Inf, if max is set to 0.0 it is read as +Inf). If min = max then all values + // equal min|max will be filtered away + std::optional filterPmdecError; + + // If defined then only stars with Radial Velocity values between [min, max] will + // be inserted into Octree (if min is set to 0.0 it is read as -Inf, if max is set + // to 0.0 it is read as +Inf). If min = max then all values equal min|max will be + // filtered away + std::optional filterRv; + + // If defined then only stars with Radial Velocity Error values between [min, max] + // will be inserted into Octree (if min is set to 0.0 it is read as -Inf, if max + // is set to 0.0 it is read as +Inf). If min = max then all values equal min|max + // will be filtered away + std::optional filterRvError; + }; +#include "constructoctreetask_codegen.cpp" } // namespace namespace openspace { ConstructOctreeTask::ConstructOctreeTask(const ghoul::Dictionary& dictionary) { - openspace::documentation::testSpecificationAndThrow( - documentation(), - dictionary, - "ConstructOctreeTask" - ); + const Parameters p = codegen::bake(dictionary); - _inFileOrFolderPath = absPath(dictionary.value(KeyInFileOrFolderPath)); - _outFileOrFolderPath = absPath(dictionary.value(KeyOutFileOrFolderPath)); - - if (dictionary.hasKey(KeyMaxDist)) { - _maxDist = static_cast(dictionary.value(KeyMaxDist)); - } - - if (dictionary.hasKey(KeyMaxStarsPerNode)) { - _maxStarsPerNode = static_cast(dictionary.value(KeyMaxStarsPerNode)); - } - - if (dictionary.hasKey(KeySingleFileInput)) { - _singleFileInput = dictionary.value(KeySingleFileInput); - } + _inFileOrFolderPath = absPath(p.inFileOrFolderPath); + _outFileOrFolderPath = absPath(p.outFileOrFolderPath); + _maxDist = p.maxDist.value_or(_maxDist); + _maxStarsPerNode = p.maxStarsPerNode.value_or(_maxStarsPerNode); + _singleFileInput = p.singleFileInput.value_or(_singleFileInput); _octreeManager = std::make_shared(); _indexOctreeManager = std::make_shared(); - // Check for filter params. - if (dictionary.hasKey(KeyFilterPosX)) { - _posX = dictionary.value(KeyFilterPosX); - _filterPosX = true; - } - if (dictionary.hasKey(KeyFilterPosY)) { - _posY = dictionary.value(KeyFilterPosY); - _filterPosY = true; - } - if (dictionary.hasKey(KeyFilterPosZ)) { - _posZ = dictionary.value(KeyFilterPosZ); - _filterPosZ = true; - } - if (dictionary.hasKey(KeyFilterGMag)) { - _gMag = dictionary.value(KeyFilterGMag); - _filterGMag = true; - } - if (dictionary.hasKey(KeyFilterBpRp)) { - _bpRp = dictionary.value(KeyFilterBpRp); - _filterBpRp = true; - } - if (dictionary.hasKey(KeyFilterVelX)) { - _velX = dictionary.value(KeyFilterVelX); - _filterVelX = true; - } - if (dictionary.hasKey(KeyFilterVelY)) { - _velY = dictionary.value(KeyFilterVelY); - _filterVelY = true; - } - if (dictionary.hasKey(KeyFilterVelZ)) { - _velZ = dictionary.value(KeyFilterVelZ); - _filterVelZ = true; - } - if (dictionary.hasKey(KeyFilterBpMag)) { - _bpMag = dictionary.value(KeyFilterBpMag); - _filterBpMag = true; - } - if (dictionary.hasKey(KeyFilterRpMag)) { - _rpMag = dictionary.value(KeyFilterRpMag); - _filterRpMag = true; - } - if (dictionary.hasKey(KeyFilterBpG)) { - _bpG = dictionary.value(KeyFilterBpG); - _filterBpG = true; - } - if (dictionary.hasKey(KeyFilterGRp)) { - _gRp = dictionary.value(KeyFilterGRp); - _filterGRp = true; - } - if (dictionary.hasKey(KeyFilterRa)) { - _ra = dictionary.value(KeyFilterRa); - _filterRa = true; - } - if (dictionary.hasKey(KeyFilterRaError)) { - _raError = dictionary.value(KeyFilterRaError); - _filterRaError = true; - } - if (dictionary.hasKey(KeyFilterDec)) { - _dec = dictionary.value(KeyFilterDec); - _filterDec = true; - } - if (dictionary.hasKey(KeyFilterDecError)) { - _decError = dictionary.value(KeyFilterDecError); - _filterDecError = true; - } - if (dictionary.hasKey(KeyFilterParallax)) { - _parallax = dictionary.value(KeyFilterParallax); - _filterParallax = true; - } - if (dictionary.hasKey(KeyFilterParallaxError)) { - _parallaxError = dictionary.value(KeyFilterParallaxError); - _filterParallaxError = true; - } - if (dictionary.hasKey(KeyFilterPmra)) { - _pmra = dictionary.value(KeyFilterPmra); - _filterPmra = true; - } - if (dictionary.hasKey(KeyFilterPmraError)) { - _pmraError = dictionary.value(KeyFilterPmraError); - _filterPmraError = true; - } - if (dictionary.hasKey(KeyFilterPmdec)) { - _pmdec = dictionary.value(KeyFilterPmdec); - _filterPmdec = true; - } - if (dictionary.hasKey(KeyFilterPmdecError)) { - _pmdecError = dictionary.value(KeyFilterPmdecError); - _filterPmdecError = true; - } - if (dictionary.hasKey(KeyFilterRv)) { - _rv = dictionary.value(KeyFilterRv); - _filterRv = true; - } - if (dictionary.hasKey(KeyFilterRvError)) { - _rvError = dictionary.value(KeyFilterRvError); - _filterRvError = true; - } + + _posX = p.filterPosX.value_or(_posX); + _filterPosX = p.filterPosX.has_value(); + + _posY = p.filterPosY.value_or(_posY); + _filterPosY = p.filterPosY.has_value(); + + _posZ = p.filterPosZ.value_or(_posZ); + _filterPosZ = p.filterPosZ.has_value(); + + _gMag = p.filterGMag.value_or(_gMag); + _filterGMag = p.filterGMag.has_value(); + + _bpRp = p.filterBpRp.value_or(_bpRp); + _filterBpRp = p.filterBpRp.has_value(); + + _velX = p.filterVelX.value_or(_velX); + _filterVelX = p.filterVelX.has_value(); + + _velY = p.filterVelY.value_or(_velY); + _filterVelY = p.filterVelY.has_value(); + + _velZ = p.filterVelZ.value_or(_velZ); + _filterVelZ = p.filterVelZ.has_value(); + + _bpMag = p.filterBpMag.value_or(_bpMag); + _filterBpMag = p.filterBpMag.has_value(); + + _rpMag = p.filterRpMag.value_or(_rpMag); + _filterRpMag = p.filterRpMag.has_value(); + + _bpG = p.filterBpG.value_or(_bpG); + _filterBpG = p.filterBpG.has_value(); + + _gRp = p.filterGRp.value_or(_gRp); + _filterGRp = p.filterGRp.has_value(); + + _ra = p.filterRa.value_or(_ra); + _filterRa = p.filterRa.has_value(); + + _raError = p.filterRaError.value_or(_raError); + _filterRaError = p.filterRaError.has_value(); + + _dec = p.filterDec.value_or(_dec); + _filterDec = p.filterDec.has_value(); + + _decError = p.filterDecError.value_or(_decError); + _filterDecError = p.filterDecError.has_value(); + + _parallax = p.filterParallax.value_or(_parallax); + _filterParallax = p.filterParallax.has_value(); + + _parallaxError = p.filterParallaxError.value_or(_parallaxError); + _filterParallaxError = p.filterParallaxError.has_value(); + + _pmra = p.filterPmra.value_or(_pmra); + _filterPmra = p.filterPmra.has_value(); + + _pmraError = p.filterPmraError.value_or(_pmraError); + _filterPmraError = p.filterPmraError.has_value(); + + _pmdec = p.filterPmdec.value_or(_pmdec); + _filterPmdec = p.filterPmdec.has_value(); + + _pmdecError = p.filterPmdecError.value_or(_pmdecError); + _filterPmdecError = p.filterPmdecError.has_value(); + + _rv = p.filterRv.value_or(_rv); + _filterRv = p.filterRv.has_value(); + + _rvError = p.filterRvError.value_or(_rvError); + _filterRvError = p.filterRvError.has_value(); } std::string ConstructOctreeTask::description() { @@ -201,7 +300,7 @@ std::string ConstructOctreeTask::description() { } void ConstructOctreeTask::perform(const Task::ProgressCallback& onProgress) { - onProgress(0.0f); + onProgress(0.f); if (_singleFileInput) { constructOctreeFromSingleFile(onProgress); @@ -210,7 +309,7 @@ void ConstructOctreeTask::perform(const Task::ProgressCallback& onProgress) { constructOctreeFromFolder(onProgress); } - onProgress(1.0f); + onProgress(1.f); } void ConstructOctreeTask::constructOctreeFromSingleFile( @@ -543,269 +642,9 @@ bool ConstructOctreeTask::filterStar(const glm::vec2& range, float filterValue, } documentation::Documentation ConstructOctreeTask::Documentation() { - using namespace documentation; - return { - "ConstructOctreeTask", - "gaiamission_constructoctreefrombin", - { - { - KeyInFileOrFolderPath, - new StringVerifier, - Optional::No, - "If SingleFileInput is set to true then this specifies the path to a " - "single BIN file containing a full dataset. Otherwise this specifies the " - "path to a folder with multiple BIN files containing subsets of sorted " - "star data.", - }, - { - KeyOutFileOrFolderPath, - new StringVerifier, - Optional::No, - "If SingleFileInput is set to true then this specifies the output file " - "name (including full path). Otherwise this specifies the path to the " - "folder which to save all files.", - }, - { - KeyMaxDist, - new IntVerifier, - Optional::Yes, - "If set it determines what MAX_DIST to use when creating Octree." - }, - { - KeyMaxStarsPerNode, - new IntVerifier, - Optional::Yes, - "If set it determines what MAX_STAR_PER_NODE to use when creating Octree." - }, - { - KeySingleFileInput, - new BoolVerifier, - Optional::Yes, - "If true then task will read from a single file and output a single " - "binary file with the full Octree. If false then task will read all " - "files in specified folder and output multiple files for the Octree." - }, - { - KeyFilterPosX, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Position X values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterPosY, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Position Y values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterPosZ, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Position Z values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterGMag, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with G mean magnitude values between " - "[min, max] will be inserted into Octree (if min is set to 20.0 it is " - "read as -Inf, if max is set to 20.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away. Default " - "GMag = 20.0 if no value existed." - }, - { - KeyFilterBpRp, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Bp-Rp color values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterVelX, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Velocity X values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterVelY, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Velocity Y values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterVelZ, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Velocity Z values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterBpMag, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Bp mean magnitude values between " - "[min, max] will be inserted into Octree (if min is set to 20.0 it is " - "read as -Inf, if max is set to 20.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away. Default " - "BpMag = 20.0 if no value existed." - }, - { - KeyFilterRpMag, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Rp mean magnitude values between " - "[min, max] will be inserted into Octree (if min is set to 20.0 it is " - "read as -Inf, if max is set to 20.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away. Default RpMag = " - "20.0 if no value existed." - }, - { - KeyFilterBpG, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Bp-G color values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterGRp, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with G-Rp color values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterRa, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with RA values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterRaError, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with RA Error values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterDec, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with DEC values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterDecError, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with DEC Error values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterParallax, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Parallax values between [min, max] " - "will be inserted into Octree (if min is set to 0.0 it is read as -Inf, " - "if max is set to 0.0 it is read as +Inf). If min = max then all values " - "equal min|max will be filtered away." - }, - { - KeyFilterParallaxError, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Parallax Error values between " - "[min, max] will be inserted into Octree (if min is set to 0.0 it is " - "read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away." - }, - { - KeyFilterPmra, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Proper Motion RA values between " - "[min, max] will be inserted into Octree (if min is set to 0.0 it is " - "read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away." - }, - { - KeyFilterPmraError, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Proper Motion RA Error values between " - "[min, max] will be inserted into Octree (if min is set to 0.0 it is " - "read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away." - }, - { - KeyFilterPmdec, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Proper Motion DEC values between " - "[min, max] will be inserted into Octree (if min is set to 0.0 it is " - "read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away." - }, - { - KeyFilterPmdecError, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Proper Motion DEC Error values between " - "[min, max] will be inserted into Octree (if min is set to 0.0 it is " - "read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away." - }, - { - KeyFilterRv, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Radial Velocity values between " - "[min, max] will be inserted into Octree (if min is set to 0.0 it is " - "read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away." - }, - { - KeyFilterRvError, - new Vector2Verifier, - Optional::Yes, - "If defined then only stars with Radial Velocity Error values between " - "[min, max] will be inserted into Octree (if min is set to 0.0 it is " - "read as -Inf, if max is set to 0.0 it is read as +Inf). If min = max " - "then all values equal min|max will be filtered away." - }, - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "gaiamission_constructoctreefrombin"; + return doc; } } // namespace openspace diff --git a/modules/gaia/tasks/readfitstask.cpp b/modules/gaia/tasks/readfitstask.cpp index 5139ab6366..865433da6a 100644 --- a/modules/gaia/tasks/readfitstask.cpp +++ b/modules/gaia/tasks/readfitstask.cpp @@ -36,55 +36,61 @@ #include #include +#include namespace { - constexpr const char* KeyInFileOrFolderPath = "InFileOrFolderPath"; - constexpr const char* KeyOutFileOrFolderPath = "OutFileOrFolderPath"; - constexpr const char* KeySingleFileProcess = "SingleFileProcess"; - constexpr const char* KeyThreadsToUse = "ThreadsToUse"; - constexpr const char* KeyFirstRow = "FirstRow"; - constexpr const char* KeyLastRow = "LastRow"; constexpr const char* KeyFilterColumnNames = "FilterColumnNames"; constexpr const char* _loggerCat = "ReadFitsTask"; + + struct [[codegen::Dictionary(ReadFitsTask)]] Parameters { + // If SingleFileProcess is set to true then this specifies the path to a single + // FITS file that will be read. Otherwise it specifies the path to a folder with + // multiple FITS files that are to be read + std::string inFileOrFolderPath; + + // If SingleFileProcess is set to true then this specifies the name (including + // entire path) to the output file. Otherwise it specifies the path to the output + // folder which to export binary star data to + std::string outFileOrFolderPath; + + // If true then task will read from a single FITS file and output a single binary + // file. If false then task will read all files in specified folder and output + // multiple files sorted by location + std::optional singleFileProcess; + + // Defines how many threads to use when reading from multiple files + std::optional threadsToUse [[codegen::greater(1)]]; + + // Defines the first row that will be read from the specified FITS file(s). If not + // defined then reading will start at first row + std::optional firstRow; + + // Defines the last row that will be read from the specified FITS file(s). If not + // defined (or less than FirstRow) then full file(s) will be read + std::optional lastRow; + + // A list of strings with the names of all the additional columns that are to be + // read from the specified FITS file(s). These columns can be used for filtering + // while constructing Octree later + std::optional> filterColumnNames; + }; +#include "readfitstask_codegen.cpp" } // namespace namespace openspace { ReadFitsTask::ReadFitsTask(const ghoul::Dictionary& dictionary) { - openspace::documentation::testSpecificationAndThrow( - documentation(), - dictionary, - "ReadFitsTask" - ); + const Parameters p = codegen::bake(dictionary); - _inFileOrFolderPath = absPath(dictionary.value(KeyInFileOrFolderPath)); - _outFileOrFolderPath = absPath(dictionary.value(KeyOutFileOrFolderPath)); + _inFileOrFolderPath = absPath(p.inFileOrFolderPath); + _outFileOrFolderPath = absPath(p.outFileOrFolderPath); + _singleFileProcess = p.singleFileProcess.value_or(_singleFileProcess); + _threadsToUse = p.threadsToUse.value_or(_threadsToUse); + _firstRow = p.firstRow.value_or(_firstRow); + _lastRow = p.lastRow.value_or(_lastRow); - if (dictionary.hasKey(KeySingleFileProcess)) { - _singleFileProcess = dictionary.value(KeySingleFileProcess); - } - - if (dictionary.hasKey(KeyThreadsToUse)) { - _threadsToUse = static_cast(dictionary.value(KeyThreadsToUse)); - if (_threadsToUse < 1) { - LINFO(fmt::format( - "User defined ThreadsToUse was: {}. Will be set to 1", _threadsToUse - )); - _threadsToUse = 1; - } - } - - if (dictionary.hasKey(KeyFirstRow)) { - _firstRow = static_cast(dictionary.value(KeyFirstRow)); - } - - if (dictionary.hasKey(KeyLastRow)) { - _lastRow = static_cast(dictionary.value(KeyLastRow)); - } - - - if (dictionary.hasKey(KeyFilterColumnNames)) { + if (p.filterColumnNames.has_value()) { ghoul::Dictionary d = dictionary.value(KeyFilterColumnNames); // Ugly fix for ASCII sorting when there are more columns read than 10. @@ -322,66 +328,9 @@ int ReadFitsTask::writeOctantToFile(const std::vector& octantData, int in } documentation::Documentation ReadFitsTask::Documentation() { - using namespace documentation; - return { - "ReadFitsFile", - "gaiamission_fitsfiletorawdata", - { - { - KeyInFileOrFolderPath, - new StringVerifier, - Optional::No, - "If SingleFileProcess is set to true then this specifies the path to a " - "single FITS file that will be read. Otherwise it specifies the path to " - "a folder with multiple FITS files that are to be read.", - }, - { - KeyOutFileOrFolderPath, - new StringVerifier, - Optional::No, - "If SingleFileProcess is set to true then this specifies the name " - "(including entire path) to the output file. Otherwise it specifies the " - "path to the output folder which to export binary star data to.", - }, - { - KeySingleFileProcess, - new BoolVerifier, - Optional::Yes, - "If true then task will read from a single FITS file and output a single " - "binary file. If false then task will read all files in specified folder " - "and output multiple files sorted by location." - }, - { - KeyThreadsToUse, - new IntVerifier, - Optional::Yes, - "Defines how many threads to use when reading from multiple files." - }, - { - KeyFirstRow, - new IntVerifier, - Optional::Yes, - "Defines the first row that will be read from the specified FITS " - "file(s). If not defined then reading will start at first row.", - }, - { - KeyLastRow, - new IntVerifier, - Optional::Yes, - "Defines the last row that will be read from the specified FITS file(s). " - "If not defined (or less than FirstRow) then full file(s) will be read.", - }, - { - KeyFilterColumnNames, - new StringListVerifier, - Optional::Yes, - "A list of strings with the names of all the additional columns that are " - "to be read from the specified FITS file(s). These columns can be used " - "for filtering while constructing Octree later.", - }, - - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "gaiamission_fitsfiletorawdata"; + return doc; } } // namespace openspace diff --git a/modules/gaia/tasks/readspecktask.cpp b/modules/gaia/tasks/readspecktask.cpp index 8db543c2de..04526a33d9 100644 --- a/modules/gaia/tasks/readspecktask.cpp +++ b/modules/gaia/tasks/readspecktask.cpp @@ -34,23 +34,30 @@ #include namespace { - constexpr const char* KeyInFilePath = "InFilePath"; - constexpr const char* KeyOutFilePath = "OutFilePath"; - constexpr const char* _loggerCat = "ReadSpeckTask"; + + struct [[codegen::Dictionary(ReadSpeckTask)]] Parameters { + // The path to the SPECK file that are to be read + std::string inFilePath; + + // The path to the file to export raw VBO data to + std::string outFilePath; + }; +#include "readspecktask_codegen.cpp" } // namespace namespace openspace { -ReadSpeckTask::ReadSpeckTask(const ghoul::Dictionary& dictionary) { - openspace::documentation::testSpecificationAndThrow( - documentation(), - dictionary, - "ReadSpeckTask" - ); +documentation::Documentation ReadSpeckTask::Documentation() { + documentation::Documentation doc = codegen::doc(); + doc.id = "gaiamission_speckfiletorawdata"; + return doc; +} - _inFilePath = absPath(dictionary.value(KeyInFilePath)); - _outFilePath = absPath(dictionary.value(KeyOutFilePath)); +ReadSpeckTask::ReadSpeckTask(const ghoul::Dictionary& dictionary) { + const Parameters p = codegen::bake(dictionary); + _inFilePath = absPath(p.inFilePath); + _outFilePath = absPath(p.outFilePath); } std::string ReadSpeckTask::description() { @@ -92,26 +99,4 @@ void ReadSpeckTask::perform(const Task::ProgressCallback& onProgress) { onProgress(1.f); } -documentation::Documentation ReadSpeckTask::Documentation() { - using namespace documentation; - return { - "ReadSpeckTask", - "gaiamission_speckfiletorawdata", - { - { - KeyInFilePath, - new StringVerifier, - Optional::No, - "The path to the SPECK file that are to be read.", - }, - { - KeyOutFilePath, - new StringVerifier, - Optional::No, - "The path to the file to export raw VBO data to.", - }, - } - }; -} - } // namespace openspace diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index bdfdd16a6f..6db7ebdfdc 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -453,7 +453,9 @@ std::vector GlobeBrowsingModule::documentations() globebrowsing::Layer::Documentation(), globebrowsing::LayerAdjustment::Documentation(), globebrowsing::LayerManager::Documentation(), - GlobeLabelsComponent::Documentation() + GlobeLabelsComponent::Documentation(), + RingsComponent::Documentation(), + ShadowComponent::Documentation() }; } diff --git a/modules/globebrowsing/scripts/layer_support.lua b/modules/globebrowsing/scripts/layer_support.lua index 9771fd8b3f..e6153e0d84 100644 --- a/modules/globebrowsing/scripts/layer_support.lua +++ b/modules/globebrowsing/scripts/layer_support.lua @@ -118,7 +118,7 @@ end openspace.globebrowsing.createTemporalGibsGdalXml = function (layerName, startDate, endDate, timeResolution, resolution, format, temporalFormat) temporalFormat = temporalFormat or 'YYYY-MM-DD' - temporalTemplate = + local temporalTemplate = "" .. "" .. startDate .. "" .. "" .. endDate .. "" .. @@ -130,7 +130,7 @@ openspace.globebrowsing.createTemporalGibsGdalXml = function (layerName, startDa end openspace.globebrowsing.createGibsGdalXml = function (layerName, date, resolution, format) - tileLevel = 5 + local tileLevel = 5 -- These resolutions are defined by GIBS: https://wiki.earthdata.nasa.gov/display/GIBS/GIBS+API+for+Developers#GIBSAPIforDevelopers-Script-levelAccessviaGDAL if resolution == "2km" then tileLevel = 5 @@ -153,7 +153,7 @@ openspace.globebrowsing.createGibsGdalXml = function (layerName, date, resolutio return "" end - rasterCount = 3 + local rasterCount = 3 if format == "jpg" then if layerName == "ASTER_GDEM_Greyscale_Shaded_Relief" then rasterCount = 1 @@ -167,7 +167,7 @@ openspace.globebrowsing.createGibsGdalXml = function (layerName, date, resolutio return "" end - gdalWmsTemplate = + local gdalWmsTemplate = "" .. "" .. "https://gibs.earthdata.nasa.gov/wmts/epsg4326/best/" .. @@ -198,14 +198,21 @@ openspace.globebrowsing.createGibsGdalXml = function (layerName, date, resolutio end openspace.globebrowsing.parseInfoFile = function (file) - Name = nil - Identifier = nil - Description = nil - ColorFile = nil - HeightFile = nil + -- We are loading these values from an external info file and since we are switching + -- to a strict Lua, we need to predefine these global variables + local function declare(name) + rawset(_G, name, "") + end + + declare("Name") + declare("Identifier") + declare("Description") + declare("ColorFile") + declare("HeightFile") + declare("Location") local dir = openspace.directoryForPath(file) - file_func, error = loadfile(file) + local file_func, error = loadfile(file) if file_func then file_func() else @@ -213,6 +220,15 @@ openspace.globebrowsing.parseInfoFile = function (file) return nil, nil, nil, nil end + -- Hoist the global variables into local space + local Name = rawget(_G, "Name") + local Identifier = rawget(_G, "Identifier") + local Description = rawget(_G, "Description") + local ColorFile = rawget(_G, "ColorFile") + local HeightFile = rawget(_G, "HeightFile") + local Location = rawget(_G, "Location") + + -- Now we can start local name = Name or Identifier local identifier = Identifier or Name @@ -222,7 +238,7 @@ openspace.globebrowsing.parseInfoFile = function (file) end local color = nil - if ColorFile then + if ColorFile and ColorFile ~= "" then color = { Identifier = identifier, Name = name, @@ -233,7 +249,7 @@ openspace.globebrowsing.parseInfoFile = function (file) end local height = nil - if HeightFile then + if HeightFile and HeightFile ~= "" then height = { Identifier = identifier, Name = name, diff --git a/modules/globebrowsing/shaders/renderer_fs.glsl b/modules/globebrowsing/shaders/renderer_fs.glsl index 09d291cc93..07ba765e6c 100644 --- a/modules/globebrowsing/shaders/renderer_fs.glsl +++ b/modules/globebrowsing/shaders/renderer_fs.glsl @@ -156,6 +156,7 @@ in vec3 positionCameraSpace; in vec3 positionWorldSpace; #endif // USE_ECLIPSE_SHADOWS +uniform float opacity; Fragment getFragment() { @@ -296,5 +297,7 @@ Fragment getFragment() { frag.color.xyz *= shadow < 0.99 ? clamp(shadow + 0.3, 0.0, 1.0) : shadow; #endif + frag.color.a *= opacity; + return frag; } diff --git a/modules/globebrowsing/src/dashboarditemglobelocation.cpp b/modules/globebrowsing/src/dashboarditemglobelocation.cpp index 8c53564982..fe51c0fb9f 100644 --- a/modules/globebrowsing/src/dashboarditemglobelocation.cpp +++ b/modules/globebrowsing/src/dashboarditemglobelocation.cpp @@ -62,36 +62,25 @@ namespace { "Determines the number of significant digits that are shown in the location text." }; + struct [[codegen::Dictionary(DashboardItemGlobeLocation)]] Parameters { + // [[codegen::verbatim(FontNameInfo.description)]] + std::optional fontName; + + // [[codegen::verbatim(FontSizeInfo.description)]] + std::optional fontSize; + + // [[codegen::verbatim(SignificantDigitsInfo.description)]] + std::optional significantDigits; + }; +#include "dashboarditemglobelocation_codegen.cpp" } // namespace namespace openspace { documentation::Documentation DashboardItemGlobeLocation::Documentation() { - using namespace documentation; - return { - "DashboardItem Globe Location", - "globebrowsing_dashboarditem_globelocation", - { - { - FontNameInfo.identifier, - new StringVerifier, - Optional::Yes, - FontNameInfo.description - }, - { - FontSizeInfo.identifier, - new IntVerifier, - Optional::Yes, - FontSizeInfo.description - }, - { - SignificantDigitsInfo.identifier, - new IntVerifier, - Optional::Yes, - SignificantDigitsInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "globebrowsing_dashboarditem_globelocation"; + return doc; } DashboardItemGlobeLocation::DashboardItemGlobeLocation( @@ -102,30 +91,15 @@ DashboardItemGlobeLocation::DashboardItemGlobeLocation( , _significantDigits(SignificantDigitsInfo, 4, 1, 12) , _font(global::fontManager->font(KeyFontMono, 10)) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "DashboardItemGlobeLocation" - ); - - if (dictionary.hasKey(FontNameInfo.identifier)) { - _fontName = dictionary.value(FontNameInfo.identifier); - } - if (dictionary.hasKey(FontSizeInfo.identifier)) { - _fontSize = static_cast(dictionary.value(FontSizeInfo.identifier)); - } - if (dictionary.hasKey(SignificantDigitsInfo.identifier)) { - _significantDigits = static_cast( - dictionary.value(SignificantDigitsInfo.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); }); @@ -139,6 +113,7 @@ DashboardItemGlobeLocation::DashboardItemGlobeLocation( _significantDigits.value() ); }; + _significantDigits = p.significantDigits.value_or(_significantDigits); _significantDigits.onChange(updateFormatString); addProperty(_significantDigits); updateFormatString(); diff --git a/modules/globebrowsing/src/globelabelscomponent.cpp b/modules/globebrowsing/src/globelabelscomponent.cpp index 3975dfb0af..185dc0ce6b 100644 --- a/modules/globebrowsing/src/globelabelscomponent.cpp +++ b/modules/globebrowsing/src/globelabelscomponent.cpp @@ -42,14 +42,14 @@ #include #include #include +#include #include #include +#include namespace { constexpr const char* _loggerCat = "GlobeLabels"; - constexpr const char* KeyLabelsFileName = "FileName"; - constexpr const double LabelFadeOutLimitAltitudeMeters = 25000.0; constexpr const double RangeAngularCoefConst = 0.8; constexpr const float MinOpacityValueConst = 0.009f; @@ -163,114 +163,72 @@ namespace { "Label Alignment Option", "Labels are aligned horizontally or circularly related to the planet." }; + + struct [[codegen::Dictionary(GlobeLabelsComponent)]] Parameters { + // The path to the labels file + std::optional fileName; + + // [[codegen::verbatim(LabelsInfo.description)]] + std::optional labels; + + // [[codegen::verbatim(LabelsEnableInfo.description)]] + std::optional enable; + + // [[codegen::verbatim(LabelsFontSizeInfo.description)]] + std::optional labelsFontSize; + + // [[codegen::verbatim(LabelsMinSizeInfo.description)]] + std::optional labelsMinSize; + + // [[codegen::verbatim(LabelsMaxSizeInfo.description)]] + std::optional labelsMaxSize; + + // [[codegen::verbatim(LabelsSizeInfo.description)]] + std::optional labelsSize; + + // [[codegen::verbatim(LabelsMinHeightInfo.description)]] + std::optional labelsMinHeight; + + // [[codegen::verbatim(LabelsColorInfo.description)]] + std::optional labelsColor [[codegen::color()]]; + + // [[codegen::verbatim(LabelsOpacityInfo.description)]] + std::optional labelsOpacity [[codegen::inrange(0.f, 1.0)]]; + + // [[codegen::verbatim(LabelsFadeInStartingDistanceInfo.description)]] + std::optional fadeInStartingDistance; + + // [[codegen::verbatim(LabelsFadeOutStartingDistanceInfo.description)]] + std::optional fadeOutStartingDistance; + + // [[codegen::verbatim(LabelsFadeInEnabledInfo.description)]] + std::optional labelsFadeInEnabled; + + // [[codegen::verbatim(LabelsFadeOutEnabledInfo.description)]] + std::optional labelsFadeOutEnabled; + + // [[codegen::verbatim(LabelsDisableCullingEnabledInfo.description)]] + std::optional labelsDisableCullingEnabled; + + // [[codegen::verbatim(LabelsDistanceEPSInfo.description)]] + std::optional labelsDistanceEPS; + + enum class Alignment { + Horizontally, + Circularly + }; + // [[codegen::verbatim(LabelAlignmentOptionInfo.description)]] + std::optional labelAlignmentOption; + }; +#include "globelabelscomponent_codegen.cpp" } // namespace namespace openspace { documentation::Documentation GlobeLabelsComponent::Documentation() { - using namespace documentation; - return { - "GlobeLabels Component", - "globebrowsing_globelabelscomponent", - { - { - LabelsInfo.identifier, - new BoolVerifier, - Optional::Yes, - LabelsInfo.description - }, - { - LabelsEnableInfo.identifier, - new BoolVerifier, - Optional::Yes, - LabelsEnableInfo.description - }, - { - LabelsFontSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LabelsFontSizeInfo.description - }, - { - LabelsMaxSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LabelsMaxSizeInfo.description - }, - { - LabelsMinSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LabelsMinSizeInfo.description - }, - { - LabelsSizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LabelsSizeInfo.description - }, - { - LabelsMinHeightInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LabelsMinHeightInfo.description - }, - { - LabelsColorInfo.identifier, - new Color3Verifier, - Optional::Yes, - LabelsColorInfo.description - }, - { - LabelsOpacityInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LabelsOpacityInfo.description - }, - { - LabelsFadeInStartingDistanceInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LabelsFadeInStartingDistanceInfo.description - }, - { - LabelsFadeOutStartingDistanceInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LabelsFadeOutStartingDistanceInfo.description - }, - { - LabelsFadeInEnabledInfo.identifier, - new BoolVerifier, - Optional::Yes, - LabelsFadeInEnabledInfo.description - }, - { - LabelsFadeOutEnabledInfo.identifier, - new BoolVerifier, - Optional::Yes, - LabelsFadeOutEnabledInfo.description - }, - { - LabelsDisableCullingEnabledInfo.identifier, - new BoolVerifier, - Optional::Yes, - LabelsDisableCullingEnabledInfo.description - }, - { - LabelsDistanceEPSInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LabelsDistanceEPSInfo.description - }, - { - LabelAlignmentOptionInfo.identifier, - new StringVerifier, - Optional::Yes, - LabelAlignmentOptionInfo.description - }, - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "globebrowsing_globelabelscomponent"; + return doc; } GlobeLabelsComponent::GlobeLabelsComponent() @@ -293,7 +251,7 @@ GlobeLabelsComponent::GlobeLabelsComponent() , _labelsFadeInEnabled(LabelsFadeInEnabledInfo, false) , _labelsFadeOutEnabled(LabelsFadeOutEnabledInfo, false) , _labelsDisableCullingEnabled(LabelsDisableCullingEnabledInfo, false) - , _labelsDistaneEPS(LabelsDistanceEPSInfo, 100000.f, 1000.f, 10000000.f) + , _labelsDistanceEPS(LabelsDistanceEPSInfo, 100000.f, 1000.f, 10000000.f) , _labelAlignmentOption( LabelAlignmentOptionInfo, properties::OptionProperty::DisplayType::Dropdown @@ -312,7 +270,7 @@ GlobeLabelsComponent::GlobeLabelsComponent() addProperty(_labelsFadeInEnabled); addProperty(_labelsFadeOutEnabled); addProperty(_labelsDisableCullingEnabled); - addProperty(_labelsDistaneEPS); + addProperty(_labelsDistanceEPS); _labelAlignmentOption.addOption(Horizontally, "Horizontally"); _labelAlignmentOption.addOption(Circularly, "Circularly"); @@ -324,125 +282,45 @@ void GlobeLabelsComponent::initialize(const ghoul::Dictionary& dictionary, globebrowsing::RenderableGlobe* globe) { ZoneScoped - - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "GlobeLabelsComponent" - ); - _globe = globe; - // Reads labels' file and build cache file if necessary - if (dictionary.isEmpty()) { - return; - } - if (!dictionary.hasValue(KeyLabelsFileName)) { + const Parameters p = codegen::bake(dictionary); + if (!p.fileName.has_value()) { return; } - std::string labelsFile = dictionary.value(KeyLabelsFileName); - bool loadSuccess = loadLabelsData(absPath(labelsFile)); + const bool loadSuccess = loadLabelsData(absPath(p.fileName->string())); if (!loadSuccess) { return; } - if (dictionary.hasKey(LabelsEnableInfo.identifier)) { - // In case of the label's dic is present but is disabled - _labelsEnabled = dictionary.value(LabelsEnableInfo.identifier); - } - else { - // Is the labels dic is enable in the configuration file, - // enables the label automatically. - _labelsEnabled = true; - } - if (dictionary.hasKey(LabelsFontSizeInfo.identifier)) { - _labelsFontSize = static_cast( - dictionary.value(LabelsFontSizeInfo.identifier) - ); - _labelsFontSize.onChange([this]() { initializeFonts(); }); - } + _labelsEnabled = p.enable.value_or(true); + _labelsFontSize = p.labelsFontSize.value_or(_labelsFontSize); + _labelsFontSize.onChange([this]() { initializeFonts(); }); + _labelsSize = p.labelsSize.value_or(_labelsSize); + _labelsMinHeight = p.labelsMinHeight.value_or(_labelsMinHeight); + _labelsColor = p.labelsColor.value_or(_labelsColor); + _labelsOpacity = p.labelsOpacity.value_or(_labelsOpacity); + _labelsFadeInEnabled = p.labelsFadeInEnabled.value_or(_labelsFadeInEnabled); + _labelsFadeInDist = p.fadeInStartingDistance.value_or(_labelsFadeInDist); + _labelsFadeOutEnabled = p.labelsFadeOutEnabled.value_or(_labelsFadeOutEnabled); + _labelsFadeOutDist = p.fadeOutStartingDistance.value_or(_labelsFadeOutDist); + _labelsMinSize = p.labelsMinSize.value_or(_labelsMinSize); + _labelsMaxSize = p.labelsMaxSize.value_or(_labelsMaxSize); + _labelsDisableCullingEnabled = + p.labelsDisableCullingEnabled.value_or(_labelsDisableCullingEnabled); + _labelsDistanceEPS = p.labelsDistanceEPS.value_or(_labelsDistanceEPS); - if (dictionary.hasKey(LabelsSizeInfo.identifier)) { - _labelsSize = static_cast( - dictionary.value(LabelsSizeInfo.identifier) - ); - } - - if (dictionary.hasKey(LabelsMinHeightInfo.identifier)) { - _labelsMinHeight = static_cast( - dictionary.value(LabelsMinHeightInfo.identifier) - ); - } - - if (dictionary.hasKey(LabelsColorInfo.identifier)) { - _labelsColor = dictionary.value(LabelsColorInfo.identifier); - } - - if (dictionary.hasKey(LabelsOpacityInfo.identifier)) { - _labelsOpacity = static_cast( - dictionary.value(LabelsOpacityInfo.identifier) - ); - } - - if (dictionary.hasKey(LabelsFadeInEnabledInfo.identifier)) { - _labelsFadeInEnabled = dictionary.value(LabelsFadeInEnabledInfo.identifier); - } - - if (dictionary.hasKey(LabelsFadeInStartingDistanceInfo.identifier)) { - _labelsFadeInDist = static_cast( - dictionary.value(LabelsFadeInStartingDistanceInfo.identifier) - ); - } - - if (dictionary.hasKey(LabelsFadeOutEnabledInfo.identifier)) { - _labelsFadeOutEnabled = dictionary.value( - LabelsFadeOutEnabledInfo.identifier - ); - } - - if (dictionary.hasKey(LabelsFadeOutStartingDistanceInfo.identifier)) { - _labelsFadeOutDist = static_cast( - dictionary.value(LabelsFadeOutStartingDistanceInfo.identifier) - ); - } - - if (dictionary.hasKey(LabelsMinSizeInfo.identifier)) { - _labelsMinSize = static_cast( - dictionary.value(LabelsMinSizeInfo.identifier) - ); - } - - if (dictionary.hasKey(LabelsMaxSizeInfo.identifier)) { - _labelsMaxSize = static_cast( - dictionary.value(LabelsMaxSizeInfo.identifier) - ); - } - - if (dictionary.hasKey(LabelsDisableCullingEnabledInfo.identifier)) { - bool disabled = dictionary.value( - LabelsDisableCullingEnabledInfo.identifier - ); - _labelsDisableCullingEnabled = disabled; - } - - if (dictionary.hasKey(LabelsDistanceEPSInfo.identifier)) { - _labelsDistaneEPS = static_cast( - dictionary.value(LabelsDistanceEPSInfo.identifier) - ); - } - - if (dictionary.hasKey(LabelAlignmentOptionInfo.identifier)) { - std::string alignment = - dictionary.value(LabelAlignmentOptionInfo.identifier); - if (alignment == "Horizontally") { - _labelAlignmentOption = Horizontally; - } - else if (alignment == "Circularly" ) { - _labelAlignmentOption = Circularly; - } - else { - LERROR("Unknown alignment option: " + alignment); + if (p.labelAlignmentOption.has_value()) { + switch (*p.labelAlignmentOption) { + case Parameters::Alignment::Horizontally: + _labelAlignmentOption = Horizontally; + break; + case Parameters::Alignment::Circularly: + _labelAlignmentOption = Circularly; + break; + default: + throw ghoul::MissingCaseException(); } } @@ -732,7 +610,7 @@ void GlobeLabelsComponent::renderLabels(const RenderData& data, glm::length(locationPositionWorld - data.camera.positionVec3()); if (_labelsDisableCullingEnabled || - ((distToCamera > (distanceCameraToLabelWorld + _labelsDistaneEPS)) && + ((distToCamera > (distanceCameraToLabelWorld + _labelsDistanceEPS)) && isLabelInFrustum(VP, locationPositionWorld))) { if (_labelAlignmentOption == Circularly) { diff --git a/modules/globebrowsing/src/globelabelscomponent.h b/modules/globebrowsing/src/globelabelscomponent.h index 9c7bc4eb6f..ce56c80b0d 100644 --- a/modules/globebrowsing/src/globelabelscomponent.h +++ b/modules/globebrowsing/src/globelabelscomponent.h @@ -96,7 +96,7 @@ private: properties::BoolProperty _labelsFadeInEnabled; properties::BoolProperty _labelsFadeOutEnabled; properties::BoolProperty _labelsDisableCullingEnabled; - properties::FloatProperty _labelsDistaneEPS; + properties::FloatProperty _labelsDistanceEPS; properties::OptionProperty _labelAlignmentOption; private: diff --git a/modules/globebrowsing/src/globetranslation.cpp b/modules/globebrowsing/src/globetranslation.cpp index 633198ba48..6056b81a52 100644 --- a/modules/globebrowsing/src/globetranslation.cpp +++ b/modules/globebrowsing/src/globetranslation.cpp @@ -74,51 +74,33 @@ namespace { "as an offset from the heightmap. Otherwise, it will be an offset from the " "globe's reference ellipsoid. The default value is 'false'." }; + + struct [[codegen::Dictionary(GlobeTranslation)]] Parameters { + // [[codegen::verbatim(GlobeInfo.description)]] + std::string globe + [[codegen::annotation("A valid scene graph node with a RenderableGlobe")]]; + + // [[codegen::verbatim(LongitudeInfo.description)]] + std::optional longitude; + + // [[codegen::verbatim(LatitudeInfo.description)]] + std::optional latitude; + + // [[codegen::verbatim(AltitudeInfo.description)]] + std::optional altitude; + + // [[codegen::verbatim(UseHeightmapInfo.description)]] + std::optional useHeightmap; + }; +#include "globetranslation_codegen.cpp" } // namespace namespace openspace::globebrowsing { documentation::Documentation GlobeTranslation::Documentation() { - using namespace openspace::documentation; - - return { - "Globe Translation", - "space_translation_globetranslation", - { - { - GlobeInfo.identifier, - new StringAnnotationVerifier( - "A valid scene graph node with a RenderableGlobe" - ), - Optional::No, - GlobeInfo.description - }, - { - LongitudeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LongitudeInfo.description - }, - { - LatitudeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LatitudeInfo.description, - }, - { - AltitudeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - AltitudeInfo.description - }, - { - UseHeightmapInfo.identifier, - new BoolVerifier, - Optional::Yes, - UseHeightmapInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "space_translation_globetranslation"; + return doc; } GlobeTranslation::GlobeTranslation(const ghoul::Dictionary& dictionary) @@ -128,39 +110,28 @@ GlobeTranslation::GlobeTranslation(const ghoul::Dictionary& dictionary) , _altitude(AltitudeInfo, 0.0, 0.0, 1e12) , _useHeightmap(UseHeightmapInfo, false) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "GlobeTranslation" - ); - - _globe = dictionary.value(GlobeInfo.identifier); - if (dictionary.hasKey(LongitudeInfo.identifier)) { - _longitude = dictionary.value(LongitudeInfo.identifier); - } - if (dictionary.hasKey(LatitudeInfo.identifier)) { - _latitude = dictionary.value(LatitudeInfo.identifier); - } - if (dictionary.hasKey(AltitudeInfo.identifier)) { - _altitude = dictionary.value(AltitudeInfo.identifier); - } - if (dictionary.hasKey(UseHeightmapInfo.identifier)) { - _useHeightmap = dictionary.value(UseHeightmapInfo.identifier); - } + const Parameters p = codegen::bake(dictionary); + _globe = p.globe; _globe.onChange([this]() { fillAttachedNode(); _positionIsDirty = true; }); + _longitude = p.longitude.value_or(_longitude); _longitude.onChange([this]() { _positionIsDirty = true; }); - _latitude.onChange([this]() { _positionIsDirty = true; }); - _altitude.onChange([this]() { _positionIsDirty = true; }); - _useHeightmap.onChange([this]() { _positionIsDirty = true; }); - addProperty(_longitude); + + _latitude = p.latitude.value_or(_latitude); + _latitude.onChange([this]() { _positionIsDirty = true; }); addProperty(_latitude); + + _altitude = p.altitude.value_or(_altitude); + _altitude.onChange([this]() { _positionIsDirty = true; }); addProperty(_altitude); + + _useHeightmap = p.useHeightmap.value_or(_useHeightmap); + _useHeightmap.onChange([this]() { _positionIsDirty = true; }); addProperty(_useHeightmap); } diff --git a/modules/globebrowsing/src/layer.cpp b/modules/globebrowsing/src/layer.cpp index 7cc2745cb3..43039ef251 100644 --- a/modules/globebrowsing/src/layer.cpp +++ b/modules/globebrowsing/src/layer.cpp @@ -172,7 +172,7 @@ namespace { std::optional blendMode; // If the primary layer creation fails, this layer is used as a fallback - std::optional + std::optional fallback [[codegen::reference("globebrowsing_layer")]]; }; #include "layer_codegen.cpp" diff --git a/modules/globebrowsing/src/layeradjustment.cpp b/modules/globebrowsing/src/layeradjustment.cpp index a572fab6d2..512fdaf88d 100644 --- a/modules/globebrowsing/src/layeradjustment.cpp +++ b/modules/globebrowsing/src/layeradjustment.cpp @@ -26,12 +26,9 @@ #include #include +#include namespace { - constexpr const char* KeyType = "Type"; - constexpr const char* KeyChromaKeyColor = "ChromaKeyColor"; - constexpr const char* KeyChromaKeyTolerance = "ChromaKeyTolerance"; - constexpr openspace::properties::Property::PropertyInfo ChromaKeyColorInfo = { "ChromaKeyColor", "Chroma Key Color", @@ -50,37 +47,32 @@ namespace { "Type", "The type of layer adjustment that is applied to the underlying layer." }; + + struct [[codegen::Dictionary(LayerAdjustment)]] Parameters { + 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 [[codegen::color()]]; + + // Specifies the tolerance to match the color to the chroma key when the + // 'ChromaKey' type is selected for the 'Type' + std::optional chromaKeyTolerance; + }; +#include "layeradjustment_codegen.cpp" } // namespace namespace openspace::globebrowsing { documentation::Documentation LayerAdjustment::Documentation() { - using namespace documentation; - return { - "LayerAdjustment", - "globebrowsing_layeradjustment", - { - { - KeyType, - new StringInListVerifier({ "None", "ChromaKey", "TransferFunction" }), - Optional::Yes, - "Specifies the type of the adjustment that is applied" - }, - { - KeyChromaKeyColor, - new Color3Verifier, - Optional::Yes, - "Specifies the chroma key used when selecting 'ChromaKey' for the 'Type'." - }, - { - KeyChromaKeyTolerance, - new DoubleVerifier, - Optional::Yes, - "Specifies the tolerance to match the color to the chroma key when the " - "'ChromaKey' type is selected for the 'Type'." - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "globebrowsing_layeradjustment"; + return doc; } LayerAdjustment::LayerAdjustment() @@ -121,31 +113,27 @@ LayerAdjustment::LayerAdjustment() } void LayerAdjustment::setValuesFromDictionary(const ghoul::Dictionary& adjustmentDict) { - documentation::testSpecificationAndThrow( - Documentation(), - adjustmentDict, - "LayerAdjustment" - ); + const Parameters p = codegen::bake(adjustmentDict); - if (adjustmentDict.hasValue(KeyType)) { - std::string dictType = adjustmentDict.value(KeyType); - _typeOption = static_cast( - ghoul::from_string(dictType) - ); + if (p.type.has_value()) { + switch (*p.type) { + case Parameters::Type::None: + _typeOption = static_cast(layergroupid::AdjustmentTypeID::None); + break; + case Parameters::Type::ChromaKey: + _typeOption = static_cast(layergroupid::AdjustmentTypeID::ChromaKey); + break; + case Parameters::Type::TransferFunction: + _typeOption = + static_cast(layergroupid::AdjustmentTypeID::TransferFunction); + break; + default: + throw ghoul::MissingCaseException(); + } } - if (adjustmentDict.hasValue(KeyChromaKeyColor)) { - glm::vec3 dictChromaKeyColor = - adjustmentDict.value(KeyChromaKeyColor); - _chromaKeyColor = std::move(dictChromaKeyColor); - } - - if (adjustmentDict.hasValue(KeyChromaKeyTolerance)) { - float dictChromaKeyTolerance = static_cast( - adjustmentDict.value(KeyChromaKeyTolerance) - ); - _chromaKeyTolerance = dictChromaKeyTolerance; - } + _chromaKeyColor = p.chromaKeyColor.value_or(_chromaKeyColor); + _chromaKeyTolerance = p.chromaKeyTolerance.value_or(_chromaKeyTolerance); } layergroupid::AdjustmentTypeID LayerAdjustment::type() const { diff --git a/modules/globebrowsing/src/rawtiledatareader.cpp b/modules/globebrowsing/src/rawtiledatareader.cpp index 1b5005585c..81254ff64d 100644 --- a/modules/globebrowsing/src/rawtiledatareader.cpp +++ b/modules/globebrowsing/src/rawtiledatareader.cpp @@ -949,7 +949,8 @@ TileMetaData RawTileDataReader::tileMetaData(RawTile& rawTile, bool allIsMissing = true; for (int y = 0; y < region.numPixels.y; ++y) { - const size_t yi = (static_cast(region.numPixels.y) - 1 - y) * bytesPerLine; + const size_t yi = + (static_cast(region.numPixels.y) - 1 - y) * bytesPerLine; size_t i = 0; for (int x = 0; x < region.numPixels.x; ++x) { for (size_t raster = 0; raster < _initData.nRasters; ++raster) { diff --git a/modules/globebrowsing/src/renderableglobe.cpp b/modules/globebrowsing/src/renderableglobe.cpp index 85d23a654c..c0813352a8 100644 --- a/modules/globebrowsing/src/renderableglobe.cpp +++ b/modules/globebrowsing/src/renderableglobe.cpp @@ -79,11 +79,6 @@ namespace { bool isShadowing = false; }; - constexpr const char* KeyRadii = "Radii"; - constexpr const char* KeyLayers = "Layers"; - constexpr const char* KeyShadowGroup = "ShadowGroup"; - constexpr const char* KeyLabels = "Labels"; - const openspace::globebrowsing::AABB3 CullingFrustum{ glm::vec3(-1.f, -1.f, 0.f), glm::vec3( 1.f, 1.f, 1e35) @@ -232,6 +227,47 @@ namespace { "This is the number of currently active layers, if this value reaches the " "maximum, bad things will happen." }; + + struct [[codegen::Dictionary(RenderableGlobe)]] Parameters { + // Specifies the radii for this planet. If the Double version of this is used, all + // three radii are assumed to be equal + std::optional> radii; + + // Specifies whether the planet should be shaded by the primary light source or + // not. If it is disabled, all parts of the planet are illuminated + std::optional performShading; + + // A list of all the layers that should be added + std::map layers + [[codegen::reference("globebrowsing_layermanager")]]; + + // Specifies information about planetary labels that can be rendered on the + // object's surface + std::optional labels + [[codegen::reference("globebrowsing_globelabelscomponent")]]; + + struct ShadowGroup { + struct Source { + std::string name; + double radius; + }; + std::vector sources; + + struct Caster { + std::string name; + double radius; + }; + std::vector casters; + }; + std::optional shadowGroup; + + std::optional rings + [[codegen::reference("globebrowsing_rings_component")]]; + + std::optional shadows + [[codegen::reference("globebrowsing_shadows_component")]]; + }; +#include "renderableglobe_codegen.cpp" } // namespace using namespace openspace::properties; @@ -461,48 +497,9 @@ Chunk::Chunk(const TileIndex& ti) {} documentation::Documentation RenderableGlobe::Documentation() { - using namespace documentation; - return { - "RenderableGlobe", - "globebrowsing_renderableglobe", - { - { - KeyRadii, - new OrVerifier({ new DoubleVector3Verifier, new DoubleVerifier }), - Optional::Yes, - "Specifies the radii for this planet. If the Double version of this is " - "used, all three radii are assumed to be equal." - }, - { - "PerformShading", - new BoolVerifier, - Optional::Yes, - "Specifies whether the planet should be shaded by the primary light " - "source or not. If it is disabled, all parts of the planet are " - "illuminated." - }, - { - KeyLayers, - new TableVerifier({ - { - "*", - new ReferencingVerifier("globebrowsing_layermanager"), - Optional::Yes, - "Descriptions of the individual layer groups" - } - }), - Optional::Yes, - "A list of all the layers that should be added" - }, - { - KeyLabels, - new ReferencingVerifier("globebrowsing_globelabelscomponent"), - Optional::Yes, - "Specifies information about planetary labels that can be rendered on " - "the object's surface." - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "globebrowsing_renderableglobe"; + return doc; } RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) @@ -539,75 +536,53 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) , _ringsComponent(dictionary) , _shadowComponent(dictionary) { + const Parameters p = codegen::bake(dictionary); + _generalProperties.currentLodScaleFactor.setReadOnly(true); // Read the radii in to its own dictionary - if (dictionary.hasValue(KeyRadii)) { - _ellipsoid = Ellipsoid(dictionary.value(KeyRadii)); - setBoundingSphere(static_cast(_ellipsoid.maximumRadius())); - } - else if (dictionary.hasValue(KeyRadii)) { - const double radius = dictionary.value(KeyRadii); - _ellipsoid = Ellipsoid({ radius, radius, radius }); - setBoundingSphere(static_cast(_ellipsoid.maximumRadius())); + if (p.radii.has_value()) { + if (std::holds_alternative(*p.radii)) { + _ellipsoid = Ellipsoid(std::get(*p.radii)); + setBoundingSphere(static_cast(_ellipsoid.maximumRadius())); + } + else if (std::holds_alternative(*p.radii)) { + const double radius = std::get(*p.radii); + _ellipsoid = Ellipsoid({ radius, radius, radius }); + setBoundingSphere(static_cast(_ellipsoid.maximumRadius())); + } + else { + throw ghoul::MissingCaseException(); + } } - if (dictionary.hasKey("PerformShading")) { - _generalProperties.performShading = dictionary.value("PerformShading"); - } + _generalProperties.performShading = + p.performShading.value_or(_generalProperties.performShading); + // Init layer manager - ghoul::Dictionary layersDictionary; - if (!dictionary.hasValue(KeyLayers)) { - throw ghoul::RuntimeError(std::string(KeyLayers) + " must be specified"); - } - layersDictionary = dictionary.value(KeyLayers); - + // @TODO (abock, 2021-03-25) The layermanager should be changed to take a + // std::map instead and then we don't need to get it + // as a bare dictionary anymore and can use the value from the struct directly + ghoul::Dictionary layersDictionary = dictionary.value("Layers"); _layerManager.initialize(layersDictionary); + addProperty(_opacity); addProperty(_generalProperties.performShading); addProperty(_generalProperties.useAccurateNormals); - // ================================================================ - // ======== Reads Shadow (Eclipses) Entries in asset file ========= - // ================================================================ - if (dictionary.hasValue(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); - } - + if (p.shadowGroup.has_value()) { std::vector shadowConfArray; - for (const std::pair& source : sourceArray) { - for (const std::pair& caster : casterArray) { + for (const Parameters::ShadowGroup::Source& source : p.shadowGroup->sources) { + for (const Parameters::ShadowGroup::Caster& caster : p.shadowGroup->casters) { Ellipsoid::ShadowConfiguration sc; - sc.source = source; - sc.caster = caster; + sc.source = std::pair(source.name, source.radius); + sc.caster = std::pair(source.name, source.radius); shadowConfArray.push_back(sc); } } _ellipsoid.setShadowConfigurationArray(shadowConfArray); - } - if (!_ellipsoid.shadowConfigurationArray().empty()) { addProperty(_generalProperties.eclipseShadowsEnabled); addProperty(_generalProperties.eclipseHardShadows); } @@ -667,22 +642,20 @@ RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary) _localChunkBuffer.resize(2048); _traversalMemory.resize(512); - // Labels Dictionary - if (dictionary.hasValue(KeyLabels)) { - _labelsDictionary = dictionary.value(KeyLabels); - } + _labelsDictionary = p.labels.value_or(_labelsDictionary); + // Components - if (dictionary.hasValue("Rings")) { + _hasRings = p.rings.has_value(); + if (_hasRings) { _ringsComponent.initialize(); addPropertySubOwner(_ringsComponent); - _hasRings = true; } - if (dictionary.hasKey("Shadows")) { + _hasShadows = p.shadows.has_value(); + if (_hasShadows) { _shadowComponent.initialize(); addPropertySubOwner(_shadowComponent); - _hasShadows = true; _generalProperties.shadowMapping = true; } _generalProperties.shadowMapping.onChange(notifyShaderRecompilation); @@ -999,6 +972,9 @@ void RenderableGlobe::renderChunks(const RenderData& data, RendererTasks&, _globalRenderer.program->setUniform("orenNayarRoughness", onr); } + _localRenderer.program->setUniform("opacity", _opacity); + _globalRenderer.program->setUniform("opacity", _opacity); + if (_globalRenderer.updatedSinceLastCall) { const std::array& layerGroups = @@ -1487,7 +1463,7 @@ void RenderableGlobe::renderChunkLocally(const Chunk& chunk, const RenderData& d program.setUniform("shadowMapTexture", shadowMapUnit); program.setUniform("zFightingPercentage", _generalProperties.zFightingPercentage); - } + } else if (_generalProperties.shadowMapping) { shadowMapUnit.activate(); // JCC: Avoiding a to recompiling the shaders or having more than one diff --git a/modules/globebrowsing/src/ringscomponent.cpp b/modules/globebrowsing/src/ringscomponent.cpp index 418a96461b..6f0855196e 100644 --- a/modules/globebrowsing/src/ringscomponent.cpp +++ b/modules/globebrowsing/src/ringscomponent.cpp @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include @@ -155,90 +156,53 @@ namespace { "The number of samples used during shadow mapping calculation " "(Percentage Closer Filtering)." }; + + struct [[codegen::Dictionary(RingsComponent)]] Parameters { + // [[codegen::verbatim(TextureInfo.description)]] + std::optional texture; + + // [[codegen::verbatim(TextureFwrdInfo.description)]] + std::optional textureFwrd; + + // [[codegen::verbatim(TextureBckwrdInfo.description)]] + std::optional textureBckwrd; + + // [[codegen::verbatim(TextureUnlitInfo.description)]] + std::optional textureUnlit; + + // [[codegen::verbatim(TextureColorInfo.description)]] + std::optional textureColor; + + // [[codegen::verbatim(TextureTransparencyInfo.description)]] + std::optional textureTransparency; + + // [[codegen::verbatim(SizeInfo.description)]] + std::optional size; + + // [[codegen::verbatim(OffsetInfo.description)]] + std::optional offset; + + // [[codegen::verbatim(NightFactorInfo.description)]] + std::optional nightFactor; + + // [[codegen::verbatim(ColorFilterInfo.description)]] + std::optional colorFilter; + + // [[codegen::verbatim(ZFightingPercentageInfo.description)]] + std::optional zFightingPercentage; + + // [[codegen::verbatim(NumberShadowSamplesInfo.description)]] + std::optional numberShadowSamples; + }; +#include "ringscomponent_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RingsComponent::Documentation() { - using namespace documentation; - return { - "Rings Component", - "globebrowsing_rings_component", - { - { - TextureInfo.identifier, - new StringVerifier, - Optional::Yes, - TextureInfo.description - }, - { - TextureFwrdInfo.identifier, - new StringVerifier, - Optional::Yes, - TextureFwrdInfo.description - }, - { - TextureBckwrdInfo.identifier, - new StringVerifier, - Optional::Yes, - TextureBckwrdInfo.description - }, - { - TextureUnlitInfo.identifier, - new StringVerifier, - Optional::Yes, - TextureUnlitInfo.description - }, - { - TextureColorInfo.identifier, - new StringVerifier, - Optional::Yes, - TextureColorInfo.description - }, - { - TextureTransparencyInfo.identifier, - new StringVerifier, - Optional::Yes, - TextureTransparencyInfo.description - }, - { - SizeInfo.identifier, - new DoubleVerifier, - Optional::Yes, - 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 - }, - { - ZFightingPercentageInfo.identifier, - new DoubleVerifier, - Optional::Yes, - ZFightingPercentageInfo.description - }, - { - NumberShadowSamplesInfo.identifier, - new IntVerifier, - Optional::Yes, - NumberShadowSamplesInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "globebrowsing_rings_component"; + return doc; } RingsComponent::RingsComponent(const ghoul::Dictionary& dictionary) @@ -265,14 +229,17 @@ RingsComponent::RingsComponent(const ghoul::Dictionary& dictionary) // term and rather extract the values directly here. This would require a bit of // a rewrite in the RenderableGlobe class to not create the RingsComponent in the // class-initializer list though + // @TODO (abock, 2021-03-25) Righto! The RenderableGlobe passes this dictionary + // in as-is so it would be easy to just pass it directly to the initialize method + // instead _ringsDictionary = dictionary.value("Rings"); - } - documentation::testSpecificationAndThrow( - Documentation(), - _ringsDictionary, - "RingsComponent" - ); + documentation::testSpecificationAndThrow( + Documentation(), + _ringsDictionary, + "RingsComponent" + ); + } } void RingsComponent::initialize() { @@ -280,106 +247,78 @@ void RingsComponent::initialize() { using ghoul::filesystem::File; + const Parameters p = codegen::bake(_ringsDictionary); + addProperty(_enabled); - _size = static_cast(_ringsDictionary.value(SizeInfo.identifier)); - //setBoundingSphere(_size); + _size = p.size.value_or(_size); _size.onChange([&]() { _planeIsDirty = true; }); addProperty(_size); - if (_ringsDictionary.hasKey(TextureInfo.identifier)) { - _texturePath = absPath( - _ringsDictionary.value(TextureInfo.identifier) - ); + if (p.texture.has_value()) { + _texturePath = absPath(p.texture->string()); _textureFile = std::make_unique(_texturePath); _texturePath.onChange([&]() { loadTexture(); }); addProperty(_texturePath); _textureFile->setCallback([&](const File&) { _textureIsDirty = true; }); } - if (_ringsDictionary.hasKey(TextureFwrdInfo.identifier)) { - _textureFwrdPath = absPath( - _ringsDictionary.value(TextureFwrdInfo.identifier) - ); + if (p.textureFwrd.has_value()) { + _textureFwrdPath = absPath(p.textureFwrd->string()); _textureFileForwards = std::make_unique(_textureFwrdPath); _textureFwrdPath.onChange([&]() { loadTexture(); }); addProperty(_textureFwrdPath); _textureFileForwards->setCallback([&](const File&) { _textureIsDirty = true; }); } - - if (_ringsDictionary.hasKey(TextureBckwrdInfo.identifier)) { - _textureBckwrdPath = absPath( - _ringsDictionary.value(TextureBckwrdInfo.identifier) - ); + + if (p.textureBckwrd.has_value()) { + _textureBckwrdPath = absPath(p.textureBckwrd->string()); _textureFileBackwards = std::make_unique(_textureBckwrdPath); _textureBckwrdPath.onChange([&]() { loadTexture(); }); addProperty(_textureBckwrdPath); _textureFileBackwards->setCallback([&](const File&) { _textureIsDirty = true; }); } - if (_ringsDictionary.hasKey(TextureUnlitInfo.identifier)) { - _textureUnlitPath = absPath( - _ringsDictionary.value(TextureUnlitInfo.identifier) - ); + if (p.textureUnlit.has_value()) { + _textureUnlitPath = absPath(p.textureUnlit->string()); _textureFileUnlit = std::make_unique(_textureUnlitPath); _textureUnlitPath.onChange([&]() { loadTexture(); }); addProperty(_textureUnlitPath); _textureFileUnlit->setCallback([&](const File&) { _textureIsDirty = true; }); } - if (_ringsDictionary.hasKey(TextureColorInfo.identifier)) { - _textureColorPath = absPath( - _ringsDictionary.value(TextureColorInfo.identifier) - ); + if (p.textureColor.has_value()) { + _textureColorPath = absPath(p.textureColor->string()); _textureFileColor = std::make_unique(_textureColorPath); _textureColorPath.onChange([&]() { loadTexture(); }); addProperty(_textureColorPath); _textureFileColor->setCallback([&](const File&) { _textureIsDirty = true; }); } - if (_ringsDictionary.hasKey(TextureTransparencyInfo.identifier)) { - _textureTransparencyPath = absPath( - _ringsDictionary.value(TextureTransparencyInfo.identifier) - ); + if (p.textureTransparency.has_value()) { + _textureTransparencyPath = absPath(p.textureTransparency->string()); _textureFileTransparency = std::make_unique(_textureTransparencyPath); _textureTransparencyPath.onChange([&]() { loadTexture(); }); addProperty(_textureTransparencyPath); _textureFileTransparency->setCallback([&](const File&) { _textureIsDirty = true; }); } - if (_ringsDictionary.hasValue(OffsetInfo.identifier)) { - _offset = _ringsDictionary.value(OffsetInfo.identifier); - } + _offset = p.offset.value_or(_offset); addProperty(_offset); - if (_ringsDictionary.hasValue(NightFactorInfo.identifier)) { - _nightFactor = static_cast( - _ringsDictionary.value(NightFactorInfo.identifier) - ); - } + _nightFactor = p.nightFactor.value_or(_nightFactor); addProperty(_nightFactor); - if (_ringsDictionary.hasValue(ColorFilterInfo.identifier)) { - _colorFilter = static_cast( - _ringsDictionary.value(ColorFilterInfo.identifier) - ); - } + _colorFilter = p.colorFilter.value_or(_colorFilter); + addProperty(_colorFilter); // Shadow Mapping Quality Controls - if (_ringsDictionary.hasKey(ZFightingPercentageInfo.identifier)) { - _zFightingPercentage = static_cast( - _ringsDictionary.value(ZFightingPercentageInfo.identifier) - ); - } + _zFightingPercentage = p.zFightingPercentage.value_or(_zFightingPercentage); addProperty(_zFightingPercentage); - if (_ringsDictionary.hasKey(NumberShadowSamplesInfo.identifier)) { - _nShadowSamples = _ringsDictionary.value(NumberShadowSamplesInfo.identifier); - } + _nShadowSamples = p.numberShadowSamples.value_or(_nShadowSamples); _nShadowSamples.onChange([this]() { compileShadowShader(); }); addProperty(_nShadowSamples); - - addProperty(_colorFilter); } bool RingsComponent::isReady() const { @@ -476,7 +415,7 @@ void RingsComponent::draw(const RenderData& data, _shader->setUniform(_uniformCacheAdvancedRings.colorFilterValue, _colorFilter); _shader->setUniform(_uniformCacheAdvancedRings.nightFactor, _nightFactor); _shader->setUniform(_uniformCacheAdvancedRings.sunPosition, _sunPosition); - + const glm::dmat4 inverseModelTransform = glm::inverse(modelTransform); glm::vec3 sunPositionObjectSpace = glm::normalize( @@ -614,7 +553,7 @@ void RingsComponent::draw(const RenderData& data, else { _texture->bind(); } - + _geometryOnlyShader->setUniform(_geomUniformCache.ringTexture, ringTextureUnit); } @@ -673,7 +612,7 @@ void RingsComponent::loadTexture() { using namespace ghoul::opengl; if (!_texturePath.value().empty()) { - + std::unique_ptr texture = TextureReader::ref().loadTexture( absPath(_texturePath) ); diff --git a/modules/globebrowsing/src/ringscomponent.h b/modules/globebrowsing/src/ringscomponent.h index 661096d3b7..a11ef59b18 100644 --- a/modules/globebrowsing/src/ringscomponent.h +++ b/modules/globebrowsing/src/ringscomponent.h @@ -98,7 +98,7 @@ private: ) _uniformCache; UniformCache(modelViewProjectionMatrix, textureOffset, colorFilterValue, nightFactor, sunPosition, sunPositionObj, camPositionObj, ringTextureFwrd, ringTextureBckwrd, - ringTextureUnlit, ringTextureColor, ringTextureTransparency, shadowMatrix, + ringTextureUnlit, ringTextureColor, ringTextureTransparency, shadowMatrix, shadowMapTexture, zFightingPercentage ) _uniformCacheAdvancedRings; UniformCache(modelViewProjectionMatrix, textureOffset, ringTexture diff --git a/modules/globebrowsing/src/shadowcomponent.cpp b/modules/globebrowsing/src/shadowcomponent.cpp index ab237291c4..55a5285480 100644 --- a/modules/globebrowsing/src/shadowcomponent.cpp +++ b/modules/globebrowsing/src/shadowcomponent.cpp @@ -141,30 +141,23 @@ namespace { } } } + + struct [[codegen::Dictionary(ShadowComponent)]] Parameters { + // [[codegen::verbatim(DistanceFractionInfo.description)]] + std::optional distanceFraction; + + // [[codegen::verbatim(DepthMapSizeInfo.description)]] + std::optional depthMapSize; + }; +#include "shadowcomponent_codegen.cpp" } // namespace namespace openspace { documentation::Documentation ShadowComponent::Documentation() { - using namespace documentation; - return { - "ShadowsRing Component", - "globebrowsing_shadows_component", - { - { - DistanceFractionInfo.identifier, - new DoubleVerifier, - Optional::Yes, - DistanceFractionInfo.description - }, - { - DepthMapSizeInfo.identifier, - new Vector2ListVerifier, - Optional::Yes, - DepthMapSizeInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "globebrowsing_shadows_component"; + return doc; } ShadowComponent::ShadowComponent(const ghoul::Dictionary& dictionary) @@ -172,37 +165,30 @@ ShadowComponent::ShadowComponent(const ghoul::Dictionary& dictionary) , _saveDepthTexture(SaveDepthTextureInfo) , _distanceFraction(DistanceFractionInfo, 20, 1, 10000) , _enabled({ "Enabled", "Enabled", "Enable/Disable Shadows" }, true) - , _shadowMapDictionary(dictionary) { using ghoul::filesystem::File; - if (dictionary.hasValue("Shadows")) { - // @TODO (abock, 2019-12-16) It would be better to not store the dictionary long - // term and rather extract the values directly here. This would require a bit of - // a rewrite in the RenderableGlobe class to not create the ShadowComponent in the - // class-initializer list though - _shadowMapDictionary = dictionary.value("Shadows"); + // @TODO (abock, 2021-03-25) This is not really a nice solution as this key name is + // coded into the RenderableGlobe. Instead, the parent should unpack the dictionary + // and pass the unpacked dictionary in here; Or maybe we don't want a dictionary at + // this state anyway? + if (!dictionary.hasValue("Shadows")) { + return; } + ghoul::Dictionary d = dictionary.value("Shadows"); + + const Parameters p = codegen::bake(d); - documentation::testSpecificationAndThrow( - Documentation(), - _shadowMapDictionary, - "ShadowComponent" - ); + addProperty(_enabled); + + _distanceFraction = p.distanceFraction.value_or(_distanceFraction); + addProperty(_distanceFraction); - if (_shadowMapDictionary.hasKey(DistanceFractionInfo.identifier)) { - _distanceFraction = static_cast( - _shadowMapDictionary.value(DistanceFractionInfo.identifier) - ); - } _saveDepthTexture.onChange([&]() { _executeDepthTextureSave = true; }); - - if (_shadowMapDictionary.hasKey(DepthMapSizeInfo.identifier)) { - glm::dvec2 depthMapSize = - _shadowMapDictionary.value(DepthMapSizeInfo.identifier); - _shadowDepthTextureWidth = static_cast(depthMapSize.x); - _shadowDepthTextureHeight = static_cast(depthMapSize.y); + if (p.depthMapSize.has_value()) { + _shadowDepthTextureWidth = p.depthMapSize->x; + _shadowDepthTextureHeight = p.depthMapSize->y; _dynamicDepthTextureRes = false; } else { @@ -212,13 +198,7 @@ ShadowComponent::ShadowComponent(const ghoul::Dictionary& dictionary) _dynamicDepthTextureRes = true; } - _saveDepthTexture.onChange([&]() { _executeDepthTextureSave = true; }); - - _viewDepthMap = false; - - addProperty(_enabled); addProperty(_saveDepthTexture); - addProperty(_distanceFraction); } void ShadowComponent::initialize() { @@ -323,7 +303,7 @@ RenderData ShadowComponent::begin(const RenderData& data) { // Saves current state glGetIntegerv(GL_FRAMEBUFFER_BINDING, &_currentFBO); global::renderEngine->openglStateCache().viewport(_mViewport); - + glBindFramebuffer(GL_FRAMEBUFFER, _shadowFBO); GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0, GL_NONE, GL_NONE }; glDrawBuffers(3, drawBuffers); diff --git a/modules/globebrowsing/src/shadowcomponent.h b/modules/globebrowsing/src/shadowcomponent.h index 30aabbe057..dddea2fb66 100644 --- a/modules/globebrowsing/src/shadowcomponent.h +++ b/modules/globebrowsing/src/shadowcomponent.h @@ -105,8 +105,6 @@ private: properties::IntProperty _distanceFraction; properties::BoolProperty _enabled; - ghoul::Dictionary _shadowMapDictionary; - int _shadowDepthTextureHeight = 4096; int _shadowDepthTextureWidth = 4096; bool _dynamicDepthTextureRes = true; @@ -125,14 +123,6 @@ private: GLboolean _depthIsEnabled; GLboolean _blendIsEnabled = false; - GLenum _faceToCull; - GLenum _depthFunction; - - GLfloat _polygonOffSetFactor; - GLfloat _polygonOffSetUnits; - GLfloat _colorClearValue[4]; - GLfloat _depthClearValue; - glm::vec3 _sunPosition = glm::vec3(0.f); glm::dmat4 _shadowMatrix = glm::dmat4(1.0); diff --git a/modules/globebrowsing/src/tileprovider.cpp b/modules/globebrowsing/src/tileprovider.cpp index 379857325d..ddf1200ed9 100644 --- a/modules/globebrowsing/src/tileprovider.cpp +++ b/modules/globebrowsing/src/tileprovider.cpp @@ -657,6 +657,10 @@ SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& di if (dictionary.hasValue(sizereferenceprovider::KeyRadii)) { ellipsoid = dictionary.value(sizereferenceprovider::KeyRadii); } + else if (dictionary.hasValue(sizereferenceprovider::KeyRadii)) { + const double r = dictionary.value(sizereferenceprovider::KeyRadii); + ellipsoid = glm::dvec3(r, r, r); + } } diff --git a/modules/iswa/rendering/iswacygnet.cpp b/modules/iswa/rendering/iswacygnet.cpp index 267f00ac53..944e309d26 100644 --- a/modules/iswa/rendering/iswacygnet.cpp +++ b/modules/iswa/rendering/iswacygnet.cpp @@ -184,7 +184,8 @@ void IswaCygnet::render(const RenderData& data, RendererTasks&) { _data.spatialScale.x * _data.offset, _data.spatialScale.w ); - glm::vec3 position = glm::vec3(pposition) * static_cast(pow(10.f, pposition.w)); + glm::vec3 position = + glm::vec3(pposition) * static_cast(pow(10.f, pposition.w)); // Activate shader _shader->activate(); 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/space/rendering/renderablehabitablezone.h b/modules/space/rendering/renderablehabitablezone.h index 6aa5d7f31b..75c921ee1a 100644 --- a/modules/space/rendering/renderablehabitablezone.h +++ b/modules/space/rendering/renderablehabitablezone.h @@ -22,8 +22,8 @@ * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ****************************************************************************************/ -#ifndef __OPENSPACE_MODULE_EXOPLANETS___RENDERABLEHABITABLEZONE___H__ -#define __OPENSPACE_MODULE_EXOPLANETS___RENDERABLEHABITABLEZONE___H__ +#ifndef __OPENSPACE_MODULE_SPACE___RENDERABLEHABITABLEZONE___H__ +#define __OPENSPACE_MODULE_SPACE___RENDERABLEHABITABLEZONE___H__ #include #include @@ -72,4 +72,4 @@ private: } // namespace openspace -#endif // __OPENSPACE_MODULE_EXOPLANETS___RENDERABLEHABITABLEZONE___H__ +#endif // __OPENSPACE_MODULE_SPACE___RENDERABLEHABITABLEZONE___H__ diff --git a/modules/space/rendering/renderablesatellites.cpp b/modules/space/rendering/renderablesatellites.cpp index 64d0f887d7..f808be2147 100644 --- a/modules/space/rendering/renderablesatellites.cpp +++ b/modules/space/rendering/renderablesatellites.cpp @@ -90,13 +90,13 @@ RenderableSatellites::RenderableSatellites(const ghoul::Dictionary& dictionary) _updateStartRenderIdxSelect = [this]() { if ((_numObjects - _startRenderIdx) < _sizeRender) { - _sizeRender = _numObjects - _startRenderIdx; + _sizeRender = static_cast(_numObjects - _startRenderIdx); } updateBuffers(); }; _updateRenderSizeSelect = [this]() { if (_sizeRender > (_numObjects - _startRenderIdx)) { - _startRenderIdx = _numObjects - _sizeRender; + _startRenderIdx = static_cast(_numObjects - _sizeRender); } updateBuffers(); }; diff --git a/modules/space/rendering/renderablesmallbody.cpp b/modules/space/rendering/renderablesmallbody.cpp index 0a0259eb98..72414c3453 100644 --- a/modules/space/rendering/renderablesmallbody.cpp +++ b/modules/space/rendering/renderablesmallbody.cpp @@ -113,8 +113,8 @@ documentation::Documentation RenderableSmallBody::Documentation() { RenderableSmallBody::RenderableSmallBody(const ghoul::Dictionary& dictionary) : RenderableOrbitalKepler(dictionary) - , _upperLimit(UpperLimitInfo, 1000, 1, 1000000) , _contiguousMode(ContiguousModeInfo, false) + , _upperLimit(UpperLimitInfo, 1000, 1, 1000000) { codegen::bake(dictionary); @@ -142,7 +142,7 @@ RenderableSmallBody::RenderableSmallBody(const ghoul::Dictionary& dictionary) _updateStartRenderIdxSelect = std::function([this] { if (_contiguousMode) { if ((_numObjects - _startRenderIdx) < _sizeRender) { - _sizeRender = _numObjects - _startRenderIdx; + _sizeRender = static_cast(_numObjects - _startRenderIdx); } _updateDataBuffersAtNextRender = true; } @@ -150,7 +150,7 @@ RenderableSmallBody::RenderableSmallBody(const ghoul::Dictionary& dictionary) _updateRenderSizeSelect = std::function([this] { if (_contiguousMode) { if (_sizeRender > (_numObjects - _startRenderIdx)) { - _startRenderIdx = _numObjects - _sizeRender; + _startRenderIdx = static_cast(_numObjects - _sizeRender); } _updateDataBuffersAtNextRender = true; } @@ -221,7 +221,7 @@ void RenderableSmallBody::readDataFile(const std::string& filename) { else { lineSkipFraction = static_cast(_upperLimit) / static_cast(_numObjects); - endElement = _numObjects - 1; + endElement = static_cast(_numObjects - 1); } if (line.compare(expectedHeaderLine) != 0) { diff --git a/modules/space/rendering/renderablesmallbody.h b/modules/space/rendering/renderablesmallbody.h index 1be028b539..b55c114d65 100644 --- a/modules/space/rendering/renderablesmallbody.h +++ b/modules/space/rendering/renderablesmallbody.h @@ -59,7 +59,6 @@ private: /// The index array that is potentially used in the draw call. If this is empty, no /// element draw call is used. std::vector _indexBufferData; - bool contiguousMode = true; properties::BoolProperty _contiguousMode; properties::UIntProperty _upperLimit; properties::Property::OnChangeHandle _contiguousModeCallbackhandle; diff --git a/modules/space/rendering/renderablestars.cpp b/modules/space/rendering/renderablestars.cpp index a1b1879f14..1ce1c04748 100644 --- a/modules/space/rendering/renderablestars.cpp +++ b/modules/space/rendering/renderablestars.cpp @@ -307,7 +307,8 @@ namespace { }; struct [[codegen::Dictionary(RenderableStars)]] Parameters { - // The path to the SPECK file containing information about the stars being rendered + // The path to the SPECK file containing information about the stars being + // rendered std::filesystem::path speckFile [[codegen::key("File")]]; // [[codegen::verbatim(ColorTextureInfo.description)]] @@ -336,8 +337,8 @@ namespace { // 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 + // 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)]] @@ -770,8 +771,8 @@ void RenderableStars::loadPSFTexture() { void RenderableStars::renderPSFToTexture() { // Saves current FBO first - GLint defaultFBO; - defaultFBO = global::renderEngine->openglStateCache().defaultFramebuffer(); + // GLint defaultFBO; + // defaultFBO = global::renderEngine->openglStateCache().defaultFramebuffer(); // GLint m_viewport[4]; // global::renderEngine.openglStateCache().viewPort(m_viewport); diff --git a/modules/space/rotation/spicerotation.cpp b/modules/space/rotation/spicerotation.cpp index 02b1b025c0..927c1c7ceb 100644 --- a/modules/space/rotation/spicerotation.cpp +++ b/modules/space/rotation/spicerotation.cpp @@ -64,7 +64,8 @@ namespace { std::optional, std::string>> kernels; // [[codegen::verbatim(TimeFrameInfo.description)]] - std::optional timeFrame [[codegen::reference("core_time_frame")]]; + std::optional timeFrame + [[codegen::reference("core_time_frame")]]; }; #include "spicerotation_codegen.cpp" } // namespace diff --git a/modules/spacecraftinstruments/rendering/renderablecrawlingline.cpp b/modules/spacecraftinstruments/rendering/renderablecrawlingline.cpp index 363969ed1c..1ed8bfcddd 100644 --- a/modules/spacecraftinstruments/rendering/renderablecrawlingline.cpp +++ b/modules/spacecraftinstruments/rendering/renderablecrawlingline.cpp @@ -34,19 +34,38 @@ #include #include #include +#include namespace { - constexpr const char* KeySource = "Source"; - constexpr const char* KeyTarget = "Target"; - constexpr const char* KeyInstrument = "Instrument"; - constexpr const char* KeyColor = "Color"; - constexpr const char* KeyColorStart = "Start"; - constexpr const char* KeyColorEnd = "End"; - struct VBOData { float position[3]; float color[4]; }; + + struct [[codegen::Dictionary(RenderableCrawlingLine)]] Parameters { + // Denotes the SPICE name of the source of the renderable crawling line, for + // example, the spacecraft + std::string source; + + // Denotes the SPICE name of the target of the crawling line + std::string target; + + // Denotes the SPICE name of the instrument that is used to render the crawling + // line + std::string instrument; + + struct Color { + // The color at the start of the line + glm::vec4 start [[codegen::color()]]; + + // The color at the end of the line + glm::vec4 end [[codegen::color()]]; + }; + // Specifies the colors that are used for the crawling line. One value determines + // the starting color of the line, the second value is the color at the end + Color color; + }; +#include "renderablecrawlingline_codegen.cpp" } // namespace // @TODO: This class is not properly working anymore and needs to be substantially @@ -56,76 +75,21 @@ namespace { namespace openspace { documentation::Documentation RenderableCrawlingLine::Documentation() { - using namespace documentation; - return { - "RenderableCrawlingLine", - "newhorizons_renderable_crawlingline", - { - { - KeySource, - new StringVerifier, - Optional::No, - "Denotes the SPICE name of the source of the renderable crawling line, " - "for example, the space craft" - }, - { - KeyTarget, - new StringVerifier, - Optional::Yes, - "Denotes the SPICE name of the target of the crawling line" - }, - { - KeyInstrument, - new StringVerifier, - Optional::No, - "Denotes the SPICE name of the instrument that is used to render the " - "crawling line" - }, - { - KeyColor, - new TableVerifier({ - { - KeyColorStart, - new Color4Verifier, - Optional::No, - "The color at the start of the line", - }, - { - KeyColorEnd, - new Color4Verifier, - Optional::No, - "The color at the end of the line" - } - }), - Optional::No, - "Specifies the colors that are used for the crawling line. One value " - "determines the starting color of the line, the second value is the " - "color at the end of the line." - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "newhorizons_renderable_crawlingline"; + return doc; } RenderableCrawlingLine::RenderableCrawlingLine(const ghoul::Dictionary& dictionary) : Renderable(dictionary) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableCrawlingLine" - ); + const Parameters p = codegen::bake(dictionary); - _source = dictionary.value(KeySource); - _target = dictionary.value(KeyTarget); - _instrumentName = dictionary.value(KeyInstrument); - - _lineColorBegin = dictionary.value( - std::string(KeyColor) + "." + KeyColorStart - ); - - _lineColorEnd = dictionary.value( - std::string(KeyColor) + "." + KeyColorEnd - ); + _source = p.source; + _target = p.target; + _instrumentName = p.instrument; + _lineColorBegin = p.color.start; + _lineColorEnd = p.color.end; } bool RenderableCrawlingLine::isReady() const { diff --git a/modules/spacecraftinstruments/rendering/renderablefov.cpp b/modules/spacecraftinstruments/rendering/renderablefov.cpp index 25111acf83..30e0753aa5 100644 --- a/modules/spacecraftinstruments/rendering/renderablefov.cpp +++ b/modules/spacecraftinstruments/rendering/renderablefov.cpp @@ -35,17 +35,10 @@ #include #include #include +#include namespace { constexpr const char* ProgramName = "FovProgram"; - constexpr const char* KeyBody = "Body"; - constexpr const char* KeyFrame = "Frame"; - constexpr const char* KeyInstrument = "Instrument"; - constexpr const char* KeyInstrumentName = "Name"; - constexpr const char* KeyInstrumentAberration = "Aberration"; - constexpr const char* KeyPotentialTargets = "PotentialTargets"; - constexpr const char* KeyFrameConversions = "FrameConversions"; - constexpr const char* KeyBoundsSimplification = "SimplifyBounds"; constexpr const std::array UniformNames = { "modelViewProjectionTransform", "defaultColorStart", "defaultColorEnd", @@ -153,142 +146,55 @@ namespace { } } // 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" + 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 { documentation::Documentation RenderableFov::Documentation() { - using namespace documentation; - return { - "RenderableFieldOfView", - "newhorizons_renderable_fieldofview", - { - { - KeyBody, - new StringVerifier, - Optional::No, - "The SPICE name of the source body for which the field of view should be " - "rendered." - }, - { - KeyFrame, - new StringVerifier, - Optional::No, - "The SPICE name of the source body's frame in which the field of view " - "should be rendered." - }, - { - KeyInstrument, - new TableVerifier({ - { - KeyInstrumentName, - new StringVerifier, - Optional::No, - "The SPICE name of the instrument that is rendered" - }, - { - KeyInstrumentAberration, - new StringInListVerifier({ - // Taken from SpiceManager::AberrationCorrection - "NONE", - "LT", "LT+S", - "CN", "CN+S", - "XLT", "XLT+S", - "XCN", "XCN+S" - }), - Optional::Yes, - "The aberration correction that is used for this field of view. " - "The default is 'NONE'." - } - }), - Optional::No, - "A table describing the instrument whose field of view should be " - "rendered." - }, - { - KeyPotentialTargets, - new StringListVerifier, - Optional::No, - "A list of potential targets (specified as SPICE names) that the field " - "of view should be tested against." - }, - { - KeyFrameConversions, - new TableVerifier({ - { - DocumentationEntry::Wildcard, - new StringVerifier, - Optional::No - } - }), - Optional::Yes, - "A list of frame conversions that should be registered with the " - "SpiceManager." - }, - { - LineWidthInfo.identifier, - new DoubleVerifier, - Optional::Yes, - LineWidthInfo.description - }, - { - StandoffDistanceInfo.identifier, - new DoubleVerifier, - Optional::Yes, - StandoffDistanceInfo.description - }, - { - KeyBoundsSimplification, - new BoolVerifier, - Optional::Yes, - "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." - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "newhorizons_renderable_fieldofview"; + return doc; } @@ -342,61 +248,37 @@ RenderableFov::RenderableFov(const ghoul::Dictionary& dictionary) } }) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableFov" - ); + const Parameters p = codegen::bake(dictionary); - _instrument.spacecraft = dictionary.value(KeyBody); - _instrument.referenceFrame = dictionary.value(KeyFrame); - - _instrument.name = dictionary.value( - std::string(KeyInstrument) + "." + KeyInstrumentName - ); - - std::string ia = std::string(KeyInstrument) + "." + KeyInstrumentAberration; - if (dictionary.hasValue(ia)) { - const std::string& ac = dictionary.value(ia); - _instrument.aberrationCorrection = SpiceManager::AberrationCorrection(ac); + _instrument.spacecraft = p.body; + _instrument.referenceFrame = p.frame; + _instrument.name = p.instrument.name; + if (p.instrument.aberration.has_value()) { + _instrument.aberrationCorrection = SpiceManager::AberrationCorrection( + *p.instrument.aberration + ); } - ghoul::Dictionary pt = dictionary.value(KeyPotentialTargets); - _instrument.potentialTargets.reserve(pt.size()); - for (size_t i = 1; i <= pt.size(); ++i) { - std::string target = pt.value(std::to_string(i)); - _instrument.potentialTargets.push_back(std::move(target)); - } + _instrument.potentialTargets = p.potentialTargets; - if (dictionary.hasKey(KeyFrameConversions)) { - ghoul::Dictionary fc = dictionary.value(KeyFrameConversions); - for (std::string_view key : fc.keys()) { + if (p.frameConversions.has_value()) { + for (const std::pair& fc : *p.frameConversions) { global::moduleEngine->module()->addFrame( - std::string(key), - fc.value(key) + fc.first, + fc.second ); } } - if (dictionary.hasKey(LineWidthInfo.identifier)) { - _lineWidth = static_cast(dictionary.value( - LineWidthInfo.identifier - )); - } - - if (dictionary.hasKey(StandoffDistanceInfo.identifier)) { - _standOffDistance = static_cast(dictionary.value( - StandoffDistanceInfo.identifier - )); - } - - if (dictionary.hasKey(KeyBoundsSimplification)) { - _simplifyBounds = dictionary.value(KeyBoundsSimplification); - } - + _lineWidth = p.lineWidth.value_or(_lineWidth); addProperty(_lineWidth); - addProperty(_drawSolid); + + _standOffDistance = p.standOffDistance.value_or(_standOffDistance); addProperty(_standOffDistance); + + _simplifyBounds = p.simplifyBounds.value_or(_simplifyBounds); + + addProperty(_drawSolid); addProperty(_colors.defaultStart); addProperty(_colors.defaultEnd); diff --git a/modules/spacecraftinstruments/rendering/renderableplaneprojection.cpp b/modules/spacecraftinstruments/rendering/renderableplaneprojection.cpp index a165d84c5d..be21ff31a0 100644 --- a/modules/spacecraftinstruments/rendering/renderableplaneprojection.cpp +++ b/modules/spacecraftinstruments/rendering/renderableplaneprojection.cpp @@ -45,12 +45,6 @@ namespace { constexpr const char* _loggerCat = "RenderablePlaneProjection"; - constexpr const char* KeySpacecraft = "Spacecraft"; - constexpr const char* KeyInstrument = "Instrument"; - constexpr const char* KeyMoving = "Moving"; - constexpr const char* KeyTexture = "Texture"; - constexpr const char* KeyName = "Name"; - constexpr const char* KeyTarget = "DefaultTarget"; constexpr const char* GalacticFrame = "GALACTIC"; struct [[codegen::Dictionary(RenderablePlaneProjection)]] Parameters { @@ -279,7 +273,6 @@ void RenderablePlaneProjection::updatePlane(const Image& img, double currentTime glm::vec3(projection[1]), glm::vec3(projection[2]), glm::vec3(projection[3]) - }; const GLfloat vertex_data[] = { // square of two triangles drawn within fov in target coordinates diff --git a/modules/spacecraftinstruments/rendering/renderableplanetprojection.cpp b/modules/spacecraftinstruments/rendering/renderableplanetprojection.cpp index 4c2f2479ee..147ce0c659 100644 --- a/modules/spacecraftinstruments/rendering/renderableplanetprojection.cpp +++ b/modules/spacecraftinstruments/rendering/renderableplanetprojection.cpp @@ -39,6 +39,7 @@ #include #include #include +#include namespace { constexpr const char* _loggerCat = "RenderablePlanetProjection"; @@ -56,8 +57,6 @@ namespace { "boresight", "_radius", "_segments" }; - constexpr const char* KeyGeometry = "Geometry"; - constexpr const char* KeyProjection = "Projection"; constexpr const char* KeyRadius = "Geometry.Radius"; constexpr const char* _mainFrame = "GALACTIC"; @@ -134,67 +133,42 @@ namespace { "Clear Projection Buffer", "Remove all pending projections from the buffer" }; + + struct [[codegen::Dictionary(RenderablePlanetProjection)]] Parameters { + // The geometry that is used for rendering this planet + ghoul::Dictionary geometry [[codegen::reference("space_geometry_planet")]]; + // Contains information about projecting onto this planet + ghoul::Dictionary projection + [[codegen::reference("newhorizons_projectioncomponent")]]; + + // [[codegen::verbatim(ColorTexturePathsInfo.description)]] + std::vector colorTexturePaths; + + // [[codegen::verbatim(HeightTexturePathsInfo.description)]] + std::vector heightTexturePaths; + + // [[codegen::verbatim(HeightExaggerationInfo.description)]] + std::optional heightExaggeration; + + // [[codegen::verbatim(MeridianShiftInfo.description)]] + std::optional meridianShift; + + // [[codegen::verbatim(AmbientBrightnessInfo.description)]] + std::optional ambientBrightness; + + // [[codegen::verbatim(MaxProjectionsPerFrameInfo.description)]] + std::optional maxProjectionsPerFrame; + }; +#include "renderableplanetprojection_codegen.cpp" } // namespace namespace openspace { documentation::Documentation RenderablePlanetProjection::Documentation() { - using namespace openspace::documentation; - return { - "Renderable Planet Projection", - "newhorizons_renderable_planetprojection", - { - { - KeyGeometry, - new ReferencingVerifier("space_geometry_planet"), - Optional::No, - "The geometry that is used for rendering this planet.", - }, - { - KeyProjection, - new ReferencingVerifier("newhorizons_projectioncomponent"), - Optional::No, - "Contains information about projecting onto this planet.", - }, - { - ColorTexturePathsInfo.identifier, - new StringListVerifier, - Optional::No, - ColorTexturePathsInfo.description - }, - { - HeightTexturePathsInfo.identifier, - new StringListVerifier, - Optional::Yes, - HeightTexturePathsInfo.description - }, - { - HeightExaggerationInfo.identifier, - new DoubleVerifier, - Optional::Yes, - HeightExaggerationInfo.description - }, - { - MeridianShiftInfo.identifier, - new BoolVerifier, - Optional::Yes, - MeridianShiftInfo.description - }, - { - AmbientBrightnessInfo.identifier, - new DoubleVerifier, - Optional::Yes, - AmbientBrightnessInfo.description - }, - { - MaxProjectionsPerFrameInfo.identifier, - new DoubleVerifier, - Optional::Yes, - MaxProjectionsPerFrameInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "newhorizons_renderable_planetprojection"; + return doc; } RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary& dict) @@ -210,43 +184,24 @@ RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary& , _projectionsInBuffer(ProjectionsInBufferInfo, 0, 1, 32) , _clearProjectionBuffer(ClearProjectionBufferInfo) { - documentation::testSpecificationAndThrow( - Documentation(), - dict, - "RenderablePlanetProjection" - ); + const Parameters p = codegen::bake(dict); - ghoul::Dictionary geometryDictionary = dict.value(KeyGeometry); - _geometry = planetgeometry::PlanetGeometry::createFromDictionary(geometryDictionary); - - _projectionComponent.initialize( - identifier(), - dict.value(KeyProjection) - ); + _geometry = planetgeometry::PlanetGeometry::createFromDictionary(p.geometry); + _projectionComponent.initialize(identifier(), p.projection); _colorTexturePaths.addOption(0, NoImageText); _colorTexturePaths.onChange([this](){ _colorTextureDirty = true; }); addProperty(_colorTexturePaths); - if (dict.hasValue(ColorTexturePathsInfo.identifier)) { - const ghoul::Dictionary& value = dict.value( - ColorTexturePathsInfo.identifier + for (const std::string& t : p.colorTexturePaths) { + _colorTexturePaths.addOption( + static_cast(_colorTexturePaths.options().size()), + t ); - - for (size_t i = 1; i <= value.size(); ++i) { - std::string texture = absPath(value.value(std::to_string(i))); - - _colorTexturePaths.addOption( - // as we started with 0, this works - static_cast(_colorTexturePaths.options().size()), - texture - ); - - _colorTexturePaths = static_cast( - _colorTexturePaths.options().size() - 1 - ); - } } + _colorTexturePaths = static_cast( + _colorTexturePaths.options().size() - 1 + ); _addColorTexturePath.onChange([this]() { if (!_addColorTexturePath.value().empty()) { @@ -271,27 +226,15 @@ RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary& _heightMapTexturePaths.onChange([this]() { _heightMapTextureDirty = true; }); addProperty(_heightMapTexturePaths); - - if (dict.hasValue(HeightTexturePathsInfo.identifier)) { - const ghoul::Dictionary& value = dict.value( - HeightTexturePathsInfo.identifier + for (const std::string& t : p.heightTexturePaths) { + _heightMapTexturePaths.addOption( + static_cast(_heightMapTexturePaths.options().size()), + t ); - - for (size_t i = 1; i <= value.size(); ++i) { - std::string texture = absPath(value.value(std::to_string(i))); - - _heightMapTexturePaths.addOption( - // as we started with 0, this works - static_cast(_heightMapTexturePaths.options().size()), - texture - ); - - _heightMapTexturePaths = static_cast( - _heightMapTexturePaths.options().size() - 1 - ); - } } - + _heightMapTexturePaths = static_cast( + _heightMapTexturePaths.options().size() - 1 + ); _addHeightMapTexturePath.onChange([this]() { if (!_addHeightMapTexturePath.value().empty()) { _heightMapTexturePaths.addOption( @@ -308,11 +251,12 @@ RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary& }); addProperty(_addHeightMapTexturePath); + _meridianShift = p.meridianShift.value_or(_meridianShift); + addProperty(_meridianShift); - if (dict.hasValue(MeridianShiftInfo.identifier)) { - _meridianShift = dict.value(MeridianShiftInfo.identifier); - } - + // @TODO (abock, 2021-03-26) Poking into the Geometry dictionary is not really + // optimal as we don't have local control over how the dictionary is checked. We + // should instead ask the geometry whether it has a radius or not double radius = std::pow(10.0, 9.0); if (dict.hasValue(KeyRadius)) { radius = dict.value(KeyRadius); @@ -322,25 +266,16 @@ RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary& addPropertySubOwner(_geometry.get()); addPropertySubOwner(_projectionComponent); - if (dict.hasKey(HeightExaggerationInfo.identifier)) { - _heightExaggeration = static_cast( - dict.value(HeightExaggerationInfo.identifier) - ); - } - - if (dict.hasKey(MaxProjectionsPerFrameInfo.identifier)) { - _maxProjectionsPerFrame = static_cast( - dict.value(MaxProjectionsPerFrameInfo.identifier) - ); - } - + _heightExaggeration = p.heightExaggeration.value_or(_heightExaggeration); addProperty(_heightExaggeration); - addProperty(_meridianShift); - addProperty(_ambientBrightness); - + + _maxProjectionsPerFrame = p.maxProjectionsPerFrame.value_or(_maxProjectionsPerFrame); addProperty(_maxProjectionsPerFrame); + + addProperty(_ambientBrightness); addProperty(_projectionsInBuffer); + _clearProjectionBuffer.onChange([this]() { _imageTimes.clear(); _projectionsInBuffer = static_cast(_imageTimes.size()); diff --git a/modules/sync/syncs/httpsynchronization.cpp b/modules/sync/syncs/httpsynchronization.cpp index 9a01580bd2..80acc90ddb 100644 --- a/modules/sync/syncs/httpsynchronization.cpp +++ b/modules/sync/syncs/httpsynchronization.cpp @@ -38,39 +38,29 @@ namespace { constexpr const char* _loggerCat = "HttpSynchronization"; - constexpr const char* KeyIdentifier = "Identifier"; - constexpr const char* KeyVersion = "Version"; - constexpr const char* TempSuffix = ".tmp"; constexpr const char* QueryKeyIdentifier = "identifier"; constexpr const char* QueryKeyFileVersion = "file_version"; constexpr const char* QueryKeyApplicationVersion = "application_version"; constexpr const int ApplicationVersion = 1; + + struct [[codegen::Dictionary(HttpSynchronization)]] Parameters { + // A unique identifier for this resource + std::string identifier; + + // The version of this resource + int version; + }; +#include "httpsynchronization_codegen.cpp" } // namespace namespace openspace { documentation::Documentation HttpSynchronization::Documentation() { - using namespace openspace::documentation; - return { - "HttpSynchronization", - "http_synchronization", - { - { - KeyIdentifier, - new StringVerifier, - Optional::No, - "A unique identifier for this resource" - }, - { - KeyVersion, - new IntVerifier, - Optional::No, - "The version of this resource" - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "http_synchronization"; + return doc; } HttpSynchronization::HttpSynchronization(const ghoul::Dictionary& dict, @@ -81,14 +71,10 @@ HttpSynchronization::HttpSynchronization(const ghoul::Dictionary& dict, , _synchronizationRoot(std::move(synchronizationRoot)) , _synchronizationRepositories(std::move(synchronizationRepositories)) { - documentation::testSpecificationAndThrow( - Documentation(), - dict, - "HttpSynchronization" - ); + const Parameters p = codegen::bake(dict); - _identifier = dict.value(KeyIdentifier); - _version = static_cast(dict.value(KeyVersion)); + _identifier = p.identifier; + _version = p.version; } HttpSynchronization::~HttpSynchronization() { diff --git a/modules/sync/syncs/urlsynchronization.cpp b/modules/sync/syncs/urlsynchronization.cpp index a8b7ee98fb..b1c75a80a6 100644 --- a/modules/sync/syncs/urlsynchronization.cpp +++ b/modules/sync/syncs/urlsynchronization.cpp @@ -37,70 +37,49 @@ #include #include #include +#include +#include namespace { - constexpr const char* KeyUrl = "Url"; - constexpr const char* KeyIdentifier = "Identifier"; - constexpr const char* KeyOverride = "Override"; - constexpr const char* KeyUseHash = "UseHash"; - constexpr const char* KeyFilename = "Filename"; - constexpr const char* TempSuffix = ".tmp"; + + struct [[codegen::Dictionary(UrlSynchronization)]] Parameters { + // The URL or urls from where the files are downloaded. If multiple URLs are + // provided, all files will be downloaded to the same directory + std::variant> url; + + // This optional identifier will be part of the used folder structure and, if + // provided, can be used to manually find the downloaded folder in the + // synchronization folder. If this value is not specified, 'UseHash' has to be set + // to 'true' + std::optional identifier; + + // If this value is set to 'true' and it is not overwritten by the global + // settings, the file(s) pointed to by this URLSynchronization will always be + // downloaded, thus overwriting the local files. This is useful for files that are + // updated regularly remotely and should be fetch at every startup + std::optional forceOverride [[codegen::key("override")]]; + + // If this value is set to 'true' (the default), the hash of the URL is appended + // to the directory name to produce a unique directory under all circumstances. If + // this is not desired, the URLSynchronization use the bare directory name alone + // if this value is 'false'. If this value is 'false', the identifier has to be + // specified + std::optional useHash; + + // Optional to provide filename to override the one which is otherwise + // automatically created from the url + std::optional filename; + }; +#include "urlsynchronization_codegen.cpp" } // namespace namespace openspace { documentation::Documentation UrlSynchronization::Documentation() { - using namespace openspace::documentation; - return { - "Url Synchronization", - "sync_synchronization_url", - { - { - KeyUrl, - new OrVerifier({ new StringVerifier, new StringListVerifier }), - Optional::No, - "The URL or urls from where the files are downloaded. If multiple URLs " - "are provided, all files will be downloaded to the same directory." - }, - { - KeyIdentifier, - new StringVerifier, - Optional::Yes, - "This optional identifier will be part of the used folder structure and, " - "if provided, can be used to manually find the downloaded folder in the " - "synchronization folder. If this value is not specified, 'UseHash' has " - "to be set to 'true'." - }, - { - KeyOverride, - new BoolVerifier, - Optional::Yes, - "If this value is set to 'true' and it is not overwritten by the global " - "settings, the file(s) pointed to by this URLSynchronization will always " - "be downloaded, thus overwriting the local files. This is useful for " - "files that are updated regularly remotely and should be fetch at every " - "startup." - }, - { - KeyUseHash, - new BoolVerifier, - Optional::Yes, - "If this value is set to 'true' (the default), the hash of the URL is " - "appended to the directory name to produce a unique directory under all " - "circumstances. If this is not desired, the URLSynchronization use the " - "bare directory name alone if this value is 'false'. If this value is " - "'false', the identifier has to be specified." - }, - { - KeyFilename, - new StringVerifier, - Optional::Yes, - "Optional to provide filename to override the one which is otherwise " - "automatically created from the url. " - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "sync_synchronization_url"; + return doc; } UrlSynchronization::UrlSynchronization(const ghoul::Dictionary& dict, @@ -108,43 +87,33 @@ UrlSynchronization::UrlSynchronization(const ghoul::Dictionary& dict, : ResourceSynchronization(dict) , _synchronizationRoot(std::move(synchronizationRoot)) { - documentation::testSpecificationAndThrow( - Documentation(), - dict, - "UrlSynchroniztion" - ); + const Parameters p = codegen::bake(dict); - if (dict.hasValue(KeyUrl)) { - _urls.push_back(dict.value(KeyUrl)); + if (std::holds_alternative(p.url)) { + _urls.push_back(std::get(p.url)); + + } + else if (std::holds_alternative>(p.url)) { + _urls = std::get>(p.url); } else { - ghoul::Dictionary urls = dict.value(KeyUrl); - for (size_t i = 1; i <= urls.size(); ++i) { - std::string url = urls.value(std::to_string(i)); - _urls.push_back(std::move(url)); - } + throw ghoul::MissingCaseException(); } - if (dict.hasValue(KeyFilename)) { - _filename = dict.value(KeyFilename); - } + _filename = p.filename.value_or(_filename); - bool useHash = true; - if (dict.hasValue(KeyUseHash)) { - useHash = dict.value(KeyUseHash); - } + bool useHash = p.useHash.value_or(true); // We just merge all of the URLs together to generate a hash, it's not as stable to // reordering URLs, but every other solution would be more error prone std::string urlConcat = std::accumulate(_urls.begin(), _urls.end(), std::string()); size_t hash = std::hash{}(urlConcat); - if (dict.hasValue(KeyIdentifier)) { - std::string ident = dict.value(KeyIdentifier); + if (p.identifier.has_value()) { if (useHash) { - _identifier = std::move(ident) + "(" + std::to_string(hash) + ")"; + _identifier = *p.identifier + "(" + std::to_string(hash) + ")"; } else { - _identifier = std::move(ident); + _identifier = *p.identifier; } } else { @@ -154,17 +123,15 @@ UrlSynchronization::UrlSynchronization(const ghoul::Dictionary& dict, else { documentation::TestResult res; res.success = false; - res.offenses.push_back({ - std::string(KeyIdentifier) + "|" + KeyUseHash, - documentation::TestResult::Offense::Reason::MissingKey - }); + documentation::TestResult::Offense o; + o.offender = "Identifier|UseHash"; + o.reason = documentation::TestResult::Offense::Reason::MissingKey; + res.offenses.push_back(o); throw documentation::SpecificationError(std::move(res), "UrlSynchronization"); } } - if (dict.hasValue(KeyOverride)) { - _forceOverride = dict.value(KeyOverride); - } + _forceOverride = p.forceOverride.value_or(_forceOverride); } UrlSynchronization::~UrlSynchronization() { @@ -193,7 +160,6 @@ void UrlSynchronization::start() { std::vector> downloads; for (const std::string& url : _urls) { - if (_filename.empty()) { const size_t lastSlash = url.find_last_of('/'); std::string lastPartOfUrl = url.substr(lastSlash + 1); diff --git a/modules/vislab/rendering/renderabledistancelabel.cpp b/modules/vislab/rendering/renderabledistancelabel.cpp index 397798d431..8d8adaa56e 100644 --- a/modules/vislab/rendering/renderabledistancelabel.cpp +++ b/modules/vislab/rendering/renderabledistancelabel.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include namespace { @@ -56,36 +57,26 @@ namespace { "Property to define a custom unit descriptor to use to describe the distance " "value. Defaults to the units SI descriptor if not specified." }; -} + + struct [[codegen::Dictionary(RenderableDistanceLabel)]] Parameters { + // [[codegen::verbatim(NodeLineInfo.description)]] + std::string nodeLine; + + // [[codegen::verbatim(DistanceUnitInfo.description)]] + std::optional distanceUnit; + + // [[codegen::verbatim(CustomUnitDescriptorInfo.description)]] + std::optional customUnitDescriptor; + }; +#include "renderabledistancelabel_codegen.cpp" +} // namespace namespace openspace { documentation::Documentation RenderableDistanceLabel::Documentation() { - using namespace documentation; - return { - "Renderable Distance Label", - "vislab_renderable_distance_label", - { - { - NodeLineInfo.identifier, - new StringVerifier, - Optional::No, - NodeLineInfo.description - }, - { - DistanceUnitInfo.identifier, - new IntVerifier, - Optional::Yes, - DistanceUnitInfo.description - }, - { - CustomUnitDescriptorInfo.identifier, - new StringVerifier, - Optional::Yes, - CustomUnitDescriptorInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "vislab_renderable_distance_label"; + return doc; } RenderableDistanceLabel::RenderableDistanceLabel(const ghoul::Dictionary& dictionary) @@ -94,27 +85,16 @@ RenderableDistanceLabel::RenderableDistanceLabel(const ghoul::Dictionary& dictio , _distanceUnit(DistanceUnitInfo, 1, 0, 11) , _customUnitDescriptor(CustomUnitDescriptorInfo) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RenderableDistanceLabel" - ); + const Parameters p = codegen::bake(dictionary); - if (dictionary.hasKey(NodeLineInfo.identifier)) { - _nodelineId = dictionary.value(NodeLineInfo.identifier); - addProperty(_nodelineId); - } - if (dictionary.hasKey(DistanceUnitInfo.identifier)) { - _distanceUnit = static_cast( - dictionary.value(DistanceUnitInfo.identifier) - ); - addProperty(_distanceUnit); - } - if (dictionary.hasKey(CustomUnitDescriptorInfo.identifier)) { - _customUnitDescriptor = - dictionary.value(CustomUnitDescriptorInfo.identifier); - addProperty(_customUnitDescriptor); - } + _nodelineId = p.nodeLine; + addProperty(_nodelineId); + + _distanceUnit = p.distanceUnit.value_or(_distanceUnit); + addProperty(_distanceUnit); + + _customUnitDescriptor = p.customUnitDescriptor.value_or(_customUnitDescriptor); + addProperty(_customUnitDescriptor); } void RenderableDistanceLabel::update(const UpdateData&) { diff --git a/modules/vislab/vislabmodule.cpp b/modules/vislab/vislabmodule.cpp index 9546cc9704..bd97596c70 100644 --- a/modules/vislab/vislabmodule.cpp +++ b/modules/vislab/vislabmodule.cpp @@ -2,7 +2,7 @@ * * * OpenSpace * * * - * Copyright (c) 2014-2020 * + * Copyright (c) 2014-2021 * * * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * * software and associated documentation files (the "Software"), to deal in the Software * diff --git a/modules/volume/rawvolumemetadata.cpp b/modules/volume/rawvolumemetadata.cpp index 9ad143a764..85c0a05bbd 100644 --- a/modules/volume/rawvolumemetadata.cpp +++ b/modules/volume/rawvolumemetadata.cpp @@ -28,20 +28,35 @@ #include #include #include +#include namespace { - constexpr const char* KeyDimensions = "Dimensions"; - constexpr const char* KeyLowerDomainBound = "LowerDomainBound"; - constexpr const char* KeyUpperDomainBound = "UpperDomainBound"; + struct [[codegen::Dictionary(RawVolumeMetaData)]] Parameters { + // Specifies the number of grid cells in each dimension + glm::ivec3 dimensions; - constexpr const char* KeyMinValue = "MinValue"; - constexpr const char* KeyMaxValue = "MaxValue"; + // Specifies the unit used to specity the domain + std::optional domainUnit; - constexpr const char* KeyTime = "Time"; - constexpr const char* KeyDomainUnit = "DomainUnit"; - constexpr const char* KeyValueUnit = "ValueUnit"; + // Specifies the lower domain bounds in the model coordinate system + std::optional lowerDomainBound; - constexpr const char* KeyGridType = "GridType"; + // Specifies the upper domain bounds in the model coordinate system + std::optional upperDomainBound; + + // Specifies the time on the format YYYY-MM-DDTHH:MM:SS.000Z + std::optional time; + + // Specifies the unit used to specity the value + std::optional valueUnit; + + // Specifies the minimum value stored in the volume + std::optional minValue; + + // Specifies the maximum value stored in the volume + std::optional maxValue; + }; +#include "rawvolumemetadata_codegen.cpp" } // namespace namespace openspace::volume { @@ -49,51 +64,53 @@ namespace openspace::volume { RawVolumeMetadata RawVolumeMetadata::createFromDictionary( const ghoul::Dictionary& dictionary) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "RawVolumeMetadata" - ); + const Parameters p = codegen::bake(dictionary); RawVolumeMetadata metadata; - metadata.dimensions = dictionary.value(KeyDimensions); + metadata.dimensions = p.dimensions; - metadata.hasDomainBounds = dictionary.hasValue(KeyLowerDomainBound) && - dictionary.hasValue(KeyUpperDomainBound); + metadata.hasDomainBounds = + p.lowerDomainBound.has_value() && + p.upperDomainBound.has_value(); if (metadata.hasDomainBounds) { - metadata.lowerDomainBound = dictionary.value(KeyLowerDomainBound); - metadata.upperDomainBound = dictionary.value(KeyUpperDomainBound); + metadata.lowerDomainBound = *p.lowerDomainBound; + metadata.upperDomainBound = *p.upperDomainBound; } - metadata.hasDomainUnit = static_cast( - dictionary.hasValue(KeyDomainUnit) - ); + metadata.hasDomainUnit = p.domainUnit.has_value(); if (metadata.hasDomainUnit) { - metadata.domainUnit = dictionary.value(KeyDomainUnit); + metadata.domainUnit = *p.domainUnit; } - metadata.hasValueRange = dictionary.hasValue(KeyMinValue) && - dictionary.hasValue(KeyMaxValue); - + metadata.hasValueRange = p.minValue.has_value() && p.maxValue.has_value(); if (metadata.hasValueRange) { - metadata.minValue = static_cast(dictionary.value(KeyMinValue)); - metadata.maxValue = static_cast(dictionary.value(KeyMaxValue)); + metadata.minValue = *p.minValue; + metadata.maxValue = *p.maxValue; } - metadata.hasValueUnit = static_cast(dictionary.hasValue(KeyValueUnit)); + metadata.hasValueUnit = p.valueUnit.has_value(); if (metadata.hasValueUnit) { - metadata.valueUnit = dictionary.value(KeyValueUnit); + metadata.valueUnit = *p.valueUnit; } - metadata.hasTime = dictionary.hasValue(KeyTime); + metadata.hasTime = p.time.has_value(); if (metadata.hasTime) { - std::string timeString = dictionary.value(KeyTime); - metadata.time = Time::convertTime(timeString); + metadata.time = Time::convertTime(*p.time); } return metadata; } ghoul::Dictionary RawVolumeMetadata::dictionary() { + constexpr const char* KeyDimensions = "Dimensions"; + constexpr const char* KeyLowerDomainBound = "LowerDomainBound"; + constexpr const char* KeyUpperDomainBound = "UpperDomainBound"; + constexpr const char* KeyMinValue = "MinValue"; + constexpr const char* KeyMaxValue = "MaxValue"; + constexpr const char* KeyTime = "Time"; + constexpr const char* KeyDomainUnit = "DomainUnit"; + constexpr const char* KeyValueUnit = "ValueUnit"; + constexpr const char* KeyGridType = "GridType"; + ghoul::Dictionary dict; dict.setValue(KeyDimensions, glm::dvec3(dimensions)); dict.setValue(KeyGridType, gridTypeToString(gridType)); @@ -126,61 +143,9 @@ ghoul::Dictionary RawVolumeMetadata::dictionary() { } documentation::Documentation RawVolumeMetadata::Documentation() { - using namespace documentation; - return { - "RawVolumeMetadata", - "volume_rawvolumemetadata", - { - { - KeyDimensions, - new DoubleVector3Verifier, - Optional::No, - "Specifies the number of grid cells in each dimension", - }, - { - KeyDomainUnit, - new StringVerifier, - Optional::Yes, - "Specifies the unit used to specity the domain", - }, - { - KeyLowerDomainBound, - new DoubleVector3Verifier, - Optional::Yes, - "Specifies the lower domain bounds in the model coordinate system", - }, - { - KeyUpperDomainBound, - new DoubleVector3Verifier, - Optional::Yes, - "Specifies the upper domain bounds in the model coordinate system", - }, - { - KeyTime, - new StringVerifier, - Optional::Yes, - "Specifies the time on the format YYYY-MM-DDTHH:MM:SS.000Z", - }, - { - KeyValueUnit, - new StringVerifier, - Optional::Yes, - "Specifies the unit used to specity the value", - }, - { - KeyMinValue, - new DoubleVerifier, - Optional::Yes, - "Specifies the minimum value stored in the volume" - }, - { - KeyMaxValue, - new DoubleVerifier, - Optional::Yes, - "Specifies the maximum value stored in the volume" - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "volume_rawvolumemetadata"; + return doc; } } // namespace openspace::volume diff --git a/modules/volume/tasks/generaterawvolumetask.cpp b/modules/volume/tasks/generaterawvolumetask.cpp index 6de0d6af6a..53372f91f8 100644 --- a/modules/volume/tasks/generaterawvolumetask.cpp +++ b/modules/volume/tasks/generaterawvolumetask.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -37,52 +38,67 @@ #include #include #include - #include namespace { - constexpr const char* KeyRawVolumeOutput = "RawVolumeOutput"; - constexpr const char* KeyDictionaryOutput = "DictionaryOutput"; - constexpr const char* KeyDimensions = "Dimensions"; - constexpr const char* KeyTime = "Time"; - constexpr const char* KeyValueFunction = "ValueFunction"; - constexpr const char* KeyLowerDomainBound = "LowerDomainBound"; - constexpr const char* KeyUpperDomainBound = "UpperDomainBound"; + struct [[codegen::Dictionary(GenerateRawVolumeTask)]] Parameters { + // The Lua function used to compute the cell values + std::string valueFunction [[codegen::annotation("A Lua expression that returns a " + "function taking three numbers as arguments (x, y, z) and returning a " + "number")]]; + + // The raw volume file to export data to + std::string rawVolumeOutput [[codegen::annotation("A valid filepath")]]; + + // The lua dictionary file to export metadata to + std::string dictionaryOutput [[codegen::annotation("A valid filepath")]]; + + // The timestamp that is written to the metadata of this volume + std::string time; + + // A vector representing the number of cells in each dimension + glm::ivec3 dimensions; + + // A vector representing the lower bound of the domain + glm::dvec3 lowerDomainBound; + + // A vector representing the upper bound of the domain + glm::dvec3 upperDomainBound; + }; +#include "generaterawvolumetask_codegen.cpp" } // namespace namespace openspace::volume { -GenerateRawVolumeTask::GenerateRawVolumeTask(const ghoul::Dictionary& dictionary) { - openspace::documentation::testSpecificationAndThrow( - documentation(), - dictionary, - "GenerateRawVolumeTask" - ); +documentation::Documentation GenerateRawVolumeTask::documentation() { + documentation::Documentation doc = codegen::doc(); + doc.id = "generate_raw_volume_task"; + return doc; +} - _rawVolumeOutputPath = absPath(dictionary.value(KeyRawVolumeOutput)); - _dictionaryOutputPath = absPath(dictionary.value(KeyDictionaryOutput)); - _dimensions = glm::uvec3(dictionary.value(KeyDimensions)); - _time = dictionary.value(KeyTime); - _valueFunctionLua = dictionary.value(KeyValueFunction); - _lowerDomainBound = dictionary.value(KeyLowerDomainBound); - _upperDomainBound = dictionary.value(KeyUpperDomainBound); +GenerateRawVolumeTask::GenerateRawVolumeTask(const ghoul::Dictionary& dictionary) { + const Parameters p = codegen::bake(dictionary); + + _rawVolumeOutputPath = absPath(p.rawVolumeOutput); + _dictionaryOutputPath = absPath(p.dictionaryOutput); + _dimensions = p.dimensions; + _time = p.time; + _valueFunctionLua = p.valueFunction; + _lowerDomainBound = p.lowerDomainBound; + _upperDomainBound = p.upperDomainBound; } std::string GenerateRawVolumeTask::description() { - return "Generate a raw volume with dimenstions: (" + - std::to_string(_dimensions.x) + ", " + - std::to_string(_dimensions.y) + ", " + - std::to_string(_dimensions.z) + "). " + - "For each cell, set the value by evaluating the lua function: " + - "`" + _valueFunctionLua + "`, with three arguments (x, y, z) ranging from " + - "(" + std::to_string(_lowerDomainBound.x) + ", " - + std::to_string(_lowerDomainBound.y) + ", " + - std::to_string(_lowerDomainBound.z) + ") to (" + - std::to_string(_upperDomainBound.x) + ", " + - std::to_string(_upperDomainBound.y) + ", " + - std::to_string(_upperDomainBound.z) + ")." + - "Write raw volume data into " + _rawVolumeOutputPath + - " and dictionary with metadata to " + _dictionaryOutputPath; + return fmt::format( + "Generate a raw volume with dimenstions: ({}, {}, {}). For each cell, set the " + "value by evaluating the lua function: `{}`, with three arguments (x, y, z) " + "ranging from ({}, {}, {}) to ({}, {}, {}). Write raw volume data into {} and " + "dictionary with metadata to {}", + _dimensions.x, _dimensions.y, _dimensions.z, _valueFunctionLua, + _lowerDomainBound.x, _lowerDomainBound.y, _lowerDomainBound.z, + _upperDomainBound.x, _upperDomainBound.y, _upperDomainBound.z, + _rawVolumeOutputPath, _dictionaryOutputPath + ); } void GenerateRawVolumeTask::perform(const Task::ProgressCallback& progressCallback) { @@ -184,51 +200,4 @@ void GenerateRawVolumeTask::perform(const Task::ProgressCallback& progressCallba progressCallback(1.0f); } -documentation::Documentation GenerateRawVolumeTask::documentation() { - using namespace documentation; - return { - "GenerateRawVolumeTask", - "generate_raw_volume_task", - { - { - KeyValueFunction, - new StringAnnotationVerifier("A lua expression that returns a function " - "taking three numbers as arguments (x, y, z) and returning a number."), - Optional::No, - "The lua function used to compute the cell values", - }, - { - KeyRawVolumeOutput, - new StringAnnotationVerifier("A valid filepath"), - Optional::No, - "The raw volume file to export data to", - }, - { - KeyDictionaryOutput, - new StringAnnotationVerifier("A valid filepath"), - Optional::No, - "The lua dictionary file to export metadata to", - }, - { - KeyDimensions, - new DoubleVector3Verifier, - Optional::No, - "A vector representing the number of cells in each dimension", - }, - { - KeyLowerDomainBound, - new DoubleVector3Verifier, - Optional::No, - "A vector representing the lower bound of the domain" - }, - { - KeyUpperDomainBound, - new DoubleVector3Verifier, - Optional::No, - "A vector representing the upper bound of the domain" - } - } - }; -} - } // namespace openspace::volume diff --git a/openspace.cfg b/openspace.cfg index 242bb1ba49..7f18243690 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -229,18 +229,20 @@ ScreenSpaceRotation = { 0.0, 0.0, 0.0 } RenderingMethod = "Framebuffer" OpenGLDebugContext = { - Activate = true, - FilterIdentifier = { - { Type = "Other", Source = "API", Identifier = 131185 }, - -- Buffer performance warning: "copied/moved from VIDEO memory to HOST memory" - { Type = "Performance", Source = "API", Identifier = 131186 }, - -- API_ID_LINE_WIDTH deprecated behavior warning has been generated - { Type = "Deprecated", Source = "API", Identifier = 7 }, - -- Program/shader state performance warning: Vertex shader in program %i is being recompiled based on GL state. - { Type = "Performance", Source = "API", Identifier = 131218 }, - -- This is getting a bit wordy - { Type = "Push group", Source = "Application", Identifier = 0 }, - { Type = "Pop group", Source = "Application", Identifier = 0 }, + Activate = true, + FilterIdentifier = { + { Type = "Other", Source = "API", Identifier = 131185 }, + -- API_ID_RECOMPILE_FRAGMENT_SHADER performance warning has been generated. Fragment shader recompiled due to state change + { Type = "Performance", Source = "API", Identifier = 2 }, + -- Buffer performance warning: "copied/moved from VIDEO memory to HOST memory" + { Type = "Performance", Source = "API", Identifier = 131186 }, + -- API_ID_LINE_WIDTH deprecated behavior warning has been generated + { Type = "Deprecated", Source = "API", Identifier = 7 }, + -- Program/shader state performance warning: Vertex shader in program %i is being recompiled based on GL state. + { Type = "Performance", Source = "API", Identifier = 131218 }, + -- This is getting a bit wordy + { Type = "Push group", Source = "Application", Identifier = 0 }, + { Type = "Pop group", Source = "Application", Identifier = 0 }, }, -- FilterSeverity = { } } diff --git a/scripts/configuration_helper.lua b/scripts/configuration_helper.lua index 970314a89a..84dd547e75 100644 --- a/scripts/configuration_helper.lua +++ b/scripts/configuration_helper.lua @@ -702,7 +702,7 @@ function sgct.config.single(arg) ) sgctconfiginitializeString = "sgct.config.single" - trackedSpecifier = "tracked=\"true\"" + local trackedSpecifier = "tracked=\"true\"" if (arg["tracked"] ~= nil and arg["tracked"] == false) then trackedSpecifier = "tracked=\"false\"" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6f62fad495..3a0dcc73a6 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,7 +32,6 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/documentation/documentationgenerator.cpp ${OPENSPACE_BASE_DIR}/src/documentation/verifier.cpp ${OPENSPACE_BASE_DIR}/src/engine/configuration.cpp - ${OPENSPACE_BASE_DIR}/src/engine/configuration_doc.inl ${OPENSPACE_BASE_DIR}/src/engine/downloadmanager.cpp ${OPENSPACE_BASE_DIR}/src/engine/globals.cpp ${OPENSPACE_BASE_DIR}/src/engine/globalscallbacks.cpp @@ -133,6 +132,7 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/rendering/dashboard.cpp ${OPENSPACE_BASE_DIR}/src/rendering/dashboard_lua.inl ${OPENSPACE_BASE_DIR}/src/rendering/dashboarditem.cpp + ${OPENSPACE_BASE_DIR}/src/rendering/dashboardtextitem.cpp ${OPENSPACE_BASE_DIR}/src/rendering/framebufferrenderer.cpp ${OPENSPACE_BASE_DIR}/src/rendering/deferredcastermanager.cpp ${OPENSPACE_BASE_DIR}/src/rendering/helper.cpp @@ -161,7 +161,6 @@ set(OPENSPACE_SOURCE ${OPENSPACE_BASE_DIR}/src/scene/sceneinitializer.cpp ${OPENSPACE_BASE_DIR}/src/scene/scenelicensewriter.cpp ${OPENSPACE_BASE_DIR}/src/scene/scenegraphnode.cpp - ${OPENSPACE_BASE_DIR}/src/scene/scenegraphnode_doc.inl ${OPENSPACE_BASE_DIR}/src/scene/timeframe.cpp ${OPENSPACE_BASE_DIR}/src/scene/translation.cpp ${OPENSPACE_BASE_DIR}/src/scripting/lualibrary.cpp @@ -208,6 +207,10 @@ if (APPLE) ${OPENSPACE_SOURCE} ${OPENSPACE_BASE_DIR}/src/interaction/touchbar.mm ) + set_source_files_properties( + ${OPENSPACE_BASE_DIR}/src/interaction/touchbar.mm + PROPERTIES SKIP_PRECOMPILE_HEADERS ON + ) endif () set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/json.h @@ -323,6 +326,7 @@ set(OPENSPACE_HEADER ${OPENSPACE_BASE_DIR}/include/openspace/rendering/abufferrenderer.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/dashboard.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/dashboarditem.h + ${OPENSPACE_BASE_DIR}/include/openspace/rendering/dashboardtextitem.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/framebufferrenderer.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/deferredcaster.h ${OPENSPACE_BASE_DIR}/include/openspace/rendering/deferredcasterlistener.h diff --git a/src/documentation/documentation.cpp b/src/documentation/documentation.cpp index 3c31287910..96a907209b 100644 --- a/src/documentation/documentation.cpp +++ b/src/documentation/documentation.cpp @@ -140,21 +140,6 @@ namespace openspace::documentation { const std::string DocumentationEntry::Wildcard = "*"; -//std::string concatenate(const std::vector& offenses) { -// std::string result = "Error in specification ("; -// for (const TestResult::Offense& o : offenses) { -// if (o.explanation.empty()) { -// result += fmt::format("{} ({}), ", o.offender, ghoul::to_string(o.reason)); -// } -// else { -// result += fmt::format("{} ({}: {}), ", o.offender, ghoul::to_string(o.reason), o.explanation); -// } -// } -// result.pop_back(); -// result.back() = ')'; -// return result; -//} - SpecificationError::SpecificationError(TestResult res, std::string comp) : ghoul::RuntimeError("Error in specification", std::move(comp)) , result(std::move(res)) diff --git a/src/documentation/verifier.cpp b/src/documentation/verifier.cpp index ed326b1910..d0930d33bd 100644 --- a/src/documentation/verifier.cpp +++ b/src/documentation/verifier.cpp @@ -139,7 +139,9 @@ TestResult IntVerifier::operator()(const ghoul::Dictionary& dict, { if (dict.hasValue(key)) { // We have a key and the value is int, we are done - return { true, {}, {} }; + TestResult res; + res.success = true; + return res; } else { if (dict.hasKey(key)) { @@ -149,23 +151,39 @@ TestResult IntVerifier::operator()(const ghoul::Dictionary& dict, double intPart; bool isInt = modf(value, &intPart) == 0.0; if (isInt) { - return { true, {}, {} }; + TestResult res; + res.success = true; + return res; } else { - return { - false, - { { key, TestResult::Offense::Reason::WrongType } }, - {} - }; + TestResult res; + res.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::WrongType; + res.offenses.push_back(o); + return res; } } else { // If we don't have a double value, we cannot have an int value - return { false, {{ key, TestResult::Offense::Reason::WrongType }}, {} }; + TestResult res; + res.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::WrongType; + res.offenses.push_back(o); + return res; } } else { - return { false, {{ key, TestResult::Offense::Reason::MissingKey }}, {} }; + TestResult res; + res.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::MissingKey; + res.offenses.push_back(o); + return res; } } } @@ -174,6 +192,33 @@ std::string IntVerifier::type() const { return "Integer"; } +StringVerifier::StringVerifier(bool mustBeNotEmpty) + : TemplateVerifier() + , _mustBeNotEmpty(mustBeNotEmpty) +{} + +TestResult StringVerifier::operator()(const ghoul::Dictionary& dictionary, + const std::string& key) const +{ + TestResult res = TemplateVerifier::operator()(dictionary, key); + if (!res.success) { + return res; + } + + std::string value = dictionary.value(key); + if (value.empty() && _mustBeNotEmpty) { + res.success = false; + res.offenses.push_back({ + key, TestResult::Offense::Reason::Verification, "value must not be empty" + }); + } + return res; +} + +bool StringVerifier::mustBeNotEmpty() const { + return _mustBeNotEmpty; +} + std::string StringVerifier::type() const { return "String"; } @@ -237,17 +282,26 @@ TestResult Color3Verifier::operator()(const ghoul::Dictionary& dictionary, glm::dvec3 values = dictionary.value(key); if (values.x < 0.0 || values.x > 1.0) { res.success = false; - res.offenses.push_back({ key + ".x", TestResult::Offense::Reason::Verification }); + TestResult::Offense o; + o.offender = key + ".x"; + o.reason = TestResult::Offense::Reason::Verification; + res.offenses.push_back(o); } if (values.y < 0.0 || values.y > 1.0) { res.success = false; - res.offenses.push_back({ key + ".y", TestResult::Offense::Reason::Verification }); + TestResult::Offense o; + o.offender = key + ".y"; + o.reason = TestResult::Offense::Reason::Verification; + res.offenses.push_back(o); } if (values.z < 0.0 || values.z > 1.0) { res.success = false; - res.offenses.push_back({ key + ".z", TestResult::Offense::Reason::Verification }); + TestResult::Offense o; + o.offender = key + ".z"; + o.reason = TestResult::Offense::Reason::Verification; + res.offenses.push_back(o); } return res; @@ -265,27 +319,39 @@ TestResult Color4Verifier::operator()(const ghoul::Dictionary& dictionary, return res; } - std::vector values = dictionary.value>(key); - if (values[0] < 0.0 || values[0] > 1.0) { + glm::dvec4 values = dictionary.value(key); + if (values.x < 0.0 || values.x > 1.0) { res.success = false; - res.offenses.push_back({ key + ".x", TestResult::Offense::Reason::Verification }); + TestResult::Offense o; + o.offender = key + ".x"; + o.reason = TestResult::Offense::Reason::Verification; + res.offenses.push_back(o); } - if (values[1] < 0.0 || values[1] > 1.0) { + if (values.y < 0.0 || values.y > 1.0) { res.success = false; - res.offenses.push_back({ key + ".y", TestResult::Offense::Reason::Verification }); + TestResult::Offense o; + o.offender = key + ".y"; + o.reason = TestResult::Offense::Reason::Verification; + res.offenses.push_back(o); } - if (values[2] < 0.0 || values[2] > 1.0) { + if (values.z < 0.0 || values.z > 1.0) { res.success = false; - res.offenses.push_back({ key + ".z", TestResult::Offense::Reason::Verification }); + TestResult::Offense o; + o.offender = key + ".z"; + o.reason = TestResult::Offense::Reason::Verification; + res.offenses.push_back(o); } - if (values[3] < 0.0 || values[3] > 1.0) { + if (values.w < 0.0 || values.w > 1.0) { res.success = false; - res.offenses.push_back({ key + ".a", TestResult::Offense::Reason::Verification }); + TestResult::Offense o; + o.offender = key + ".a"; + o.reason = TestResult::Offense::Reason::Verification; + res.offenses.push_back(o); } - + return res; } @@ -298,7 +364,9 @@ TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dic const std::string& key) const { if (dict.hasValue(key)) { - return { true, {}, {} }; + TestResult res; + res.success = true; + return res; } else { if (dict.hasKey(key)) { @@ -310,22 +378,38 @@ TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dic modf(value.y, &intPart.y) == 0.0 }; if (isInt.x && isInt.y) { - return { true, {}, {} }; + TestResult res; + res.success = true; + return res; } else { - return { - false, - {{ key, TestResult::Offense::Reason::WrongType }}, - {} - }; + TestResult res; + res.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::WrongType; + res.offenses.push_back(o); + return res; } } else { - return { false, {{ key, TestResult::Offense::Reason::WrongType }}, {} }; + TestResult res; + res.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::WrongType; + res.offenses.push_back(o); + return res; } } else { - return { false, {{ key, TestResult::Offense::Reason::MissingKey }}, {} }; + TestResult res; + res.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::MissingKey; + res.offenses.push_back(o); + return res; } } } @@ -335,7 +419,9 @@ TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dic const std::string& key) const { if (dict.hasValue(key)) { - return { true, {}, {} }; + TestResult res; + res.success = true; + return res; } else { if (dict.hasKey(key)) { @@ -348,22 +434,38 @@ TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dic modf(value.z, &intPart.z) == 0.0 }; if (isInt.x && isInt.y && isInt.z) { - return { true, {}, {} }; + TestResult res; + res.success = true; + return res; } else { - return { - false, - {{ key, TestResult::Offense::Reason::WrongType }}, - {} - }; + TestResult res; + res.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::WrongType; + res.offenses.push_back(o); + return res; } } else { - return { false, {{ key, TestResult::Offense::Reason::WrongType }}, {} }; + TestResult res; + res.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::WrongType; + res.offenses.push_back(o); + return res; } } else { - return { false, {{ key, TestResult::Offense::Reason::MissingKey }}, {} }; + TestResult res; + res.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::MissingKey; + res.offenses.push_back(o); + return res; } } } @@ -373,7 +475,9 @@ TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dic const std::string& key) const { if (dict.hasValue(key)) { - return { true, {}, {} }; + TestResult res; + res.success = true; + return res; } else { if (dict.hasKey(key)) { @@ -387,22 +491,38 @@ TestResult TemplateVerifier::operator()(const ghoul::Dictionary& dic modf(value.w, &intPart.w) == 0.0 }; if (isInt.x && isInt.y && isInt.z && isInt.w) { - return { true, {}, {} }; + TestResult res; + res.success = true; + return res; } else { - return { - false, - {{ key, TestResult::Offense::Reason::WrongType }}, - {} - }; + TestResult res; + res.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::WrongType; + res.offenses.push_back(o); + return res; } } else { - return { false, {{ key, TestResult::Offense::Reason::WrongType }}, {} }; + TestResult res; + res.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::WrongType; + res.offenses.push_back(o); + return res; } } else { - return { false, {{ key, TestResult::Offense::Reason::MissingKey }}, {} }; + TestResult res; + res.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::MissingKey; + res.offenses.push_back(o); + return res; } } } @@ -432,11 +552,22 @@ TestResult TableVerifier::operator()(const ghoul::Dictionary& dictionary, } else { if (dictionary.hasKey(key)) { - return { false, { { key, TestResult::Offense::Reason::WrongType } }, {} }; - + TestResult res; + res.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::WrongType; + res.offenses.push_back(o); + return res; } else { - return { false, { { key, TestResult::Offense::Reason::MissingKey } }, {} }; + TestResult res; + res.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::MissingKey; + res.offenses.push_back(o); + return res; } } } @@ -485,11 +616,11 @@ TestResult ReferencingVerifier::operator()(const ghoul::Dictionary& dictionary, ); if (it == docs.end()) { - res.offenses.push_back({ - key, - TestResult::Offense::Reason::UnknownIdentifier - }); res.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::UnknownIdentifier; + res.offenses.push_back(o); return res; } @@ -549,10 +680,18 @@ TestResult AndVerifier::operator()(const ghoul::Dictionary& dictionary, ); if (success) { - return { true, {}, {} }; + TestResult res; + res.success = true; + return res; } else { - return { false, { { key, TestResult::Offense::Reason::Verification } }, {} }; + TestResult res; + res.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::Verification; + res.offenses.push_back(o); + return res; } } @@ -584,10 +723,17 @@ std::string AndVerifier::documentation() const { return ghoul::join(documentations, ", "); } -OrVerifier::OrVerifier(const std::vector values_) { +OrVerifier::OrVerifier( + const std::vector>> values_) +{ ghoul_assert(!values_.empty(), "values must not be empty"); - for (Verifier* v : values_) { - this->values.push_back(std::shared_ptr(v)); + for (const std::variant>& v : values_) { + if (std::holds_alternative(v)) { + this->values.push_back(std::shared_ptr(std::get(v))); + } + else { + this->values.push_back(std::get>(v)); + } } } @@ -611,10 +757,18 @@ TestResult OrVerifier::operator()(const ghoul::Dictionary& dictionary, ); if (success) { - return { true, {}, {} }; + TestResult res; + res.success = true; + return res; } else { - return { false, { { key, TestResult::Offense::Reason::Verification } }, {} }; + TestResult res; + res.success = false; + TestResult::Offense o; + o.offender = key; + o.reason = TestResult::Offense::Reason::Verification; + res.offenses.push_back(o); + return res; } } diff --git a/src/engine/configuration.cpp b/src/engine/configuration.cpp index 35727a3790..f063bded20 100644 --- a/src/engine/configuration.cpp +++ b/src/engine/configuration.cpp @@ -27,287 +27,304 @@ #include #include #include +#include #include #include #include +#include namespace { - constexpr const char* BasePathToken = "${BASE}"; // We can't use ${SCRIPTS} here as that hasn't been defined by this point constexpr const char* InitialConfigHelper = "${BASE}/scripts/configuration_helper.lua"; - // Variable names for the openspace.cfg file - // These are also used in the _doc include file - constexpr const char* KeySGCTConfig = "SGCTConfig"; - constexpr const char* KeyAsset = "Asset"; - constexpr const char* KeyProfile = "Profile"; - constexpr const char* KeyGlobalCustomizationScripts = "GlobalCustomizationScripts"; - constexpr const char* KeyPaths = "Paths"; - constexpr const char* KeyFonts = "Fonts"; - constexpr const char* KeyLogging = "Logging"; - constexpr const char* KeyLogDir = "LogDir"; - constexpr const char* KeyPerformancePrefix = "PerformancePrefix"; - constexpr const char* KeyLogLevel = "LogLevel"; - constexpr const char* KeyImmediateFlush = "ImmediateFlush"; - constexpr const char* KeyLogs = "Logs"; - constexpr const char* KeyCapabilitiesVerbosity = "CapabilitiesVerbosity"; - constexpr const char* KeyDocumentationPath = "Path"; - constexpr const char* KeyDocumentation = "Documentation"; - constexpr const char* KeyScriptLog = "ScriptLog"; - constexpr const char* KeyShutdownCountdown = "ShutdownCountdown"; - constexpr const char* KeyPerSceneCache = "PerSceneCache"; - constexpr const char* KeyOnScreenTextScaling = "OnScreenTextScaling"; - constexpr const char* KeyRenderingMethod = "RenderingMethod"; - constexpr const char* KeyDisableRenderingOnMaster = "DisableRenderingOnMaster"; - constexpr const char* KeyGlobalRotation = "GlobalRotation"; - constexpr const char* KeyScreenSpaceRotation = "ScreenSpaceRotation"; - constexpr const char* KeyMasterRotation = "MasterRotation"; - constexpr const char* KeyDisableInGameConsole = "DisableInGameConsole"; - constexpr const char* KeyScreenshotUseDate = "ScreenshotUseDate"; - constexpr const char* KeyHttpProxy = "HttpProxy"; - constexpr const char* KeyAddress = "Address"; - constexpr const char* KeyPort = "Port"; - constexpr const char* KeyAuthentication = "Authentication"; - constexpr const char* KeyUser = "User"; - constexpr const char* KeyPassword = "Password"; - constexpr const char* KeyOpenGLDebugContext = "OpenGLDebugContext"; - constexpr const char* KeyActivate = "Activate"; - constexpr const char* KeySynchronous = "Synchronous"; - constexpr const char* KeyFilterIdentifier = "FilterIdentifier"; - constexpr const char* KeyIdentifier = "Identifier"; - constexpr const char* KeySource = "Source"; - constexpr const char* KeyType = "Type"; - constexpr const char* KeyFilterSeverity = "FilterSeverity"; - constexpr const char* KeyCheckOpenGLState = "CheckOpenGLState"; - constexpr const char* KeyLogEachOpenGLCall = "LogEachOpenGLCall"; - constexpr const char* KeyVersionCheckUrl = "VersionCheckUrl"; - constexpr const char* KeyUseMultithreadedInitialization = - "UseMultithreadedInitialization"; - constexpr const char* KeyLoadingScreen = "LoadingScreen"; - constexpr const char* KeyShowMessage = "ShowMessage"; - constexpr const char* KeyShowNodeNames = "ShowNodeNames"; - constexpr const char* KeyShowProgressbar = "ShowProgressbar"; - constexpr const char* KeyModuleConfigurations = "ModuleConfigurations"; + struct [[codegen::Dictionary(Configuration)]] Parameters { + // The SGCT configuration file that determines the window and view frustum + // settings that are being used when OpenSpace is started + std::optional windowConfiguration [[codegen::key("SGCTConfig")]]; - constexpr const char* KeySgctConfigNameInitialized = "sgctconfiginitializeString"; - constexpr const char* KeyReadOnlyProfiles = "ReadOnlyProfiles"; - constexpr const char* KeyBypassLauncher = "BypassLauncher"; + // The scene description that is used to populate the application after startup. + // The scene determines which objects are loaded, the startup time and other + // scene-specific settings. More information is provided in the Scene + // documentation. If the 'Asset' and the 'Profile' values are specified, the asset + // is silently ignored + std::optional asset; - template - void getValue(ghoul::lua::LuaState& L, const char* name, T& value) { - using namespace openspace::configuration; + // The profile that should be loaded at the startup. The profile determines which + // assets are loaded, the startup time, keyboard shortcuts, and other settings. + std::optional profile; - auto it = std::find_if( - Configuration::Documentation.entries.begin(), - Configuration::Documentation.entries.end(), - [name](const openspace::documentation::DocumentationEntry& e) { - return e.key == name; - } - ); + // This value names a list of scripts that get executed after initialization of + // any scene. These scripts can be used for user-specific customization, such as a + // global rebinding of keys from the default + std::optional> globalCustomizationScripts; - bool isOptional = - it != Configuration::Documentation.entries.end() - ? it->optional : - true; + // A list of paths that are automatically registered with the file system. If a + // key X is used in the table, it is then useable by referencing ${X} in all other + // configuration files or scripts + std::map paths; - lua_getglobal(L, name); - if (isOptional && lua_isnil(L, -1)) { - return; - } + // A list of all fonts that will automatically be loaded on startup. Each + // key-value pair contained in the table will become the name and the file for a + // font + std::optional> fonts; - if (!isOptional && lua_isnil(L, -1)) { - openspace::documentation::TestResult testResult = { - false, - { { - name, - openspace::documentation::TestResult::Offense::Reason::MissingKey - }}, - {} + struct Logging { + // List from logmanager.cpp::levelFromString + enum class Level { + Trace, + Debug, + Info, + Warning, + Error, + Fatal, + None }; - throw openspace::documentation::SpecificationError( - std::move(testResult), - "Configuration" - ); - } + // The severity of log messages that will be displayed. Only messages of the + // selected level or higher will be displayed. All levels below will be + // silently discarded. The order of severities is: + // Debug < Info < Warning < Error < Fatal < None. + std::optional logLevel; - if constexpr (std::is_same_v) { - ghoul::Dictionary d = ghoul::lua::value(L); - glm::dvec3 res; - res.x = d.value("1"); - res.y = d.value("2"); - res.z = d.value("3"); - value = res; - } - // NOLINTNEXTLINE - else if constexpr (std::is_same_v>) { - ghoul::Dictionary d = ghoul::lua::value(L); + // Determines whether error messages will be displayed immediately or if it is + // acceptable to have a short delay, but being more performant. If the delay + // is allowed ('true'), messages might get lost if the application crashes + // shortly after a message was logged + std::optional immediateFlush; - std::vector res; - for (size_t i = 1; i <= d.size(); ++i) { - res.push_back(d.value(std::to_string(i))); - } - value = std::move(res); - } - // NOLINTNEXTLINE - else if constexpr (std::is_same_v>) { - ghoul::Dictionary d = ghoul::lua::value(L); + // Per default, log messages are written to the console, the onscreen text, + // and (if available) the Visual Studio output window. This table can define + // other logging methods that will be used additionally + std::optional> logs + [[codegen::reference("core_logfactory")]]; - std::map res; - std::vector keys = d.keys(); - for (size_t i = 0; i < d.size(); ++i) { - std::string_view key = keys[i]; - std::string v = d.value(key); - res[std::string(key)] = std::move(v); - } - value = std::move(res); - } - // NOLINTNEXTLINE - else if constexpr (std::is_same_v>) { - ghoul::Dictionary d = ghoul::lua::value(L); + // List from OpenspaceEngine::initialize + enum class Verbosity { + None, + Minimal, + Default, + Full + }; + // At startup, a list of system capabilities is created and logged. This value + // determines how verbose this listing should be + std::optional capabilitiesVerbosity; + }; + // Configurations for the logging of messages that are generated throughout the + // code and are useful for debugging potential errors or other information + std::optional logging; - std::map res; - std::vector keys = d.keys(); - for (size_t i = 0; i < d.size(); ++i) { - std::string_view key = keys[i]; - ghoul::Dictionary v = d.value(key); - res[std::string(key)] = std::move(v); - } - value = std::move(res); - } - // NOLINTNEXTLINE - else if constexpr (std::is_same_v) { - Configuration::Logging& v = static_cast(value); - ghoul::Dictionary d = ghoul::lua::value(L); + // The file that will be created on startup containing the log of all Lua scripts + // that are executed in the last session. Any existing file (including the results + // from previous runs) will be silently overwritten + std::optional scriptLog; - if (d.hasValue(KeyLogLevel)) { - v.level = d.value(KeyLogLevel); - } - if (d.hasValue(KeyImmediateFlush)) { - v.forceImmediateFlush = d.value(KeyImmediateFlush); - } - if (d.hasValue(KeyCapabilitiesVerbosity)) { - v.capabilitiesVerbosity = d.value(KeyCapabilitiesVerbosity); - } + struct Documentation { + // The path where the documentation files will be stored + std::optional path; + }; + // Right now only contains the path where the documentation is written to + std::optional documentation; - if (d.hasValue(KeyLogs)) { - ghoul::Dictionary l = d.value(KeyLogs); - std::vector res; - for (size_t i = 1; i <= l.size(); ++i) { - res.push_back(l.value(std::to_string(i))); - } - v.logs = res; - } - } - // NOLINTNEXTLINE - else if constexpr (std::is_same_v) { - Configuration::DocumentationInfo& v = - static_cast(value); - ghoul::Dictionary d = ghoul::lua::value(L); - if (d.hasValue(KeyDocumentationPath)) { - v.path = d.value(KeyDocumentationPath); - } - } - // NOLINTNEXTLINE - else if constexpr (std::is_same_v) { - Configuration::LoadingScreen& v = - static_cast(value); - ghoul::Dictionary d = ghoul::lua::value(L); - if (d.hasValue(KeyShowMessage)) { - v.isShowingMessages = d.value(KeyShowMessage); - } - if (d.hasValue(KeyShowNodeNames)) { - v.isShowingNodeNames = d.value(KeyShowNodeNames); - } - if (d.hasValue(KeyShowProgressbar)) { - v.isShowingProgressbar = d.value(KeyShowProgressbar); - } - } - // NOLINTNEXTLINE - else if constexpr (std::is_same_v) { - Configuration::OpenGLDebugContext& v = - static_cast(value); - ghoul::Dictionary d = ghoul::lua::value(L); + // The countdown that the application will wait between pressing ESC and actually + // shutting down. If ESC is pressed again in this time, the shutdown is aborted + std::optional shutdownCountdown [[codegen::greater(0.0)]]; - if (d.hasValue(KeyActivate)) { - v.isActive = d.value(KeyActivate); - } - if (d.hasValue(KeySynchronous)) { - v.isSynchronous = d.value(KeySynchronous); - } + // If this is set to 'true', the name of the scene will be appended to the cache + // directory, thus not reusing the same directory. This is useful in cases where + // the same instance of OpenSpace is run with multiple scenes, but the caches + // should be retained. This value defaults to 'false' + std::optional perSceneCache; - if (d.hasValue(KeyFilterIdentifier)) { - ghoul::Dictionary f = d.value(KeyFilterIdentifier); + enum class Scaling { + Window [[codegen::key("window")]], + Framebuffer [[codegen::key("framebuffer")]] + }; + // The method for scaling the onscreen text in the window. As the resolution of + // the rendering can be different from the size of the window, the onscreen text + // can either be scaled according to the window size ('window'), or the rendering + // resolution ('framebuffer'). This value defaults to 'window' + std::optional onScreenTextScaling; - std::vector res; - for (size_t i = 1; i <= f.size(); ++i) { - Configuration::OpenGLDebugContext::IdentifierFilter filter; - ghoul::Dictionary fi = f.value(std::to_string(i)); + // List from RenderEngine::setRendererFromString + enum class RenderingMethod { + Framebuffer, + ABuffer + }; + // The renderer that is use after startup. The renderer 'ABuffer' requires support + // for at least OpenGL 4.3 + std::optional renderingMethod; - if (fi.hasValue(KeyIdentifier)) { - filter.identifier = static_cast( - fi.value(KeyIdentifier) - ); - } - if (fi.hasValue(KeySource)) { - filter.source = fi.value(KeySource); - } - if (fi.hasValue(KeyType)) { - filter.type = fi.value(KeyType); - } + // Toggles whether the master in a multi-application setup should be rendering or + // just managing the state of the network. This is desired in cases where the + // master computer does not have the resources to render a scene + std::optional disableRenderingOnMaster; - auto fff = filter; - const auto ffg = filter; + // Applies a global view rotation. Use this to rotate the position of the focus + // node away from the default location on the screen. This setting persists even + // when a new focus node is selected. Defined using roll, pitch, yaw in radians + std::optional globalRotation; - res.push_back(std::move(filter)); - } + // Applies a view rotation for only the master node, defined using roll, pitch yaw + // in radians. This can be used to compensate the master view direction for tilted + // display systems in clustered immersive environments + std::optional masterRotation; - v.identifierFilters = res; - } + // Applies a global rotation for all screenspace renderables. Defined using roll, + // pitch, yaw in radians + std::optional screenSpaceRotation; - if (d.hasValue(KeyFilterSeverity)) { - ghoul::Dictionary f = d.value(KeyFilterSeverity); + // If this value is set to 'true' the ingame console is disabled, locking the + // system down against random access + std::optional disableInGameConsole; - std::vector res; - for (size_t i = 1; i <= f.size(); ++i) { - res.push_back(f.value(std::to_string(i))); - } - v.severityFilters = res; - } - } - // NOLINTNEXTLINE - else if constexpr (std::is_same_v) { - Configuration::HTTPProxy& v = static_cast(value); - ghoul::Dictionary d = ghoul::lua::value(L); + // Toggles whether screenshots generated by OpenSpace contain the date when the + // concrete OpenSpace instance was started. This value is enabled by default, but + // it is advised to disable this value if rendering sessions of individual frames + // pass beyond local midnight + std::optional screenshotUseDate; - if (d.hasValue(KeyActivate)) { - v.usingHttpProxy = d.value(KeyActivate); - } - if (d.hasValue(KeyAddress)) { - v.address = d.value(KeyAddress); - } - if (d.hasValue(KeyPort)) { - v.port = static_cast(d.value(KeyPort)); - } - if (d.hasValue(KeyAuthentication)) { - v.authentication = d.value(KeyAuthentication); - } - if (d.hasValue(KeyUser)) { - v.user = d.value(KeyUser); - } - if (d.hasValue(KeyPassword)) { - v.password = d.value(KeyPassword); - } - } - else { - value = ghoul::lua::value(L); - } - } + struct HttpProxy { + // Determines whether the proxy is being used + std::optional activate; + // The address of the http proxy + std::string address; + + // The port of the http proxy + int port [[codegen::inrange(0, 65536)]]; + + enum class Authentication { + Basic [[codegen::key("basic")]], + Ntlm [[codegen::key("ntlm")]], + Digest [[codegen::key("digest")]], + Any [[codegen::key("any")]] + }; + // The authentication method of the http proxy + std::optional authentication; + + // The user of the http proxy + std::optional user; + + // The password of the http proxy + std::optional password; + }; + // This defines the use for a proxy when fetching data over http. No proxy will be + // used if this is left out + std::optional httpProxy; + + struct OpenGLDebugContext { + // Determines whether the OpenGL context should be a debug context + bool activate; + + // Determines whether the OpenGL debug callbacks are performed synchronously. + // If set to 'true' the callbacks are in the same thread as the context and in + // the scope of the OpenGL function that triggered the message. The default + // value is 'true' + std::optional synchronous; + + // Individual OpenGL debug message identifiers + struct Filter { + // The identifier that is to be filtered + int identifier; + + // Taken from ghoul::debugcontext.cpp + enum class Source { + API, + WindowSystem [[codegen::key("Window System")]], + ShaderCompiler [[codegen::key("Shader Compiler")]], + ThirdParty [[codegen::key("Third Party")]], + Application, + Other, + DontCare [[codegen::key("Don't care")]] + }; + // The source of the identifier to be filtered + Source source; + + // Taken from ghoul::debugcontext.cpp + enum class Type { + Error, + Deprecated, + Undefined, + Portability, + Performance, + Marker, + PushGroup [[codegen::key("Push group")]], + PopGroup [[codegen::key("Pop group")]], + Other, + DontCare [[codegen::key("Don't care")]] + }; + // The type of the identifier to be filtered + Type type; + }; + // A list of OpenGL debug messages identifiers that are filtered + std::optional> filterIdentifier; + + // A list of severities that can are filtered out + enum class Severity { + High, + Medium, + Low, + Notification + }; + // Determines the settings for the creation of an OpenGL debug context + std::optional> filterSeverity; + }; + // Determines the settings for the creation of an OpenGL debug context + std::optional openGLDebugContext; + + // Determines whether the OpenGL state is checked after each OpenGL function call. + // This will dramatically slow down the rendering, but will make finding OpenGL + // errors easier. This defaults to 'false' + std::optional checkOpenGLState; + + // Determines whether each OpenGL call that happens should be logged using the + // 'TRACE' loglevel. This will bring the rendering to a crawl but provides useful + // debugging features for the order in which OpenGL calls occur. This defaults to + // 'false' + std::optional logEachOpenGLCall; + + // This value determines whether the initialization of the scene graph should + // occur multithreaded, that is, whether multiple scene graph nodes should + // initialize in parallel. The only use for this value is to disable it for + // debugging support + std::optional useMultithreadedInitialization; + + // If this value is set to 'true', the launcher will not be shown and OpenSpace + // will start with the provided configuration options directly. Useful in + // multiprojector setups where a launcher window would be undesired + std::optional bypassLauncher; + + // The URL that is pinged to check which version of OpenSpace is the most current + // if you don't want this request to happen, this value should not be set at all + std::optional versionCheckUrl; + + struct LoadingScreen { + // If this value is set to 'true', the loading screen will display a message + // information about the current phase the loading is in + std::optional showMessage; + + // If this value is set to 'true', the loading screen will display a list of + // all of the nodes with their respective status (created, loaded, + // initialized) + std::optional showNodeNames; + + // If this value is set to 'true', the loading screen will contain a progress + // bar that gives an estimate of the loading progression + std::optional showProgressbar; + }; + // Values in this table describe the behavior of the loading screen that is + // displayed while the scene graph is created and initialized + std::optional loadingScreen; + + // List of profiles that cannot be overwritten by user + std::optional> readOnlyProfiles; + + // Configurations for each module + std::optional> moduleConfigurations; + }; +#include "configuration_codegen.cpp" } // namespace -#include "configuration_doc.inl" - namespace openspace::configuration { void parseLuaState(Configuration& configuration) { @@ -317,40 +334,277 @@ void parseLuaState(Configuration& configuration) { Configuration& c = configuration; LuaState& s = c.state; - getValue(s, KeySGCTConfig, c.windowConfiguration); - getValue(s, KeyAsset, c.asset); - getValue(s, KeyProfile, c.profile); - getValue(s, KeyGlobalCustomizationScripts, c.globalCustomizationScripts); - getValue(s, KeyPaths, c.pathTokens); - getValue(s, KeyFonts, c.fonts); - getValue(s, KeyScriptLog, c.scriptLog); - getValue(s, KeyVersionCheckUrl, c.versionCheckUrl); - getValue(s, KeyUseMultithreadedInitialization, c.useMultithreadedInitialization); - getValue(s, KeyCheckOpenGLState, c.isCheckingOpenGLState); - getValue(s, KeyLogEachOpenGLCall, c.isLoggingOpenGLCalls); - getValue(s, KeyShutdownCountdown, c.shutdownCountdown); - getValue(s, KeyScreenshotUseDate, c.shouldUseScreenshotDate); - getValue(s, KeyOnScreenTextScaling, c.onScreenTextScaling); - getValue(s, KeyPerSceneCache, c.usePerSceneCache); - getValue(s, KeyDisableRenderingOnMaster, c.isRenderingOnMasterDisabled); + // The sgctConfigNameInitialized is a bit special + lua_getglobal(s, "sgctconfiginitializeString"); + c.sgctConfigNameInitialized = ghoul::lua::value( + s, + ghoul::lua::PopValue::Yes + ); - getValue(s, KeyGlobalRotation, c.globalRotation); - getValue(s, KeyScreenSpaceRotation, c.screenSpaceRotation); - getValue(s, KeyMasterRotation, c.masterRotation); - getValue(s, KeyDisableInGameConsole, c.isConsoleDisabled); - getValue(s, KeyRenderingMethod, c.renderingMethod); - getValue(s, KeyLogging, c.logging); - getValue(s, KeyDocumentation, c.documentation); - getValue(s, KeyLoadingScreen, c.loadingScreen); - getValue(s, KeyModuleConfigurations, c.moduleConfigurations); - getValue(s, KeyOpenGLDebugContext, c.openGLDebugContext); - getValue(s, KeyHttpProxy, c.httpProxy); - getValue(s, KeySgctConfigNameInitialized, c.sgctConfigNameInitialized); - getValue(s, KeyReadOnlyProfiles, c.readOnlyProfiles); - getValue(s, KeyBypassLauncher, c.bypassLauncher); + // The configuration file sets all values as global variables, so we need to pull them + // into a table first so that we can pass that table to the dictionary constructor + lua_newtable(s); + + // We go through all of the entries and lift them from global scope into the table on + // the stack so that we can create a ghoul::Dictionary from this new table + documentation::Documentation doc = codegen::doc(); + for (const documentation::DocumentationEntry& e : doc.entries) { + lua_pushstring(s, e.key.c_str()); + lua_getglobal(s, e.key.c_str()); + lua_settable(s, -3); + } + + + ghoul::Dictionary d; + ghoul::lua::luaDictionaryFromState(s, d); + lua_settop(s, 0); + const Parameters p = codegen::bake(d); + + c.windowConfiguration = p.windowConfiguration.value_or(c.windowConfiguration); + c.asset = p.asset.value_or(c.asset); + c.profile = p.profile.value_or(c.profile); + c.globalCustomizationScripts = + p.globalCustomizationScripts.value_or(c.globalCustomizationScripts); + c.pathTokens = p.paths; + c.fonts = p.fonts.value_or(c.fonts); + c.scriptLog = p.scriptLog.value_or(c.scriptLog); + c.versionCheckUrl = p.versionCheckUrl.value_or(c.versionCheckUrl); + c.useMultithreadedInitialization = + p.useMultithreadedInitialization.value_or(c.useMultithreadedInitialization); + c.isCheckingOpenGLState = p.checkOpenGLState.value_or(c.isCheckingOpenGLState); + c.isLoggingOpenGLCalls = p.logEachOpenGLCall.value_or(c.isLoggingOpenGLCalls); + c.shutdownCountdown = p.shutdownCountdown.value_or(c.shutdownCountdown); + c.shouldUseScreenshotDate = p.screenshotUseDate.value_or(c.shouldUseScreenshotDate); + if (p.onScreenTextScaling.has_value()) { + switch (*p.onScreenTextScaling) { + case Parameters::Scaling::Window: + c.onScreenTextScaling = "window"; + break; + case Parameters::Scaling::Framebuffer: + c.onScreenTextScaling = "framebuffer"; + break; + default: + throw ghoul::MissingCaseException(); + } + } + c.usePerSceneCache = p.perSceneCache.value_or(c.usePerSceneCache); + c.isRenderingOnMasterDisabled = + p.disableRenderingOnMaster.value_or(c.isRenderingOnMasterDisabled); + c.globalRotation = p.globalRotation.value_or(c.globalRotation); + c.masterRotation = p.masterRotation.value_or(c.masterRotation); + c.screenSpaceRotation = p.screenSpaceRotation.value_or(c.screenSpaceRotation); + if (p.renderingMethod.has_value()) { + switch (*p.renderingMethod) { + case Parameters::RenderingMethod::Framebuffer: + c.renderingMethod = "Framebuffer"; + break; + case Parameters::RenderingMethod::ABuffer: + c.renderingMethod = "ABuffer"; + break; + default: + throw ghoul::MissingCaseException(); + } + } + c.isConsoleDisabled = p.disableInGameConsole.value_or(c.isConsoleDisabled); + if (p.logging.has_value()) { + if (p.logging->logLevel.has_value()) { + switch (*p.logging->logLevel) { + case Parameters::Logging::Level::Trace: + c.logging.level = "Trace"; + break; + case Parameters::Logging::Level::Debug: + c.logging.level = "Debug"; + break; + case Parameters::Logging::Level::Info: + c.logging.level = "Info"; + break; + case Parameters::Logging::Level::Warning: + c.logging.level = "Warning"; + break; + case Parameters::Logging::Level::Error: + c.logging.level = "Error"; + break; + case Parameters::Logging::Level::Fatal: + c.logging.level = "Fatal"; + break; + case Parameters::Logging::Level::None: + c.logging.level = "None"; + break; + default: + throw ghoul::MissingCaseException(); + } + } + + c.logging.forceImmediateFlush = + p.logging->immediateFlush.value_or(c.logging.forceImmediateFlush); + c.logging.logs = p.logging->logs.value_or(c.logging.logs); + if (p.logging->capabilitiesVerbosity.has_value()) { + switch (*p.logging->capabilitiesVerbosity) { + case Parameters::Logging::Verbosity::None: + c.logging.capabilitiesVerbosity = "None"; + break; + case Parameters::Logging::Verbosity::Minimal: + c.logging.capabilitiesVerbosity = "Minimal"; + break; + case Parameters::Logging::Verbosity::Default: + c.logging.capabilitiesVerbosity = "Default"; + break; + case Parameters::Logging::Verbosity::Full: + c.logging.capabilitiesVerbosity = "Full"; + break; + default: + throw ghoul::MissingCaseException(); + } + } + } + + if (p.documentation.has_value()) { + c.documentation.path = p.documentation->path.value_or(c.documentation.path); + } + + if (p.loadingScreen.has_value()) { + const Parameters::LoadingScreen& l = *p.loadingScreen; + c.loadingScreen.isShowingMessages = + l.showMessage.value_or(c.loadingScreen.isShowingMessages); + c.loadingScreen.isShowingProgressbar = + l.showProgressbar.value_or(c.loadingScreen.isShowingProgressbar); + c.loadingScreen.isShowingNodeNames = + l.showNodeNames.value_or(c.loadingScreen.isShowingNodeNames); + } + + c.moduleConfigurations = p.moduleConfigurations.value_or(c.moduleConfigurations); + + if (p.openGLDebugContext.has_value()) { + const Parameters::OpenGLDebugContext& l = *p.openGLDebugContext; + c.openGLDebugContext.isActive = l.activate; + c.openGLDebugContext.isSynchronous = l.synchronous.value_or( + c.openGLDebugContext.isSynchronous + ); + if (l.filterIdentifier.has_value()) { + for (const Parameters::OpenGLDebugContext::Filter& f : *l.filterIdentifier) { + Configuration::OpenGLDebugContext::IdentifierFilter filter; + filter.identifier = static_cast(f.identifier); + switch (f.source) { + case Parameters::OpenGLDebugContext::Filter::Source::API: + filter.source = "API"; + break; + case Parameters::OpenGLDebugContext::Filter::Source::WindowSystem: + filter.source = "Window System"; + break; + case Parameters::OpenGLDebugContext::Filter::Source::ShaderCompiler: + filter.source = "Shader Compiler"; + break; + case Parameters::OpenGLDebugContext::Filter::Source::ThirdParty: + filter.source = "Third Party"; + break; + case Parameters::OpenGLDebugContext::Filter::Source::Application: + filter.source = "Application"; + break; + case Parameters::OpenGLDebugContext::Filter::Source::Other: + filter.source = "Other"; + break; + case Parameters::OpenGLDebugContext::Filter::Source::DontCare: + filter.source = "Don't care"; + break; + default: + throw ghoul::MissingCaseException(); + } + switch (f.type) { + case Parameters::OpenGLDebugContext::Filter::Type::Error: + filter.type = "Error"; + break; + case Parameters::OpenGLDebugContext::Filter::Type::Deprecated: + filter.type = "Deprecated"; + break; + case Parameters::OpenGLDebugContext::Filter::Type::Undefined: + filter.type = "Undefined"; + break; + case Parameters::OpenGLDebugContext::Filter::Type::Portability: + filter.type = "Portability"; + break; + case Parameters::OpenGLDebugContext::Filter::Type::Performance: + filter.type = "Performance"; + break; + case Parameters::OpenGLDebugContext::Filter::Type::Marker: + filter.type = "Marker"; + break; + case Parameters::OpenGLDebugContext::Filter::Type::PushGroup: + filter.type = "Push group"; + break; + case Parameters::OpenGLDebugContext::Filter::Type::PopGroup: + filter.type = "Pop group"; + break; + case Parameters::OpenGLDebugContext::Filter::Type::Other: + filter.type = "Other"; + break; + case Parameters::OpenGLDebugContext::Filter::Type::DontCare: + filter.type = "Don't care"; + break; + default: + throw ghoul::MissingCaseException(); + } + + c.openGLDebugContext.identifierFilters.push_back(filter); + } + } + if (l.filterSeverity.has_value()) { + for (Parameters::OpenGLDebugContext::Severity sev : *l.filterSeverity) { + std::string severity; + switch (sev) { + case Parameters::OpenGLDebugContext::Severity::High: + severity = "High"; + break; + case Parameters::OpenGLDebugContext::Severity::Medium: + severity = "Medium"; + break; + case Parameters::OpenGLDebugContext::Severity::Low: + severity = "Low"; + break; + case Parameters::OpenGLDebugContext::Severity::Notification: + severity = "Notification"; + break; + default: + throw ghoul::MissingCaseException(); + } + c.openGLDebugContext.severityFilters.push_back(severity); + } + } + } + + if (p.httpProxy.has_value()) { + c.httpProxy.usingHttpProxy = + p.httpProxy->activate.value_or(c.httpProxy.usingHttpProxy); + c.httpProxy.address = p.httpProxy->address; + c.httpProxy.port = static_cast(p.httpProxy->port); + if (p.httpProxy->authentication.has_value()) { + switch (*p.httpProxy->authentication) { + case Parameters::HttpProxy::Authentication::Basic: + c.httpProxy.authentication = "basic"; + break; + case Parameters::HttpProxy::Authentication::Ntlm: + c.httpProxy.authentication = "ntlm"; + break; + case Parameters::HttpProxy::Authentication::Digest: + c.httpProxy.authentication = "digest"; + break; + case Parameters::HttpProxy::Authentication::Any: + c.httpProxy.authentication = "any"; + break; + default: + throw ghoul::MissingCaseException(); + } + } + c.httpProxy.user = p.httpProxy->user.value_or(c.httpProxy.user); + c.httpProxy.password = p.httpProxy->password.value_or(c.httpProxy.password); + } + + c.readOnlyProfiles = p.readOnlyProfiles.value_or(c.readOnlyProfiles); + c.bypassLauncher = p.bypassLauncher.value_or(c.bypassLauncher); } +documentation::Documentation Configuration::Documentation = codegen::doc(); + std::string findConfiguration(const std::string& filename) { using ghoul::filesystem::Directory; @@ -383,16 +637,14 @@ std::string findConfiguration(const std::string& filename) { } } -Configuration loadConfigurationFromFile(const std::string& filename) { +Configuration loadConfigurationFromFile(const std::string& filename, + const std::string& overrideScript) +{ ghoul_assert(!filename.empty(), "Filename must not be empty"); ghoul_assert(FileSys.fileExists(filename), "File must exist"); Configuration result; - // Register the base path as the directory where 'filename' lives - std::string basePath = ghoul::filesystem::File(filename).directoryName(); - FileSys.registerPathToken(BasePathToken, basePath); - // If there is an initial config helper file, load it into the state if (FileSys.fileExists(absPath(InitialConfigHelper))) { ghoul::lua::runScriptFile(result.state, absPath(InitialConfigHelper)); @@ -401,6 +653,12 @@ Configuration loadConfigurationFromFile(const std::string& filename) { // Load the configuration file into the state ghoul::lua::runScriptFile(result.state, filename); + if (!overrideScript.empty()) { + LDEBUGC("Configuration", "Executing Lua script passed through the commandline:"); + LDEBUGC("Configuration", overrideScript); + ghoul::lua::runScript(result.state, overrideScript); + } + parseLuaState(result); return result; diff --git a/src/engine/configuration_doc.inl b/src/engine/configuration_doc.inl deleted file mode 100644 index 16430a7c0c..0000000000 --- a/src/engine/configuration_doc.inl +++ /dev/null @@ -1,450 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2021 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include -#include - -namespace openspace::configuration { - -using namespace documentation; -documentation::Documentation Configuration::Documentation = { - "OpenSpace Configuration", - "openspace_configuraion", - { - { - KeySGCTConfig, - new StringAnnotationVerifier("A valid SGCT configuration file"), - Optional::Yes, - "The SGCT configuration file that determines the window and view frustum " - "settings that are being used when OpenSpace is started." - }, - { - KeySgctConfigNameInitialized, - new StringAnnotationVerifier("The type of SGCT autogen function (if called)"), - Optional::Yes, - "The SGCT configuration can be defined from an .xml file, or auto-generated " - "by an sgct.config.* lua function. If a lua function is used to generate the " - "SGCT configuration, then this key contains the name of the function, " - "otherwise is blank." - }, - { - KeyAsset, - new StringAnnotationVerifier( - "A valid scene file as described in the Scene documentation" - ), - Optional::Yes, - "The scene description that is used to populate the application after " - "startup. The scene determines which objects are loaded, the startup " - "time and other scene-specific settings. More information is provided in " - "the Scene documentation." - }, - { - KeyGlobalCustomizationScripts, - new StringListVerifier, - Optional::Yes, - "This value names a list of scripts that get executed after initialization " - "of any scene. These scripts can be used for user-specific customization, " - "such as a global rebinding of keys from the default." - }, - { - KeyPaths, - new StringListVerifier, - Optional::No, - "A list of paths that are automatically registered with the file system. " - "If a key X is used in the table, it is then useable by referencing ${X} " - "in all other configuration files or scripts." - }, - { - KeyFonts, - new StringListVerifier("Font paths loadable by FreeType"), - Optional::Yes, - "A list of all fonts that will automatically be loaded on startup. Each " - "key-value pair contained in the table will become the name and the file " - "for a font." - }, - { - KeyLogging, - new TableVerifier({ - { - KeyLogDir, - new StringVerifier, - Optional::Yes, - "The directory for logs. Default value is \"${BASE}\"" - }, - { - KeyPerformancePrefix, - new StringVerifier, - Optional::Yes, - "A string to prefix PerformanceMeasurement logfiles." - "Default value is \"PM-\"" - }, - { - KeyLogLevel, - new StringInListVerifier( - // List from logmanager.cpp::levelFromString - { "Trace", "Debug", "Info", "Warning", "Error", "Fatal", "None" } - ), - Optional::Yes, - "The severity of log messages that will be displayed. Only " - "messages of the selected level or higher will be displayed. All " - "levels below will be silently discarded. The order of " - "severities is: Debug < Info < Warning < Error < Fatal < None." - }, - { - KeyImmediateFlush, - new BoolVerifier, - Optional::Yes, - "Determines whether error messages will be displayed immediately " - "or if it is acceptable to have a short delay, but being more " - "performant. If the delay is allowed ('true'), messages might " - "get lost if the application crashes shortly after a message was " - "logged." - }, - { - KeyLogs, - new TableVerifier({ - { - "*", - new ReferencingVerifier("core_logfactory"), - Optional::No, - "Additional log files" - } - }), - Optional::Yes, - "Per default, log messages are written to the console, the " - "onscreen text, and (if available) the Visual Studio output " - "window. This table can define other logging methods that will " - "be used additionally." - }, - { - KeyCapabilitiesVerbosity, - new StringInListVerifier( - // List from OpenspaceEngine::initialize - { "None", "Minimal", "Default", "Full" } - ), - Optional::Yes, - "At startup, a list of system capabilities is created and logged." - "This value determines how verbose this listing should be." - } - }), - Optional::Yes, - "Configurations for the logging of messages that are generated " - "throughout the code and are useful for debugging potential errors or " - "other information." - }, - { - KeyScriptLog, - new StringVerifier, - Optional::Yes, - "The file that will be created on startup containing the log of all Lua " - "scripts that are executed in the last session. Any existing file (including " - "the results from previous runs) will be silently overwritten." - }, - { - KeyDocumentationPath, - new TableVerifier({ - { - KeyDocumentationPath, - new StringVerifier, - Optional::Yes, - "The path where the documentation files will be stored." - }, - }), - Optional::Yes, - "Right now only contains the path where the documentation is written to." - }, - { - KeyShutdownCountdown, - new DoubleGreaterEqualVerifier(0.0), - Optional::Yes, - "The countdown that the application will wait between pressing ESC and " - "actually shutting down. If ESC is pressed again in this time, the " - "shutdown is aborted." - }, - { - KeyPerSceneCache, - new BoolVerifier, - Optional::Yes, - "If this is set to 'true', the name of the scene will be appended to the " - "cache directory, thus not reusing the same directory. This is useful in " - "cases where the same instance of OpenSpace is run with multiple scenes, but " - "the caches should be retained. This value defaults to 'false'." - }, - { - KeyOnScreenTextScaling, - new StringInListVerifier({ - // Values from RenderEngine:updateRenderer - "window", "framebuffer" - }), - Optional::Yes, - "The method for scaling the onscreen text in the window. As the resolution " - "of the rendering can be different from the size of the window, the onscreen " - "text can either be scaled according to the window size ('window'), or the " - "rendering resolution ('framebuffer'). This value defaults to 'window'." - }, - { - KeyRenderingMethod, - new StringInListVerifier( - // List from RenderEngine::setRendererFromString - { "Framebuffer", "ABuffer" } - ), - Optional::Yes, - "The renderer that is use after startup. The renderer 'ABuffer' requires " - "support for at least OpenGL 4.3" - }, - { - KeyDisableRenderingOnMaster, - new BoolVerifier, - Optional::Yes, - "Toggles whether the master in a multi-application setup should be rendering " - "or just managing the state of the network. This is desired in cases where " - "the master computer does not have the resources to render a scene." - }, - { - KeyGlobalRotation, - new DoubleVector3Verifier, - Optional::Yes, - "Applies a global view rotation. Use this to rotate the position of the " - "focus node away from the default location on the screen. This setting " - "persists even when a new focus node is selected. Defined using roll, pitch, " - "yaw in radians" - }, - { - KeyMasterRotation, - new DoubleVector3Verifier, - Optional::Yes, - "Applies a view rotation for only the master node, defined using " - "roll, pitch yaw in radians. This can be used to compensate the master view " - "direction for tilted display systems in clustered immersive environments." - }, - { - KeyScreenSpaceRotation, - new DoubleVector3Verifier, - Optional::Yes, - "Applies a global rotation for all screenspace renderables. Defined using " - "roll, pitch, yaw in radians." - }, - { - KeyScreenshotUseDate, - new BoolVerifier, - Optional::Yes, - "Toggles whether screenshots generated by OpenSpace contain the date when " - "the concrete OpenSpace instance was started. This value is enabled by " - "default, but it is advised to disable this value if rendering sessions of " - "individual frames pass beyond local midnight." - }, - { - KeyHttpProxy, - new TableVerifier({ - { - KeyActivate, - new BoolVerifier, - Optional::Yes, - "Determines whether the proxy is being used" - }, - { - KeyAddress, - new StringVerifier, - Optional::No, - "The address of the http proxy" - }, - { - KeyPort, - new IntVerifier, - Optional::No, - "The port of the http proxy" - }, - { - KeyAuthentication, - new StringInListVerifier( - { "basic", "ntlm", "digest", "any" } - ), - Optional::Yes, - "The authentication method of the http proxy" - }, - { - KeyUser, - new StringVerifier, - Optional::Yes, - "The user of the http proxy" - }, - { - KeyPassword, - new StringVerifier, - Optional::Yes, - "The password of the http proxy" - } - }), - Optional::Yes, - "This defines the use for a proxy when fetching data over http." - "No proxy will be used if this is left out." - }, - { - KeyOpenGLDebugContext, - new TableVerifier({ - { - KeyActivate, - new BoolVerifier, - Optional::No, - "Determines whether the OpenGL context should be a debug context" - }, - { - KeySynchronous, - new BoolVerifier, - Optional::Yes, - "Determines whether the OpenGL debug callbacks are performed " - "synchronously. If set to the callbacks are in the same " - "thread as the context and in the scope of the OpenGL function that " - "triggered the message. The default value is ." - }, - { - KeyFilterIdentifier, - new TableVerifier({{ - "*", - new TableVerifier({ - { - KeyIdentifier, - new IntVerifier, - Optional::No, - "The identifier that is to be filtered" - }, - { - KeySource, - new StringInListVerifier({ - // Taken from ghoul::debugcontext.cpp - "API", "Window System", "Shader Compiler", - "Third Party", "Application", "Other", "Don't care" - }), - Optional::No, - "The source of the identifier to be filtered" - }, - { - KeyType, - new StringInListVerifier({ - // Taken from ghoul::debugcontext.cpp - "Error", "Deprecated", "Undefined", "Portability", - "Performance", "Marker", "Push group", "Pop group", - "Other", "Don't care" - }), - Optional::No, - "The type of the identifier to be filtered" - } - }), - Optional::No, - "Individual OpenGL debug message identifiers" - }}), - Optional::Yes, - "A list of OpenGL debug messages identifiers that are filtered" - }, - { - KeyFilterSeverity, - new TableVerifier({ - { - "*", - new StringInListVerifier( - // ghoul::debugcontext.cpp - { "High", "Medium", "Low", "Notification" } - ), - Optional::No - } - }), - Optional::Yes, - "A list of severities that can are filtered out" - } - }), - Optional::Yes, - "Determines the settings for the creation of an OpenGL debug context.", - }, - { - KeyCheckOpenGLState, - new BoolVerifier, - Optional::Yes, - "Determines whether the OpenGL state is checked after each OpenGL function " - "call. This will dramatically slow down the rendering, but will make finding " - "OpenGL errors easier. This defaults to 'false'." - }, - { - KeyLogEachOpenGLCall, - new BoolVerifier, - Optional::Yes, - "Determines whether each OpenGL call that happens should be logged using the " - "'TRACE' loglevel. This will bring the rendering to a crawl but provides " - "useful debugging features for the order in which OpenGL calls occur. This " - "defaults to 'false'." - }, - { - KeyUseMultithreadedInitialization, - new BoolVerifier, - Optional::Yes, - "This value determines whether the initialization of the scene graph should " - "occur multithreaded, that is, whether multiple scene graph nodes should " - "initialize in parallel. The only use for this value is to disable it for " - "debugging support." - }, - { - KeyLoadingScreen, - new TableVerifier({ - { - KeyShowMessage, - new BoolVerifier, - Optional::Yes, - "If this value is set to 'true', the loading screen will display a " - "message information about the current phase the loading is in." - }, - { - KeyShowNodeNames, - new BoolVerifier, - Optional::Yes, - "If this value is set to 'true', the loading screen will display a " - "list of all of the nodes with their respective status (created, " - "loaded, initialized)." - }, - { - KeyShowProgressbar, - new BoolVerifier, - Optional::Yes, - "If this value is set to 'true', the loading screen will contain a " - "progress bar that gives an estimate of the loading progression." - } - }), - Optional::Yes, - "Values in this table describe the behavior of the loading screen that is " - "displayed while the scene graph is created and initialized." - }, - { - KeyModuleConfigurations, - new TableVerifier, - Optional::Yes, - "Configurations for each module" - }, - { - KeyReadOnlyProfiles, - new StringListVerifier, - Optional::Yes, - "List of profiles that cannot be overwritten by user" - } - } -}; - -} // namespace openspace::configuration diff --git a/src/engine/logfactory.cpp b/src/engine/logfactory.cpp index a1f65f8898..90633d26e6 100644 --- a/src/engine/logfactory.cpp +++ b/src/engine/logfactory.cpp @@ -32,186 +32,130 @@ #include #include #include +#include namespace { - constexpr const char* KeyType = "Type"; - constexpr const char* KeyFilename = "File"; - constexpr const char* KeyAppend = "Append"; - constexpr const char* KeyTimeStamping = "TimeStamping"; - constexpr const char* KeyDateStamping = "DateStamping"; - constexpr const char* KeyCategoryStamping = "CategoryStamping"; - constexpr const char* KeyLogLevelStamping = "LogLevelStamping"; - constexpr const char* KeyLogLevel = "LogLevel"; - - constexpr const char* ValueHtmlLog = "html"; - constexpr const char* ValueTextLog = "Text"; - constexpr const char* BootstrapPath = "${WEB}/common/bootstrap.min.css"; constexpr const char* CssPath = "${WEB}/log/style.css"; constexpr const char* JsPath = "${WEB}/log/script.js"; + + struct [[codegen::Dictionary(LogFactory)]] Parameters { + enum class Type { + Html [[codegen::key("html")]], + Text + }; + // The type of the new log to be generated + Type type; + + // The filename to which the log will be written + std::string file; + + // Determines whether the file will be cleared at startup or if the contents will + // be appended to previous runs + std::optional append; + + // Determines whether the log entires should be stamped with the time at which the + // message was logged + std::optional timeStamping; + + // Determines whether the log entries should be stamped with the date at which the + // message was logged + std::optional dateStamping; + + // Determines whether the log entries should be stamped with the category that + // creates the log message + std::optional categoryStamping; + + // Determines whether the log entries should be stamped with the log level that + // was used to create the log message + std::optional logLevelStamping; + + enum class LogLevel { + AllLogging, + Trace, + Debug, + Info, + Warning, + Error, + Fatal, + NoLogging + }; + // The log level for this specific text-based log + std::optional logLevel; + }; +#include "logfactory_codegen.cpp" } // namespace namespace openspace { documentation::Documentation LogFactoryDocumentation() { - using namespace documentation; - - return { - "LogFactory", - "core_logfactory", - { - { - KeyType, - new StringInListVerifier({ - // List from createLog - ValueTextLog, ValueHtmlLog - }), - Optional::No, - "The type of the new log to be generated." - }, - { - KeyFilename, - new StringVerifier, - Optional::No, - "The filename to which the log will be written." - }, - { - KeyAppend, - new BoolVerifier, - Optional::Yes, - "Determines whether the file will be cleared at startup or if the " - "contents will be appended to previous runs." - }, - { - KeyTimeStamping, - new BoolVerifier, - Optional::Yes, - "Determines whether the log entires should be stamped with the time at " - "which the message was logged." - }, - { - KeyDateStamping, - new BoolVerifier, - Optional::Yes, - "Determines whether the log entries should be stamped with the date at " - "which the message was logged." - }, - { - KeyCategoryStamping, - new BoolVerifier, - Optional::Yes, - "Determines whether the log entries should be stamped with the " - "category that creates the log message." - }, - { - KeyLogLevelStamping, - new BoolVerifier, - Optional::Yes, - "Determines whether the log entries should be stamped with the log level " - "that was used to create the log message." - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "core_logfactory"; + return doc; } std::unique_ptr createLog(const ghoul::Dictionary& dictionary) { - documentation::testSpecificationAndThrow( - LogFactoryDocumentation(), - dictionary, - "LogFactory" - ); + const Parameters p = codegen::bake(dictionary); - // 'type' and 'filename' are required keys - const std::string& type = dictionary.value(KeyType); - const std::string& filename = absPath(dictionary.value(KeyFilename)); - - // the rest are optional - bool append = true; - if (dictionary.hasValue(KeyAppend)) { - append = dictionary.value(KeyAppend); - } - bool timeStamp = true; - if (dictionary.hasValue(KeyTimeStamping)) { - timeStamp = dictionary.value(KeyTimeStamping); - } - bool dateStamp = true; - if (dictionary.hasValue(KeyDateStamping)) { - dateStamp = dictionary.value(KeyDateStamping); - } - bool categoryStamp = true; - if (dictionary.hasValue(KeyCategoryStamping)) { - categoryStamp = dictionary.value(KeyCategoryStamping); - } - bool logLevelStamp = true; - if (dictionary.hasValue(KeyLogLevelStamping)) { - logLevelStamp = dictionary.value(KeyLogLevelStamping); - } - std::string logLevel; - if (dictionary.hasValue(KeyLogLevel)) { - logLevel = dictionary.value(KeyLogLevel); - } - - using Append = ghoul::logging::TextLog::Append; - using TimeStamping = ghoul::logging::Log::TimeStamping; - using DateStamping = ghoul::logging::Log::DateStamping; - using CategoryStamping = ghoul::logging::Log::CategoryStamping; - using LogLevelStamping = ghoul::logging::Log::LogLevelStamping; - - if (type == ValueHtmlLog) { - std::vector cssFiles{absPath(BootstrapPath), absPath(CssPath)}; - std::vector jsFiles{absPath(JsPath)}; - - if (logLevel.empty()) { - return std::make_unique( - filename, - Append(append), - TimeStamping(timeStamp), - DateStamping(dateStamp), - CategoryStamping(categoryStamp), - LogLevelStamping(logLevelStamp), - cssFiles, - jsFiles - ); + std::string filename = absPath(p.file); + bool append = p.append.value_or(true); + bool timeStamp = p.timeStamping.value_or(true); + bool dateStamp = p.dateStamping.value_or(true); + bool categoryStamp = p.categoryStamping.value_or(true); + bool logLevelStamp = p.logLevelStamping.value_or(true); + ghoul::logging::LogLevel level = [](Parameters::LogLevel l) { + switch (l) { + case Parameters::LogLevel::AllLogging: + return ghoul::logging::LogLevel::AllLogging; + case Parameters::LogLevel::Trace: + return ghoul::logging::LogLevel::Trace; + case Parameters::LogLevel::Debug: + return ghoul::logging::LogLevel::Debug; + case Parameters::LogLevel::Info: + return ghoul::logging::LogLevel::Info; + case Parameters::LogLevel::Warning: + return ghoul::logging::LogLevel::Warning; + case Parameters::LogLevel::Error: + return ghoul::logging::LogLevel::Error; + case Parameters::LogLevel::Fatal: + return ghoul::logging::LogLevel::Fatal; + case Parameters::LogLevel::NoLogging: + return ghoul::logging::LogLevel::NoLogging; + default: + throw ghoul::MissingCaseException(); } - else { + }(p.logLevel.value_or(Parameters::LogLevel::AllLogging)); + + switch (p.type) { + case Parameters::Type::Html: + { + std::vector cssFiles{ absPath(BootstrapPath), absPath(CssPath) }; + std::vector jsFiles{ absPath(JsPath) }; + return std::make_unique( filename, - Append(append), - TimeStamping(timeStamp), - DateStamping(dateStamp), - CategoryStamping(categoryStamp), - LogLevelStamping(logLevelStamp), + ghoul::logging::TextLog::Append(append), + ghoul::logging::Log::TimeStamping(timeStamp), + ghoul::logging::Log::DateStamping(dateStamp), + ghoul::logging::Log::CategoryStamping(categoryStamp), + ghoul::logging::Log::LogLevelStamping(logLevelStamp), cssFiles, jsFiles, - ghoul::from_string(logLevel) - ); + level + ); } - } - else if (type == ValueTextLog) { - if (logLevel.empty()) { + case Parameters::Type::Text: return std::make_unique( filename, - Append(append), - TimeStamping(timeStamp), - DateStamping(dateStamp), - CategoryStamping(categoryStamp), - LogLevelStamping(logLevelStamp) + ghoul::logging::TextLog::Append(append), + ghoul::logging::Log::TimeStamping(timeStamp), + ghoul::logging::Log::DateStamping(dateStamp), + ghoul::logging::Log::CategoryStamping(categoryStamp), + ghoul::logging::Log::LogLevelStamping(logLevelStamp), + level ); - } - else { - return std::make_unique( - filename, - Append(append), - TimeStamping(timeStamp), - DateStamping(dateStamp), - CategoryStamping(categoryStamp), - LogLevelStamping(logLevelStamp), - ghoul::from_string(logLevel) - ); - } - } - else { - throw ghoul::MissingCaseException(); + default: + throw new ghoul::MissingCaseException(); } } diff --git a/src/engine/moduleengine.cpp b/src/engine/moduleengine.cpp index 05d98a3a04..e2e8836265 100644 --- a/src/engine/moduleengine.cpp +++ b/src/engine/moduleengine.cpp @@ -63,7 +63,6 @@ void ModuleEngine::initialize( m->initialize(configuration); } catch (const documentation::SpecificationError& e) { - //LFATALC(e.component, e.message); for (const documentation::TestResult::Offense& o : e.result.offenses) { LERRORC(e.component, o.offender + ": " + ghoul::to_string(o.reason)); } diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index 7c306ddc2d..2eca8e12f4 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -1609,8 +1609,8 @@ scripting::LuaLibrary OpenSpaceEngine::luaLibrary() { "Removes a tag (second argument) from a scene graph node (first argument)" }, { - "createSingeColorImage", - &luascriptfunctions::createSingeColorImage, + "createSingleColorImage", + &luascriptfunctions::createSingleColorImage, {}, "string, vec3", "Creates a 1 pixel image with a certain color in the cache folder and " diff --git a/src/engine/openspaceengine_lua.inl b/src/engine/openspaceengine_lua.inl index c52a1dae18..d5881b8ada 100644 --- a/src/engine/openspaceengine_lua.inl +++ b/src/engine/openspaceengine_lua.inl @@ -294,11 +294,11 @@ int downloadFile(lua_State* L) { /** * \ingroup LuaScripts -* createSingeColorImage(): +* createSingleColorImage(): * Creates a one pixel image with a given color and returns the path to the cached file */ -int createSingeColorImage(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::createSingeColorImage"); +int createSingleColorImage(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::createSingleColorImage"); const std::string& name = ghoul::lua::value(L, 1); const ghoul::Dictionary& d = ghoul::lua::value(L, 2); @@ -306,11 +306,10 @@ int createSingeColorImage(lua_State* L) { // @TODO (emmbr 2020-12-18) Verify that the input dictionary is a vec3 // Would like to clean this up with a more direct use of the Verifier in the future - using namespace openspace::documentation; const std::string& key = "color"; ghoul::Dictionary colorDict; colorDict.setValue(key, d); - TestResult res = Color3Verifier()(colorDict, key); + documentation::TestResult res = documentation::Color3Verifier()(colorDict, key); if (!res.success) { return ghoul::lua::luaError( diff --git a/src/interaction/joystickcamerastates.cpp b/src/interaction/joystickcamerastates.cpp index 75c0e40306..78a9f97506 100644 --- a/src/interaction/joystickcamerastates.cpp +++ b/src/interaction/joystickcamerastates.cpp @@ -56,8 +56,7 @@ void JoystickCameraStates::updateStateFromInput(const InputState& inputState, float value = inputState.joystickAxis(i); if (std::fabs(value) <= t.deadzone) { - value = 0.f; - hasValue = false; + continue; } if (t.normalize) { diff --git a/src/interaction/navigationhandler.cpp b/src/interaction/navigationhandler.cpp index fa3aefb28f..203a674f1e 100644 --- a/src/interaction/navigationhandler.cpp +++ b/src/interaction/navigationhandler.cpp @@ -44,13 +44,6 @@ namespace { constexpr const char* _loggerCat = "NavigationHandler"; - constexpr const char* KeyAnchor = "Anchor"; - constexpr const char* KeyAim = "Aim"; - constexpr const char* KeyPosition = "Position"; - constexpr const char* KeyUp = "Up"; - constexpr const char* KeyYaw = "Yaw"; - constexpr const char* KeyPitch = "Pitch"; - constexpr const char* KeyReferenceFrame = "ReferenceFrame"; const double Epsilon = 1E-7; using namespace openspace; @@ -73,6 +66,31 @@ namespace { "than using the mouse interaction." }; + struct [[codegen::Dictionary(NavigationHandler)]] Parameters { + // The identifier of the anchor node + std::string anchor; + + // The identifier of the aim node, if used + std::optional aim; + + // The identifier of the scene graph node to use as reference frame. If not + // specified, this will be the same as the anchor + std::optional referenceFrame; + + // The position of the camera relative to the anchor node, expressed in meters in + // the specified reference frame + glm::dvec3 position; + + // The up vector expressed in the coordinate system of the reference frame + std::optional up; + + // The yaw angle in radians. Positive angle means yawing camera to the right + std::optional yaw; + + // The pitch angle in radians. Positive angle means pitching camera upwards + std::optional pitch; + }; +#include "navigationhandler_codegen.cpp" } // namespace #include "navigationhandler_lua.inl" @@ -80,6 +98,14 @@ namespace { namespace openspace::interaction { ghoul::Dictionary NavigationHandler::NavigationState::dictionary() const { + constexpr const char* KeyAnchor = "Anchor"; + constexpr const char* KeyAim = "Aim"; + constexpr const char* KeyPosition = "Position"; + constexpr const char* KeyUp = "Up"; + constexpr const char* KeyYaw = "Yaw"; + constexpr const char* KeyPitch = "Pitch"; + constexpr const char* KeyReferenceFrame = "ReferenceFrame"; + ghoul::Dictionary cameraDict; cameraDict.setValue(KeyPosition, position); cameraDict.setValue(KeyAnchor, anchor); @@ -105,36 +131,19 @@ ghoul::Dictionary NavigationHandler::NavigationState::dictionary() const { } NavigationHandler::NavigationState::NavigationState(const ghoul::Dictionary& dictionary) { - const bool hasAnchor = dictionary.hasValue(KeyAnchor); - const bool hasPosition = dictionary.hasValue(KeyPosition); - if (!hasAnchor || !hasPosition) { - throw ghoul::RuntimeError( - "Position and Anchor need to be defined for navigation dictionary." - ); - } + const Parameters p = codegen::bake(dictionary); - anchor = dictionary.value(KeyAnchor); - position = dictionary.value(KeyPosition); + anchor = p.anchor; + position = p.position; - if (dictionary.hasValue(KeyReferenceFrame)) { - referenceFrame = dictionary.value(KeyReferenceFrame); - } - else { - referenceFrame = anchor; - } - if (dictionary.hasValue(KeyAim)) { - aim = dictionary.value(KeyAim); - } + referenceFrame = p.referenceFrame.value_or(anchor); + aim = p.aim.value_or(aim); - if (dictionary.hasValue(KeyUp)) { - up = dictionary.value(KeyUp); + if (p.up.has_value()) { + up = *p.up; - if (dictionary.hasValue(KeyYaw)) { - yaw = dictionary.value(KeyYaw); - } - if (dictionary.hasValue(KeyPitch)) { - pitch = dictionary.value(KeyPitch); - } + yaw = p.yaw.value_or(yaw); + pitch = p.pitch.value_or(pitch); } } @@ -142,8 +151,7 @@ NavigationHandler::NavigationState::NavigationState(std::string anchor_, std::st std::string referenceFrame_, glm::dvec3 position_, std::optional up_, - double yaw_, - double pitch_) + double yaw_, double pitch_) : anchor(std::move(anchor_)) , aim(std::move(aim_)) , referenceFrame(std::move(referenceFrame_)) @@ -545,60 +553,9 @@ std::vector NavigationHandler::joystickButtonCommand(int button) co } documentation::Documentation NavigationHandler::NavigationState::Documentation() { - using namespace documentation; - - return { - "Navigation State", - "core_navigation_state", - { - { - KeyAnchor, - new StringVerifier, - Optional::No, - "The identifier of the anchor node." - }, - { - KeyAim, - new StringVerifier, - Optional::Yes, - "The identifier of the aim node, if used." - }, - { - KeyReferenceFrame, - new StringVerifier, - Optional::Yes, - "The identifier of the scene graph node to use as reference frame. " - "If not specified, this will be the same as the anchor." - }, - { - KeyPosition, - new DoubleVector3Verifier, - Optional::No, - "The position of the camera relative to the anchor node, " - "expressed in meters in the specified reference frame." - }, - { - KeyUp, - new DoubleVector3Verifier, - Optional::Yes, - "The up vector expressed in the coordinate system of the reference frame." - }, - { - KeyYaw, - new DoubleVerifier, - Optional::Yes, - "The yaw angle in radians. " - "Positive angle means yawing camera to the right." - }, - { - KeyPitch, - new DoubleVerifier, - Optional::Yes, - "The pitch angle in radians. " - "Positive angle means pitching camera upwards." - }, - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "core_navigation_state"; + return doc; } scripting::LuaLibrary NavigationHandler::luaLibrary() { diff --git a/src/mission/mission.cpp b/src/mission/mission.cpp index 95c63cadf3..feadaac081 100644 --- a/src/mission/mission.cpp +++ b/src/mission/mission.cpp @@ -29,73 +29,47 @@ #include #include #include +#include namespace { - constexpr const char* KeyName = "Name"; - constexpr const char* KeyDescription = "Description"; - constexpr const char* KeyPhases = "Phases"; - constexpr const char* KeyTimeRange = "TimeRange"; + struct [[codegen::Dictionary(MissionPhase)]] Parameters { + // The human readable name of this mission or mission phase that is displayed to + // the user + std::string name; + + // A description of this mission or mission phase + std::optional description; + + // The time range for which this mission or mission phase is valid. If no time + // range is specified, the ranges of sub mission phases are used instead + std::optional timeRange + [[codegen::reference("core_util_timerange")]]; + + // The phases into which this mission or mission phase is separated + std::optional> phases + [[codegen::reference("core_mission_mission")]]; + }; +#include "mission_codegen.cpp" } // namespace namespace openspace { documentation::Documentation MissionPhase::Documentation() { - using namespace documentation; - - return { - "Missions and Mission Phases", - "core_mission_mission", - { - { - KeyName, - new StringVerifier, - Optional::No, - "The human readable name of this mission or mission phase that is " - "displayed to the user." - }, - { - KeyDescription, - new StringVerifier, - Optional::Yes, - "A description of this mission or mission phase." - }, - { - KeyTimeRange, - new ReferencingVerifier("core_util_timerange"), - Optional::Yes, - "The time range for which this mission or mission phase is valid. If no " - "time range is specified, the ranges of sub mission phases are used " - "instead." - }, - { - KeyPhases, - new TableVerifier({ - { - "*", - new ReferencingVerifier("core_mission_mission"), - Optional::Yes - } - }), - Optional::Yes, - "The phases into which this mission or mission phase is separated." - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "core_mission_mission"; + return doc; } MissionPhase::MissionPhase(const ghoul::Dictionary& dictionary) { - _name = dictionary.value(KeyName); - if (dictionary.hasValue(KeyDescription)) { - _description = dictionary.value(KeyDescription); - } + const Parameters p = codegen::bake(dictionary); - if (dictionary.hasValue(KeyPhases)) { - ghoul::Dictionary childDicts = dictionary.value(KeyPhases); - // This is a nested mission phase - _subphases.reserve(childDicts.size()); - for (size_t i = 0; i < childDicts.size(); ++i) { - std::string key = std::to_string(i + 1); - _subphases.emplace_back(childDicts.value(key)); + _name = p.name; + _description = p.description.value_or(_description); + + if (p.phases.has_value()) { + _subphases.reserve(p.phases->size()); + for (const ghoul::Dictionary& phase : *p.phases) { + _subphases.emplace_back(phase); } // Ensure subphases are sorted @@ -112,15 +86,14 @@ MissionPhase::MissionPhase(const ghoul::Dictionary& dictionary) { timeRangeSubPhases.start = _subphases[0].timeRange().start; timeRangeSubPhases.end = _subphases.back().timeRange().end; - // user may specify an overall time range. In that case expand this timerange. - if (dictionary.hasValue(KeyTimeRange)) { - ghoul::Dictionary range = dictionary.value(KeyTimeRange); - TimeRange overallTimeRange(range); + // user may specify an overall time range. In that case expand this timerange + if (p.timeRange.has_value()) { + TimeRange overallTimeRange(*p.timeRange); if (!overallTimeRange.includes(timeRangeSubPhases)) { - throw ghoul::RuntimeError( + throw ghoul::RuntimeError(fmt::format( "User specified time range must at least include its subphases'", - "Mission (" + _name + ")" - ); + "Mission ({})", _name + )); } _timeRange.include(overallTimeRange); @@ -132,16 +105,14 @@ MissionPhase::MissionPhase(const ghoul::Dictionary& dictionary) { } } else { - if (dictionary.hasValue(KeyTimeRange)) { - ghoul::Dictionary timeRangeDict = - dictionary.value(KeyTimeRange); - _timeRange = TimeRange(timeRangeDict); // throws exception if unable to parse + if (p.timeRange.has_value()) { + _timeRange = TimeRange(*p.timeRange); // throws exception if unable to parse } else { - throw ghoul::RuntimeError( + throw ghoul::RuntimeError(fmt::format( "If there are no subphases specified, the time range has to be specified", - "Mission (" + _name + ")" - ); + "Mission ({})", _name + )); } } } diff --git a/src/rendering/dashboarditem.cpp b/src/rendering/dashboarditem.cpp index 9dbc2e3604..d0f7e6ff39 100644 --- a/src/rendering/dashboarditem.cpp +++ b/src/rendering/dashboarditem.cpp @@ -28,8 +28,8 @@ #include #include #include -#include #include +#include namespace { constexpr const char* KeyType = "Type"; @@ -40,12 +40,6 @@ namespace { "If this value is set to 'true' this dashboard item is shown in the dashboard" }; - constexpr openspace::properties::Property::PropertyInfo TypeInfo = { - "Type", - "Type", - "" - }; - constexpr openspace::properties::Property::PropertyInfo IdentifierInfo = { "Identifier", "Identifier", @@ -57,36 +51,25 @@ namespace { "Gui Name", "" }; + + struct [[codegen::Dictionary(DashboardItem)]] Parameters { + std::string type; + + // [[codegen::verbatim(IdentifierInfo.description)]] + std::string identifier; + + // [[codegen::verbatim(GuiNameInfo.description)]] + std::optional guiName; + }; +#include "dashboarditem_codegen.cpp" } // namespace namespace openspace { documentation::Documentation DashboardItem::Documentation() { - using namespace documentation; - return { - "DashboardItem", - "dashboarditem", - { - { - TypeInfo.identifier, - new StringVerifier, - Optional::No, - TypeInfo.description - }, - { - IdentifierInfo.identifier, - new StringVerifier, - Optional::No, - IdentifierInfo.description - }, - { - GuiNameInfo.identifier, - new StringVerifier, - Optional::Yes, - GuiNameInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "dashboarditem"; + return doc; } std::unique_ptr DashboardItem::createFromDictionary( @@ -105,18 +88,11 @@ DashboardItem::DashboardItem(const ghoul::Dictionary& dictionary) : properties::PropertyOwner({ "", "" }) , _isEnabled(EnabledInfo, true) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "DashboardItem" - ); + const Parameters p = codegen::bake(dictionary); - std::string identifier = dictionary.value(IdentifierInfo.identifier); - setIdentifier(std::move(identifier)); - - if (dictionary.hasValue(GuiNameInfo.identifier)) { - std::string guiName = dictionary.value(GuiNameInfo.identifier); - setGuiName(std::move(guiName)); + setIdentifier(p.identifier); + if (p.guiName.has_value()) { + setGuiName(*p.guiName); } addProperty(_isEnabled); @@ -126,73 +102,4 @@ bool DashboardItem::isEnabled() const { return _isEnabled; } - -namespace { - constexpr openspace::properties::Property::PropertyInfo FontNameInfo = { - "FontName", - "Font Name", - "This value is the name of the font that is used. It can either refer to an " - "internal name registered previously, or it can refer to a path that is used." - }; - - constexpr openspace::properties::Property::PropertyInfo FontSizeInfo = { - "FontSize", - "Font Size", - "This value determines the size of the font that is used to render the distance." - }; -} // namespace - -documentation::Documentation DashboardTextItem::Documentation() { - using namespace documentation; - return { - "DashboardTextItem", - "dashboardtextitem", - { - { - FontNameInfo.identifier, - new StringVerifier, - Optional::Yes, - FontNameInfo.description - }, - { - FontSizeInfo.identifier, - new IntVerifier, - Optional::Yes, - FontSizeInfo.description - } - } - }; -} - -DashboardTextItem::DashboardTextItem(const ghoul::Dictionary& dictionary, float fontSize, - const std::string& fontName) - : DashboardItem(dictionary) - , _fontName(FontNameInfo, fontName) - , _fontSize(FontSizeInfo, fontSize, 6.f, 144.f, 1.f) -{ - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "DashboardTextItem" - ); - - if (dictionary.hasKey(FontNameInfo.identifier)) { - _fontName = dictionary.value(FontNameInfo.identifier); - } - _fontName.onChange([this]() { - _font = global::fontManager->font(_fontName, _fontSize); - }); - addProperty(_fontName); - - if (dictionary.hasKey(FontSizeInfo.identifier)) { - _fontSize = static_cast(dictionary.value(FontSizeInfo.identifier)); - } - _fontSize.onChange([this]() { - _font = global::fontManager->font(_fontName, _fontSize); - }); - addProperty(_fontSize); - - _font = global::fontManager->font(_fontName, _fontSize); -} - } // namespace openspace diff --git a/src/rendering/dashboardtextitem.cpp b/src/rendering/dashboardtextitem.cpp new file mode 100644 index 0000000000..fae12f4403 --- /dev/null +++ b/src/rendering/dashboardtextitem.cpp @@ -0,0 +1,88 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include + +#include +#include +#include +#include +#include + +namespace { + constexpr openspace::properties::Property::PropertyInfo FontNameInfo = { + "FontName", + "Font Name", + "This value is the name of the font that is used. It can either refer to an " + "internal name registered previously, or it can refer to a path that is used." + }; + + constexpr openspace::properties::Property::PropertyInfo FontSizeInfo = { + "FontSize", + "Font Size", + "This value determines the size of the font that is used to render the distance." + }; + + struct [[codegen::Dictionary(DashboardTextItem)]] Parameters { + // [[codegen::verbatim(FontNameInfo.description)]] + std::optional fontName; + + // [[codegen::verbatim(FontSizeInfo.description)]] + std::optional fontSize; + }; +#include "dashboardtextitem_codegen.cpp" +} // namespace + +namespace openspace { + +documentation::Documentation DashboardTextItem::Documentation() { + documentation::Documentation doc = codegen::doc(); + doc.id = "dashboardtextitem"; + return doc; +} + +DashboardTextItem::DashboardTextItem(const ghoul::Dictionary& dictionary, float fontSize, + const std::string& fontName) + : DashboardItem(dictionary) + , _fontName(FontNameInfo, fontName) + , _fontSize(FontSizeInfo, fontSize, 6.f, 144.f, 1.f) +{ + 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); + }); + addProperty(_fontSize); + + _font = global::fontManager->font(_fontName, _fontSize); +} + +} // namespace openspace diff --git a/src/rendering/renderable.cpp b/src/rendering/renderable.cpp index 9fa0d27259..ffc5ceef16 100644 --- a/src/rendering/renderable.cpp +++ b/src/rendering/renderable.cpp @@ -129,7 +129,7 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary) registerUpdateRenderBinFromOpacity(); const Parameters p = codegen::bake(dictionary); - + if (p.tag.has_value()) { if (std::holds_alternative(*p.tag)) { if (!std::get(*p.tag).empty()) { diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index 7130840e05..fdc278b9bd 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -134,6 +134,13 @@ namespace { "interface." }; + constexpr openspace::properties::Property::PropertyInfo ScreenshotUseDateInfo = { + "ScreenshotUseDate", + "Screenshot Folder uses Date", + "If this value is set to 'true', screenshots will be saved to a folder that " + "contains the time at which this value was enabled" + }; + constexpr openspace::properties::Property::PropertyInfo ShowFrameNumberInfo = { "ShowFrameInformation", "Show Frame Information", @@ -255,6 +262,7 @@ RenderEngine::RenderEngine() , _showVersionInfo(ShowVersionInfo, true) , _showCameraInfo(ShowCameraInfo, true) , _applyWarping(ApplyWarpingInfo, false) + , _screenshotUseDate(ScreenshotUseDateInfo, false) , _showFrameInformation(ShowFrameNumberInfo, false) , _disableMasterRendering(DisableMasterInfo, false) , _globalBlackOutFactor(GlobalBlackoutFactorInfo, 1.f, 0.f, 1.f) @@ -348,6 +356,44 @@ RenderEngine::RenderEngine() addProperty(_globalBlackOutFactor); addProperty(_applyWarping); + _screenshotUseDate.onChange([this]() { + // If there is no screenshot folder, don't bother with handling the change + if (!FileSys.hasRegisteredToken("${STARTUP_SCREENSHOT}")) { + return; + } + + if (_screenshotUseDate) { + // Going from 'false' -> 'true' + // We might need to create the folder first + + std::time_t now = std::time(nullptr); + std::tm* nowTime = std::localtime(&now); + char date[128]; + strftime(date, sizeof(date), "%Y-%m-%d-%H-%M", nowTime); + + std::string newFolder = absPath("${STARTUP_SCREENSHOT}/" + std::string(date)); + if (!FileSys.directoryExists(newFolder)) { + FileSys.createDirectory(newFolder); + } + FileSys.registerPathToken( + "${SCREENSHOTS}", + newFolder, + ghoul::filesystem::FileSystem::Override::Yes + ); + } + else { + // Going from 'true' -> 'false' + // We reset the screenshot folder back to what it was in the beginning + FileSys.registerPathToken( + "${SCREENSHOTS}", + absPath("${STARTUP_SCREENSHOT}"), + ghoul::filesystem::FileSystem::Override::Yes + ); + } + global::windowDelegate->setScreenshotFolder(absPath("${SCREENSHOTS}")); + }); + addProperty(_screenshotUseDate); + _horizFieldOfView.onChange([this]() { if (global::windowDelegate->isMaster()) { global::windowDelegate->setHorizFieldOfView(_horizFieldOfView); @@ -447,6 +493,8 @@ void RenderEngine::initialize() { ); } } + + _screenshotUseDate = global::configuration->shouldUseScreenshotDate; } void RenderEngine::initializeGL() { diff --git a/src/rendering/screenspacerenderable.cpp b/src/rendering/screenspacerenderable.cpp index 9f913096a2..fa64370e68 100644 --- a/src/rendering/screenspacerenderable.cpp +++ b/src/rendering/screenspacerenderable.cpp @@ -38,11 +38,10 @@ #include #include #include +#include +#include namespace { - constexpr const char* KeyType = "Type"; - constexpr const char* KeyTag = "Tag"; - constexpr const std::array UniformNames = { "Alpha", "ModelTransform", "ViewProjectionMatrix", "texture1" }; @@ -207,109 +206,72 @@ namespace { wrap(elevation, -glm::pi(), glm::pi()) ); } + + struct [[codegen::Dictionary(ScreenSpaceRenderable)]] Parameters { + // The type of the Screenspace renderable that is to be created. The available + // types of Screenspace renderable depend on the configuration of the application + // and can be written to disk on application startup into the FactoryDocumentation + std::string type + [[codegen::annotation("Must name a valid Screenspace renderable")]]; + + // Specifies the name of this screenspace renderable. This does not have to be + // unique to the scene, but it is recommended to be + std::optional name; + + // This is the unique identifier for this screenspace renderable. It has to be + // unique amongst all existing screenspace nodes that already have been added to + // the scene. The identifier is not allowed to have any whitespace or '.' and must + // not be empty + std::optional identifier; + + // [[codegen::verbatim(EnabledInfo.description)]] + std::optional enabled; + + // [[codegen::verbatim(UseRadiusAzimuthElevationInfo.description)]] + std::optional useRadiusAzimuthElevation; + + // [[codegen::verbatim(FaceCameraInfo.description)]] + std::optional faceCamera; + + // [[codegen::verbatim(CartesianPositionInfo.description)]] + std::optional cartesianPosition; + + // [[codegen::verbatim(RadiusAzimuthElevationInfo.description)]] + std::optional radiusAzimuthElevation; + + // [[codegen::verbatim(ScaleInfo.description)]] + std::optional scale; + + // [[codegen::verbatim(UsePerspectiveProjectionInfo.description)]] + std::optional usePerspectiveProjection; + + // [codegen::verbatim(OpacityInfo.description)]] + std::optional opacity [[codegen::inrange(0.f, 1.f)]]; + + // Defines either a single or multiple tags that apply to this + // ScreenSpaceRenderable, thus making it possible to address multiple, separate + // Renderables with a single property change + std::optional>> tag; + }; +#include "screenspacerenderable_codegen.cpp" } // namespace namespace openspace { documentation::Documentation ScreenSpaceRenderable::Documentation() { - using namespace openspace::documentation; - - return { - "Screenspace Renderable", - "core_screenspacerenderable", - { - { - KeyType, - new StringAnnotationVerifier("Must name a valid Screenspace renderable"), - Optional::No, - "The type of the Screenspace renderable that is to be created. The " - "available types of Screenspace renderable depend on the configuration of" - "the application and can be written to disk on application startup into " - "the FactoryDocumentation." - }, - { - KeyName, - new StringVerifier, - Optional::Yes, - "Specifies the name of this screenspace renderable. This does not have " - "to be unique to the scene, but it is recommended to be." - }, - { - KeyIdentifier, - new StringVerifier, - Optional::Yes, - "This is the unique identifier for this screenspace renderable. It has " - "to be unique amongst all existing screenspace nodes that already have " - "been added to the scene. The identifier is not allowed to have any " - "whitespace or '.' and must not be empty." - }, - { - EnabledInfo.identifier, - new BoolVerifier, - Optional::Yes, - EnabledInfo.description - }, - { - UseRadiusAzimuthElevationInfo.identifier, - new BoolVerifier, - Optional::Yes, - UseRadiusAzimuthElevationInfo.description - }, - { - FaceCameraInfo.identifier, - new BoolVerifier, - Optional::Yes, - FaceCameraInfo.description - }, - { - CartesianPositionInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - CartesianPositionInfo.description - }, - { - RadiusAzimuthElevationInfo.identifier, - new DoubleVector3Verifier, - Optional::Yes, - RadiusAzimuthElevationInfo.description - }, - { - ScaleInfo.identifier, - new DoubleVerifier, - Optional::Yes, - ScaleInfo.description - }, - { - OpacityInfo.identifier, - new DoubleVerifier, - Optional::Yes, - OpacityInfo.description - }, - { - KeyTag, - new OrVerifier({ new StringVerifier, new StringListVerifier }), - Optional::Yes, - "Defines either a single or multiple tags that apply to this " - "ScreenSpaceRenderable, thus making it possible to address multiple, " - "seprate Renderables with a single property change." - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "core_screenspacerenderable"; + return doc; } std::unique_ptr ScreenSpaceRenderable::createFromDictionary( const ghoul::Dictionary& dictionary) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "ScreenSpaceRenderable" - ); + const Parameters p = codegen::bake(dictionary); - const std::string& renderableType = dictionary.value(KeyType); ScreenSpaceRenderable* ssr = FactoryManager::ref().factory()->create( - renderableType, + p.type, dictionary ); return std::unique_ptr(ssr); @@ -365,12 +327,14 @@ ScreenSpaceRenderable::ScreenSpaceRenderable(const ghoul::Dictionary& dictionary , _opacity(OpacityInfo, 1.f, 0.f, 1.f) , _delete(DeleteInfo) { - if (dictionary.hasKey(KeyIdentifier)) { - setIdentifier(dictionary.value(KeyIdentifier)); + const Parameters p = codegen::bake(dictionary); + + if (p.identifier.has_value()) { + setIdentifier(*p.identifier); } - if (dictionary.hasKey(KeyName)) { - setGuiName(dictionary.value(KeyName)); + if (p.name.has_value()) { + setGuiName(*p.name); } addProperty(_enabled); @@ -394,62 +358,38 @@ ScreenSpaceRenderable::ScreenSpaceRenderable(const ghoul::Dictionary& dictionary addProperty(_opacity); addProperty(_localRotation); - if (dictionary.hasKey(EnabledInfo.identifier)) { - _enabled = dictionary.value(EnabledInfo.identifier); - } - - if (dictionary.hasKey(UseRadiusAzimuthElevationInfo.identifier)) { - _useRadiusAzimuthElevation = dictionary.value( - UseRadiusAzimuthElevationInfo.identifier - ); - } + _enabled = p.enabled.value_or(_enabled); + _useRadiusAzimuthElevation = + p.useRadiusAzimuthElevation.value_or(_useRadiusAzimuthElevation); if (_useRadiusAzimuthElevation) { - if (dictionary.hasKey(RadiusAzimuthElevationInfo.identifier)) { - _raePosition = dictionary.value( - RadiusAzimuthElevationInfo.identifier - ); - } + _raePosition = p.radiusAzimuthElevation.value_or(_raePosition); } else { - if (dictionary.hasKey(CartesianPositionInfo.identifier)) { - _cartesianPosition = dictionary.value( - CartesianPositionInfo.identifier - ); + _cartesianPosition = p.cartesianPosition.value_or(_cartesianPosition); + } + + _scale = p.scale.value_or(_scale); + _opacity = p.opacity.value_or(_opacity); + _usePerspectiveProjection = + p.usePerspectiveProjection.value_or(_usePerspectiveProjection); + + _faceCamera = p.faceCamera.value_or(_faceCamera); + + if (p.tag.has_value()) { + if (std::holds_alternative(*p.tag)) { + addTag(std::get(*p.tag)); } - } - - if (dictionary.hasKey(ScaleInfo.identifier)) { - _scale = static_cast(dictionary.value(ScaleInfo.identifier)); - } - - if (dictionary.hasKey(OpacityInfo.identifier)) { - _opacity = static_cast(dictionary.value(OpacityInfo.identifier)); - } - - if (dictionary.hasKey(UsePerspectiveProjectionInfo.identifier)) { - _usePerspectiveProjection = - dictionary.value(UsePerspectiveProjectionInfo.identifier); - } - - if (dictionary.hasKey(FaceCameraInfo.identifier)) { - _faceCamera = dictionary.value(FaceCameraInfo.identifier); - } - - if (dictionary.hasValue(KeyTag)) { - std::string tagName = dictionary.value(KeyTag); - if (!tagName.empty()) { - addTag(std::move(tagName)); - } - } - 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 if (std::holds_alternative>(*p.tag)) { + for (const std::string& t : std::get>(*p.tag)) { + if (!t.empty()) { + addTag(t); + } } } + else { + throw ghoul::MissingCaseException(); + } } _delete.onChange([this](){ diff --git a/src/scene/lightsource.cpp b/src/scene/lightsource.cpp index 61bb9fffd1..597cff1265 100644 --- a/src/scene/lightsource.cpp +++ b/src/scene/lightsource.cpp @@ -32,17 +32,28 @@ #include #include #include +#include namespace { - constexpr const char* KeyType = "Type"; - - constexpr const char* KeyIdentifier = "Identifier"; - constexpr openspace::properties::Property::PropertyInfo EnabledInfo = { "Enabled", "Enabled", "Whether the light source is enabled or not" }; + + struct [[codegen::Dictionary(LightSource)]] Parameters { + // The type of the light source that is described in this element. The available + // types of light sources depend on the configuration of the application and can + // be written to disk on application startup into the FactoryDocumentation + std::string type [[codegen::annotation("Must name a valid LightSource type")]]; + + // The identifier of the light source + std::string identifier; + + // [[codegen::verbatim(EnabledInfo.description)]] + std::optional enabled; + }; +#include "lightsource_codegen.cpp" } // namespace namespace openspace { @@ -52,49 +63,19 @@ bool LightSource::isEnabled() const { } documentation::Documentation LightSource::Documentation() { - using namespace openspace::documentation; - - return { - "Light Source", - "core_light_source", - { - { - KeyType, - new StringAnnotationVerifier("Must name a valid LightSource type"), - Optional::No, - "The type of the light source that is described in this element. " - "The available types of light sources depend on the configuration " - "of the application and can be written to disk on " - "application startup into the FactoryDocumentation." - }, - { - KeyIdentifier, - new StringVerifier, - Optional::No, - "The identifier of the light source." - }, - { - EnabledInfo.identifier, - new BoolVerifier, - Optional::Yes, - EnabledInfo.description - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "core_light_source"; + return doc; } std::unique_ptr LightSource::createFromDictionary( - const ghoul::Dictionary& dictionary) + const ghoul::Dictionary& dictionary) { - documentation::testSpecificationAndThrow(Documentation(), dictionary, "LightSource"); - - const std::string timeFrameType = dictionary.value(KeyType); + const Parameters p = codegen::bake(dictionary); auto factory = FactoryManager::ref().factory(); - LightSource* source = factory->create(timeFrameType, dictionary); - - const std::string identifier = dictionary.value(KeyIdentifier); - source->setIdentifier(identifier); + LightSource* source = factory->create(p.type, dictionary); + source->setIdentifier(p.identifier); return std::unique_ptr(source); } @@ -110,10 +91,9 @@ LightSource::LightSource(const ghoul::Dictionary& dictionary) : properties::PropertyOwner({ "LightSource" }) , _enabled(EnabledInfo, true) { - if (dictionary.hasValue(EnabledInfo.identifier)) { - _enabled = dictionary.value(EnabledInfo.identifier); - } + const Parameters p = codegen::bake(dictionary); + _enabled = p.enabled.value_or(_enabled); addProperty(_enabled); } diff --git a/src/scene/rotation.cpp b/src/scene/rotation.cpp index 59daaf823d..637b60029e 100644 --- a/src/scene/rotation.cpp +++ b/src/scene/rotation.cpp @@ -36,40 +36,30 @@ #include namespace { - constexpr const char* KeyType = "Type"; + struct [[codegen::Dictionary(Rotation)]] Parameters { + // The type of the rotation that is described in this element. The available types + // of rotations depend on the configuration of the application and can be written + // to disk on application startup into the FactoryDocumentation + std::string type [[codegen::annotation("Must name a valid Rotation type")]]; + }; +#include "rotation_codegen.cpp" } // namespace namespace openspace { documentation::Documentation Rotation::Documentation() { - using namespace openspace::documentation; - - return { - "Transformation Rotation", - "core_transform_rotation", - { - { - KeyType, - new StringAnnotationVerifier("Must name a valid Rotation type."), - Optional::No, - "The type of the rotation that is described in this element. The " - "available types of rotations depend on the configuration of the " - "application and can be written to disk on application startup into the " - "FactoryDocumentation." - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "core_transform_rotation"; + return doc; } ghoul::mm_unique_ptr Rotation::createFromDictionary( const ghoul::Dictionary& dictionary) { - documentation::testSpecificationAndThrow(Documentation(), dictionary, "Rotation"); + const Parameters p = codegen::bake(dictionary); - const std::string& rotationType = dictionary.value(KeyType); - auto factory = FactoryManager::ref().factory(); - Rotation* result = factory->create( - rotationType, + Rotation* result = FactoryManager::ref().factory()->create( + p.type, dictionary, &global::memoryManager->PersistentMemory ); @@ -78,6 +68,8 @@ ghoul::mm_unique_ptr Rotation::createFromDictionary( Rotation::Rotation() : properties::PropertyOwner({ "Rotation" }) {} +// @TODO (abock, 2021-03-25) This constructor can probably die since it doesn't do any +// above the default constructor Rotation::Rotation(const ghoul::Dictionary&) : properties::PropertyOwner({ "Rotation" }) {} diff --git a/src/scene/scenegraphnode.cpp b/src/scene/scenegraphnode.cpp index 38ddc471bf..0f3b760444 100644 --- a/src/scene/scenegraphnode.cpp +++ b/src/scene/scenegraphnode.cpp @@ -27,6 +27,8 @@ #include #include #include +#include +#include #include #include #include @@ -38,23 +40,11 @@ #include #include #include -#include "scenegraphnode_doc.inl" - #include +#include namespace { constexpr const char* _loggerCat = "SceneGraphNode"; - constexpr const char* KeyRenderable = "Renderable"; - constexpr const char* KeyGuiName = "GUI.Name"; - constexpr const char* KeyGuiPath = "GUI.Path"; - constexpr const char* KeyGuiHidden = "GUI.Hidden"; - constexpr const char* KeyGuiDescription = "GUI.Description"; - - constexpr const char* KeyTransformTranslation = "Transform.Translation"; - constexpr const char* KeyTransformRotation = "Transform.Rotation"; - constexpr const char* KeyTransformScale = "Transform.Scale"; - - constexpr const char* KeyTimeFrame = "TimeFrame"; constexpr openspace::properties::Property::PropertyInfo ComputeScreenSpaceInfo = { @@ -138,6 +128,90 @@ namespace { openspace::properties::Property::Visibility::Hidden }; + struct [[codegen::Dictionary(SceneGraphNode)]] Parameters { + // The identifier of this scenegraph node. This name must be unique among all + // scene graph nodes that are loaded in a specific scene. If a duplicate is + // detected the loading of the node will fail, as will all childing that depend on + // the node. The identifier must not contain any whitespaces or '.' + std::string identifier; + + // This names the parent of the currently specified scenegraph node. The parent + // must already exist in the scene graph. If not specified, the node will be + // attached to the root of the scenegraph + std::optional parent + [[codegen::annotation( + "If specified, this must be a name for another scenegraph node" + )]]; + + // The renderable that is to be created for this scenegraph node. A renderable is + // a component of a scenegraph node that will lead to some visual result on the + // screen. The specifics heavily depend on the 'Type' of the renderable. If no + // Renderable is specified, this scenegraph node is an internal node and can be + // used for either group children, or apply common transformations to a group of + // children + std::optional renderable [[codegen::reference("renderable")]]; + + // A hard-coded bounding sphere to be used for the cases where the Renderable is + // not able to provide a reasonable bounding sphere or the calculated bounding + // sphere needs to be overwritten for some reason + std::optional boundingSphere; + + struct Transform { + // This node describes a translation that is applied to the scenegraph node + // and all its children. Depending on the 'Type' of the translation, this can + // either be a static translation or a time-varying one + std::optional translation + [[codegen::reference("core_transform_translation")]]; + + // This nodes describes a rotation that is applied to the scenegraph node and + // all its children. Depending on the 'Type' of the rotation, this can either + // be a static rotation or a time-varying one + std::optional rotation + [[codegen::reference("core_transform_rotation")]]; + + // This node describes a scaling that is applied to the scenegraph node and + // all its children. Depending on the 'Type' of the scaling, this can either + // be a static scaling or a time-varying one + std::optional scale + [[codegen::reference("core_transform_scaling")]]; + }; + + // This describes a set of transformations that are applied to this scenegraph + // node and all of its children. There are only three possible values + // corresponding to a 'Translation', a 'Rotation', and a 'Scale' + std::optional transform; + + // Specifies the time frame for when this node should be active + std::optional timeFrame + [[codegen::reference("core_time_frame")]]; + + // A tag or list of tags that can be used to reference to a group of scenegraph + // nodes. + std::optional>> tag; + + struct Gui { + // An optional user-facing name for this SceneGraphNode, which does not have + // to be unique, though it is recommended, and can contain any characters + std::optional name; + + // If this value is specified, this '/' separated URI specifies the location + // of this scenegraph node in a GUI representation, for instance + // '/SolarSystem/Earth/Moon' + std::optional path; + + // A user-facing description about this scene graph node + std::optional description; + + // If this value is specified, GUI applications are incouraged to ignore this + // scenegraph node. This is most useful to trim collective lists of nodes and + // not display, for example, barycenters + std::optional hidden; + }; + // Additional information that is passed to GUI applications. These are all hints + // and do not have any impact on the actual function of the scenegraph node + std::optional gui [[codegen::key("GUI")]]; + }; +#include "scenegraphnode_codegen.cpp" } // namespace namespace openspace { @@ -149,11 +223,7 @@ int SceneGraphNode::nextIndex = 0; ghoul::mm_unique_ptr SceneGraphNode::createFromDictionary( const ghoul::Dictionary& dictionary) { - openspace::documentation::testSpecificationAndThrow( - SceneGraphNode::Documentation(), - dictionary, - "SceneGraphNode" - ); + const Parameters p = codegen::bake(dictionary); SceneGraphNode* n = global::memoryManager->PersistentMemory.alloc(); ghoul::mm_unique_ptr result = ghoul::mm_unique_ptr(n); @@ -162,89 +232,102 @@ ghoul::mm_unique_ptr SceneGraphNode::createFromDictionary( result->index = nextIndex++; #endif // Debugging_Core_SceneGraphNode_Indices - std::string identifier = dictionary.value(KeyIdentifier); - result->setIdentifier(std::move(identifier)); + result->setIdentifier(p.identifier); - if (dictionary.hasKey(KeyGuiName)) { - result->setGuiName(dictionary.value(KeyGuiName)); - result->_guiDisplayName = result->guiName(); - result->addProperty(result->_guiDisplayName); + if (p.gui.has_value()) { + if (p.gui->name.has_value()) { + result->setGuiName(*p.gui->name); + result->_guiDisplayName = result->guiName(); + result->addProperty(result->_guiDisplayName); + } + + if (p.gui->description.has_value()) { + result->setDescription(*p.gui->description); + result->_guiDescription = result->description(); + result->addProperty(result->_guiDescription); + } + + if (p.gui->hidden.has_value()) { + result->_guiHidden = *p.gui->hidden; + result->addProperty(result->_guiHidden); + } + + if (p.gui->path.has_value()) { + result->_guiPath = *p.gui->path; + result->addProperty(result->_guiPath); + } } - if (dictionary.hasKey(KeyGuiDescription)) { - result->setDescription(dictionary.value(KeyGuiDescription)); - result->_guiDescription = result->description(); - result->addProperty(result->_guiDescription); - } - - if (dictionary.hasKey(KeyGuiHidden)) { - result->_guiHidden = dictionary.value(KeyGuiHidden); - result->addProperty(result->_guiHidden); - } - - if (dictionary.hasKey(BoundingSphereInfo.identifier)) { - result->_boundingSphere = dictionary.value(BoundingSphereInfo.identifier); + if (p.boundingSphere.has_value()) { + result->_boundingSphere = *p.boundingSphere; result->_boundingSphere.setVisibility(properties::Property::Visibility::All); } - if (dictionary.hasKey(KeyTransformTranslation)) { - ghoul::Dictionary translationDictionary = - dictionary.value(KeyTransformTranslation); - result->_transform.translation = Translation::createFromDictionary( - translationDictionary - ); - if (result->_transform.translation == nullptr) { - LERROR(fmt::format( - "Failed to create ephemeris for SceneGraphNode '{}'", result->identifier() + if (p.transform.has_value()) { + if (p.transform->translation.has_value()) { + result->_transform.translation = Translation::createFromDictionary( + *p.transform->translation + ); + + // @TODO(abock, 2021-03-05) I don't think this is necessary anymore as we + // transitioned to throwing exceptions when the construction fails + if (result->_transform.translation == nullptr) { + LERROR(fmt::format( + "Failed to create ephemeris for SceneGraphNode '{}'", + result->identifier() + )); + return nullptr; + } + LDEBUG(fmt::format( + "Successfully created ephemeris for '{}'", result->identifier() )); - return nullptr; + result->addPropertySubOwner(result->_transform.translation.get()); + } + + if (p.transform->rotation.has_value()) { + result->_transform.rotation = Rotation::createFromDictionary( + *p.transform->rotation + ); + + // @TODO(abock, 2021-03-05) I don't think this is necessary anymore as we + // transitioned to throwing exceptions when the construction fails + if (result->_transform.rotation == nullptr) { + LERROR(fmt::format( + "Failed to create rotation for SceneGraphNode '{}'", + result->identifier() + )); + return nullptr; + } + LDEBUG(fmt::format( + "Successfully created rotation for '{}'", result->identifier() + )); + result->addPropertySubOwner(result->_transform.rotation.get()); + } + + if (p.transform->scale.has_value()) { + result->_transform.scale = Scale::createFromDictionary(*p.transform->scale); + + // @TODO(abock, 2021-03-05) I don't think this is necessary anymore as we + // transitioned to throwing exceptions when the construction fails + if (result->_transform.scale == nullptr) { + LERROR(fmt::format( + "Failed to create scale for SceneGraphNode '{}'", + result->identifier() + )); + return nullptr; + } + LDEBUG(fmt::format( + "Successfully created scale for '{}'", result->identifier() + )); + result->addPropertySubOwner(result->_transform.scale.get()); } - LDEBUG(fmt::format( - "Successfully created ephemeris for '{}'", result->identifier() - )); - } - if (result->_transform.translation) { - result->addPropertySubOwner(result->_transform.translation.get()); } - if (dictionary.hasKey(KeyTransformRotation)) { - ghoul::Dictionary rotationDictionary = - dictionary.value(KeyTransformRotation); - result->_transform.rotation = Rotation::createFromDictionary(rotationDictionary); - if (result->_transform.rotation == nullptr) { - LERROR(fmt::format( - "Failed to create rotation for SceneGraphNode '{}'", result->identifier() - )); - return nullptr; - } - LDEBUG(fmt::format( - "Successfully created rotation for '{}'", result->identifier() - )); - } - if (result->_transform.rotation) { - result->addPropertySubOwner(result->_transform.rotation.get()); - } + if (p.timeFrame.has_value()) { + result->_timeFrame = TimeFrame::createFromDictionary(*p.timeFrame); - if (dictionary.hasKey(KeyTransformScale)) { - ghoul::Dictionary scaleDictionary = - dictionary.value(KeyTransformScale); - result->_transform.scale = Scale::createFromDictionary(scaleDictionary); - if (result->_transform.scale == nullptr) { - LERROR(fmt::format( - "Failed to create scale for SceneGraphNode '{}'", result->identifier() - )); - return nullptr; - } - LDEBUG(fmt::format("Successfully created scale for '{}'", result->identifier())); - } - if (result->_transform.scale) { - result->addPropertySubOwner(result->_transform.scale.get()); - } - - if (dictionary.hasKey(KeyTimeFrame)) { - ghoul::Dictionary timeFrameDictionary = - dictionary.value(KeyTimeFrame); - result->_timeFrame = TimeFrame::createFromDictionary(timeFrameDictionary); + // @TODO(abock, 2021-03-05) I don't think this is necessary anymore as we + // transitioned to throwing exceptions when the construction fails if (result->_timeFrame == nullptr) { LERROR(fmt::format( "Failed to create time frame for SceneGraphNode '{}'", @@ -252,30 +335,26 @@ ghoul::mm_unique_ptr SceneGraphNode::createFromDictionary( )); return nullptr; } - result->addPropertySubOwner(result->_timeFrame.get()); LDEBUG(fmt::format( - "Successfully created time frame for '{}'", - result->identifier() + "Successfully created time frame for '{}'", result->identifier() )); + result->addPropertySubOwner(result->_timeFrame.get()); } // We initialize the renderable last as it probably has the most dependencies - if (dictionary.hasValue(KeyRenderable)) { - ghoul::Dictionary renderableDictionary = - dictionary.value(KeyRenderable); - - result->_renderable = Renderable::createFromDictionary(renderableDictionary); + if (p.renderable.has_value()) { + result->_renderable = Renderable::createFromDictionary(*p.renderable); ghoul_assert(result->_renderable, "Failed to create Renderable"); result->addPropertySubOwner(result->_renderable.get()); LDEBUG(fmt::format( "Successfully created renderable for '{}'", result->identifier() )); - // If the renderable child has a larger bounding sphere, we allow it tooverride + // If the renderable child has a larger bounding sphere, we allow it to override if (result->_renderable->boundingSphere() > result->_boundingSphere) { result->_boundingSphere = result->_renderable->boundingSphere(); - if (dictionary.hasKey(BoundingSphereInfo.identifier)) { + if (p.boundingSphere.has_value()) { LWARNING(fmt::format( "The specified property 'BoundingSphere' for '{}' was overwritten " "by a child renderable", @@ -285,37 +364,34 @@ ghoul::mm_unique_ptr SceneGraphNode::createFromDictionary( } } - if (dictionary.hasKey(KeyTag)) { - if (dictionary.hasValue(KeyTag)) { - std::string tagName = dictionary.value(KeyTag); - if (!tagName.empty()) { - result->addTag(std::move(tagName)); - } + if (p.tag.has_value()) { + if (std::holds_alternative(*p.tag)) { + result->addTag(std::get(*p.tag)); } - else if (dictionary.hasValue(KeyTag)) { - ghoul::Dictionary tagNames = dictionary.value(KeyTag); - std::string tagName; - for (std::string_view key : tagNames.keys()) { - tagName = tagNames.value(key); - if (!tagName.empty()) { - result->addTag(std::move(tagName)); + else if (std::holds_alternative>(*p.tag)) { + for (const std::string& tag : std::get>(*p.tag)) { + if (!tag.empty()) { + result->addTag(tag); } } } + else { + throw ghoul::MissingCaseException(); + } } - if (dictionary.hasKey(KeyGuiPath)) { - result->_guiPath = dictionary.value(KeyGuiPath); - result->addProperty(result->_guiPath); - } - - LDEBUG(fmt::format("Successfully created SceneGraphNode '{}'", result->identifier())); result->_lastScreenSpaceUpdateTime = std::chrono::high_resolution_clock::now(); return result; } +documentation::Documentation SceneGraphNode::Documentation() { + documentation::Documentation doc = codegen::doc(); + doc.id = "core_scene_node"; + return doc; +} + SceneGraphNode::SceneGraphNode() : properties::PropertyOwner({ "" }) , _guiHidden(GuiHiddenInfo) diff --git a/src/scene/scenegraphnode_doc.inl b/src/scene/scenegraphnode_doc.inl deleted file mode 100644 index 29f89546e6..0000000000 --- a/src/scene/scenegraphnode_doc.inl +++ /dev/null @@ -1,145 +0,0 @@ -/***************************************************************************************** - * * - * OpenSpace * - * * - * Copyright (c) 2014-2021 * - * * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this * - * software and associated documentation files (the "Software"), to deal in the Software * - * without restriction, including without limitation the rights to use, copy, modify, * - * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * - * permit persons to whom the Software is furnished to do so, subject to the following * - * conditions: * - * * - * The above copyright notice and this permission notice shall be included in all copies * - * or substantial portions of the Software. * - * * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * - * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * - * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * - * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * - * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * - * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * - ****************************************************************************************/ - -#include -#include - -namespace openspace { - -documentation::Documentation SceneGraphNode::Documentation() { - using namespace documentation; - - return { - "Scenegraph Node", - "core_scene_node", - { - { - "Identifier", - new StringVerifier, - Optional::No, - "The identifier of this scenegraph node. This name must be unique among all " - "scene graph nodes that are loaded in a specific scene. If a duplicate is " - "detected the loading of the node will fail, as will all childing that " - "depend on the node. The identifier must not contain any whitespaces or '.'." - }, - { - "Parent", - new StringAnnotationVerifier( - "If specified, this must be a name for another scenegraph node" - ), - Optional::Yes, - "This names the parent of the currently specified scenegraph node. The " - "parent must already exist in the scene graph. If not specified, the node " - "will be attached to the root of the scenegraph.", - }, - { - "Renderable", - new ReferencingVerifier("renderable"), - Optional::Yes, - "The renderable that is to be created for this scenegraph node. A renderable " - "is a component of a scenegraph node that will lead to some visual result on " - "the screen. The specifics heavily depend on the 'Type' of the renderable. " - "If no Renderable is specified, this scenegraph node is an internal node and " - "can be used for either group children, or apply common transformations to a " - "group of children." - }, - { - "Transform", - new TableVerifier({ - { - "Translation", - new ReferencingVerifier("core_transform_translation"), - Optional::Yes, - "This node describes a translation that is applied to the scenegraph " - "node and all its children. Depending on the 'Type' of the " - "translation, this can either be a static translation or a " - "time-varying one." - }, - { - "Rotation", - new ReferencingVerifier("core_transform_rotation"), - Optional::Yes, - "This nodes describes a rotation that is applied to the scenegraph " - "node and all its children. Depending on the 'Type' of the rotation, " - "this can either be a static rotation or a time-varying one." - }, - { - "Scale", - new ReferencingVerifier("core_transform_scaling"), - Optional::Yes, - "This node describes a scaling that is applied to the scenegraph " - "node and all its children. Depending on the 'Type' of the scaling, " - "this can either be a static scaling or a time-varying one." - } - }), - Optional::Yes, - "This describes a set of transformations that are applied to this scenegraph " - "node and all of its children. There are only three possible values " - "corresponding to a 'Translation', a 'Rotation', and a 'Scale'." - }, - { - "TimeFrame", - new ReferencingVerifier("core_time_frame"), - Optional::Yes, - "Specifies the time frame for when this node should be active." - }, - { - "GUI", - new TableVerifier({ - { - "Name", - new StringVerifier, - Optional::Yes, - "An optional user-facing name for this SceneGraphNode, which does " - "not have to be unique, though it is recommended, and can contain " - "any characters." - }, - { - "Path", - new StringVerifier, - Optional::Yes, - "If this value is specified, this '/' separated URI specifies the " - "location of this scenegraph node in a GUI representation, for " - "instance '/SolarSystem/Earth/Moon'." - }, - { - "Hidden", - new BoolVerifier, - Optional::Yes, - "If this value is specified, GUI applications are incouraged to " - "ignore this scenegraph node. This is most useful to trim collective " - "lists of nodes and not display, for example, barycenters." - } - }), - Optional::Yes, - "Additional information that is passed to GUI applications. These are all " - "hints and do not have any impact on the actual function of the scenegraph " - "node." - }, - - } - }; -} - -} // namespace openspace diff --git a/src/scene/translation.cpp b/src/scene/translation.cpp index 55ff79b80d..878270f827 100644 --- a/src/scene/translation.cpp +++ b/src/scene/translation.cpp @@ -34,45 +34,33 @@ #include namespace { - const char* KeyType = "Type"; + struct [[codegen::Dictionary(Translation)]] Parameters { + // The type of translation that is described in this element. The available types + // of translations depend on the configuration of the application and can be + // written to disk on application startup into the FactoryDocumentation + std::string type [[codegen::annotation("Must name a valid Translation type")]]; + }; +#include "translation_codegen.cpp" } // namespace namespace openspace { documentation::Documentation Translation::Documentation() { - using namespace documentation; - - return { - "Transformation Translation", - "core_transform_translation", - { - { - KeyType, - new StringAnnotationVerifier("Must name a valid Translation type"), - Optional::No, - "The type of translation that is described in this element. " - "The available types of translations depend on the " - "configuration of the application and can be written to disk " - "on application startup into the FactoryDocumentation." - } - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "core_transform_translation"; + return doc; } ghoul::mm_unique_ptr Translation::createFromDictionary( const ghoul::Dictionary& dictionary) { - documentation::testSpecificationAndThrow(Documentation(), dictionary, "Translation"); + const Parameters p = codegen::bake(dictionary); - const std::string& translationType = dictionary.value(KeyType); - ghoul::TemplateFactory* factory - = FactoryManager::ref().factory(); - Translation* result = factory->create( - translationType, + Translation* result = FactoryManager::ref().factory()->create( + p.type, dictionary, &global::memoryManager->PersistentMemory ); - result->setIdentifier("Translation"); return ghoul::mm_unique_ptr(result); } diff --git a/src/scripting/scriptscheduler.cpp b/src/scripting/scriptscheduler.cpp index 7523f91e69..7898b27c49 100644 --- a/src/scripting/scriptscheduler.cpp +++ b/src/scripting/scriptscheduler.cpp @@ -33,68 +33,51 @@ #include "scriptscheduler_lua.inl" namespace { - constexpr const char* KeyTime = "Time"; - constexpr const char* KeyForwardScript = "ForwardScript"; - constexpr const char* KeyBackwardScript = "BackwardScript"; - constexpr const char* KeyUniversalScript = "Script"; + struct [[codegen::Dictionary(ScheduledScript)]] Parameters { + // The time at which, when the in game time passes it, the two scripts will + // be executed. If the traversal is forwards (towards + infinity), the + // ForwardScript will be executed, otherwise the BackwardScript will be + // executed instead + std::string time; + + // The Lua script that will be executed when the specified time is passed + // independent of its direction. This script will be executed before the + // specific scripts if both versions are specified + std::optional script; + + // The Lua script that is executed when OpenSpace passes the time in a + // forward direction + std::optional forwardScript; + + // The Lua script that is executed when OpenSpace passes the time in a + // backward direction + std::optional backwardScript; + }; +#include "scriptscheduler_codegen.cpp" } // namespace namespace openspace::scripting { documentation::Documentation ScriptScheduler::Documentation() { - using namespace openspace::documentation; - - using TimeVerifier = StringVerifier; - using LuaScriptVerifier = StringVerifier; - - return { - "Scheduled Scripts", - "core_scheduledscript", - { - { - "*", - new TableVerifier({ - { - KeyTime, - new TimeVerifier, - Optional::No, - "The time at which, when the in game time passes it, the two " - "scripts will be executed. If the traversal is forwards (towards " - "+ infinity), the ForwardScript will be executed, otherwise the " - "BackwardScript will be executed instead." - }, - { - KeyUniversalScript, - new LuaScriptVerifier, - Optional::Yes, - "The Lua script that will be executed when the specified time is " - "passed independent of its direction. This script will be " - "executed before the specific scripts if both versions are " - "specified" - }, - { - KeyForwardScript, - new LuaScriptVerifier, - Optional::Yes, - "The Lua script that is executed when OpenSpace passes the time " - "in a forward direction." - }, - { - KeyBackwardScript, - new LuaScriptVerifier, - Optional::Yes, - "The Lua script that is executed when OpenSpace passes the time " - "in a backward direction." - } - }), - Optional::No - } - } - }; + // @TODO (abock, 2021-03-25) This is not really correct. This function currently + // returns the documentation for the ScheduledScript, not for the ScriptScheduler + // itself. This should be cleaned up a bit + documentation::Documentation doc = codegen::doc(); + doc.id = "core_scheduledscript"; + return doc; } using namespace openspace::interaction; +ScriptScheduler::ScheduledScript::ScheduledScript(const ghoul::Dictionary& dict) { + const Parameters p = codegen::bake(dict); + + time = Time::convertTime(p.time); + forwardScript = p.forwardScript.value_or(forwardScript); + backwardScript = p.backwardScript.value_or(backwardScript); + universalScript = p.script.value_or(universalScript); +} + void ScriptScheduler::loadScripts(std::vector scheduledScripts) { // Sort scripts by time; use a stable_sort as the user might have had an intention // specifying multiple scripts for the same time in a specific order diff --git a/src/scripting/scriptscheduler_lua.inl b/src/scripting/scriptscheduler_lua.inl index 7c63502e9f..f0d2402539 100644 --- a/src/scripting/scriptscheduler_lua.inl +++ b/src/scripting/scriptscheduler_lua.inl @@ -38,35 +38,20 @@ int loadFile(lua_State* L) { return ghoul::lua::luaError(L, "filepath string is empty"); } - ghoul::Dictionary scriptsDict = ghoul::lua::loadDictionaryFromFile(fileName, L); + ghoul::Dictionary scriptsDict; + scriptsDict.setValue("Scripts", ghoul::lua::loadDictionaryFromFile(fileName, L)); documentation::testSpecificationAndThrow( scripting::ScriptScheduler::Documentation(), scriptsDict, "ScriptScheduler" ); - std::vector scripts; - for (int i = 1; i <= scriptsDict.size(); ++i) { + for (size_t i = 1; i <= scriptsDict.size(); ++i) { ghoul::Dictionary d = scriptsDict.value(std::to_string(i)); - scripting::ScriptScheduler::ScheduledScript script; - constexpr const char* KeyTime = "Time"; - if (d.hasValue(KeyTime)) { - script.time = Time::convertTime(d.value(KeyTime)); - } - constexpr const char* KeyForwardScript = "ForwardScript"; - if (d.hasValue(KeyForwardScript)) { - script.forwardScript = d.value(KeyForwardScript); - } - constexpr const char* KeyBackwardScript = "BackwardScript"; - if (d.hasValue(KeyBackwardScript)) { - script.backwardScript = d.value(KeyBackwardScript); - } - constexpr const char* KeyUniversalScript = "Script"; - if (d.hasValue(KeyUniversalScript)) { - script.universalScript = d.value(KeyUniversalScript); - } + scripting::ScriptScheduler::ScheduledScript script = + scripting::ScriptScheduler::ScheduledScript(d); scripts.push_back(script); } diff --git a/src/util/resourcesynchronization.cpp b/src/util/resourcesynchronization.cpp index 0e9a61449b..6d391f3701 100644 --- a/src/util/resourcesynchronization.cpp +++ b/src/util/resourcesynchronization.cpp @@ -30,67 +30,41 @@ #include namespace { - constexpr const char* KeyType = "Type"; - constexpr const char* KeyName = "Name"; + struct [[codegen::Dictionary(ResourceSynchronization)]] Parameters { + // This key specifies the type of ResourceSyncrhonization that gets created. It + // has to be one of the valid ResourceSyncrhonizations that are available for + // creation (see the FactoryDocumentation for a list of possible + // ResourceSyncrhonizations), which depends on the configration of the application + std::string type + [[codegen::annotation("A ResourceSynchronization created by a factory")]]; + + // A user readable name of this synchronization + std::string name; + }; +#include "resourcesynchronization_codegen.cpp" } // namespace namespace openspace { documentation::Documentation ResourceSynchronization::Documentation() { - using namespace openspace::documentation; - - return { - "ResourceSynchronization", - "resourceSynchronization", - { - { - KeyType, - new StringAnnotationVerifier( - "A valid ResourceSyncrhonization created by a factory" - ), - Optional::No, - "This key specifies the type of ResourceSyncrhonization that gets " - "created. It has to be one of the valid ResourceSyncrhonizations that " - "are available for creation (see the FactoryDocumentation for a list of " - "possible ResourceSyncrhonizations), which depends on the configration " - "of the application" - }, - { - KeyName, - new StringVerifier, - Optional::No, - "A user readable name of this synchronization" - }, - } - }; + documentation::Documentation doc = codegen::doc(); + doc.id = "resourceSynchronization"; + return doc; } std::unique_ptr ResourceSynchronization::createFromDictionary( const ghoul::Dictionary& dictionary) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "ResourceSynchronization" - ); - - const std::string& synchronizationType = dictionary.value(KeyType); + const Parameters p = codegen::bake(dictionary); auto factory = FactoryManager::ref().factory(); ghoul_assert(factory, "ResourceSynchronization factory did not exist"); - ResourceSynchronization* sync = factory->create(synchronizationType, dictionary); + ResourceSynchronization* sync = factory->create(p.type, dictionary); + sync->_name = p.name; return std::unique_ptr(sync); } -ResourceSynchronization::ResourceSynchronization(const ghoul::Dictionary& dictionary) { - documentation::testSpecificationAndThrow( - Documentation(), - dictionary, - "ResourceSynchronization" - ); - - _name = dictionary.value(KeyName); -} +ResourceSynchronization::ResourceSynchronization(const ghoul::Dictionary&) {} ResourceSynchronization::State ResourceSynchronization::state() const { return _state; @@ -111,14 +85,14 @@ bool ResourceSynchronization::isSyncing() const { ResourceSynchronization::CallbackHandle ResourceSynchronization::addStateChangeCallback(StateChangeCallback cb) { - std::lock_guard guard(_callbackMutex); + std::lock_guard guard(_callbackMutex); CallbackHandle callbackId = _nextCallbackId++; _stateChangeCallbacks[callbackId] = std::move(cb); return callbackId; } void ResourceSynchronization::removeStateChangeCallback(CallbackHandle id) { - std::lock_guard guard(_callbackMutex); + std::lock_guard guard(_callbackMutex); _stateChangeCallbacks.erase(id); } diff --git a/src/util/spicemanager.cpp b/src/util/spicemanager.cpp index f3c68adc56..1b22158f2c 100644 --- a/src/util/spicemanager.cpp +++ b/src/util/spicemanager.cpp @@ -586,7 +586,7 @@ std::string SpiceManager::dateFromEphemerisTime(double ephemerisTime, const char ephemerisTime, format )); } - + return std::string(Buffer); } diff --git a/support/coding/check_style_guide.py b/support/coding/check_style_guide.py index 8b23b4027f..ce60631737 100644 --- a/support/coding/check_style_guide.py +++ b/support/coding/check_style_guide.py @@ -3,7 +3,7 @@ """ OpenSpace -Copyright (c) 2014-2020 +Copyright (c) 2014-2021 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software @@ -59,7 +59,7 @@ import os import re import sys -current_year = '2020' +current_year = '2021' is_strict_mode = False is_silent_mode = False @@ -659,19 +659,23 @@ if not is_silent_mode: check_files( [basePath + 'src/**/*.cpp'], - [], + [basePath + 'src/**/*_codegen.cpp'], 'openspace_core', check_source_file ) check_files( [basePath + 'apps/**/*.cpp'], - [basePath + 'apps/**/ext/**/*.cpp'], + [basePath + 'apps/**/ext/**/*.cpp', basePath + 'apps/**/*_codegen.cpp'], 'openspace_app', check_source_file ) check_files( [basePath + 'modules/**/*.cpp'], - [basePath + 'modules/**/ext/**/*.cpp', basePath + 'modules/**/node_modules/**/*.cpp'], + [ + basePath + 'modules/**/ext/**/*.cpp', + basePath + 'modules/**/node_modules/**/*.cpp', + basePath + 'modules/**/*_codegen.cpp' + ], 'openspace_module', check_source_file ) diff --git a/support/coding/codegen b/support/coding/codegen index 1ca72c0202..2efd176817 160000 --- a/support/coding/codegen +++ b/support/coding/codegen @@ -1 +1 @@ -Subproject commit 1ca72c0202e3bd4b61510f84797db131591c8ca3 +Subproject commit 2efd1768176c1559b8eda3cbdcaeea2ded46e145 diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 522b4509c8..03d0883df7 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -28,6 +28,7 @@ add_executable( test_assetloader.cpp test_concurrentjobmanager.cpp test_concurrentqueue.cpp + test_configuration.cpp test_documentation.cpp test_iswamanager.cpp test_latlonpatch.cpp diff --git a/tests/main.cpp b/tests/main.cpp index 788f7cf5f8..578dc62cb1 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -44,7 +44,7 @@ int main(int argc, char** argv) { using namespace openspace; ghoul::logging::LogManager::initialize( - ghoul::logging::LogLevel::Debug, + ghoul::logging::LogLevel::Info, ghoul::logging::LogManager::ImmediateFlush::Yes ); ghoul::initialize(); @@ -59,10 +59,21 @@ int main(int argc, char** argv) { ); std::string configFile = configuration::findConfiguration(); - *global::configuration = configuration::loadConfigurationFromFile(configFile); + // Register the base path as the directory where 'filename' lives + std::string base = ghoul::filesystem::File(configFile).directoryName(); + constexpr const char* BasePathToken = "${BASE}"; + FileSys.registerPathToken(BasePathToken, base); + + *global::configuration = configuration::loadConfigurationFromFile(configFile, ""); global::openSpaceEngine->registerPathTokens(); global::openSpaceEngine->initialize(); + ghoul::logging::LogManager::deinitialize(); + ghoul::logging::LogManager::initialize( + ghoul::logging::LogLevel::Info, + ghoul::logging::LogManager::ImmediateFlush::Yes + ); + FileSys.registerPathToken("${TESTDIR}", "${BASE}/tests"); // All of the relevant tests initialize the SpiceManager diff --git a/tests/test_configuration.cpp b/tests/test_configuration.cpp new file mode 100644 index 0000000000..f7c031d251 --- /dev/null +++ b/tests/test_configuration.cpp @@ -0,0 +1,640 @@ +/***************************************************************************************** + * * + * OpenSpace * + * * + * Copyright (c) 2014-2021 * + * * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this * + * software and associated documentation files (the "Software"), to deal in the Software * + * without restriction, including without limitation the rights to use, copy, modify, * + * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to * + * permit persons to whom the Software is furnished to do so, subject to the following * + * conditions: * + * * + * The above copyright notice and this permission notice shall be included in all copies * + * or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * + * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A * + * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT * + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE * + * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + ****************************************************************************************/ + +#include "catch2/catch.hpp" + +#include +#include +#include +#include + +using namespace openspace::configuration; + +namespace { + std::string MinimalConfig = R"( +Paths = {} +)"; + + void writeConfig(const std::string& filename, const std::string& content) { + std::string config = MinimalConfig + content; + std::ofstream f(filename); + f << MinimalConfig << '\n' << content; + } + + Configuration loadConfiguration(const std::string& tag, const std::string& content) { + std::string filename = fmt::format("test_configuration_{}.cfg", tag); + std::filesystem::path path = std::filesystem::temp_directory_path(); + std::string configFile = (path / filename).string(); + writeConfig(configFile, content); + Configuration conf = loadConfigurationFromFile(configFile, content); + std::filesystem::remove(configFile); + return conf; + + } +} // namespace + +TEST_CASE("Configuration: minimal", "[configuration]") { + loadConfiguration("minimal", ""); +} + +TEST_CASE("Configuration: windowConfiguration", "[configuration]") { + constexpr const char Extra[] = R"(SGCTConfig = "foobar")"; + const Configuration c = loadConfiguration("windowConfiguration", Extra); + REQUIRE(c.windowConfiguration == "foobar"); +} + +TEST_CASE("Configuration: asset", "[configuration]") { + constexpr const char Extra[] = R"(Asset = "foobar")"; + const Configuration c = loadConfiguration("asset", Extra); + REQUIRE(c.asset == "foobar"); +} + +TEST_CASE("Configuration: profile", "[configuration]") { + constexpr const char Extra[] = R"(Profile = "foobar")"; + const Configuration c = loadConfiguration("profile", Extra); + REQUIRE(c.profile == "foobar"); +} + +TEST_CASE("Configuration: globalCustomizationScripts", "[configuration]") { + constexpr const char Extra[] = R"(GlobalCustomizationScripts = { "foo", "bar" })"; + const Configuration c = loadConfiguration("globalCustomization", Extra); + REQUIRE(c.globalCustomizationScripts.size() == 2); + CHECK(c.globalCustomizationScripts == std::vector{ "foo", "bar" }); +} + +TEST_CASE("Configuration: paths", "[configuration]") { + constexpr const char Extra[] = R"(Paths = { foo = "1", bar = "2" })"; + const Configuration c = loadConfiguration("paths", Extra); + REQUIRE(c.pathTokens.size() == 2); + CHECK( + c.pathTokens == + std::map{ { "foo", "1" }, { "bar", "2" } } + ); +} + +TEST_CASE("Configuration: fonts", "[configuration]") { + constexpr const char Extra[] = R"(Fonts = { foo = "1", bar = "2" })"; + const Configuration c = loadConfiguration("fonts", Extra); + REQUIRE(c.fonts.size() == 2); + CHECK( + c.fonts == + std::map{ { "foo", "1" }, { "bar", "2" } } + ); +} + +TEST_CASE("Configuration: logging", "[configuration]") { + Configuration defaultConf; + { + // Empty + constexpr const char Extra[] = R"(Logging = {})"; + const Configuration c = loadConfiguration("logging1", Extra); + + CHECK(c.logging.level == defaultConf.logging.level); + CHECK(c.logging.forceImmediateFlush == defaultConf.logging.forceImmediateFlush); + CHECK( + c.logging.capabilitiesVerbosity == + defaultConf.logging.capabilitiesVerbosity + ); + CHECK(c.logging.logs == defaultConf.logging.logs); + } + { + // level + constexpr const char Extra[] = R"(Logging = { LogLevel = "Fatal" })"; + const Configuration c = loadConfiguration("logging2", Extra); + + CHECK(c.logging.level == "Fatal"); + CHECK(c.logging.forceImmediateFlush == defaultConf.logging.forceImmediateFlush); + CHECK( + c.logging.capabilitiesVerbosity == + defaultConf.logging.capabilitiesVerbosity + ); + CHECK(c.logging.logs == defaultConf.logging.logs); + } + { + // forceimmediate + constexpr const char Extra[] = R"(Logging = { ImmediateFlush = false })"; + const Configuration c = loadConfiguration("logging3", Extra); + + CHECK(c.logging.level == defaultConf.logging.level); + CHECK(c.logging.forceImmediateFlush == false); + CHECK( + c.logging.capabilitiesVerbosity == + defaultConf.logging.capabilitiesVerbosity + ); + CHECK(c.logging.logs == defaultConf.logging.logs); + } + { + // logs + constexpr const char Extra[] = R"( +Logging = { + Logs = { + { Type = "html", File = "foobar", Append = false } + } +} +)"; + const Configuration c = loadConfiguration("logging4", Extra); + + CHECK(c.logging.level == defaultConf.logging.level); + CHECK(c.logging.forceImmediateFlush == defaultConf.logging.forceImmediateFlush); + CHECK( + c.logging.capabilitiesVerbosity == + defaultConf.logging.capabilitiesVerbosity + ); + REQUIRE(c.logging.logs.size() == 1); + const ghoul::Dictionary& d = c.logging.logs[0]; + REQUIRE(d.hasValue("Type")); + CHECK(d.value("Type") == "html"); + REQUIRE(d.hasValue("File")); + CHECK(d.value("File") == "foobar"); + REQUIRE(d.hasValue("Append")); + CHECK(d.value("Append") == false); + } + { + // capabilities verbosity + constexpr const char Extra[] = R"(Logging = { CapabilitiesVerbosity = "Full" })"; + const Configuration c = loadConfiguration("logging5", Extra); + + CHECK(c.logging.level == defaultConf.logging.level); + CHECK(c.logging.forceImmediateFlush == defaultConf.logging.forceImmediateFlush); + CHECK(c.logging.capabilitiesVerbosity == "Full"); + CHECK(c.logging.logs == defaultConf.logging.logs); + } +} + +TEST_CASE("Configuration: scriptlog", "[configuration]") { + constexpr const char Extra[] = R"(ScriptLog = "foobar")"; + const Configuration c = loadConfiguration("scriptlog", Extra); + CHECK(c.scriptLog == "foobar"); +} + +TEST_CASE("Configuration: documentationpath", "[configuration]") { + constexpr const char Extra[] = R"(Documentation = { Path = "foobar" })"; + const Configuration c = loadConfiguration("documentationpath", Extra); + CHECK(c.documentation.path == "foobar"); +} + +TEST_CASE("Configuration: versioncheckurl", "[configuration]") { + constexpr const char Extra[] = R"(VersionCheckUrl = "foobar")"; + const Configuration c = loadConfiguration("versioncheckurl", Extra); + CHECK(c.versionCheckUrl == "foobar"); +} + +TEST_CASE("Configuration: useMultithreadedInit", "[configuration]") { + constexpr const char Extra[] = R"(UseMultithreadedInitialization = true)"; + const Configuration c = loadConfiguration("useMultithreadedInit", Extra); + CHECK(c.useMultithreadedInitialization == true); +} + +TEST_CASE("Configuration: loadingscreen", "[configuration]") { + Configuration defaultConf; + + { + // empty + constexpr const char Extra[] = R"(LoadingScreen = {})"; + const Configuration c = loadConfiguration("loadingscreen1", Extra); + CHECK( + c.loadingScreen.isShowingMessages == + defaultConf.loadingScreen.isShowingMessages + ); + CHECK( + c.loadingScreen.isShowingProgressbar == + defaultConf.loadingScreen.isShowingProgressbar + ); + CHECK( + c.loadingScreen.isShowingNodeNames == + defaultConf.loadingScreen.isShowingNodeNames + ); + } + { + // isShowingMessages + constexpr const char Extra[] = R"(LoadingScreen = { ShowMessage = true })"; + const Configuration c = loadConfiguration("loadingscreen2", Extra); + CHECK(c.loadingScreen.isShowingMessages == true); + CHECK( + c.loadingScreen.isShowingProgressbar == + defaultConf.loadingScreen.isShowingProgressbar + ); + CHECK( + c.loadingScreen.isShowingNodeNames == + defaultConf.loadingScreen.isShowingNodeNames + ); + } + { + // isShowingProgressbar + constexpr const char Extra[] = R"(LoadingScreen = { ShowProgressbar = true })"; + const Configuration c = loadConfiguration("loadingscreen3", Extra); + CHECK( + c.loadingScreen.isShowingMessages == + defaultConf.loadingScreen.isShowingMessages + ); + CHECK(c.loadingScreen.isShowingProgressbar == true); + CHECK( + c.loadingScreen.isShowingNodeNames == + defaultConf.loadingScreen.isShowingNodeNames + ); + } + { + // isShowingNodeNames + constexpr const char Extra[] = R"(LoadingScreen = { ShowNodeNames = true })"; + const Configuration c = loadConfiguration("loadingscreen4", Extra); + CHECK( + c.loadingScreen.isShowingMessages == + defaultConf.loadingScreen.isShowingMessages + ); + CHECK( + c.loadingScreen.isShowingProgressbar == + defaultConf.loadingScreen.isShowingProgressbar + ); + CHECK(c.loadingScreen.isShowingNodeNames == true); + } +} + +TEST_CASE("Configuration: isCheckingOpenGLState", "[configuration]") { + constexpr const char Extra[] = R"(CheckOpenGLState = true)"; + const Configuration c = loadConfiguration("isCheckingOpenGLState", Extra); + CHECK(c.isCheckingOpenGLState == true); +} + +TEST_CASE("Configuration: isLoggingOpenGLCalls", "[configuration]") { + constexpr const char Extra[] = R"(LogEachOpenGLCall = true)"; + const Configuration c = loadConfiguration("isLoggingOpenGLCalls", Extra); + CHECK(c.isLoggingOpenGLCalls == true); +} + +TEST_CASE("Configuration: shutdownCountdown", "[configuration]") { + constexpr const char Extra[] = R"(ShutdownCountdown = 0.5)"; + const Configuration c = loadConfiguration("shutdownCountdown", Extra); + CHECK(c.shutdownCountdown == 0.5f); +} + +TEST_CASE("Configuration: shouldUseScreenshotDate", "[configuration]") { + constexpr const char Extra[] = R"(ScreenshotUseDate = true)"; + const Configuration c = loadConfiguration("shouldUseScreenshotDate", Extra); + CHECK(c.shouldUseScreenshotDate == true); +} + +TEST_CASE("Configuration: onScreenTextScaling", "[configuration]") { + constexpr const char Extra[] = R"(OnScreenTextScaling = "framebuffer")"; + const Configuration c = loadConfiguration("onScreenTextScaling", Extra); + CHECK(c.onScreenTextScaling == "framebuffer"); +} + +TEST_CASE("Configuration: usePerSceneCache", "[configuration]") { + constexpr const char Extra[] = R"(PerSceneCache = true)"; + const Configuration c = loadConfiguration("usePerSceneCache", Extra); + CHECK(c.usePerSceneCache == true); +} + +TEST_CASE("Configuration: isRenderingOnMasterDisabled", "[configuration]") { + constexpr const char Extra[] = R"(DisableRenderingOnMaster = true)"; + const Configuration c = loadConfiguration("isRenderingOnMasterDisabled", Extra); + CHECK(c.isRenderingOnMasterDisabled == true); +} + +TEST_CASE("Configuration: globalRotation", "[configuration]") { + constexpr const char Extra[] = R"(GlobalRotation = { 1.0, 2.0, 3.0 })"; + const Configuration c = loadConfiguration("globalRotation", Extra); + CHECK(c.globalRotation == glm::dvec3(1.0, 2.0, 3.0)); +} + +TEST_CASE("Configuration: screenSpaceRotation", "[configuration]") { + constexpr const char Extra[] = R"(ScreenSpaceRotation = { 1.0, 2.0, 3.0 })"; + const Configuration c = loadConfiguration("screenSpaceRotation", Extra); + CHECK(c.screenSpaceRotation == glm::dvec3(1.0, 2.0, 3.0)); +} + +TEST_CASE("Configuration: masterRotation", "[configuration]") { + constexpr const char Extra[] = R"(MasterRotation = { 1.0, 2.0, 3.0 })"; + const Configuration c = loadConfiguration("masterRotation", Extra); + CHECK(c.masterRotation == glm::dvec3(1.0, 2.0, 3.0)); +} + +TEST_CASE("Configuration: isConsoleDisabled", "[configuration]") { + constexpr const char Extra[] = R"(DisableInGameConsole = true)"; + const Configuration c = loadConfiguration("isConsoleDisabled", Extra); + CHECK(c.isConsoleDisabled == true); +} + +TEST_CASE("Configuration: bypassLauncher", "[configuration]") { + constexpr const char Extra[] = R"(BypassLauncher = true)"; + const Configuration c = loadConfiguration("bypassLauncher", Extra); + CHECK(c.bypassLauncher == true); +} + +TEST_CASE("Configuration: moduleConfigurations", "[configuration]") { + { + // empty + constexpr const char Extra[] = R"(ModuleConfigurations = {})"; + const Configuration c = loadConfiguration("moduleConfigurations", Extra); + CHECK(c.moduleConfigurations.empty()); + } + { + // values + constexpr const char Extra[] = R"( +ModuleConfigurations = { + Foo = { + Foo2 = 1.0, + Foo3 = "abc" + }, + Bar = { + Bar2 = true, + Bar3 = { 1.0, 2.0, 3.0 } + } +} +)"; + const Configuration c = loadConfiguration("moduleConfigurations", Extra); + REQUIRE(c.moduleConfigurations.size() == 2); + ghoul::Dictionary foo = c.moduleConfigurations.at("Foo"); + REQUIRE(foo.size() == 2); + REQUIRE(foo.hasValue("Foo2")); + CHECK(foo.value("Foo2") == 1.0); + REQUIRE(foo.hasValue("Foo3")); + CHECK(foo.value("Foo3") == std::string("abc")); + + ghoul::Dictionary bar = c.moduleConfigurations.at("Bar"); + REQUIRE(bar.size() == 2); + REQUIRE(bar.hasValue("Bar2")); + CHECK(bar.value("Bar2") == true); + REQUIRE(bar.hasValue("Bar3")); + CHECK(bar.value("Bar3") == glm::dvec3(1.0, 2.0, 3.0)); + } +} + +TEST_CASE("Configuration: renderingMethod", "[configuration]") { + constexpr const char Extra[] = R"(RenderingMethod = "ABuffer")"; + const Configuration c = loadConfiguration("renderingMethod", Extra); + CHECK(c.renderingMethod == "ABuffer"); +} + +TEST_CASE("Configuration: openGLDebugContext", "[configuration]") { + Configuration defaultConf; + { + // empty-ish / activate + constexpr const char Extra[] = R"(OpenGLDebugContext = { Activate = true })"; + const Configuration c = loadConfiguration("openGLDebugContext1", Extra); + CHECK(c.openGLDebugContext.isActive == true); + CHECK( + c.openGLDebugContext.isSynchronous == + defaultConf.openGLDebugContext.isSynchronous + ); + REQUIRE( + c.openGLDebugContext.identifierFilters.size() == + defaultConf.openGLDebugContext.identifierFilters.size() + ); + for (size_t i = 0; i < c.openGLDebugContext.identifierFilters.size(); i += 1) { + CHECK( + c.openGLDebugContext.identifierFilters[i].identifier == + defaultConf.openGLDebugContext.identifierFilters[i].identifier + ); + CHECK( + c.openGLDebugContext.identifierFilters[i].source == + defaultConf.openGLDebugContext.identifierFilters[i].source + ); + CHECK( + c.openGLDebugContext.identifierFilters[i].type == + defaultConf.openGLDebugContext.identifierFilters[i].type + ); + } + CHECK( + c.openGLDebugContext.severityFilters == + defaultConf.openGLDebugContext.severityFilters + ); + } + { + // isSynchronous + constexpr const char Extra[] = R"( +OpenGLDebugContext = { Activate = true, Synchronous = true } +)"; + const Configuration c = loadConfiguration("openGLDebugContext2", Extra); + CHECK(c.openGLDebugContext.isActive == true); + CHECK(c.openGLDebugContext.isSynchronous == true); + REQUIRE( + c.openGLDebugContext.identifierFilters.size() == + defaultConf.openGLDebugContext.identifierFilters.size() + ); + for (size_t i = 0; i < c.openGLDebugContext.identifierFilters.size(); i += 1) { + CHECK( + c.openGLDebugContext.identifierFilters[i].identifier == + defaultConf.openGLDebugContext.identifierFilters[i].identifier + ); + CHECK( + c.openGLDebugContext.identifierFilters[i].source == + defaultConf.openGLDebugContext.identifierFilters[i].source + ); + CHECK( + c.openGLDebugContext.identifierFilters[i].type == + defaultConf.openGLDebugContext.identifierFilters[i].type + ); + } + CHECK( + c.openGLDebugContext.severityFilters == + defaultConf.openGLDebugContext.severityFilters + ); + } + { + // identifierFilters + constexpr const char Extra[] = R"( +OpenGLDebugContext = { + Activate = true, + FilterIdentifier = { + { Identifier = 1, Source = "API", Type = "Error" }, + { Identifier = 2, Source = "Window System", Type = "Deprecated" }, + { Identifier = 3, Source = "Shader Compiler", Type = "Undefined" }, + { Identifier = 4, Source = "Third Party", Type = "Portability" }, + { Identifier = 5, Source = "Application", Type = "Performance" }, + { Identifier = 6, Source = "Other", Type = "Marker" }, + { Identifier = 7, Source = "Don't care", Type = "Push group" }, + { Identifier = 8, Source = "API", Type = "Pop group" }, + { Identifier = 9, Source = "Window System", Type = "Other" }, + { Identifier = 10, Source = "Shader Compiler", Type = "Don't care" } + } +} +)"; + const Configuration c = loadConfiguration("openGLDebugContext3", Extra); + CHECK(c.openGLDebugContext.isActive == true); + CHECK( + c.openGLDebugContext.isSynchronous == + defaultConf.openGLDebugContext.isSynchronous + ); + REQUIRE(c.openGLDebugContext.identifierFilters.size() == 10); + CHECK(c.openGLDebugContext.identifierFilters[0].identifier == 1); + CHECK(c.openGLDebugContext.identifierFilters[0].source == "API"); + CHECK(c.openGLDebugContext.identifierFilters[0].type == "Error"); + CHECK(c.openGLDebugContext.identifierFilters[1].identifier == 2); + CHECK(c.openGLDebugContext.identifierFilters[1].source == "Window System"); + CHECK(c.openGLDebugContext.identifierFilters[1].type == "Deprecated"); + CHECK(c.openGLDebugContext.identifierFilters[2].identifier == 3); + CHECK(c.openGLDebugContext.identifierFilters[2].source == "Shader Compiler"); + CHECK(c.openGLDebugContext.identifierFilters[2].type == "Undefined"); + CHECK(c.openGLDebugContext.identifierFilters[3].identifier == 4); + CHECK(c.openGLDebugContext.identifierFilters[3].source == "Third Party"); + CHECK(c.openGLDebugContext.identifierFilters[3].type == "Portability"); + CHECK(c.openGLDebugContext.identifierFilters[4].identifier == 5); + CHECK(c.openGLDebugContext.identifierFilters[4].source == "Application"); + CHECK(c.openGLDebugContext.identifierFilters[4].type == "Performance"); + CHECK(c.openGLDebugContext.identifierFilters[5].identifier == 6); + CHECK(c.openGLDebugContext.identifierFilters[5].source == "Other"); + CHECK(c.openGLDebugContext.identifierFilters[5].type == "Marker"); + CHECK(c.openGLDebugContext.identifierFilters[6].identifier == 7); + CHECK(c.openGLDebugContext.identifierFilters[6].source == "Don't care"); + CHECK(c.openGLDebugContext.identifierFilters[6].type == "Push group"); + CHECK(c.openGLDebugContext.identifierFilters[7].identifier == 8); + CHECK(c.openGLDebugContext.identifierFilters[7].source == "API"); + CHECK(c.openGLDebugContext.identifierFilters[7].type == "Pop group"); + CHECK(c.openGLDebugContext.identifierFilters[8].identifier == 9); + CHECK(c.openGLDebugContext.identifierFilters[8].source == "Window System"); + CHECK(c.openGLDebugContext.identifierFilters[8].type == "Other"); + CHECK(c.openGLDebugContext.identifierFilters[9].identifier == 10); + CHECK(c.openGLDebugContext.identifierFilters[9].source == "Shader Compiler"); + CHECK(c.openGLDebugContext.identifierFilters[9].type == "Don't care"); + + CHECK( + c.openGLDebugContext.severityFilters == + defaultConf.openGLDebugContext.severityFilters + ); + } + { + // filterSeverity + constexpr const char Extra[] = R"( +OpenGLDebugContext = { Activate = true, FilterSeverity = { "High", "Medium" } } +)"; + const Configuration c = loadConfiguration("openGLDebugContext4", Extra); + CHECK(c.openGLDebugContext.isActive == true); + CHECK( + c.openGLDebugContext.isSynchronous == + defaultConf.openGLDebugContext.isSynchronous + ); + REQUIRE( + c.openGLDebugContext.identifierFilters.size() == + defaultConf.openGLDebugContext.identifierFilters.size() + ); + for (size_t i = 0; i < c.openGLDebugContext.identifierFilters.size(); i += 1) { + CHECK( + c.openGLDebugContext.identifierFilters[i].identifier == + defaultConf.openGLDebugContext.identifierFilters[i].identifier + ); + CHECK( + c.openGLDebugContext.identifierFilters[i].source == + defaultConf.openGLDebugContext.identifierFilters[i].source + ); + CHECK( + c.openGLDebugContext.identifierFilters[i].type == + defaultConf.openGLDebugContext.identifierFilters[i].type + ); + } + REQUIRE(c.openGLDebugContext.severityFilters.size() == 2); + CHECK( + c.openGLDebugContext.severityFilters == + std::vector{ "High", "Medium" } + ); + } +} + +TEST_CASE("Configuration: httpProxy", "[configuration]") { + Configuration defaultConf; + { + // empty-ish / address + port + constexpr const char Extra[] = R"( +HttpProxy = { + Address = "foobar", + Port = 1234 +} +)"; + const Configuration c = loadConfiguration("httpProxy1", Extra); + CHECK(c.httpProxy.usingHttpProxy == defaultConf.httpProxy.usingHttpProxy); + CHECK(c.httpProxy.address == "foobar"); + CHECK(c.httpProxy.port == 1234); + CHECK(c.httpProxy.authentication == defaultConf.httpProxy.authentication); + CHECK(c.httpProxy.user == defaultConf.httpProxy.user); + CHECK(c.httpProxy.password == defaultConf.httpProxy.password); + } + { + // activate + constexpr const char Extra[] = R"( +HttpProxy = { + Activate = true, + Address = "foobar", + Port = 1234 +} +)"; + const Configuration c = loadConfiguration("httpProxy2", Extra); + CHECK(c.httpProxy.usingHttpProxy == true); + CHECK(c.httpProxy.address == "foobar"); + CHECK(c.httpProxy.port == 1234); + CHECK(c.httpProxy.authentication == defaultConf.httpProxy.authentication); + CHECK(c.httpProxy.user == defaultConf.httpProxy.user); + CHECK(c.httpProxy.password == defaultConf.httpProxy.password); + } + { + // authentication + constexpr const char Extra[] = R"( +HttpProxy = { + Address = "foobar", + Port = 1234, + Authentication = "ntlm" +} +)"; + const Configuration c = loadConfiguration("httpProxy3", Extra); + CHECK(c.httpProxy.usingHttpProxy == defaultConf.httpProxy.usingHttpProxy); + CHECK(c.httpProxy.address == "foobar"); + CHECK(c.httpProxy.port == 1234); + CHECK(c.httpProxy.authentication == "ntlm"); + CHECK(c.httpProxy.user == defaultConf.httpProxy.user); + CHECK(c.httpProxy.password == defaultConf.httpProxy.password); + } + { + // user + constexpr const char Extra[] = R"( +HttpProxy = { + Address = "foobar", + Port = 1234, + User = "user-bar" +} +)"; + const Configuration c = loadConfiguration("httpProxy4", Extra); + CHECK(c.httpProxy.usingHttpProxy == defaultConf.httpProxy.usingHttpProxy); + CHECK(c.httpProxy.address == "foobar"); + CHECK(c.httpProxy.port == 1234); + CHECK(c.httpProxy.authentication == defaultConf.httpProxy.authentication); + CHECK(c.httpProxy.user == "user-bar"); + CHECK(c.httpProxy.password == defaultConf.httpProxy.password); + } + { + // password + constexpr const char Extra[] = R"( +HttpProxy = { + Address = "foobar", + Port = 1234, + Password = "password-bar" +} +)"; + const Configuration c = loadConfiguration("httpProxy5", Extra); + CHECK(c.httpProxy.usingHttpProxy == defaultConf.httpProxy.usingHttpProxy); + CHECK(c.httpProxy.address == "foobar"); + CHECK(c.httpProxy.port == 1234); + CHECK(c.httpProxy.authentication == defaultConf.httpProxy.authentication); + CHECK(c.httpProxy.user == defaultConf.httpProxy.user); + CHECK(c.httpProxy.password == "password-bar"); + } +} diff --git a/tests/test_lua_createsinglecolorimage.cpp b/tests/test_lua_createsinglecolorimage.cpp index 612b7b6af9..88b98d68ab 100644 --- a/tests/test_lua_createsinglecolorimage.cpp +++ b/tests/test_lua_createsinglecolorimage.cpp @@ -38,7 +38,7 @@ TEST_CASE("CreateSingleColorImage: Create image and check return value", ghoul::lua::push(L, "colorFile"); ghoul::lua::push(L, std::vector{ 1.0, 0.0, 0.0 }); - int res = openspace::luascriptfunctions::createSingeColorImage(L); + int res = openspace::luascriptfunctions::createSingleColorImage(L); // One return value CHECK(res == 1); @@ -58,7 +58,7 @@ TEST_CASE("CreateSingleColorImage: Faulty 1st input type", "[createsinglecolorim ghoul::lua::push(L, std::vector{ 1.0, 0.0, 0.0 }); CHECK_THROWS_WITH( - openspace::luascriptfunctions::createSingeColorImage(L), + openspace::luascriptfunctions::createSingleColorImage(L), Catch::Matchers::Contains("parameter 1 was not the expected type") ); } @@ -69,7 +69,7 @@ TEST_CASE("CreateSingleColorImage: Faulty 2nd input type", "[createsinglecolorim ghoul::lua::push(L, "not a vector"); CHECK_THROWS_WITH( - openspace::luascriptfunctions::createSingeColorImage(L), + openspace::luascriptfunctions::createSingleColorImage(L), Catch::Matchers::Contains("parameter 2 was not the expected type") ); } @@ -80,7 +80,7 @@ TEST_CASE("CreateSingleColorImage: Invalid number of inputs", "[createsinglecolo ghoul::lua::push(L, std::vector{ 1.0, 0.0, 0.0 }); CHECK_THROWS_WITH( - openspace::luascriptfunctions::createSingeColorImage(L), + openspace::luascriptfunctions::createSingleColorImage(L), Catch::Matchers::Contains("Expected 2 arguments, got 1") ); } @@ -93,7 +93,7 @@ TEST_CASE("CreateSingleColorImage: Faulty color value (vec4)", ghoul::lua::push(L, std::vector{ 1.0, 0.0, 0.0, 0.0 }); CHECK_THROWS_WITH( - openspace::luascriptfunctions::createSingeColorImage(L), + openspace::luascriptfunctions::createSingleColorImage(L), Catch::Matchers::Contains( "Invalid color. Expected three double values {r, g, b} in range 0 to 1" ) @@ -108,7 +108,7 @@ TEST_CASE("CreateSingleColorImage: Faulty color value (invalid values)", ghoul::lua::push(L, std::vector{ 255.0, 0.0, 0.0 }); // not a valid color CHECK_THROWS_WITH( - openspace::luascriptfunctions::createSingeColorImage(L), + openspace::luascriptfunctions::createSingleColorImage(L), Catch::Matchers::Contains( "Invalid color. Expected three double values {r, g, b} in range 0 to 1" ) @@ -122,7 +122,7 @@ TEST_CASE("CreateSingleColorImage: Check if file was created", ghoul::lua::push(L, "colorFile2"); ghoul::lua::push(L, std::vector{ 0.0, 1.0, 0.0 }); - int res = openspace::luascriptfunctions::createSingeColorImage(L); + int res = openspace::luascriptfunctions::createSingleColorImage(L); CHECK(res == 1); std::string path = ghoul::lua::value(L, 1); @@ -135,7 +135,7 @@ TEST_CASE("CreateSingleColorImage: Load created image", "[createsinglecolorimage ghoul::lua::push(L, std::vector{ 1.0, 0.0, 0.0 }); // Loads the same file that was created in a previous test case - int res = openspace::luascriptfunctions::createSingeColorImage(L); + int res = openspace::luascriptfunctions::createSingleColorImage(L); CHECK(res == 1); CHECK(lua_gettop(L) == 1);