mirror of
https://github.com/OpenSpace/OpenSpace.git
synced 2026-01-07 04:00:37 -06:00
Fixed failed merging of master.
This commit is contained in:
1
apps/OpenSpace-MinVR/ext/glfw
Submodule
1
apps/OpenSpace-MinVR/ext/glfw
Submodule
Submodule apps/OpenSpace-MinVR/ext/glfw added at 7ef34eb06d
@@ -200,7 +200,6 @@ void Handler::onVREvent(const VRDataIndex& eventData) {
|
||||
if (button == MouseButton::Right && action == MouseAction::Press) {
|
||||
windowingGlobals.mouseButtons |= 1 << 2;
|
||||
}
|
||||
|
||||
using KM = KeyModifier;
|
||||
KM mod = KM::NoModifier;
|
||||
mod |= keyboardState.modifierShift ? KM::Shift : KM::NoModifier;
|
||||
|
||||
Submodule apps/OpenSpace/ext/sgct updated: 99e5595539...25c8d30bde
@@ -1,9 +1,10 @@
|
||||
asset.require('./base')
|
||||
|
||||
local earthAsset = asset.require('scene/solarsystem/planets/earth/earth')
|
||||
|
||||
asset.onInitialize(function ()
|
||||
local now = openspace.time.currentWallTime()
|
||||
-- Jump back one day to show a complete planet
|
||||
-- Jump back one day to be able to show complete weather data on Earth.
|
||||
openspace.time.setTime(openspace.time.advancedTime(now, "-1d"))
|
||||
|
||||
openspace.globebrowsing.goToGeo("Earth", 58.5877, 16.1924, 20000000)
|
||||
|
||||
10
data/assets/examples/screenspacebrowser.asset
Normal file
10
data/assets/examples/screenspacebrowser.asset
Normal file
@@ -0,0 +1,10 @@
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
|
||||
local spec = {
|
||||
Type = "ScreenSpaceBrowser",
|
||||
Identifier = "ScreenSpaceBrowserExample",
|
||||
Name = "Screen Space Browser Example",
|
||||
Url = "https://www.openspaceproject.com/"
|
||||
};
|
||||
|
||||
assetHelper.registerScreenSpaceRenderables(asset, { spec })
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,74 @@
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
local sunTransforms = asset.require('scene/solarsystem/sun/transforms')
|
||||
local kernelsFolder = asset.syncedResource({
|
||||
Name = "Apollo Kernels",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "apollo_spice",
|
||||
Version = 1
|
||||
})
|
||||
|
||||
local kernels = {
|
||||
kernelsFolder .. "/moon_080317.tf",
|
||||
kernelsFolder .. "/apollo8.tf",
|
||||
kernelsFolder .. "/moon_pa_de421_1900-2050.bpc",
|
||||
kernelsFolder .. '/apollo8.tsc',
|
||||
kernelsFolder .. '/apollo8.bsp',
|
||||
kernelsFolder .. '/apollo8_earthrise.bc',
|
||||
}
|
||||
|
||||
local apolloSpiceId = "-908"
|
||||
|
||||
|
||||
local Apollo8LaunchTrail = {
|
||||
Identifier = "Apollo8LaunchTrail",
|
||||
Parent = "Earth",
|
||||
Renderable = {
|
||||
Type = "RenderableTrailTrajectory",
|
||||
Translation = {
|
||||
Type = "SpiceTranslation",
|
||||
Target = apolloSpiceId,
|
||||
Observer = "EARTH",
|
||||
Frame = "IAU_EARTH",
|
||||
Kernels = kernels
|
||||
},
|
||||
Color = { 0.70, 0.50, 0.20 },
|
||||
StartTime = "1968 DEC 21 12:51:00",
|
||||
EndTime = "1968 DEC 21 23:23:22",
|
||||
SampleInterval = 30
|
||||
},
|
||||
GUI = {
|
||||
Name = "Apollo 8 Launch Trail",
|
||||
Path = "/Solar System/Missions/Apollo"
|
||||
}
|
||||
}
|
||||
|
||||
local Apollo8EarthBarycenterTrail = {
|
||||
Identifier = "Apollo8EarthBarycenterTrail",
|
||||
Parent = "EarthBarycenter",
|
||||
Renderable = {
|
||||
Type = "RenderableTrailTrajectory",
|
||||
Translation = {
|
||||
Type = "SpiceTranslation",
|
||||
Target = apolloSpiceId,
|
||||
Observer = "EARTH BARYCENTER",
|
||||
Frame = "GALACTIC",
|
||||
Kernels = kernels
|
||||
},
|
||||
Color = { 1, 0.0, 0.0 },
|
||||
StartTime = "1968 DEC 21",
|
||||
EndTime = "1968 DEC 28",
|
||||
SampleInterval = 30,
|
||||
Enabled = false,
|
||||
},
|
||||
GUI = {
|
||||
Name = "Apollo 8 Earth Barycenter Trail",
|
||||
Path = "/Solar System/Missions/Apollo"
|
||||
}
|
||||
}
|
||||
|
||||
local exportList = {
|
||||
Apollo8LaunchTrail,
|
||||
Apollo8EarthBarycenterTrail,
|
||||
}
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, exportList)
|
||||
@@ -0,0 +1,120 @@
|
||||
-- Apollo mission insignias on their locations on the Lunar surface.
|
||||
-- The insignias are invisible by default, but can be enabled using shown or hidden using
|
||||
-- the exported functions `showInsignias(interpolationDuration)` and `hideInsignias(interpolationDuration)`.
|
||||
|
||||
local assetHelper = asset.require('util/asset_helper')
|
||||
|
||||
local insigniasPath = asset.syncedResource({
|
||||
Name = "Apollo Insignias",
|
||||
Type = "HttpSynchronization",
|
||||
Identifier = "apollo_insignias",
|
||||
Version = 1
|
||||
})
|
||||
local moon = asset.require('scene/solarsystem/planets/earth/moon/moon')
|
||||
|
||||
local landingData = {
|
||||
{
|
||||
Identifier = "Apollo11",
|
||||
Name = "Apollo 11",
|
||||
Name = "Apollo 11",
|
||||
Texture = "apollo11.png",
|
||||
LunarModule = {0.67409, 23.47298, 0.0},
|
||||
},
|
||||
{
|
||||
Identifier = "Apollo12",
|
||||
Name = "Apollo 12",
|
||||
Texture = "apollo12.png",
|
||||
LunarModule = {-3.01381, -23.41930, 0.0}
|
||||
},
|
||||
{
|
||||
Identifier = "Apollo14",
|
||||
Name = "Apollo 14",
|
||||
Texture = "apollo14.png",
|
||||
LunarModule = {-3.64544, -17.47139, 0.0}
|
||||
},
|
||||
{
|
||||
Identifier = "Apollo15",
|
||||
Name = "Apollo 15",
|
||||
Texture = "apollo15.png",
|
||||
LunarModule = {26.13224, 3.63400, 0.0}
|
||||
},
|
||||
{
|
||||
Identifier = "Apollo16",
|
||||
Name = "Apollo 16",
|
||||
Texture = "apollo16.png",
|
||||
LunarModule = {-8.97341, 15.49859, 0.0}
|
||||
},
|
||||
{
|
||||
Identifier = "Apollo17",
|
||||
Name = "Apollo 17",
|
||||
Texture = "apollo17.png",
|
||||
LunarModule = {20.18809, 30.77475, 0.0}
|
||||
}
|
||||
}
|
||||
|
||||
local nodes = {}
|
||||
local size = 100000;
|
||||
|
||||
for i = 1, #landingData do
|
||||
local entry = landingData[i]
|
||||
nodes[i] = {
|
||||
Identifier = entry.Identifier .. "Insignia",
|
||||
Parent = moon.Moon.Identifier,
|
||||
Transform = {
|
||||
Translation = {
|
||||
Type = "GlobeTranslation",
|
||||
Globe = moon.Moon.Identifier,
|
||||
Latitude = entry.LunarModule[1],
|
||||
Longitude = entry.LunarModule[2],
|
||||
Altitude = entry.LunarModule[3] + size * 1.1,
|
||||
UseHeightmap = false
|
||||
},
|
||||
},
|
||||
Renderable = {
|
||||
Type = "RenderablePlaneImageLocal",
|
||||
Size = size,
|
||||
Origin = "Center",
|
||||
Billboard = true,
|
||||
Texture = insigniasPath .. "/" .. entry.Texture,
|
||||
Opacity = 0.0
|
||||
},
|
||||
GUI = {
|
||||
Path = "/Other/Labels",
|
||||
Name = entry.Name .. " Insignia"
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
asset.onInitialize(function ()
|
||||
openspace.bindShortcut(
|
||||
'Show Apollo Landing Labels',
|
||||
'openspace.setPropertyValue("Scene.Apollo*Insignia.Renderable.Opacity", 1, 0.5)',
|
||||
'Show patches of the Apollo missions on their respective landing sites',
|
||||
'/Missions/Apollo'
|
||||
)
|
||||
|
||||
openspace.bindShortcut(
|
||||
'Hide Apollo Landing Labels',
|
||||
'openspace.setPropertyValue("Scene.Apollo*Insignia.Renderable.Opacity", 0, 0.5)',
|
||||
'Hide patches of the Apollo missions on their respective landing sites',
|
||||
'/Missions/Apollo'
|
||||
)
|
||||
end)
|
||||
|
||||
asset.export('showInsignia', function (missinNumber, interpolationDuration)
|
||||
openspace.setPropertyValue("Scene.Apollo" .. missionNumber .. "Insignia.Renderable.Opacity", 1, interpolationDuration)
|
||||
end)
|
||||
|
||||
asset.export('hideInsignia', function (missinNumber, interpolationDuration)
|
||||
openspace.setPropertyValue("Scene.Apollo" .. missionNumber .. "Insignia.Renderable.Opacity", 0, interpolationDuration)
|
||||
end)
|
||||
|
||||
asset.export('showInsignias', function (interpolationDuration)
|
||||
openspace.setPropertyValue("Scene.Apollo*Insignia.Renderable.Opacity", 1, interpolationDuration)
|
||||
end)
|
||||
|
||||
asset.export('hideInsignias', function (interpolationDuration)
|
||||
openspace.setPropertyValue("Scene.Apollo*Insignia.Renderable.Opacity", 0, interpolationDuration)
|
||||
end)
|
||||
|
||||
assetHelper.registerSceneGraphNodesAndExport(asset, nodes)
|
||||
@@ -25,6 +25,7 @@ local color_layers = {
|
||||
FilePath = mapServiceConfigs .. "/Utah/Mars_Color.wms",
|
||||
Enabled = true,
|
||||
Fallback = {
|
||||
Identifier = "Mars_Texture",
|
||||
Name = "Mars Texture",
|
||||
FilePath = textures .. "/mars.jpg",
|
||||
Enabled = true
|
||||
@@ -35,6 +36,7 @@ local color_layers = {
|
||||
Name = "MOC WA Color [Sweden]",
|
||||
FilePath = mapServiceConfigs .. "/LiU/Color.wms",
|
||||
Fallback = {
|
||||
Identifier = "Mars_Texture",
|
||||
Name = "Mars Texture",
|
||||
FilePath = textures .. "/mars.jpg",
|
||||
Enabled = true
|
||||
|
||||
18
data/assets/util/ipac.asset
Normal file
18
data/assets/util/ipac.asset
Normal file
@@ -0,0 +1,18 @@
|
||||
asset.onInitialize(function()
|
||||
openspace.clearKeys()
|
||||
openspace.bindKey("RIGHT", "openspace.navigation.addGlobalRotation(-5.0, 0.0)");
|
||||
openspace.bindKey("LEFT", "openspace.navigation.addGlobalRotation(5.0, 0.0)");
|
||||
openspace.bindKey("UP", "openspace.navigation.addGlobalRotation(0.0, 5.0)");
|
||||
openspace.bindKey("DOWN", "openspace.navigation.addGlobalRotation(0.0, -5.0)");
|
||||
|
||||
openspace.bindKey("CTRL+RIGHT", "openspace.navigation.addLocalRotation(-5.0, 0.0)");
|
||||
openspace.bindKey("CTRL+LEFT", "openspace.navigation.addLocalRotation(5.0, 0.0)");
|
||||
openspace.bindKey("CTRL+UP", "openspace.navigation.addLocalRotation(0.0, 5.0)");
|
||||
openspace.bindKey("CTRL+DOWN", "openspace.navigation.addLocalRotation(0.0, -5.0)");
|
||||
|
||||
openspace.bindKey("ALT+UP", "openspace.navigation.addTruckMovement(0.0, 5.0)");
|
||||
openspace.bindKey("ALT+DOWN", "openspace.navigation.addTruckMovement(0.0, -5.0)");
|
||||
|
||||
openspace.bindKey("SPACE", "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'Moon');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);")
|
||||
openspace.bindKey("Z", "openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Aim', '');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.Anchor', 'Earth');openspace.setPropertyValueSingle('NavigationHandler.OrbitalNavigator.RetargetAnchor', nil);")
|
||||
end)
|
||||
21
data/assets/util/static_server.asset
Normal file
21
data/assets/util/static_server.asset
Normal file
@@ -0,0 +1,21 @@
|
||||
local backendHash = "7ca0a34e9c4c065b7bfad0623db0e322bf3e0af9"
|
||||
local dataProvider = "data.openspaceproject.com/files/webgui"
|
||||
|
||||
local backend = asset.syncedResource({
|
||||
Identifier = "WebGuiBackend",
|
||||
Name = "Web Gui Backend",
|
||||
Type = "UrlSynchronization",
|
||||
Url = dataProvider .. "/backend/" .. backendHash .. "/backend.zip"
|
||||
})
|
||||
|
||||
asset.onInitialize(function ()
|
||||
-- Unzip the server bundle
|
||||
dest = backend .. "/backend"
|
||||
if not openspace.directoryExists(dest) then
|
||||
openspace.unzipFile(backend .. "/backend.zip", dest, true)
|
||||
end
|
||||
|
||||
openspace.setPropertyValueSingle(
|
||||
"Modules.WebGui.ServerProcessEntryPoint", backend .. "/backend/backend.js"
|
||||
)
|
||||
end)
|
||||
Submodule ext/ghoul updated: cf5b311dda...526b27cb65
22555
ext/json/json.hpp
22555
ext/json/json.hpp
File diff suppressed because it is too large
Load Diff
@@ -57,7 +57,6 @@ struct TestResult {
|
||||
*/
|
||||
enum class Reason {
|
||||
MissingKey, ///< The offending key that was requested was not found
|
||||
ExtraKey, ///< The exhaustive documentation contained an extra key
|
||||
WrongType, ///< The key's value was not of the expected type
|
||||
Verification, ///< The value did not pass a necessary non-type verifier
|
||||
UnknownIdentifier ///< The identifier for a ReferencingVerifier did not exist
|
||||
|
||||
@@ -52,6 +52,7 @@ struct WindowDelegate;
|
||||
namespace configuration { struct Configuration; }
|
||||
namespace interaction {
|
||||
struct JoystickInputStates;
|
||||
struct WebsocketInputStates;
|
||||
class KeybindingManager;
|
||||
class NavigationHandler;
|
||||
class SessionRecording;
|
||||
@@ -87,6 +88,7 @@ VirtualPropertyManager& gVirtualPropertyManager();
|
||||
WindowDelegate& gWindowDelegate();
|
||||
configuration::Configuration& gConfiguration();
|
||||
interaction::JoystickInputStates& gJoystickInputStates();
|
||||
interaction::WebsocketInputStates& gWebsocketInputStates();
|
||||
interaction::KeybindingManager& gKeybindingManager();
|
||||
interaction::NavigationHandler& gNavigationHandler();
|
||||
interaction::SessionRecording& gSessionRecording();
|
||||
@@ -120,6 +122,8 @@ static WindowDelegate& windowDelegate = detail::gWindowDelegate();
|
||||
static configuration::Configuration& configuration = detail::gConfiguration();
|
||||
static interaction::JoystickInputStates& joystickInputStates =
|
||||
detail::gJoystickInputStates();
|
||||
static interaction::WebsocketInputStates& websocketInputStates =
|
||||
detail::gWebsocketInputStates();
|
||||
static interaction::KeybindingManager& keybindingManager = detail::gKeybindingManager();
|
||||
static interaction::NavigationHandler& navigationHandler = detail::gNavigationHandler();
|
||||
static interaction::SessionRecording& sessionRecording = detail::gSessionRecording();
|
||||
|
||||
@@ -109,6 +109,7 @@ private:
|
||||
|
||||
std::unique_ptr<Scene> _scene;
|
||||
std::unique_ptr<AssetManager> _assetManager;
|
||||
bool _shouldAbortLoading = false;
|
||||
std::unique_ptr<LoadingScreen> _loadingScreen;
|
||||
std::unique_ptr<VersionChecker> _versionChecker;
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#ifndef __OPENSPACE_CORE___INPUTSTATE___H__
|
||||
#define __OPENSPACE_CORE___INPUTSTATE___H__
|
||||
|
||||
#include <openspace/interaction/websocketinputstate.h>
|
||||
#include <openspace/util/keys.h>
|
||||
#include <openspace/util/mouse.h>
|
||||
#include <ghoul/glm.h>
|
||||
@@ -33,6 +34,7 @@
|
||||
namespace openspace::interaction {
|
||||
|
||||
struct JoystickInputStates;
|
||||
struct WebsocketInputStates;
|
||||
|
||||
// This class represents the global input state of interaction devices
|
||||
class InputState {
|
||||
@@ -56,6 +58,12 @@ public:
|
||||
float joystickAxis(int i) const;
|
||||
bool joystickButton(int i) const;
|
||||
|
||||
WebsocketInputStates& websocketInputStates();
|
||||
float websocketAxis(int i) const;
|
||||
bool websocketButton(int i) const;
|
||||
bool hasWebsocketStates() const;
|
||||
void resetWebsockets();
|
||||
|
||||
private:
|
||||
// Input from keyboard
|
||||
std::vector<std::pair<Key, KeyModifier>> _keysDown;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <openspace/interaction/orbitalnavigator.h>
|
||||
#include <openspace/interaction/keyframenavigator.h>
|
||||
#include <openspace/properties/propertyowner.h>
|
||||
#include <openspace/interaction/websocketcamerastates.h>
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/util/mouse.h>
|
||||
@@ -47,6 +48,7 @@ namespace openspace::scripting { struct LuaLibrary; }
|
||||
namespace openspace::interaction {
|
||||
|
||||
struct JoystickInputStates;
|
||||
struct WebsocketInputStates;
|
||||
class KeyframeNavigator;
|
||||
class OrbitalNavigator;
|
||||
|
||||
@@ -122,9 +124,16 @@ public:
|
||||
void clearJoystickButtonCommand(int button);
|
||||
std::vector<std::string> joystickButtonCommand(int button) const;
|
||||
|
||||
// Websockets
|
||||
void setWebsocketAxisMapping(int axis, WebsocketCameraStates::AxisType mapping,
|
||||
WebsocketCameraStates::AxisInvert shouldInvert =
|
||||
WebsocketCameraStates::AxisInvert::No,
|
||||
WebsocketCameraStates::AxisNormalize shouldNormalize =
|
||||
WebsocketCameraStates::AxisNormalize::No);
|
||||
|
||||
NavigationState navigationState(const SceneGraphNode& referenceFrame) const;
|
||||
|
||||
void saveNavigationState(const std::string& filepath,
|
||||
void saveNavigationState(const std::string& filepath,
|
||||
const std::string& referenceFrameIdentifier);
|
||||
|
||||
void loadNavigationState(const std::string& filepath);
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include <openspace/interaction/interpolator.h>
|
||||
#include <openspace/interaction/joystickcamerastates.h>
|
||||
#include <openspace/interaction/mousecamerastates.h>
|
||||
#include <openspace/interaction/scriptcamerastates.h>
|
||||
#include <openspace/interaction/websocketcamerastates.h>
|
||||
#include <openspace/properties/stringproperty.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
@@ -74,6 +76,12 @@ public:
|
||||
|
||||
JoystickCameraStates& joystickStates();
|
||||
const JoystickCameraStates& joystickStates() const;
|
||||
|
||||
WebsocketCameraStates& websocketStates();
|
||||
const WebsocketCameraStates& websocketStates() const;
|
||||
|
||||
ScriptCameraStates& scriptStates();
|
||||
const ScriptCameraStates& scriptStates() const;
|
||||
|
||||
bool followingNodeRotation() const;
|
||||
const SceneGraphNode* anchorNode() const;
|
||||
@@ -135,6 +143,7 @@ private:
|
||||
|
||||
properties::FloatProperty _mouseSensitivity;
|
||||
properties::FloatProperty _joystickSensitivity;
|
||||
properties::FloatProperty _websocketSensitivity;
|
||||
|
||||
properties::BoolProperty _useAdaptiveStereoscopicDepth;
|
||||
properties::FloatProperty _stereoscopicDepthOfFocusSurface;
|
||||
@@ -146,6 +155,8 @@ private:
|
||||
|
||||
MouseCameraStates _mouseStates;
|
||||
JoystickCameraStates _joystickStates;
|
||||
WebsocketCameraStates _websocketStates;
|
||||
ScriptCameraStates _scriptStates;
|
||||
|
||||
const SceneGraphNode* _anchorNode = nullptr;
|
||||
const SceneGraphNode* _aimNode = nullptr;
|
||||
|
||||
54
include/openspace/interaction/scriptcamerastates.h
Normal file
54
include/openspace/interaction/scriptcamerastates.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2019 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_CORE___SCRIPTCAMERASTATES___H__
|
||||
#define __OPENSPACE_CORE___SCRIPTCAMERASTATES___H__
|
||||
|
||||
#include <openspace/interaction/camerainteractionstates.h>
|
||||
|
||||
namespace openspace::interaction {
|
||||
|
||||
class ScriptCameraStates : public CameraInteractionStates {
|
||||
public:
|
||||
ScriptCameraStates();
|
||||
|
||||
void updateStateFromInput(const InputState& inputState, double deltaTime) override;
|
||||
|
||||
void addLocalRotation(const glm::dvec2& delta);
|
||||
void addGlobalRotation(const glm::dvec2& delta);
|
||||
void addTruckMovement(const glm::dvec2& delta);
|
||||
void addLocalRoll(const glm::dvec2& delta);
|
||||
void addGlobalRoll(const glm::dvec2& delta);
|
||||
|
||||
private:
|
||||
glm::dvec2 _localRotation;
|
||||
glm::dvec2 _globalRotation;
|
||||
glm::dvec2 _truckMovement;
|
||||
glm::dvec2 _localRoll;
|
||||
glm::dvec2 _globalRoll;
|
||||
};
|
||||
|
||||
} // namespace openspace::interaction
|
||||
|
||||
#endif // __OPENSPACE_CORE___SCRIPTCAMERASTATES___H__
|
||||
117
include/openspace/interaction/websocketcamerastates.h
Normal file
117
include/openspace/interaction/websocketcamerastates.h
Normal file
@@ -0,0 +1,117 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2019 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_CORE___WEBSOCKETCAMERASTATES___H__
|
||||
#define __OPENSPACE_CORE___WEBSOCKETCAMERASTATES___H__
|
||||
|
||||
#include <openspace/interaction/camerainteractionstates.h>
|
||||
|
||||
#include <openspace/interaction/websocketinputstate.h>
|
||||
#include <ghoul/misc/boolean.h>
|
||||
#include <ghoul/misc/stringconversion.h>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace openspace::interaction {
|
||||
|
||||
class WebsocketCameraStates : public CameraInteractionStates {
|
||||
public:
|
||||
enum class AxisType {
|
||||
None = 0,
|
||||
OrbitX,
|
||||
OrbitY,
|
||||
ZoomIn,
|
||||
ZoomOut,
|
||||
LocalRollX,
|
||||
LocalRollY,
|
||||
GlobalRollX,
|
||||
GlobalRollY,
|
||||
PanX,
|
||||
PanY
|
||||
};
|
||||
|
||||
BooleanType(AxisInvert);
|
||||
BooleanType(AxisNormalize);
|
||||
BooleanType(ButtonCommandRemote);
|
||||
|
||||
struct AxisInformation {
|
||||
AxisType type = AxisType::None;
|
||||
AxisInvert invert = AxisInvert::No;
|
||||
AxisNormalize normalize = AxisNormalize::No;
|
||||
|
||||
float deadzone = 0.f;
|
||||
};
|
||||
|
||||
WebsocketCameraStates(double sensitivity, double velocityScaleFactor);
|
||||
|
||||
void updateStateFromInput(const InputState& inputState, double deltaTime) override;
|
||||
|
||||
void setAxisMapping(int axis, AxisType mapping,
|
||||
AxisInvert shouldInvert = AxisInvert::No,
|
||||
AxisNormalize shouldNormalize = AxisNormalize::No
|
||||
);
|
||||
|
||||
AxisInformation axisMapping(int axis) const;
|
||||
|
||||
void setDeadzone(int axis, float deadzone);
|
||||
float deadzone(int axis) const;
|
||||
|
||||
|
||||
void bindButtonCommand(int button, std::string command, WebsocketAction action,
|
||||
ButtonCommandRemote remote, std::string documentation);
|
||||
void clearButtonCommand(int button);
|
||||
std::vector<std::string> buttonCommand(int button) const;
|
||||
|
||||
private:
|
||||
// We use an array for the axes and a map for the buttons since the axis are going to
|
||||
// be accessed much more often and thus have to be more efficient. And storing a few
|
||||
// extra AxisInformation that are not used will not matter that much; finding an axis
|
||||
// location in a potential map each frame, however, would
|
||||
|
||||
std::array<AxisInformation, WebsocketInputState::MaxAxes> _axisMapping;
|
||||
|
||||
struct ButtonInformation {
|
||||
std::string command;
|
||||
WebsocketAction action;
|
||||
ButtonCommandRemote synchronization;
|
||||
std::string documentation;
|
||||
};
|
||||
|
||||
std::multimap<int, ButtonInformation> _buttonMapping;
|
||||
};
|
||||
|
||||
} // namespace openspace::interaction
|
||||
|
||||
namespace ghoul {
|
||||
|
||||
template <>
|
||||
std::string to_string(const openspace::interaction::WebsocketCameraStates::AxisType& type);
|
||||
|
||||
template <>
|
||||
openspace::interaction::WebsocketCameraStates::AxisType
|
||||
from_string(const std::string& string);
|
||||
|
||||
} // namespace ghoul
|
||||
|
||||
#endif // __OPENSPACE_CORE___WEBSOCKETCAMERASTATES___H__
|
||||
125
include/openspace/interaction/websocketinputstate.h
Normal file
125
include/openspace/interaction/websocketinputstate.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2019 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_CORE___WEBSOCKETINPUTSTATE___H__
|
||||
#define __OPENSPACE_CORE___WEBSOCKETINPUTSTATE___H__
|
||||
|
||||
#include <ghoul/misc/stringconversion.h>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
namespace openspace::interaction {
|
||||
|
||||
/**
|
||||
* Actions that any button of a websocket can have. Each button must be in one of these
|
||||
* states
|
||||
*/
|
||||
enum class WebsocketAction : uint8_t {
|
||||
/// Idle state if the button is unpressed and has been unpressed since last frame
|
||||
Idle = 0,
|
||||
/// If the button has been pressed since the last frame
|
||||
Press,
|
||||
/// If the button has been pressed since longer than last frame
|
||||
Repeat,
|
||||
/// If the button was released since the last frame
|
||||
Release
|
||||
};
|
||||
|
||||
/**
|
||||
* The input state of a single websocket.
|
||||
*/
|
||||
struct WebsocketInputState {
|
||||
/// The maximum number of supported axes
|
||||
static constexpr const int MaxAxes = 10;
|
||||
/// The maximum number of supported buttons
|
||||
static constexpr const int MaxButtons = 32;
|
||||
|
||||
/// Marks whether this websocket is connected. If this value is \c false, all other
|
||||
/// members of this struct are undefined
|
||||
bool isConnected = false;
|
||||
|
||||
/// The name of this websocket
|
||||
std::string name;
|
||||
|
||||
/// The number of axes that this websocket supports
|
||||
int nAxes = 0;
|
||||
/// The values for each axis. Each value is in the range [-1, 1]. Only the first
|
||||
/// \c nAxes values are defined values, the rest are undefined
|
||||
std::array<float, MaxAxes> axes;
|
||||
|
||||
/// The number of buttons that this websocket possesses
|
||||
int nButtons = 0;
|
||||
/// The status of each button. Only the first \c nButtons values are defined, the rest
|
||||
/// are undefined
|
||||
std::array<WebsocketAction, MaxButtons> buttons;
|
||||
};
|
||||
|
||||
/// The maximum number of websockets that are supported by this system. This number is
|
||||
/// derived from the available GLFW constants
|
||||
constexpr const int MaxWebsockets = 16;
|
||||
//struct WebsocketInputStates : public std::array<WebsocketInputState, MaxWebsockets> {
|
||||
struct WebsocketInputStates : public std::unordered_map<size_t, WebsocketInputState*> {
|
||||
/**
|
||||
* This function adds the contributions of all connected websockets for the provided
|
||||
* \p axis. After adding each websockets contribution, the result is clamped to [-1,1].
|
||||
* If a websocket does not possess a particular axis, it's does not contribute to the
|
||||
* sum.
|
||||
*
|
||||
* \param axis The numerical axis for which the values are added
|
||||
* \return The summed axis values of all connected websockets
|
||||
*
|
||||
* \pre \p axis must be 0 or positive
|
||||
*/
|
||||
float axis(int axis) const;
|
||||
|
||||
/**
|
||||
* This functions checks whether any connected websocket has its \p button in the
|
||||
* passed \p action. Any websocket that does not posses the \p button, it will be
|
||||
* ignored.
|
||||
*
|
||||
* \param button The button that is to be checked
|
||||
* \param action The action which is checked for each button
|
||||
* \return \c true if there is at least one websocket whose \param button is in the
|
||||
* \p action state
|
||||
*
|
||||
* \pre \p button must be 0 or positive
|
||||
*/
|
||||
bool button(int button, WebsocketAction action) const;
|
||||
};
|
||||
|
||||
} // namespace openspace::interaction
|
||||
|
||||
namespace ghoul {
|
||||
|
||||
template <>
|
||||
std::string to_string(const openspace::interaction::WebsocketAction& action);
|
||||
|
||||
template <>
|
||||
openspace::interaction::WebsocketAction from_string(const std::string& str);
|
||||
|
||||
} // namespace ghoul
|
||||
|
||||
#endif // __OPENSPACE_CORE___WEBSOCKETINPUTSTATE___H__
|
||||
@@ -303,7 +303,6 @@ protected:
|
||||
/// The description for this PropertyOwner
|
||||
std::string _description;
|
||||
|
||||
private:
|
||||
/// The owner of this PropertyOwner
|
||||
PropertyOwner* _owner = nullptr;
|
||||
/// A list of all registered Property's
|
||||
|
||||
@@ -86,8 +86,8 @@ public:
|
||||
struct ProgressInfo {
|
||||
float progress = 0.f;
|
||||
|
||||
int currentSize = -1;
|
||||
int totalSize = -1;
|
||||
int64_t currentSize = -1;
|
||||
int64_t totalSize = -1;
|
||||
};
|
||||
|
||||
void updateItem(const std::string& itemIdentifier, const std::string& itemName,
|
||||
|
||||
@@ -261,8 +261,8 @@ void AtmosphereDeferredcaster::preRaycast(const RenderData& renderData,
|
||||
program.setUniform(_uniformCache2.dModelTransformMatrix, _modelTransform);
|
||||
|
||||
// Eye Space in SGCT to Eye Space in OS (SGCT View to OS Camera Rig)
|
||||
glm::dmat4 dSgctEye2OSEye = glm::inverse(
|
||||
glm::dmat4(renderData.camera.viewMatrix()));
|
||||
// glm::dmat4 dSgctEye2OSEye = glm::inverse(
|
||||
// glm::dmat4(renderData.camera.viewMatrix()));
|
||||
|
||||
glm::dmat4 dSGCTViewToWorldMatrix = glm::inverse(
|
||||
renderData.camera.combinedViewMatrix()
|
||||
@@ -1508,7 +1508,7 @@ bool AtmosphereDeferredcaster::isAtmosphereInFrustum(const glm::dmat4& MVMatrix,
|
||||
double bottomDistance = MVMatrix[3][3] + MVMatrix[3][1];
|
||||
double topDistance = MVMatrix[3][3] - MVMatrix[3][1];
|
||||
double nearDistance = MVMatrix[3][3] + MVMatrix[3][2];
|
||||
double farDistance = MVMatrix[3][3] - MVMatrix[3][2];
|
||||
// double farDistance = MVMatrix[3][3] - MVMatrix[3][2];
|
||||
|
||||
// Normalize Planes
|
||||
double invMag = 1.0 / glm::length(leftNormal);
|
||||
@@ -1533,7 +1533,7 @@ bool AtmosphereDeferredcaster::isAtmosphereInFrustum(const glm::dmat4& MVMatrix,
|
||||
|
||||
invMag = 1.0 / glm::length(farNormal);
|
||||
farNormal *= invMag;
|
||||
farDistance *= invMag;
|
||||
// farDistance *= invMag;
|
||||
|
||||
if ((glm::dot(leftNormal, position) + leftDistance) < -radius) {
|
||||
return false;
|
||||
|
||||
@@ -233,7 +233,7 @@ void RenderableTrailOrbit::update(const UpdateData& data) {
|
||||
// Write the current location into the floating position
|
||||
const glm::vec3 p = _translation->position({
|
||||
{},
|
||||
data.time.now(),
|
||||
data.time,
|
||||
Time(0.0),
|
||||
false
|
||||
});
|
||||
|
||||
118
modules/base/rotation/timelinerotation.cpp
Normal file
118
modules/base/rotation/timelinerotation.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2019 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/base/rotation/timelinerotation.h>
|
||||
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <openspace/util/time.h>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyType = "Type";
|
||||
constexpr const char* KeyKeyframes = "Keyframes";
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation TimelineRotation::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"Timeline Rotation",
|
||||
"base_transform_rotation_keyframe",
|
||||
{
|
||||
{
|
||||
KeyType,
|
||||
new StringEqualVerifier("TimelineRotation"),
|
||||
Optional::No
|
||||
},
|
||||
{
|
||||
KeyKeyframes,
|
||||
new TableVerifier({
|
||||
{ "*", new TableVerifier(), Optional::No, "Any translation object" }
|
||||
}),
|
||||
Optional::No,
|
||||
"A table of keyframes, with keys formatted as YYYY-MM-DDTHH:MM:SS"
|
||||
"and values that are valid Rotation objects."
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TimelineRotation::TimelineRotation(const ghoul::Dictionary& dictionary) {
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"TimelineTranslation"
|
||||
);
|
||||
|
||||
const ghoul::Dictionary& keyframes =
|
||||
dictionary.value<ghoul::Dictionary>(KeyKeyframes);
|
||||
|
||||
std::vector<std::string> timeStrings = keyframes.keys();
|
||||
for (const std::string& timeString : timeStrings) {
|
||||
const double t = Time::convertTime(timeString);
|
||||
|
||||
std::unique_ptr<Rotation> rotation =
|
||||
Rotation::createFromDictionary(
|
||||
keyframes.value<ghoul::Dictionary>(timeString)
|
||||
);
|
||||
|
||||
if (rotation) {
|
||||
_timeline.addKeyframe(t, std::move(rotation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glm::dmat3 TimelineRotation::matrix(const UpdateData& data) const {
|
||||
const double now = data.time.j2000Seconds();
|
||||
using KeyframePointer = const Keyframe<std::unique_ptr<Rotation>>*;
|
||||
|
||||
KeyframePointer prev = _timeline.lastKeyframeBefore(now, true);
|
||||
KeyframePointer next = _timeline.firstKeyframeAfter(now, true);
|
||||
|
||||
if (!prev && !next) {
|
||||
return glm::dmat3(0.0);
|
||||
}
|
||||
if (!prev) {
|
||||
prev = next;
|
||||
}
|
||||
if (!next) {
|
||||
next = prev;
|
||||
}
|
||||
const double prevTime = prev->timestamp;
|
||||
const double nextTime = next->timestamp;
|
||||
|
||||
double t = 0.0;
|
||||
if (nextTime - prevTime > 0.0) {
|
||||
t = (now - prevTime) / (nextTime - prevTime);
|
||||
}
|
||||
|
||||
const glm::dquat nextRot = glm::quat_cast(next->data->matrix(data));
|
||||
const glm::dquat prevRot = glm::quat_cast(prev->data->matrix(data));
|
||||
|
||||
return glm::dmat3(glm::slerp(prevRot, nextRot, t));
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
49
modules/base/rotation/timelinerotation.h
Normal file
49
modules/base/rotation/timelinerotation.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2019 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_BASE___TIMELINEROTATION___H__
|
||||
#define __OPENSPACE_MODULE_BASE___TIMELINEROTATION___H__
|
||||
|
||||
#include <openspace/scene/rotation.h>
|
||||
#include <openspace/util/timeline.h>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
struct UpdateData;
|
||||
|
||||
namespace documentation { struct Documentation; }
|
||||
|
||||
class TimelineRotation : public Rotation {
|
||||
public:
|
||||
TimelineRotation(const ghoul::Dictionary& dictionary);
|
||||
glm::dmat3 matrix(const UpdateData& data) const override;
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
Timeline<std::unique_ptr<Rotation>> _timeline;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_BASE___TIMELINEROTATION___H__
|
||||
114
modules/base/translation/timelinetranslation.cpp
Normal file
114
modules/base/translation/timelinetranslation.cpp
Normal file
@@ -0,0 +1,114 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2019 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/base/translation/timelinetranslation.h>
|
||||
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <openspace/util/updatestructures.h>
|
||||
#include <openspace/util/time.h>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyType = "Type";
|
||||
constexpr const char* KeyKeyframes = "Keyframes";
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
|
||||
documentation::Documentation TimelineTranslation::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"Timeline Translation",
|
||||
"base_transform_translation_keyframe",
|
||||
{
|
||||
{
|
||||
KeyType,
|
||||
new StringEqualVerifier("TimelineTranslation"),
|
||||
Optional::No
|
||||
},
|
||||
{
|
||||
KeyKeyframes,
|
||||
new TableVerifier({
|
||||
{ "*", new TableVerifier(), Optional::No, "Any translation object" }
|
||||
}),
|
||||
Optional::No,
|
||||
"A table of keyframes, with keys formatted as YYYY-MM-DDTHH:MM:SS"
|
||||
"and values that are valid Translation objects."
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
TimelineTranslation::TimelineTranslation(const ghoul::Dictionary& dictionary) {
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
dictionary,
|
||||
"TimelineTranslation"
|
||||
);
|
||||
|
||||
const ghoul::Dictionary& keyframes =
|
||||
dictionary.value<ghoul::Dictionary>(KeyKeyframes);
|
||||
|
||||
std::vector<std::string> timeStrings = keyframes.keys();
|
||||
for (const std::string& timeString : timeStrings) {
|
||||
const double t = Time::convertTime(timeString);
|
||||
|
||||
std::unique_ptr<Translation> translation =
|
||||
Translation::createFromDictionary(
|
||||
keyframes.value<ghoul::Dictionary>(timeString)
|
||||
);
|
||||
|
||||
if (translation) {
|
||||
_timeline.addKeyframe(t, std::move(translation));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glm::dvec3 TimelineTranslation::position(const UpdateData& data) const {
|
||||
const double now = data.time.j2000Seconds();
|
||||
using KeyframePointer = const Keyframe<std::unique_ptr<Translation>>*;
|
||||
|
||||
KeyframePointer prev = _timeline.lastKeyframeBefore(now, true);
|
||||
KeyframePointer next = _timeline.firstKeyframeAfter(now, true);
|
||||
|
||||
if (!prev && !next) {
|
||||
return glm::dvec3(0.0);
|
||||
}
|
||||
if (!prev) {
|
||||
prev = next;
|
||||
}
|
||||
if (!next) {
|
||||
next = prev;
|
||||
}
|
||||
const double prevTime = prev->timestamp;
|
||||
const double nextTime = next->timestamp;
|
||||
|
||||
double t = 0.0;
|
||||
if (nextTime - prevTime > 0.0) {
|
||||
t = (now - prevTime) / (nextTime - prevTime);
|
||||
}
|
||||
return t * next->data->position(data) + (1.0 - t) * prev->data->position(data);
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
50
modules/base/translation/timelinetranslation.h
Normal file
50
modules/base/translation/timelinetranslation.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2018 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_BASE___TIMELINETRANSLATION___H__
|
||||
#define __OPENSPACE_MODULE_BASE___TIMELINETRANSLATION___H__
|
||||
|
||||
#include <openspace/scene/translation.h>
|
||||
#include <openspace/util/timeline.h>
|
||||
|
||||
namespace openspace {
|
||||
|
||||
struct UpdateData;
|
||||
|
||||
namespace documentation { struct Documentation; }
|
||||
|
||||
class TimelineTranslation : public Translation {
|
||||
public:
|
||||
TimelineTranslation(const ghoul::Dictionary& dictionary);
|
||||
|
||||
glm::dvec3 position(const UpdateData& data) const override;
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
Timeline<std::unique_ptr<Translation>> _timeline;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_BASE___TIMELINETRANSLATION___H__
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <ghoul/fmt.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
|
||||
namespace {
|
||||
constexpr const char* _loggerCat = "FieldlinesState";
|
||||
|
||||
@@ -28,7 +28,11 @@
|
||||
#include <modules/globebrowsing/src/dashboarditemglobelocation.h>
|
||||
#include <modules/globebrowsing/src/gdalwrapper.h>
|
||||
#include <modules/globebrowsing/src/geodeticpatch.h>
|
||||
#include <modules/globebrowsing/src/globelabelscomponent.h>
|
||||
#include <modules/globebrowsing/src/globetranslation.h>
|
||||
#include <modules/globebrowsing/src/layer.h>
|
||||
#include <modules/globebrowsing/src/layeradjustment.h>
|
||||
#include <modules/globebrowsing/src/layermanager.h>
|
||||
#include <modules/globebrowsing/src/memoryawaretilecache.h>
|
||||
#include <modules/globebrowsing/src/tileprovider.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
@@ -261,7 +265,7 @@ void GlobeBrowsingModule::internalInitialize(const ghoul::Dictionary& dict) {
|
||||
// >= as we might have multiple frames per postDraw call (stereo rendering,
|
||||
// fisheye, etc)
|
||||
const uint16_t next = _frameInfo.lastSavedFrame + _frameInfo.saveEveryNthFrame;
|
||||
const bool shouldSave = _saveInstrumentation &&
|
||||
const bool shouldSave = _saveInstrumentation &&
|
||||
global::renderEngine.frameNumber() >= next;
|
||||
if (shouldSave) {
|
||||
using K = const globebrowsing::RenderableGlobe*;
|
||||
@@ -385,6 +389,27 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const {
|
||||
"any of " + listLayerGroups + ". The third argument is the dictionary"
|
||||
"defining the layer."
|
||||
},
|
||||
{
|
||||
"getLayers",
|
||||
&globebrowsing::luascriptfunctions::getLayers,
|
||||
{},
|
||||
"string, string",
|
||||
"Returns the list of layers for the scene graph node specified in the first "
|
||||
"parameter. The second parameter specifies which layer type should be "
|
||||
"queried."
|
||||
},
|
||||
{
|
||||
"moveLayer",
|
||||
&globebrowsing::luascriptfunctions::moveLayer,
|
||||
{},
|
||||
"string, string, number, number",
|
||||
"Rearranges the order of a single layer in a scene graph node. The first "
|
||||
"parameter specifies the scene graph node, the second parameter specifies "
|
||||
"the name of the layer group, the third parameter is the original position "
|
||||
"of the layer that should be moved and the last parameter is the new "
|
||||
"position. The new position may be -1 to place the layer at the top or any "
|
||||
"large number bigger than the number of layers to place it at the bottom."
|
||||
},
|
||||
{
|
||||
"goToChunk",
|
||||
&globebrowsing::luascriptfunctions::goToChunk,
|
||||
@@ -461,6 +486,15 @@ scripting::LuaLibrary GlobeBrowsingModule::luaLibrary() const {
|
||||
return res;
|
||||
}
|
||||
|
||||
std::vector<documentation::Documentation> GlobeBrowsingModule::documentations() const {
|
||||
return {
|
||||
globebrowsing::Layer::Documentation(),
|
||||
globebrowsing::LayerAdjustment::Documentation(),
|
||||
globebrowsing::LayerManager::Documentation(),
|
||||
GlobeLabelsComponent::Documentation()
|
||||
};
|
||||
}
|
||||
|
||||
void GlobeBrowsingModule::goToChunk(const globebrowsing::RenderableGlobe& globe,
|
||||
int x, int y, int level)
|
||||
{
|
||||
@@ -478,7 +512,7 @@ void GlobeBrowsingModule::goToGeo(const globebrowsing::RenderableGlobe& globe,
|
||||
);
|
||||
}
|
||||
|
||||
void GlobeBrowsingModule::goToGeo(const globebrowsing::RenderableGlobe& globe,
|
||||
void GlobeBrowsingModule::goToGeo(const globebrowsing::RenderableGlobe& globe,
|
||||
double latitude, double longitude, double altitude)
|
||||
{
|
||||
using namespace globebrowsing;
|
||||
@@ -537,7 +571,7 @@ void GlobeBrowsingModule::goToChunk(const globebrowsing::RenderableGlobe& globe,
|
||||
const SurfacePositionHandle posHandle = globe.calculateSurfacePositionHandle(
|
||||
cameraPositionModelSpace
|
||||
);
|
||||
|
||||
|
||||
const Geodetic2 geo2 = globe.ellipsoid().cartesianToGeodetic2(
|
||||
posHandle.centerToReferenceSurface
|
||||
);
|
||||
|
||||
@@ -65,6 +65,8 @@ public:
|
||||
|
||||
globebrowsing::cache::MemoryAwareTileCache* tileCache();
|
||||
scripting::LuaLibrary luaLibrary() const override;
|
||||
std::vector<documentation::Documentation> documentations() const override;
|
||||
|
||||
const globebrowsing::RenderableGlobe* castFocusNodeRenderableToGlobe();
|
||||
|
||||
struct Layer {
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <modules/globebrowsing/src/renderableglobe.h>
|
||||
|
||||
#include <modules/globebrowsing/src/layer.h>
|
||||
#include <modules/globebrowsing/src/layergroup.h>
|
||||
#include <modules/globebrowsing/src/layermanager.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/engine/moduleengine.h>
|
||||
@@ -127,6 +128,77 @@ int deleteLayer(lua_State* L) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getLayers(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::getLayers");
|
||||
|
||||
const std::string& globeIdentifier = ghoul::lua::value<std::string>(L, 1);
|
||||
const std::string& layer = ghoul::lua::value<std::string>(L, 2);
|
||||
lua_pop(L, 2);
|
||||
|
||||
SceneGraphNode* n = sceneGraphNode(globeIdentifier);
|
||||
if (!n) {
|
||||
return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier);
|
||||
}
|
||||
|
||||
const RenderableGlobe* globe = dynamic_cast<const RenderableGlobe*>(n->renderable());
|
||||
if (!globe) {
|
||||
return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe");
|
||||
}
|
||||
|
||||
globebrowsing::layergroupid::GroupID group =
|
||||
ghoul::from_string<globebrowsing::layergroupid::GroupID>(layer);
|
||||
if (group == globebrowsing::layergroupid::GroupID::Unknown) {
|
||||
return ghoul::lua::luaError(L, "Unknown layer groupd: " + layer);
|
||||
}
|
||||
|
||||
const globebrowsing::LayerGroup& lg = globe->layerManager().layerGroup(group);
|
||||
std::vector<globebrowsing::Layer*> layers = lg.layers();
|
||||
|
||||
lua_newtable(L);
|
||||
int key = 1;
|
||||
for (globebrowsing::Layer* l : layers) {
|
||||
ghoul::lua::push(L, key, l->identifier());
|
||||
lua_settable(L, -3);
|
||||
key++;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int moveLayer(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::moveLayer");
|
||||
|
||||
const std::string& globeIdentifier = ghoul::lua::value<std::string>(L, 1);
|
||||
const std::string& layer = ghoul::lua::value<std::string>(L, 2);
|
||||
int oldPosition = ghoul::lua::value<int>(L, 3);
|
||||
int newPosition = ghoul::lua::value<int>(L, 4);
|
||||
lua_pop(L, 4);
|
||||
|
||||
if (oldPosition == newPosition) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
SceneGraphNode* n = sceneGraphNode(globeIdentifier);
|
||||
if (!n) {
|
||||
return ghoul::lua::luaError(L, "Unknown globe name: " + globeIdentifier);
|
||||
}
|
||||
|
||||
RenderableGlobe* globe = dynamic_cast<RenderableGlobe*>(n->renderable());
|
||||
if (!globe) {
|
||||
return ghoul::lua::luaError(L, "Identifier must be a RenderableGlobe");
|
||||
}
|
||||
|
||||
globebrowsing::layergroupid::GroupID group =
|
||||
ghoul::from_string<globebrowsing::layergroupid::GroupID>(layer);
|
||||
if (group == globebrowsing::layergroupid::GroupID::Unknown) {
|
||||
return ghoul::lua::luaError(L, "Unknown layer groupd: " + layer);
|
||||
}
|
||||
|
||||
globebrowsing::LayerGroup& lg = globe->layerManager().layerGroup(group);
|
||||
lg.moveLayers(oldPosition, newPosition);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int goToChunk(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 4, "lua::goToChunk");
|
||||
|
||||
@@ -153,7 +225,7 @@ int goToChunk(lua_State* L) {
|
||||
}
|
||||
|
||||
int goToGeo(lua_State* L) {
|
||||
const int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::goToGeo");
|
||||
int nArguments = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::goToGeo");
|
||||
|
||||
// Check if the user provided a Scene graph node identifier as the first argument.
|
||||
// lua_isstring returns true for both numbers and strings, so better use !lua_isnumber
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
#include <modules/globebrowsing/src/layer.h>
|
||||
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <modules/globebrowsing/src/layergroup.h>
|
||||
#include <modules/globebrowsing/src/layermanager.h>
|
||||
#include <modules/globebrowsing/src/tileindex.h>
|
||||
@@ -93,6 +95,114 @@ namespace {
|
||||
};
|
||||
} // namespace
|
||||
|
||||
documentation::Documentation Layer::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"Layer",
|
||||
"globebrowsing_layer",
|
||||
{
|
||||
{
|
||||
KeyIdentifier,
|
||||
new StringVerifier,
|
||||
Optional::No,
|
||||
"The unique identifier for this layer. May not contain '.' or spaces."
|
||||
},
|
||||
{
|
||||
KeyName,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"A human-readable name for the user interface. If this is omitted, the "
|
||||
"identifier is used instead."
|
||||
},
|
||||
{
|
||||
KeyDesc,
|
||||
new StringVerifier,
|
||||
Optional::Yes,
|
||||
"A human-readable description of the layer to be used in informational "
|
||||
"texts presented to the user."
|
||||
},
|
||||
{
|
||||
"Type",
|
||||
new StringInListVerifier({
|
||||
"DefaultTileLayer", "SingleImageTileLayer", "SizeReferenceTileLayer",
|
||||
"TemporalTileLayer", "TileIndexTileLayer", "ByIndexTileLayer",
|
||||
"ByLevelTileLayer", "SolidColor"
|
||||
}),
|
||||
Optional::Yes,
|
||||
"Specifies the type of layer that is to be added. If this value is not "
|
||||
"specified, the layer is a DefaultTileLayer."
|
||||
},
|
||||
{
|
||||
EnabledInfo.identifier,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
"Determine whether the layer is enabled or not. If this value is not "
|
||||
"specified, the layer is disabled."
|
||||
},
|
||||
{
|
||||
KeyPadTiles,
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
"Determines whether the downloaded tiles should have a padding added to "
|
||||
"the borders."
|
||||
},
|
||||
{
|
||||
KeySettings,
|
||||
new TableVerifier({
|
||||
{
|
||||
KeyOpacity,
|
||||
new DoubleInRangeVerifier(0.0, 1.0),
|
||||
Optional::Yes,
|
||||
"The opacity value of the layer."
|
||||
},
|
||||
{
|
||||
KeyGamma,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
"The gamma value that is applied to each pixel of the layer."
|
||||
},
|
||||
{
|
||||
KeyMultiplier,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
"The multiplicative factor that is applied to each pixel of the "
|
||||
"layer."
|
||||
},
|
||||
{
|
||||
KeyOffset,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
"An additive offset that is applied to each pixel of the layer."
|
||||
}
|
||||
}),
|
||||
Optional::Yes,
|
||||
"Specifies the render settings that should be applied to this layer."
|
||||
},
|
||||
{
|
||||
KeyAdjustment,
|
||||
new ReferencingVerifier("globebrowsing_layeradjustment"),
|
||||
Optional::Yes,
|
||||
""
|
||||
},
|
||||
{
|
||||
BlendModeInfo.identifier,
|
||||
new StringInListVerifier({
|
||||
"Normal", "Multiply", "Add", "Subtract", "Color"
|
||||
}),
|
||||
Optional::Yes,
|
||||
"Sets the blend mode of this layer to determine how it interacts with "
|
||||
"other layers on top of this."
|
||||
},
|
||||
{
|
||||
"Fallback",
|
||||
new ReferencingVerifier("globebrowsing_layer"),
|
||||
Optional::Yes,
|
||||
"If the primary layer creation fails, this layer is used as a fallback"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict,
|
||||
LayerGroup& parent)
|
||||
: properties::PropertyOwner({
|
||||
@@ -109,13 +219,15 @@ Layer::Layer(layergroupid::GroupID id, const ghoul::Dictionary& layerDict,
|
||||
, _solidColor(ColorInfo, glm::vec3(1.f), glm::vec3(0.f), glm::vec3(1.f))
|
||||
, _layerGroupId(id)
|
||||
{
|
||||
documentation::testSpecificationAndThrow(Documentation(), layerDict, "Layer");
|
||||
|
||||
layergroupid::TypeID typeID;
|
||||
if (layerDict.hasKeyAndValue<std::string>("Type")) {
|
||||
const std::string& typeString = layerDict.value<std::string>("Type");
|
||||
typeID = ghoul::from_string<layergroupid::TypeID>(typeString);
|
||||
}
|
||||
else {
|
||||
typeID = layergroupid::TypeID::DefaultTileLayer;
|
||||
typeID = layergroupid::TypeID::DefaultTileLayer;
|
||||
}
|
||||
if (typeID == layergroupid::TypeID::Unknown) {
|
||||
throw ghoul::RuntimeError("Unknown layer type!");
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
#include <openspace/properties/optionproperty.h>
|
||||
#include <openspace/properties/scalar/boolproperty.h>
|
||||
|
||||
namespace openspace::documentation { struct Documentation; }
|
||||
|
||||
namespace openspace::globebrowsing {
|
||||
|
||||
struct LayerGroup;
|
||||
@@ -72,6 +74,8 @@ public:
|
||||
glm::vec2 tileUvToTextureSamplePosition(const TileUvTransform& uvTransform,
|
||||
const glm::vec2& tileUV, const glm::uvec2& resolution);
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
void initializeBasedOnType(layergroupid::TypeID typeId, ghoul::Dictionary initDict);
|
||||
void addVisibleProperties();
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
|
||||
#include <modules/globebrowsing/src/layeradjustment.h>
|
||||
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
|
||||
namespace {
|
||||
constexpr const char* KeyType = "Type";
|
||||
constexpr const char* KeyChromaKeyColor = "ChromaKeyColor";
|
||||
@@ -51,6 +54,35 @@ namespace {
|
||||
|
||||
namespace openspace::globebrowsing {
|
||||
|
||||
documentation::Documentation LayerAdjustment::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"LayerAdjustment",
|
||||
"globebrowsing_layeradjustment",
|
||||
{
|
||||
{
|
||||
KeyType,
|
||||
new StringInListVerifier({ "None", "ChromaKey", "TransferFunction" }),
|
||||
Optional::Yes,
|
||||
"Specifies the type of the adjustment that is applied"
|
||||
},
|
||||
{
|
||||
KeyChromaKeyColor,
|
||||
new DoubleVector3Verifier,
|
||||
Optional::Yes,
|
||||
"Specifies the chroma key used when selecting 'ChromaKey' for the 'Type'."
|
||||
},
|
||||
{
|
||||
KeyChromaKeyTolerance,
|
||||
new DoubleVerifier,
|
||||
Optional::Yes,
|
||||
"Specifies the tolerance to match the color to the chroma key when the "
|
||||
"'ChromaKey' type is selected for the 'Type'."
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
LayerAdjustment::LayerAdjustment()
|
||||
: properties::PropertyOwner({ "adjustment" })
|
||||
, _chromaKeyColor(ChromaKeyColorInfo, glm::vec3(0.f), glm::vec3(0.f), glm::vec3(1.f))
|
||||
@@ -89,6 +121,12 @@ LayerAdjustment::LayerAdjustment()
|
||||
}
|
||||
|
||||
void LayerAdjustment::setValuesFromDictionary(const ghoul::Dictionary& adjustmentDict) {
|
||||
documentation::testSpecificationAndThrow(
|
||||
Documentation(),
|
||||
adjustmentDict,
|
||||
"LayerAdjustment"
|
||||
);
|
||||
|
||||
if (adjustmentDict.hasKeyAndValue<std::string>(KeyType)) {
|
||||
std::string dictType = adjustmentDict.value<std::string>(KeyType);
|
||||
_typeOption = static_cast<int>(
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include <openspace/properties/scalar/floatproperty.h>
|
||||
#include <openspace/properties/vector/vec3property.h>
|
||||
|
||||
namespace openspace::documentation { struct Documentation; }
|
||||
|
||||
namespace openspace::globebrowsing {
|
||||
|
||||
namespace tileprovider { struct TileProvider; }
|
||||
@@ -50,6 +52,8 @@ public:
|
||||
|
||||
void onChange(std::function<void(void)> callback);
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
void addVisibleProperties();
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <modules/globebrowsing/src/layergroup.h>
|
||||
|
||||
#include <modules/globebrowsing/src/layer.h>
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
namespace {
|
||||
@@ -106,6 +107,14 @@ int LayerGroup::update() {
|
||||
}
|
||||
|
||||
Layer* LayerGroup::addLayer(const ghoul::Dictionary& layerDict) {
|
||||
documentation::TestResult res = documentation::testSpecification(
|
||||
Layer::Documentation(),
|
||||
layerDict
|
||||
);
|
||||
if (!res.success) {
|
||||
LERROR("Error adding layer. " + ghoul::to_string(res));
|
||||
}
|
||||
|
||||
if (!layerDict.hasKeyAndValue<std::string>("Identifier")) {
|
||||
LERROR("'Identifier' must be specified for layer.");
|
||||
return nullptr;
|
||||
@@ -155,6 +164,33 @@ void LayerGroup::deleteLayer(const std::string& layerName) {
|
||||
LERROR("Could not find layer " + layerName);
|
||||
}
|
||||
|
||||
void LayerGroup::moveLayers(int oldPosition, int newPosition) {
|
||||
oldPosition = std::max(0, oldPosition);
|
||||
newPosition = std::min(newPosition, static_cast<int>(_layers.size()));
|
||||
|
||||
// We need to adjust the new position as we first delete the old position, if this
|
||||
// position is before the new position we have reduced the size of the vector by 1 and
|
||||
// need to adapt where we want to put the value in
|
||||
if (oldPosition < newPosition) {
|
||||
newPosition -= 1;
|
||||
}
|
||||
|
||||
// There are two synchronous vectors that we have to update here. The _layers vector
|
||||
// is used to determine the order while rendering, the _subowners is the order in
|
||||
// which the layers are shown in the UI
|
||||
auto oldPosLayers = _layers.begin() + oldPosition;
|
||||
std::unique_ptr<Layer> v = std::move(*oldPosLayers);
|
||||
_layers.erase(oldPosLayers);
|
||||
auto newPosLayers = _layers.begin() + newPosition;
|
||||
_layers.insert(newPosLayers, std::move(v));
|
||||
|
||||
auto oldPosOwner = _subOwners.begin() + oldPosition;
|
||||
PropertyOwner* owner = std::move(*oldPosOwner);
|
||||
_subOwners.erase(oldPosOwner);
|
||||
auto newPosOwner = _subOwners.begin() + newPosition;
|
||||
_subOwners.insert(newPosOwner, std::move(owner));
|
||||
}
|
||||
|
||||
std::vector<Layer*> LayerGroup::layers() const {
|
||||
std::vector<Layer*> res;
|
||||
res.reserve(_layers.size());
|
||||
|
||||
@@ -53,6 +53,7 @@ struct LayerGroup : public properties::PropertyOwner {
|
||||
|
||||
Layer* addLayer(const ghoul::Dictionary& layerDict);
|
||||
void deleteLayer(const std::string& layerName);
|
||||
void moveLayers(int oldPosition, int newPosition);
|
||||
|
||||
/// @returns const vector of all layers
|
||||
std::vector<Layer*> layers() const;
|
||||
|
||||
@@ -28,10 +28,28 @@
|
||||
#include <modules/globebrowsing/src/layergroup.h>
|
||||
#include <modules/globebrowsing/src/tileprovider.h>
|
||||
#include <modules/globebrowsing/src/tiletextureinitdata.h>
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
|
||||
namespace openspace::globebrowsing {
|
||||
|
||||
documentation::Documentation LayerManager::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"LayerManager",
|
||||
"globebrowsing_layermanager",
|
||||
{
|
||||
{
|
||||
"*",
|
||||
new ReferencingVerifier("globebrowsing_layer"),
|
||||
Optional::Yes,
|
||||
"Specifies an individual layer"
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
LayerManager::LayerManager() : properties::PropertyOwner({ "Layers" }) {}
|
||||
|
||||
void LayerManager::initialize(const ghoul::Dictionary& layerGroupsDict) {
|
||||
@@ -88,6 +106,10 @@ void LayerManager::deleteLayer(layergroupid::GroupID id, const std::string& laye
|
||||
_layerGroups[id]->deleteLayer(layerName);
|
||||
}
|
||||
|
||||
LayerGroup& LayerManager::layerGroup(layergroupid::GroupID groupId) {
|
||||
return *_layerGroups[groupId];
|
||||
}
|
||||
|
||||
const LayerGroup& LayerManager::layerGroup(layergroupid::GroupID groupId) const {
|
||||
return *_layerGroups[groupId];
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
|
||||
namespace ghoul { class Dictionary; }
|
||||
|
||||
namespace openspace::documentation { struct Documentation; }
|
||||
|
||||
namespace openspace::globebrowsing {
|
||||
|
||||
class Layer;
|
||||
@@ -57,6 +59,7 @@ public:
|
||||
const ghoul::Dictionary& layerDict);
|
||||
void deleteLayer(layergroupid::GroupID groupId, const std::string& layerName);
|
||||
|
||||
LayerGroup& layerGroup(layergroupid::GroupID);
|
||||
const LayerGroup& layerGroup(layergroupid::GroupID) const;
|
||||
|
||||
bool hasAnyBlendingLayersEnabled() const;
|
||||
@@ -69,6 +72,8 @@ public:
|
||||
|
||||
void onChange(std::function<void(Layer* l)> callback);
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
std::array<std::unique_ptr<LayerGroup>, NumLayerGroups> _layerGroups;
|
||||
};
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include <modules/globebrowsing/src/renderableglobe.h>
|
||||
#include <modules/globebrowsing/src/tileprovider.h>
|
||||
#include <modules/debugging/rendering/debugrenderer.h>
|
||||
#include <openspace/documentation/documentation.h>
|
||||
#include <openspace/documentation/verifier.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/performance/performancemanager.h>
|
||||
#include <openspace/performance/performancemeasurement.h>
|
||||
@@ -424,6 +426,57 @@ Chunk::Chunk(const TileIndex& ti)
|
||||
, status(Status::DoNothing)
|
||||
{}
|
||||
|
||||
documentation::Documentation RenderableGlobe::Documentation() {
|
||||
using namespace documentation;
|
||||
return {
|
||||
"RenderableGlobe",
|
||||
"globebrowsing_renderableglobe",
|
||||
{
|
||||
{
|
||||
"Type",
|
||||
new StringEqualVerifier("RenderableGlobe"),
|
||||
Optional::No,
|
||||
""
|
||||
},
|
||||
{
|
||||
KeyRadii,
|
||||
new OrVerifier({ new DoubleVector3Verifier, new DoubleVerifier }),
|
||||
Optional::Yes,
|
||||
"Specifies the radii for this planet. If the Double version of this is "
|
||||
"used, all three radii are assumed to be equal."
|
||||
},
|
||||
{
|
||||
"PerformShading",
|
||||
new BoolVerifier,
|
||||
Optional::Yes,
|
||||
"Specifies whether the planet should be shaded by the primary light "
|
||||
"source or not. If it is disabled, all parts of the planet are "
|
||||
"illuminated."
|
||||
},
|
||||
{
|
||||
KeyLayers,
|
||||
new TableVerifier({
|
||||
{
|
||||
"*",
|
||||
new ReferencingVerifier("globebrowsing_layermanager"),
|
||||
Optional::Yes,
|
||||
"Descriptions of the individual layer groups"
|
||||
}
|
||||
}),
|
||||
Optional::Yes,
|
||||
"A list of all the layers that should be added"
|
||||
},
|
||||
{
|
||||
KeyLabels,
|
||||
new ReferencingVerifier("globebrowsing_globelabelscomponent"),
|
||||
Optional::Yes,
|
||||
"Specifies information about planetary labels that can be rendered on "
|
||||
"the object's surface."
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
RenderableGlobe::RenderableGlobe(const ghoul::Dictionary& dictionary)
|
||||
: Renderable(dictionary)
|
||||
, _debugProperties({
|
||||
|
||||
@@ -41,6 +41,8 @@
|
||||
#include <ghoul/opengl/uniformcache.h>
|
||||
#include <cstddef>
|
||||
|
||||
namespace openspace::documentation { struct Documentation; }
|
||||
|
||||
namespace openspace::globebrowsing {
|
||||
|
||||
class GPULayerGroup;
|
||||
@@ -111,6 +113,8 @@ public:
|
||||
LayerManager& layerManager();
|
||||
const glm::dmat4& modelTransform() const;
|
||||
|
||||
static documentation::Documentation Documentation();
|
||||
|
||||
private:
|
||||
constexpr static const int MinSplitDepth = 2;
|
||||
constexpr static const int MaxSplitDepth = 22;
|
||||
|
||||
@@ -34,6 +34,7 @@ set(HEADER_FILES
|
||||
include/topics/authorizationtopic.h
|
||||
include/topics/bouncetopic.h
|
||||
include/topics/documentationtopic.h
|
||||
include/topics/flightcontrollertopic.h
|
||||
include/topics/getpropertytopic.h
|
||||
include/topics/luascripttopic.h
|
||||
include/topics/sessionrecordingtopic.h
|
||||
@@ -56,6 +57,7 @@ set(SOURCE_FILES
|
||||
src/topics/authorizationtopic.cpp
|
||||
src/topics/bouncetopic.cpp
|
||||
src/topics/documentationtopic.cpp
|
||||
src/topics/flightcontrollertopic.cpp
|
||||
src/topics/getpropertytopic.cpp
|
||||
src/topics/luascripttopic.cpp
|
||||
src/topics/sessionrecordingtopic.cpp
|
||||
|
||||
79
modules/server/include/topics/flightcontrollertopic.h
Normal file
79
modules/server/include/topics/flightcontrollertopic.h
Normal file
@@ -0,0 +1,79 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2019 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#ifndef __OPENSPACE_MODULE_SERVER___FLIGHTCONTROLLER_TOPIC___H__
|
||||
#define __OPENSPACE_MODULE_SERVER___FLIGHTCONTROLLER_TOPIC___H__
|
||||
|
||||
#include <modules/server/include/topics/topic.h>
|
||||
|
||||
#include <openspace/interaction/websocketinputstate.h>
|
||||
|
||||
namespace openspace::interaction {
|
||||
|
||||
struct WebsocketInputStates;
|
||||
struct WebsocketInputState;
|
||||
}
|
||||
|
||||
namespace openspace {
|
||||
|
||||
class FlightControllerTopic : public Topic {
|
||||
public:
|
||||
FlightControllerTopic();
|
||||
~FlightControllerTopic();
|
||||
|
||||
void handleJson(const nlohmann::json& json) override;
|
||||
bool isDone() const override;
|
||||
|
||||
void engageAutopilot(const nlohmann::json &json);
|
||||
void disengageAutopilot() const;
|
||||
void handleAutopilot(const nlohmann::json &json);
|
||||
|
||||
private:
|
||||
bool _isDone = false;
|
||||
bool _autopilotEngaged;
|
||||
nlohmann::json _payload;
|
||||
nlohmann::json _focusNodes;
|
||||
nlohmann::json _allNodes;
|
||||
nlohmann::json _interestingTimes;
|
||||
|
||||
openspace::interaction::WebsocketInputStates _inputStates;
|
||||
openspace::interaction::WebsocketInputState _inputState;
|
||||
|
||||
void connect();
|
||||
void disconnect();
|
||||
void processInputState(const nlohmann::json& json);
|
||||
void setFocusNodes();
|
||||
void setInterestingTimes();
|
||||
void updateView(const nlohmann::json& json) const;
|
||||
void changeFocus(const nlohmann::json& json) const;
|
||||
void setRenderableEnabled(const nlohmann::json& json) const;
|
||||
void processLua(const nlohmann::json& json);
|
||||
void setFriction(const nlohmann::json& json) const;
|
||||
void setFriction(bool roll, bool rotation, bool zoom) const;
|
||||
void setFriction(bool all) const;
|
||||
};
|
||||
|
||||
} // namespace openspace
|
||||
|
||||
#endif // __OPENSPACE_MODULE_SERVER___FLIGHTCONTROLLER_TOPIC___H__
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <modules/server/include/topics/authorizationtopic.h>
|
||||
#include <modules/server/include/topics/bouncetopic.h>
|
||||
#include <modules/server/include/topics/documentationtopic.h>
|
||||
#include <modules/server/include/topics/flightcontrollertopic.h>
|
||||
#include <modules/server/include/topics/getpropertytopic.h>
|
||||
#include <modules/server/include/topics/luascripttopic.h>
|
||||
#include <modules/server/include/topics/sessionrecordingtopic.h>
|
||||
@@ -64,6 +65,7 @@ namespace {
|
||||
constexpr const char* TimeTopicKey = "time";
|
||||
constexpr const char* TriggerPropertyTopicKey = "trigger";
|
||||
constexpr const char* BounceTopicKey = "bounce";
|
||||
constexpr const char* FlightControllerTopicKey = "flightcontroller";
|
||||
} // namespace
|
||||
|
||||
namespace openspace {
|
||||
@@ -95,6 +97,7 @@ Connection::Connection(std::unique_ptr<ghoul::io::Socket> s,
|
||||
_topicFactory.registerClass<TimeTopic>(TimeTopicKey);
|
||||
_topicFactory.registerClass<TriggerPropertyTopic>(TriggerPropertyTopicKey);
|
||||
_topicFactory.registerClass<BounceTopic>(BounceTopicKey);
|
||||
_topicFactory.registerClass<FlightControllerTopic>(FlightControllerTopicKey);
|
||||
_topicFactory.registerClass<VersionTopic>(VersionTopicKey);
|
||||
}
|
||||
|
||||
@@ -125,8 +128,8 @@ void Connection::handleMessage(const std::string& message) {
|
||||
message.begin(),
|
||||
message.end(),
|
||||
sanitizedString.begin(),
|
||||
[](const unsigned char& c) {
|
||||
return std::isprint(c) ? c : ' ';
|
||||
[](wchar_t c) {
|
||||
return std::isprint(c, std::locale("")) ? c : ' ';
|
||||
}
|
||||
);
|
||||
LERROR(fmt::format("Could not parse JSON: '{}'", sanitizedString));
|
||||
|
||||
438
modules/server/src/topics/flightcontrollertopic.cpp
Normal file
438
modules/server/src/topics/flightcontrollertopic.cpp
Normal file
@@ -0,0 +1,438 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2019 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <modules/server/include/topics/flightcontrollertopic.h>
|
||||
|
||||
#include <modules/server/include/connection.h>
|
||||
#include <modules/server/include/jsonconverters.h>
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/interaction/inputstate.h>
|
||||
#include <openspace/interaction/websocketcamerastates.h>
|
||||
#include <openspace/interaction/websocketinputstate.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/interaction/orbitalnavigator.h>
|
||||
#include <openspace/rendering/renderable.h>
|
||||
#include <openspace/rendering/renderengine.h>
|
||||
#include <openspace/scene/scenegraphnode.h>
|
||||
#include <openspace/scene/scene.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
#include <openspace/util/timemanager.h>
|
||||
#include <ghoul/filesystem/file.h>
|
||||
#include <ghoul/filesystem/filesystem.h>
|
||||
#include <ghoul/fmt.h>
|
||||
#include <ghoul/logging/logmanager.h>
|
||||
#include <ghoul/lua/ghoul_lua.h>
|
||||
#include <iterator>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace {
|
||||
constexpr const char* BasePathToken = "${BASE}";
|
||||
|
||||
enum class Command {
|
||||
Connect = 0,
|
||||
Disconnect,
|
||||
InputState,
|
||||
UpdateView,
|
||||
Autopilot,
|
||||
Friction,
|
||||
Lua
|
||||
};
|
||||
|
||||
using AxisType = openspace::interaction::WebsocketCameraStates::AxisType;
|
||||
|
||||
constexpr const char* _loggerCat = "FlightControllerTopic";
|
||||
constexpr const char* TypeKey = "type";
|
||||
constexpr const char* ValuesKey = "values";
|
||||
|
||||
// Disconnect JSON keys
|
||||
constexpr const char* SuccessKey = "success";
|
||||
|
||||
// Connect JSON keys
|
||||
constexpr const char* FocusNodesKey = "focusNodes";
|
||||
constexpr const char* AllNodesKey = "allNodes";
|
||||
constexpr const char* InterestingTimesKey = "interestingTimes";
|
||||
|
||||
// Change focus JSON keys
|
||||
constexpr const char* FocusKey = "focus";
|
||||
constexpr const char* SceneNodeName = "identifier";
|
||||
constexpr const char* SceneNodeEnabled = "enabled";
|
||||
|
||||
constexpr const char* RenderableKey = "renderable";
|
||||
constexpr const char* RenderableEnabled = "Enabled";
|
||||
|
||||
// Autopilot JSON keys
|
||||
constexpr const char* AutopilotEngagedKey = "engaged";
|
||||
constexpr const char* AutopilotInputKey = "autopilotInput";
|
||||
|
||||
constexpr const char* FlightControllerType = "flightcontroller";
|
||||
|
||||
// Friction JSON Keys
|
||||
constexpr const char* FrictionEngagedKey = "engaged";
|
||||
constexpr const char* FrictionPropertyUri = "NavigationHandler.OrbitalNavigator.Friction";
|
||||
constexpr const char* FrictionRotationKey = "rotation";
|
||||
constexpr const char* FrictionZoomKey = "zoom";
|
||||
constexpr const char* FrictionRollKey = "roll";
|
||||
constexpr const char* RotationalFriction = "Friction.RotationalFriction";
|
||||
constexpr const char* ZoomFriction = "Friction.ZoomFriction";
|
||||
constexpr const char* RollFriction = "Friction.RollFriction";
|
||||
|
||||
// Friction Lua Keys
|
||||
constexpr const char* LuaKey = "lua";
|
||||
constexpr const char* LuaScript = "script";
|
||||
|
||||
constexpr const char* OrbitX = "orbitX";
|
||||
constexpr const char* OrbitY = "orbitY";
|
||||
constexpr const char* ZoomIn = "zoomIn";
|
||||
constexpr const char* ZoomOut = "zoomOut";
|
||||
constexpr const char* LocalRollX = "localRollX";
|
||||
constexpr const char* LocalRollY = "localRollY";
|
||||
constexpr const char* GlobalRollX = "globalRollX";
|
||||
constexpr const char* GlobalRollY = "globalRollY";
|
||||
constexpr const char* PanX = "panX";
|
||||
constexpr const char* PanY = "panY";
|
||||
|
||||
constexpr const char* Connect = "connect";
|
||||
constexpr const char* Disconnect = "disconnect";
|
||||
constexpr const char* InputState = "inputState";
|
||||
constexpr const char* UpdateView = "updateView";
|
||||
constexpr const char* Autopilot = "autopilot";
|
||||
constexpr const char* Friction = "friction";
|
||||
constexpr const char* Lua = "lua";
|
||||
|
||||
const static std::unordered_map<std::string, AxisType> AxisIndexMap ({
|
||||
{ OrbitX, AxisType::OrbitX },
|
||||
{ OrbitY, AxisType::OrbitY },
|
||||
{ ZoomIn, AxisType::ZoomIn },
|
||||
{ ZoomOut, AxisType::ZoomOut },
|
||||
{ LocalRollX, AxisType::LocalRollX },
|
||||
{ LocalRollY, AxisType::LocalRollY },
|
||||
{ GlobalRollX, AxisType::GlobalRollX },
|
||||
{ GlobalRollY, AxisType::GlobalRollY },
|
||||
{ PanX, AxisType::PanX },
|
||||
{ PanY, AxisType::PanY }
|
||||
});
|
||||
|
||||
const static std::unordered_map<std::string, Command> CommandMap ({
|
||||
{ Connect, Command::Connect },
|
||||
{ Disconnect, Command::Disconnect },
|
||||
{ InputState, Command::InputState },
|
||||
{ UpdateView, Command::UpdateView },
|
||||
{ Autopilot, Command::Autopilot },
|
||||
{ Friction, Command::Friction },
|
||||
{ Lua, Command::Lua }
|
||||
});
|
||||
|
||||
const int Axes = 10;
|
||||
|
||||
} // namespace
|
||||
|
||||
using nlohmann::json;
|
||||
|
||||
namespace openspace {
|
||||
|
||||
FlightControllerTopic::FlightControllerTopic() {
|
||||
for (auto it = AxisIndexMap.begin(); it != AxisIndexMap.end(); ++it) {
|
||||
global::navigationHandler.setWebsocketAxisMapping(
|
||||
int(std::distance(AxisIndexMap.begin(), it)),
|
||||
it->second
|
||||
);
|
||||
}
|
||||
|
||||
// Add WebsocketInputState to global states
|
||||
global::websocketInputStates[_topicId] = &_inputState;
|
||||
}
|
||||
|
||||
FlightControllerTopic::~FlightControllerTopic() {
|
||||
// Reset global websocketInputStates
|
||||
global::websocketInputStates.erase(_topicId);
|
||||
global::websocketInputStates = interaction::WebsocketInputStates();
|
||||
}
|
||||
|
||||
bool FlightControllerTopic::isDone() const {
|
||||
if (_isDone) {
|
||||
disengageAutopilot();
|
||||
}
|
||||
return _isDone;
|
||||
}
|
||||
|
||||
void FlightControllerTopic::handleJson(const nlohmann::json& json) {
|
||||
auto it = CommandMap.find(json[TypeKey]);
|
||||
if (it == CommandMap.end()) {
|
||||
LWARNING(fmt::format("Poorly formatted JSON command: no '{}' in payload", TypeKey));
|
||||
return;
|
||||
}
|
||||
|
||||
switch (it->second) {
|
||||
case Command::Connect:
|
||||
connect();
|
||||
break;
|
||||
case Command::Disconnect:
|
||||
disconnect();
|
||||
break;
|
||||
case Command::InputState:
|
||||
processInputState(json);
|
||||
break;
|
||||
case Command::UpdateView:
|
||||
updateView(json);
|
||||
break;
|
||||
case Command::Autopilot:
|
||||
handleAutopilot(json[Autopilot]);
|
||||
break;
|
||||
case Command::Friction:
|
||||
setFriction(json[Friction]);
|
||||
break;
|
||||
case Command::Lua:
|
||||
processLua(json[Lua]);
|
||||
break;
|
||||
default:
|
||||
LWARNING(fmt::format("Unrecognized action: {}", it->first));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void FlightControllerTopic::connect() {
|
||||
_isDone = false;
|
||||
std::fill(_inputState.axes.begin(), _inputState.axes.end(), 0);
|
||||
_payload[TypeKey] = Connect;
|
||||
setFocusNodes();
|
||||
setInterestingTimes();
|
||||
_payload[Connect][FocusNodesKey] = _focusNodes;
|
||||
_payload[Connect][AllNodesKey] = _allNodes;
|
||||
_payload[Connect][InterestingTimesKey] = _interestingTimes;
|
||||
_connection->sendJson(wrappedPayload(_payload));
|
||||
}
|
||||
|
||||
void FlightControllerTopic::setFocusNodes() {
|
||||
// Get all scene nodes
|
||||
std::vector<SceneGraphNode*> nodes =
|
||||
global::renderEngine.scene()->allSceneGraphNodes();
|
||||
|
||||
// Remove all nodes with no renderable
|
||||
nodes.erase(
|
||||
std::remove_if(
|
||||
nodes.begin(),
|
||||
nodes.end(),
|
||||
[](SceneGraphNode* node) { return node->renderable() == nullptr; }
|
||||
),
|
||||
nodes.end()
|
||||
);
|
||||
|
||||
// Sort them alphabetically
|
||||
std::sort(
|
||||
nodes.begin(),
|
||||
nodes.end(),
|
||||
[](SceneGraphNode* lhs, SceneGraphNode* rhs) {
|
||||
return lhs->guiName() < rhs->guiName();
|
||||
}
|
||||
);
|
||||
|
||||
// Add to interesting nodes list and all nodes list
|
||||
for (SceneGraphNode* n : nodes) {
|
||||
// Set whether it's enabled
|
||||
const std::vector<std::string>& tags = n->tags();
|
||||
const auto it = std::find(tags.begin(), tags.end(), "GUI.Interesting");
|
||||
if (it != tags.end()) {
|
||||
_focusNodes[n->guiName()][SceneNodeName] = n->identifier();
|
||||
_focusNodes[n->guiName()][SceneNodeEnabled] = n->renderable()->isEnabled();
|
||||
}
|
||||
_allNodes[n->guiName()][SceneNodeName] = n->identifier();
|
||||
_allNodes[n->guiName()][SceneNodeEnabled] = n->renderable()->isEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
void FlightControllerTopic::setInterestingTimes() {
|
||||
std::vector<Scene::InterestingTime> times =
|
||||
global::renderEngine.scene()->interestingTimes();
|
||||
|
||||
std::sort(
|
||||
times.begin(),
|
||||
times.end(),
|
||||
[](Scene::InterestingTime lhs, Scene::InterestingTime rhs) {
|
||||
return lhs.name < rhs.name;
|
||||
}
|
||||
);
|
||||
|
||||
for (const Scene::InterestingTime& t : times) {
|
||||
_interestingTimes[t.name] = t.time;
|
||||
}
|
||||
}
|
||||
|
||||
void FlightControllerTopic::updateView(const nlohmann::json& json) const {
|
||||
if (json.find(FocusKey) != json.end()) {
|
||||
changeFocus(json);
|
||||
}
|
||||
if (json.find(RenderableKey) != json.end()) {
|
||||
setRenderableEnabled(json);
|
||||
}
|
||||
}
|
||||
|
||||
void FlightControllerTopic::changeFocus(const nlohmann::json& json) const {
|
||||
if (json[FocusKey].find(SceneNodeName) == json[FocusKey].end()) {
|
||||
const std::string j = json;
|
||||
LWARNING(fmt::format("Could not find {} key in JSON. JSON was:\n{}", FocusKey, j));
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string focus = json[FocusKey][SceneNodeName];
|
||||
const SceneGraphNode* node = global::renderEngine.scene()->sceneGraphNode(focus);
|
||||
if (node) {
|
||||
global::navigationHandler.orbitalNavigator().setFocusNode(node->identifier());
|
||||
global::navigationHandler.orbitalNavigator().startRetargetAnchor();
|
||||
}
|
||||
else {
|
||||
LWARNING(fmt::format("Could not find node named {}", focus));
|
||||
}
|
||||
}
|
||||
|
||||
void FlightControllerTopic::setRenderableEnabled(const nlohmann::json& json) const {
|
||||
if (json[RenderableKey].find(SceneNodeName) == json[RenderableKey].end()) {
|
||||
const std::string j = json;
|
||||
LWARNING(fmt::format("Could not find {} key in JSON. JSON was:\n{}", FocusKey, j));
|
||||
return;
|
||||
}
|
||||
|
||||
const std::string name = json[RenderableKey][SceneNodeName];
|
||||
const bool enabled = json[RenderableKey][SceneNodeEnabled];
|
||||
|
||||
const SceneGraphNode* node = global::renderEngine.scene()->sceneGraphNode(name);
|
||||
if (node && node->renderable() != nullptr) {
|
||||
node->renderable()->property(RenderableEnabled)->set(enabled);
|
||||
}
|
||||
}
|
||||
|
||||
void FlightControllerTopic::disconnect() {
|
||||
// Reset global websocketInputStates
|
||||
global::websocketInputStates.erase(_topicId);
|
||||
global::websocketInputStates = interaction::WebsocketInputStates();
|
||||
|
||||
// Update FlightController
|
||||
nlohmann::json j;
|
||||
j[TypeKey] = Disconnect;
|
||||
j[Disconnect][SuccessKey] = true;
|
||||
_connection->sendJson(wrappedPayload(j));
|
||||
|
||||
_isDone = true;
|
||||
}
|
||||
|
||||
void FlightControllerTopic::setFriction(bool all) const {
|
||||
setFriction(all, all, all);
|
||||
}
|
||||
|
||||
void FlightControllerTopic::setFriction(bool roll, bool rotation, bool zoom) const {
|
||||
const interaction::OrbitalNavigator& navigator =
|
||||
global::navigationHandler.orbitalNavigator();
|
||||
|
||||
navigator.property(RollFriction)->set(roll);
|
||||
navigator.property(RotationalFriction)->set(rotation);
|
||||
navigator.property(ZoomFriction)->set(zoom);
|
||||
|
||||
// Update FlightController
|
||||
nlohmann::json j;
|
||||
j[TypeKey] = Friction;
|
||||
j[Friction][FrictionRollKey] = roll;
|
||||
j[Friction][FrictionRotationKey] = rotation;
|
||||
j[Friction][FrictionZoomKey] = zoom;
|
||||
_connection->sendJson(wrappedPayload(j));
|
||||
}
|
||||
|
||||
void FlightControllerTopic::setFriction(const nlohmann::json& json) const {
|
||||
setFriction(json[FrictionRollKey], json[FrictionRotationKey], json[FrictionZoomKey]);
|
||||
}
|
||||
|
||||
void FlightControllerTopic::disengageAutopilot() const {
|
||||
setFriction(true);
|
||||
}
|
||||
|
||||
void FlightControllerTopic::engageAutopilot(const nlohmann::json &json) {
|
||||
// Disable/enable friction
|
||||
setFriction(false);
|
||||
auto input = json[AutopilotInputKey][ValuesKey];
|
||||
|
||||
std::fill(_inputState.axes.begin(), _inputState.axes.end(), 0);
|
||||
_inputState.isConnected = true;
|
||||
|
||||
for (auto it = input.begin(); it != input.end(); ++it) {
|
||||
const auto mapIt = AxisIndexMap.find(it.key());
|
||||
if (mapIt == AxisIndexMap.end()) {
|
||||
if (it.key() != TypeKey || CommandMap.find(it.value()) == CommandMap.end()) {
|
||||
LWARNING(fmt::format(
|
||||
"No axis, button, or command named {} (value: {})",
|
||||
it.key(), static_cast<int>(it.value())
|
||||
));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
_inputState.axes[std::distance(AxisIndexMap.begin(), mapIt)] = float(it.value());
|
||||
}
|
||||
}
|
||||
|
||||
void FlightControllerTopic::handleAutopilot(const nlohmann::json &json) {
|
||||
const bool engaged = json[AutopilotEngagedKey];
|
||||
|
||||
if (engaged) {
|
||||
engageAutopilot(json);
|
||||
}
|
||||
else {
|
||||
disengageAutopilot();
|
||||
}
|
||||
_autopilotEngaged = engaged;
|
||||
|
||||
nlohmann::json j;
|
||||
j[TypeKey] = Autopilot;
|
||||
j[Autopilot][AutopilotEngagedKey] = _autopilotEngaged;
|
||||
|
||||
_connection->sendJson(wrappedPayload(j));
|
||||
}
|
||||
|
||||
void FlightControllerTopic::processInputState(const nlohmann::json& json) {
|
||||
std::fill(_inputState.axes.begin(), _inputState.axes.end(), 0);
|
||||
_inputState.isConnected = true;
|
||||
|
||||
// Get "inputState" object from "payload"
|
||||
auto input = json[InputState][ValuesKey];
|
||||
|
||||
for (auto it = input.begin(); it != input.end(); ++it) {
|
||||
const auto mapIt = AxisIndexMap.find(it.key());
|
||||
if (mapIt == AxisIndexMap.end()) {
|
||||
if (it.key() != TypeKey || CommandMap.find(it.value()) == CommandMap.end()) {
|
||||
LWARNING(fmt::format(
|
||||
"No axis, button, or command named {} (value: {})",
|
||||
it.key() , static_cast<int>(it.value())
|
||||
));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
_inputState.axes[std::distance(AxisIndexMap.begin(), mapIt)] = float(it.value());
|
||||
}
|
||||
}
|
||||
|
||||
void FlightControllerTopic::processLua(const nlohmann::json &json) {
|
||||
const std::string script = json[LuaScript];
|
||||
global::scriptEngine.queueScript(
|
||||
script,
|
||||
openspace::scripting::ScriptEngine::RemoteScripting::Yes
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace openspace
|
||||
@@ -54,11 +54,14 @@ set(OPENSPACE_SOURCE
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/navigationhandler_lua.inl
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/mousecamerastates.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/orbitalnavigator.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/scriptcamerastates.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/externinteraction.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/sessionrecording.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/sessionrecording_lua.inl
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/shortcutmanager.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/shortcutmanager_lua.inl
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/websocketinputstate.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/websocketcamerastates.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/mission/mission.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/mission/missionmanager.cpp
|
||||
${OPENSPACE_BASE_DIR}/src/mission/missionmanager_lua.inl
|
||||
@@ -202,7 +205,6 @@ if (APPLE)
|
||||
${OPENSPACE_BASE_DIR}/src/interaction/touchbar.mm
|
||||
)
|
||||
endif ()
|
||||
|
||||
set(OPENSPACE_HEADER
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/json.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/documentation/core_registration.h
|
||||
@@ -236,9 +238,12 @@ set(OPENSPACE_HEADER
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/navigationhandler.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/orbitalnavigator.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/externinteraction.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/scriptcamerastates.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/sessionrecording.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/sessionrecording.inl
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/shortcutmanager.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/websocketinputstate.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/interaction/websocketcamerastates.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/mission/mission.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/mission/missionmanager.h
|
||||
${OPENSPACE_BASE_DIR}/include/openspace/network/parallelconnection.h
|
||||
|
||||
@@ -94,8 +94,6 @@ template <>
|
||||
std::string to_string(const openspace::documentation::TestResult::Offense::Reason& value)
|
||||
{
|
||||
switch (value) {
|
||||
case openspace::documentation::TestResult::Offense::Reason::ExtraKey:
|
||||
return "Extra key";
|
||||
case openspace::documentation::TestResult::Offense::Reason::MissingKey:
|
||||
return "Missing key";
|
||||
case openspace::documentation::TestResult::Offense::Reason::UnknownIdentifier:
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
#include <openspace/engine/windowdelegate.h>
|
||||
#include <openspace/interaction/keybindingmanager.h>
|
||||
#include <openspace/interaction/joystickinputstate.h>
|
||||
#include <openspace/interaction/websocketinputstate.h>
|
||||
#include <openspace/interaction/navigationhandler.h>
|
||||
#include <openspace/interaction/sessionrecording.h>
|
||||
#include <openspace/interaction/shortcutmanager.h>
|
||||
@@ -154,6 +155,11 @@ interaction::JoystickInputStates& gJoystickInputStates() {
|
||||
return g;
|
||||
}
|
||||
|
||||
interaction::WebsocketInputStates& gWebsocketInputStates() {
|
||||
static interaction::WebsocketInputStates g;
|
||||
return g;
|
||||
}
|
||||
|
||||
interaction::KeybindingManager& gKeybindingManager() {
|
||||
static interaction::KeybindingManager g;
|
||||
return g;
|
||||
|
||||
@@ -708,6 +708,10 @@ void OpenSpaceEngine::loadSingleAsset(const std::string& assetPath) {
|
||||
|
||||
bool loading = true;
|
||||
while (loading) {
|
||||
if (_shouldAbortLoading) {
|
||||
global::windowDelegate.terminate();
|
||||
break;
|
||||
}
|
||||
_loadingScreen->render();
|
||||
_assetManager->update();
|
||||
|
||||
@@ -719,10 +723,10 @@ void OpenSpaceEngine::loadSingleAsset(const std::string& assetPath) {
|
||||
progressInfo.progress = (*it)->progress();
|
||||
|
||||
if ((*it)->nTotalBytesIsKnown()) {
|
||||
progressInfo.currentSize = static_cast<int>(
|
||||
progressInfo.currentSize = static_cast<uint64_t>(
|
||||
(*it)->nSynchronizedBytes()
|
||||
);
|
||||
progressInfo.totalSize = static_cast<int>(
|
||||
progressInfo.totalSize = static_cast<uint64_t>(
|
||||
(*it)->nTotalBytes()
|
||||
);
|
||||
}
|
||||
@@ -750,6 +754,10 @@ void OpenSpaceEngine::loadSingleAsset(const std::string& assetPath) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (_shouldAbortLoading) {
|
||||
_loadingScreen = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
_loadingScreen->setPhase(LoadingScreen::Phase::Initialization);
|
||||
|
||||
@@ -992,7 +1000,8 @@ void OpenSpaceEngine::preSynchronization() {
|
||||
|
||||
global::syncEngine.preSynchronization(SyncEngine::IsMaster(master));
|
||||
if (master) {
|
||||
double dt = global::windowDelegate.averageDeltaTime();
|
||||
|
||||
double dt = global::windowDelegate.deltaTime();
|
||||
|
||||
if (global::sessionRecording.isSavingFramesDuringPlayback()) {
|
||||
dt = global::sessionRecording.fixedDeltaTimeDuringFrameOutput();
|
||||
@@ -1183,6 +1192,16 @@ void OpenSpaceEngine::postDraw() {
|
||||
}
|
||||
|
||||
void OpenSpaceEngine::keyboardCallback(Key key, KeyModifier mod, KeyAction action) {
|
||||
if (_loadingScreen) {
|
||||
// If the loading screen object exists, we are currently loading and want key
|
||||
// presses to behave differently
|
||||
if (key == Key::Escape) {
|
||||
_shouldAbortLoading = true;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
using F = std::function<bool (Key, KeyModifier, KeyAction)>;
|
||||
for (const F& func : global::callback::keyboard) {
|
||||
const bool isConsumed = func(key, mod, action);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <openspace/engine/globals.h>
|
||||
#include <openspace/interaction/joystickinputstate.h>
|
||||
#include <openspace/interaction/websocketinputstate.h>
|
||||
#include <ghoul/fmt.h>
|
||||
#include <algorithm>
|
||||
|
||||
@@ -91,10 +92,13 @@ bool InputState::isKeyPressed(std::pair<Key, KeyModifier> keyModPair) const {
|
||||
}
|
||||
|
||||
bool InputState::isKeyPressed(Key key) const {
|
||||
auto it = std::find_if(_keysDown.begin(), _keysDown.end(),
|
||||
auto it = std::find_if(
|
||||
_keysDown.begin(),
|
||||
_keysDown.end(),
|
||||
[key](const std::pair<Key, KeyModifier>& keyModPair) {
|
||||
return key == keyModPair.first;
|
||||
});
|
||||
return key == keyModPair.first;
|
||||
}
|
||||
);
|
||||
return it != _keysDown.end();
|
||||
}
|
||||
|
||||
@@ -111,4 +115,24 @@ bool InputState::joystickButton(int i) const {
|
||||
return global::joystickInputStates.button(i, JoystickAction::Press);
|
||||
}
|
||||
|
||||
float InputState::websocketAxis(int i) const {
|
||||
return global::websocketInputStates.axis(i);
|
||||
}
|
||||
|
||||
bool InputState::websocketButton(int i) const {
|
||||
return global::websocketInputStates.button(i, WebsocketAction::Press);
|
||||
}
|
||||
|
||||
void InputState::resetWebsockets() {
|
||||
using K = size_t;
|
||||
using V = WebsocketInputState*;
|
||||
for (const std::pair<const K, V>& p : global::websocketInputStates) {
|
||||
p.second->isConnected = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool InputState::hasWebsocketStates() const {
|
||||
return !global::websocketInputStates.empty();
|
||||
}
|
||||
|
||||
} // namespace openspace::interaction
|
||||
|
||||
@@ -67,7 +67,7 @@ namespace openspace::interaction {
|
||||
|
||||
|
||||
ghoul::Dictionary
|
||||
openspace::interaction::NavigationHandler::NavigationState::dictionary() const
|
||||
openspace::interaction::NavigationHandler::NavigationState::dictionary() const
|
||||
{
|
||||
ghoul::Dictionary cameraDict;
|
||||
cameraDict.setValue(KeyPosition, position);
|
||||
@@ -94,7 +94,7 @@ openspace::interaction::NavigationHandler::NavigationState::dictionary() const
|
||||
}
|
||||
|
||||
openspace::interaction::NavigationHandler::NavigationState::NavigationState(
|
||||
const ghoul::Dictionary& dictionary)
|
||||
const ghoul::Dictionary& dictionary)
|
||||
{
|
||||
const bool hasAnchor = dictionary.hasValue<std::string>(KeyAnchor);
|
||||
const bool hasPosition = dictionary.hasValue<glm::dvec3>(KeyPosition);
|
||||
@@ -130,13 +130,13 @@ openspace::interaction::NavigationHandler::NavigationState::NavigationState(
|
||||
}
|
||||
|
||||
openspace::interaction::NavigationHandler::NavigationState::NavigationState(
|
||||
std::string anchor,
|
||||
std::string aim,
|
||||
std::string referenceFrame,
|
||||
glm::dvec3 position,
|
||||
std::optional<glm::dvec3> up,
|
||||
double yaw,
|
||||
double pitch)
|
||||
std::string anchor,
|
||||
std::string aim,
|
||||
std::string referenceFrame,
|
||||
glm::dvec3 position,
|
||||
std::optional<glm::dvec3> up,
|
||||
double yaw,
|
||||
double pitch)
|
||||
: anchor(std::move(anchor))
|
||||
, aim(std::move(aim))
|
||||
, referenceFrame(std::move(referenceFrame))
|
||||
@@ -214,7 +214,8 @@ void NavigationHandler::updateCamera(double deltaTime) {
|
||||
applyNavigationState(_pendingNavigationState.value());
|
||||
_orbitalNavigator.resetVelocities();
|
||||
_pendingNavigationState.reset();
|
||||
} else if (!_playbackModeEnabled && _camera) {
|
||||
}
|
||||
else if (!_playbackModeEnabled && _camera) {
|
||||
if (_useKeyFrameInteraction) {
|
||||
_keyframeNavigator.updateCamera(*_camera, _playbackModeEnabled);
|
||||
}
|
||||
@@ -272,7 +273,7 @@ void NavigationHandler::applyNavigationState(const NavigationHandler::Navigation
|
||||
// Construct vectors of a "neutral" view, i.e. when the aim is centered in view.
|
||||
glm::dvec3 neutralView =
|
||||
glm::normalize(aimNode->worldPosition() - cameraPositionWorld);
|
||||
|
||||
|
||||
glm::dquat neutralCameraRotation = glm::inverse(glm::quat_cast(glm::lookAt(
|
||||
glm::dvec3(0.0),
|
||||
neutralView,
|
||||
@@ -331,7 +332,7 @@ void NavigationHandler::keyboardCallback(Key key, KeyModifier modifier, KeyActio
|
||||
}
|
||||
|
||||
NavigationHandler::NavigationState NavigationHandler::navigationState(
|
||||
const SceneGraphNode& referenceFrame) const
|
||||
const SceneGraphNode& referenceFrame) const
|
||||
{
|
||||
const SceneGraphNode* anchor = _orbitalNavigator.anchorNode();
|
||||
const SceneGraphNode* aim = _orbitalNavigator.aimNode();
|
||||
@@ -355,7 +356,7 @@ NavigationHandler::NavigationState NavigationHandler::navigationState(
|
||||
// Need to compensate by redisual roll left in local rotation:
|
||||
const glm::dquat unroll = glm::angleAxis(eulerAngles.z, glm::dvec3(0, 0, 1));
|
||||
const glm::dvec3 neutralUp =
|
||||
glm::inverse(invNeutralRotation) * unroll * _camera->lookUpVectorCameraSpace();
|
||||
glm::inverse(invNeutralRotation) * unroll * _camera->lookUpVectorCameraSpace();
|
||||
|
||||
const glm::dmat3 invReferenceFrameTransform =
|
||||
glm::inverse(referenceFrame.worldRotationMatrix());
|
||||
@@ -366,7 +367,7 @@ NavigationHandler::NavigationState NavigationHandler::navigationState(
|
||||
return NavigationState(
|
||||
_orbitalNavigator.anchorNode()->identifier(),
|
||||
_orbitalNavigator.aimNode() ?
|
||||
_orbitalNavigator.aimNode()->identifier() : "",
|
||||
_orbitalNavigator.aimNode()->identifier() : "",
|
||||
referenceFrame.identifier(),
|
||||
position,
|
||||
invReferenceFrameTransform * neutralUp, yaw, pitch
|
||||
@@ -374,7 +375,7 @@ NavigationHandler::NavigationState NavigationHandler::navigationState(
|
||||
}
|
||||
|
||||
void NavigationHandler::saveNavigationState(const std::string& filepath,
|
||||
const std::string& referenceFrameIdentifier)
|
||||
const std::string& referenceFrameIdentifier)
|
||||
{
|
||||
const SceneGraphNode* referenceFrame = _orbitalNavigator.followingNodeRotation() ?
|
||||
_orbitalNavigator.anchorNode() :
|
||||
@@ -428,9 +429,9 @@ void NavigationHandler::loadNavigationState(const std::string& filepath) {
|
||||
}
|
||||
|
||||
void NavigationHandler::setJoystickAxisMapping(int axis,
|
||||
JoystickCameraStates::AxisType mapping,
|
||||
JoystickCameraStates::AxisInvert shouldInvert,
|
||||
JoystickCameraStates::AxisNormalize shouldNormalize)
|
||||
JoystickCameraStates::AxisType mapping,
|
||||
JoystickCameraStates::AxisInvert shouldInvert,
|
||||
JoystickCameraStates::AxisNormalize shouldNormalize)
|
||||
{
|
||||
_orbitalNavigator.joystickStates().setAxisMapping(
|
||||
axis,
|
||||
@@ -440,8 +441,22 @@ void NavigationHandler::setJoystickAxisMapping(int axis,
|
||||
);
|
||||
}
|
||||
|
||||
void NavigationHandler::setWebsocketAxisMapping(int axis,
|
||||
WebsocketCameraStates::AxisType mapping,
|
||||
WebsocketCameraStates::AxisInvert shouldInvert,
|
||||
WebsocketCameraStates::AxisNormalize shouldNormalize)
|
||||
{
|
||||
_orbitalNavigator.websocketStates().setAxisMapping(
|
||||
axis,
|
||||
mapping,
|
||||
shouldInvert,
|
||||
shouldNormalize
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
JoystickCameraStates::AxisInformation
|
||||
NavigationHandler::joystickAxisMapping(int axis) const
|
||||
NavigationHandler::joystickAxisMapping(int axis) const
|
||||
{
|
||||
return _orbitalNavigator.joystickStates().axisMapping(axis);
|
||||
}
|
||||
@@ -455,9 +470,9 @@ float NavigationHandler::joystickAxisDeadzone(int axis) const {
|
||||
}
|
||||
|
||||
void NavigationHandler::bindJoystickButtonCommand(int button, std::string command,
|
||||
JoystickAction action,
|
||||
JoystickCameraStates::ButtonCommandRemote remote,
|
||||
std::string documentation)
|
||||
JoystickAction action,
|
||||
JoystickCameraStates::ButtonCommandRemote remote,
|
||||
std::string documentation)
|
||||
{
|
||||
_orbitalNavigator.joystickStates().bindButtonCommand(
|
||||
button,
|
||||
@@ -635,6 +650,41 @@ scripting::LuaLibrary NavigationHandler::luaLibrary() {
|
||||
"int",
|
||||
"Returns the script that is currently bound to be executed when the "
|
||||
"provided button is pressed"
|
||||
},
|
||||
{
|
||||
"addGlobalRotation",
|
||||
&luascriptfunctions::addGlobalRotation,
|
||||
{},
|
||||
"double, double",
|
||||
"Directly adds to the global rotation of the camera"
|
||||
},
|
||||
{
|
||||
"addLocalRotation",
|
||||
&luascriptfunctions::addLocalRotation,
|
||||
{},
|
||||
"double, double",
|
||||
"Directly adds to the local rotation of the camera"
|
||||
},
|
||||
{
|
||||
"addTruckMovement",
|
||||
&luascriptfunctions::addTruckMovement,
|
||||
{},
|
||||
"double, double",
|
||||
"Directly adds to the truck movement of the camera"
|
||||
},
|
||||
{
|
||||
"addLocalRoll",
|
||||
&luascriptfunctions::addLocalRoll,
|
||||
{},
|
||||
"double, double",
|
||||
"Directly adds to the local roll of the camera"
|
||||
},
|
||||
{
|
||||
"addGlobalRoll",
|
||||
&luascriptfunctions::addGlobalRoll,
|
||||
{},
|
||||
"double, double",
|
||||
"Directly adds to the global roll of the camera"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
****************************************************************************************/
|
||||
|
||||
#include <numeric>
|
||||
#include <openspace/interaction/scriptcamerastates.h>
|
||||
|
||||
namespace openspace::luascriptfunctions {
|
||||
|
||||
@@ -51,9 +52,7 @@ int setNavigationState(lua_State* L) {
|
||||
ghoul::Dictionary navigationStateDictionary;
|
||||
ghoul::lua::luaDictionaryFromState(L, navigationStateDictionary);
|
||||
|
||||
using namespace openspace::documentation;
|
||||
|
||||
TestResult r = testSpecification(
|
||||
openspace::documentation::TestResult r = openspace::documentation::testSpecification(
|
||||
interaction::NavigationHandler::NavigationState::Documentation(),
|
||||
navigationStateDictionary
|
||||
);
|
||||
@@ -61,8 +60,7 @@ int setNavigationState(lua_State* L) {
|
||||
if (!r.success) {
|
||||
lua_settop(L, 0);
|
||||
return ghoul::lua::luaError(
|
||||
L,
|
||||
fmt::format("Could not set camera state: {}", ghoul::to_string(r))
|
||||
L, fmt::format("Could not set camera state: {}", ghoul::to_string(r))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -250,4 +248,74 @@ int joystickButton(lua_State* L) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
int addGlobalRotation(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addGlobalRotation");
|
||||
|
||||
const double v1 = ghoul::lua::value<double>(L, 1, ghoul::lua::PopValue::No);
|
||||
const double v2 = ghoul::lua::value<double>(L, 2, ghoul::lua::PopValue::No);
|
||||
|
||||
global::navigationHandler.orbitalNavigator().scriptStates().addGlobalRotation(
|
||||
glm::dvec2(v1, v2)
|
||||
);
|
||||
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int addLocalRotation(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addLocalRotation");
|
||||
|
||||
const double v1 = ghoul::lua::value<double>(L, 1, ghoul::lua::PopValue::No);
|
||||
const double v2 = ghoul::lua::value<double>(L, 2, ghoul::lua::PopValue::No);
|
||||
|
||||
global::navigationHandler.orbitalNavigator().scriptStates().addLocalRotation(
|
||||
glm::dvec2(v1, v2)
|
||||
);
|
||||
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int addTruckMovement(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addTruckMovement");
|
||||
|
||||
const double v1 = ghoul::lua::value<double>(L, 1, ghoul::lua::PopValue::No);
|
||||
const double v2 = ghoul::lua::value<double>(L, 2, ghoul::lua::PopValue::No);
|
||||
|
||||
global::navigationHandler.orbitalNavigator().scriptStates().addTruckMovement(
|
||||
glm::dvec2(v1, v2)
|
||||
);
|
||||
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int addLocalRoll(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addLocalRoll");
|
||||
|
||||
const double v1 = ghoul::lua::value<double>(L, 1, ghoul::lua::PopValue::No);
|
||||
const double v2 = ghoul::lua::value<double>(L, 2, ghoul::lua::PopValue::No);
|
||||
|
||||
global::navigationHandler.orbitalNavigator().scriptStates().addLocalRoll(
|
||||
glm::dvec2(v1, v2)
|
||||
);
|
||||
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int addGlobalRoll(lua_State* L) {
|
||||
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::addGlobalRoll");
|
||||
|
||||
const double v1 = ghoul::lua::value<double>(L, 1, ghoul::lua::PopValue::No);
|
||||
const double v2 = ghoul::lua::value<double>(L, 2, ghoul::lua::PopValue::No);
|
||||
|
||||
global::navigationHandler.orbitalNavigator().scriptStates().addGlobalRoll(
|
||||
glm::dvec2(v1, v2)
|
||||
);
|
||||
|
||||
lua_settop(L, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace openspace::luascriptfunctions
|
||||
|
||||
@@ -109,6 +109,13 @@ namespace {
|
||||
"the sensitivity is the less impact a joystick motion will have."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo WebsocketSensitivityInfo = {
|
||||
"WebsocketSensitivity",
|
||||
"Websocket Sensitivity",
|
||||
"Determines the sensitivity of the camera motion thorugh a websocket. The lower "
|
||||
"the sensitivity is the less impact a webstick motion will have."
|
||||
};
|
||||
|
||||
constexpr openspace::properties::Property::PropertyInfo FrictionInfo = {
|
||||
"Friction",
|
||||
"Friction Factor",
|
||||
@@ -205,6 +212,7 @@ OrbitalNavigator::OrbitalNavigator()
|
||||
, _minimumAllowedDistance(MinimumDistanceInfo, 10.0f, 0.0f, 10000.f)
|
||||
, _mouseSensitivity(MouseSensitivityInfo, 15.0f, 1.0f, 50.f)
|
||||
, _joystickSensitivity(JoystickSensitivityInfo, 10.0f, 1.0f, 50.f)
|
||||
, _websocketSensitivity(WebsocketSensitivityInfo, 10.0f, 1.0f, 50.f)
|
||||
, _useAdaptiveStereoscopicDepth(UseAdaptiveStereoscopicDepthInfo, true)
|
||||
, _stereoscopicDepthOfFocusSurface(StereoscopicDepthOfFocusSurfaceInfo, 8, 0.25, 100)
|
||||
, _staticViewScaleExponent(StaticViewScaleExponentInfo, 0.f, -30, 10)
|
||||
@@ -213,6 +221,7 @@ OrbitalNavigator::OrbitalNavigator()
|
||||
, _followRotationInterpolationTime(FollowRotationInterpTimeInfo, 1.0, 0.0, 10.0)
|
||||
, _mouseStates(_mouseSensitivity * 0.0001, 1 / (_friction.friction + 0.0000001))
|
||||
, _joystickStates(_joystickSensitivity * 0.1, 1 / (_friction.friction + 0.0000001))
|
||||
, _websocketStates(_websocketSensitivity, 1 / (_friction.friction + 0.0000001))
|
||||
{
|
||||
|
||||
_anchor.onChange([this]() {
|
||||
@@ -290,26 +299,34 @@ OrbitalNavigator::OrbitalNavigator()
|
||||
_friction.roll.onChange([&]() {
|
||||
_mouseStates.setRotationalFriction(_friction.roll);
|
||||
_joystickStates.setRotationalFriction(_friction.roll);
|
||||
_websocketStates.setRotationalFriction(_friction.roll);
|
||||
});
|
||||
_friction.rotational.onChange([&]() {
|
||||
_mouseStates.setHorizontalFriction(_friction.rotational);
|
||||
_joystickStates.setHorizontalFriction(_friction.rotational);
|
||||
_websocketStates.setHorizontalFriction(_friction.rotational);
|
||||
});
|
||||
_friction.zoom.onChange([&]() {
|
||||
_mouseStates.setVerticalFriction(_friction.zoom);
|
||||
_joystickStates.setVerticalFriction(_friction.zoom);
|
||||
_websocketStates.setVerticalFriction(_friction.zoom);
|
||||
});
|
||||
_friction.friction.onChange([&]() {
|
||||
_mouseStates.setVelocityScaleFactor(1 / (_friction.friction + 0.0000001));
|
||||
_joystickStates.setVelocityScaleFactor(1 / (_friction.friction + 0.0000001));
|
||||
_websocketStates.setVelocityScaleFactor(1 / (_friction.friction + 0.0000001));
|
||||
});
|
||||
|
||||
_mouseSensitivity.onChange([&]() {
|
||||
_mouseStates.setSensitivity(_mouseSensitivity * pow(10.0, -4));
|
||||
});
|
||||
_joystickSensitivity.onChange([&]() {
|
||||
_joystickStates.setSensitivity(_joystickSensitivity * pow(10.0, -4));
|
||||
_joystickStates.setSensitivity(_joystickSensitivity * 0.1);
|
||||
});
|
||||
_websocketSensitivity.onChange([&]() {
|
||||
_websocketStates.setSensitivity(_websocketSensitivity);
|
||||
});
|
||||
|
||||
|
||||
addPropertySubOwner(_friction);
|
||||
|
||||
@@ -331,6 +348,7 @@ OrbitalNavigator::OrbitalNavigator()
|
||||
|
||||
addProperty(_mouseSensitivity);
|
||||
addProperty(_joystickSensitivity);
|
||||
addProperty(_websocketSensitivity);
|
||||
}
|
||||
|
||||
glm::dvec3 OrbitalNavigator::anchorNodeToCameraVector() const {
|
||||
@@ -348,6 +366,7 @@ glm::quat OrbitalNavigator::anchorNodeToCameraRotation() const {
|
||||
void OrbitalNavigator::resetVelocities() {
|
||||
_mouseStates.resetVelocities();
|
||||
_joystickStates.resetVelocities();
|
||||
_scriptStates.resetVelocities();
|
||||
}
|
||||
|
||||
void OrbitalNavigator::updateStatesFromInput(const InputState& inputState,
|
||||
@@ -355,6 +374,8 @@ void OrbitalNavigator::updateStatesFromInput(const InputState& inputState,
|
||||
{
|
||||
_mouseStates.updateStateFromInput(inputState, deltaTime);
|
||||
_joystickStates.updateStateFromInput(inputState, deltaTime);
|
||||
_websocketStates.updateStateFromInput(inputState, deltaTime);
|
||||
_scriptStates.updateStateFromInput(inputState, deltaTime);
|
||||
}
|
||||
|
||||
void OrbitalNavigator::updateCameraStateFromStates(double deltaTime) {
|
||||
@@ -871,7 +892,9 @@ glm::dquat OrbitalNavigator::roll(double deltaTime,
|
||||
{
|
||||
const glm::dquat mouseRollQuat = glm::angleAxis(
|
||||
_mouseStates.localRollVelocity().x * deltaTime +
|
||||
_joystickStates.localRollVelocity().x * deltaTime,
|
||||
_joystickStates.localRollVelocity().x * deltaTime +
|
||||
_websocketStates.localRollVelocity().x * deltaTime +
|
||||
_scriptStates.localRollVelocity().x * deltaTime,
|
||||
glm::dvec3(0.0, 0.0, 1.0)
|
||||
);
|
||||
return localCameraRotation * mouseRollQuat;
|
||||
@@ -892,8 +915,20 @@ glm::dquat OrbitalNavigator::rotateLocally(double deltaTime,
|
||||
0.0
|
||||
) * deltaTime);
|
||||
|
||||
const glm::dquat websocketRotationDiff = glm::dquat(glm::dvec3(
|
||||
_websocketStates.localRotationVelocity().y,
|
||||
_websocketStates.localRotationVelocity().x,
|
||||
0.0
|
||||
) * deltaTime);
|
||||
|
||||
return localCameraRotation * joystickRotationDiff * mouseRotationDiff;
|
||||
const glm::dquat scriptRotationDiff = glm::dquat(glm::dvec3(
|
||||
_scriptStates.localRotationVelocity().y,
|
||||
_scriptStates.localRotationVelocity().x,
|
||||
0.0
|
||||
) * deltaTime);
|
||||
|
||||
return localCameraRotation * joystickRotationDiff * mouseRotationDiff *
|
||||
websocketRotationDiff * scriptRotationDiff;
|
||||
}
|
||||
glm::dquat OrbitalNavigator::interpolateLocalRotation(double deltaTime,
|
||||
const glm::dquat& localCameraRotation)
|
||||
@@ -1061,19 +1096,31 @@ glm::dvec3 OrbitalNavigator::translateHorizontally(double deltaTime,
|
||||
const glm::dquat mouseRotationDiffCamSpace = glm::dquat(glm::dvec3(
|
||||
-_mouseStates.globalRotationVelocity().y * deltaTime,
|
||||
-_mouseStates.globalRotationVelocity().x * deltaTime,
|
||||
0) * speedScale);
|
||||
0.0) * speedScale);
|
||||
|
||||
const glm::dquat joystickRotationDiffCamSpace = glm::dquat(glm::dvec3(
|
||||
-_joystickStates.globalRotationVelocity().y * deltaTime,
|
||||
-_joystickStates.globalRotationVelocity().x * deltaTime,
|
||||
0.0) * speedScale
|
||||
);
|
||||
|
||||
const glm::dquat scriptRotationDiffCamSpace = glm::dquat(glm::dvec3(
|
||||
-_scriptStates.globalRotationVelocity().y * deltaTime,
|
||||
-_scriptStates.globalRotationVelocity().x * deltaTime,
|
||||
0.0) * speedScale
|
||||
);
|
||||
|
||||
const glm::dquat websocketRotationDiffCamSpace = glm::dquat(glm::dvec3(
|
||||
-_websocketStates.globalRotationVelocity().y * deltaTime,
|
||||
-_websocketStates.globalRotationVelocity().x * deltaTime,
|
||||
0) * speedScale
|
||||
);
|
||||
|
||||
// Transform to world space
|
||||
const glm::dquat rotationDiffWorldSpace = globalCameraRotation *
|
||||
joystickRotationDiffCamSpace *
|
||||
mouseRotationDiffCamSpace *
|
||||
glm::inverse(globalCameraRotation);
|
||||
joystickRotationDiffCamSpace * mouseRotationDiffCamSpace *
|
||||
websocketRotationDiffCamSpace * scriptRotationDiffCamSpace *
|
||||
glm::inverse(globalCameraRotation);
|
||||
|
||||
// Rotate and find the difference vector
|
||||
const glm::dvec3 rotationDiffVec3 =
|
||||
@@ -1134,7 +1181,9 @@ glm::dvec3 OrbitalNavigator::translateVertically(double deltaTime,
|
||||
const glm::dvec3 actualSurfaceToCamera = posDiff - centerToActualSurface;
|
||||
|
||||
const double totalVelocity = _joystickStates.truckMovementVelocity().y +
|
||||
_mouseStates.truckMovementVelocity().y;
|
||||
_mouseStates.truckMovementVelocity().y +
|
||||
_websocketStates.truckMovementVelocity().y +
|
||||
_scriptStates.truckMovementVelocity().y;
|
||||
|
||||
return cameraPosition - actualSurfaceToCamera * totalVelocity * deltaTime;
|
||||
}
|
||||
@@ -1153,7 +1202,9 @@ glm::dquat OrbitalNavigator::rotateHorizontally(double deltaTime,
|
||||
|
||||
const glm::dquat mouseCameraRollRotation = glm::angleAxis(
|
||||
_mouseStates.globalRollVelocity().x * deltaTime +
|
||||
_joystickStates.globalRollVelocity().x * deltaTime,
|
||||
_joystickStates.globalRollVelocity().x * deltaTime +
|
||||
_websocketStates.globalRollVelocity().x * deltaTime +
|
||||
_scriptStates.globalRollVelocity().x * deltaTime,
|
||||
directionFromSurfaceToCamera
|
||||
);
|
||||
return mouseCameraRollRotation * globalCameraRotation;
|
||||
@@ -1239,4 +1290,20 @@ const JoystickCameraStates& OrbitalNavigator::joystickStates() const {
|
||||
return _joystickStates;
|
||||
}
|
||||
|
||||
WebsocketCameraStates& OrbitalNavigator::websocketStates() {
|
||||
return _websocketStates;
|
||||
}
|
||||
|
||||
const WebsocketCameraStates& OrbitalNavigator::websocketStates() const {
|
||||
return _websocketStates;
|
||||
}
|
||||
|
||||
ScriptCameraStates& OrbitalNavigator::scriptStates() {
|
||||
return _scriptStates;
|
||||
}
|
||||
|
||||
const ScriptCameraStates& OrbitalNavigator::scriptStates() const {
|
||||
return _scriptStates;
|
||||
}
|
||||
|
||||
} // namespace openspace::interaction
|
||||
|
||||
118
src/interaction/scriptcamerastates.cpp
Normal file
118
src/interaction/scriptcamerastates.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2019 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/interaction/scriptcamerastates.h>
|
||||
|
||||
#include <openspace/interaction/inputstate.h>
|
||||
|
||||
namespace {
|
||||
const double SENSITIVITY_ADJUSTMENT_INCREASE = 8.0;
|
||||
const double SENSITIVITY_ADJUSTMENT_DECREASE = 0.5;
|
||||
}
|
||||
|
||||
namespace openspace::interaction {
|
||||
|
||||
ScriptCameraStates::ScriptCameraStates() : CameraInteractionStates(1.0, 1.0) {}
|
||||
|
||||
void ScriptCameraStates::updateStateFromInput(const InputState& inputState,
|
||||
double deltaTime)
|
||||
{
|
||||
if (_localRotation != glm::dvec2(0.0)) {
|
||||
_localRotationState.velocity.set(
|
||||
_localRotation * _sensitivity,
|
||||
deltaTime
|
||||
);
|
||||
_localRotation = glm::dvec2(0.0);
|
||||
}
|
||||
else {
|
||||
_localRotationState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
|
||||
if (_globalRotation != glm::dvec2(0.0)) {
|
||||
_globalRotationState.velocity.set(
|
||||
_globalRotation * _sensitivity,
|
||||
deltaTime
|
||||
);
|
||||
_globalRotation = glm::dvec2(0.0);
|
||||
}
|
||||
else {
|
||||
_globalRotationState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
|
||||
if (_truckMovement != glm::dvec2(0.0)) {
|
||||
_truckMovementState.velocity.set(
|
||||
_truckMovement * _sensitivity,
|
||||
deltaTime
|
||||
);
|
||||
_truckMovement = glm::dvec2(0.0);
|
||||
}
|
||||
else {
|
||||
_truckMovementState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
|
||||
if (_localRoll != glm::dvec2(0.0)) {
|
||||
_localRollState.velocity.set(
|
||||
_localRoll * _sensitivity,
|
||||
deltaTime
|
||||
);
|
||||
_localRoll = glm::dvec2(0.0);
|
||||
}
|
||||
else {
|
||||
_localRollState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
|
||||
if (_globalRoll != glm::dvec2(0.0)) {
|
||||
_globalRollState.velocity.set(
|
||||
_globalRoll * _sensitivity,
|
||||
deltaTime
|
||||
);
|
||||
_globalRoll = glm::dvec2(0.0);
|
||||
}
|
||||
else {
|
||||
_globalRollState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptCameraStates::addLocalRotation(const glm::dvec2& delta) {
|
||||
_localRotation += delta;
|
||||
}
|
||||
|
||||
void ScriptCameraStates::addGlobalRotation(const glm::dvec2& delta) {
|
||||
_globalRotation += delta;
|
||||
}
|
||||
|
||||
void ScriptCameraStates::addTruckMovement(const glm::dvec2& delta) {
|
||||
_truckMovement += delta;
|
||||
}
|
||||
|
||||
void ScriptCameraStates::addLocalRoll(const glm::dvec2& delta) {
|
||||
_localRoll += delta;
|
||||
}
|
||||
|
||||
void ScriptCameraStates::addGlobalRoll(const glm::dvec2& delta) {
|
||||
_globalRoll += delta;
|
||||
}
|
||||
|
||||
|
||||
} // namespace openspace::interaction
|
||||
260
src/interaction/websocketcamerastates.cpp
Normal file
260
src/interaction/websocketcamerastates.cpp
Normal file
@@ -0,0 +1,260 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2019 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/interaction/websocketcamerastates.h>
|
||||
|
||||
#include <openspace/engine/openspaceengine.h>
|
||||
#include <openspace/interaction/inputstate.h>
|
||||
#include <openspace/scripting/scriptengine.h>
|
||||
#include <ghoul/misc/stringconversion.h>
|
||||
#include <utility>
|
||||
|
||||
namespace openspace::interaction {
|
||||
|
||||
WebsocketCameraStates::WebsocketCameraStates(double sensitivity, double velocityScaleFactor)
|
||||
: CameraInteractionStates(sensitivity, velocityScaleFactor)
|
||||
{}
|
||||
|
||||
void WebsocketCameraStates::updateStateFromInput(const InputState& inputState,
|
||||
double deltaTime)
|
||||
{
|
||||
std::pair<bool, glm::dvec2> globalRotation = { false, glm::dvec2(0.0) };
|
||||
std::pair<bool, double> zoom = { false, 0.0 };
|
||||
std::pair<bool, glm::dvec2> localRoll = { false, glm::dvec2(0.0) };
|
||||
std::pair<bool, glm::dvec2> globalRoll = { false, glm::dvec2(0.0) };
|
||||
std::pair<bool, glm::dvec2> localRotation = { false, glm::dvec2(0.0) };
|
||||
|
||||
if (inputState.hasWebsocketStates()) {
|
||||
for (int i = 0; i < WebsocketInputState::MaxAxes; ++i) {
|
||||
AxisInformation t = _axisMapping[i];
|
||||
if (t.type == AxisType::None) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float value = inputState.websocketAxis(i);
|
||||
bool hasValue = abs(value) > t.deadzone;
|
||||
|
||||
if (!hasValue) {
|
||||
value = 0.f;
|
||||
}
|
||||
|
||||
if (t.normalize) {
|
||||
value = (value + 1.f) / 2.f;
|
||||
}
|
||||
|
||||
if (t.invert) {
|
||||
value *= -1.f;
|
||||
}
|
||||
|
||||
value = static_cast<float>(value * _sensitivity);
|
||||
|
||||
switch (t.type) {
|
||||
case AxisType::None:
|
||||
break;
|
||||
case AxisType::OrbitX:
|
||||
globalRotation.first = hasValue || globalRotation.first;
|
||||
globalRotation.second.x = value;
|
||||
break;
|
||||
case AxisType::OrbitY:
|
||||
globalRotation.first = hasValue || globalRotation.first;
|
||||
globalRotation.second.y = value;
|
||||
break;
|
||||
case AxisType::ZoomIn:
|
||||
zoom.first = hasValue || zoom.first;
|
||||
zoom.second += value;
|
||||
break;
|
||||
case AxisType::ZoomOut:
|
||||
zoom.first = hasValue || zoom.first;
|
||||
zoom.second -= value;
|
||||
break;
|
||||
case AxisType::LocalRollX:
|
||||
localRoll.first = hasValue || localRoll.first;
|
||||
localRoll.second.x = value;
|
||||
break;
|
||||
case AxisType::LocalRollY:
|
||||
localRoll.first = hasValue || localRoll.first;
|
||||
localRoll.second.y = value;
|
||||
break;
|
||||
case AxisType::GlobalRollX:
|
||||
globalRoll.first = hasValue || globalRoll.first;
|
||||
globalRoll.second.x = value;
|
||||
break;
|
||||
case AxisType::GlobalRollY:
|
||||
globalRoll.first = hasValue || globalRoll.first;
|
||||
globalRoll.second.y = value;
|
||||
break;
|
||||
case AxisType::PanX:
|
||||
localRotation.first = hasValue || localRotation.first;
|
||||
localRotation.second.x = value;
|
||||
break;
|
||||
case AxisType::PanY:
|
||||
localRotation.first = hasValue || localRotation.first;
|
||||
localRotation.second.y = value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (globalRotation.first) {
|
||||
_globalRotationState.velocity.set(globalRotation.second, deltaTime);
|
||||
}
|
||||
else {
|
||||
_globalRotationState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
|
||||
if (zoom.first) {
|
||||
_truckMovementState.velocity.set(glm::dvec2(zoom.second), deltaTime);
|
||||
}
|
||||
else {
|
||||
_truckMovementState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
|
||||
if (localRoll.first) {
|
||||
_localRollState.velocity.set(localRoll.second, deltaTime);
|
||||
}
|
||||
else {
|
||||
_localRollState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
|
||||
if (globalRoll.first) {
|
||||
_globalRollState.velocity.set(globalRoll.second, deltaTime);
|
||||
}
|
||||
else {
|
||||
_globalRollState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
|
||||
if (localRotation.first) {
|
||||
_localRotationState.velocity.set(localRotation.second, deltaTime);
|
||||
}
|
||||
else {
|
||||
_localRotationState.velocity.decelerate(deltaTime);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void WebsocketCameraStates::setAxisMapping(int axis, AxisType mapping,
|
||||
AxisInvert shouldInvert,
|
||||
AxisNormalize shouldNormalize)
|
||||
{
|
||||
ghoul_assert(axis < WebsocketInputState::MaxAxes, "axis must be < MaxAxes");
|
||||
|
||||
_axisMapping[axis].type = mapping;
|
||||
_axisMapping[axis].invert = shouldInvert;
|
||||
_axisMapping[axis].normalize = shouldNormalize;
|
||||
}
|
||||
|
||||
WebsocketCameraStates::AxisInformation WebsocketCameraStates::axisMapping(int axis) const {
|
||||
return _axisMapping[axis];
|
||||
}
|
||||
|
||||
void WebsocketCameraStates::setDeadzone(int axis, float deadzone) {
|
||||
_axisMapping[axis].deadzone = deadzone;
|
||||
}
|
||||
|
||||
float WebsocketCameraStates::deadzone(int axis) const {
|
||||
return _axisMapping[axis].deadzone;
|
||||
}
|
||||
|
||||
void WebsocketCameraStates::bindButtonCommand(int button, std::string command,
|
||||
WebsocketAction action,
|
||||
ButtonCommandRemote remote,
|
||||
std::string documentation)
|
||||
{
|
||||
_buttonMapping.insert({
|
||||
button,
|
||||
{ std::move(command), action, remote, std::move(documentation) }
|
||||
});
|
||||
}
|
||||
|
||||
void WebsocketCameraStates::clearButtonCommand(int button) {
|
||||
for (auto it = _buttonMapping.begin(); it != _buttonMapping.end();) {
|
||||
// If the current iterator is the button that we are looking for, delete it
|
||||
// (std::multimap::erase will return the iterator to the next element for us)
|
||||
if (it->first == button) {
|
||||
it = _buttonMapping.erase(it);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::string> WebsocketCameraStates::buttonCommand(int button) const {
|
||||
std::vector<std::string> result;
|
||||
auto itRange = _buttonMapping.equal_range(button);
|
||||
for (auto it = itRange.first; it != itRange.second; ++it) {
|
||||
result.push_back(it->second.command);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace openspace::interaction
|
||||
|
||||
namespace ghoul {
|
||||
|
||||
template <>
|
||||
std::string to_string(const openspace::interaction::WebsocketCameraStates::AxisType& type)
|
||||
{
|
||||
using T = openspace::interaction::WebsocketCameraStates::AxisType;
|
||||
switch (type) {
|
||||
case T::None: return "None";
|
||||
case T::OrbitX: return "Orbit X";
|
||||
case T::OrbitY: return "Orbit Y";
|
||||
case T::ZoomIn: return "Zoom In";
|
||||
case T::ZoomOut: return "Zoom Out";
|
||||
case T::LocalRollX: return "LocalRoll X";
|
||||
case T::LocalRollY: return "LocalRoll Y";
|
||||
case T::GlobalRollX: return "GlobalRoll X";
|
||||
case T::GlobalRollY: return "GlobalRoll Y";
|
||||
case T::PanX: return "Pan X";
|
||||
case T::PanY: return "Pan Y";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
openspace::interaction::WebsocketCameraStates::AxisType from_string(
|
||||
const std::string& string)
|
||||
{
|
||||
using T = openspace::interaction::WebsocketCameraStates::AxisType;
|
||||
|
||||
static const std::map<std::string, T> Map = {
|
||||
{ "None", T::None },
|
||||
{ "Orbit X", T::OrbitX },
|
||||
{ "Orbit Y", T::OrbitY },
|
||||
{ "Zoom In", T::ZoomIn },
|
||||
{ "Zoom Out", T::ZoomOut },
|
||||
{ "LocalRoll X", T::LocalRollX },
|
||||
{ "LocalRoll Y", T::LocalRollY },
|
||||
{ "GlobalRoll X", T::GlobalRollX },
|
||||
{ "GlobalRoll Y", T::GlobalRollY },
|
||||
{ "Pan X", T::PanX },
|
||||
{ "Pan Y", T::PanY }
|
||||
};
|
||||
|
||||
return Map.at(string);
|
||||
}
|
||||
|
||||
} // namespace ghoul
|
||||
97
src/interaction/websocketinputstate.cpp
Normal file
97
src/interaction/websocketinputstate.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/*****************************************************************************************
|
||||
* *
|
||||
* OpenSpace *
|
||||
* *
|
||||
* Copyright (c) 2014-2019 *
|
||||
* *
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of this *
|
||||
* software and associated documentation files (the "Software"), to deal in the Software *
|
||||
* without restriction, including without limitation the rights to use, copy, modify, *
|
||||
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to *
|
||||
* permit persons to whom the Software is furnished to do so, subject to the following *
|
||||
* conditions: *
|
||||
* *
|
||||
* The above copyright notice and this permission notice shall be included in all copies *
|
||||
* or substantial portions of the Software. *
|
||||
* *
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, *
|
||||
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A *
|
||||
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT *
|
||||
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF *
|
||||
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE *
|
||||
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
|
||||
****************************************************************************************/
|
||||
|
||||
#include <openspace/interaction/websocketinputstate.h>
|
||||
|
||||
#include <ghoul/misc/invariants.h>
|
||||
#include <ghoul/misc/stringconversion.h>
|
||||
#include <map>
|
||||
#include <numeric>
|
||||
|
||||
namespace openspace::interaction {
|
||||
|
||||
float WebsocketInputStates::axis(int axis) const {
|
||||
ghoul_precondition(axis >= 0, "axis must be 0 or positive");
|
||||
|
||||
float res = std::accumulate(
|
||||
begin(),
|
||||
end(),
|
||||
0.f,
|
||||
[axis](float value, const std::pair<const size_t, const WebsocketInputState *> state) {
|
||||
if (state.second->isConnected) {
|
||||
value += state.second->axes[axis];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
);
|
||||
|
||||
// If multiple websockets are connected, we might get values outside the -1,1 range by
|
||||
// summing them up
|
||||
return std::clamp(res, -1.f, 1.f);
|
||||
}
|
||||
|
||||
bool WebsocketInputStates::button(int button, WebsocketAction action) const {
|
||||
ghoul_precondition(button >= 0, "button must be 0 or positive");
|
||||
|
||||
bool res = std::any_of(
|
||||
begin(),
|
||||
end(),
|
||||
[button, action](const std::pair<const size_t, const WebsocketInputState *> state) {
|
||||
return state.second->isConnected ?
|
||||
( state.second->buttons[button] == action )
|
||||
: false;
|
||||
}
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace openspace::interaction
|
||||
|
||||
namespace ghoul {
|
||||
|
||||
template <>
|
||||
std::string to_string(const openspace::interaction::WebsocketAction& action) {
|
||||
switch (action) {
|
||||
case openspace::interaction::WebsocketAction::Idle: return "Idle";
|
||||
case openspace::interaction::WebsocketAction::Press: return "Press";
|
||||
case openspace::interaction::WebsocketAction::Repeat: return "Repeat";
|
||||
case openspace::interaction::WebsocketAction::Release: return "Release";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
openspace::interaction::WebsocketAction from_string(const std::string& string) {
|
||||
static const std::map<std::string, openspace::interaction::WebsocketAction> Map = {
|
||||
{ "Idle", openspace::interaction::WebsocketAction::Idle },
|
||||
{ "Press", openspace::interaction::WebsocketAction::Press },
|
||||
{ "Repeat", openspace::interaction::WebsocketAction::Repeat },
|
||||
{ "Release", openspace::interaction::WebsocketAction::Release }
|
||||
};
|
||||
|
||||
return Map.at(string);
|
||||
|
||||
}
|
||||
|
||||
} // namespace ghoul
|
||||
@@ -440,11 +440,7 @@ void LoadingScreen::render() {
|
||||
if (info.totalSize < 1024 * 1024) { // 1MB
|
||||
text = fmt::format(
|
||||
"{} ({}%)\n{}/{} {}",
|
||||
text,
|
||||
p,
|
||||
info.currentSize,
|
||||
info.totalSize,
|
||||
"bytes"
|
||||
text, p, info.currentSize, info.totalSize, "bytes"
|
||||
);
|
||||
}
|
||||
else {
|
||||
@@ -453,11 +449,7 @@ void LoadingScreen::render() {
|
||||
|
||||
text = fmt::format(
|
||||
"{} ({}%)\n{:.3f}/{:.3f} {}",
|
||||
text,
|
||||
p,
|
||||
curr,
|
||||
total,
|
||||
"MB"
|
||||
text, p, curr, total, "MB"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user