diff --git a/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp b/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp index 650437baf5..8702e0e8da 100644 --- a/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp +++ b/apps/OpenSpace/ext/launcher/src/launcherwindow.cpp @@ -382,6 +382,23 @@ void LauncherWindow::populateProfilesList(std::string preset) { } } +// Returns 'true' if the file was a configuration file, 'false' otherwise +bool handleConfigurationFile(QComboBox& box, const std::filesystem::directory_entry& p) { + const bool isXml = p.path().extension() == ".xml"; + const bool isJson = p.path().extension() == ".json"; + if (!isXml && !isJson) { + return false; + } + box.addItem(QString::fromStdString(p.path().filename().string())); + + // For now, mark the XML configuration files to show that they are deprecated + if (isXml) { + box.setItemData(box.count() - 1, QBrush(Qt::darkYellow), Qt::ForegroundRole); + } + + return true; +} + void LauncherWindow::populateWindowConfigsList(std::string preset) { namespace fs = std::filesystem; @@ -389,28 +406,32 @@ void LauncherWindow::populateWindowConfigsList(std::string preset) { _userConfigCount = 0; _windowConfigBox->addItem(QString::fromStdString("--- User Configurations ---")); - const QStandardItemModel* model = qobject_cast(_windowConfigBox->model()); + const QStandardItemModel* model = + qobject_cast(_windowConfigBox->model()); + model->item(_userConfigCount)->setEnabled(false); ++_userConfigCount; - // Add all the files with the .xml extension to the dropdown + + bool hasXmlConfig = false; + + // Add all the files with the .xml or .json extension to the dropdown for (const fs::directory_entry& p : fs::directory_iterator(_userConfigPath)) { - if (p.path().extension() != ".xml") { - continue; + bool isConfigFile = handleConfigurationFile(*_windowConfigBox, p); + if (isConfigFile) { + ++_userConfigCount; } - _windowConfigBox->addItem(QString::fromStdString(p.path().stem().string())); - ++_userConfigCount; + + hasXmlConfig |= p.path().extension() == ".xml"; } _windowConfigBox->addItem(QString::fromStdString("--- OpenSpace Configurations ---")); model = qobject_cast(_windowConfigBox->model()); model->item(_userConfigCount)->setEnabled(false); if (std::filesystem::exists(_configPath)) { - // Add all the files with the .xml extension to the dropdown + // Add all the files with the .xml or .json extension to the dropdown for (const fs::directory_entry& p : fs::directory_iterator(_configPath)) { - if (p.path().extension() != ".xml") { - continue; - } - _windowConfigBox->addItem(QString::fromStdString(p.path().stem().string())); + handleConfigurationFile(*_windowConfigBox, p); + hasXmlConfig |= p.path().extension() == ".xml"; } } else { @@ -420,6 +441,17 @@ void LauncherWindow::populateWindowConfigsList(std::string preset) { ); } + if (hasXmlConfig) { + // At least one XML configuration file is present, so we should show the tooltip + // informing the user that files will be deprecated + _windowConfigBox->setToolTip( + "Support for XML-based configuration files will be removed in the next " + "version of OpenSpace. Please convert the files to the new JSON format or " + "run the Node tool at " + "https://github.com/sgct/sgct/tree/master/support/config-converter" + ); + } + // Try to find the requested configuration file and set it as the current one. As we // have support for function-generated configuration files that will not be in the // list we need to add a preset that doesn't exist a file for @@ -434,7 +466,7 @@ void LauncherWindow::populateWindowConfigsList(std::string preset) { } } -void LauncherWindow::openProfileEditor(const std::string& profile, const bool isUserProfile) { +void LauncherWindow::openProfileEditor(const std::string& profile, bool isUserProfile) { std::optional p; std::string saveProfilePath = isUserProfile ? _userProfilePath : _profilePath; if (profile.empty()) { diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index 138e0b2065..15c2a977e1 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit 138e0b20653af97e777b61f40ea04976005bd69c +Subproject commit 15c2a977e16350f9c98a4ef74d6b35a43d35b0bb diff --git a/apps/OpenSpace/main.cpp b/apps/OpenSpace/main.cpp index d683fec60c..7757d0b47e 100644 --- a/apps/OpenSpace/main.cpp +++ b/apps/OpenSpace/main.cpp @@ -989,8 +989,7 @@ std::string setWindowConfigPresetForGui(const std::string labelFromCfgFile, std::string selectedSgctProfileFromLauncher(LauncherWindow& lw, bool hasCliSGCTConfig, std::string windowConfiguration, - const std::string& labelFromCfgFile, - const std::string& xmlExt) + const std::string& labelFromCfgFile) { std::string config = windowConfiguration; if (!hasCliSGCTConfig) { @@ -1004,13 +1003,31 @@ std::string selectedSgctProfileFromLauncher(LauncherWindow& lw, bool hasCliSGCTC } } else { - if (std::filesystem::path(config).extension() == ".xml") { - //user customzied sgct config + std::filesystem::path c = absPath(config); + + std::filesystem::path cj = c; + cj.replace_extension(".json"); + + std::filesystem::path cx = c; + cx.replace_extension(".xml"); + + if (c.extension().empty()) { + if (std::filesystem::exists(cj)) { + config += ".json"; + } + else if (std::filesystem::exists(cx)) { + config += ".xml"; + } + else { + throw ghoul::RuntimeError(fmt::format( + "Error loading configuration file {}. File could not be found", + config + )); + } } else { - config += xmlExt; + // user customzied sgct config } - } global::configuration->windowConfiguration = config; } @@ -1163,7 +1180,6 @@ int main(int argc, char* argv[]) { // Call profile GUI const std::string labelFromCfgFile = " (from .cfg)"; - const std::string xmlExt = ".xml"; std::string windowCfgPreset = setWindowConfigPresetForGui( labelFromCfgFile, hasSGCTConfig, @@ -1211,8 +1227,7 @@ int main(int argc, char* argv[]) { win, hasSGCTConfig, windowConfiguration, - labelFromCfgFile, - xmlExt + labelFromCfgFile ); } else { glfwInit(); diff --git a/config/equirectangular_gui.json b/config/equirectangular_gui.json new file mode 100644 index 0000000000..fe744ef269 --- /dev/null +++ b/config/equirectangular_gui.json @@ -0,0 +1,58 @@ +{ + "version": 1, + "masteraddress": "localhost", + "externalcontrolport": 20500, + "settings": { + "display": { + "swapinterval": 0 + } + }, + "nodes": [ + { + "address": "localhost", + "port": 20401, + "windows": [ + { + "name": "OpenSpace", + "fullscreen": false, + "draw2d": false, + "stereo": "none", + "pos": { "x": 50, "y": 50 }, + "size": { "x": 1280, "y": 720 }, + "viewports": [ + { + "tracked": true, + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "EquirectangularProjection", + "quality": "1k" + } + } + ] + }, + { + "name": "GUI", + "tags": [ "GUI" ], + "fullscreen": false, + "draw3d": false, + "stereo": "none", + "pos": { "x": 50, "y": 50 }, + "size": { "x": 1280, "y": 720 }, + "viewports": [ + { + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.065, + "pos": { "x": 0.0, "y": 0.0, "z": 0.0 } + } + ] +} diff --git a/config/equirectangular_gui.xml b/config/equirectangular_gui.xml deleted file mode 100644 index 98c6d545bb..0000000000 --- a/config/equirectangular_gui.xml +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/config/fullscreen1080.json b/config/fullscreen1080.json new file mode 100644 index 0000000000..59ef891571 --- /dev/null +++ b/config/fullscreen1080.json @@ -0,0 +1,47 @@ +{ + "version": 1, + "masteraddress": "localhost", + "externalcontrolport": 20500, + "settings": { + "display": { + "swapinterval": 0 + } + }, + "nodes": [ + { + "address": "localhost", + "port": 20401, + "windows": [ + { + "fullscreen": true, + "name": "OpenSpace", + "msaa": 4, + "stereo": "none", + "pos": { "x": 0, "y": 0 }, + "size": { "x": 1920, "y": 1080 }, + "viewports": [ + { + "tracked": true, + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "PlanarProjection", + "fov": { + "hfov": 80.0, + "vfov": 50.534015846724 + }, + "orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 } + } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.065, + "pos": { "x": 0.0, "y": 0.0, "z": 0.0 } + } + ] +} diff --git a/config/fullscreen1080.xml b/config/fullscreen1080.xml deleted file mode 100644 index 52d703f435..0000000000 --- a/config/fullscreen1080.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/config/gui_projector.json b/config/gui_projector.json new file mode 100644 index 0000000000..7afdaa45df --- /dev/null +++ b/config/gui_projector.json @@ -0,0 +1,64 @@ +{ + "version": 1, + "masteraddress": "localhost", + "externalcontrolport": 20500, + "settings": { + "display": { + "swapinterval": 0 + } + }, + "nodes": [ + { + "address": "localhost", + "port": 20401, + "windows": [ + { + "fullscreen": true, + "monitor": 1, + "name": "OpenSpace", + "draw2d": false, + "stereo": "none", + "pos": { "x": 0, "y": 0 }, + "size": { "x": 1920, "y": 1080 }, + "viewports": [ + { + "tracked": true, + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "PlanarProjection", + "fov": { + "hfov": 80.0, + "vfov": 50.534015846724 + }, + "orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 } + } + } + ] + }, + { + "fullscreen": false, + "border": false, + "name": "GUI", + "tags": [ "GUI" ], + "draw3d": false, + "stereo": "none", + "pos": { "x": 0, "y": 0 }, + "size": { "x": 1920, "y": 1080 }, + "viewports": [ + { + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.065, + "pos": { "x": 0.0, "y": 0.0, "z": 0.0 } + } + ] +} diff --git a/config/gui_projector.xml b/config/gui_projector.xml deleted file mode 100644 index 9ac213193b..0000000000 --- a/config/gui_projector.xml +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/config/openvr_htcVive.xml b/config/openvr_htcVive.xml deleted file mode 100644 index c5ab46597a..0000000000 --- a/config/openvr_htcVive.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/config/openvr_oculusRiftCv1.xml b/config/openvr_oculusRiftCv1.xml deleted file mode 100644 index 665715fb53..0000000000 --- a/config/openvr_oculusRiftCv1.xml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/config/single.json b/config/single.json new file mode 100644 index 0000000000..b471846706 --- /dev/null +++ b/config/single.json @@ -0,0 +1,46 @@ +{ + "version": 1, + "masteraddress": "localhost", + "externalcontrolport": 20500, + "settings": { + "display": { + "swapinterval": 0 + } + }, + "nodes": [ + { + "address": "localhost", + "port": 20401, + "windows": [ + { + "name": "OpenSpace", + "fullscreen": false, + "stereo": "none", + "pos": { "x": 50, "y": 50 }, + "size": { "x": 1280, "y": 720 }, + "viewports": [ + { + "tracked": true, + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "PlanarProjection", + "fov": { + "hfov": 80.0, + "vfov": 50.534015846724 + }, + "orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 } + } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.065, + "pos": { "x": 0.0, "y": 0.0, "z": 0.0 } + } + ] +} diff --git a/config/single.xml b/config/single.xml deleted file mode 100644 index 6ec2d5a125..0000000000 --- a/config/single.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/config/single_fisheye.json b/config/single_fisheye.json new file mode 100644 index 0000000000..adfacbe680 --- /dev/null +++ b/config/single_fisheye.json @@ -0,0 +1,37 @@ +{ + "version": 1, + "masteraddress": "localhost", + "nodes": [ + { + "address": "localhost", + "port": 20401, + "windows": [ + { + "name": "OpenSpace", + "fullscreen": false, + "stereo": "none", + "size": { "x": 1024, "y": 1024 }, + "viewports": [ + { + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "FisheyeProjection", + "fov": 180.0, + "quality": "1k", + "tilt": 27.0, + "background": { "r": 0.1, "g": 0.1, "b": 0.1, "a": 1.0 } + } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.06, + "pos": { "x": 0.0, "y": 0.0, "z": 0.0 } + } + ] +} diff --git a/config/single_fisheye.xml b/config/single_fisheye.xml deleted file mode 100644 index e27230e520..0000000000 --- a/config/single_fisheye.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/config/single_fisheye_gui.json b/config/single_fisheye_gui.json new file mode 100644 index 0000000000..6c78d1ecfd --- /dev/null +++ b/config/single_fisheye_gui.json @@ -0,0 +1,61 @@ +{ + "version": 1, + "masteraddress": "localhost", + "nodes": [ + { + "address": "localhost", + "port": 20401, + "windows": [ + { + "name": "OpenSpace", + "fullscreen": false, + "draw2d": false, + "stereo": "none", + "size": { "x": 1024, "y": 1024 }, + "viewports": [ + { + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "FisheyeProjection", + "fov": 180.0, + "quality": "1k", + "tilt": 27.0, + "background": { "r": 0.1, "g": 0.1, "b": 0.1, "a": 1.0 } + } + } + ] + }, + { + "name": "GUI", + "tags": [ "GUI" ], + "fullscreen": false, + "draw3d": false, + "stereo": "none", + "pos": { "x": 50, "y": 50 }, + "size": { "x": 1024, "y": 1024 }, + "viewports": [ + { + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "PlanarProjection", + "fov": { + "hfov": 80.0, + "vfov": 50.534015846724 + }, + "orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 } + } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.06, + "pos": { "x": 0.0, "y": 0.0, "z": 0.0 } + } + ] +} diff --git a/config/single_fisheye_gui.xml b/config/single_fisheye_gui.xml deleted file mode 100644 index 794a03b056..0000000000 --- a/config/single_fisheye_gui.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/config/single_gui.json b/config/single_gui.json new file mode 100644 index 0000000000..9149d936da --- /dev/null +++ b/config/single_gui.json @@ -0,0 +1,70 @@ +{ + "version": 1, + "masteraddress": "localhost", + "externalcontrolport": 20500, + "settings": { + "display": { + "swapinterval": 0 + } + }, + "nodes": [ + { + "address": "localhost", + "port": 20401, + "windows": [ + { + "name": "OpenSpace", + "fullscreen": false, + "draw2d": false, + "stereo": "none", + "pos": { "x": 50, "y": 50 }, + "size": { "x": 1280, "y": 720 }, + "viewports": [ + { + "tracked": true, + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "PlanarProjection", + "fov": { + "hfov": 80.0, + "vfov": 50.534015846724 + }, + "orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 } + } + } + ] + }, + { + "name": "GUI", + "tags": [ "GUI" ], + "fullscreen": false, + "draw3d": false, + "stereo": "none", + "pos": { "x": 50, "y": 50 }, + "size": { "x": 1280, "y": 720 }, + "viewports": [ + { + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "PlanarProjection", + "fov": { + "hfov": 80.0, + "vfov": 50.534015846724 + }, + "orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 } + } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.065, + "pos": { "x": 0.0, "y": 0.0, "z": 0.0 } + } + ] +} diff --git a/config/single_gui.xml b/config/single_gui.xml deleted file mode 100644 index 832273090e..0000000000 --- a/config/single_gui.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/config/single_sbs_stereo.json b/config/single_sbs_stereo.json new file mode 100644 index 0000000000..2c0019f083 --- /dev/null +++ b/config/single_sbs_stereo.json @@ -0,0 +1,46 @@ +{ + "version": 1, + "masteraddress": "localhost", + "externalcontrolport": 20500, + "settings": { + "display": { + "swapinterval": 0 + } + }, + "nodes": [ + { + "address": "localhost", + "port": 20401, + "windows": [ + { + "name": "OpenSpace", + "fullscreen": false, + "stereo": "side_by_side", + "pos": { "x": 50, "y": 50 }, + "size": { "x": 1280, "y": 720 }, + "viewports": [ + { + "tracked": true, + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "PlanarProjection", + "fov": { + "hfov": 80.0, + "vfov": 50.534015846724 + }, + "orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 } + } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.065, + "pos": { "x": 0.0, "y": 0.0, "z": 0.0 } + } + ] +} diff --git a/config/single_sbs_stereo.xml b/config/single_sbs_stereo.xml deleted file mode 100644 index e0707559c1..0000000000 --- a/config/single_sbs_stereo.xml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/config/single_two_win.json b/config/single_two_win.json new file mode 100644 index 0000000000..caaefa2cb1 --- /dev/null +++ b/config/single_two_win.json @@ -0,0 +1,59 @@ +{ + "version": 1, + "masteraddress": "127.0.0.1", + "nodes": [ + { + "address": "127.0.0.1", + "port": 20401, + "windows": [ + { + "border": true, + "fullscreen": false, + "pos": { "x": 10, "y": 100 }, + "size": { "x": 1280, "y": 720 }, + "viewports": [ + { + "tracked": true, + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "PlanarProjection", + "fov": { + "hfov": 80.0, + "vfov": 50.534015846724 + }, + "orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 } + } + } + ] + }, + { + "border": true, + "fullscreen": false, + "pos": { "x": 340, "y": 100 }, + "size": { "x": 1280, "y": 720 }, + "viewports": [ + { + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "PlanarProjection", + "fov": { + "hfov": 80.0, + "vfov": 50.534015846724 + }, + "orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 } + } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.065, + "pos": { "x": 0.0, "y": 0.0, "z": 4.0 } + } + ] +} diff --git a/config/single_two_win.xml b/config/single_two_win.xml deleted file mode 100644 index ed1b09fc04..0000000000 --- a/config/single_two_win.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/config/spherical_mirror.json b/config/spherical_mirror.json new file mode 100644 index 0000000000..f8f1e5669c --- /dev/null +++ b/config/spherical_mirror.json @@ -0,0 +1,40 @@ +{ + "version": 1, + "masteraddress": "127.0.0.1", + "nodes": [ + { + "address": "127.0.0.1", + "port": 20401, + "windows": [ + { + "fullscreen": false, + "name": "Spherical Projection", + "stereo": "none", + "pos": { "x": 0, "y": 100 }, + "size": { "x": 1280, "y": 720 }, + "res": { "x": 2048, "y": 2048 }, + "viewports": [ + { + "mesh": "mesh/standard_16x9.data", + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "FisheyeProjection", + "fov": 180.0, + "quality": "2k", + "tilt": 30.0, + "background": { "r": 0.1, "g": 0.1, "b": 0.1, "a": 1.0 } + } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.06, + "pos": { "x": 0.0, "y": 0.0, "z": 0.0 } + } + ] +} diff --git a/config/spherical_mirror.xml b/config/spherical_mirror.xml deleted file mode 100644 index f15de39d45..0000000000 --- a/config/spherical_mirror.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/config/spherical_mirror_gui.json b/config/spherical_mirror_gui.json new file mode 100644 index 0000000000..07d4ffbd7a --- /dev/null +++ b/config/spherical_mirror_gui.json @@ -0,0 +1,65 @@ +{ + "version": 1, + "masteraddress": "127.0.0.1", + "nodes": [ + { + "address": "127.0.0.1", + "port": 20401, + "windows": [ + { + "fullscreen": false, + "name": "Spherical Projection", + "stereo": "none", + "draw2d": false, + "pos": { "x": 0, "y": 100 }, + "size": { "x": 1280, "y": 720 }, + "res": { "x": 2048, "y": 2048 }, + "viewports": [ + { + "mesh": "mesh/standard_16x9.data", + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "FisheyeProjection", + "fov": 180.0, + "quality": "2k", + "tilt": 30.0, + "background": { "r": 0.1, "g": 0.1, "b": 0.1, "a": 1.0 } + } + } + ] + }, + { + "fullscreen": false, + "name": "GUI", + "tags": [ "GUI" ], + "draw3d": false, + "stereo": "none", + "pos": { "x": 50, "y": 50 }, + "size": { "x": 1280, "y": 720 }, + "res": { "x": 2048, "y": 2048 }, + "viewports": [ + { + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "PlanarProjection", + "fov": { + "hfov": 80.0, + "vfov": 50.534015846724 + }, + "orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 } + } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.06, + "pos": { "x": 0.0, "y": 0.0, "z": 0.0 } + } + ] +} diff --git a/config/spherical_mirror_gui.xml b/config/spherical_mirror_gui.xml deleted file mode 100644 index e1e84e46df..0000000000 --- a/config/spherical_mirror_gui.xml +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/config/spout_output.json b/config/spout_output.json new file mode 100644 index 0000000000..a6d5d1148d --- /dev/null +++ b/config/spout_output.json @@ -0,0 +1,36 @@ +{ + "version": 1, + "masteraddress": "localhost", + "nodes": [ + { + "address": "localhost", + "port": 20401, + "windows": [ + { + "fullscreen": false, + "name": "OpenSpace", + "stereo": "none", + "size": { "x": 1024, "y": 1024 }, + "viewports": [ + { + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "SpoutOutputProjection", + "quality": "1k", + "mappingspoutname": "OpenSpace", + "background": { "r": 0.1, "g": 0.1, "b": 0.1, "a": 1.0 } + } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.06, + "pos": { "x": 0.0, "y": 0.0, "z": 0.0 } + } + ] +} diff --git a/config/spout_output.xml b/config/spout_output.xml deleted file mode 100644 index da4efdc48f..0000000000 --- a/config/spout_output.xml +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/config/two_nodes.json b/config/two_nodes.json new file mode 100644 index 0000000000..723250a6f0 --- /dev/null +++ b/config/two_nodes.json @@ -0,0 +1,64 @@ +{ + "version": 1, + "masteraddress": "127.0.0.1", + "nodes": [ + { + "address": "127.0.0.1", + "port": 20401, + "windows": [ + { + "fullscreen": false, + "pos": { "x": 0, "y": 300 }, + "size": { "x": 1280, "y": 720 }, + "viewports": [ + { + "tracked": true, + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "PlanarProjection", + "fov": { + "hfov": 80.0, + "vfov": 50.534015846724 + }, + "orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 } + } + } + ] + } + ] + }, + { + "address": "127.0.0.2", + "port": 20402, + "windows": [ + { + "fullscreen": false, + "pos": { "x": 640, "y": 300 }, + "size": { "x": 1280, "y": 720 }, + "viewports": [ + { + "tracked": true, + "pos": { "x": 0.0, "y": 0.0 }, + "size": { "x": 1.0, "y": 1.0 }, + "projection": { + "type": "PlanarProjection", + "fov": { + "hfov": 80.0, + "vfov": 50.534015846724 + }, + "orientation": { "yaw": 0.0, "pitch": 0.0, "roll": 0.0 } + } + } + ] + } + ] + } + ], + "users": [ + { + "eyeseparation": 0.065, + "pos": { "x": 0.0, "y": 0.0, "z": 4.0 } + } + ] +} diff --git a/config/two_nodes.xml b/config/two_nodes.xml deleted file mode 100644 index e47946d5ef..0000000000 --- a/config/two_nodes.xml +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/data/assets/scene/solarsystem/planets/mars/default_layers.asset b/data/assets/scene/solarsystem/planets/mars/default_layers.asset index f691513188..198fa783b5 100644 --- a/data/assets/scene/solarsystem/planets/mars/default_layers.asset +++ b/data/assets/scene/solarsystem/planets/mars/default_layers.asset @@ -20,7 +20,7 @@ asset.require("./layers/colorlayers/hirisels") -- Height layers asset.require("./layers/heightlayers/mola_sweden") asset.require("./layers/heightlayers/mola_utah") -local heightLayer = asset.require("./layers/heightlayers/mdem200m") +local heightLayer = asset.require("./layers/heightlayers/MDEM200M") asset.require("./layers/heightlayers/hirisels") -- Overlays diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index eca2e190a7..203b14ea9d 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -3,7 +3,7 @@ asset.require("./static_server") local guiCustomization = asset.require("customization/gui") -- Select which commit hashes to use for the frontend and backend -local frontendHash = "4fe18eea379c8493dbcb2cea6798d09a85819912" +local frontendHash = "7e513ba86b0bb989b72f22712ebf0bb5a626ba06" local dataProvider = "data.openspaceproject.com/files/webgui" local frontend = asset.syncedResource({ diff --git a/include/openspace/navigation/orbitalnavigator.h b/include/openspace/navigation/orbitalnavigator.h index f541e78788..6820a2cfd9 100644 --- a/include/openspace/navigation/orbitalnavigator.h +++ b/include/openspace/navigation/orbitalnavigator.h @@ -148,6 +148,7 @@ private: // Reset camera direction to the aim node. properties::TriggerProperty _retargetAim; + properties::BoolProperty _followAnchorNodeRotation; properties::FloatProperty _followAnchorNodeRotationDistance; properties::FloatProperty _minimumAllowedDistance; diff --git a/include/openspace/navigation/pathnavigator.h b/include/openspace/navigation/pathnavigator.h index dbf8940825..b993d086bc 100644 --- a/include/openspace/navigation/pathnavigator.h +++ b/include/openspace/navigation/pathnavigator.h @@ -81,6 +81,8 @@ public: static scripting::LuaLibrary luaLibrary(); private: + void handlePathEnd(); + /** * Populate list of nodes that are relevant for collision checks, etc */ @@ -90,6 +92,7 @@ private: std::unique_ptr _currentPath = nullptr; bool _isPlaying = false; + bool _startSimulationTimeOnFinish = false; properties::OptionProperty _defaultPathType; properties::BoolProperty _includeRoll; diff --git a/modules/atmosphere/atmospheremodule.cpp b/modules/atmosphere/atmospheremodule.cpp index 2d973d535b..c98166061f 100644 --- a/modules/atmosphere/atmospheremodule.cpp +++ b/modules/atmosphere/atmospheremodule.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -40,4 +41,9 @@ void AtmosphereModule::internalInitialize(const ghoul::Dictionary&) { fRenderable->registerClass("RenderableAtmosphere"); } +std::vector AtmosphereModule::documentations() const { + return { + RenderableAtmosphere::Documentation() + }; +} } // namespace openspace diff --git a/modules/atmosphere/atmospheremodule.h b/modules/atmosphere/atmospheremodule.h index 9ffb525245..82bc925158 100644 --- a/modules/atmosphere/atmospheremodule.h +++ b/modules/atmosphere/atmospheremodule.h @@ -35,6 +35,8 @@ public: AtmosphereModule(); + std::vector documentations() const override; + private: void internalInitialize(const ghoul::Dictionary&) override; }; diff --git a/modules/base/basemodule.cpp b/modules/base/basemodule.cpp index 895a00e93b..00a1b14ec8 100644 --- a/modules/base/basemodule.cpp +++ b/modules/base/basemodule.cpp @@ -197,11 +197,16 @@ std::vector BaseModule::documentations() const { DashboardItemDistance::Documentation(), DashboardItemFramerate::Documentation(), DashboardItemMission::Documentation(), + DashboardItemParallelConnection::Documentation(), + DashboardItemPropertyValue::Documentation(), DashboardItemSimulationIncrement::Documentation(), DashboardItemSpacing::Documentation(), + DashboardItemText::Documentation(), DashboardItemVelocity::Documentation(), RenderableBoxGrid::Documentation(), + RenderableCartesianAxes::Documentation(), + RenderableDisc::Documentation(), RenderableGrid::Documentation(), RenderableLabels::Documentation(), RenderableModel::Documentation(), @@ -210,8 +215,8 @@ std::vector BaseModule::documentations() const { RenderablePlaneImageLocal::Documentation(), RenderablePlaneImageOnline::Documentation(), RenderablePlaneTimeVaryingImage::Documentation(), + RenderablePrism::Documentation(), RenderableRadialGrid::Documentation(), - RenderableDisc::Documentation(), RenderableSphere::Documentation(), RenderableSphericalGrid::Documentation(), RenderableTimeVaryingSphere::Documentation(), @@ -241,8 +246,8 @@ std::vector BaseModule::documentations() const { TimeFrameInterval::Documentation(), TimeFrameUnion::Documentation(), - SceneGraphLightSource::Documentation(), CameraLightSource::Documentation(), + SceneGraphLightSource::Documentation() }; } diff --git a/modules/base/dashboard/dashboarditemmission.cpp b/modules/base/dashboard/dashboarditemmission.cpp index ae584d2732..d86dadb5e2 100644 --- a/modules/base/dashboard/dashboarditemmission.cpp +++ b/modules/base/dashboard/dashboarditemmission.cpp @@ -55,6 +55,12 @@ namespace { namespace openspace { +documentation::Documentation DashboardItemMission::Documentation() { + documentation::Documentation doc = DashboardTextItem::Documentation(); + doc.id = "base_dashboarditem_mission"; + return doc; +} + DashboardItemMission::DashboardItemMission(const ghoul::Dictionary& dictionary) : DashboardTextItem(dictionary, 15.f) {} diff --git a/modules/base/dashboard/dashboarditemmission.h b/modules/base/dashboard/dashboarditemmission.h index 6de41c30e5..d197f79a21 100644 --- a/modules/base/dashboard/dashboarditemmission.h +++ b/modules/base/dashboard/dashboarditemmission.h @@ -39,6 +39,8 @@ public: void render(glm::vec2& penPosition) override; glm::vec2 size() const override; + + static documentation::Documentation Documentation(); }; } // namespace openspace diff --git a/modules/base/dashboard/dashboarditemparallelconnection.cpp b/modules/base/dashboard/dashboarditemparallelconnection.cpp index 13f3375077..02e68e00dc 100644 --- a/modules/base/dashboard/dashboarditemparallelconnection.cpp +++ b/modules/base/dashboard/dashboarditemparallelconnection.cpp @@ -38,6 +38,12 @@ namespace openspace { +documentation::Documentation DashboardItemParallelConnection::Documentation() { + documentation::Documentation doc = DashboardTextItem::Documentation(); + doc.id = "base_dashboarditem_parallelconnection"; + return doc; +} + DashboardItemParallelConnection::DashboardItemParallelConnection( const ghoul::Dictionary& dictionary) : DashboardTextItem(dictionary) diff --git a/modules/base/dashboard/dashboarditemparallelconnection.h b/modules/base/dashboard/dashboarditemparallelconnection.h index f643eff442..4b4f5c12a7 100644 --- a/modules/base/dashboard/dashboarditemparallelconnection.h +++ b/modules/base/dashboard/dashboarditemparallelconnection.h @@ -39,6 +39,8 @@ public: void render(glm::vec2& penPosition) override; glm::vec2 size() const override; + + static documentation::Documentation Documentation(); }; } // namespace openspace diff --git a/modules/fieldlinessequence/fieldlinessequencemodule.cpp b/modules/fieldlinessequence/fieldlinessequencemodule.cpp index 8184781050..b832c33571 100644 --- a/modules/fieldlinessequence/fieldlinessequencemodule.cpp +++ b/modules/fieldlinessequence/fieldlinessequencemodule.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -65,4 +66,10 @@ void FieldlinesSequenceModule::internalInitialize(const ghoul::Dictionary&) { factory->registerClass("RenderableFieldlinesSequence"); } +std::vector FieldlinesSequenceModule::documentations() const { + return { + RenderableFieldlinesSequence::Documentation() + }; +} + } // namespace openspace diff --git a/modules/fieldlinessequence/fieldlinessequencemodule.h b/modules/fieldlinessequence/fieldlinessequencemodule.h index 45c444ffaf..28e83c560a 100644 --- a/modules/fieldlinessequence/fieldlinessequencemodule.h +++ b/modules/fieldlinessequence/fieldlinessequencemodule.h @@ -35,6 +35,8 @@ public: FieldlinesSequenceModule(); + std::vector documentations() const override; + static std::string DefaultTransferFunctionFile; private: diff --git a/modules/galaxy/galaxymodule.cpp b/modules/galaxy/galaxymodule.cpp index 06670632d4..f2917b8be5 100644 --- a/modules/galaxy/galaxymodule.cpp +++ b/modules/galaxy/galaxymodule.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -47,4 +48,12 @@ void GalaxyModule::internalInitialize(const ghoul::Dictionary&) { fTask->registerClass("MilkywayPointsConversionTask"); } +std::vector GalaxyModule::documentations() const { + return { + RenderableGalaxy::Documentation(), + MilkywayConversionTask::Documentation(), + MilkywayPointsConversionTask::Documentation() + }; +} + } // namespace openspace diff --git a/modules/galaxy/galaxymodule.h b/modules/galaxy/galaxymodule.h index f34f294da5..8664ed84d7 100644 --- a/modules/galaxy/galaxymodule.h +++ b/modules/galaxy/galaxymodule.h @@ -35,6 +35,8 @@ public: GalaxyModule(); + std::vector documentations() const override; + private: void internalInitialize(const ghoul::Dictionary&) override; }; diff --git a/modules/galaxy/rendering/renderablegalaxy.cpp b/modules/galaxy/rendering/renderablegalaxy.cpp index ce1602f36d..ead0306bcb 100644 --- a/modules/galaxy/rendering/renderablegalaxy.cpp +++ b/modules/galaxy/rendering/renderablegalaxy.cpp @@ -55,7 +55,7 @@ namespace { constexpr int8_t CurrentCacheVersion = 1; - constexpr const char* _loggerCat = "Renderable Galaxy"; + constexpr const char* _loggerCat = "RenderableGalaxy"; enum StarRenderingMethod { Points, @@ -75,37 +75,45 @@ namespace { constexpr openspace::properties::Property::PropertyInfo VolumeRenderingEnabledInfo = { "VolumeRenderingEnabled", "Volume Rendering", - "" // @TODO Missing documentation + "If this value is enabled, the volume rendering component of the galaxy " + "rendering is turned on. Otherwise, the volume rendering is skipped" }; constexpr openspace::properties::Property::PropertyInfo StarRenderingEnabledInfo = { "StarRenderingEnabled", "Star Rendering", - "" // @TODO Missing documentation + "If this value is enabled, the point-based star rendering component of the " + "galaxy rendering is turned on. Otherwise, the volume rendering is skipped" }; constexpr openspace::properties::Property::PropertyInfo StepSizeInfo = { "StepSize", "Step Size", - "" // @TODO Missing documentation + "Determines the distance between steps taken in the volume rendering. The lower " + "the number is, the better the rendering looks, but also takes more " + "computational resources to render" }; constexpr openspace::properties::Property::PropertyInfo AbsorptionMultiplyInfo = { "AbsorptionMultiply", "Absorption Multiplier", - "" // @TODO Missing documentation + "A unit-less scale factor for the probability of dust absorbing a light " + "particle. The amount of absorption determines the spectrum of the light that is " + "emitted from the galaxy" }; constexpr openspace::properties::Property::PropertyInfo EmissionMultiplyInfo = { "EmissionMultiply", "Emission Multiplier", - "" // @TODO Missing documentation + "A unit-less scale factor for the amount of light being emitted by dust in the " + "galaxy." }; constexpr openspace::properties::Property::PropertyInfo RotationInfo = { "Rotation", "Euler rotation", - "" // @TODO Missing documentation + "The internal rotation of the volume rendering in Euler angles", + openspace::properties::Property::Visibility::Developer }; constexpr openspace::properties::Property::PropertyInfo StarRenderingMethodInfo = { @@ -118,15 +126,17 @@ namespace { constexpr openspace::properties::Property::PropertyInfo EnabledPointsRatioInfo = { "EnabledPointsRatio", "Enabled points", - "" // @TODO Missing documentation + "The ratio of point-like stars that are rendered to produce the overall galaxy " + "image. At a value of 0, no stars are rendered, at a value of 1 all points " + "contained in the dataset are rendered. The specific value chosen is a " + "compromise between image fidelity and rendering performance." }; constexpr openspace::properties::Property::PropertyInfo DownscaleVolumeRenderingInfo = { "Downscale", "Downscale Factor Volume Rendering", - "This value set the downscaling factor" - " when rendering the current volume." + "This value sets the downscaling factor when rendering the current volume." }; constexpr openspace::properties::Property::PropertyInfo NumberOfRayCastingStepsInfo = @@ -229,13 +239,17 @@ namespace { namespace openspace { +documentation::Documentation RenderableGalaxy::Documentation() { + return codegen::doc("galaxy_renderablegalaxy"); +} + RenderableGalaxy::RenderableGalaxy(const ghoul::Dictionary& dictionary) : Renderable(dictionary) , _volumeRenderingEnabled(VolumeRenderingEnabledInfo, true) , _starRenderingEnabled(StarRenderingEnabledInfo, true) , _stepSize(StepSizeInfo, 0.01f, 0.001f, 0.05f, 0.001f) - , _absorptionMultiply(AbsorptionMultiplyInfo, 40.f, 0.0f, 200.0f) - , _emissionMultiply(EmissionMultiplyInfo, 200.f, 0.0f, 1000.0f) + , _absorptionMultiply(AbsorptionMultiplyInfo, 40.f, 0.f, 200.0f) + , _emissionMultiply(EmissionMultiplyInfo, 200.f, 0.f, 1000.0f) , _starRenderingMethod( StarRenderingMethodInfo, properties::OptionProperty::DisplayType::Dropdown diff --git a/modules/galaxy/rendering/renderablegalaxy.h b/modules/galaxy/rendering/renderablegalaxy.h index 16841fd097..6d7755d82a 100644 --- a/modules/galaxy/rendering/renderablegalaxy.h +++ b/modules/galaxy/rendering/renderablegalaxy.h @@ -54,6 +54,8 @@ public: void render(const RenderData& data, RendererTasks& tasks) override; void update(const UpdateData& data) override; + static documentation::Documentation Documentation(); + private: void renderPoints(const RenderData& data); void renderBillboards(const RenderData& data); diff --git a/modules/galaxy/tasks/milkywayconversiontask.cpp b/modules/galaxy/tasks/milkywayconversiontask.cpp index 24073c3547..df03bffd2d 100644 --- a/modules/galaxy/tasks/milkywayconversiontask.cpp +++ b/modules/galaxy/tasks/milkywayconversiontask.cpp @@ -107,7 +107,7 @@ void MilkywayConversionTask::perform(const Task::ProgressCallback& onProgress) { rawWriter.write(sampleFunction, onProgress); } -documentation::Documentation MilkywayConversionTask::documentation() { +documentation::Documentation MilkywayConversionTask::Documentation() { return documentation::Documentation(); } diff --git a/modules/galaxy/tasks/milkywayconversiontask.h b/modules/galaxy/tasks/milkywayconversiontask.h index d40c7860f6..a546b3e212 100644 --- a/modules/galaxy/tasks/milkywayconversiontask.h +++ b/modules/galaxy/tasks/milkywayconversiontask.h @@ -45,7 +45,7 @@ public: std::string description() override; void perform(const Task::ProgressCallback& onProgress) override; - static documentation::Documentation documentation(); + static documentation::Documentation Documentation(); private: std::string _inFilenamePrefix; diff --git a/modules/galaxy/tasks/milkywaypointsconversiontask.cpp b/modules/galaxy/tasks/milkywaypointsconversiontask.cpp index a8d1841ce7..0aa0b4b4a2 100644 --- a/modules/galaxy/tasks/milkywaypointsconversiontask.cpp +++ b/modules/galaxy/tasks/milkywaypointsconversiontask.cpp @@ -90,7 +90,7 @@ void MilkywayPointsConversionTask::perform(const Task::ProgressCallback& progres out.close(); } -documentation::Documentation MilkywayPointsConversionTask::documentation() { +documentation::Documentation MilkywayPointsConversionTask::Documentation() { return documentation::Documentation(); } diff --git a/modules/galaxy/tasks/milkywaypointsconversiontask.h b/modules/galaxy/tasks/milkywaypointsconversiontask.h index 332dcb1ec2..2eaf5ec980 100644 --- a/modules/galaxy/tasks/milkywaypointsconversiontask.h +++ b/modules/galaxy/tasks/milkywaypointsconversiontask.h @@ -47,7 +47,7 @@ public: std::string description() override; void perform(const Task::ProgressCallback& progressCallback) override; - static documentation::Documentation documentation(); + static documentation::Documentation Documentation(); private: std::string _inFilename; diff --git a/modules/globebrowsing/globebrowsingmodule.cpp b/modules/globebrowsing/globebrowsingmodule.cpp index baeef89d6d..7b8aa4f4bf 100644 --- a/modules/globebrowsing/globebrowsingmodule.cpp +++ b/modules/globebrowsing/globebrowsingmodule.cpp @@ -483,7 +483,15 @@ std::vector GlobeBrowsingModule::documentations() globebrowsing::LayerAdjustment::Documentation(), globebrowsing::LayerManager::Documentation(), globebrowsing::GlobeTranslation::Documentation(), + globebrowsing::GlobeRotation::Documentation(), globebrowsing::RenderableGlobe::Documentation(), + globebrowsing::DefaultTileProvider::Documentation(), + globebrowsing::ImageSequenceTileProvider::Documentation(), + globebrowsing::SingleImageProvider::Documentation(), + globebrowsing::SizeReferenceTileProvider::Documentation(), + globebrowsing::TemporalTileProvider::Documentation(), + globebrowsing::TileProviderByIndex::Documentation(), + globebrowsing::TileProviderByLevel::Documentation(), GlobeLabelsComponent::Documentation(), RingsComponent::Documentation(), ShadowComponent::Documentation() diff --git a/modules/globebrowsing/src/layeradjustment.cpp b/modules/globebrowsing/src/layeradjustment.cpp index 2205bcd9d9..a28cb273f8 100644 --- a/modules/globebrowsing/src/layeradjustment.cpp +++ b/modules/globebrowsing/src/layeradjustment.cpp @@ -74,7 +74,7 @@ documentation::Documentation LayerAdjustment::Documentation() { } LayerAdjustment::LayerAdjustment() - : properties::PropertyOwner({ "adjustment" }) + : properties::PropertyOwner({ "Adjustment" }) , _chromaKeyColor(ChromaKeyColorInfo, glm::vec3(0.f), glm::vec3(0.f), glm::vec3(1.f)) , _chromaKeyTolerance(ChromaKeyToleranceInfo, 0.f, 0.f, 1.f) , _typeOption(TypeInfo, properties::OptionProperty::DisplayType::Dropdown) diff --git a/modules/globebrowsing/src/layergroup.cpp b/modules/globebrowsing/src/layergroup.cpp index 3adf42d366..d788adf9c7 100644 --- a/modules/globebrowsing/src/layergroup.cpp +++ b/modules/globebrowsing/src/layergroup.cpp @@ -185,7 +185,6 @@ void LayerGroup::deleteLayer(const std::string& layerName) { std::string name = layerName; removePropertySubOwner(it->get()); (*it)->deinitialize(); - _layers.erase(it); properties::PropertyOwner* layerGroup = it->get()->owner(); properties::PropertyOwner* layerManager = layerGroup->owner(); properties::PropertyOwner* globe = layerManager->owner(); @@ -195,6 +194,7 @@ void LayerGroup::deleteLayer(const std::string& layerName) { layerGroup->identifier(), it->get()->identifier() ); + _layers.erase(it); update(); if (_onChangeCallback) { _onChangeCallback(nullptr); diff --git a/modules/globebrowsing/src/layermanager.cpp b/modules/globebrowsing/src/layermanager.cpp index 24e0faad86..612c42a64f 100644 --- a/modules/globebrowsing/src/layermanager.cpp +++ b/modules/globebrowsing/src/layermanager.cpp @@ -98,6 +98,16 @@ Layer* LayerManager::addLayer(layergroupid::GroupID groupId, try { return _layerGroups[groupId]->addLayer(layerDict); } + catch (const documentation::SpecificationError& e) { + LERRORC(e.component, e.message); + for (const documentation::TestResult::Offense& o : e.result.offenses) { + LERRORC(o.offender, ghoul::to_string(o.reason)); + } + for (const documentation::TestResult::Warning& w : e.result.warnings) { + LWARNINGC(w.offender, ghoul::to_string(w.reason)); + } + return nullptr; + } catch (const ghoul::RuntimeError& e) { LERRORC(e.component, e.message); return nullptr; diff --git a/modules/globebrowsing/src/tileprovider/defaulttileprovider.cpp b/modules/globebrowsing/src/tileprovider/defaulttileprovider.cpp index 7047094a45..6a11f3acb4 100644 --- a/modules/globebrowsing/src/tileprovider/defaulttileprovider.cpp +++ b/modules/globebrowsing/src/tileprovider/defaulttileprovider.cpp @@ -76,6 +76,10 @@ namespace { namespace openspace::globebrowsing { +documentation::Documentation DefaultTileProvider::Documentation() { + return codegen::doc("globebrowsing_defaulttileprovider"); +} + DefaultTileProvider::DefaultTileProvider(const ghoul::Dictionary& dictionary) : _filePath(FilePathInfo, "") , _tilePixelSize(TilePixelSizeInfo, 32, 32, 2048) diff --git a/modules/globebrowsing/src/tileprovider/defaulttileprovider.h b/modules/globebrowsing/src/tileprovider/defaulttileprovider.h index 51250ca02f..0cb6195ea8 100644 --- a/modules/globebrowsing/src/tileprovider/defaulttileprovider.h +++ b/modules/globebrowsing/src/tileprovider/defaulttileprovider.h @@ -44,6 +44,8 @@ public: int maxLevel() override final; float noDataValueAsFloat() override final; + static documentation::Documentation Documentation(); + private: void initAsyncTileDataReader(TileTextureInitData initData); diff --git a/modules/globebrowsing/src/tileprovider/imagesequencetileprovider.cpp b/modules/globebrowsing/src/tileprovider/imagesequencetileprovider.cpp index 2bf0485566..f922c99681 100644 --- a/modules/globebrowsing/src/tileprovider/imagesequencetileprovider.cpp +++ b/modules/globebrowsing/src/tileprovider/imagesequencetileprovider.cpp @@ -61,6 +61,10 @@ namespace { namespace openspace::globebrowsing { +documentation::Documentation ImageSequenceTileProvider::Documentation() { + return codegen::doc("globebrowsing_imagesequencetileprovider"); +} + ImageSequenceTileProvider::ImageSequenceTileProvider(const ghoul::Dictionary& dictionary) : _index(IndexInfo, 0) , _currentImage(CurrentImageInfo) diff --git a/modules/globebrowsing/src/tileprovider/imagesequencetileprovider.h b/modules/globebrowsing/src/tileprovider/imagesequencetileprovider.h index 0ee4730db9..afacdfe05b 100644 --- a/modules/globebrowsing/src/tileprovider/imagesequencetileprovider.h +++ b/modules/globebrowsing/src/tileprovider/imagesequencetileprovider.h @@ -43,6 +43,8 @@ public: int maxLevel() override final; float noDataValueAsFloat() override final; + static documentation::Documentation Documentation(); + private: std::unique_ptr _currentTileProvider = nullptr; diff --git a/modules/globebrowsing/src/tileprovider/singleimagetileprovider.cpp b/modules/globebrowsing/src/tileprovider/singleimagetileprovider.cpp index a4a113b2b9..a6e6911ef2 100644 --- a/modules/globebrowsing/src/tileprovider/singleimagetileprovider.cpp +++ b/modules/globebrowsing/src/tileprovider/singleimagetileprovider.cpp @@ -44,6 +44,10 @@ namespace { namespace openspace::globebrowsing { +documentation::Documentation SingleImageProvider::Documentation() { + return codegen::doc("globebrowsing_singleimageprovider"); +} + SingleImageProvider::SingleImageProvider(const ghoul::Dictionary& dictionary) : _filePath(FilePathInfo) { diff --git a/modules/globebrowsing/src/tileprovider/singleimagetileprovider.h b/modules/globebrowsing/src/tileprovider/singleimagetileprovider.h index c3fee2725b..a911c719f3 100644 --- a/modules/globebrowsing/src/tileprovider/singleimagetileprovider.h +++ b/modules/globebrowsing/src/tileprovider/singleimagetileprovider.h @@ -27,6 +27,8 @@ #include +namespace openspace { struct Documentation; } + namespace openspace::globebrowsing { class SingleImageProvider : public TileProvider { @@ -41,6 +43,8 @@ public: int maxLevel() override final; float noDataValueAsFloat() override final; + static documentation::Documentation Documentation(); + private: properties::StringProperty _filePath; diff --git a/modules/globebrowsing/src/tileprovider/sizereferencetileprovider.cpp b/modules/globebrowsing/src/tileprovider/sizereferencetileprovider.cpp index 9343d5a99e..a179af979f 100644 --- a/modules/globebrowsing/src/tileprovider/sizereferencetileprovider.cpp +++ b/modules/globebrowsing/src/tileprovider/sizereferencetileprovider.cpp @@ -40,6 +40,10 @@ namespace { namespace openspace::globebrowsing { +documentation::Documentation SizeReferenceTileProvider::Documentation() { + return codegen::doc("globebrowsing_sizereferencetileprovider"); +} + SizeReferenceTileProvider::SizeReferenceTileProvider(const ghoul::Dictionary& dictionary) : TextTileProvider(tileTextureInitData(layergroupid::GroupID::ColorLayers, false)) { diff --git a/modules/globebrowsing/src/tileprovider/sizereferencetileprovider.h b/modules/globebrowsing/src/tileprovider/sizereferencetileprovider.h index 499f8c2a53..adb25c42c7 100644 --- a/modules/globebrowsing/src/tileprovider/sizereferencetileprovider.h +++ b/modules/globebrowsing/src/tileprovider/sizereferencetileprovider.h @@ -40,6 +40,8 @@ public: int maxLevel() override final; float noDataValueAsFloat() override final; + static documentation::Documentation Documentation(); + private: Ellipsoid _ellipsoid; }; diff --git a/modules/globebrowsing/src/tileprovider/temporaltileprovider.cpp b/modules/globebrowsing/src/tileprovider/temporaltileprovider.cpp index bc71de7b14..6284ded487 100644 --- a/modules/globebrowsing/src/tileprovider/temporaltileprovider.cpp +++ b/modules/globebrowsing/src/tileprovider/temporaltileprovider.cpp @@ -165,6 +165,10 @@ namespace { namespace openspace::globebrowsing { +documentation::Documentation TemporalTileProvider::Documentation() { + return codegen::doc("globebrowsing_temporaltileprovider"); +} + TemporalTileProvider::TemporalTileProvider(const ghoul::Dictionary& dictionary) : _initDict(dictionary) , _useFixedTime(UseFixedTimeInfo, false) diff --git a/modules/globebrowsing/src/tileprovider/temporaltileprovider.h b/modules/globebrowsing/src/tileprovider/temporaltileprovider.h index 95dfc1f128..469251ac4c 100644 --- a/modules/globebrowsing/src/tileprovider/temporaltileprovider.h +++ b/modules/globebrowsing/src/tileprovider/temporaltileprovider.h @@ -54,6 +54,8 @@ public: int maxLevel() override final; float noDataValueAsFloat() override final; + static documentation::Documentation Documentation(); + private: enum class Mode { Prototype, diff --git a/modules/globebrowsing/src/tileprovider/tileprovider.cpp b/modules/globebrowsing/src/tileprovider/tileprovider.cpp index f7864e2724..cc7ea99e24 100644 --- a/modules/globebrowsing/src/tileprovider/tileprovider.cpp +++ b/modules/globebrowsing/src/tileprovider/tileprovider.cpp @@ -116,7 +116,7 @@ void TileProvider::deinitializeDefaultTile() { DefaultTileTexture = nullptr; } -TileProvider::TileProvider() : properties::PropertyOwner({ "tileProvider" }) {} +TileProvider::TileProvider() : properties::PropertyOwner({ "TileProvider" }) {} void TileProvider::initialize() { ZoneScoped diff --git a/modules/globebrowsing/src/tileprovider/tileproviderbyindex.cpp b/modules/globebrowsing/src/tileprovider/tileproviderbyindex.cpp index af85ae70d8..c9871e92f1 100644 --- a/modules/globebrowsing/src/tileprovider/tileproviderbyindex.cpp +++ b/modules/globebrowsing/src/tileprovider/tileproviderbyindex.cpp @@ -51,6 +51,10 @@ namespace { namespace openspace::globebrowsing { +documentation::Documentation TileProviderByIndex::Documentation() { + return codegen::doc("globebrowsing_tileproviderbyindex"); +} + TileProviderByIndex::TileProviderByIndex(const ghoul::Dictionary& dictionary) { ZoneScoped diff --git a/modules/globebrowsing/src/tileprovider/tileproviderbyindex.h b/modules/globebrowsing/src/tileprovider/tileproviderbyindex.h index 1d523748e2..9af02b6378 100644 --- a/modules/globebrowsing/src/tileprovider/tileproviderbyindex.h +++ b/modules/globebrowsing/src/tileprovider/tileproviderbyindex.h @@ -41,6 +41,8 @@ public: int maxLevel() override final; float noDataValueAsFloat() override final; + static documentation::Documentation Documentation(); + private: std::unordered_map> _providers; std::unique_ptr _defaultTileProvider; diff --git a/modules/globebrowsing/src/tileprovider/tileproviderbylevel.cpp b/modules/globebrowsing/src/tileprovider/tileproviderbylevel.cpp index c27576012d..e082cdac98 100644 --- a/modules/globebrowsing/src/tileprovider/tileproviderbylevel.cpp +++ b/modules/globebrowsing/src/tileprovider/tileproviderbylevel.cpp @@ -41,6 +41,10 @@ namespace { namespace openspace::globebrowsing { +documentation::Documentation TileProviderByLevel::Documentation() { + return codegen::doc("globebrowsing_tileproviderbylevel"); +} + TileProviderByLevel::TileProviderByLevel(const ghoul::Dictionary& dictionary) { ZoneScoped diff --git a/modules/globebrowsing/src/tileprovider/tileproviderbylevel.h b/modules/globebrowsing/src/tileprovider/tileproviderbylevel.h index 1ec3c4995e..1020c5d29d 100644 --- a/modules/globebrowsing/src/tileprovider/tileproviderbylevel.h +++ b/modules/globebrowsing/src/tileprovider/tileproviderbylevel.h @@ -41,6 +41,8 @@ public: int maxLevel() override final; float noDataValueAsFloat() override final; + static documentation::Documentation Documentation(); + private: std::vector _providerIndices; std::vector> _levelTileProviders; diff --git a/modules/space/spacemodule.cpp b/modules/space/spacemodule.cpp index cdaaf62509..062a9623eb 100644 --- a/modules/space/spacemodule.cpp +++ b/modules/space/spacemodule.cpp @@ -124,6 +124,9 @@ void SpaceModule::internalDeinitializeGL() { std::vector SpaceModule::documentations() const { return { + HorizonsTranslation::Documentation(), + KeplerTranslation::Documentation(), + planetgeometry::PlanetGeometry::Documentation(), RenderableConstellationBounds::Documentation(), RenderableFluxNodes::Documentation(), RenderableHabitableZone::Documentation(), @@ -132,13 +135,10 @@ std::vector SpaceModule::documentations() const { RenderableSmallBody::Documentation(), RenderableStars::Documentation(), RenderableTravelSpeed::Documentation(), + planetgeometry::SimpleSphereGeometry::Documentation(), SpiceRotation::Documentation(), SpiceTranslation::Documentation(), - KeplerTranslation::Documentation(), - TLETranslation::Documentation(), - HorizonsTranslation::Documentation(), - planetgeometry::PlanetGeometry::Documentation(), - planetgeometry::SimpleSphereGeometry::Documentation() + TLETranslation::Documentation() }; } diff --git a/modules/spacecraftinstruments/rendering/renderablecrawlingline.cpp b/modules/spacecraftinstruments/rendering/renderablecrawlingline.cpp index 38862178e5..16a55863b2 100644 --- a/modules/spacecraftinstruments/rendering/renderablecrawlingline.cpp +++ b/modules/spacecraftinstruments/rendering/renderablecrawlingline.cpp @@ -73,7 +73,7 @@ namespace { namespace openspace { documentation::Documentation RenderableCrawlingLine::Documentation() { - return codegen::doc("newhorizons_renderable_crawlingline"); + return codegen::doc("spacecraftinstruments_renderablecrawlingline"); } RenderableCrawlingLine::RenderableCrawlingLine(const ghoul::Dictionary& dictionary) diff --git a/modules/spacecraftinstruments/rendering/renderablefov.cpp b/modules/spacecraftinstruments/rendering/renderablefov.cpp index e7eb9a9134..993cccb0c3 100644 --- a/modules/spacecraftinstruments/rendering/renderablefov.cpp +++ b/modules/spacecraftinstruments/rendering/renderablefov.cpp @@ -196,7 +196,7 @@ namespace { namespace openspace { documentation::Documentation RenderableFov::Documentation() { - return codegen::doc("newhorizons_renderable_fieldofview"); + return codegen::doc("spacecraftinstruments_renderablefieldofview"); } RenderableFov::RenderableFov(const ghoul::Dictionary& dictionary) diff --git a/modules/spacecraftinstruments/rendering/renderablemodelprojection.cpp b/modules/spacecraftinstruments/rendering/renderablemodelprojection.cpp index 3bd9ea34ba..085aa9b429 100644 --- a/modules/spacecraftinstruments/rendering/renderablemodelprojection.cpp +++ b/modules/spacecraftinstruments/rendering/renderablemodelprojection.cpp @@ -90,7 +90,7 @@ namespace { namespace openspace { documentation::Documentation RenderableModelProjection::Documentation() { - return codegen::doc("newhorizons_renderable_modelprojection"); + return codegen::doc("spacecraftinstruments_renderablemodelprojection"); } RenderableModelProjection::RenderableModelProjection(const ghoul::Dictionary& dictionary) diff --git a/modules/spacecraftinstruments/rendering/renderableplaneprojection.cpp b/modules/spacecraftinstruments/rendering/renderableplaneprojection.cpp index 9fac9699f6..2a5aab8aeb 100644 --- a/modules/spacecraftinstruments/rendering/renderableplaneprojection.cpp +++ b/modules/spacecraftinstruments/rendering/renderableplaneprojection.cpp @@ -45,6 +45,7 @@ namespace { constexpr const char* _loggerCat = "RenderablePlaneProjection"; constexpr const char* GalacticFrame = "GALACTIC"; + // @TODO (emmbr 2022-01-20) Add documentation struct [[codegen::Dictionary(RenderablePlaneProjection)]] Parameters { std::optional spacecraft; std::optional instrument; @@ -58,6 +59,10 @@ namespace { namespace openspace { +documentation::Documentation RenderablePlaneProjection::Documentation() { + return codegen::doc("spacecraftinstruments_renderableorbitdisc"); +} + RenderablePlaneProjection::RenderablePlaneProjection(const ghoul::Dictionary& dict) : Renderable(dict) { diff --git a/modules/spacecraftinstruments/rendering/renderableplaneprojection.h b/modules/spacecraftinstruments/rendering/renderableplaneprojection.h index cf78ef932c..5a225883f7 100644 --- a/modules/spacecraftinstruments/rendering/renderableplaneprojection.h +++ b/modules/spacecraftinstruments/rendering/renderableplaneprojection.h @@ -56,6 +56,8 @@ public: void render(const RenderData& data, RendererTasks& rendererTask) override; void update(const UpdateData& data) override; + static documentation::Documentation Documentation(); + private: void loadTexture(); void updatePlane(const Image& img, double currentTime); diff --git a/modules/spacecraftinstruments/rendering/renderableplanetprojection.cpp b/modules/spacecraftinstruments/rendering/renderableplanetprojection.cpp index 05900d0cd0..804c96c71c 100644 --- a/modules/spacecraftinstruments/rendering/renderableplanetprojection.cpp +++ b/modules/spacecraftinstruments/rendering/renderableplanetprojection.cpp @@ -162,7 +162,7 @@ namespace { namespace openspace { documentation::Documentation RenderablePlanetProjection::Documentation() { - return codegen::doc("newhorizons_renderable_planetprojection"); + return codegen::doc("spacecraftinstruments_renderableplanetprojection"); } RenderablePlanetProjection::RenderablePlanetProjection(const ghoul::Dictionary& dict) diff --git a/modules/spacecraftinstruments/rendering/renderableshadowcylinder.cpp b/modules/spacecraftinstruments/rendering/renderableshadowcylinder.cpp index 7df88e279f..30f515a775 100644 --- a/modules/spacecraftinstruments/rendering/renderableshadowcylinder.cpp +++ b/modules/spacecraftinstruments/rendering/renderableshadowcylinder.cpp @@ -143,7 +143,7 @@ namespace { namespace openspace { documentation::Documentation RenderableShadowCylinder::Documentation() { - return codegen::doc("newhorizons_renderable_shadowcylinder"); + return codegen::doc("spacecraftinstruments_renderableshadowcylinder"); } RenderableShadowCylinder::RenderableShadowCylinder(const ghoul::Dictionary& dictionary) diff --git a/modules/spacecraftinstruments/spacecraftinstrumentsmodule.cpp b/modules/spacecraftinstruments/spacecraftinstrumentsmodule.cpp index b60f0c0181..874b33dfbf 100644 --- a/modules/spacecraftinstruments/spacecraftinstrumentsmodule.cpp +++ b/modules/spacecraftinstruments/spacecraftinstrumentsmodule.cpp @@ -61,12 +61,12 @@ void SpacecraftInstrumentsModule::internalInitialize(const ghoul::Dictionary&) { auto fRenderable = FactoryManager::ref().factory(); ghoul_assert(fRenderable, "No renderable factory existed"); - fRenderable->registerClass("RenderableShadowCylinder"); fRenderable->registerClass("RenderableCrawlingLine"); fRenderable->registerClass("RenderableFov"); + fRenderable->registerClass("RenderableModelProjection"); fRenderable->registerClass("RenderablePlaneProjection"); fRenderable->registerClass("RenderablePlanetProjection"); - fRenderable->registerClass("RenderableModelProjection"); + fRenderable->registerClass("RenderableShadowCylinder"); auto fDecoder = FactoryManager::ref().factory(); fDecoder->registerClass("Instrument"); @@ -85,9 +85,12 @@ std::vector SpacecraftInstrumentsModule::documentations() const { return { + RenderableCrawlingLine::Documentation(), RenderableFov::Documentation(), RenderableModelProjection::Documentation(), + RenderablePlaneProjection::Documentation(), RenderablePlanetProjection::Documentation(), + RenderableShadowCylinder::Documentation(), ProjectionComponent::Documentation() }; } diff --git a/modules/spacecraftinstruments/util/projectioncomponent.cpp b/modules/spacecraftinstruments/util/projectioncomponent.cpp index 3955db5c3c..1298646143 100644 --- a/modules/spacecraftinstruments/util/projectioncomponent.cpp +++ b/modules/spacecraftinstruments/util/projectioncomponent.cpp @@ -162,7 +162,7 @@ namespace { namespace openspace { documentation::Documentation ProjectionComponent::Documentation() { - return codegen::doc("newhorizons_projectioncomponent"); + return codegen::doc("spacecraftinstruments_projectioncomponent"); } ProjectionComponent::ProjectionComponent() diff --git a/modules/toyvolume/rendering/renderabletoyvolume.cpp b/modules/toyvolume/rendering/renderabletoyvolume.cpp index bccf0aee95..c5e5b1934c 100644 --- a/modules/toyvolume/rendering/renderabletoyvolume.cpp +++ b/modules/toyvolume/rendering/renderabletoyvolume.cpp @@ -32,7 +32,7 @@ #include namespace { - constexpr const char* _loggerCat = "Renderable ToyVolume"; + constexpr const char* _loggerCat = "RenderableToyVolume"; constexpr openspace::properties::Property::PropertyInfo SizeInfo = { "Size", "Size", diff --git a/modules/vislab/rendering/renderabledistancelabel.h b/modules/vislab/rendering/renderabledistancelabel.h index 330c00510b..3a0b765aad 100644 --- a/modules/vislab/rendering/renderabledistancelabel.h +++ b/modules/vislab/rendering/renderabledistancelabel.h @@ -37,8 +37,8 @@ public: void update(const UpdateData& data) override; static documentation::Documentation Documentation(); -private: +private: properties::StringProperty _nodelineId; properties::IntProperty _distanceUnit; properties::StringProperty _customUnitDescriptor; diff --git a/modules/vislab/vislabmodule.cpp b/modules/vislab/vislabmodule.cpp index 2356928bbf..399923f651 100644 --- a/modules/vislab/vislabmodule.cpp +++ b/modules/vislab/vislabmodule.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -40,4 +41,10 @@ void VisLabModule::internalInitialize(const ghoul::Dictionary&) { renderableFactory->registerClass("RenderableDistanceLabel"); } +std::vectorVisLabModule::documentations() const { + return { + RenderableDistanceLabel::Documentation() + }; +} + } // namespace openspace diff --git a/modules/vislab/vislabmodule.h b/modules/vislab/vislabmodule.h index 1ebf9cfaf3..5e2b7a6079 100644 --- a/modules/vislab/vislabmodule.h +++ b/modules/vislab/vislabmodule.h @@ -35,6 +35,9 @@ public: VisLabModule(); + std::vector documentations() const override; + + private: void internalInitialize(const ghoul::Dictionary&) override; }; diff --git a/modules/volume/tasks/generaterawvolumetask.cpp b/modules/volume/tasks/generaterawvolumetask.cpp index 66e5833680..f0e3a7d74b 100644 --- a/modules/volume/tasks/generaterawvolumetask.cpp +++ b/modules/volume/tasks/generaterawvolumetask.cpp @@ -71,7 +71,7 @@ namespace { namespace openspace::volume { -documentation::Documentation GenerateRawVolumeTask::documentation() { +documentation::Documentation GenerateRawVolumeTask::Documentation() { return codegen::doc("generate_raw_volume_task"); } diff --git a/modules/volume/tasks/generaterawvolumetask.h b/modules/volume/tasks/generaterawvolumetask.h index 384b767339..7d302727a6 100644 --- a/modules/volume/tasks/generaterawvolumetask.h +++ b/modules/volume/tasks/generaterawvolumetask.h @@ -38,7 +38,7 @@ public: GenerateRawVolumeTask(const ghoul::Dictionary& dictionary); std::string description() override; void perform(const Task::ProgressCallback& progressCallback) override; - static documentation::Documentation documentation(); + static documentation::Documentation Documentation(); private: std::filesystem::path _rawVolumeOutputPath; diff --git a/modules/volume/volumemodule.cpp b/modules/volume/volumemodule.cpp index 2f3b34dd1d..7900e671c8 100644 --- a/modules/volume/volumemodule.cpp +++ b/modules/volume/volumemodule.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -46,7 +47,13 @@ void VolumeModule::internalInitialize(const ghoul::Dictionary&) { auto tFactory = FactoryManager::ref().factory(); ghoul_assert(tFactory, "No task factory existed"); tFactory->registerClass("GenerateRawVolumeTask"); +} +std::vector VolumeModule::documentations() const { + return { + RenderableTimeVaryingVolume::Documentation(), + GenerateRawVolumeTask::Documentation() + }; } } // namespace openspace diff --git a/modules/volume/volumemodule.h b/modules/volume/volumemodule.h index 8808f7ae68..cf850323ca 100644 --- a/modules/volume/volumemodule.h +++ b/modules/volume/volumemodule.h @@ -36,6 +36,8 @@ public: VolumeModule(); void internalInitialize(const ghoul::Dictionary&) override; + + std::vector documentations() const override; }; } // namespace openspace diff --git a/scripts/configuration_helper.lua b/scripts/configuration_helper.lua index deb3b94651..0b55af825a 100644 --- a/scripts/configuration_helper.lua +++ b/scripts/configuration_helper.lua @@ -1,43 +1,32 @@ -- Helper functions that are useful to customize the openspace.cfg loading ---[[ -########################################################################################## - Public functions -########################################################################################## -]]-- +-- ####################################################################################### +-- ## Public functions ## +-- ####################################################################################### -- SGCT related functions sgct = {} sgct.config = {} --- This function takes a text definition for an SGCT configuration file and returns the path --- to a temporary file containing the string which SGCT can use -function sgct.makeConfig(config) end - -- Creates a configuration file similar to the default 'single.xml': -- The parameter is a table and can contain the follow attributes: -- first argument: horizontal window size {default: 1280} -- second argument: vertical window size {default: 720} -- res: A table containing the horizontal and vertical resolution [example: res={3840, 2160}] --- windowPos: The position of the window on the screen [example: windowPos={50, 100}] {default: {50, 50}} +-- pos: The position of the window on the screen [example: pos={50, 100}] {default: {50, 50}} -- fullScreen: Whether the application should run in exclusive full screen [example: fullScreen=true] {default: false} -- border: Whether the application should have window decorations (aka. border) [example: border=false] {default: true} -- monitor: Determines the monitor on which the application is started [example: monitor=2] {default: 0} -- shared: Determines whether the contents of the window should be shared using the SPOUT library [example: shared=true] {default: false} -- Expert settings: --- name: The name of the window [example: window="Foobar"] {default: "OpenSpace"} --- tags: A list of string tags that are passed to the window [example: tags ={"GUI"}] {default: {}} -- vsync: Whether the rendering speed is locked to the refreshrate [example: vsync=true] {default: false} -- refreshRate: If vsync is enabled, this is the target framerate [example: refreshRate=30] {default: infinity} -- stereo: Select the stereo rendering mode as supported by SGCT [example: stereo='anaglyph_red_cyan'] {default: 'none'} -- msaa: The multisampling anti-aliasing factor [example: msaa=8] {default: 4} --- eyeSep: The base eye separation in m [example: eyeSep=0.1] {default: 0.065} --- eyePos: The location of the user [example: eyePos={0.0, 1.0, 0.0}] {default: {0.0, 0.0, 0.0}} -- scene: Global settings to all scene objects (offset, orientation, scaling; each optional) -- [example: scene = {offset = {x = 1.0, y = 1.0, z = 2.0}, orientation = { yaw = 120, pitch = 15, roll = 0.0 }, scale = 10.0}] --- capture: Settings to configure the image capture [example: capture = { path = "./images"] -- sgctDebug: Determines whether a higher debug level in SGCT is enabled [example: sgctDebug=true] {default: false} -- fov: The field of view settings [example: fov={ left=20, right=30, up=10, down=50}] {default: { left=40.0, right=40.0, up=22.5, down=22.5}} -- tracked: Determines whether the aspect ratio of the camera defined at application startup should persist when the window is resized [example: tracked=false] {default: true} @@ -49,30 +38,27 @@ function sgct.makeConfig(config) end -- sgct.config.single(msaa=1) -> 1280x720 resolution without multisampling function sgct.config.single(arg) end + + -- Creates a configuration file similar to the default 'single_fisheye.xml' -- The parameter is a table and can contain the follow attributes: -- first argument: horizontal window size {default: 1280} -- second argument: vertical window size {default: 720} -- res: A table containing the horizontal and vertical resolution [example: res={3840, 2160}] --- windowPos: The position of the window on the screen [example: windowPos={50, 100}] {default: {50, 50}} +-- pos: The position of the window on the screen [example: pos={50, 100}] {default: {50, 50}} -- fullScreen: Whether the application should run in exclusive full screen [example: fullScreen=true] {default: false} -- border: Whether the application should have window decorations (aka. border) [example: border=false] {default: true} -- monitor: Determines the monitor on which the application is started [example: monitor=2] {default: 0} -- shared: Determines whether the contents of the window should be shared using the SPOUT library [example: shared=true] {default: false} -- Expert settings: --- name: The name of the window [example: window="Foobar"] {default: "OpenSpace"} --- tags: A list of string tags that are passed to the window [example: tags ={"GUI"}] {default: {}} -- vsync: Whether the rendering speed is locked to the refreshrate [example: vsync=true] {default: false} -- refreshRate: If vsync is enabled, this is the target framerate [example: refreshRate=30] {default: infinity} -- stereo: Select the stereo rendering mode as supported by SGCT [example: stereo='anaglyph_red_cyan'] {default: 'none'} -- msaa: The multisampling anti-aliasing factor [example: msaa=8] {default: 4} --- eyeSep: The base eye separation in m [example: eyeSep=0.1] {default: 0.065} --- eyePos: The location of the user [example: eyePos={0.0, 1.0, 0.0}] {default: {0.0, 0.0, 0.0}} -- scene: Global settings to all scene objects (offset, orientation, scaling; each optional) -- [example: scene = {offset = {x = 1.0, y = 1.0, z = 2.0}, orientation = { yaw = 120, pitch = 15, roll = 0.0 }, scale = 10.0}] --- capture: Settings to configure the image capture [example: capture = { path = "./images"] -- sgctDebug: Determines whether a higher debug level in SGCT is enabled [example: sgctDebug=true] {default: false} -- fov: The field of view for the fisheye [example: fov=360] {default: 180} -- quality: The quality setting for the cubemap textures [example: quality="4k"] {default: "1k"} @@ -86,11 +72,12 @@ function sgct.config.single(arg) end -- sgct.config.fisheye(msaa=1) -> 1280x720 resolution without multisampling function sgct.config.fisheye(arg) end -function sgct.config.cube(arg) end - -- Global variable storing the name of the config function called at initialization sgctconfiginitializeString = "" + + + --[[ ########################################################################################## Internal helper functions @@ -98,808 +85,373 @@ sgctconfiginitializeString = "" ]]-- function generateSingleViewportFOV(down, up, left, right, tracked) - return -[[ - - - - - - - - -]] + local result = {} + + table.insert(result, [[ {]]) + + if tracked then + table.insert(result, [[ "tracked": ]] .. tostring(tracked) .. [[,]]) + end + + table.insert(result, [[ "projection": {]]) + table.insert(result, [[ "type": "PlanarProjection",]]) + table.insert(result, [[ "fov": {]]) + table.insert(result, [[ "left": ]] .. left .. [[,]]) + table.insert(result, [[ "right": ]] .. right .. [[,]]) + table.insert(result, [[ "up": ]] .. up .. [[,]]) + table.insert(result, [[ "down": ]] .. down) + table.insert(result, [[ }]]) + table.insert(result, [[ }]]) + table.insert(result, [[ }]]) + + return table.concat(result, "\n") end -function generateSingleViewport(lowerLeft, upperLeft, upperRight, tracked) - return -[[ - - - - - - - - - -]] +function generateFisheyeViewport(fov, quality, tilt, background, crop, offset, tracked) + local result = {} + + table.insert(result, [[ {]]) + + if tracked then + table.insert(result, [[ "tracked": ]] .. tostring(tracked) .. [[,]]) + end + + table.insert(result, [[ "projection": {]]) + table.insert(result, [[ "type": "FisheyeProjection",]]) + + if fov then + table.insert(result, [[ "fov": ]] .. fov .. [[,]]) + end + table.insert(result, [[ "quality": "]] .. quality .. [[",]]) + table.insert(result, [[ "tilt": ]] .. tilt .. [[,]]) + + if crop then + table.insert(result, [[ "crop": {]]) + table.insert(result, [[ "left": ]] .. crop["left"] .. [[,]]) + table.insert(result, [[ "right": ]] .. crop["right"] .. [[,]]) + table.insert(result, [[ "top": ]] .. crop["top"] .. [[,]]) + table.insert(result, [[ "bottom": ]] .. crop["bottom"]) + table.insert(result, [[ },]]) + end + + if offset then + table.insert(result, [[ "offset": {]]) + table.insert(result, [[ "x": ]] .. offset["x"] .. [[,]]) + table.insert(result, [[ "y": ]] .. offset["y"] .. [[,]]) + table.insert(result, [[ "z": ]] .. offset["z"]) + table.insert(result, [[ },]]) + end + + table.insert(result, [[ "background": {]]) + table.insert(result, [[ "r": ]] .. background["r"] .. [[,]]) + table.insert(result, [[ "g": ]] .. background["g"] .. [[,]]) + table.insert(result, [[ "b": ]] .. background["b"] .. [[,]]) + table.insert(result, [[ "a": ]] .. background["a"]) + table.insert(result, [[ }]]) + table.insert(result, [[ }]]) + table.insert(result, [[ }]]) + + return table.concat(result, "\n") end -function generateFisheyeViewport(fov, quality, tilt, background, crop, offset, trackedSpecifier) - local b = [[ - -]] +function generateWindow(result, fullScreen, msaa, border, monitor, tags, stereo, pos, + size, res, viewport) + table.insert(result, [[ "name": "OpenSpace",]]) - local c = "" - if crop then - c = [[ - -]] - end + if fullScreen then + table.insert(result, [[ "fullscreen": ]] .. tostring(fullScreen) .. [[,]]) + end - local o = "" - if offset then - o = [[ - -]] - end + if msaa then + table.insert(result, [[ "msaa": ]] .. msaa .. [[,]]) + end - return [[ - - - - -]]..b..[[ -]]..c..[[ -]]..o..[[ - - -]] + if border then + table.insert(result, [[ "border": ]] .. tostring(border) .. [[,]]) + end + + if monitor then + table.insert(result, [[ "monitor": ]] .. monitor .. [[,]]) + end + + if #(tags) > 0 then + local t = table.concat(arg["tags"], [[,]]) + table.insert(result, [[ "tags": [ ]] .. t .. [[ ], ]]) + end + + if stereo then + table.insert(result, [[ "stereo": "]] .. stereo .. [[",]]) + end + + local px = pos[1] + local py = pos[2] + table.insert(result, [[ "pos": { "x": ]] .. px .. [[, "y": ]] .. py .. [[ },]]) + + local sx = size[1] + local sy = size[2] + table.insert(result, [[ "size": { "x": ]] .. sx .. [[, "y": ]] .. sy .. [[ },]]) + + if res then + res[1] = res[1] or size[1] + res[2] = res[2] or size[2] + table.insert(result, [[ "res": {]]) + table.insert(result, [[ "x": ]] .. res[1] .. [[,]]) + table.insert(result, [[ "y": ]] .. res[2]) + table.insert(result, [[ },]]) + end + + table.insert(result, [[ "viewports": []]) + + table.insert(result, viewport) + table.insert(result, [[ ] ]]) end -function generateWindow(arg) - local resolution = "" - if arg["res"] then - arg["res"][1] = arg["res"][1] or arg["windowSize"][1] - arg["res"][2] = arg["res"][2] or arg["windowSize"][2] - - resolution = -[[ - -]] - end - - local tags = "" - if arg["tags"] then - tags = table.concat(arg["tags"], ",") - end - - - return -[[ - - - - -]]..resolution.. -[[ -]].. -arg["viewport"].. -[[ - -]] +function generateUser(result) + table.insert(result, [[ {]]) + table.insert(result, [[ "eyeseparation": 0.06,]]) + table.insert(result, [[ "pos": { "x": 0.0, "y": 0.0, "z": 0.0 }]]) + table.insert(result, [[ }]]) end -function generateUser(arg) - return [[ - - - -]] +function generateScene(result, scene) + if scene == nil then + return nil + end + + local offset = scene["offset"] or { x = 0.0, y = 0.0, z = 0.0 } + local orientation = scene["orientation"] or { yaw = 0.0, pitch = 0.0, roll = 0.0 } + local scale = scene["scale"] or 1.0 + + table.insert(result, [[{]]) + table.insert(result, [[ "offset": {]]) + table.insert(result, [[ "x": ]] .. offset["x"] .. [[,]]) + table.insert(result, [[ "y": ]] .. offset["y"] .. [[,]]) + table.insert(result, [[ "z": ]] .. offset["z"] .. [[,]]) + table.insert(result, [[ },]]) + table.insert(result, [[ "orientation": {]]) + table.insert(result, [[ "yaw": ]] .. orientation["yaw"] .. [[,]]) + table.insert(result, [[ "pitch": ]] .. orientation["pitch"] .. [[,]]) + table.insert(result, [[ "roll": ]] .. orientation["roll"] .. [[,]]) + table.insert(result, [[ },]]) + table.insert(result, [[ "scale": ]] .. scale) + table.insert(result, [[}]]) end -function generateScene(arg) - local scene = arg["scene"] +function generateSettings(result, refreshRate, vsync) + table.insert(result, [[ "display": {]]) - if scene == nil then - return "" - else - local offset = nil - if scene["offset"] then - local o = scene["offset"] - offset = [[]] - end + if (arg["refreshRate"]) then + table.insert(result, [[ "refreshrate": ]] .. arg["refreshRate"] .. [[,]]) + end - local orientation = nil - if scene["orientation"] then - local o = scene["orientation"] - orientation = [[]] - end + if arg["vsync"] then + table.insert(result, [[ "swapinterval": 1]]) + else + table.insert(result, [[ "swapinterval": 0]]) + end - local scale = nil - if scene["scale"] then - scale = [[]] - end - - local sceneString = " " - if offset then - sceneString = sceneString .. "\n " .. offset .. "\n" - end - if orientation then - sceneString = sceneString .. "\n " .. orientation .. "\n" - end - if scale then - sceneString = sceneString .. "\n " .. scale .. "\n" - end - - sceneString = sceneString .. " \n" - - return sceneString - - -- return [[ - -- - -- ]]..offset..[[ - -- ]]..orientation..[[ - -- ]]..scale..[[ - -- ]] - end + table.insert(result, [[ }]]) end -function generateSettings(arg) - local v - if arg["vsync"] then - v = 1 - else - v = 0 - end +function generateCluster(arg, viewport) + local result = {} - local refresh = "" - if arg["refreshRate"] then - refresh = "refreshRate=\"" .. arg["refreshRate"] .. "\" " - end + table.insert(result, [[{]]) + table.insert(result, [[ "version": 1,]]) + table.insert(result, [[ "masteraddress": "127.0.0.1",]]) + if arg["sgctDebug"] then + table.insert(result, [[ "debug": ]] .. tostring(arg["sgctdebug"]) .. [[,]]) + end + if (arg["settings"]) then + table.insert(result, [[ "settings": {]]) + generateSettings(result, arg["refreshRate"], arg["vsync"]) + table.insert(result, [[ },]]) + end - return [[ - - - -]] + if arg["scene"] then + table.insert(result, [[ "scene": {]]) + generateScene(result, arg["scene"]) + table.insert(result, [[ },]]) + end + + table.insert(result, [[ "nodes": []]) + table.insert(result, [[ {]]) + table.insert(result, [[ "address": "127.0.0.1",]]) + table.insert(result, [[ "port": 20401,]]) + table.insert(result, [[ "windows": []]) + table.insert(result, [[ {]]) + generateWindow(result, arg["fullScreen"], arg["msaa"], arg["border"], arg["monitor"], + arg["tags"], arg["stereo"], arg["pos"], arg["size"], arg["res"], viewport) + table.insert(result, [[ }]]) + table.insert(result, [[ ] ]]) + table.insert(result, [[ }]]) + table.insert(result, [[ ],]]) + table.insert(result, [[ "users": []]) + generateUser(result) + table.insert(result, [[ ] ]]) + table.insert(result, [[}]]) + + return table.concat(result, "\n") end -function generateCapture(arg) - if arg["capture"] == nil then - return "" - else - local path = "" - if arg["capture"]["path"] then - path = 'path="' .. arg["capture"]["path"] .. '" ' - end +function check(type_str, arg, param, subparam_type) + local t = type(arg[param]) + assert(t == type_str or t == "nil", param .. " must be a " .. type_str .. " or nil") - local monoPath = "" - if arg["capture"]["monoPath"] then - path = 'monoPath="' .. arg["capture"]["monoPath"] .. '" ' - end - - local leftPath = "" - if arg["capture"]["leftPath"] then - path = 'leftPath="' .. arg["capture"]["leftPath"] .. '" ' - end - - local rightPath = "" - if arg["capture"]["rightPath"] then - path = 'rightPath="' .. arg["capture"]["rightPath"] .. '" ' - end - - local format = "" - if arg["capture"]["format"] then - path = 'format="' .. arg["capture"]["format"] .. '" ' - end - end + if type_str == "table" and subparam_type and arg[param] then + for k, v in pairs(arg[param]) do + assert( + type(v) == subparam_type, + param .. "[" .. k .. "] must be a " .. subparam_type + ) + end + end end -function generateCluster(arg) - return [[ - - -]] .. (arg["settings"] or "") .. [[ -]] .. (arg["scene"] or "") .. [[ - -]] .. arg["window"] ..[[ - -]] .. arg["user"] .. [[ -]] .. (arg["capture"] or "") .. [[ - -]] +function generateSingleWindowConfig(arg, viewport) + check("table", arg, "res", "number") + check("table", arg, "tags", "string") + check("table", arg, "pos", "number") + check("boolean", arg, "shared") + check("boolean", arg, "fullScreen") + check("boolean", arg, "border") + check("boolean", arg, "vsync") + check("boolean", arg, "sgctDebug") + check("number", arg, "monitor") + check("number", arg, "msaa") + check("number", arg, "refreshRate") + check("string", arg, "stereo") + + check("table", arg, "scene") + if arg["scene"] then + check("table", arg["scene"], "offset", "number") + check("table", arg["scene"], "orientation", "number") + check("number", arg["scene"], "scale") + end + + if arg["shared"] then + local t = arg["tags"] + t[#t + 1] = "Spout" + end + + return generateCluster(arg, viewport) end -function generateSingleWindowConfig(arg) - -- First some type checking - assert( - type(arg["res"]) == "table" or type(arg["res"]) == "nil", - "res must be a table or nil" - ) - if (type(arg["res"]) == "table") then - assert(type(arg["res"][1]) == "number", "res[1] must be a number") - assert(type(arg["res"][2]) == "number", "res[2] must be a number") - end - - assert( - type(arg["shared"]) == "boolean" or type(arg["shared"]) == "nil", - "shared must be a boolean or nil" - ) - - assert( - type(arg["tags"]) == "table" or type(arg["tags"]) == "nil", - "tags must be a table or nil" - ) - if (type(arg["tags"]) == "table") and (next(arg["tags"]) ~= nil) then - for index, value in ipairs(arg["tags"]) do - assert(type(value) == "string", "Each tag must be a string") - end - end - - assert( - type(arg["windowSize"]) == "table" or type(arg["windowSize"]) == "nil", - "windowSize must be a table or nil" - ) - if (type(arg["windowSize"]) == "table") then - assert(type(arg["windowSize"][1]) == "number", "windowPos[1] must be a number") - assert(type(arg["windowSize"][2]) == "number", "windowPos[2] must be a number") - end - - assert( - type(arg["windowPos"]) == "table" or type(arg["windowPos"]) == "nil", - "windowPos must be a table or nil" - ) - if (type(arg["windowPos"]) == "table") then - assert(type(arg["windowPos"][1]) == "number", "windowPos[1] must be a number") - assert(type(arg["windowPos"][2]) == "number", "windowPos[2] must be a number") - end - - assert( - type(arg["name"]) == "string" or type(arg["name"]) == "nil", - "name must be a string or nil" - ) - - assert( - type(arg["fullScreen"]) == "boolean" or type(arg["fullScreen"]) == "nil", - "fullScreen must be a boolean or nil" - ) - - assert( - type(arg["monitor"]) == "number" or type(arg["monitor"]) == "nil", - "monitor must be a number or nil" - ) - - assert( - type(arg["border"]) == "boolean" or type(arg["border"]) == "nil", - "border must be a boolean or nil" - ) - - assert( - type(arg["msaa"]) == "number" or type(arg["msaa"]) == "nil", - "msaa must be a number or nil" - ) - - assert( - type(arg["vsync"]) == "boolean" or type(arg["vsync"]) == "nil", - "vsync must be a boolean or nil" - ) - - assert( - type(arg["refreshRate"]) == "number" or type(arg["refreshRate"]) == "nil", - "refreshRate must be a number or nil" - ) - - assert( - type(arg["stereo"]) == "string" or type(arg["stereo"]) == "nil", - "stereo must be a boolean or nil" - ) - - assert( - type(arg["eyeSep"]) == "number" or type(arg["eyeSep"]) == "nil", - "eyeSep must be a number or nil" - ) - - assert( - type(arg["eyePos"]) == "table" or type(arg["eyePos"]) == "nil", - "eyePos must be a table or nil" - ) - if (type(arg["eyePos"]) == "table") then - assert(type(arg["eyePos"][1]) == "number", "eyePos[1] must be a number") - assert(type(arg["eyePos"][2]) == "number", "eyePos[2] must be a number") - assert(type(arg["eyePos"][3]) == "number", "eyePos[3] must be a number") - end - - assert( - type(arg["sgctDebug"]) == "boolean" or type(arg["sgctDebug"]) == "nil", - "sgctDebug must be a boolean or nil" - ) - - assert( - type(arg["scene"]) == "table" or type(arg["scene"]) == "nil", - "scene must be a table or nil" - ) - if type(arg["scene"]) == "table" then - local offset = arg["scene"]["offset"] - assert( - type(offset) == "table" or type(offset) == "nil", - "scene['offset'] must be a table or nil" - ) - if type(offset) == "table" then - assert(type(offset["x"]) == "number", "scene['offset']['x'] must be a number") - assert(type(offset["y"]) == "number", "scene['offset']['y'] must be a number") - assert(type(offset["z"]) == "number", "scene['offset']['z'] must be a number") - end - - local orientation = arg["scene"]["orientation"] - assert( - type(orientation) == "table" or type(orientation) == "nil", - "scene['orientation] must be a table or nil" - ) - if type(orientation) == "table" then - assert(type(orientation["yaw"]) == "number", "orientation['yaw'] must be a number") - assert(type(orientation["pitch"]) == "number", "orientation['pitch'] must be a number") - assert(type(orientation["roll"]) == "number", "orientation['roll'] must be a number") - end - - local scale = arg["scene"]["scale"] - assert( - type(scale) == "number" or type(scale) == "nil", - "scene['scale'] must be a number or nil" - ) - end - - assert( - type(arg["capture"]) == "table" or type(arg["capture"]) == "nil", - "capture must be a table or nil" - ) - if type(arg["capture"]) == "table" then - local c = arg["capture"] - assert( - type(c["path"]) == "string" or type(c["path"]) == "nil", - "capture['path'] must be a string or nil" - ) - assert( - type(c["monoPath"]) == "string" or type(c["monoPath"]) == "nil", - "capture['monoPath'] must be a string or nil" - ) - assert( - type(c["leftPath"]) == "string" or type(c["leftPath"]) == "nil", - "capture['leftPath'] must be a string or nil" - ) - assert( - type(c["rightPath"]) == "string" or type(c["rightPath"]) == "nil", - "capture['rightPath'] must be a string or nil" - ) - assert( - type(c["format"]) == "string" or type(c["format"]) == "nil", - "capture['format'] must be a string or nil" - ) - end - - assert(type(arg["viewport"]) == "string", "viewport must be a string") - - -- Then setting reasonable default values - if arg["vsync"] == nil then - arg["vsync"] = false - end - - if arg["fullScreen"] == nil then - arg["fullScreen"] = false - end - - if arg["monitor"] == nil then - arg["monitor"] = 0 - end - - if arg["tags"] == nil then - arg["tags"] = {} - end - - if arg["msaa"] == nil then - arg["msaa"] = 4 - end - - if arg["border"] == nil then - arg["border"] = true - end - - if arg["shared"] then - local t = arg["tags"] - t[#t + 1] = "Spout" - end - - if arg["name"] == nil then - arg["name"] = "OpenSpace" - end - - if arg["stereo"] == nil then - arg["stereo"] = "none" - end - - if arg["windowPos"] == nil then - arg["windowPos"] = { 50, 50 } - end - - if arg["eyeSep"] == nil then - arg["eyeSep"] = 0.065 - end - - if arg["eyePos"] == nil then - arg["eyePos"] = { 0.0, 0.0, 0.0 } - end - - if arg["sgctDebug"] == nil then - arg["sgctDebug"] = false - end - - if not arg["windowSize"] then - arg["windowSize"] = {1280, 720} - end - - arg["scene"] = generateScene(arg) - arg["settings"] = generateSettings(arg) - arg["window"] = generateWindow(arg) - arg["user"] = generateUser(arg) - arg["capture"] = generateCapture(arg) - - return generateCluster(arg) -end - - function normalizeArg(arg) - arg = arg or {} + arg = arg or {} - if (type(arg["windowSize"]) == "table") then - assert( - type(arg[1]) == "nil" and type(arg[2]) == "nil", - "Only windowSize or the first and second arguments can be set. Not both" - ) - end - assert( - type(arg[1]) == "number" or type(arg[1]) == "nil", - "First argument must be a number or nil" - ) - assert( - type(arg[2]) == "number" or type(arg[2]) == "nil", - "Second argument must be a number or nil" - ) - if (type(arg[1]) == "number") then - if (type(arg[2]) == "nil") then - arg[2] = arg[1] * 9/16 - end - arg["windowSize"] = { arg[1], arg[2] } - arg[1] = nil - arg[2] = nil - end + check("number", arg, 1) + check("number", arg, 2) - return arg + if type(arg[1]) == "number" and type(arg[2]) == "number" then + arg["size"] = { arg[1], arg[2] } + arg[1] = nil + arg[2] = nil + end end + function sgct.makeConfig(config) - local configFile = os.tmpname() - - local file = io.open(configFile, "w+") - - file:write(config) - - io.close(file) - return configFile + local configFile = os.tmpname() .. ".json" + local file = io.open(configFile, "w+") + file:write(config) + io.close(file) + return configFile end function sgct.config.single(arg) - arg = normalizeArg(arg) + normalizeArg(arg) - assert( - type(arg["windowSize"]) == "table" or type(arg["windowSize"]) == "nil", - "windowSize must be a table or nil" - ) + check("table", arg, "size", "number") + check("table", arg, "fov", "number") - assert( - type(arg["fov"]) == "table" or type(arg["fov"]) == "nil", - "fov must be a table or nil" - ) - if (type(arg["fov"]) == "table") then - assert(type(arg["fov"]["left"]) == "number", "fov['left'] must be a number") - assert(type(arg["fov"]["right"]) == "number", "fov['right'] must be a number") - assert(type(arg["fov"]["up"]) == "number", "fov['up'] must be a number") - assert(type(arg["fov"]["down"]) == "number", "fov['down'] must be a number") + arg["vsync"] = arg["vsync"] or false + arg["tags"] = arg["tags"] or {} + arg["pos"] = arg["pos"] or { 50, 50 } + arg["size"] = arg["size"] or { 1280, 720 } + + if (not arg["fov"]) then + local tanDefaultFov = math.tan(math.rad(40.0)) + + local tanHorizontalFov + local tanVerticalFov + local aspectRatio = arg["size"][1] / arg["size"][2] + if (aspectRatio > 1) then + tanHorizontalFov = tanDefaultFov + tanVerticalFov = tanDefaultFov / aspectRatio else - local defaultFov = 40 - local defaultRatio = 16/9 -- comes from default res 1280 x 720 - local tanDefaultFov = math.tan(math.pi * defaultFov / 180) - - if (type(arg["windowSize"]) == "table") then - assert(type(arg["windowSize"][1]) == "number", "windowPos[1] must be a number") - assert(type(arg["windowSize"][2]) == "number", "windowPos[2] must be a number") - local tanHorizontalFov = tanDefaultFov - local tanVerticalFov = tanDefaultFov - - local ratio = arg["windowSize"][1] / arg["windowSize"][2] - - -- ratio between w and h should be - -- same as tan(horizontalFov) and tan(verticalFov) - - if (ratio > 1) then - tanVerticalFov = tanHorizontalFov / ratio - else - tanHorizontalFov = tanVerticalFov * ratio - end - - -- sgct expects fov in degrees - arg["fov"] = { - down = 180 * math.atan(tanVerticalFov) / math.pi, - up = 180 * math.atan(tanVerticalFov) / math.pi, - left = 180 * math.atan(tanHorizontalFov) / math.pi, - right = 180 * math.atan(tanHorizontalFov) / math.pi - } - else - -- sgct expects fov in degrees - arg["fov"] = { - down = 180 * math.atan(tanDefaultFov / defaultRatio) / math.pi, - up = 180 * math.atan(tanDefaultFov / defaultRatio) / math.pi, - left = 180 * math.atan(tanDefaultFov) / math.pi, - right = 180 * math.atan(tanDefaultFov) / math.pi - } - end + tanHorizontalFov = tanDefaultFov * aspectRatio + tanVerticalFov = tanDefaultFov end - assert( - type(arg["tracked"]) == "boolean" or type(arg["tracked"]) == "nil", - "tracked must be a boolean or nil" - ) - sgctconfiginitializeString = "sgct.config.single" + arg["fov"] = { + down = math.deg(math.atan(tanVerticalFov)), + up = math.deg(math.atan(tanVerticalFov)), + left = math.deg(math.atan(tanHorizontalFov)), + right = math.deg(math.atan(tanHorizontalFov)) + } + end - local trackedSpecifier = "tracked=\"true\"" + check("boolean", arg, "tracked") + sgctconfiginitializeString = "sgct.config.single" - if (arg["tracked"] ~= nil and arg["tracked"] == false) then - trackedSpecifier = "tracked=\"false\"" - end + arg["tracked"] = arg["tracked"] or true - arg["viewport"] = generateSingleViewportFOV( - arg["fov"]["down"], - arg["fov"]["up"], - arg["fov"]["left"], - arg["fov"]["right"], - trackedSpecifier - ) - return sgct.makeConfig(generateSingleWindowConfig(arg)) + local viewport = generateSingleViewportFOV(arg["fov"]["down"], arg["fov"]["up"], + arg["fov"]["left"], arg["fov"]["right"], arg["tracked"]) + + return sgct.makeConfig(generateSingleWindowConfig(arg, viewport)) end function sgct.config.fisheye(arg) + normalizeArg(arg) - arg = normalizeArg(arg) + check("number", arg, "fov") + check("number", arg, "tilt") + check("string", arg, "quality") + check("table", arg, "background", "number") + check("table", arg, "crop", "number") + check("table", arg, "offset", "number") - assert( - type(arg["fov"]) == "number" or type(arg["fov"]) == "nil", - "fov must be a number or nil" - ) + sgctconfiginitializeString = "sgct.config.fisheye" - assert( - type(arg["quality"]) == "string" or type(arg["quality"]) == "nil", - "quality must be a string or nil" - ) + arg["vsync"] = arg["vsync"] or false + arg["tags"] = arg["tags"] or {} + arg["pos"] = arg["pos"] or { 50, 50 } + arg["size"] = arg["size"] or { 1024, 1024 } - assert( - type(arg["tilt"]) == "number" or type(arg["tilt"]) == "nil", - "tilt must be a number or nil" - ) + arg["quality"] = arg["quality"] or "1k" + arg["tilt"] = arg["tilt"] or 90.0 + arg["background"] = arg["background"] or { r = 0.0, g = 0.0, b = 0.0, a = 1.0 } + arg["tracked"] = arg["tracked"] or false - assert( - type(arg["background"]) == "table" or type(arg["background"]) == "nil", - "background must be a table or nil" - ) - if type(arg["background"]) == "table" then - assert(type(background["r"]) == "number", "backgroud['r'] must be a number") - assert(type(background["g"]) == "number", "backgroud['g'] must be a number") - assert(type(background["b"]) == "number", "backgroud['b'] must be a number") - assert(type(background["a"]) == "number", "backgroud['a'] must be a number") - end + local viewport = generateFisheyeViewport(arg["fov"], arg["quality"], arg["tilt"], + arg["background"], arg["crop"], arg["offset"], arg["tracked"]) - assert( - type(arg["crop"]) == "table" or type(arg["crop"]) == "nil", - "crop must be a table or nil" - ) - if type(arg["crop"]) == "table" then - assert( - type(arg["crop"]["left"]) == "number", "crop['left'] must be a number" - ) - assert( - type(arg["crop"]["right"]) == "number", "crop['right'] must be a number" - ) - assert( - type(arg["crop"]["top"]) == "number", "crop['top'] must be a number" - ) - assert( - type(arg["crop"]["bottom"]) == "number", "crop['bottom'] must be a number" - ) - end - - assert( - type(arg["offset"]) == "table" or type(arg["offset"]) == "nil", - "offset must be a table or nil" - ) - if type(arg["offset"]) == "table" then - assert(type(arg["offset"]["x"]) == "number", "offset['x'] must be a number") - assert(type(arg["offset"]["y"]) == "number", "offset['y'] must be a number") - assert(type(arg["offset"]["z"]) == "number", "offset['z'] must be a number") - end - - sgctconfiginitializeString = "sgct.config.fisheye" - - if arg["fov"] == nil then - arg["fov"] = 180 - end - - if arg["quality"] == nil then - arg["quality"] = "1k" - end - - if arg["tilt"] == nil then - arg["tilt"] = 90 - end - - if arg["background"] == nil then - arg["background"] = { r = 0.0, g = 0.0, b = 0.0, a = 1.0 } - end - - local trackedSpecifier = "" - if (arg["tracked"] ~= nil and arg["tracked"] == true) then - trackedSpecifier = "tracked=\"true\"" - else - trackedSpecifier = "tracked=\"false\"" - end - - arg["viewport"] = generateFisheyeViewport( - arg["fov"], - arg["quality"], - arg["tilt"], - arg["background"], - arg["crop"], - arg["offset"], - trackedSpecifier - ) - - return sgct.makeConfig(generateSingleWindowConfig(arg)) + return sgct.makeConfig(generateSingleWindowConfig(arg, viewport)) end - - - -function sgct.config.cube(arg) - function getCubeWindow(location, res, size, trackedSpecifier) - local pos - local lowerLeft - local upperLeft - local upperRight - if location == 'left' then - pos = { 0, size[2] } - lowerLeft = { -1, -1, 1 } - upperLeft = { -1, 1, 1 } - upperRight = { -1, 1, -1 } - elseif location == 'right' then - pos = { 2 * size[1], size[2] } - lowerLeft = { 1, -1, -1 } - upperLeft = { 1, 1, -1 } - upperRight = { 1, 1, 1 } - elseif location == 'up' then - pos = { size[1], 0 } - lowerLeft = { 1, 1, -1 } - upperLeft = { 1, 1, 1 } - upperRight = { -1, 1, 1 } - elseif location == 'down' then - pos = { size[1], 2 * size[2] } - lowerLeft = { -1, -1, 1 } - upperLeft = { -1, -1, -1 } - upperRight = { 1, -1, -1 } - elseif location == 'back' then - pos = { 2 * size[1], 2 * size[2] } - lowerLeft = { 1, -1, 1 } - upperLeft = { 1, 1, 1 } - upperRight = { -1, 1, 1 } - elseif location == 'front' then - pos = { size[1], size[2] } - lowerLeft = { -1, -1, -1 } - upperLeft = { -1, 1, -1 } - upperRight = { 1, 1, -1 } - end - - arg = {} - arg["msaa"] = 8 - arg["border"] = false - arg["name"] = "OpenSpace_" .. location - arg["tags"] = { "Spout" } - arg["windowSize"] = size - arg["windowPos"] = pos - arg["res"] = { res, res } - arg["viewport"] = generateSingleViewport(lowerLeft, upperLeft, upperRight, trackedSpecifier) - - return generateWindow(arg) - end - - function getControlWindow(down, up, left, right, trackedSpecifier) - arg = {} - arg["viewport"] = generateSingleViewportFOV(down, up, left, right, trackedSpecifier) - return generateWindow(arg) - end - - sgctconfiginitializeString = "sgct.config.cube" - - res = 1024 - size = { 640, 360 } - - arg["scene"] = generateScene(arg) - arg["settings"] = generateSettings(arg) - if (arg["tracked"] ~= nil and arg["tracked"] == true) then - trackedSpecifier = "tracked=\"true\"" - else - trackedSpecifier = "tracked=\"false\"" - end - - arg["window"] = getControlWindow(16.875, 16.875, 30.0, 30.0, trackedSpecifier) .. - getCubeWindow('front', res, size, trackedSpecifier) .. - getCubeWindow('back', res, size, trackedSpecifier) .. - getCubeWindow('left', res, size, trackedSpecifier) .. - getCubeWindow('right', res, size, trackedSpecifier) .. - getCubeWindow('up', res, size, trackedSpecifier) .. - getCubeWindow('down', res, size, trackedSpecifier) - - arg["user"] = generateUser(arg) - arg["capture"] = generateCapture(arg) - - return sgct.makeConfig(generateCluster(arg)) -end - diff --git a/src/navigation/orbitalnavigator.cpp b/src/navigation/orbitalnavigator.cpp index 80ab5f441d..d190938d28 100644 --- a/src/navigation/orbitalnavigator.cpp +++ b/src/navigation/orbitalnavigator.cpp @@ -134,24 +134,33 @@ namespace { }; constexpr openspace::properties::Property::PropertyInfo FollowAnchorNodeInfo = { + "FollowAnchorNodeRotation", + "Follow Anchor Node Rotation", + "If true, the camera will rotate with the current achor node if within a " + "certain distance from it. When this happens, the object will appear fixed in " + "relation to the camera. The distance at which the change happens is controlled " + "through another property." + }; + + constexpr openspace::properties::Property::PropertyInfo + FollowAnchorNodeDistanceInfo = { "FollowAnchorNodeRotationDistance", - "Follow anchor node rotation distance", + "Follow Anchor Node Rotation Distance", "A factor used to determine the distance at which the camera starts rotating " - "with the anchor node. When this happends, a the object will appear fixed in " - "relation to the camera. The actual distance will be computed by multiplying " + "with the anchor node. The actual distance will be computed by multiplying " "this factor with the approximate radius of the node." }; constexpr openspace::properties::Property::PropertyInfo MinimumDistanceInfo = { "MinimumAllowedDistance", - "Minimum allowed distance", + "Minimum Allowed Distance", "Limits how close the camera can get to an object. The distance is given in " "meters above the surface." }; constexpr openspace::properties::Property::PropertyInfo VelocityZoomControlInfo = { "VelocityZoomControl", - "Velocity zoom control", + "Velocity Zoom Control", "Controls the velocity of the camera motion when zooming in to the focus node " "on a linear flight. The higher the value the faster the camera will move " "towards the focus." @@ -180,7 +189,7 @@ namespace { constexpr openspace::properties::Property::PropertyInfo StereoInterpolationTimeInfo = { "StereoInterpolationTime", - "Stereo interpolation time", + "Stereo Interpolation Time", "The time to interpolate to a new stereoscopic depth " "when the anchor node is changed, in seconds." }; @@ -188,7 +197,7 @@ namespace { constexpr openspace::properties::Property::PropertyInfo RetargetInterpolationTimeInfo = { "RetargetAnchorInterpolationTime", - "Retarget interpolation time", + "Retarget Interpolation Time", "The time to interpolate the camera rotation " "when the anchor or aim node is changed, in seconds." }; @@ -196,13 +205,13 @@ namespace { constexpr openspace::properties::Property::PropertyInfo FollowRotationInterpTimeInfo = { "FollowRotationInterpolationTime", - "Follow rotation interpolation time", + "Follow Rotation Interpolation Time", "The interpolation time when toggling following focus node rotation." }; constexpr openspace::properties::Property::PropertyInfo InvertMouseButtons = { "InvertMouseButtons", - "Invert left and right mouse buttons", + "Invert Left and Right Mouse Buttons", "If this value is 'false', the left mouse button causes the camera to rotate " "around the object and the right mouse button causes the zooming motion. If this " "value is 'true', these two functionalities are reversed." @@ -229,7 +238,7 @@ namespace { constexpr openspace::properties::Property::PropertyInfo StereoscopicDepthOfFocusSurfaceInfo = { "StereoscopicDepthOfFocusSurface", - "Stereoscopic depth of the surface in focus", + "Stereoscopic Depth of the Surface in Focus", "Set the stereoscopically perceived distance (in meters) to the closest " "point out of the surface of the anchor and the center of the aim node. " "Only used if UseAdaptiveStereoscopicDepthInfo is set to true." @@ -331,7 +340,8 @@ OrbitalNavigator::OrbitalNavigator() , _aim(AimInfo) , _retargetAnchor(RetargetAnchorInfo) , _retargetAim(RetargetAimInfo) - , _followAnchorNodeRotationDistance(FollowAnchorNodeInfo, 5.f, 0.f, 20.f) + , _followAnchorNodeRotation(FollowAnchorNodeInfo, true) + , _followAnchorNodeRotationDistance(FollowAnchorNodeDistanceInfo, 5.f, 0.f, 20.f) , _minimumAllowedDistance(MinimumDistanceInfo, 10.0f, 0.0f, 10000.f) , _mouseSensitivity(MouseSensitivityInfo, 15.f, 1.f, 50.f) , _joystickSensitivity(JoystickSensitivityInfo, 10.f, 1.0f, 50.f) @@ -491,6 +501,7 @@ OrbitalNavigator::OrbitalNavigator() addProperty(_aim); addProperty(_retargetAnchor); addProperty(_retargetAim); + addProperty(_followAnchorNodeRotation); addProperty(_followAnchorNodeRotationDistance); addProperty(_minimumAllowedDistance); @@ -954,7 +965,7 @@ void OrbitalNavigator::setRetargetInterpolationTime(float durationInSeconds) { bool OrbitalNavigator::shouldFollowAnchorRotation(const glm::dvec3& cameraPosition) const { - if (!_anchorNode) { + if (!_anchorNode || !_followAnchorNodeRotation) { return false; } diff --git a/src/navigation/pathnavigator.cpp b/src/navigation/pathnavigator.cpp index 9bd101265d..df29a3e169 100644 --- a/src/navigation/pathnavigator.cpp +++ b/src/navigation/pathnavigator.cpp @@ -200,7 +200,7 @@ void PathNavigator::updateCamera(double deltaTime) { if (_currentPath->hasReachedEnd()) { LINFO("Reached end of path"); - _isPlaying = false; + handlePathEnd(); if (_applyIdleBehaviorOnFinish) { constexpr const char* ApplyIdleBehaviorScript = @@ -263,10 +263,16 @@ void PathNavigator::startPath() { return; } - //OBS! Until we can handle simulation time: early out if not paused + // Always pause the simulation time when flying, to aovid problem with objects + // moving. However, keep track of whether the time was running before the path + // was started, so we can reset it on finish if (!global::timeManager->isPaused()) { - LERROR("Simulation time must be paused to run a camera path"); - return; + global::timeManager->setPause(true); + _startSimulationTimeOnFinish = true; + LINFO( + "Pausing time simulation during path traversal. " + "Will unpause once the camera path is finished" + ); } LINFO("Starting path"); @@ -280,9 +286,7 @@ void PathNavigator::abortPath() { LWARNING("No camera path is playing"); return; } - _isPlaying = false; - clearPath(); // TODO: instead of clearing this could be handled better - + handlePathEnd(); LINFO("Aborted camera path"); } @@ -329,6 +333,16 @@ const std::vector& PathNavigator::relevantNodes() { return _relevantNodes; } +void PathNavigator::handlePathEnd() { + _isPlaying = false; + + if (_startSimulationTimeOnFinish) { + global::timeManager->setPause(false); + } + _startSimulationTimeOnFinish = false; + clearPath(); +} + void PathNavigator::findRelevantNodes() { const std::vector& allNodes = global::renderEngine->scene()->allSceneGraphNodes(); @@ -413,8 +427,8 @@ scripting::LuaLibrary PathNavigator::luaLibrary() { "Stops a path, if one is being played" }, { - "goTo", - &luascriptfunctions::goTo, + "flyTo", + &luascriptfunctions::flyTo, "string [, bool, double]", "Move the camera to the node with the specified identifier. The optional " "double specifies the duration of the motion. If the optional bool is " @@ -422,8 +436,8 @@ scripting::LuaLibrary PathNavigator::luaLibrary() { "node. Either of the optional parameters can be left out." }, { - "goToHeight", - &luascriptfunctions::goToHeight, + "flyToHeight", + &luascriptfunctions::flyToHeight, "string, double [, bool, double]", "Move the camera to the node with the specified identifier. The second " "argument is the desired target height above the target node's bounding " @@ -433,8 +447,8 @@ scripting::LuaLibrary PathNavigator::luaLibrary() { "parameters can be left out." }, { - "goToNavigationState", - &luascriptfunctions::goToNavigationState, + "flyToNavigationState", + &luascriptfunctions::flyToNavigationState, "table, [double]", "Create a path to the navigation state described by the input table. " "The optional double specifies the target duration of the motion. Note " @@ -445,7 +459,7 @@ scripting::LuaLibrary PathNavigator::luaLibrary() { "createPath", &luascriptfunctions::createPath, "table", - "Create the path as described by the lua table input argument" + "Create a camera path as described by the lua table input argument" }, } }; diff --git a/src/navigation/pathnavigator_lua.inl b/src/navigation/pathnavigator_lua.inl index f921fb0182..de306c1d4c 100644 --- a/src/navigation/pathnavigator_lua.inl +++ b/src/navigation/pathnavigator_lua.inl @@ -68,8 +68,8 @@ int stopPath(lua_State* L) { return 0; } -int goTo(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, { 1, 3 }, "lua::goTo"); +int flyTo(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, { 1, 3 }, "lua::flyTo"); auto [nodeIdentifier, useUpFromTargetOrDuration, duration] = ghoul::lua::values< std::string, std::optional>, std::optional >(L); @@ -120,8 +120,8 @@ int goTo(lua_State* L) { return 0; } -int goToHeight(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::goToHeight"); +int flyToHeight(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::flyToHeight"); auto [nodeIdentifier, height, useUpFromTargetOrDuration, duration] = ghoul::lua::values< std::string, double, std::optional>, @@ -169,8 +169,8 @@ int goToHeight(lua_State* L) { return 0; } -int goToNavigationState(lua_State* L) { - ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::goToNavigationState"); +int flyToNavigationState(lua_State* L) { + ghoul::lua::checkArgumentsAndThrow(L, { 1, 2 }, "lua::flyToNavigationState"); auto [navigationState, duration] = ghoul::lua::values>(L); @@ -182,7 +182,7 @@ int goToNavigationState(lua_State* L) { ); } catch (documentation::SpecificationError& e) { - LERRORC("goToNavigationState", ghoul::to_string(e.result)); + LERRORC("flyToNavigationState", ghoul::to_string(e.result)); return ghoul::lua::luaError( L, fmt::format("Unable to create a path: {}", e.what()) ); diff --git a/src/scene/assetmanager.cpp b/src/scene/assetmanager.cpp index 5c9a712d33..d3cee96134 100644 --- a/src/scene/assetmanager.cpp +++ b/src/scene/assetmanager.cpp @@ -127,8 +127,8 @@ void AssetManager::deinitialize() { for (Asset* asset : _rootAssets) { if (!asset->hasInitializedParent()) { asset->deinitialize(); + asset->unload(); } - asset->unload(); } _toBeDeleted.clear(); } diff --git a/src/scripting/scriptengine_lua.inl b/src/scripting/scriptengine_lua.inl index 32da22087a..5dfa440a59 100644 --- a/src/scripting/scriptengine_lua.inl +++ b/src/scripting/scriptengine_lua.inl @@ -300,6 +300,10 @@ int unzipFile(lua_State* L) { dest = absPath(dest).string(); deleteSource = deleteSource.value_or(false); + if (!std::filesystem::exists(source)) { + return luaL_error(L, "Source file was not found"); + } + int arg = 2; zip_extract(source.c_str(), dest.c_str(), [](const char*, void*) { return 0; }, &arg); diff --git a/support/coding/codegen b/support/coding/codegen index d3b1ba7b43..425a0a224e 160000 --- a/support/coding/codegen +++ b/support/coding/codegen @@ -1 +1 @@ -Subproject commit d3b1ba7b4391ded0f7ea64d00c1ad3e4e828776c +Subproject commit 425a0a224e28802f0f2d88c0b2034ee5a473cc3b