diff --git a/.gitignore b/.gitignore index 9c7118d6b..f8cf29592 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ !/plugins/csp-anchor-labels !/plugins/csp-atmospheres !/plugins/csp-custom-web-ui +!/plugins/csp-guided-tour !/plugins/csp-demo-node-editor !/plugins/csp-vr-accessibility !/plugins/csp-fly-to-locations diff --git a/CMakeLists.txt b/CMakeLists.txt index f9bf43726..7d93891bf 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -279,7 +279,7 @@ if (MSVC) $<$:-external:anglebrackets> $<$:-external:W0> $<$:-W3> - $<$:-WX> + # $<$:-WX> $<$:-EHsc> $<$:-wd4251> diff --git a/config/base/scripts/hmd.bat b/config/base/scripts/hmd.bat index 8e91ce447..aeb9e4ba1 100644 --- a/config/base/scripts/hmd.bat +++ b/config/base/scripts/hmd.bat @@ -13,7 +13,7 @@ set CURRENT_DIR=%cd% cd "%SCRIPT_DIR%" rem Scene config file can be passed as first parameter. -set SETTINGS=../share/config/simple_hmd.json +set SETTINGS=../share/config/user-guided-tour_hmd.json IF NOT "%1"=="" ( SET SETTINGS=%1 SHIFT diff --git a/config/base/scripts/start.bat b/config/base/scripts/start.bat index 6f9fe052c..b40b1a949 100644 --- a/config/base/scripts/start.bat +++ b/config/base/scripts/start.bat @@ -13,7 +13,7 @@ set CURRENT_DIR=%cd% cd "%SCRIPT_DIR%" rem Scene config file can be passed as first parameter. -set SETTINGS=../share/config/simple_desktop.json +set SETTINGS=../share/config/user-guided-tour.json IF NOT "%1"=="" ( SET SETTINGS=%1 SHIFT diff --git a/config/base/vista/display.ini b/config/base/vista/display.ini index 102b5297a..fe1fdce94 100644 --- a/config/base/vista/display.ini +++ b/config/base/vista/display.ini @@ -5,6 +5,11 @@ # SPDX-FileCopyrightText: German Aerospace Center (DLR) # SPDX-License-Identifier: CC0-1.0 +#[FONTS] +# MONO_FONT = fonts/SometypeMono-Regular.ttf +# SANS_FONT = fonts/OpenSans-Regular.ttf +# SERIF_FONT = fonts/SourceSerifPro-Regular.ttf + [SYSTEM] DISPLAYSYSTEMS = MAIN WINDOWINGTOOLKIT = SDL2 diff --git a/config/base/vista/display_hmd.ini b/config/base/vista/display_hmd.ini index bef6783fc..1451391f9 100644 --- a/config/base/vista/display_hmd.ini +++ b/config/base/vista/display_hmd.ini @@ -16,7 +16,7 @@ WINDOWINGTOOLKIT = OPENVR_SDL2 NAME = MIRROR_WINDOW STEREO = false SIZE = 1280, 800 -FULLSCREEN = false +FULLSCREEN = true TITLE = CosmoScout VR VSYNC = false diff --git a/config/base/vista/interaction.ini b/config/base/vista/interaction.ini index c2812fb60..cdae1fce3 100644 --- a/config/base/vista/interaction.ini +++ b/config/base/vista/interaction.ini @@ -7,9 +7,9 @@ [SYSTEM] DRIVERPLUGINDIRS = ${VISTACORELIBS_DRIVER_PLUGIN_DIRS} -DEVICEDRIVERS = KEYBOARD, MOUSE, SPACENAVIGATOR, SDL2CONTROLLER -INTERACTIONCONTEXTS = KEYINPUT, MOUSEINPUT, MOUSEZOOM, MOUSEPAN, SPACENAVIGATION, KEYBOARDNAVIGATION, CONTROLLERNAVIGATION -DUMPDFNGRAPHS = FALSE +DEVICEDRIVERS = KEYBOARD, MOUSE, SPACENAVIGATOR, SDL2CONTROLLER, ICAROS +INTERACTIONCONTEXTS = KEYINPUT, MOUSEINPUT, MOUSEZOOM, MOUSEPAN, SPACENAVIGATION, KEYBOARDNAVIGATION, CONTROLLERNAVIGATION, ICAROSNAVIGATION +DUMPDFNGRAPHS = TRUE ###################### interaction contexts ########################### @@ -42,6 +42,11 @@ GRAPH = xml/keyboard_navigation.xml ROLE = CONTROLLERNAVIGATION GRAPH = xml/controller_navigation.xml +[ICAROSNAVIGATION] +ROLE = ICAROSNAVIGATION +GRAPH = xml/icaros_navigation.xml +RELOADTRIGGER = T + ######################## device drivers ############################### [KEYBOARD] @@ -84,3 +89,11 @@ RAWID = 0 [CONTROLLER_DB] PATH = ../share/config/vista/gamecontrollerdb.txt + +[ICAROS] +TYPE = ICAROS +HISTORY = 10 +SENSORS = ICAROS_CONTROLLER + +[ICAROS_CONTROLLER] +RAWID = 0 \ No newline at end of file diff --git a/config/base/vista/interaction_hmd.ini b/config/base/vista/interaction_hmd.ini index d443b85c9..32d789773 100644 --- a/config/base/vista/interaction_hmd.ini +++ b/config/base/vista/interaction_hmd.ini @@ -7,8 +7,8 @@ [SYSTEM] DRIVERPLUGINDIRS = ${VISTACORELIBS_DRIVER_PLUGIN_DIRS} -DEVICEDRIVERS = KEYBOARD, MOUSE, OPENVRDRIVER, SDL2CONTROLLER -INTERACTIONCONTEXTS = KEYINPUT, KEYBOARDNAVIGATION, HEADTRACKING, FLYSTICKNAVIGATION, FLYSTICKINPUT, CONTROLLERNAVIGATION +DEVICEDRIVERS = KEYBOARD, MOUSE, OPENVRDRIVER, SDL2CONTROLLER, ICAROS +INTERACTIONCONTEXTS = KEYINPUT, KEYBOARDNAVIGATION, HEADTRACKING, FLYSTICKNAVIGATION, FLYSTICKINPUT, CONTROLLERNAVIGATION, ICAROSNAVIGATION ###################### interaction contexts ########################### @@ -36,6 +36,11 @@ GRAPH = xml/openvr_standardinput.xml ROLE = CONTROLLERNAVIGATION GRAPH = xml/controller_navigation.xml +[ICAROSNAVIGATION] +ROLE = ICAROSNAVIGATION +GRAPH = xml/icaros_navigation.xml +RELOADTRIGGER = T + ######################## device drivers ############################### [KEYBOARD] @@ -83,3 +88,12 @@ RAWID = 0 [CONTROLLER_DB] PATH = ../share/config/vista/gamecontrollerdb.txt + + +[ICAROS] +TYPE = ICAROS +HISTORY = 10 +SENSORS = ICAROS_CONTROLLER + +[ICAROS_CONTROLLER] +RAWID = 0 \ No newline at end of file diff --git a/config/base/vista/xml/icaros_navigation.xml b/config/base/vista/xml/icaros_navigation.xml new file mode 100644 index 000000000..1e08aea91 --- /dev/null +++ b/config/base/vista/xml/icaros_navigation.xml @@ -0,0 +1,267 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ORIENTATION, BUTTON_1, BUTTON_2, BUTTON_3, BUTTON_4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/config/base/vista/xml/icaros_navigation_lisa.xml b/config/base/vista/xml/icaros_navigation_lisa.xml new file mode 100644 index 000000000..36045d912 --- /dev/null +++ b/config/base/vista/xml/icaros_navigation_lisa.xml @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + ORIENTATION, BUTTON_1, BUTTON_2, BUTTON_3, BUTTON_4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/config/base/vista/xml/icaros_navigation_markus.xml b/config/base/vista/xml/icaros_navigation_markus.xml new file mode 100644 index 000000000..ff1c5a0ad --- /dev/null +++ b/config/base/vista/xml/icaros_navigation_markus.xml @@ -0,0 +1,106 @@ + + + + + + + + + + + + + + + + + + ORIENTATION, BUTTON_1, BUTTON_2, BUTTON_3, BUTTON_4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/externals/vista b/externals/vista index dc6baf659..a74c90d1d 160000 --- a/externals/vista +++ b/externals/vista @@ -1 +1 @@ -Subproject commit dc6baf6594d123a78272a82d1a327dab76522d3f +Subproject commit a74c90d1d97280634619b028a66d19fb2a7591f2 diff --git a/make_externals.bat b/make_externals.bat index 5fde36433..0b83f830a 100644 --- a/make_externals.bat +++ b/make_externals.bat @@ -81,6 +81,7 @@ cmake -E make_directory "%INSTALL_DIR%/share" cmake -E make_directory "%INSTALL_DIR%/bin" cmake -E make_directory "%INSTALL_DIR%/include" + rem glew ------------------------------------------------------------------------------------------- :glew @@ -327,7 +328,9 @@ cmake %CMAKE_FLAGS% -DCMAKE_INSTALL_PREFIX="%INSTALL_DIR%" -DVISTADEMO_ENABLED=O -DVISTACORELIBS_USE_INFINITE_REVERSE_PROJECTION=On -DOPENSG_ROOT_DIR=%INSTALL_DIR%^ -DOPENVR_ROOT_DIR="%INSTALL_DIR%" -DVISTACORELIBS_USE_GLUT_WINDOWIMP=Off^ -DVISTACORELIBS_USE_SDL2_WINDOWIMP=On -DSDL2_ROOT_DIR=%INSTALL_DIR%^ + -DVISTADRIVERS_BUILD_ICAROS=On -DFTDI_ROOT_DIR=D:/icarosTreiber^ -DSDL2_TTF_ROOT_DIR=%INSTALL_DIR% -DCMAKE_UNITY_BUILD=%UNITY_BUILD%^ + -DVISTADRIVERS_BUILD_3DCSPACENAVIGATOR=On^ -DVISTA_USE_PRECOMPILED_HEADERS=%PRECOMPILED_HEADERS% "%EXTERNALS_DIR%/vista" || goto :error cmake --build . --config %BUILD_TYPE% --target install --parallel %NUMBER_OF_PROCESSORS% || goto :error diff --git a/plugins/csp-custom-web-ui/src/Plugin.cpp b/plugins/csp-custom-web-ui/src/Plugin.cpp index 6d3322296..47d4fbfdc 100644 --- a/plugins/csp-custom-web-ui/src/Plugin.cpp +++ b/plugins/csp-custom-web-ui/src/Plugin.cpp @@ -137,7 +137,7 @@ void Plugin::update() { if (object) { auto scale = mSolarSystem->getScaleBasedOnObserverDistance( object, item.mPosition, item.mScale, mAllSettings->mGraphics.pWorldUIScale.get()); - auto rotation = mSolarSystem->getRotationToObserver(object, item.mPosition, false); + auto rotation = mSolarSystem->getRotationToObserver(object, item.mPosition, true); auto transform = object->getObserverRelativeTransform(item.mPosition, rotation, scale); item.mAnchor->SetTransform(glm::value_ptr(transform), true); diff --git a/plugins/csp-guided-tour/CMakeLists.txt b/plugins/csp-guided-tour/CMakeLists.txt new file mode 100644 index 000000000..fbecc975a --- /dev/null +++ b/plugins/csp-guided-tour/CMakeLists.txt @@ -0,0 +1,47 @@ +# ------------------------------------------------------------------------------------------------ # +# This file is part of CosmoScout VR # +# ------------------------------------------------------------------------------------------------ # + +# SPDX-FileCopyrightText: German Aerospace Center (DLR) +# SPDX-License-Identifier: MIT + +option(CSP_GUIDED_TOUR "Enable compilation of this plugin" ON) + +if (NOT CSP_GUIDED_TOUR) + return() +endif() + +# build plugin ------------------------------------------------------------------------------------- + +file(GLOB SOURCE_FILES src/*.cpp) + +# Resoucre files and header files are only added in order to make them available in your IDE. +file(GLOB HEADER_FILES src/*.hpp) +file(GLOB_RECURSE RESOUCRE_FILES gui/*) + +add_library(csp-guided-tour SHARED + ${SOURCE_FILES} + ${HEADER_FILES} + ${RESOUCRE_FILES} +) + +target_link_libraries(csp-guided-tour + PUBLIC + cs-core +) + +# Add this Plugin to a "plugins" folder in your IDE. +set_property(TARGET csp-guided-tour PROPERTY FOLDER "plugins") + +# We mark all resource files as "header" in order to make sure that no one tries to compile them. +set_source_files_properties(${RESOUCRE_FILES} PROPERTIES HEADER_FILE_ONLY TRUE) + +# Make directory structure available in your IDE. +source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}" FILES + ${SOURCE_FILES} ${HEADER_FILES} ${RESOUCRE_FILES} +) + +# install plugin ----------------------------------------------------------------------------------- + +install(TARGETS csp-guided-tour DESTINATION "share/plugins") +install(DIRECTORY "gui" DESTINATION "share/resources") diff --git a/plugins/csp-guided-tour/README.md b/plugins/csp-guided-tour/README.md new file mode 100644 index 000000000..eed74de29 --- /dev/null +++ b/plugins/csp-guided-tour/README.md @@ -0,0 +1,53 @@ + + +# GUIDED TOUR for CosmoScout VR + +A CosmoScout VR plugin which allows adding custom HTML-based UI elements as sidebar-tabs, as floating windows or into free space. + +## Configuration + +This plugin can be enabled with the following configuration in your `settings.json`. +The given values are just some examples, feel free to add your own items: + +```javascript +{ + ... + "plugins": { + ... + "csp-guided-tour": { + "sidebar-items": [ + { + "name": "Spotify", + "icon": "queue_music", + "html": "" + } + ], + "space-items": [ + { + "object": "Earth", + "longitude": 14, + "latitude": 51, + "elevation": 100, + "scale": 1000, + "width": 800, + "height": 600, + "html": "" + } + ], + "window-items": [ + { + "name": "Wikipedia", + "icon": "language", + "html": "" + } + ] + }, + ... + } +} +``` + +**More in-depth information and some tutorials will be provided soon.** diff --git a/plugins/csp-guided-tour/gui/csp-guided-tour-tab.html b/plugins/csp-guided-tour/gui/csp-guided-tour-tab.html new file mode 100644 index 000000000..6a5deae04 --- /dev/null +++ b/plugins/csp-guided-tour/gui/csp-guided-tour-tab.html @@ -0,0 +1,24 @@ +
+ +
+ + + + + \ No newline at end of file diff --git a/plugins/csp-guided-tour/gui/guided-tour-controller-frontend.html b/plugins/csp-guided-tour/gui/guided-tour-controller-frontend.html new file mode 100644 index 000000000..5eb67ad1f --- /dev/null +++ b/plugins/csp-guided-tour/gui/guided-tour-controller-frontend.html @@ -0,0 +1,161 @@ + + + + + + + CosmoScout VR + + + + + + + + + +
+
+ Guided Tour +
+
+ +
+

