Fixed failed merging of master.

This commit is contained in:
Jonathas Costa
2019-07-31 15:05:52 -04:00
61 changed files with 21213 additions and 7434 deletions

View File

@@ -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;

View File

@@ -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)

View 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

View File

@@ -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)

View File

@@ -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)

View File

@@ -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

View 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)

View 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)

File diff suppressed because it is too large Load Diff

View File

@@ -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

View File

@@ -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();

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View 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__

View 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__

View 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__

View File

@@ -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

View File

@@ -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,

View File

@@ -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;

View File

@@ -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
});

View 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

View 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__

View 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

View 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__

View File

@@ -29,6 +29,7 @@
#include <ghoul/fmt.h>
#include <ghoul/logging/logmanager.h>
#include <fstream>
#include <iomanip>
namespace {
constexpr const char* _loggerCat = "FieldlinesState";

View File

@@ -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
);

View File

@@ -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 {

View File

@@ -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

View File

@@ -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!");

View File

@@ -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();

View File

@@ -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>(

View File

@@ -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();

View File

@@ -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());

View File

@@ -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;

View File

@@ -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];
}

View File

@@ -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;
};

View File

@@ -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({

View File

@@ -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;

View File

@@ -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

View 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__

View File

@@ -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));

View 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

View File

@@ -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

View File

@@ -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:

View File

@@ -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;

View File

@@ -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);

View File

@@ -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

View File

@@ -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"
}
}
};

View File

@@ -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

View File

@@ -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

View 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

View 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

View 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

View File

@@ -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"
);
}
}