From 78eb6736119b320c67c5dfef3173328bb77c7316 Mon Sep 17 00:00:00 2001 From: liuloppan Date: Wed, 18 Sep 2019 23:49:51 +0200 Subject: [PATCH] Feature/gui for touch (#967) Merging in feature gui for touch. Enable touch module to run. Currently only run on development mode with the "touch" scene. --- data/assets/base.asset | 4 +- data/assets/customization/gui.asset | 2 +- data/assets/gui/images.asset | 48 ++++++ .../dwarf_planets/pluto/charon.asset | 4 - .../dwarf_planets/pluto/pluto.asset | 4 - .../missions/newhorizons/pluto.asset | 4 - .../solarsystem/planets/earth/earth.asset | 6 - .../solarsystem/planets/jupiter/io/io.asset | 2 +- .../solarsystem/planets/jupiter/jupiter.asset | 4 - .../scene/solarsystem/planets/mars/mars.asset | 4 - .../solarsystem/planets/mercury/mercury.asset | 4 - .../solarsystem/planets/neptune/neptune.asset | 4 - .../solarsystem/planets/saturn/saturn.asset | 4 - .../solarsystem/planets/uranus/uranus.asset | 4 - .../solarsystem/planets/venus/venus.asset | 4 - data/assets/touch.scene | 37 +++++ data/assets/util/webgui.asset | 26 +-- .../openspace/interaction/navigationhandler.h | 5 + .../openspace/interaction/orbitalnavigator.h | 19 ++- include/openspace/rendering/dashboard.h | 3 + include/openspace/rendering/renderable.h | 2 +- include/openspace/scene/scenegraphnode.h | 16 ++ include/openspace/util/camera.h | 1 + .../base/dashboard/dashboarditemdistance.cpp | 1 + .../base/dashboard/dashboarditemdistance.h | 2 + modules/base/scale/staticscale.cpp | 2 +- modules/cefwebgui/cefwebguimodule.cpp | 26 +-- .../globebrowsing/scripts/layer_support.lua | 2 +- modules/touch/include/touchinteraction.h | 3 + modules/touch/src/touchinteraction.cpp | 101 ++++++++++-- modules/touch/src/touchmarker.cpp | 2 +- modules/webbrowser/include/browserinstance.h | 1 - modules/webgui/webguimodule.h | 4 +- openspace.cfg | 2 +- scripts/core_scripts.lua | 2 +- src/engine/configuration.cpp | 1 - src/interaction/navigationhandler.cpp | 13 ++ src/interaction/orbitalnavigator.cpp | 101 ++++++++++-- src/rendering/dashboard.cpp | 14 ++ src/rendering/renderable.cpp | 13 +- src/rendering/renderengine.cpp | 8 +- src/scene/scenegraphnode.cpp | 154 +++++++++++++++++- 42 files changed, 543 insertions(+), 120 deletions(-) create mode 100644 data/assets/gui/images.asset create mode 100644 data/assets/touch.scene diff --git a/data/assets/base.asset b/data/assets/base.asset index 791c43aa69..73e2db77ab 100644 --- a/data/assets/base.asset +++ b/data/assets/base.asset @@ -25,7 +25,7 @@ asset.require('util/default_dashboard') asset.require('util/default_joystick') -- Load web gui -asset.require('util/webgui') +local webGui = asset.require('util/webgui') asset.request('customization/globebrowsing') @@ -66,6 +66,8 @@ local Keybindings = { } asset.onInitialize(function () + webGui.setCefRoute("onscreen") + sceneHelper.bindKeys(Keybindings) openspace.setDefaultGuiSorting() diff --git a/data/assets/customization/gui.asset b/data/assets/customization/gui.asset index b1d255fdbd..e18cd44a7f 100644 --- a/data/assets/customization/gui.asset +++ b/data/assets/customization/gui.asset @@ -5,4 +5,4 @@ asset.export("webguiDevelopmentMode", false) -- 1) Set the above `webguiDevelopmentMode` to true -- 2) Clone the repository: https://github.com/OpenSpace/OpenSpace-WebGuiFrontend -- 3) Install nodejs (including npm) --- 4) Within the repository, run `npm install` and `npm start` \ No newline at end of file +-- 4) Within the repository, run `npm install` and `npm start` diff --git a/data/assets/gui/images.asset b/data/assets/gui/images.asset new file mode 100644 index 0000000000..abb6bee4b9 --- /dev/null +++ b/data/assets/gui/images.asset @@ -0,0 +1,48 @@ +-- This asset requires OpenSpace to be built with the OPENSPACE_MODULE_SYNC enabled + +local assetHelper = asset.require("util/asset_helper") + +asset.syncedResource({ + Type = "UrlSynchronization", + Name = "Icons", + Identifier = "planet_icons", + Url = { + "http://data.openspaceproject.com/files/webgui/assets/icons/solarsystem/earth.png", + "http://data.openspaceproject.com/files/webgui/assets/icons/solarsystem/moon.png", + "http://data.openspaceproject.com/files/webgui/assets/icons/solarsystem/jupiter.png", + "http://data.openspaceproject.com/files/webgui/assets/icons/solarsystem/mars.png", + "http://data.openspaceproject.com/files/webgui/assets/icons/solarsystem/mercury.png", + "http://data.openspaceproject.com/files/webgui/assets/icons/solarsystem/neptune.png", + "http://data.openspaceproject.com/files/webgui/assets/icons/solarsystem/saturn.png", + "http://data.openspaceproject.com/files/webgui/assets/icons/solarsystem/uranus.png", + "http://data.openspaceproject.com/files/webgui/assets/icons/solarsystem/venus.png", + "http://data.openspaceproject.com/files/webgui/assets/icons/solarsystem/callisto.png", + "http://data.openspaceproject.com/files/webgui/assets/icons/solarsystem/europa.png", + "http://data.openspaceproject.com/files/webgui/assets/icons/solarsystem/ganymede.png", + "http://data.openspaceproject.com/files/webgui/assets/icons/solarsystem/io.png", + }, + UseHash = false +}) + +asset.syncedResource({ + Type = "UrlSynchronization", + Name = "Stories", + Identifier = "story_images", + Url = { + "http://data.openspaceproject.com/files/webgui/assets/images/stories/story_solarsystem.png", + "http://data.openspaceproject.com/files/webgui/assets/images/stories/story_jupitermoons.png", + "http://data.openspaceproject.com/files/webgui/assets/images/stories/story_earthweather.png", + "http://data.openspaceproject.com/files/webgui/assets/images/stories/story_mars.png", + "http://data.openspaceproject.com/files/webgui/assets/images/stories/story_galaxies.png", + "http://data.openspaceproject.com/files/webgui/assets/images/stories/story_example.png", + }, + UseHash = false +}) + +asset.syncedResource({ + Type = "UrlSynchronization", + Name = "Instructions", + Identifier = "images", + Url = "http://data.openspaceproject.com/files/webgui/assets/images/instructions.png", + UseHash = false +}) diff --git a/data/assets/scene/solarsystem/dwarf_planets/pluto/charon.asset b/data/assets/scene/solarsystem/dwarf_planets/pluto/charon.asset index 32111bafe3..c9c58a820f 100644 --- a/data/assets/scene/solarsystem/dwarf_planets/pluto/charon.asset +++ b/data/assets/scene/solarsystem/dwarf_planets/pluto/charon.asset @@ -20,10 +20,6 @@ local Charon = { Type = "SpiceRotation", SourceFrame = "IAU_CHARON", DestinationFrame = "GALACTIC" - }, - Scale = { - Type = "StaticScale", - Scale = 1.0 } }, Renderable = { diff --git a/data/assets/scene/solarsystem/dwarf_planets/pluto/pluto.asset b/data/assets/scene/solarsystem/dwarf_planets/pluto/pluto.asset index fbd3516b88..8d2b891b4b 100644 --- a/data/assets/scene/solarsystem/dwarf_planets/pluto/pluto.asset +++ b/data/assets/scene/solarsystem/dwarf_planets/pluto/pluto.asset @@ -20,10 +20,6 @@ local Pluto = { Type = "SpiceRotation", SourceFrame = "IAU_PLUTO", DestinationFrame = "GALACTIC" - }, - Scale = { - Type = "StaticScale", - Scale = 1.0 } }, Renderable = { diff --git a/data/assets/scene/solarsystem/missions/newhorizons/pluto.asset b/data/assets/scene/solarsystem/missions/newhorizons/pluto.asset index ec93de4ff5..72eb98db1e 100644 --- a/data/assets/scene/solarsystem/missions/newhorizons/pluto.asset +++ b/data/assets/scene/solarsystem/missions/newhorizons/pluto.asset @@ -46,10 +46,6 @@ local PlutoProjection = { Type = "SpiceRotation", SourceFrame = "IAU_PLUTO", DestinationFrame = "GALACTIC" - }, - Scale = { - Type = "StaticScale", - Scale = 1.0 } }, Renderable = { diff --git a/data/assets/scene/solarsystem/planets/earth/earth.asset b/data/assets/scene/solarsystem/planets/earth/earth.asset index 82b9cf9a70..f934b499bd 100644 --- a/data/assets/scene/solarsystem/planets/earth/earth.asset +++ b/data/assets/scene/solarsystem/planets/earth/earth.asset @@ -14,12 +14,6 @@ local mapServiceConfigsPath = asset.localResource("map_service_configs") local Earth = { Identifier = "Earth", Parent = transforms.EarthIAU.Identifier, - Transform = { - Scale = { - Type = "StaticScale", - Scale = 1.0 - } - }, Renderable = { Type = "RenderableGlobe", Radii = earthEllipsoid, diff --git a/data/assets/scene/solarsystem/planets/jupiter/io/io.asset b/data/assets/scene/solarsystem/planets/jupiter/io/io.asset index 678d6bf4ff..ca10670c06 100644 --- a/data/assets/scene/solarsystem/planets/jupiter/io/io.asset +++ b/data/assets/scene/solarsystem/planets/jupiter/io/io.asset @@ -29,7 +29,7 @@ local Io = { Target = "IO", Observer = "JUPITER BARYCENTER", Kernels = kernel - }, + } }, Renderable = { Type = "RenderableGlobe", diff --git a/data/assets/scene/solarsystem/planets/jupiter/jupiter.asset b/data/assets/scene/solarsystem/planets/jupiter/jupiter.asset index b15a546a5e..9333c339c1 100644 --- a/data/assets/scene/solarsystem/planets/jupiter/jupiter.asset +++ b/data/assets/scene/solarsystem/planets/jupiter/jupiter.asset @@ -20,10 +20,6 @@ local Jupiter = { Type = "SpiceRotation", SourceFrame = "IAU_JUPITER", DestinationFrame = "GALACTIC" - }, - Scale = { - Type = "StaticScale", - Scale = 1.0 } }, Renderable = { diff --git a/data/assets/scene/solarsystem/planets/mars/mars.asset b/data/assets/scene/solarsystem/planets/mars/mars.asset index 3d2d7e3f10..57ee23d861 100644 --- a/data/assets/scene/solarsystem/planets/mars/mars.asset +++ b/data/assets/scene/solarsystem/planets/mars/mars.asset @@ -153,10 +153,6 @@ local Mars = { Type = "SpiceRotation", SourceFrame = "IAU_MARS", DestinationFrame = "GALACTIC" - }, - Scale = { - Type = "StaticScale", - Scale = 1.0 } }, Renderable = { diff --git a/data/assets/scene/solarsystem/planets/mercury/mercury.asset b/data/assets/scene/solarsystem/planets/mercury/mercury.asset index b5f60b4e93..d2bcf7c591 100644 --- a/data/assets/scene/solarsystem/planets/mercury/mercury.asset +++ b/data/assets/scene/solarsystem/planets/mercury/mercury.asset @@ -189,10 +189,6 @@ local Mercury = { Type = "SpiceRotation", SourceFrame = "IAU_MERCURY", DestinationFrame = "GALACTIC" - }, - Scale = { - Type = "StaticScale", - Scale = 1.0 } }, Renderable = { diff --git a/data/assets/scene/solarsystem/planets/neptune/neptune.asset b/data/assets/scene/solarsystem/planets/neptune/neptune.asset index 450b1fa4c7..677395e8e5 100644 --- a/data/assets/scene/solarsystem/planets/neptune/neptune.asset +++ b/data/assets/scene/solarsystem/planets/neptune/neptune.asset @@ -18,10 +18,6 @@ local Neptune = { Type = "SpiceRotation", SourceFrame = "IAU_NEPTUNE", DestinationFrame = "GALACTIC" - }, - Scale = { - Type = "StaticScale", - Scale = 1.0 } }, Renderable = { diff --git a/data/assets/scene/solarsystem/planets/saturn/saturn.asset b/data/assets/scene/solarsystem/planets/saturn/saturn.asset index d9ea30dac3..77b45972f2 100644 --- a/data/assets/scene/solarsystem/planets/saturn/saturn.asset +++ b/data/assets/scene/solarsystem/planets/saturn/saturn.asset @@ -20,10 +20,6 @@ local Saturn = { Type = "SpiceRotation", SourceFrame = "IAU_SATURN", DestinationFrame = "GALACTIC" - }, - Scale = { - Type = "StaticScale", - Scale = 1.0 } }, Renderable = { diff --git a/data/assets/scene/solarsystem/planets/uranus/uranus.asset b/data/assets/scene/solarsystem/planets/uranus/uranus.asset index 03ca0abd60..1bb29fa184 100644 --- a/data/assets/scene/solarsystem/planets/uranus/uranus.asset +++ b/data/assets/scene/solarsystem/planets/uranus/uranus.asset @@ -20,10 +20,6 @@ local Uranus = { Type = "SpiceRotation", SourceFrame = "IAU_URANUS", DestinationFrame = "GALACTIC" - }, - Scale = { - Type = "StaticScale", - Scale = 1.0 } }, Renderable = { diff --git a/data/assets/scene/solarsystem/planets/venus/venus.asset b/data/assets/scene/solarsystem/planets/venus/venus.asset index 17c3f3ea10..0b7617dad2 100644 --- a/data/assets/scene/solarsystem/planets/venus/venus.asset +++ b/data/assets/scene/solarsystem/planets/venus/venus.asset @@ -26,10 +26,6 @@ local Venus = { Type = "SpiceTranslation", Target = "VENUS", Observer = "VENUS BARYCENTER" - }, - Scale = { - Type = "StaticScale", - Scale = 1.0 } }, Renderable = { diff --git a/data/assets/touch.scene b/data/assets/touch.scene new file mode 100644 index 0000000000..d981a1ebcb --- /dev/null +++ b/data/assets/touch.scene @@ -0,0 +1,37 @@ +local has_touch = openspace.modules.isLoaded('Touch') +if not has_touch then + openspace.printFatal('Could not load scene "' .. asset.filePath .. '" due to missing module "touch"') + do return end +end + +asset.require('./base') +local webGui = asset.require('util/webgui') + +local earthAsset = asset.require('scene/solarsystem/planets/earth/earth') + +asset.onInitialize(function () + local now = openspace.time.currentWallTime() + -- Jump back one day to be able to show complete weather data on Earth. + openspace.time.setTime(openspace.time.advancedTime(now, "-1d")) + + openspace.markInterestingNodes( + { "Earth", "Mars", "Moon" } + ) + + openspace.navigation.setNavigationState({ + Anchor = earthAsset.Earth.Identifier, + Position = { 58.5877, 16.1924, 20000000 } + }) + + openspace.setPropertyValueSingle('Scene.Pluto.Renderable.Enabled', false) + openspace.setPropertyValueSingle('Scene.Charon.Renderable.Enabled', false) + openspace.setPropertyValueSingle('Scene.PlutoBarycenterTrail.Renderable.Enabled', false) + + webGui.setCefRoute("ontouch") +end) + +asset.onDeinitialize(function () + openspace.removeInterestingNodes( + { "Earth", "Mars", "Moon" } + ) +end) diff --git a/data/assets/util/webgui.asset b/data/assets/util/webgui.asset index cf1f498148..5a052ed12b 100644 --- a/data/assets/util/webgui.asset +++ b/data/assets/util/webgui.asset @@ -37,16 +37,6 @@ asset.onInitialize(function () openspace.setPropertyValueSingle("Modules.WebGui.DefaultEndpoint", "frontend") openspace.setPropertyValueSingle("Modules.WebGui.ServerProcessEnabled", enabled) - if guiCustomization.webguiDevelopmentMode then - -- Route CEF to the deveopment version of the GUI. - -- This must be manually served using `npm start` - -- in the OpenSpace-WebGuiFrontend repository. - openspace.setPropertyValueSingle( - "Modules.CefWebGui.GuiUrl", - "http://127.0.0.1:4690/frontend/#/onscreen" - ) - end - -- The GUI contains date and simulation increment, -- so let's remove these from the dashboard. if openspace.getPropertyValue('Modules.CefWebGui.Visible') then @@ -76,3 +66,19 @@ asset.onDeinitialize(function () -- need to address in webguimodule.cpp --openspace.setPropertyValueSingle("Modules.WebGui.Directories", newDirectories) end) + +function setCefRoute(route) + local port = 4680 + -- As a developer, you can manually serve the webgui from port 4690 + -- with the command `npm start` in the web gui repository + if guiCustomization.webguiDevelopmentMode then + port = 4690 + end + openspace.setPropertyValueSingle( + "Modules.CefWebGui.GuiUrl", + "http://127.0.0.1:" .. port .. "/frontend/#/" .. route + ) +end + + +asset.export("setCefRoute", setCefRoute) diff --git a/include/openspace/interaction/navigationhandler.h b/include/openspace/interaction/navigationhandler.h index 1d6249c6d0..89fc965785 100644 --- a/include/openspace/interaction/navigationhandler.h +++ b/include/openspace/interaction/navigationhandler.h @@ -80,6 +80,10 @@ public: void deinitialize(); // Mutators + + void setFocusNode(SceneGraphNode* node); + void resetCameraDirection(); + void setNavigationStateNextFame(NavigationState state); void setCamera(Camera* camera); void setInterpolationTime(float durationInSeconds); @@ -92,6 +96,7 @@ public: // Accessors Camera* camera() const; + const SceneGraphNode* anchorNode() const; const InputState& inputState() const; const OrbitalNavigator& orbitalNavigator() const; OrbitalNavigator& orbitalNavigator(); diff --git a/include/openspace/interaction/orbitalnavigator.h b/include/openspace/interaction/orbitalnavigator.h index 4ec4ced185..155bfdd1af 100644 --- a/include/openspace/interaction/orbitalnavigator.h +++ b/include/openspace/interaction/orbitalnavigator.h @@ -64,6 +64,8 @@ public: void setCamera(Camera* camera); void clearPreviousState(); + SceneGraphNode* focusNode() const; + void setFocusNode(const SceneGraphNode* focusNode); void setFocusNode(const std::string& focusNode); void setAnchorNode(const std::string& anchorNode); void setAimNode(const std::string& aimNode); @@ -118,7 +120,6 @@ private: properties::FloatProperty friction; }; - void setFocusNode(const SceneGraphNode* focusNode); void setAnchorNode(const SceneGraphNode* anchorNode); void setAimNode(const SceneGraphNode* aimNode); @@ -141,7 +142,11 @@ private: properties::FloatProperty _followAnchorNodeRotationDistance; properties::FloatProperty _minimumAllowedDistance; + properties::FloatProperty _flightDestinationDistance; + properties::BoolProperty _applyLinearFlight; + + properties::FloatProperty _velocitySensitivity; properties::FloatProperty _mouseSensitivity; properties::FloatProperty _joystickSensitivity; properties::FloatProperty _websocketSensitivity; @@ -246,6 +251,18 @@ private: const glm::dvec3& objectPosition, const glm::dquat& globalCameraRotation, const SurfacePositionHandle& positionHandle) const; + /** + * Moves the camera along a vector, camPosToCenterPosDiff, until it reaches the focusLimit. + * The velocity of the zooming depend on distFromCameraToFocus and the final frame + * where the camera stops moving depends on the distance set in the variable focusLimit. + * The bool determines whether to move/fly towards the focus node or away from it. + * \returns a new position of the camera, closer to the focusLimit than the previous + * position. + */ + glm::dvec3 moveCameraAlongVector(const glm::dvec3& camPos, + double distFromCameraToFocus, const glm::dvec3& camPosToCenterPosDiff, + double destination) const; + /* * Adds rotation to the camera position so that it follows the rotation of the anchor * node defined by the differential anchorNodeRotationDiff. diff --git a/include/openspace/rendering/dashboard.h b/include/openspace/rendering/dashboard.h index 9101721805..12f10b5a98 100644 --- a/include/openspace/rendering/dashboard.h +++ b/include/openspace/rendering/dashboard.h @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -50,6 +51,7 @@ public: void removeDashboardItem(const std::string& identifier); void removeDashboardItem(int index); void clearDashboardItems(); + glm::vec2 getStartPositionOffset(); /** * Returns the Lua library that contains all Lua functions available to affect the @@ -59,6 +61,7 @@ public: private: properties::BoolProperty _isEnabled; + properties::IVec2Property _startPositionOffset; std::vector> _items; }; diff --git a/include/openspace/rendering/renderable.h b/include/openspace/rendering/renderable.h index 0e6f0896ee..d72a6e1b8c 100644 --- a/include/openspace/rendering/renderable.h +++ b/include/openspace/rendering/renderable.h @@ -94,6 +94,7 @@ public: protected: properties::BoolProperty _enabled; properties::FloatProperty _opacity; + properties::FloatProperty _boundingSphere; properties::StringProperty _renderableType; void setRenderBinFromOpacity(); @@ -101,7 +102,6 @@ protected: private: RenderBin _renderBin = RenderBin::Opaque; - float _boundingSphere = 0.f; }; } // namespace openspace diff --git a/include/openspace/scene/scenegraphnode.h b/include/openspace/scene/scenegraphnode.h index 7240107596..eab4fd6ee6 100644 --- a/include/openspace/scene/scenegraphnode.h +++ b/include/openspace/scene/scenegraphnode.h @@ -29,12 +29,16 @@ #include #include +#include +#include +#include #include #include #include #include #include #include +#include //#define Debugging_Core_SceneGraphNode_Indices @@ -149,6 +153,7 @@ private: glm::dvec3 calculateWorldPosition() const; glm::dmat3 calculateWorldRotation() const; double calculateWorldScale() const; + void computeScreenSpaceData(RenderData& newData); std::atomic _state = State::Loaded; std::vector> _children; @@ -187,6 +192,17 @@ private: glm::dmat4 _modelTransformCached; glm::dmat4 _inverseModelTransformCached; + properties::BoolProperty _computeScreenSpaceValues; + properties::IVec2Property _screenSpacePosition; + properties::BoolProperty _screenVisibility; + properties::DoubleProperty _distFromCamToNode; + properties::DoubleProperty _screenSizeRadius; + properties::FloatProperty _visibilityDistance; + + // This variable is used for the rate-limiting of the screenspace positions (if they + // are calculated when _computeScreenSpaceValues is true) + std::chrono::high_resolution_clock::time_point _lastScreenSpaceUpdateTime; + #ifdef Debugging_Core_SceneGraphNode_Indices int index = 0; static int nextIndex; diff --git a/include/openspace/util/camera.h b/include/openspace/util/camera.h index da511165f1..8131d04191 100644 --- a/include/openspace/util/camera.h +++ b/include/openspace/util/camera.h @@ -101,6 +101,7 @@ public: // Right now this function returns the actual combined matrix which makes some // of the old calls to the function wrong.. const glm::dmat4& combinedViewMatrix() const; + const glm::dmat4& combinedViewMatrixNoScale() const; void invalidateCache(); diff --git a/modules/base/dashboard/dashboarditemdistance.cpp b/modules/base/dashboard/dashboarditemdistance.cpp index 32c0453ec7..7cb68aac93 100644 --- a/modules/base/dashboard/dashboarditemdistance.cpp +++ b/modules/base/dashboard/dashboarditemdistance.cpp @@ -440,6 +440,7 @@ void DashboardItemDistance::render(glm::vec2& penPosition) { } penPosition.y -= _font->height(); + RenderFont( *_font, penPosition, diff --git a/modules/base/dashboard/dashboarditemdistance.h b/modules/base/dashboard/dashboarditemdistance.h index e55bb57bcf..480f500f6d 100644 --- a/modules/base/dashboard/dashboarditemdistance.h +++ b/modules/base/dashboard/dashboarditemdistance.h @@ -52,6 +52,8 @@ public: static documentation::Documentation Documentation(); + bool storyStyleActive(); + private: enum Type { Node = 0, diff --git a/modules/base/scale/staticscale.cpp b/modules/base/scale/staticscale.cpp index 6a3e6251dc..91f2602f1c 100644 --- a/modules/base/scale/staticscale.cpp +++ b/modules/base/scale/staticscale.cpp @@ -58,7 +58,7 @@ double StaticScale::scaleValue(const UpdateData&) const { return _scaleValue; } -StaticScale::StaticScale() : _scaleValue(ScaleInfo, 1.0, 1.0, 1e6) { +StaticScale::StaticScale() : _scaleValue(ScaleInfo, 1.0, 0.1, 100) { addProperty(_scaleValue); _scaleValue.onChange([this]() { diff --git a/modules/cefwebgui/cefwebguimodule.cpp b/modules/cefwebgui/cefwebguimodule.cpp index 4a69090acf..44c3ffa24b 100644 --- a/modules/cefwebgui/cefwebguimodule.cpp +++ b/modules/cefwebgui/cefwebguimodule.cpp @@ -160,21 +160,21 @@ void CefWebGuiModule::internalInitialize(const ghoul::Dictionary& configuration) } }); - if (configuration.hasValue(GuiUrlInfo.identifier)) { - _url = configuration.value(GuiUrlInfo.identifier); - } else { - WebGuiModule* webGuiModule = global::moduleEngine.module(); - _url = "http://127.0.0.1:" + - std::to_string(webGuiModule->port()) + "/frontend/#/onscreen"; + // We need this to make sure that the browser is reloaded + // once the endpoint comes online, on OpenSpace startup. - _endpointCallback = webGuiModule->addEndpointChangeCallback( - [this](const std::string& endpoint, bool exists) { - if (exists && endpoint == "frontend" && _instance) { - _instance->reloadBrowser(); - } + // TODO: See if the hardcoded endpoint `frontend` below can be removed. + // Possible fix: Reload browser if cefwebgui is routed to localhost + // and the same endpoint that just came online. + WebGuiModule* webGuiModule = global::moduleEngine.module(); + + _endpointCallback = webGuiModule->addEndpointChangeCallback( + [this](const std::string& endpoint, bool exists) { + if (exists && endpoint == "frontend" && _instance) { + _instance->reloadBrowser(); } - ); - } + } + ); if (configuration.hasValue(GuiScaleInfo.identifier)) { _guiScale = configuration.value(GuiScaleInfo.identifier); diff --git a/modules/globebrowsing/scripts/layer_support.lua b/modules/globebrowsing/scripts/layer_support.lua index c60c487d0b..d76864112f 100644 --- a/modules/globebrowsing/scripts/layer_support.lua +++ b/modules/globebrowsing/scripts/layer_support.lua @@ -333,4 +333,4 @@ openspace.globebrowsing.loadWMSServersFromFile = function (file_path) end end -end \ No newline at end of file +end diff --git a/modules/touch/include/touchinteraction.h b/modules/touch/include/touchinteraction.h index 0d9942184c..f8de436b4b 100644 --- a/modules/touch/include/touchinteraction.h +++ b/modules/touch/include/touchinteraction.h @@ -32,6 +32,7 @@ #include #include +#include #include #include #include @@ -208,6 +209,8 @@ private: properties::FloatProperty _zoomSensitivityProportionalDist; properties::FloatProperty _zoomSensitivityDistanceThreshold; properties::FloatProperty _zoomBoundarySphereMultiplier; + properties::DoubleProperty _zoomInLimit; + properties::DoubleProperty _zoomOutLimit; properties::FloatProperty _inputStillThreshold; properties::FloatProperty _centroidStillThreshold; properties::BoolProperty _panEnabled; diff --git a/modules/touch/src/touchinteraction.cpp b/modules/touch/src/touchinteraction.cpp index 65f6e5e6f5..de3d78b6bd 100644 --- a/modules/touch/src/touchinteraction.cpp +++ b/modules/touch/src/touchinteraction.cpp @@ -38,6 +38,7 @@ #include #include #include +#include #include @@ -227,6 +228,22 @@ namespace { "Minimum radius for picking in NDC coordinates", "" // @TODO Missing documentation }; + + constexpr openspace::properties::Property::PropertyInfo ZoomOutLimitInfo = { + "ZoomOutLimit", + "Zoom Out Limit", + "The maximum distance you are allowed to navigate away from the anchor. " + "This should always be larger than the zoom in value if you want to be able " + "to zoom. Defaults to maximum allowed double." + }; + + constexpr openspace::properties::Property::PropertyInfo ZoomInLimitInfo = { + "ZoomInLimit", + "Zoom In Limit", + "The minimum distance from the anchor that you are allowed to navigate to. " + "Its purpose is to limit zooming in on a node. If this value is not set it " + "defaults to the surface of the current anchor. " + }; } // namespace using namespace TUIO; @@ -256,6 +273,8 @@ TouchInteraction::TouchInteraction() 0.25f ) , _zoomBoundarySphereMultiplier(ZoomBoundarySphereMultiplierInfo, 1.001f, 1.f, 1.01f) + , _zoomOutLimit(ZoomOutLimitInfo, std::numeric_limits::max(), 1000.0f, std::numeric_limits::max()) + , _zoomInLimit(ZoomInLimitInfo, -1.0f, 0.0f, std::numeric_limits::max()) , _inputStillThreshold(InputSensitivityInfo, 0.0005f, 0.f, 0.001f) // used to void wrongly interpreted roll interactions , _centroidStillThreshold(StationaryCentroidInfo, 0.0018f, 0.f, 0.01f) @@ -321,6 +340,8 @@ TouchInteraction::TouchInteraction() addProperty(_zoomSensitivityProportionalDist); addProperty(_zoomSensitivityDistanceThreshold); addProperty(_zoomBoundarySphereMultiplier); + addProperty(_zoomInLimit); + addProperty(_zoomOutLimit); addProperty(_constTimeDecay_secs); addProperty(_inputStillThreshold); addProperty(_centroidStillThreshold); @@ -673,7 +694,8 @@ void TouchInteraction::directControl(const std::vector& list) { if (c != list.end()) { // normalized -1 to 1 coordinates on screen screenPoints.emplace_back(2 * (c->getX() - 0.5), -2 * (c->getY() - 0.5)); - } else { + } + else { global::moduleEngine.module()->touchInput = { true, glm::dvec2(0.0, 0.0), @@ -1130,7 +1152,8 @@ void TouchInteraction::computeVelocities(const std::vector& list, static_cast(_zoomSensitivityExponential) ); } - } else { + } + else { zoomFactor = 1.0; } _vel.zoom = zoomFactor * _zoomSensitivityProportionalDist * @@ -1283,7 +1306,6 @@ void TouchInteraction::step(double dt) { dquat localCamRot = inverse(globalCamRot) * _camera->rotationQuaternion(); double boundingSphere = anchor->boundingSphere(); - dvec3 centerToBoundingSphere; double distance = std::max(length(centerToCamera) - boundingSphere, 0.0); _currentRadius = boundingSphere / std::max(distance * _projectionScaleFactor, 1.0); @@ -1327,19 +1349,67 @@ void TouchInteraction::step(double dt) { globalCamRot = normalize(quat_cast(inverse(lookAtMatrix))); } { // Zooming - centerToBoundingSphere = -directionToCenter * boundingSphere; - centerToCamera = camPos - centerPos; - double planetBoundaryRadius = length(centerToBoundingSphere); - planetBoundaryRadius *= _zoomBoundarySphereMultiplier; - double distToSurface = length(centerToCamera - planetBoundaryRadius); + + // This is a rough estimate of the node surface + double zoomInBounds = boundingSphere * _zoomBoundarySphereMultiplier; + + // If nobody has set another zoom in limit, use the default zoom in bounds + if (_zoomInLimit.value() < 0) { + _zoomInLimit.setValue(zoomInBounds); + } + else if (_zoomInLimit.value() < zoomInBounds) { + // If zoom in limit is less than the estimated node radius we need to + // make sure we do not get too close to possible height maps + SurfacePositionHandle posHandle = anchor->calculateSurfacePositionHandle(camPos); + glm::dvec3 centerToActualSurfaceModelSpace = posHandle.centerToReferenceSurface + + posHandle.referenceSurfaceOutDirection * posHandle.heightToSurface; + glm::dvec3 centerToActualSurface = glm::dmat3(anchor->modelTransform()) * + centerToActualSurfaceModelSpace; + double nodeRadius = length(centerToActualSurface); + + // Because of heightmaps we should make sure we do not go through the surface + if (_zoomInLimit.value() < nodeRadius) { +#ifdef TOUCH_DEBUG_PROPERTIES + LINFO(fmt::format( + "{}: Zoom In Limit should be larger than anchor center to surface, setting it to {}", + _loggerCat, zoomInBounds); +#endif + _zoomInLimit.setValue(zoomInBounds); + } + } + + // Make sure zoom in limit is not larger than zoom out limit + if (_zoomInLimit.value() > _zoomOutLimit.value()) { + LWARNING(fmt::format( + "{}: Zoom In Limit should be smaller than Zoom Out Limit", + _loggerCat, _zoomOutLimit.value() + )); + } //Apply the velocity to update camera position - glm::dvec3 velocityIncr = directionToCenter * _vel.zoom * dt; - bool isDeltaLessThanDistToSurface = (length(_vel.zoom * dt) < distToSurface); - bool isNewPosOutsidePlanetRadius = - (length(centerToCamera + velocityIncr) > planetBoundaryRadius); - if (isDeltaLessThanDistToSurface && isNewPosOutsidePlanetRadius) { - camPos += velocityIncr; + glm::dvec3 zoomDistanceIncrement = directionToCenter * _vel.zoom * dt; + double newPosDistance = length(centerToCamera + zoomDistanceIncrement); + double currentPosDistance = length(centerToCamera); + + // Possible with other navigations performed outside touch interaction + bool currentPosViolatingZoomOutLimit = (currentPosDistance >= _zoomOutLimit.value()); + bool willNewPositionViolateZoomOutLimit = (newPosDistance >= _zoomOutLimit.value()); + bool willNewPositionViolateZoomInLimit = (newPosDistance < _zoomInLimit.value()); + + if(!willNewPositionViolateZoomInLimit && !willNewPositionViolateZoomOutLimit){ + camPos += zoomDistanceIncrement; + } + else if (currentPosViolatingZoomOutLimit) { +#ifdef TOUCH_DEBUG_PROPERTIES + LINFO(fmt::format( + "{}: You are outside zoom out {} limit, only zoom in allowed", + _loggerCat, _zoomOutLimit.value()); +#endif + // Only allow zooming in if you are outside the zoom out limit + if (newPosDistance < currentPosDistance) + { + camPos += zoomDistanceIncrement; + } } else { #ifdef TOUCH_DEBUG_PROPERTIES @@ -1534,7 +1604,8 @@ void TouchInteraction::setFocusNode(const SceneGraphNode* focusNode) { global::navigationHandler.orbitalNavigator().setAnchorNode( focusNode->identifier() ); - } else { + } + else { global::navigationHandler.orbitalNavigator().setAnchorNode(""); } } diff --git a/modules/touch/src/touchmarker.cpp b/modules/touch/src/touchmarker.cpp index c6f4d5af9e..07d15aec9a 100644 --- a/modules/touch/src/touchmarker.cpp +++ b/modules/touch/src/touchmarker.cpp @@ -131,7 +131,7 @@ void TouchMarker::render(const std::vector& list) { glBlendEquation(GL_FUNC_ADD); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_PROGRAM_POINT_SIZE); // Enable gl_PointSize in vertex shader - glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); + // glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); // When included this line makes the webgui disappear at touch interaction glBindVertexArray(_quad); glDrawArrays(GL_POINTS, 0, static_cast(_vertexData.size() / 2)); diff --git a/modules/webbrowser/include/browserinstance.h b/modules/webbrowser/include/browserinstance.h index 537c371600..5aa1cc71de 100644 --- a/modules/webbrowser/include/browserinstance.h +++ b/modules/webbrowser/include/browserinstance.h @@ -86,7 +86,6 @@ public: void sendTouchPressEvent(const CefMouseEvent & event, CefBrowserHost::MouseButtonType button, const int clickCount); - void sendResleasePressEvent(const CefMouseEvent & event, CefBrowserHost::MouseButtonType button, const int clickCount); diff --git a/modules/webgui/webguimodule.h b/modules/webgui/webguimodule.h index 7419d1b44e..f4793c2f22 100644 --- a/modules/webgui/webguimodule.h +++ b/modules/webgui/webguimodule.h @@ -27,10 +27,10 @@ #include -#include #include -#include +#include #include +#include #include #include #include diff --git a/openspace.cfg b/openspace.cfg index 41ccdfe588..b47a47aa89 100644 --- a/openspace.cfg +++ b/openspace.cfg @@ -55,6 +55,7 @@ Asset = "default" -- Asset = "insight" -- Asset = "apollo8" -- Asset = "apollo_sites" +-- Asset = "touch" -- These scripts are executed after the initialization of each scene, thus making -- it possible to have global overrides to default values or execute other scripts @@ -130,7 +131,6 @@ ModuleConfigurations = { WebSocketInterface = "DefaultWebSocketInterface" }, CefWebGui = { - -- GuiUrl = "http://localhost:4680/#/onscreen/", -- GuiScale = 2.0, Enabled = true, Visible = true diff --git a/scripts/core_scripts.lua b/scripts/core_scripts.lua index 073e7d3c7e..bc6df932f3 100644 --- a/scripts/core_scripts.lua +++ b/scripts/core_scripts.lua @@ -1,6 +1,6 @@ openspace.documentation = { { - Name = "markInteratingNodes", + Name = "markInterestingNodes", Arguments = "List of nodes", Documentation = "This function marks the scene graph nodes identified by name " .. "as interesting, which will provide shortcut access to focus buttons and " .. diff --git a/src/engine/configuration.cpp b/src/engine/configuration.cpp index ee9264e4ad..8912f488a8 100644 --- a/src/engine/configuration.cpp +++ b/src/engine/configuration.cpp @@ -296,7 +296,6 @@ void parseLuaState(Configuration& configuration) { getValue(s, KeyMasterRotation, c.masterRotation); getValue(s, KeyDisableInGameConsole, c.isConsoleDisabled); getValue(s, KeyRenderingMethod, c.renderingMethod); - getValue(s, KeyLogging, c.logging); getValue(s, KeyDocumentation, c.documentation); getValue(s, KeyLoadingScreen, c.loadingScreen); diff --git a/src/interaction/navigationhandler.cpp b/src/interaction/navigationhandler.cpp index ba7a2ea4f3..3cb6361ddf 100644 --- a/src/interaction/navigationhandler.cpp +++ b/src/interaction/navigationhandler.cpp @@ -165,6 +165,15 @@ void NavigationHandler::deinitialize() { global::parallelPeer.connectionEvent().unsubscribe("NavigationHandler"); } +void NavigationHandler::setFocusNode(SceneGraphNode* node) { + _orbitalNavigator.setFocusNode(node); + _camera->setPositionVec3(anchorNode()->worldPosition()); +} + +void NavigationHandler::resetCameraDirection() { + _orbitalNavigator.startRetargetAnchor(); +} + void NavigationHandler::setCamera(Camera* camera) { _camera = camera; _orbitalNavigator.setCamera(camera); @@ -299,6 +308,10 @@ void NavigationHandler::stopPlayback() { _playbackModeEnabled = false; } +const SceneGraphNode* NavigationHandler::anchorNode() const { + return _orbitalNavigator.anchorNode(); +} + Camera* NavigationHandler::camera() const { return _camera; } diff --git a/src/interaction/orbitalnavigator.cpp b/src/interaction/orbitalnavigator.cpp index ea817396b4..29a0e2d844 100644 --- a/src/interaction/orbitalnavigator.cpp +++ b/src/interaction/orbitalnavigator.cpp @@ -23,7 +23,6 @@ ****************************************************************************************/ #include - #include #include #include @@ -35,6 +34,7 @@ namespace { constexpr const double AngleEpsilon = 1E-7; constexpr const double DistanceRatioAimThreshold = 1E-4; + constexpr const double FlightDestinationFactor = 1E-4; constexpr const openspace::properties::Property::PropertyInfo AnchorInfo = { "Anchor", @@ -136,12 +136,31 @@ namespace { "" // @TODO Missing documentation }; - constexpr openspace::properties::Property::PropertyInfo StereoInterpolationTimeInfo = - { - "StereoInterpolationTime", - "Stereo interpolation time", - "The time to interpolate to a new stereoscopic depth " - "when the anchor node is changed." + constexpr openspace::properties::Property::PropertyInfo VelocityZoomControlInfo = { + "VelocityZoomControl", + "Velocity zoom control", + "Controls the velocity of the camera motion when zooming in to the focus node. " + "The higher the value the faster the camera will move towards the focus." + }; + + constexpr openspace::properties::Property::PropertyInfo ApplyLinearFlightInfo = { + "ApplyLinearFlight", + "Apply Linear Flight", + "This property makes the camera move to the specified distance 'FlightDestinationDistance' while facing the anchor" + }; + + constexpr openspace::properties::Property::PropertyInfo FlightDestinationDistanceInfo = { + "FlightDestinationDistance", + "Flight Destination Distance", + "The final distance we want to fly to, with regards to the anchor node." + }; + + constexpr openspace::properties::Property::PropertyInfo + StereoInterpolationTimeInfo = { + "StereoInterpolationTime", + "Stereo interpolation time", + "The time to interpolate to a new stereoscopic depth " + "when the anchor node is changed." }; constexpr openspace::properties::Property::PropertyInfo @@ -210,6 +229,9 @@ OrbitalNavigator::OrbitalNavigator() , _retargetAim(RetargetAimInfo) , _followAnchorNodeRotationDistance(FollowAnchorNodeInfo, 5.0f, 0.0f, 20.f) , _minimumAllowedDistance(MinimumDistanceInfo, 10.0f, 0.0f, 10000.f) + , _velocitySensitivity(VelocityZoomControlInfo, 0.02f, 0.01f, 0.15f) + , _applyLinearFlight(ApplyLinearFlightInfo, false) + , _flightDestinationDistance(FlightDestinationDistanceInfo, 2e8f, 0.0f, 1e10f) , _mouseSensitivity(MouseSensitivityInfo, 15.0f, 1.0f, 50.f) , _joystickSensitivity(JoystickSensitivityInfo, 10.0f, 1.0f, 50.f) , _websocketSensitivity(WebsocketSensitivityInfo, 10.0f, 1.0f, 50.f) @@ -262,7 +284,8 @@ OrbitalNavigator::OrbitalNavigator() _retargetAim.onChange([this]() { if (_aimNode && _aimNode != _anchorNode) { startRetargetAim(); - } else { + } + else { startRetargetAnchor(); } }); @@ -337,6 +360,9 @@ OrbitalNavigator::OrbitalNavigator() addProperty(_retargetAim); addProperty(_followAnchorNodeRotationDistance); addProperty(_minimumAllowedDistance); + addProperty(_velocitySensitivity); + addProperty(_flightDestinationDistance); + addProperty(_applyLinearFlight); addProperty(_useAdaptiveStereoscopicDepth); addProperty(_staticViewScaleExponent); @@ -393,6 +419,9 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) { } const glm::dvec3 anchorPos = _anchorNode->worldPosition(); + + SurfacePositionHandle posHandle; + const glm::dvec3 prevCameraPosition = _camera->positionVec3(); const glm::dvec3 anchorDisplacement = _previousAnchorNodePosition.has_value() ? (anchorPos - _previousAnchorNodePosition.value()) : @@ -403,6 +432,31 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) { _camera->rotationQuaternion() }; + if (_applyLinearFlight) { + // Calculate a position handle based on the camera position in world space + glm::dvec3 camPosToAnchorPosDiff = prevCameraPosition - anchorPos; + // Use the boundingsphere to get an approximate distance to the surface of the node + double nodeRadius = static_cast(_anchorNode->boundingSphere()); + double distFromCameraToFocus = glm::distance(prevCameraPosition, anchorPos) - nodeRadius; + + // Make the approximation delta size depending on the flight distance + double arrivalThreshold = _flightDestinationDistance.value() * FlightDestinationFactor; + + // Fly towards the flight destination distance. When getting closer than arrivalThreshold terminate the flight + if (abs(distFromCameraToFocus - _flightDestinationDistance.value()) > arrivalThreshold) { + + pose.position = moveCameraAlongVector( + pose.position, + distFromCameraToFocus, + camPosToAnchorPosDiff, + _flightDestinationDistance + ); + } + else { + _applyLinearFlight.setValue(false); + } + } + const bool hasPreviousPositions = _previousAnchorNodePosition.has_value() && _previousAimNodePosition.has_value(); @@ -433,8 +487,7 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) { _previousAnchorNodePosition = _anchorNode->worldPosition(); // Calculate a position handle based on the camera position in world space - SurfacePositionHandle posHandle = - calculateSurfacePositionHandle(*_anchorNode, pose.position); + posHandle = calculateSurfacePositionHandle(*_anchorNode, pose.position); // Decompose camera rotation so that we can handle global and local rotation // individually. Then we combine them again when finished. @@ -532,7 +585,8 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) { if (_directlySetStereoDistance) { _currentCameraToSurfaceDistance = targetCameraToSurfaceDistance; _directlySetStereoDistance = false; - } else { + } + else { _currentCameraToSurfaceDistance = interpolateCameraToSurfaceDistance( deltaTime, _currentCameraToSurfaceDistance, @@ -543,7 +597,8 @@ void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) { _stereoscopicDepthOfFocusSurface / static_cast(_currentCameraToSurfaceDistance) ); - } else { + } + else { _camera->setScaling(glm::pow(10.f, _staticViewScaleExponent)); } } @@ -972,6 +1027,7 @@ glm::dquat OrbitalNavigator::rotateLocally(double deltaTime, return localCameraRotation * joystickRotationDiff * mouseRotationDiff * websocketRotationDiff * scriptRotationDiff; } + glm::dquat OrbitalNavigator::interpolateLocalRotation(double deltaTime, const glm::dquat& localCameraRotation) { @@ -1173,6 +1229,27 @@ glm::dvec3 OrbitalNavigator::translateHorizontally(double deltaTime, return cameraPosition + rotationDiffVec3; } +glm::dvec3 OrbitalNavigator::moveCameraAlongVector(const glm::dvec3& camPos, + double distFromCameraToFocus, + const glm::dvec3& camPosToAnchorPosDiff, + double destination) const +{ + // This factor adapts the velocity so it slows down when getting closer + // to our final destination + double velocity = 0.0; + + if (destination < distFromCameraToFocus) { // When flying towards anchor + velocity = 1.0 - destination / distFromCameraToFocus; + } + else { // When flying away from anchor + velocity = distFromCameraToFocus / destination - 1.0; + } + velocity *= _velocitySensitivity; + + // Return the updated camera position + return camPos - velocity * camPosToAnchorPosDiff; +} + glm::dvec3 OrbitalNavigator::followAnchorNodeRotation(const glm::dvec3& cameraPosition, const glm::dvec3& objectPosition, const glm::dquat& focusNodeRotationDiff) const diff --git a/src/rendering/dashboard.cpp b/src/rendering/dashboard.cpp index 01ac1eb417..f56ceeee88 100644 --- a/src/rendering/dashboard.cpp +++ b/src/rendering/dashboard.cpp @@ -37,6 +37,12 @@ namespace { "If this value is 'false', this dashboard will be invisible, regardless of the " "state of the individual components" }; + constexpr openspace::properties::Property::PropertyInfo StartPositionOffsetInfo = { + "StartPositionOffset", + "Start Position Offset", + "A 2D vector controlling where the dashboard rendering starts." + "Adding an offset in x and y-direction on screen" + }; } // namespace namespace openspace { @@ -44,8 +50,12 @@ namespace openspace { Dashboard::Dashboard() : properties::PropertyOwner({ "Dashboard" }) , _isEnabled(EnabledInfo, true) + , _startPositionOffset( + properties::IVec2Property(StartPositionOffsetInfo, glm::ivec2(10, -10)) + ) { addProperty(_isEnabled); + addProperty(_startPositionOffset); } void Dashboard::addDashboardItem(std::unique_ptr item) { @@ -128,6 +138,10 @@ void Dashboard::render(glm::vec2& penPosition) { } } +glm::vec2 Dashboard::getStartPositionOffset() { + return _startPositionOffset.value(); +}; + scripting::LuaLibrary Dashboard::luaLibrary() { return { "dashboard", diff --git a/src/rendering/renderable.cpp b/src/rendering/renderable.cpp index ac019c4aca..2ef60cb2c2 100644 --- a/src/rendering/renderable.cpp +++ b/src/rendering/renderable.cpp @@ -54,6 +54,12 @@ namespace { openspace::properties::Property::Visibility::Hidden }; + constexpr openspace::properties::Property::PropertyInfo BoundingSphereInfo = { + "BoundingSphere", + "Bounding Sphere", + "The size of the bounding sphere radius." + }; + } // namespace namespace openspace { @@ -109,6 +115,7 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary) , _enabled(EnabledInfo, true) , _opacity(OpacityInfo, 1.f, 0.f, 1.f) , _renderableType(RenderableTypeInfo, "Renderable") + , _boundingSphere(BoundingSphereInfo, 0.f, 0.f, 3e10f) { // I can't come up with a good reason not to do this for all renderables registerUpdateRenderBinFromOpacity(); @@ -144,6 +151,7 @@ Renderable::Renderable(const ghoul::Dictionary& dictionary) _renderableType = dictionary.value(RenderableTypeInfo.identifier); } addProperty(_renderableType); + addProperty(_boundingSphere); } void Renderable::initialize() {} @@ -159,11 +167,12 @@ void Renderable::update(const UpdateData&) {} void Renderable::render(const RenderData&, RendererTasks&) {} void Renderable::setBoundingSphere(float boundingSphere) { - _boundingSphere = boundingSphere; + + _boundingSphere.setValue(boundingSphere); } float Renderable::boundingSphere() const { - return _boundingSphere; + return _boundingSphere.value(); } SurfacePositionHandle Renderable::calculateSurfacePositionHandle( diff --git a/src/rendering/renderengine.cpp b/src/rendering/renderengine.cpp index c6b054b932..212e30ea12 100644 --- a/src/rendering/renderengine.cpp +++ b/src/rendering/renderengine.cpp @@ -793,7 +793,7 @@ void RenderEngine::renderEndscreen() { ); glm::vec2 penPosition = glm::vec2( fontResolution().x / 2 - size.boundingBox.x / 2, - fontResolution().y / 2- size.boundingBox.y / 2 + fontResolution().y / 2 - size.boundingBox.y / 2 ); RenderFont(*_fontDate, penPosition, "Shutting down"); } @@ -836,9 +836,11 @@ void RenderEngine::renderDashboard() { "Main Dashboard::render" ); } + + glm::vec2 dashboardStart = global::dashboard.getStartPositionOffset(); glm::vec2 penPosition = glm::vec2( - 10.f, - fontResolution().y - global::luaConsole.currentHeight() + dashboardStart.x, + dashboardStart.y + fontResolution().y - global::luaConsole.currentHeight() ); global::dashboard.render(penPosition); diff --git a/src/scene/scenegraphnode.cpp b/src/scene/scenegraphnode.cpp index 21b8c06d26..fd9e731817 100644 --- a/src/scene/scenegraphnode.cpp +++ b/src/scene/scenegraphnode.cpp @@ -27,13 +27,14 @@ #include #include #include +#include +#include #include #include #include #include #include #include - #include "scenegraphnode_doc.inl" namespace { @@ -49,8 +50,48 @@ namespace { constexpr const char* KeyTimeFrame = "TimeFrame"; + constexpr openspace::properties::Property::PropertyInfo ComputeScreenSpaceInfo = + { + "ComputeScreenSpaceData", + "Screen Space Data", + "If this value is set to 'true', the screenspace-based properties are calculated " + "at regular intervals. If these values are set to 'false', they are not updated." + }; + + constexpr openspace::properties::Property::PropertyInfo ScreenSpacePositionInfo = { + "ScreenSpacePosition", + "ScreenSpacePosition", + "" // @TODO Missing documentation + }; + constexpr openspace::properties::Property::PropertyInfo ScreenVisibilityInfo = { + "ScreenVisibility", + "ScreenVisibility", + "" // @TODO Missing documentation + }; + constexpr openspace::properties::Property::PropertyInfo DistanceFromCamToNodeInfo = { + "DistanceFromCamToNode", + "DistanceFromCamToNode", + "" // @TODO Missing documentation + }; + constexpr openspace::properties::Property::PropertyInfo ScreenSizeRadiusInfo = { + "ScreenSizeRadius", + "ScreenSizeRadius", + "" // @TODO Missing documentation + }; + constexpr openspace::properties::Property::PropertyInfo VisibilityDistanceInfo = { + "VisibilityDistance", + "VisibilityDistance", + "" // @TODO Missing documentation + }; constexpr const char* KeyFixedBoundingSphere = "FixedBoundingSphere"; + constexpr openspace::properties::Property::PropertyInfo BoundingSphereInfo = { + "BoundingSphere", + "Bounding Sphere", + "The bounding sphere of the scene graph node. This can be the " + "bounding sphere of a renderable or a fixed bounding sphere. " + }; + constexpr openspace::properties::Property::PropertyInfo GuiPathInfo = { "GuiPath", "Gui Path", @@ -235,6 +276,8 @@ std::unique_ptr SceneGraphNode::createFromDictionary( } LDEBUG(fmt::format("Successfully created SceneGraphNode '{}'", result->identifier())); + + result->_lastScreenSpaceUpdateTime = std::chrono::high_resolution_clock::now(); return result; } @@ -248,7 +291,22 @@ SceneGraphNode::SceneGraphNode() std::make_unique(), std::make_unique() } -{} + , _computeScreenSpaceValues(ComputeScreenSpaceInfo, false) + , _screenSpacePosition( + properties::IVec2Property(ScreenSpacePositionInfo, glm::ivec2(-1, -1)) + ) + , _screenVisibility(properties::BoolProperty(ScreenVisibilityInfo, false)) + , _distFromCamToNode(properties::DoubleProperty(DistanceFromCamToNodeInfo, -1.0)) + , _screenSizeRadius(properties::DoubleProperty(ScreenSizeRadiusInfo, 0)) + , _visibilityDistance(properties::FloatProperty(VisibilityDistanceInfo, 6e10f)) +{ + addProperty(_computeScreenSpaceValues); + addProperty(_screenSpacePosition); + addProperty(_screenVisibility); + addProperty(_distFromCamToNode); + addProperty(_screenSizeRadius); + addProperty(_visibilityDistance); +} SceneGraphNode::~SceneGraphNode() {} // NOLINT @@ -455,6 +513,9 @@ void SceneGraphNode::render(const RenderData& data, RendererTasks& tasks) { auto start = std::chrono::high_resolution_clock::now(); _renderable->render(newData, tasks); + if (_computeScreenSpaceValues) { + computeScreenSpaceData(newData); + } glFinish(); auto end = std::chrono::high_resolution_clock::now(); @@ -462,6 +523,9 @@ void SceneGraphNode::render(const RenderData& data, RendererTasks& tasks) { } else { _renderable->render(newData, tasks); + if (_computeScreenSpaceValues) { + computeScreenSpaceData(newData); + } } } @@ -595,6 +659,86 @@ void SceneGraphNode::setDependencies(const std::vector& depende } } +void SceneGraphNode::computeScreenSpaceData(RenderData& newData) { + // Purposely slow the update rate of screen space position in order to reduce the + // effects of jittering in the position of information icon markers in web gui. + auto now = std::chrono::high_resolution_clock::now(); + if ((now - _lastScreenSpaceUpdateTime) < std::chrono::milliseconds(100)) { + return; + } + _lastScreenSpaceUpdateTime = now; + + // Calculate ndc + const Camera& cam = newData.camera; + const glm::dvec3& worldPos = _worldPositionCached; + const glm::dvec4 clipSpace = glm::dmat4(cam.projectionMatrix()) * + cam.combinedViewMatrix() * glm::vec4(worldPos, 1.0); + const glm::dvec2 worldPosNDC = glm::dvec2(clipSpace / clipSpace.w); + + const bool visible = worldPosNDC.x >= -1.0 && worldPosNDC.x <= 1.0 && + worldPosNDC.y >= -1.0 && worldPosNDC.y <= 1.0 && clipSpace.z > 0; + + // If not on the screen, we want to reset it or don't update it + if (!visible) { + _screenVisibility = false; + return; + } + + glm::ivec2 res = global::windowDelegate.currentWindowSize(); + + // Get the radius of node + double nodeRadius = static_cast(this->boundingSphere()); + + // Distance from the camera to the node + double distFromCamToNode = glm::distance(cam.positionVec3(), worldPos) - nodeRadius; + + // Fix to limit the update of properties + if (distFromCamToNode >= _visibilityDistance) { + _screenVisibility = false; + return; + } + + _screenVisibility = true; + + // Calculate the node radius to screensize pixels + const glm::dvec3 lookUp = normalize(cam.lookUpVectorWorldSpace()); + const glm::dvec3 radiusPos = worldPos + (nodeRadius * lookUp); + const glm::dvec4 clipSpaceRadius = glm::dmat4(cam.projectionMatrix()) * + cam.combinedViewMatrix() * glm::vec4(radiusPos, 1.0); + const glm::dvec3 radiusNDC = clipSpaceRadius / clipSpaceRadius.w; + + const glm::ivec2 centerScreenSpace = glm::ivec2( + (worldPosNDC.x + 1.0) * res.x / 2, + (worldPosNDC.y + 1.0) * res.y / 2 + ); + const glm::ivec2 radiusScreenSpace = glm::ivec2( + (radiusNDC.x + 1.0) * res.x / 2, + (radiusNDC.y + 1.0) * res.y / 2 + ); + const double screenSpaceRadius = length( + glm::vec2(centerScreenSpace) - glm::vec2(radiusScreenSpace) + ); + + constexpr const double RadiusThreshold = 2.0; + const double r = abs(_screenSizeRadius - screenSpaceRadius); + if (r > RadiusThreshold) { + _screenSizeRadius = screenSpaceRadius; + } + + constexpr const double ZoomThreshold = 0.1; + const double d = abs(_distFromCamToNode - distFromCamToNode); + if (d > (ZoomThreshold * distFromCamToNode)) { + _distFromCamToNode = distFromCamToNode; + } + + constexpr const double MoveThreshold = 1.0; + const glm::ivec2 ssp = _screenSpacePosition; + const glm::dvec2 c = glm::abs(ssp - centerScreenSpace); + if (c.x > MoveThreshold || c.y > MoveThreshold) { + _screenSpacePosition = centerScreenSpace; + } +} + SurfacePositionHandle SceneGraphNode::calculateSurfacePositionHandle( const glm::dvec3& targetModelSpace) const { @@ -765,13 +909,13 @@ Renderable* SceneGraphNode::renderable() { return _renderable.get(); } -SceneGraphNode* SceneGraphNode::childNode(const std::string& identifier) { - if (this->identifier() == identifier) { +SceneGraphNode* SceneGraphNode::childNode(const std::string& id) { + if (identifier() == id) { return this; } else { for (std::unique_ptr& it : _children) { - SceneGraphNode* tmp = it->childNode(identifier); + SceneGraphNode* tmp = it->childNode(id); if (tmp) { return tmp; }