diff --git a/apps/OpenSpace/ext/launcher/include/filesystemaccess.h b/apps/OpenSpace/ext/launcher/include/filesystemaccess.h index 6acdbb1c87..945fcb113d 100644 --- a/apps/OpenSpace/ext/launcher/include/filesystemaccess.h +++ b/apps/OpenSpace/ext/launcher/include/filesystemaccess.h @@ -34,10 +34,6 @@ public: * * \param fileExtension string that defines the filter used to find files. Only * files with this extension will be recognized (e.g. '.xml') - * \param approvedPaths vector or strings containing directory names to be included - * in the search. These are directories at the base level of - * the starting point of the search. Any sub-directories within - * these directories will be included. * \param hideFileExtensions if true then file extensions will be removed from the * listed files in the output * \param useCheckboxes if true then the text output format will contain a '0' as @@ -45,8 +41,7 @@ public: * used to represent checked ('1'), uncheck ('0') or doesn't * exist in filesystem ('x') states. */ - FileSystemAccess(std::string fileExtension, - std::vector approvedPaths, bool hideFileExtensions, + FileSystemAccess(std::string fileExtension, bool hideFileExtensions, bool useCheckboxes); /** @@ -54,7 +49,8 @@ public: * * \param dir The directory from which to start the search from */ - std::string useQtFileSystemModelToTraverseDir(std::string dir, bool usersAssets = false); + std::string useQtFileSystemModelToTraverseDir(std::string dir, + bool usersAssets = false); private: void parseChildDirElements(QFileInfo item, std::string space, int level, @@ -62,7 +58,6 @@ private: bool userAssets); void parseChildFile(std::string res, bool& hasDirHeaderBeenAdded, std::vector& dirNames, std::vector& output); - bool isApprovedPath(std::string path); QFileSystemModel _filesystemModel; QDir::Filters _fileFilterOptions = QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot; diff --git a/apps/OpenSpace/ext/launcher/src/filesystemaccess.cpp b/apps/OpenSpace/ext/launcher/src/filesystemaccess.cpp index 9912c3bead..f58665913d 100644 --- a/apps/OpenSpace/ext/launcher/src/filesystemaccess.cpp +++ b/apps/OpenSpace/ext/launcher/src/filesystemaccess.cpp @@ -25,15 +25,14 @@ #include "filesystemaccess.h" FileSystemAccess::FileSystemAccess(std::string fileExtension, - std::vector approvedPaths, bool hideFileExtensions, bool useCheckboxes) : _fileExtension(std::move(fileExtension)) - , _approvedPaths(std::move(approvedPaths)) , _hideFileExtensions(hideFileExtensions) , _useCheckboxes(useCheckboxes) {} -std::string FileSystemAccess::useQtFileSystemModelToTraverseDir(std::string dir, bool userAssets) { +std::string FileSystemAccess::useQtFileSystemModelToTraverseDir(std::string dir, + bool userAssets) { _filesystemModel.setRootPath(QString::fromStdString(dir)); QModelIndex index = _filesystemModel.index(_filesystemModel.rootPath()); QFileInfo fileInfo = _filesystemModel.fileInfo(index); @@ -48,8 +47,10 @@ std::string FileSystemAccess::useQtFileSystemModelToTraverseDir(std::string dir, } void FileSystemAccess::parseChildDirElements(QFileInfo fileInfo, std::string space, - int level, std::vector& dirNames, - std::vector& output, bool userAssets) + int level, + std::vector& dirNames, + std::vector& output, + bool userAssets) { QDir dir(fileInfo.filePath()); bool hasDirHeaderBeenAdded = false; @@ -62,10 +63,8 @@ void FileSystemAccess::parseChildDirElements(QFileInfo fileInfo, std::string spa res = "${USER_ASSETS}/" + res; } if (fi.isDir()) { - if (level != 0 || (level == 0 && (isApprovedPath(res) || userAssets))) { - dirNames.push_back(res); - parseChildDirElements(fi, (space + " "), level + 1, dirNames, output, userAssets); - } + dirNames.push_back(res); + parseChildDirElements(fi, (space + " "), level + 1, dirNames, output, userAssets); } else { parseChildFile(res, hasDirHeaderBeenAdded, dirNames, output); @@ -77,19 +76,6 @@ void FileSystemAccess::parseChildDirElements(QFileInfo fileInfo, std::string spa } } -bool FileSystemAccess::isApprovedPath(std::string path) { - bool approvedMatch = false; - path.erase(0, path.find_first_not_of(" ")); - - for (const std::string& p : _approvedPaths) { - if (path.substr(0, p.length()).compare(p) == 0) { - approvedMatch = true; - break; - } - } - return approvedMatch; -} - void FileSystemAccess::parseChildFile(std::string filename, bool& hasDirHeaderBeenAdded, std::vector& dirNames, std::vector& output) diff --git a/apps/OpenSpace/ext/launcher/src/profile/actiondialog.cpp b/apps/OpenSpace/ext/launcher/src/profile/actiondialog.cpp index 2edd32ed2a..8dbdf4471e 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/actiondialog.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/actiondialog.cpp @@ -306,11 +306,30 @@ void ActionDialog::createKeyboardWidgets(QGridLayout* layout) { _keybindingWidgets.key = new QComboBox; QStringList keyList; for (const KeyInfo& ki : KeyInfos) { + // We don't want to use the Shift, Alt, and Ctrl keys directly since we already + // have them as modifier keys + if (ki.key == Key::LeftShift || ki.key == Key::RightShift || + ki.key == Key::LeftAlt || ki.key == Key::RightAlt || + ki.key == Key::LeftControl || ki.key == Key::RightControl || + ki.key == Key::LeftSuper || ki.key == Key::RightSuper || + ki.key == Key::Menu || ki.key == Key::NumLock || + ki.key == Key::World1 || ki.key == Key::World2) + { + continue; + } keyList += QString::fromStdString(std::string(ki.name)); } _keybindingWidgets.key->addItems(keyList); _keybindingWidgets.key->setCurrentIndex(-1); _keybindingWidgets.key->setEnabled(false); + connect( + _keybindingWidgets.key, QOverload::of(&QComboBox::currentIndexChanged), + [this](int newIndex) { + _keybindingWidgets.saveButtons->button(QDialogButtonBox::Save)->setEnabled( + newIndex > 0 + ); + } + ); layout->addWidget(_keybindingWidgets.key, 11, 2); layout->addWidget(new QLabel("Action chooser"), 12, 1); @@ -632,7 +651,9 @@ void ActionDialog::keybindingSelected() { std::string key = ghoul::to_string(keybinding->key.key); _keybindingWidgets.key->setCurrentText(QString::fromStdString(key)); _keybindingWidgets.key->setEnabled(true); - _keybindingWidgets.action->setCurrentText(QString::fromStdString(keybinding->action)); + _keybindingWidgets.action->setCurrentText( + QString::fromStdString(keybinding->action) + ); _keybindingWidgets.action->setEnabled(true); _keybindingWidgets.actionText->setText( QString::fromStdString(keybinding->action) @@ -640,7 +661,13 @@ void ActionDialog::keybindingSelected() { _keybindingWidgets.actionText->setEnabled(true); _keybindingWidgets.addButton->setEnabled(false); _keybindingWidgets.removeButton->setEnabled(true); + _keybindingWidgets.saveButtons->setEnabled(true); + // Only enable the save buttons if a key is selected, otherwise we would get an + // exception as the None key cannot be bound + _keybindingWidgets.saveButtons->button(QDialogButtonBox::Save)->setEnabled( + _keybindingWidgets.key->currentIndex() > 0 + ); } else { // No keybinding selected @@ -656,7 +683,7 @@ void ActionDialog::keybindingActionSelected(int) { void ActionDialog::keybindingSaved() { Profile::Keybinding* keybinding = selectedKeybinding(); - ghoul_assert(keybinding, "There must be a selected action at this point"); + ghoul_assert(keybinding, "There must be a selected keybinding at this point"); KeyModifier km = KeyModifier::None; if (_keybindingWidgets.shiftModifier->isChecked()) { diff --git a/apps/OpenSpace/ext/launcher/src/profile/assettreemodel.cpp b/apps/OpenSpace/ext/launcher/src/profile/assettreemodel.cpp index 53521995f6..e588b103bd 100644 --- a/apps/OpenSpace/ext/launcher/src/profile/assettreemodel.cpp +++ b/apps/OpenSpace/ext/launcher/src/profile/assettreemodel.cpp @@ -149,9 +149,6 @@ void AssetTreeModel::importModelData(const std::string& assetBasePath, const std::string& userAssetBasePath) { FileSystemAccess assets( ".asset", - // @TODO (abock, 2021-03-24) We need some better solution for this; what is the - // problem of just including all subfolders instead? - { "scene", "global", "customization", "dashboard", "examples", "util" }, true, true ); diff --git a/apps/OpenSpace/ext/sgct b/apps/OpenSpace/ext/sgct index a7b225f605..d89724510f 160000 --- a/apps/OpenSpace/ext/sgct +++ b/apps/OpenSpace/ext/sgct @@ -1 +1 @@ -Subproject commit a7b225f605efe02eeb98ee485c1c71cdb12e31fa +Subproject commit d89724510f70a5b19dd93f481e4fb6493e67721c diff --git a/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/hydra.asset b/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/hydra.asset index 30bcb528b6..a7f991c8cc 100644 --- a/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/hydra.asset +++ b/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/hydra.asset @@ -21,7 +21,7 @@ local Hydra = { SegmentsPerPatch = 64, Layers = {} }, - Tag = { "moon_solarSystem", "moon_dwarf", "moon_pluto" }, + Tag = { "moon_solarSystem", "moon_dwarf", "moon_pluto", "moon_minor" }, GUI = { Path = "/Solar System/Dwarf Planets/Pluto" } diff --git a/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/kerberos.asset b/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/kerberos.asset index 8d394e60c4..2cf71c1de2 100644 --- a/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/kerberos.asset +++ b/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/kerberos.asset @@ -20,7 +20,7 @@ local Kerberos = { SegmentsPerPatch = 64, Layers = {} }, - Tag = { "moon_solarSystem", "moon_dwarf", "moon_pluto" }, + Tag = { "moon_solarSystem", "moon_dwarf", "moon_pluto", "moon_minor" }, GUI = { Path = "/Solar System/Dwarf Planets/Pluto" } diff --git a/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/nix.asset b/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/nix.asset index 4503fe1893..0c057482d2 100644 --- a/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/nix.asset +++ b/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/nix.asset @@ -20,7 +20,7 @@ local Nix = { SegmentsPerPatch = 64, Layers = {} }, - Tag = { "moon_solarSystem", "moon_dwarf", "moon_pluto" }, + Tag = { "moon_solarSystem", "moon_dwarf", "moon_pluto", "moon_minor" }, GUI = { Path = "/Solar System/Dwarf Planets/Pluto" } diff --git a/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/styx.asset b/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/styx.asset index 071839e0e4..ba9195d562 100644 --- a/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/styx.asset +++ b/data/assets/scene/solarsystem/dwarf_planets/pluto/minor/styx.asset @@ -19,7 +19,7 @@ local Styx = { SegmentsPerPatch = 64, Layers = {} }, - Tag = { "moon_solarSystem", "moon_dwarf", "moon_pluto" }, + Tag = { "moon_solarSystem", "moon_dwarf", "moon_pluto", "moon_minor" }, GUI = { Path = "/Solar System/Dwarf Planets/Pluto" } diff --git a/data/assets/scene/solarsystem/planets/jupiter/minor/ananke_group.asset b/data/assets/scene/solarsystem/planets/jupiter/minor/ananke_group.asset index b9cfabaede..d26e384b3e 100644 --- a/data/assets/scene/solarsystem/planets/jupiter/minor/ananke_group.asset +++ b/data/assets/scene/solarsystem/planets/jupiter/minor/ananke_group.asset @@ -7,7 +7,7 @@ local kernel = asset.require('../kernels').jup341 local parentIdentifier = transforms.JupiterBarycenter.Identifier local parentSpice = "JUPITER BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_jupiter", "moon_ananke"} +local tags = { "moon_solarSystem", "moon_giants", "moon_jupiter", "moon_ananke", "moon_minor" } local trailColor = { 0.4, 0.3, 0.01 } local trailTags = { "moonTrail_solarSystem", diff --git a/data/assets/scene/solarsystem/planets/jupiter/minor/carme_group.asset b/data/assets/scene/solarsystem/planets/jupiter/minor/carme_group.asset index e6b56d1db4..32f0c3b067 100644 --- a/data/assets/scene/solarsystem/planets/jupiter/minor/carme_group.asset +++ b/data/assets/scene/solarsystem/planets/jupiter/minor/carme_group.asset @@ -7,7 +7,7 @@ local kernel = asset.require('../kernels').jup341 local parentIdentifier = transforms.JupiterBarycenter.Identifier local parentSpice = "JUPITER BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_jupiter", "moon_carme" } +local tags = { "moon_solarSystem", "moon_giants", "moon_jupiter", "moon_carme", "moon_minor" } local trailColor = { 0.4, 0.3, 0.01 } local trailTags = { "moonTrail_solarSystem", diff --git a/data/assets/scene/solarsystem/planets/jupiter/minor/carpo_group.asset b/data/assets/scene/solarsystem/planets/jupiter/minor/carpo_group.asset index 7fcb8e9cdc..0731ce60ba 100644 --- a/data/assets/scene/solarsystem/planets/jupiter/minor/carpo_group.asset +++ b/data/assets/scene/solarsystem/planets/jupiter/minor/carpo_group.asset @@ -7,7 +7,7 @@ local kernel = asset.require('../kernels').jup341 local parentIdentifier = transforms.JupiterBarycenter.Identifier local parentSpice = "JUPITER BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_jupiter", "moon_carpo" } +local tags = { "moon_solarSystem", "moon_giants", "moon_jupiter", "moon_carpo", "moon_minor" } local trailColor = { 0.4, 0.3, 0.01 } local trailTags = { "moonTrail_solarSystem", diff --git a/data/assets/scene/solarsystem/planets/jupiter/minor/himalia_group.asset b/data/assets/scene/solarsystem/planets/jupiter/minor/himalia_group.asset index fa9117c43c..2b0619989c 100644 --- a/data/assets/scene/solarsystem/planets/jupiter/minor/himalia_group.asset +++ b/data/assets/scene/solarsystem/planets/jupiter/minor/himalia_group.asset @@ -7,7 +7,7 @@ local kernel = asset.require('../kernels').jup341 local parentIdentifier = transforms.JupiterBarycenter.Identifier local parentSpice = "JUPITER BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_jupiter", "moon_himalia" } +local tags = { "moon_solarSystem", "moon_giants", "moon_jupiter", "moon_himalia", "moon_minor" } local trailColor = { 0.4, 0.3, 0.01 } local trailTags = { "moonTrail_solarSystem", diff --git a/data/assets/scene/solarsystem/planets/jupiter/minor/inner_group.asset b/data/assets/scene/solarsystem/planets/jupiter/minor/inner_group.asset index 63a0ae8d98..34f81084ae 100644 --- a/data/assets/scene/solarsystem/planets/jupiter/minor/inner_group.asset +++ b/data/assets/scene/solarsystem/planets/jupiter/minor/inner_group.asset @@ -7,7 +7,7 @@ local kernel = asset.require('../kernels').jup341 local parentIdentifier = transforms.JupiterBarycenter.Identifier local parentSpice = "JUPITER BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_jupiter", "moon_inner" } +local tags = { "moon_solarSystem", "moon_giants", "moon_jupiter", "moon_inner", "moon_minor" } local trailColor = { 0.4, 0.3, 0.01 } local trailTags = { "moonTrail_solarSystem", diff --git a/data/assets/scene/solarsystem/planets/jupiter/minor/other_groups.asset b/data/assets/scene/solarsystem/planets/jupiter/minor/other_groups.asset index 644d959083..c72a04d69f 100644 --- a/data/assets/scene/solarsystem/planets/jupiter/minor/other_groups.asset +++ b/data/assets/scene/solarsystem/planets/jupiter/minor/other_groups.asset @@ -7,7 +7,7 @@ local kernel = asset.require('../kernels').jup341 local parentIdentifier = transforms.JupiterBarycenter.Identifier local parentSpice = "JUPITER BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_jupiter", "moon_other" } +local tags = { "moon_solarSystem", "moon_giants", "moon_jupiter", "moon_other", "moon_minor" } local trailColor = { 0.4, 0.3, 0.01 } local trailTags = { "moonTrail_solarSystem", diff --git a/data/assets/scene/solarsystem/planets/jupiter/minor/pasiphae_group.asset b/data/assets/scene/solarsystem/planets/jupiter/minor/pasiphae_group.asset index 4576f4e782..8268262874 100644 --- a/data/assets/scene/solarsystem/planets/jupiter/minor/pasiphae_group.asset +++ b/data/assets/scene/solarsystem/planets/jupiter/minor/pasiphae_group.asset @@ -7,7 +7,7 @@ local kernel = asset.require('../kernels').jup341 local parentIdentifier = transforms.JupiterBarycenter.Identifier local parentSpice = "JUPITER BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_jupiter", "moon_pasiphae" } +local tags = { "moon_solarSystem", "moon_giants", "moon_jupiter", "moon_pasiphae", "moon_minor" } local trailColor = { 0.4, 0.3, 0.01 } local trailTags = { "moonTrail_solarSystem", diff --git a/data/assets/scene/solarsystem/planets/jupiter/minor/themisto_group.asset b/data/assets/scene/solarsystem/planets/jupiter/minor/themisto_group.asset index 0a2299e611..343eb2c432 100644 --- a/data/assets/scene/solarsystem/planets/jupiter/minor/themisto_group.asset +++ b/data/assets/scene/solarsystem/planets/jupiter/minor/themisto_group.asset @@ -7,7 +7,7 @@ local kernel = asset.require('../kernels').jup341 local parentIdentifier = transforms.JupiterBarycenter.Identifier local parentSpice = "JUPITER BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_jupiter", "moon_themisto" } +local tags = { "moon_solarSystem", "moon_giants", "moon_jupiter", "moon_themisto", "moon_minor" } local trailColor = { 0.4, 0.3, 0.01 } local trailTags = { "moonTrail_solarSystem", diff --git a/data/assets/scene/solarsystem/planets/neptune/inner_moons.asset b/data/assets/scene/solarsystem/planets/neptune/inner_moons.asset index 3a6dddaba4..dc8e85f381 100644 --- a/data/assets/scene/solarsystem/planets/neptune/inner_moons.asset +++ b/data/assets/scene/solarsystem/planets/neptune/inner_moons.asset @@ -10,7 +10,7 @@ local kernel088 = kernels.nep088 local parentIdentifier = transforms.NeptuneBarycenter.Identifier local parentSpice = "NEPTUNE BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_neptune", "moon_inner" } +local tags = { "moon_solarSystem", "moon_giants", "moon_neptune", "moon_inner", "moon_minor" } local trailColor = { 0.2, 0.5, 0.75 } local trailTags = { "moonTrail_solarSystem", diff --git a/data/assets/scene/solarsystem/planets/neptune/irregular_prograde_moons.asset b/data/assets/scene/solarsystem/planets/neptune/irregular_prograde_moons.asset index 810434bbc0..efb2834b56 100644 --- a/data/assets/scene/solarsystem/planets/neptune/irregular_prograde_moons.asset +++ b/data/assets/scene/solarsystem/planets/neptune/irregular_prograde_moons.asset @@ -10,7 +10,7 @@ local kernel088 = kernels.nep088 local parentIdentifier = transforms.NeptuneBarycenter.Identifier local parentSpice = "NEPTUNE BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_neptune", "moon_irregular_prograde" } +local tags = { "moon_solarSystem", "moon_giants", "moon_neptune", "moon_irregular_prograde", "moon_minor" } local trailColor = { 0.2, 0.5, 0.75 } local trailTags = { "moonTrail_solarSystem", diff --git a/data/assets/scene/solarsystem/planets/neptune/irregular_retrograde_moons.asset b/data/assets/scene/solarsystem/planets/neptune/irregular_retrograde_moons.asset index badb4eb266..38d9472ffa 100644 --- a/data/assets/scene/solarsystem/planets/neptune/irregular_retrograde_moons.asset +++ b/data/assets/scene/solarsystem/planets/neptune/irregular_retrograde_moons.asset @@ -9,7 +9,7 @@ local kernel086 = kernels.nep086 local parentIdentifier = transforms.NeptuneBarycenter.Identifier local parentSpice = "NEPTUNE BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_neptune", "moon_irregular_retrograde" } +local tags = { "moon_solarSystem", "moon_giants", "moon_neptune", "moon_irregular_retrograde", "moon_minor" } local trailColor = { 0.2, 0.5, 0.75 } local trailTags = { "moonTrail_solarSystem", diff --git a/data/assets/scene/solarsystem/planets/saturn/minor/gallic_group.asset b/data/assets/scene/solarsystem/planets/saturn/minor/gallic_group.asset index a08b0fc03e..f67d555de2 100644 --- a/data/assets/scene/solarsystem/planets/saturn/minor/gallic_group.asset +++ b/data/assets/scene/solarsystem/planets/saturn/minor/gallic_group.asset @@ -7,7 +7,7 @@ local kernel = asset.require('../kernels').sat368 local parentIdentifier = transforms.SaturnBarycenter.Identifier local parentSpice = "SATURN BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_saturn", "moon_gallic" } +local tags = { "moon_solarSystem", "moon_giants", "moon_saturn", "moon_gallic", "moon_minor" } local trailColor = { 0.5, 0.3, 0.3 } local trailTags = { "moonTrail_solarSystem", diff --git a/data/assets/scene/solarsystem/planets/saturn/minor/inuit_group.asset b/data/assets/scene/solarsystem/planets/saturn/minor/inuit_group.asset index 9fd0637b38..ecdf1b457a 100644 --- a/data/assets/scene/solarsystem/planets/saturn/minor/inuit_group.asset +++ b/data/assets/scene/solarsystem/planets/saturn/minor/inuit_group.asset @@ -7,7 +7,7 @@ local kernel = asset.require('../kernels').sat368 local parentIdentifier = transforms.SaturnBarycenter.Identifier local parentSpice = "SATURN BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_saturn", "moon_inuit" } +local tags = { "moon_solarSystem", "moon_giants", "moon_saturn", "moon_inuit", "moon_minor" } local trailColor = { 0.5, 0.3, 0.3 } local trailTags = { "moonTrail_solarSystem", diff --git a/data/assets/scene/solarsystem/planets/saturn/minor/norse_group.asset b/data/assets/scene/solarsystem/planets/saturn/minor/norse_group.asset index 4cad89e12f..4eb04bb6cc 100644 --- a/data/assets/scene/solarsystem/planets/saturn/minor/norse_group.asset +++ b/data/assets/scene/solarsystem/planets/saturn/minor/norse_group.asset @@ -9,7 +9,7 @@ local kernel375 = kernels.sat375 local parentIdentifier = transforms.SaturnBarycenter.Identifier local parentSpice = "SATURN BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_saturn", "moon_norse" } +local tags = { "moon_solarSystem", "moon_giants", "moon_saturn", "moon_norse", "moon_minor" } local trailColor = { 0.5, 0.3, 0.3 } local trailTags = { "moonTrail_solarSystem", diff --git a/data/assets/scene/solarsystem/planets/saturn/minor/other_group.asset b/data/assets/scene/solarsystem/planets/saturn/minor/other_group.asset index 6ceaa4a9d1..1f7654e236 100644 --- a/data/assets/scene/solarsystem/planets/saturn/minor/other_group.asset +++ b/data/assets/scene/solarsystem/planets/saturn/minor/other_group.asset @@ -9,7 +9,7 @@ local kernel393 = kernels.sat393 local parentIdentifier = transforms.SaturnBarycenter.Identifier local parentSpice = "SATURN BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_saturn", "moon_other" } +local tags = { "moon_solarSystem", "moon_giants", "moon_saturn", "moon_other", "moon_minor" } local trailColor = { 0.5, 0.3, 0.3 } local trailTags = { "moonTrail_solarSystem", diff --git a/data/assets/scene/solarsystem/planets/uranus/inner_moons.asset b/data/assets/scene/solarsystem/planets/uranus/inner_moons.asset index 662fde8b7b..54ff39f0cb 100644 --- a/data/assets/scene/solarsystem/planets/uranus/inner_moons.asset +++ b/data/assets/scene/solarsystem/planets/uranus/inner_moons.asset @@ -7,7 +7,7 @@ local kernel = asset.require('./kernels').ura091 local parentIdentifier = transforms.UranusBarycenter.Identifier local parentSpice = "URANUS BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_uranus", "moon_inner" } +local tags = { "moon_solarSystem", "moon_giants", "moon_uranus", "moon_inner", "moon_minor" } local trailColor = { 0.60, 0.65, 0.84 } local trailTags = { diff --git a/data/assets/scene/solarsystem/planets/uranus/irregular_prograde_moons.asset b/data/assets/scene/solarsystem/planets/uranus/irregular_prograde_moons.asset index a1d36a6a3f..97b359c59a 100644 --- a/data/assets/scene/solarsystem/planets/uranus/irregular_prograde_moons.asset +++ b/data/assets/scene/solarsystem/planets/uranus/irregular_prograde_moons.asset @@ -7,7 +7,7 @@ local kernel = asset.require('./kernels').ura112 local parentIdentifier = transforms.UranusBarycenter.Identifier local parentSpice = "URANUS BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_uranus", "moon_irregular_prograde" } +local tags = { "moon_solarSystem", "moon_giants", "moon_uranus", "moon_irregular_prograde", "moon_minor" } local trailColor = { 0.60, 0.65, 0.84 } local trailTags = { "moonTrail_solarSystem", diff --git a/data/assets/scene/solarsystem/planets/uranus/irregular_retrograde_moons.asset b/data/assets/scene/solarsystem/planets/uranus/irregular_retrograde_moons.asset index 11545d7f2d..c0d7b8efd9 100644 --- a/data/assets/scene/solarsystem/planets/uranus/irregular_retrograde_moons.asset +++ b/data/assets/scene/solarsystem/planets/uranus/irregular_retrograde_moons.asset @@ -7,7 +7,7 @@ local kernel = asset.require('./kernels').ura112 local parentIdentifier = transforms.UranusBarycenter.Identifier local parentSpice = "URANUS BARYCENTER" -local tags = { "moon_solarSystem", "moon_giants", "moon_uranus", "moon_irregular_retrograde" } +local tags = { "moon_solarSystem", "moon_giants", "moon_uranus", "moon_irregular_retrograde", "moon_minor" } local trailColor = { 0.60, 0.65, 0.84 } local trailTags = { "moonTrail_solarSystem", diff --git a/include/openspace/engine/configuration.h b/include/openspace/engine/configuration.h index f20b2d8900..9748891b38 100644 --- a/include/openspace/engine/configuration.h +++ b/include/openspace/engine/configuration.h @@ -131,7 +131,6 @@ struct Configuration { HTTPProxy httpProxy; // Values not read from the openspace.cfg file - bool usingProfile = false; std::string sgctConfigNameInitialized; static documentation::Documentation Documentation; diff --git a/include/openspace/engine/openspaceengine.h b/include/openspace/engine/openspaceengine.h index f06b61f356..aaadc9cd18 100644 --- a/include/openspace/engine/openspaceengine.h +++ b/include/openspace/engine/openspaceengine.h @@ -26,6 +26,7 @@ #define __OPENSPACE_CORE___OPENSPACEENGINE___H__ #include +#include #include #include #include @@ -108,7 +109,7 @@ public: static scripting::LuaLibrary luaLibrary(); private: - void loadSingleAsset(const std::string& assetPath); + void loadAsset(const std::string& assetName); void loadFonts(); void runGlobalCustomizationScripts(); @@ -136,9 +137,57 @@ private: // The first frame might take some more time in the update loop, so we need to know to // disable the synchronization; otherwise a hardware sync will kill us after 1 minute - bool _isFirstRenderingFirstFrame = true; + bool _isRenderingFirstFrame = true; }; +/** + * Sets the camera position using the time contents of a profile. The function will + * set an absolute position or a go-to-geolocation command using the globebrowsing + * module. + * \param p The Profile to be read. + */ +void setCameraFromProfile(const Profile& p); + +/** + * Reads a list of modules from a profile, and executes scripts based on whether or + * not the corresponding module is loaded. + * + * \param p The Profile to be read. + */ +void setModulesFromProfile(const Profile& p); + +/** + * Registers actions from the contents of a profile. + * + * \param p The Profile to be read. + */ +void setActionsFromProfile(const Profile& p); + +/** + * Registers keybindings from the contents of a profile. + * + * \param p The Profile to be read. + */ +void setKeybindingsFromProfile(const Profile& p); + +/** + * Reads list of nodes from profile to be marked as interesting nodes. + * If any nodes are listed, a script to mark these will be queued with the + * script engine. + * + * \param p The Profile to be read. + */ +void setMarkInterestingNodesFromProfile(const Profile& p); + +/** + * Reads list of "additional scripts" that are added to the profile to be run + * at the end of the initialization. Any openspace lua commands are allowed, + * and will be added to the script queue. + * + * \param p The Profile to be read. + */ +void setAdditionalScriptsFromProfile(const Profile& p); + } // namespace openspace // Lua functions - exposed for testing diff --git a/include/openspace/interaction/actionmanager.h b/include/openspace/interaction/actionmanager.h index b140fe1bd4..79a07aa77c 100644 --- a/include/openspace/interaction/actionmanager.h +++ b/include/openspace/interaction/actionmanager.h @@ -43,7 +43,6 @@ public: void triggerAction(const std::string& identifier, const ghoul::Dictionary& arguments) const; - static scripting::LuaLibrary luaLibrary(); private: diff --git a/include/openspace/interaction/sessionrecording.h b/include/openspace/interaction/sessionrecording.h index bf3c1da067..c04a13ece1 100644 --- a/include/openspace/interaction/sessionrecording.h +++ b/include/openspace/interaction/sessionrecording.h @@ -832,16 +832,16 @@ public: ~SessionRecording_legacy_0085() {} char FileHeaderVersion[FileHeaderVersionLength+1] = "00.85"; char TargetConvertVersion[FileHeaderVersionLength+1] = "01.00"; - std::string fileFormatVersion() { + std::string fileFormatVersion() override { return std::string(FileHeaderVersion); } - std::string targetFileFormatVersion() { + std::string targetFileFormatVersion() override { return std::string(TargetConvertVersion); } - std::string getLegacyConversionResult(std::string filename, int depth); + std::string getLegacyConversionResult(std::string filename, int depth) override; struct ScriptMessage_legacy_0085 : public datamessagestructures::ScriptMessage { - void read(std::istream* in) { + void read(std::istream* in) override { size_t strLen; //Read string length from file in->read(reinterpret_cast(&strLen), sizeof(strLen)); @@ -860,7 +860,7 @@ public: protected: bool convertScript(std::stringstream& inStream, DataMode mode, int lineNum, - std::string& inputLine, std::ofstream& outFile, unsigned char* buffer); + std::string& inputLine, std::ofstream& outFile, unsigned char* buffer) override; }; } // namespace openspace diff --git a/include/openspace/navigation/navigationhandler.h b/include/openspace/navigation/navigationhandler.h index 36d4c51cf4..b25a14dfe5 100644 --- a/include/openspace/navigation/navigationhandler.h +++ b/include/openspace/navigation/navigationhandler.h @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include diff --git a/include/openspace/network/messagestructures.h b/include/openspace/network/messagestructures.h index effe727cbe..f7b0d78fab 100644 --- a/include/openspace/network/messagestructures.h +++ b/include/openspace/network/messagestructures.h @@ -196,7 +196,9 @@ struct CameraKeyframe { << std::fixed << std::setprecision(7) << _rotation.y << ' ' << std::fixed << std::setprecision(7) << _rotation.z << ' ' << std::fixed << std::setprecision(7) << _rotation.w << ' '; - out << std::scientific << _scale << ' '; + out << std::fixed + << std::setprecision(std::numeric_limits::max_digits10) + << _scale << ' '; if (_followNodeRotation) { out << "F "; } diff --git a/include/openspace/scene/profile.h b/include/openspace/scene/profile.h index 0969c2e4f2..eeb79b8adf 100644 --- a/include/openspace/scene/profile.h +++ b/include/openspace/scene/profile.h @@ -76,10 +76,9 @@ public: SetPropertyValueSingle }; - SetType setType; + SetType setType = SetType::SetPropertyValue; std::string name; std::string value; - }; struct Action { std::string identifier; @@ -166,19 +165,6 @@ public: static scripting::LuaLibrary luaLibrary(); }; -/** - * This function takes a profile and returns its asset-ifyied version as a string. This - * is the format that is saved as a scene file that, in turn, is provided to OpenSpace as - * the root asset to load. This function is a key step to be able to load a Profile in - * OpenSpace (at the moment). - * - * \param profile The profile that should be converted to the asset-file format - * - * \return The string representation of the provided profile, ready to be loaded as an - * asset - */ -std::string convertToScene(const Profile& profile); - } // namespace openspace #endif // __OPENSPACE_CORE___PROFILE___H__ diff --git a/include/openspace/scene/scene.h b/include/openspace/scene/scene.h index f1a03be8e5..e199f1f425 100644 --- a/include/openspace/scene/scene.h +++ b/include/openspace/scene/scene.h @@ -27,7 +27,9 @@ #include +#include #include +#include #include #include #include @@ -233,6 +235,16 @@ public: */ static scripting::LuaLibrary luaLibrary(); + /** + * Sets a property using the 'properties' contents of a profile. The function will + * loop through each setProperty command. A property may be set to a bool, float, + * or string value (which must be converted because a Profile stores all values + * as strings) + * + * \param p The Profile to be read. + */ + void setPropertiesFromProfile(const Profile& p); + private: /** * Update dependencies. @@ -267,6 +279,16 @@ private: ghoul::MemoryPool<4096> _memoryPool; }; +/** + * Accepts string version of a property value from a profile, converts it to the + * appropriate type, and then pushes the value onto the lua state. + * + * \param L the lua state to push value to + * \param value string representation of the value with which to set property + */ +void propertyPushValueFromProfileToLuaState(ghoul::lua::LuaState& L, + const std::string& value); + } // namespace openspace #endif // __OPENSPACE_CORE___SCENE___H__ diff --git a/include/openspace/util/time.h b/include/openspace/util/time.h index b09bae84e6..7b19cb26ba 100644 --- a/include/openspace/util/time.h +++ b/include/openspace/util/time.h @@ -141,6 +141,20 @@ public: */ double advanceTime(double tickTime); + /** + * Sets a relative time from profile. + * \param setTime a string containing time adjustment as described in documentation + * for luascriptfunctions::time_advancedTime + */ + void setTimeRelativeFromProfile(const std::string& setTime); + + /** + * Sets an absolute time from profile. + * \param setTime a string containing time to set, which must be a valid + * ISO 8601-like date string of the format YYYY-MM-DDTHH:MN:SS + */ + void setTimeAbsoluteFromProfile(const std::string& setTime); + /** * Returns the Lua library that contains all Lua functions available to change the * current time, retrieve the current time etc. diff --git a/include/openspace/util/timemanager.h b/include/openspace/util/timemanager.h index 5914841073..87b80f3b80 100644 --- a/include/openspace/util/timemanager.h +++ b/include/openspace/util/timemanager.h @@ -25,8 +25,11 @@ #ifndef __OPENSPACE_CORE___TIMEMANAGER___H__ #define __OPENSPACE_CORE___TIMEMANAGER___H__ +#include +#include #include #include +#include "openspace/scene/profile.h" #include #include #include @@ -75,6 +78,15 @@ public: * Returns the current delta time, as affected by pause */ double deltaTime() const; + + /** + * Sets the simulation time using the time contents of a profile. The function will + * set either a relative or absolute time. + * + * \param p The Profile to be read. + */ + void setTimeFromProfile(const Profile& p); + bool isPaused() const; std::vector deltaTimeSteps() const; diff --git a/modules/base/rendering/renderableplaneimageonline.cpp b/modules/base/rendering/renderableplaneimageonline.cpp index 998790b581..d0179e9d79 100644 --- a/modules/base/rendering/renderableplaneimageonline.cpp +++ b/modules/base/rendering/renderableplaneimageonline.cpp @@ -95,7 +95,9 @@ void RenderablePlaneImageOnline::bindTexture() { } } -void RenderablePlaneImageOnline::update(const UpdateData&) { +void RenderablePlaneImageOnline::update(const UpdateData& data) { + RenderablePlane::update(data); + if (!_textureIsDirty) { return; } diff --git a/scripts/drag_drop_handler.lua b/scripts/drag_drop_handler.lua index 65ad51302f..36c2bd25ce 100644 --- a/scripts/drag_drop_handler.lua +++ b/scripts/drag_drop_handler.lua @@ -42,5 +42,5 @@ elseif extension == ".asset" then return [[openspace.printInfo("Adding asset: ']] .. filename .. [[' (drag-and-drop)"); openspace.asset.add("]] .. filename .. [[");]] .. ReloadUIScript elseif extension == ".osrec" or extension == ".osrectxt" then - return [[openspace.sessionRecording.startPlayback("]] .. basename .. [[")]] + return [[openspace.sessionRecording.startPlayback("]] .. filename .. [[")]] end diff --git a/src/engine/moduleengine.cpp b/src/engine/moduleengine.cpp index e2e8836265..235003d400 100644 --- a/src/engine/moduleengine.cpp +++ b/src/engine/moduleengine.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/src/engine/openspaceengine.cpp b/src/engine/openspaceengine.cpp index c3c448394b..99c2bd7712 100644 --- a/src/engine/openspaceengine.cpp +++ b/src/engine/openspaceengine.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -95,6 +96,10 @@ #include "openspaceengine_lua.inl" namespace { + // Helper structs for the visitor pattern of the std::variant + template struct overloaded : Ts... { using Ts::operator()...; }; + template overloaded(Ts...)->overloaded; + constexpr const char* _loggerCat = "OpenSpaceEngine"; } // namespace @@ -292,7 +297,7 @@ void OpenSpaceEngine::initialize() { LDEBUG("Registering Lua libraries"); registerCoreClasses(*global::scriptEngine); - // Convert profile to scene file (if was provided in configuration file) + // Process profile file (must be provided in configuration file) if (!global::configuration->profile.empty()) { std::string inputProfilePath = absPath("${PROFILES}").string(); std::string outputScenePath = absPath("${TEMPORARY}").string(); @@ -300,8 +305,6 @@ void OpenSpaceEngine::initialize() { + ".profile"; std::string inputUserProfile = absPath("${USER_PROFILES}").string() + "/" + global::configuration->profile + ".profile"; - std::string outputAsset = outputScenePath + "/" + global::configuration->profile - + ".asset"; if (std::filesystem::is_regular_file(inputUserProfile)) { inputProfile = inputUserProfile; @@ -330,18 +333,6 @@ void OpenSpaceEngine::initialize() { std::istreambuf_iterator() ); *global::profile = Profile(content); - - // Then save the profile to a scene so that we can load it with the - // existing infrastructure - std::ofstream scene(outputAsset); - std::string sceneContent = convertToScene(*global::profile); - scene << sceneContent; - - // Set asset name to that of the profile because a new scene file will be - // created with that name, and also because the profile name will override - // an asset name if both are provided. - global::configuration->asset = outputAsset; - global::configuration->usingProfile = true; } } @@ -384,7 +375,6 @@ void OpenSpaceEngine::initialize() { } global::openSpaceEngine->_assetManager->initialize(); - scheduleLoadSingleAsset(global::configuration->asset); LTRACE("OpenSpaceEngine::initialize(end)"); } @@ -694,10 +684,10 @@ void OpenSpaceEngine::scheduleLoadSingleAsset(std::string assetPath) { _scheduledAssetPathToLoad = std::move(assetPath); } -void OpenSpaceEngine::loadSingleAsset(const std::string& assetPath) { +void OpenSpaceEngine::loadAsset(const std::string& assetName) { ZoneScoped - LTRACE("OpenSpaceEngine::loadSingleAsset(begin)"); + LTRACE("OpenSpaceEngine::loadAsset(begin)"); global::windowDelegate->setBarrier(false); global::windowDelegate->setSynchronization(false); @@ -706,9 +696,6 @@ void OpenSpaceEngine::loadSingleAsset(const std::string& assetPath) { global::windowDelegate->setBarrier(true); }; - if (assetPath.empty()) { - return; - } if (_scene) { ZoneScopedN("Reset scene") @@ -757,7 +744,12 @@ void OpenSpaceEngine::loadSingleAsset(const std::string& assetPath) { } _assetManager->removeAll(); - _assetManager->add(assetPath); + if (!assetName.empty()) { + _assetManager->add(assetName); + } + for (const std::string& a : global::profile->assets) { + _assetManager->add(a); + } _loadingScreen->setPhase(LoadingScreen::Phase::Construction); _loadingScreen->postMessage("Loading assets"); @@ -869,7 +861,7 @@ void OpenSpaceEngine::loadSingleAsset(const std::string& assetPath) { _writeDocumentationTask = std::async(&OpenSpaceEngine::writeSceneDocumentation, this); - LTRACE("OpenSpaceEngine::loadSingleAsset(end)"); + LTRACE("OpenSpaceEngine::loadAsset(end)"); } void OpenSpaceEngine::deinitialize() { @@ -1104,14 +1096,24 @@ void OpenSpaceEngine::preSynchronization() { if (_hasScheduledAssetLoading) { LINFO(fmt::format("Loading asset: {}", absPath(_scheduledAssetPathToLoad))); global::profile->ignoreUpdates = true; - loadSingleAsset(_scheduledAssetPathToLoad); + loadAsset(_scheduledAssetPathToLoad); global::profile->ignoreUpdates = false; resetPropertyChangeFlagsOfSubowners(global::rootPropertyOwner); _hasScheduledAssetLoading = false; _scheduledAssetPathToLoad.clear(); } - - if (_isFirstRenderingFirstFrame) { + else if (_isRenderingFirstFrame) { + global::profile->ignoreUpdates = true; + loadAsset(""); + global::renderEngine->scene()->setPropertiesFromProfile(*global::profile); + global::timeManager->setTimeFromProfile(*global::profile); + global::timeManager->setDeltaTimeSteps(global::profile->deltaTimes); + setActionsFromProfile(*global::profile); + setKeybindingsFromProfile(*global::profile); + setModulesFromProfile(*global::profile); + setMarkInterestingNodesFromProfile(*global::profile); + global::profile->ignoreUpdates = false; + resetPropertyChangeFlagsOfSubowners(global::rootPropertyOwner); global::windowDelegate->setSynchronization(false); } @@ -1157,6 +1159,11 @@ void OpenSpaceEngine::preSynchronization() { func(); } + + if (_isRenderingFirstFrame) { + setCameraFromProfile(*global::profile); + setAdditionalScriptsFromProfile(*global::profile); + } LTRACE("OpenSpaceEngine::preSynchronization(end)"); } @@ -1185,7 +1192,6 @@ void OpenSpaceEngine::postSynchronizationPreDraw() { _shutdown.timer -= static_cast(global::windowDelegate->averageDeltaTime()); } - const bool updated = _assetManager->update(); if (updated) { if (_writeDocumentationTask.valid()) { @@ -1299,10 +1305,10 @@ void OpenSpaceEngine::postDraw() { func(); } - if (_isFirstRenderingFirstFrame) { + if (_isRenderingFirstFrame) { global::windowDelegate->setSynchronization(true); resetPropertyChangeFlags(); - _isFirstRenderingFirstFrame = false; + _isRenderingFirstFrame = false; } global::memoryManager->PersistentMemory.housekeeping(); @@ -1546,6 +1552,143 @@ void OpenSpaceEngine::toggleShutdownMode() { } } +void setCameraFromProfile(const Profile& p) { + std::visit( + overloaded{ + [](const Profile::CameraNavState& navStateProfile) { + interaction::NavigationState nav; + nav.anchor = navStateProfile.anchor; + if (navStateProfile.aim.has_value()) { + nav.aim = navStateProfile.aim.value(); + } + if (nav.referenceFrame.empty()) { + nav.referenceFrame = "Root"; + } + nav.position = navStateProfile.position; + if (navStateProfile.up.has_value()) { + nav.up = navStateProfile.up; + } + if (navStateProfile.yaw.has_value()) { + nav.yaw = navStateProfile.yaw.value(); + } + if (navStateProfile.pitch.has_value()) { + nav.pitch = navStateProfile.pitch.value(); + } + global::navigationHandler->setNavigationStateNextFrame(nav); + }, + [](const Profile::CameraGoToGeo& geo) { + //Instead of direct calls to navigation state code, lua commands with + //globebrowsing goToGeo are used because this prevents a module + //dependency in this core code. Eventually, goToGeo will be incorporated + //in the OpenSpace core and this code will change. + std::string geoScript = fmt::format("openspace.globebrowsing.goToGeo" + "([[{}]], {}, {}", geo.anchor, geo.latitude, geo.longitude); + if (geo.altitude.has_value()) { + geoScript += fmt::format(", {}", geo.altitude.value()); + } + geoScript += ")"; + global::scriptEngine->queueScript( + geoScript, + scripting::ScriptEngine::RemoteScripting::Yes + ); + } + }, + p.camera.value() + ); +} + +void setModulesFromProfile(const Profile& p) { + for (Profile::Module mod : p.modules) { + const std::vector& m = global::moduleEngine->modules(); + const auto it = std::find_if(m.begin(), m.end(), + [&mod](const OpenSpaceModule* moduleSearch) { + return (moduleSearch->identifier() == mod.name); + }); + if (it != m.end()) { + if (mod.loadedInstruction.has_value()) { + global::scriptEngine->queueScript( + mod.loadedInstruction.value(), + scripting::ScriptEngine::RemoteScripting::Yes + ); + } + } + else { + if (mod.notLoadedInstruction.has_value()) { + global::scriptEngine->queueScript( + mod.notLoadedInstruction.value(), + scripting::ScriptEngine::RemoteScripting::Yes + ); + } + } + } +} + +void setActionsFromProfile(const Profile& p) { + for (Profile::Action a : p.actions) { + if (a.identifier.empty()) { + LERROR("Identifier must to provided to register action"); + } + if (global::actionManager->hasAction(a.identifier)) { + LERROR( + fmt::format("Action for identifier '{}' already existed & registered", + a.identifier) + ); + } + if (a.script.empty()) { + LERROR( + fmt::format("Identifier '{}' doesn't provide a Lua command to execute", + a.identifier) + ); + } + interaction::Action action; + action.identifier = a.identifier; + action.command = a.script; + action.name = a.name; + action.documentation = a.documentation; + action.guiPath = a.guiPath; + action.synchronization = interaction::Action::IsSynchronized(a.isLocal); + global::actionManager->registerAction(std::move(action)); + } +} + +void setKeybindingsFromProfile(const Profile& p) { + for (Profile::Keybinding k : p.keybindings) { + if (k.action.empty()) { + LERROR("Action must not be empty"); + } + if (!global::actionManager->hasAction(k.action)) { + LERROR(fmt::format("Action '{}' does not exist", k.action)); + } + if (k.key.key == openspace::Key::Unknown) { + LERROR( + fmt::format( + "Could not find key '{}'", + std::to_string(static_cast(k.key.key)) + ) + ); + } + global::keybindingManager->bindKey(k.key.key, k.key.modifier, k.action); + } +} + +void setMarkInterestingNodesFromProfile(const Profile& p) { + for (const std::string& nodeName : p.markNodes) { + SceneGraphNode* node = global::renderEngine->scene()->sceneGraphNode(nodeName); + if (node) { + node->addTag("GUI.Interesting"); + } + } +} + +void setAdditionalScriptsFromProfile(const Profile& p) { + for (const std::string& a : p.additionalScripts) { + global::scriptEngine->queueScript( + a, + scripting::ScriptEngine::RemoteScripting::Yes + ); + } +} + scripting::LuaLibrary OpenSpaceEngine::luaLibrary() { return { "", diff --git a/src/interaction/actionmanager.cpp b/src/interaction/actionmanager.cpp index e49c39eeb4..89a112b0d5 100644 --- a/src/interaction/actionmanager.cpp +++ b/src/interaction/actionmanager.cpp @@ -26,12 +26,17 @@ #include #include +#include #include #include #include #include "actionmanager_lua.inl" +namespace { + constexpr const char* _loggerCat = "ActionManager"; +} // namespace + namespace openspace::interaction { bool ActionManager::hasAction(const std::string& identifier) const { diff --git a/src/interaction/keybindingmanager.cpp b/src/interaction/keybindingmanager.cpp index 9532f41725..29b3418c64 100644 --- a/src/interaction/keybindingmanager.cpp +++ b/src/interaction/keybindingmanager.cpp @@ -35,6 +35,10 @@ #include "keybindingmanager_lua.inl" +namespace { + constexpr const char* _loggerCat = "KeyBindingManager"; +} // namespace + namespace openspace::interaction { KeybindingManager::KeybindingManager() diff --git a/src/interaction/sessionrecording.cpp b/src/interaction/sessionrecording.cpp index ab2501cd8a..fe390e3648 100644 --- a/src/interaction/sessionrecording.cpp +++ b/src/interaction/sessionrecording.cpp @@ -355,15 +355,15 @@ bool SessionRecording::startPlayback(std::string& filename, bool loop) { std::string absFilename; - // Run through conversion in case file is older. Does nothing if the file format - // is up-to-date - filename = convertFile(filename); if (std::filesystem::is_regular_file(filename)) { absFilename = filename; } else { absFilename = absPath("${RECORDINGS}/" + filename).string(); } + // Run through conversion in case file is older. Does nothing if the file format + // is up-to-date + absFilename = convertFile(absFilename); if (_state == SessionState::Recording) { LERROR("Unable to start playback while in session recording mode"); @@ -1777,7 +1777,6 @@ bool SessionRecording::addKeyframe(Timestamps t3stamps, void SessionRecording::moveAheadInTime() { using namespace std::chrono; - bool paused = global::timeManager->isPaused(); bool playbackPaused = (_state == SessionState::PlaybackPaused); if (playbackPaused) { _playbackPauseOffset @@ -2202,7 +2201,7 @@ void SessionRecording::readFileIntoStringStream(std::string filename, std::ifstream& inputFstream, std::stringstream& stream) { - std::filesystem::path conversionInFilename = absPath("${RECORDINGS}/" + filename); + std::filesystem::path conversionInFilename = absPath(filename); if (!std::filesystem::is_regular_file(conversionInFilename)) { throw ConversionError(fmt::format( "Cannot find the specified playback file {} to convert", conversionInFilename diff --git a/src/navigation/navigationhandler.cpp b/src/navigation/navigationhandler.cpp index fcae0c1e47..73d74d4c66 100644 --- a/src/navigation/navigationhandler.cpp +++ b/src/navigation/navigationhandler.cpp @@ -29,9 +29,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -43,6 +45,10 @@ #include namespace { + // Helper structs for the visitor pattern of the std::variant + template struct overloaded : Ts... { using Ts::operator()...; }; + template overloaded(Ts...)->overloaded; + constexpr const char* _loggerCat = "NavigationHandler"; const double Epsilon = 1E-7; diff --git a/src/navigation/path.cpp b/src/navigation/path.cpp index ecb776b0d4..8e6b03cdff 100644 --- a/src/navigation/path.cpp +++ b/src/navigation/path.cpp @@ -291,7 +291,12 @@ SceneGraphNode* findNodeNearTarget(const SceneGraphNode* node) { global::navigationHandler->pathNavigator().relevantNodes(); for (SceneGraphNode* n : relevantNodes) { - if (n->identifier() == node->identifier()) { + bool isSame = (n->identifier() == node->identifier()); + // If the nodes are in the very same position, they are probably representing + // the same object + isSame |= glm::distance(n->worldPosition(), node->worldPosition()) < Epsilon; + + if (isSame) { continue; } diff --git a/src/scene/profile.cpp b/src/scene/profile.cpp index bbb1e2e1f1..938335bcdc 100644 --- a/src/scene/profile.cpp +++ b/src/scene/profile.cpp @@ -23,6 +23,7 @@ ****************************************************************************************/ #include +#include #include #include @@ -465,7 +466,7 @@ struct Keybinding { std::string documentation; std::string name; std::string guiPath; - bool isLocal; + bool isLocal = true; std::string script; }; @@ -737,191 +738,4 @@ scripting::LuaLibrary Profile::luaLibrary() { }; } -std::string convertToScene(const Profile& p) { - ZoneScoped - - std::string output; - - if (p.meta.has_value()) { - output += "asset.meta = {\n"; - - if (p.meta->name.has_value()) { - output += fmt::format(" Name = [[{}]],\n", *p.meta->name); - } - if (p.meta->version.has_value()) { - output += fmt::format(" Version = [[{}]],\n", *p.meta->version); - } - if (p.meta->description.has_value()) { - output += fmt::format(" Description = [[{}]],\n", *p.meta->description); - } - if (p.meta->author.has_value()) { - output += fmt::format(" Author = [[{}]],\n", *p.meta->author); - } - if (p.meta->url.has_value()) { - output += fmt::format(" URL = [[{}]],\n", *p.meta->url); - } - if (p.meta->license.has_value()) { - output += fmt::format(" License = [[{}]]\n", *p.meta->license); - } - - output += "}\n\n"; - } - - // Modules - for (const Profile::Module& m : p.modules) { - output += fmt::format( - "if openspace.modules.isLoaded(\"{}\") then {} else {} end\n", - m.name, *m.loadedInstruction, *m.notLoadedInstruction - ); - } - - // Assets - for (const std::string& asset : p.assets) { - output += fmt::format("asset.require(\"{}\");\n", asset); - } - - output += "\n\nasset.onInitialize(function()\n"; - // Actions - output += " -- Actions\n"; - for (const Profile::Action& action : p.actions) { - const std::string name = action.name.empty() ? action.identifier : action.name; - output += fmt::format( - " openspace.action.registerAction({{" - "Identifier=[[{}]], Command=[[{}]], Name=[[{}]], Documentation=[[{}]], " - "GuiPath=[[{}]], IsLocal={}" - "}})\n", - action.identifier, action.script, name, action.documentation, action.guiPath, - action.isLocal ? "true" : "false" - ); - } - - // Keybindings - output += "\n -- Keybindings\n"; - for (size_t i = 0; i < p.keybindings.size(); ++i) { - const Profile::Keybinding& k = p.keybindings[i]; - const std::string key = keyToString(k.key); - output += fmt::format(" openspace.bindKey([[{}]], [[{}]])\n", key, k.action); - } - - // Time - output += "\n -- Time\n"; - switch (p.time->type) { - case Profile::Time::Type::Absolute: - output += fmt::format(" openspace.time.setTime(\"{}\")\n", p.time->value); - break; - case Profile::Time::Type::Relative: - output += " local now = openspace.time.currentWallTime();\n"; - output += fmt::format( - " local prev = openspace.time.advancedTime(now, \"{}\");\n", p.time->value - ); - output += " openspace.time.setTime(prev);\n"; - break; - default: - throw ghoul::MissingCaseException(); - } - - // Delta Times - { - output += "\n -- Delta Times\n"; - std::string times; - for (double d : p.deltaTimes) { - times += fmt::format("{}, ", d); - } - output += fmt::format(" openspace.time.setDeltaTimeSteps({{ {} }});\n", times); - } - - // Mark Nodes - { - output += "\n -- Mark Nodes\n"; - std::string nodes; - for (const std::string& n : p.markNodes) { - nodes += fmt::format("[[{}]],", n); - } - output += fmt::format(" openspace.markInterestingNodes({{ {} }});\n", nodes); - } - - // Properties - output += "\n -- Properties\n"; - for (const Profile::Property& prop : p.properties) { - switch (prop.setType) { - case Profile::Property::SetType::SetPropertyValue: - output += fmt::format( - " openspace.setPropertyValue(\"{}\", {});\n", prop.name, prop.value - ); - break; - case Profile::Property::SetType::SetPropertyValueSingle: - output += fmt::format( - " openspace.setPropertyValueSingle(\"{}\", {});\n", - prop.name, prop.value - ); - break; - default: - throw ghoul::MissingCaseException(); - } - } - - // Camera - output += "\n -- Camera\n"; - if (p.camera.has_value()) { - output += std::visit( - overloaded { - [](const Profile::CameraNavState& c) { - std::string result; - result += " openspace.navigation.setNavigationState({"; - result += fmt::format("Anchor = [[{}]], ", c.anchor); - if (c.aim.has_value()) { - result += fmt::format("Aim = [[{}]], ", *c.aim); - } - if (!c.referenceFrame.empty()) { - result += fmt::format( - "ReferenceFrame = [[{}]], ", c.referenceFrame - ); - } - result += fmt::format( - "Position = {{ {}, {}, {} }}, ", - c.position.x, c.position.y, c.position.z - ); - if (c.up.has_value()) { - result += fmt::format( - "Up = {{ {}, {}, {} }}, ", c.up->x, c.up->y, c.up->z - ); - } - if (c.yaw.has_value()) { - result += fmt::format("Yaw = {}, ", *c.yaw); - } - if (c.pitch.has_value()) { - result += fmt::format("Pitch = {} ", *c.pitch); - } - result += "})\n"; - return result; - }, - [](const Profile::CameraGoToGeo& c) { - if (c.altitude.has_value()) { - return fmt::format( - " openspace.globebrowsing.goToGeo([[{}]], {}, {}, {});\n", - c.anchor, c.latitude, c.longitude, *c.altitude - ); - } - else { - return fmt::format( - " openspace.globebrowsing.goToGeo([[{}]], {}, {});\n", - c.anchor, c.latitude, c.longitude - ); - } - } - }, - *p.camera - ); - } - - output += "\n -- Additional Scripts begin\n"; - for (const std::string& a : p.additionalScripts) { - output += fmt::format(" {}\n", a); - } - output += " -- Additional Scripts end\n"; - output += "end)\n"; - - return output; -} - } // namespace openspace diff --git a/src/scene/profile_lua.inl b/src/scene/profile_lua.inl index a66f8dc1c2..eb51290048 100644 --- a/src/scene/profile_lua.inl +++ b/src/scene/profile_lua.inl @@ -36,14 +36,6 @@ namespace openspace::luascriptfunctions { int saveSettingsToProfile(lua_State* L) { - if (!global::configuration->usingProfile) { - return ghoul::lua::luaError( - L, - "Program was not started with a profile, so cannot use this " - "save-current-settings feature" - ); - } - ghoul::lua::checkArgumentsAndThrow(L, { 0, 2 }, "lua::saveSettingsToProfile"); auto [saveFilePath, overwrite] = ghoul::lua::values, std::optional>(L); diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index 74fdc1def5..b9797c2c73 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -484,7 +485,7 @@ std::chrono::steady_clock::time_point Scene::currentTimeForInterpolation() { } void Scene::addPropertyInterpolation(properties::Property* prop, float durationSeconds, - ghoul::EasingFunction easingFunction) + ghoul::EasingFunction easingFunction) { ghoul_precondition(prop != nullptr, "prop must not be nullptr"); ghoul_precondition(durationSeconds > 0.f, "durationSeconds must be positive"); @@ -602,6 +603,52 @@ const std::vector& Scene::interestingTimes() const { return _interestingTimes; } +void Scene::setPropertiesFromProfile(const Profile& p) { + ghoul::lua::LuaState L(ghoul::lua::LuaState::IncludeStandardLibrary::Yes); + + for (const Profile::Property& prop : p.properties) { + std::string uriOrRegex = prop.name; + std::string groupName; + if (doesUriContainGroupTag(uriOrRegex, groupName)) { + // Remove group name from start of regex and replace with '*' + uriOrRegex = removeGroupNameFromUri(uriOrRegex); + } + ghoul::lua::push(L, uriOrRegex); + ghoul::lua::push(L, 0.0); + // Later functions expect the value to be at the last position on the stack + propertyPushValueFromProfileToLuaState(L, prop.value); + + applyRegularExpression( + L, + uriOrRegex, + allProperties(), + 0.0, + groupName, + ghoul::EasingFunction::Linear + ); + //Clear lua state stack + lua_settop(L, 0); + } +} + +void propertyPushValueFromProfileToLuaState(ghoul::lua::LuaState& L, + const std::string& value) +{ + if (luascriptfunctions::isBoolValue(value)) { + ghoul::lua::push(L, (value == "true") ? true : false); + } + else if (luascriptfunctions::isFloatValue(value)) { + ghoul::lua::push(L, std::stof(value)); + } + else { + std::string stringRepresentation = value; + if (value.compare("nil") != 0) { + stringRepresentation = "[[" + stringRepresentation + "]]"; + } + ghoul::lua::push(L, stringRepresentation); + } +} + scripting::LuaLibrary Scene::luaLibrary() { return { "", diff --git a/src/scene/scene_lua.inl b/src/scene/scene_lua.inl index 77a5fd803a..8248d2973d 100644 --- a/src/scene/scene_lua.inl +++ b/src/scene/scene_lua.inl @@ -26,8 +26,11 @@ #include #include #include +#include +#include #include #include +#include namespace openspace { @@ -896,4 +899,28 @@ int worldRotation(lua_State* L) { return 1; } +/** + * \ingroup LuaScripts + * isBoolValue(const std::string& s): + * Used to check if a string is a lua bool type. Returns false if not a valid bool string. + */ +bool isBoolValue(const std::string& s) { + return (s == "true" || s == "false"); +} + +/** + * \ingroup LuaScripts + * isFloatValue(const std::string& s): + * Used to check if a string is a lua float value. Returns false if not a valid float. + */ +bool isFloatValue(const std::string& s) { + try { + float converted = std::stof(s); + return true; + } + catch (...) { + return false; + } +} + } // namespace openspace::luascriptfunctions diff --git a/src/scene/scenelicensewriter.cpp b/src/scene/scenelicensewriter.cpp index ef7f4841b9..8e1f9149e3 100644 --- a/src/scene/scenelicensewriter.cpp +++ b/src/scene/scenelicensewriter.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -55,6 +56,7 @@ std::string SceneLicenseWriter::generateJson() const { global::openSpaceEngine->assetManager().rootAsset().subTreeAssets(); int metaTotal = 0; + int metaCount = 0; for (const Asset* asset : assets) { std::optional meta = asset->metaInformation(); if (!meta.has_value()) { @@ -63,7 +65,24 @@ std::string SceneLicenseWriter::generateJson() const { metaTotal++; } - int metaCount = 0; + if (global::profile->meta.has_value()) { + metaTotal++; + constexpr const char* replStr = R"("{}": "{}", )"; + constexpr const char* replStr2 = R"("{}": "{}")"; + json << "{"; + json << fmt::format(replStr, "name", escapedJson(global::profile->meta->name.value())); + json << fmt::format(replStr, "version", escapedJson(global::profile->meta->version.value())); + json << fmt::format(replStr, "description", escapedJson(global::profile->meta->description.value())); + json << fmt::format(replStr, "author", escapedJson(global::profile->meta->author.value())); + json << fmt::format(replStr, "url", escapedJson(global::profile->meta->url.value())); + json << fmt::format(replStr2, "license", escapedJson(global::profile->meta->license.value())); + json << "}"; + + if (++metaCount != metaTotal) { + json << ","; + } + } + for (const Asset* asset : assets) { std::optional meta = asset->metaInformation(); diff --git a/src/util/time.cpp b/src/util/time.cpp index 84bbe09594..2653ee2b31 100644 --- a/src/util/time.cpp +++ b/src/util/time.cpp @@ -25,6 +25,7 @@ #include #include +#include #include #include #include @@ -121,6 +122,22 @@ void Time::ISO8601(char* buffer) const { SpiceManager::ref().dateFromEphemerisTime(_time, buffer, S, Format); } +void Time::setTimeRelativeFromProfile(const std::string& setTime) { + ghoul::lua::LuaState L(ghoul::lua::LuaState::IncludeStandardLibrary::Yes); + + luascriptfunctions::time_currentWallTime(L); + ghoul::lua::push(L, setTime); + luascriptfunctions::time_advancedTime(L); + luascriptfunctions::time_setTime(L); +} + +void Time::setTimeAbsoluteFromProfile(const std::string& setTime) { + ghoul::lua::LuaState L(ghoul::lua::LuaState::IncludeStandardLibrary::Yes); + + ghoul::lua::push(L, setTime); + luascriptfunctions::time_setTime(L); +} + scripting::LuaLibrary Time::luaLibrary() { return { "time", diff --git a/src/util/timemanager.cpp b/src/util/timemanager.cpp index a6781be9e2..89f898dbd9 100644 --- a/src/util/timemanager.cpp +++ b/src/util/timemanager.cpp @@ -868,4 +868,21 @@ double TimeManager::previousApplicationTimeForInterpolation() const { return _previousApplicationTime; } +void TimeManager::setTimeFromProfile(const Profile& p) { + Time t; + + switch (p.time.value().type) { + case Profile::Time::Type::Relative: + t.setTimeRelativeFromProfile(p.time.value().value); + break; + + case Profile::Time::Type::Absolute: + t.setTimeAbsoluteFromProfile(p.time.value().value); + break; + + default: + throw ghoul::MissingCaseException(); + } +} + } // namespace openspace