mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-07 04:00:37 -06:00
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.
This commit is contained in:
@@ -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()
|
||||
|
||||
|
||||
@@ -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`
|
||||
-- 4) Within the repository, run `npm install` and `npm start`
|
||||
|
||||
48
data/assets/gui/images.asset
Normal file
48
data/assets/gui/images.asset
Normal file
@@ -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
|
||||
})
|
||||
@@ -20,10 +20,6 @@ local Charon = {
|
||||
Type = "SpiceRotation",
|
||||
SourceFrame = "IAU_CHARON",
|
||||
DestinationFrame = "GALACTIC"
|
||||
},
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
Scale = 1.0
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
|
||||
@@ -20,10 +20,6 @@ local Pluto = {
|
||||
Type = "SpiceRotation",
|
||||
SourceFrame = "IAU_PLUTO",
|
||||
DestinationFrame = "GALACTIC"
|
||||
},
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
Scale = 1.0
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
|
||||
@@ -46,10 +46,6 @@ local PlutoProjection = {
|
||||
Type = "SpiceRotation",
|
||||
SourceFrame = "IAU_PLUTO",
|
||||
DestinationFrame = "GALACTIC"
|
||||
},
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
Scale = 1.0
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -29,7 +29,7 @@ local Io = {
|
||||
Target = "IO",
|
||||
Observer = "JUPITER BARYCENTER",
|
||||
Kernels = kernel
|
||||
},
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
Type = "RenderableGlobe",
|
||||
|
||||
@@ -20,10 +20,6 @@ local Jupiter = {
|
||||
Type = "SpiceRotation",
|
||||
SourceFrame = "IAU_JUPITER",
|
||||
DestinationFrame = "GALACTIC"
|
||||
},
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
Scale = 1.0
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
|
||||
@@ -153,10 +153,6 @@ local Mars = {
|
||||
Type = "SpiceRotation",
|
||||
SourceFrame = "IAU_MARS",
|
||||
DestinationFrame = "GALACTIC"
|
||||
},
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
Scale = 1.0
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
|
||||
@@ -189,10 +189,6 @@ local Mercury = {
|
||||
Type = "SpiceRotation",
|
||||
SourceFrame = "IAU_MERCURY",
|
||||
DestinationFrame = "GALACTIC"
|
||||
},
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
Scale = 1.0
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
|
||||
@@ -18,10 +18,6 @@ local Neptune = {
|
||||
Type = "SpiceRotation",
|
||||
SourceFrame = "IAU_NEPTUNE",
|
||||
DestinationFrame = "GALACTIC"
|
||||
},
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
Scale = 1.0
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
|
||||
@@ -20,10 +20,6 @@ local Saturn = {
|
||||
Type = "SpiceRotation",
|
||||
SourceFrame = "IAU_SATURN",
|
||||
DestinationFrame = "GALACTIC"
|
||||
},
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
Scale = 1.0
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
|
||||
@@ -20,10 +20,6 @@ local Uranus = {
|
||||
Type = "SpiceRotation",
|
||||
SourceFrame = "IAU_URANUS",
|
||||
DestinationFrame = "GALACTIC"
|
||||
},
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
Scale = 1.0
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
|
||||
@@ -26,10 +26,6 @@ local Venus = {
|
||||
Type = "SpiceTranslation",
|
||||
Target = "VENUS",
|
||||
Observer = "VENUS BARYCENTER"
|
||||
},
|
||||
Scale = {
|
||||
Type = "StaticScale",
|
||||
Scale = 1.0
|
||||
}
|
||||
},
|
||||
Renderable = {
|
||||
|
||||
37
data/assets/touch.scene
Normal file
37
data/assets/touch.scene
Normal file
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include <openspace/properties/propertyowner.h>
|
||||
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/vector/ivec2property.h>
|
||||
#include <openspace/rendering/dashboarditem.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <memory>
|
||||
@@ -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<std::unique_ptr<DashboardItem>> _items;
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -29,12 +29,16 @@
|
||||
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/doubleproperty.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
#include <openspace/properties/vector/ivec2property.h>
|
||||
#include <ghoul/glm.h>
|
||||
#include <ghoul/misc/boolean.h>
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
//#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 = State::Loaded;
|
||||
std::vector<std::unique_ptr<SceneGraphNode>> _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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -440,6 +440,7 @@ void DashboardItemDistance::render(glm::vec2& penPosition) {
|
||||
}
|
||||
|
||||
penPosition.y -= _font->height();
|
||||
|
||||
RenderFont(
|
||||
*_font,
|
||||
penPosition,
|
||||
|
||||
@@ -52,6 +52,8 @@ public:
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
bool storyStyleActive();
|
||||
|
||||
private:
|
||||
enum Type {
|
||||
Node = 0,
|
||||
|
||||
@@ -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]() {
|
||||
|
||||
@@ -160,21 +160,21 @@ void CefWebGuiModule::internalInitialize(const ghoul::Dictionary& configuration)
|
||||
}
|
||||
});
|
||||
|
||||
if (configuration.hasValue<std::string>(GuiUrlInfo.identifier)) {
|
||||
_url = configuration.value<std::string>(GuiUrlInfo.identifier);
|
||||
} else {
|
||||
WebGuiModule* webGuiModule = global::moduleEngine.module<WebGuiModule>();
|
||||
_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<WebGuiModule>();
|
||||
|
||||
_endpointCallback = webGuiModule->addEndpointChangeCallback(
|
||||
[this](const std::string& endpoint, bool exists) {
|
||||
if (exists && endpoint == "frontend" && _instance) {
|
||||
_instance->reloadBrowser();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
if (configuration.hasValue<float>(GuiScaleInfo.identifier)) {
|
||||
_guiScale = configuration.value<float>(GuiScaleInfo.identifier);
|
||||
|
||||
@@ -333,4 +333,4 @@ openspace.globebrowsing.loadWMSServersFromFile = function (file_path)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
#include <openspace/properties/scalar/doubleproperty.h>
|
||||
#include <openspace/properties/scalar/intproperty.h>
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/vector/ivec2property.h>
|
||||
@@ -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;
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
#include <ghoul/misc/invariants.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <openspace/util/camera.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
|
||||
#include <glm/gtx/quaternion.hpp>
|
||||
|
||||
@@ -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<double>::max(), 1000.0f, std::numeric_limits<double>::max())
|
||||
, _zoomInLimit(ZoomInLimitInfo, -1.0f, 0.0f, std::numeric_limits<double>::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<TuioCursor>& 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<ImGUIModule>()->touchInput = {
|
||||
true,
|
||||
glm::dvec2(0.0, 0.0),
|
||||
@@ -1130,7 +1152,8 @@ void TouchInteraction::computeVelocities(const std::vector<TuioCursor>& list,
|
||||
static_cast<float>(_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("");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ void TouchMarker::render(const std::vector<TUIO::TuioCursor>& 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<int>(_vertexData.size() / 2));
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -27,10 +27,10 @@
|
||||
|
||||
#include <openspace/util/openspacemodule.h>
|
||||
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/stringlistproperty.h>
|
||||
#include <openspace/properties/scalar/intproperty.h>
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/intproperty.h>
|
||||
#include <ghoul/misc/process.h>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 " ..
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/interaction/orbitalnavigator.h>
|
||||
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <openspace/query/query.h>
|
||||
@@ -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<double>(_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<float>(_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
|
||||
|
||||
@@ -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<DashboardItem> item) {
|
||||
@@ -128,6 +138,10 @@ void Dashboard::render(glm::vec2& penPosition) {
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec2 Dashboard::getStartPositionOffset() {
|
||||
return _startPositionOffset.value();
|
||||
};
|
||||
|
||||
scripting::LuaLibrary Dashboard::luaLibrary() {
|
||||
return {
|
||||
"dashboard",
|
||||
|
||||
@@ -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<std::string>(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(
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -27,13 +27,14 @@
|
||||
#include <modules/base/scale/staticscale.h>
|
||||
#include <modules/base/rotation/staticrotation.h>
|
||||
#include <modules/base/translation/statictranslation.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/rendering/renderable.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
#include <openspace/scene/timeframe.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/opengl/ghoul_gl.h>
|
||||
|
||||
#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> 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<StaticRotation>(),
|
||||
std::make_unique<StaticScale>()
|
||||
}
|
||||
{}
|
||||
, _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<SceneGraphNode*>& 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<double>(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<SceneGraphNode>& it : _children) {
|
||||
SceneGraphNode* tmp = it->childNode(identifier);
|
||||
SceneGraphNode* tmp = it->childNode(id);
|
||||
if (tmp) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user