Willkommen bei der guided Mars Tour. Mithilfe dieser Steuerungszentrale kann die Route neugestartet oder gewechselt werden.

+
+ +
+
+
+ + + +
+
+
+
+
+ + + + + + + + + diff --git a/plugins/csp-guided-tour/gui/js/csp-guided-tour.js b/plugins/csp-guided-tour/gui/js/csp-guided-tour.js new file mode 100644 index 000000000..b9d7bd2ce --- /dev/null +++ b/plugins/csp-guided-tour/gui/js/csp-guided-tour.js @@ -0,0 +1,118 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////// +// This file is part of CosmoScout VR // +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// SPDX-FileCopyrightText: German Aerospace Center (DLR) +// SPDX-License-Identifier: MIT + +(() => { + /** + * Measurement Tools + */ + class GuidedToursApi extends IApi { + /** + * @inheritDoc + */ + name = 'guidedTours'; + + /** + * TODO + * @param name {string} + */ + // eslint-disable-next-line class-methods-use-this + + add(name) { + const area = document.getElementById('tour-buttons'); + + const tourButton = CosmoScout.gui.loadTemplateContent('tour-button-template'); + tourButton.innerHTML = tourButton.innerHTML.replace(/%TOURNAME%/g, name).trim(); + + area.appendChild(tourButton); + } + onTourButtonClick(button, tourname) { + + if (button.checked) { + let buttons = document.querySelectorAll(".guided-tour-button"); + buttons.forEach(b => { + if (b != button) { + b.checked = false; + } + }) + CosmoScout.callbacks.guidedTours.loadTour(tourname); + + } + else { + CosmoScout.callbacks.guidedTours.loadTour("none"); + } + } + onTourResetButtonClick(button, tourname) { + + if (button.checked) { + let buttons = document.querySelectorAll(".guided-tour-button"); + buttons.forEach(b => { + if (b != button) { + b.checked = false; + } + }) + CosmoScout.callbacks.guidedTours.loadTour(tourname); + + } + else { + CosmoScout.callbacks.guidedTours.loadTour("none"); + } + } + resetAll() { + let buttons = document.querySelectorAll(".guided-tour-button"); + buttons.forEach(b => { + b.checked = false; + const tourStatusLabel = b.nextElementSibling.querySelector('.guided-tour-status'); + const label = tourStatusLabel.innerText.trim(); + if (label !== "") { + const [firstNumber, secondNumber] = label.split('/'); + const newFirstNumber = "0"; + const newLabel = `${newFirstNumber}/${secondNumber}`; + tourStatusLabel.innerText = newLabel; + } + }); + } + resetTour(tourName) { + let buttons = document.querySelectorAll('.guided-tour-button'); + buttons.forEach(b => { + const buttonTourName = b.nextElementSibling.querySelector('span').innerText; + if (buttonTourName === tourName) { + b.checked = false; + } + }); + + const tourButtons = document.querySelectorAll('.guided-tour-label'); + tourButtons.forEach(button => { + const tourStatusLabel = button.querySelector('.guided-tour-status'); + const label = tourStatusLabel.innerText.trim(); + if(label !== ""){ + if (tourName === button.querySelector('span').innerText) { + + const tourStatusLabel = button.querySelector('.guided-tour-status'); + const [_, secondNumber] = tourStatusLabel.innerText.split('/'); + tourStatusLabel.innerText = `0/${secondNumber}`; + } + } + }); + } + + + setProgress(tourName, cpCount, cpVisited) { + + const tourButtons = document.querySelectorAll('.guided-tour-label'); + + tourButtons.forEach(button => { + if (tourName == button.querySelector('span').innerText) { + const tourStatusLabel = button.querySelector('.guided-tour-status'); + tourStatusLabel.innerText = cpVisited + "/" + cpCount; + } + }); + + } + } + + CosmoScout.init(GuidedToursApi); +})(); diff --git a/plugins/csp-guided-tour/src/Plugin.cpp b/plugins/csp-guided-tour/src/Plugin.cpp new file mode 100644 index 000000000..0ab5ccb7c --- /dev/null +++ b/plugins/csp-guided-tour/src/Plugin.cpp @@ -0,0 +1,265 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////// +// This file is part of CosmoScout VR // +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// SPDX-FileCopyrightText: German Aerospace Center (DLR) +// SPDX-License-Identifier: MIT + +#include "Plugin.hpp" +#include "logger.hpp" + +#include "../../../src/cs-core/GraphicsEngine.hpp" +#include "../../../src/cs-core/GuiManager.hpp" +#include "../../../src/cs-core/InputManager.hpp" +#include "../../../src/cs-core/SolarSystem.hpp" +#include "../../../src/cs-core/TimeControl.hpp" +#include "../../../src/cs-utils/convert.hpp" + +#include +#include +#include +#include +#include +#include +//////////////////////////////////////////////////////////////////////////////////////////////////// + +EXPORT_FN cs::core::PluginBase* create() { + return new csp::guidedtour::Plugin; +} +//////////////////////////////////////////////////////////////////////////////////////////////////// + +EXPORT_FN void destroy(cs::core::PluginBase* pluginBase) { + delete pluginBase; +} +//////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace csp::guidedtour { + +void from_json(nlohmann::json const& j, Plugin::Settings::CheckPointSettings& o) { + cs::core::Settings::deserialize(j, "object", o.mObject); + cs::core::Settings::deserialize(j, "longitude", o.mLongitude); + cs::core::Settings::deserialize(j, "latitude", o.mLatitude); + cs::core::Settings::deserialize(j, "elevation", o.mElevation); + cs::core::Settings::deserialize(j, "scale", o.mScale); + cs::core::Settings::deserialize(j, "width", o.mWidth); + cs::core::Settings::deserialize(j, "height", o.mHeight); + cs::core::Settings::deserialize(j, "file", o.mFile); +} + +void to_json(nlohmann::json& j, Plugin::Settings::CheckPointSettings const& o) { + cs::core::Settings::serialize(j, "object", o.mObject); + cs::core::Settings::serialize(j, "longitude", o.mLongitude); + cs::core::Settings::serialize(j, "latitude", o.mLatitude); + cs::core::Settings::serialize(j, "elevation", o.mElevation); + cs::core::Settings::serialize(j, "scale", o.mScale); + cs::core::Settings::serialize(j, "width", o.mWidth); + cs::core::Settings::serialize(j, "height", o.mHeight); + cs::core::Settings::serialize(j, "file", o.mFile); +} + +// From_Json to_json hinzugeüfgt. +void from_json(nlohmann::json const& j, Plugin::Settings::TourSettings& o) { + cs::core::Settings::deserialize(j, "name", o.mName); + cs::core::Settings::deserialize(j, "planet", o.mPlanet); + cs::core::Settings::deserialize(j, "startPosition", o.mTourPositionStart); + cs::core::Settings::deserialize(j, "startRotation", o.mTourRotationStart); + cs::core::Settings::deserialize(j, "checkpoints", o.mCheckpoints); +} + +void to_json(nlohmann::json& j, Plugin::Settings::TourSettings const& o) { + cs::core::Settings::serialize(j, "name", o.mName); + cs::core::Settings::serialize(j, "planet", o.mPlanet); + cs::core::Settings::serialize(j, "startPosition", o.mTourPositionStart); + cs::core::Settings::serialize(j, "startRotation", o.mTourRotationStart); + cs::core::Settings::serialize(j, "checkpoints", o.mCheckpoints); +} + +/////////////////////////////////////////////////////////////////////From_Json to_json +/// hinzugeüfgt.// +// cs::core::Settings::serialize(j, "checkpoints", o.mCPItems); + +void from_json(nlohmann::json const& j, Plugin::Settings& o) { + cs::core::Settings::deserialize(j, "tours", o.mTours); +} + +void to_json(nlohmann::json& j, Plugin::Settings const& o) { + cs::core::Settings::serialize(j, "tours", o.mTours); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void Plugin::init() { + logger().info("Loading plugin..."); + + mOnLoadConnection = mAllSettings->onLoad().connect([this]() { onLoad(); }); + mOnSaveConnection = mAllSettings->onSave().connect([this]() { onSave(); }); + + mGuiManager->executeJavascriptFile("../share/resources/gui/js/csp-guided-tour.js"); + + mGuiManager->addPluginTabToSideBarFromHTML( + "Guided Tour", "flag", "../share/resources/gui/csp-guided-tour-tab.html"); + + mGuiManager->getGui()->registerCallback("guidedTours.resetTour", + "Call this to reset a specific tour.", + std::function([this](std::string&& tourName) { resetTour(tourName); })); + + mGuiManager->getGui()->registerCallback("guidedTours.reset", + "Call this to reset all Checkpoints of the current tour.", std::function([this] { + for (auto& tour : mPluginSettings.mTours) { + unload(mPluginSettings); + for (auto& checkpoint : tour.mCheckpoints) { + checkpoint.mIsVisited = false; + } + } + + unload(mPluginSettings); + mGuiManager->getGui()->callJavascript("CosmoScout.guidedTours.resetAll"); + })); + mGuiManager->getGui()->registerCallback("guidedTours.loadTour", + "Call this to load the specified tour.", + std::function([this](std::string&& tourName) { + mCurrentTour = tourName; + mLoadedTour = tourName; })); + + // Load initial settings. + onLoad(); + + logger().info("Loading done."); +} +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void Plugin::update() { + if (mCurrentTour != "") { + unload(mPluginSettings); // Delete Checkpoints statt unload + if (mCurrentTour != "none") { + loadCheckpoints(); + } + mCurrentTour = ""; + } + // Rotate the space items to face the observer. + for (auto& item : mCPItems) { + auto object = mSolarSystem->getObject(item.mObjectName); + + if (object) { + auto scale = mSolarSystem->getScaleBasedOnObserverDistance( + object, item.mPosition, item.mScale, mAllSettings->mGraphics.pWorldUIScale.get()); + auto rotation = mSolarSystem->getRotationToObserver(object, item.mPosition, true); + + auto transform = object->getObserverRelativeTransform(item.mPosition, rotation, scale); + item.mAnchor->SetTransform(glm::value_ptr(transform), true); + } + } +} +void Plugin::resetTour(std::string const& tourName) { + for (auto& tour : mPluginSettings.mTours) { + logger().info(mLoadedTour); + + if(tourName == mLoadedTour){ + unload(mPluginSettings); + } + if (tour.mName == tourName) { + mGuiManager->getGui()->callJavascript("CosmoScout.guidedTours.resetTour" , tourName); + for (auto& checkpoint : tour.mCheckpoints) { + checkpoint.mIsVisited = false; + } + return; + } + } +} + +void Plugin::deInit() { + onSave(); + unload(mPluginSettings); + mAllSettings->onLoad().disconnect(mOnLoadConnection); + mAllSettings->onSave().disconnect(mOnSaveConnection); + + mGuiManager->removePluginTab("Guided Tour"); +} + +void Plugin::onLoad() { + logger().info("onLoad Start"); + auto oldSettings = mPluginSettings; + from_json(mAllSettings->mPlugins.at("csp-guided-tour"), mPluginSettings); + for (auto const& tour : mPluginSettings.mTours) { + mGuiManager->getGui()->callJavascript("CosmoScout.guidedTours.add", tour.mName); + } + // + loadCheckpoints(); + logger().info("onLoad End"); +} + +void Plugin::onSave() { + mAllSettings->mPlugins["csp-guided-tour"] = mPluginSettings; +} + +void Plugin::unload(Settings const& pluginSettings) { + auto* pSG = GetVistaSystem()->GetGraphicsManager()->GetSceneGraph(); + for (auto const& item : mCPItems) { + pSG->GetRoot()->DisconnectChild(item.mAnchor.get()); + mInputManager->unregisterSelectable(item.mGuiNode.get()); + } + mCPItems.clear(); +} +void Plugin::loadCheckpoints() { + + for (auto const& tour : mPluginSettings.mTours) { + if (tour.mName == mCurrentTour) { + + mSolarSystem->flyObserverTo("Mars", "IAU_Mars" , tour.mTourPositionStart , tour.mTourRotationStart , 5.0); + + + for (auto const& settings : tour.mCheckpoints) { + + auto object = mSolarSystem->getObject(settings.mObject); + + CPItem item; + item.mObjectName = settings.mObject; + + auto* pSG = GetVistaSystem()->GetGraphicsManager()->GetSceneGraph(); + item.mAnchor.reset(pSG->NewTransformNode(pSG->GetRoot())); + item.mScale = settings.mScale; + + glm::dvec2 lngLat(settings.mLongitude, settings.mLatitude); + lngLat = cs::utils::convert::toRadians(lngLat); + auto radii = object->getRadii(); + item.mPosition = cs::utils::convert::toCartesian(lngLat, radii, settings.mElevation); + + item.mGuiArea = + std::make_unique(settings.mWidth, settings.mHeight); + item.mTransform.reset(pSG->NewTransformNode(item.mAnchor.get())); + item.mTransform->Scale(0.001F * static_cast(item.mGuiArea->getWidth()), + 0.001F * static_cast(item.mGuiArea->getHeight()), 1.F); + item.mTransform->Rotate( + VistaAxisAndAngle(VistaVector3D(0.0, 1.0, 0.0), -glm::pi() / 2.F)); + item.mGuiNode.reset(pSG->NewOpenGLNode(item.mTransform.get(), item.mGuiArea.get())); + mInputManager->registerSelectable(item.mGuiNode.get()); + VistaOpenSGMaterialTools::SetSortKeyOnSubtree( + item.mGuiNode.get(), static_cast(cs::utils::DrawOrder::eTransparentItems)); + item.mGuiItem = std::make_unique("file://" + settings.mFile); + + item.mGuiItem->registerCallback( + "setVisitedCpp", "Sets the isVisited Boolean.", std::function([&]() { + settings.mIsVisited = true; + + int cpCount = tour.mCheckpoints.size(); + int cpVisited = 0; + for (auto const& settings : tour.mCheckpoints) { + if (settings.mIsVisited) { + cpVisited++; + } + } + mGuiManager->getGui()->callJavascript( + "CosmoScout.guidedTours.setProgress", tour.mName, cpCount, cpVisited); + })); + item.mGuiArea->addItem(item.mGuiItem.get()); + item.mGuiItem->setCursorChangeCallback( + [](cs::gui::Cursor c) { cs::core::GuiManager::setCursor(c); }); + item.mGuiItem->waitForFinishedLoading(); + item.mGuiItem->callJavascript("setVisited", settings.mIsVisited); + mCPItems.emplace_back(std::move(item)); + } + } + } +} + +} // namespace csp::guidedtour \ No newline at end of file diff --git a/plugins/csp-guided-tour/src/Plugin.hpp b/plugins/csp-guided-tour/src/Plugin.hpp new file mode 100644 index 000000000..b8d4ad5e2 --- /dev/null +++ b/plugins/csp-guided-tour/src/Plugin.hpp @@ -0,0 +1,110 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////// +// This file is part of CosmoScout VR // +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// SPDX-FileCopyrightText: German Aerospace Center (DLR) +// SPDX-License-Identifier: MIT + +#ifndef CSP_GUIDED_TOUR_PLUGIN_HPP +#define CSP_GUIDED_TOUR_PLUGIN_HPP + +#include "../../../src/cs-core/PluginBase.hpp" + +#include + +#include +#include +#include +#include +#include + + +class VistaOpenGLNode; +class VistaTransformNode; + +namespace cs::gui { +class WorldSpaceGuiArea; +class GuiItem; +} // namespace cs::gui + +namespace csp::guidedtour { +/// This plugin allows to add custom HTML content to a sidebar-tob, to a floating window or to any +/// position in space. + +class Plugin : public cs::core::PluginBase { + public: + struct Settings { + + struct CheckPointSettings { + /// The SPICE center and frame names. + std::string mObject; + + /// The position of the item, elevation is relative to the surface height. + double mLongitude{}; + double mLatitude{}; + double mElevation{}; + + /// Size of the item. The item will scale based on the observer distance. + double mScale{}; + + /// Size of the item in pixels. + uint32_t mWidth{}; + uint32_t mHeight{}; + + /// The actual File path. + std::string mFile; + mutable bool mIsVisited; + }; + + struct TourSettings { + + std::string mName; + std::string mFrame; + std::string mPlanet; + glm::dvec3 mTourPositionStart; + glm::dquat mTourRotationStart; + std::vector mCheckpoints; + }; + /// These items will be placed somewhere on a celestial body. + + std::vector mTours; + }; + + void init() override; + void update() override; + void deInit() override; + void loadTour(std::string const& tourName); + void resetTour(std::string const& tourName); + + private: + void onLoad(); + void onSave(); + void unload(Settings const& pluginSettings); + void setTour(std::string const& tourName); + void loadCheckpoints(); + + struct CPItem { + std::unique_ptr mGuiArea; + std::unique_ptr mGuiItem; + std::unique_ptr mAnchor; + std::unique_ptr mTransform; + std::unique_ptr mGuiNode; + double mScale = 1.0; + glm::dvec3 mPosition; + std::string mObjectName; + }; + + Settings mPluginSettings; + + std::list mCPItems; + std::string mCurrentTour = "none"; + std::string mLoadedTour = "none"; + + + int mOnLoadConnection = -1; + int mOnSaveConnection = -1; +}; + +} // namespace csp::guidedtour + +#endif // CSP_GUIDED_TOUR_PLUGIN_HPP diff --git a/plugins/csp-guided-tour/src/logger.cpp b/plugins/csp-guided-tour/src/logger.cpp new file mode 100644 index 000000000..039cb8320 --- /dev/null +++ b/plugins/csp-guided-tour/src/logger.cpp @@ -0,0 +1,23 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////// +// This file is part of CosmoScout VR // +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// SPDX-FileCopyrightText: German Aerospace Center (DLR) +// SPDX-License-Identifier: MIT + +#include "logger.hpp" + +#include "../../../src/cs-utils/logger.hpp" + +namespace csp::guidedtour { + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +spdlog::logger& logger() { + static auto logger = cs::utils::createLogger("csp-guided-tour"); + return *logger; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} // namespace csp::guidedtour diff --git a/plugins/csp-guided-tour/src/logger.hpp b/plugins/csp-guided-tour/src/logger.hpp new file mode 100644 index 000000000..caa828a9a --- /dev/null +++ b/plugins/csp-guided-tour/src/logger.hpp @@ -0,0 +1,21 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////// +// This file is part of CosmoScout VR // +//////////////////////////////////////////////////////////////////////////////////////////////////// + +// SPDX-FileCopyrightText: German Aerospace Center (DLR) +// SPDX-License-Identifier: MIT + +#ifndef CSP_GUIDED_TOUR_LOGGER_HPP +#define CSP_GUIDED_TOUR_LOGGER_HPP + +#include + +namespace csp::guidedtour { + +/// This creates the default singleton logger for "csp-guided-tour" when called for the first time +/// and returns it. See cs-utils/logger.hpp for more logging details. +spdlog::logger& logger(); + +} // namespace csp::guidedtour + +#endif // CSP_GUIDED_TOUR_LOGGER_HPP diff --git a/src/cosmoscout/ObserverNavigationNode.cpp b/src/cosmoscout/ObserverNavigationNode.cpp index 1faff3b8e..db1a5f085 100644 --- a/src/cosmoscout/ObserverNavigationNode.cpp +++ b/src/cosmoscout/ObserverNavigationNode.cpp @@ -23,6 +23,7 @@ ObserverNavigationNode::ObserverNavigationNode( , mTranslation(nullptr) , mRotation(nullptr) , mOffset(nullptr) + , mRotationOffset(nullptr) , mPreventNavigationWhenHoveredGui( oParams.GetValueOrDefault("prevent_navigation_when_hovered_gui", true)) , mFixedHorizon(oParams.GetValueOrDefault("fixed_horizon", false)) @@ -50,6 +51,9 @@ ObserverNavigationNode::ObserverNavigationNode( // NOLINTNEXTLINE(cppcoreguidelines-owning-memory): deleted in IVdfnNode::~IVdfnNode() RegisterInPortPrototype("offset", new TVdfnPortTypeCompare>); + + RegisterInPortPrototype("rotation_offset", new TVdfnPortTypeCompare>); + } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -59,13 +63,15 @@ bool ObserverNavigationNode::PrepareEvaluationRun() { mTranslation = dynamic_cast*>(GetInPort("translation")); mRotation = dynamic_cast*>(GetInPort("rotation")); mOffset = dynamic_cast*>(GetInPort("offset")); + mRotationOffset = dynamic_cast*>(GetInPort("rotation_offset")); + return GetIsValid(); } //////////////////////////////////////////////////////////////////////////////////////////////////// bool ObserverNavigationNode::GetIsValid() const { - return ((mTranslation || mRotation || mOffset) && mTime); + return ((mTranslation || mRotation || mRotationOffset || mOffset ) && mTime); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -154,13 +160,22 @@ bool ObserverNavigationNode::DoEvalNode() { auto newPosition = oObs.getPosition() + oObs.getRotation() * vTranslation * oObs.getScale(); oObs.setPosition(newPosition); + glm::dquat qRotationOffset(1 , 0 ,0 ,0); + + if (mRotationOffset) { + auto tmp = mRotationOffset->GetValue().GetNormalized().GetAxisAndAngle(); + VistaVector3D axis = tmp.m_v3Axis; + double angle = tmp.m_fAngle; + qRotationOffset = glm::angleAxis(angle, glm::dvec3(axis[0], axis[1], axis[2])); + } + auto qRotation = mAngularDirection; glm::dvec3 vRotationAxis = glm::axis(qRotation); double dRotationAngle = glm::angle(qRotation) * dDeltaTime * mMaxAngularSpeed * mAngularSpeed.get(dTtime); auto newRotation = - glm::normalize(oObs.getRotation() * glm::angleAxis(dRotationAngle, vRotationAxis)); + glm::normalize(oObs.getRotation() * glm::angleAxis(dRotationAngle, vRotationAxis) * qRotationOffset); // If mFixedHorizon is set, we rotate the observer so that the horizon of the active object is // always leveled. For now, this breaks if we are in outer space or looking straight up or down. diff --git a/src/cosmoscout/ObserverNavigationNode.hpp b/src/cosmoscout/ObserverNavigationNode.hpp index 24036d9a9..ad740d5a2 100644 --- a/src/cosmoscout/ObserverNavigationNode.hpp +++ b/src/cosmoscout/ObserverNavigationNode.hpp @@ -47,6 +47,8 @@ class ObserverNavigationNode : public IVdfnNode { TVdfnPort* mTranslation; TVdfnPort* mRotation; TVdfnPort* mOffset; + TVdfnPort* mRotationOffset; + const bool mPreventNavigationWhenHoveredGui; const bool mFixedHorizon;