Issue/451 (#595)

* Add ability for Joystick input
* Change location of LuaConsole files
This commit is contained in:
Alexander Bock
2018-04-20 16:12:18 -04:00
committed by GitHub
parent a9fa9117f6
commit 3810209365
36 changed files with 2794 additions and 391 deletions
+89
View File
@@ -74,6 +74,8 @@ namespace {
constexpr const char* _loggerCat = "main";
sgct::Engine* SgctEngine;
openspace::interaction::JoystickInputStates joystickInputStates;
constexpr const char* OpenVRTag = "OpenVR";
constexpr const char* SpoutTag = "Spout";
@@ -345,12 +347,99 @@ void mainInitFunc() {
}
}
OsEng.setJoystickInputStates(joystickInputStates);
LTRACE("main::mainInitFunc(end)");
}
void mainPreSyncFunc() {
LTRACE("main::mainPreSyncFunc(begin)");
OsEng.preSynchronization();
// Query joystick status
using namespace openspace::interaction;
for (int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_LAST; ++i) {
JoystickInputState& state = joystickInputStates[i];
int present = glfwJoystickPresent(i);
if (present == GLFW_TRUE) {
if (!state.isConnected) {
// Joystick was added
state.isConnected = true;
state.name = SgctEngine->getJoystickName(i);
std::fill(state.axes.begin(), state.axes.end(), 0.f);
std::fill(
state.buttons.begin(),
state.buttons.end(),
JoystickAction::Idle
);
}
const float* axes = SgctEngine->getJoystickAxes(i, &state.nAxes);
if (state.nAxes > JoystickInputState::MaxAxes) {
LWARNING(fmt::format(
"Joystick/Gamepad {} has {} axes, but only {} axes are supported. "
"All excess axes are ignored",
state.name,
state.nAxes,
JoystickInputState::MaxAxes
));
state.nAxes = JoystickInputState::MaxAxes;
}
std::memcpy(state.axes.data(), axes, state.nAxes * sizeof(float));
const unsigned char* buttons = SgctEngine->getJoystickButtons(
i,
&state.nButtons
);
if (state.nButtons > JoystickInputState::MaxButtons) {
LWARNING(fmt::format(
"Joystick/Gamepad {} has {} buttons, but only {} buttons are "
"supported. All excess buttons are ignored",
state.name,
state.nButtons,
JoystickInputState::MaxButtons
));
state.nButtons = JoystickInputState::MaxButtons;
}
for (int j = 0; j < state.nButtons; ++j) {
bool currentlyPressed = buttons[j] == GLFW_PRESS;
if (currentlyPressed) {
switch (state.buttons[j]) {
case JoystickAction::Idle:
case JoystickAction::Release:
state.buttons[j] = JoystickAction::Press;
break;
case JoystickAction::Press:
case JoystickAction::Repeat:
state.buttons[j] = JoystickAction::Repeat;
break;
}
}
else {
switch (state.buttons[j]) {
case JoystickAction::Idle:
case JoystickAction::Release:
state.buttons[j] = JoystickAction::Idle;
break;
case JoystickAction::Press:
case JoystickAction::Repeat:
state.buttons[j] = JoystickAction::Release;
break;
}
}
}
}
else {
state.isConnected = false;
}
}
LTRACE("main::mainPreSyncFunc(end)");
}
+1
View File
@@ -12,6 +12,7 @@ assetHelper.requestAll(asset, 'scene/digitaluniverse')
-- Load default key bindings applicable to most scenes
asset.require('util/default_keybindings')
asset.require('util/default_dashboard')
asset.require('util/default_joystick')
asset.request('customization/globebrowsing')
+136
View File
@@ -0,0 +1,136 @@
local propertyHelper = asset.require('./property_helper')
-- Allowed values for the second parameter of bindJoystickAxis:
-- "None"
-- "Orbit X"
-- "Orbit Y"
-- "Zoom In"
-- "Zoom Out"
-- "LocalRoll X"
-- "LocalRoll Y"
-- "GlobalRoll X"
-- "GlobalRoll Y"
-- "Pan X"
-- "Pan Y"
-- Third parameter determines whether the axis should be inverted
-- Fourth parameter determines whether the axis should be normalized from [-1,1] to [0,1]
local XBoxController = {
LeftThumbStick = { 0 , 1 },
RightThumbStick = { 2, 3 },
LeftTrigger = 4,
RightTrigger = 5,
A = 0,
B = 1,
X = 2,
Y = 3,
LB = 4,
RB = 5,
Select = 6,
Start = 7,
LeftStick = 8,
RightStick = 9,
DPad = {
Up = 10,
Right = 11,
Down = 12,
Left = 13
}
}
local PS4Controller = {
LeftThumbStick = { 0 , 1 },
RightThumbStick = { 2, 5 },
LeftTrigger = 3,
RightTrigger = 4,
A = 3, -- Triangle
B = 0, -- Square
X = 2, -- Circle
Y = 1, -- Cross
LB = 4,
RB = 5,
Select = 9, -- options
Start = 12, -- PS button
LeftStick = 10,
RightStick = 11,
DPad = {
Up = 14,
Right = 15,
Down = 16,
Left = 17
}
}
-- Variables to store the state of the joystick between frames
Joystick = {}
Joystick.State = {}
Joystick.State.IsInRollMode = false
Joystick.State.Axis = {}
local bindLocalRoll = function(axis)
return [[
-- We only want to store the current state in the first mode that is enabled, otherwise we will overwrite the backup
if not Joystick.State.IsInRollMode then
-- Save current axis state
Joystick.State.Axis.Type, Joystick.State.Axis.Inverted, Joystick.State.Axis.Normalized = openspace.navigation.joystickAxis(]] .. axis .. [[)
end
-- Set new axis state
openspace.navigation.bindJoystickAxis(]] .. axis .. [[, "LocalRoll X", true);
Joystick.State.IsInRollMode = true
]]
end
local bindGlobalRoll = function(axis)
return [[
-- We only want to store the current state in the first mode that is enabled, otherwise we will overwrite the backup
if not Joystick.State.IsInRollMode then
-- Save current axis state
Joystick.State.Axis.Type, Joystick.State.Axis.Inverted, Joystick.State.Axis.Normalized = openspace.navigation.joystickAxis(]] .. axis .. [[)
end
-- Set new axis state
openspace.navigation.bindJoystickAxis(]] .. axis .. [[, "GlobalRoll X", true);
Joystick.State.IsInRollMode = true
]]
end
local unbindRoll = function(axis)
return [[
-- Reset previous state
openspace.navigation.bindJoystickAxis(]] .. axis .. [[, Joystick.State.Axis.Type, Joystick.State.Axis.Inverted, Joystick.State.Axis.Normalized);
]]
end
asset.onInitialize(function()
-- Set the controller to the connected controller
-- Currently: XBoxController or PS4Controller
local controller = XBoxController;
openspace.navigation.setAxisDeadZone(controller.LeftThumbStick[1], 0.05)
openspace.navigation.setAxisDeadZone(controller.LeftThumbStick[2], 0.05)
openspace.navigation.setAxisDeadZone(controller.RightThumbStick[1], 0.05)
openspace.navigation.setAxisDeadZone(controller.RightThumbStick[2], 0.05)
openspace.navigation.setAxisDeadZone(controller.LeftTrigger, 0.05)
openspace.navigation.setAxisDeadZone(controller.RightTrigger, 0.05)
openspace.navigation.bindJoystickAxis(controller.LeftThumbStick[1], "Orbit X");
openspace.navigation.bindJoystickAxis(controller.LeftThumbStick[2], "Orbit Y", true);
openspace.navigation.bindJoystickAxis(controller.RightThumbStick[1], "Pan X", true);
openspace.navigation.bindJoystickAxis(controller.RightThumbStick[2], "Pan Y");
openspace.navigation.bindJoystickAxis(controller.LeftTrigger, "Zoom Out", false, true);
openspace.navigation.bindJoystickAxis(controller.RightTrigger, "Zoom In", false, true);
openspace.navigation.bindJoystickButton(controller.LB, bindLocalRoll(controller.RightThumbStick[1]))
openspace.navigation.bindJoystickButton(controller.LB, unbindRoll(controller.RightThumbStick[1]), "Release")
openspace.navigation.bindJoystickButton(controller.RB, bindGlobalRoll(controller.RightThumbStick[1]))
openspace.navigation.bindJoystickButton(controller.RB, unbindRoll(controller.RightThumbStick[1]), "Release")
openspace.navigation.bindJoystickButton(controller.A, propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.ZoomFriction'))
openspace.navigation.bindJoystickButton(controller.B, propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.RotationalFriction'))
openspace.navigation.bindJoystickButton(controller.DPad.Left, propertyHelper.invert('NavigationHandler.OrbitalNavigator.Friction.RollFriction'))
openspace.navigation.bindJoystickButton(controller.X, "openspace.setPropertyValue('NavigationHandler.Origin', 'Earth')")
openspace.navigation.bindJoystickButton(controller.Y, "openspace.setPropertyValue('NavigationHandler.Origin', 'Mars')")
end)
+4 -2
View File
@@ -25,6 +25,7 @@
#ifndef __OPENSPACE_CORE___OPENSPACEENGINE___H__
#define __OPENSPACE_CORE___OPENSPACEENGINE___H__
#include <openspace/interaction/joystickinputstate.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/util/keys.h>
#include <openspace/util/mouse.h>
@@ -60,9 +61,9 @@ class VirtualPropertyManager;
class WindowWrapper;
namespace interaction {
class NavigationHandler;
class KeyBindingManager;
}
class NavigationHandler;
} // namespace interaction
namespace gui { class GUI; }
namespace properties { class PropertyOwner; }
namespace scripting {
@@ -111,6 +112,7 @@ public:
void mouseButtonCallback(MouseButton button, MouseAction action);
void mousePositionCallback(double x, double y);
void mouseScrollWheelCallback(double posX, double posY);
void setJoystickInputStates(interaction::JoystickInputStates& states);
void externalControlCallback(const char* receivedChars, int size, int clientId);
void encode();
void decode();
@@ -22,56 +22,60 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___MOUSESTATE___H__
#define __OPENSPACE_CORE___MOUSESTATE___H__
#ifndef __OPENSPACE_CORE___INPUTDEVICESTATES___H__
#define __OPENSPACE_CORE___INPUTDEVICESTATES___H__
#include <openspace/interaction/delayedvariable.h>
#include <openspace/interaction/inputstate.h>
#include <ghoul/glm.h>
namespace openspace::interaction {
struct MouseState {
MouseState(double scaleFactor);
void setFriction(double friction);
void setVelocityScaleFactor(double scaleFactor);
class InputState;
glm::dvec2 previousPosition;
DelayedVariable<glm::dvec2, double> velocity;
};
class MouseStates {
class CameraInteractionStates {
public:
/**
* \param sensitivity
* \param velocityScaleFactor can be set to 60 to remove the inertia of the
* interaction. Lower value will make it harder to move the camera.
*/
MouseStates(double sensitivity, double velocityScaleFactor);
void updateMouseStatesFromInput(const InputState& inputState, double deltaTime);
CameraInteractionStates(double sensitivity, double velocityScaleFactor);
virtual ~CameraInteractionStates() = default;
virtual void updateStateFromInput(const InputState& inputState, double deltaTime) = 0;
void setRotationalFriction(double friction);
void setHorizontalFriction(double friction);
void setVerticalFriction(double friction);
void setSensitivity(double sensitivity);
void setVelocityScaleFactor(double scaleFactor);
glm::dvec2 globalRotationMouseVelocity() const;
glm::dvec2 localRotationMouseVelocity() const;
glm::dvec2 truckMovementMouseVelocity() const;
glm::dvec2 localRollMouseVelocity() const;
glm::dvec2 globalRollMouseVelocity() const;
glm::dvec2 globalRotationVelocity() const;
glm::dvec2 localRotationVelocity() const;
glm::dvec2 truckMovementVelocity() const;
glm::dvec2 localRollVelocity() const;
glm::dvec2 globalRollVelocity() const;
protected:
struct InteractionState {
InteractionState(double scaleFactor);
void setFriction(double friction);
void setVelocityScaleFactor(double scaleFactor);
glm::dvec2 previousPosition;
DelayedVariable<glm::dvec2, double> velocity;
};
private:
double _sensitivity;
MouseState _globalRotationMouseState;
MouseState _localRotationMouseState;
MouseState _truckMovementMouseState;
MouseState _localRollMouseState;
MouseState _globalRollMouseState;
InteractionState _globalRotationState;
InteractionState _localRotationState;
InteractionState _truckMovementState;
InteractionState _localRollState;
InteractionState _globalRollState;
};
} // namespace openspace::interaction
#endif // __OPENSPACE_CORE___MOUSESTATE___H__
#endif // __OPENSPACE_CORE___INPUTDEVICESTATES___H__
@@ -0,0 +1,81 @@
/*****************************************************************************************
* *
* 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_CORE___CAMERAINTERACTIONSTATES___H__
#define __OPENSPACE_CORE___CAMERAINTERACTIONSTATES___H__
#include <openspace/interaction/delayedvariable.h>
#include <ghoul/glm.h>
namespace openspace::interaction {
class InputState;
class CameraInteractionStates {
public:
/**
* \param sensitivity
* \param velocityScaleFactor can be set to 60 to remove the inertia of the
* interaction. Lower value will make it harder to move the camera.
*/
CameraInteractionStates(double sensitivity, double velocityScaleFactor);
virtual ~CameraInteractionStates() = default;
virtual void updateStateFromInput(const InputState& inputState, double deltaTime) = 0;
void setRotationalFriction(double friction);
void setHorizontalFriction(double friction);
void setVerticalFriction(double friction);
void setSensitivity(double sensitivity);
void setVelocityScaleFactor(double scaleFactor);
glm::dvec2 globalRotationVelocity() const;
glm::dvec2 localRotationVelocity() const;
glm::dvec2 truckMovementVelocity() const;
glm::dvec2 localRollVelocity() const;
glm::dvec2 globalRollVelocity() const;
protected:
struct InteractionState {
InteractionState(double scaleFactor);
void setFriction(double friction);
void setVelocityScaleFactor(double scaleFactor);
glm::dvec2 previousPosition;
DelayedVariable<glm::dvec2, double> velocity;
};
double _sensitivity;
InteractionState _globalRotationState;
InteractionState _localRotationState;
InteractionState _truckMovementState;
InteractionState _localRollState;
InteractionState _globalRollState;
};
} // namespace openspace::interaction
#endif // __OPENSPACE_CORE___CAMERAINTERACTIONSTATES___H__
+20 -8
View File
@@ -25,15 +25,15 @@
#ifndef __OPENSPACE_CORE___INPUTSTATE___H__
#define __OPENSPACE_CORE___INPUTSTATE___H__
#include <openspace/interaction/joystickinputstate.h>
#include <openspace/util/keys.h>
#include <openspace/util/mouse.h>
#include <ghoul/glm.h>
#include <list>
namespace openspace::interaction {
// This class represents the global input state of interaction devices
class InputState {
public:
InputState() = default;
@@ -45,22 +45,34 @@ public:
void mousePositionCallback(double mouseX, double mouseY);
void mouseScrollWheelCallback(double mouseScrollDelta);
// Accessors
const std::list<std::pair<Key, KeyModifier>>& getPressedKeys() const;
const std::list<MouseButton>& getPressedMouseButtons() const;
glm::dvec2 getMousePosition() const;
double getMouseScrollDelta() const;
void setJoystickInputStates(JoystickInputStates& states);
// Accessors
const std::list<std::pair<Key, KeyModifier>>& pressedKeys() const;
bool isKeyPressed(std::pair<Key, KeyModifier> keyModPair) const;
bool isKeyPressed(Key key) const;
const std::list<MouseButton>& pressedMouseButtons() const;
glm::dvec2 mousePosition() const;
double mouseScrollDelta() const;
bool isMouseButtonPressed(MouseButton mouseButton) const;
const JoystickInputStates& joystickInputStates() const;
float joystickAxis(int i) const;
bool joystickButton(int i) const;
private:
// Input from keyboard and mouse
// Input from keyboard
std::list<std::pair<Key, KeyModifier>> _keysDown;
// Input from mouse
std::list<MouseButton> _mouseButtonsDown;
glm::dvec2 _mousePosition;
double _mouseScrollDelta;
// Input from joysticks
// The memory is owned by the outer most main (apps/OpenSpace/main.cpp right now)
JoystickInputStates* _joystickInputStates = nullptr;
};
} // namespace openspace::interaction
@@ -0,0 +1,122 @@
/*****************************************************************************************
* *
* 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_CORE___JOYSTICKSTATE___H__
#define __OPENSPACE_CORE___JOYSTICKSTATE___H__
#include <openspace/interaction/camerainteractionstates.h>
#include <openspace/interaction/joystickinputstate.h>
#include <ghoul/misc/boolean.h>
#include <ghoul/misc/fromstring.h>
#include <map>
#include <vector>
namespace openspace::interaction {
class JoystickCameraStates : 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;
};
JoystickCameraStates(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, JoystickAction action,
ButtonCommandRemote local);
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, JoystickInputState::MaxAxes> _axisMapping;
struct ButtonInformation {
std::string command;
JoystickAction action;
ButtonCommandRemote synchronization;
std::string documentation;
};
std::multimap<int, ButtonInformation> _buttonMapping;
};
} // namespace openspace::interaction
namespace std {
std::string to_string(const openspace::interaction::JoystickCameraStates::AxisType& type);
} // namespace std
namespace ghoul {
template <>
openspace::interaction::JoystickCameraStates::AxisType from_string(const std::string& string);
} // namespace ghoul
#endif // __OPENSPACE_CORE___JOYSTICKSTATE___H__
@@ -0,0 +1,126 @@
/*****************************************************************************************
* *
* 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_CORE___JOYSTICKINPUTSTATE___H__
#define __OPENSPACE_CORE___JOYSTICKINPUTSTATE___H__
#include <ghoul/misc/fromstring.h>
#include <array>
#include <memory>
#include <string>
namespace openspace::interaction {
/**
* Actions that any button of a joystick can have. Each button must be in one of these
* states
*/
enum class JoystickAction : 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 joystick.
*/
struct JoystickInputState {
/// The maximum number of supported axes
static const int MaxAxes = 8;
/// The maximum number of supported buttons
static const int MaxButtons = 32;
/// Marks whether this joystick is connected. If this value is \c false, all other
/// members of this struct are undefined
bool isConnected = false;
/// The name of this joystick
std::string name;
/// The number of axes that this joystick 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 joystick possesses
int nButtons = 0;
/// The status of each button. Only the first \c nButtons values are defined, the rest
/// are undefined
std::array<JoystickAction, MaxButtons> buttons;
};
/// The maximum number of joysticks that are supported by this system. This number is
/// derived from the available GLFW constants
constexpr const int MaxJoysticks = 16;
struct JoystickInputStates : public std::array<JoystickInputState, MaxJoysticks> {
/**
* This function adds the contributions of all connected joysticks for the provided
* \p axis. After adding each joysticks contribution, the result is clamped to [-1,1].
* If a joystick 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 joysticks
*
* \pre \p axis must be 0 or positive
*/
float axis(int axis) const;
/**
* This functions checks whether any connected joystick has its \p button in the
* passed \p action. Any joystick 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 joystick whose \param button is in the
* \p action state
*
* \pre \p button must be 0 or positive
*/
bool button(int button, JoystickAction action) const;
};
} // namespace openspace::interaction
namespace std {
std::string to_string(openspace::interaction::JoystickAction action);
} // namespace std
namespace ghoul {
template <>
openspace::interaction::JoystickAction from_string(const std::string& str);
} // namespace ghoul
#endif // __OPENSPACE_CORE___JOYSTICKSTATE___H__
@@ -79,7 +79,6 @@ public:
void keyboardCallback(Key key, KeyModifier modifier, KeyAction action);
private:
std::string generateJson() const override;
std::multimap<KeyWithModifier, KeyInformation> _keyLua;
@@ -22,30 +22,20 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#ifndef __OPENSPACE_CORE___CONTROLLER___H__
#define __OPENSPACE_CORE___CONTROLLER___H__
#ifndef __OPENSPACE_CORE___MOUSECAMERASTATES___H__
#define __OPENSPACE_CORE___MOUSECAMERASTATES___H__
#include <openspace/scene/scenegraphnode.h>
#include <ghoul/glm.h>
#include <glm/gtx/vector_angle.hpp>
#include <openspace/interaction/camerainteractionstates.h>
namespace openspace::interaction {
class NavigationHandler;
class Controller {
class MouseCameraStates : public CameraInteractionStates {
public:
Controller() :
_handler(nullptr)
{}
MouseCameraStates(double sensitivity, double velocityScaleFactor);
void setHandler(NavigationHandler* handler);
protected:
NavigationHandler* _handler;
void updateStateFromInput(const InputState& inputState, double deltaTime) override;
};
} // namespace openspace::interaction
#endif // __OPENSPACE_CORE___CONTROLLER___H__
#endif // __OPENSPACE_CORE___MOUSECAMERASTATES___H__
@@ -29,6 +29,8 @@
#include <openspace/interaction/orbitalnavigator.h>
#include <openspace/interaction/keyframenavigator.h>
#include <openspace/interaction/joystickinputstate.h>
#include <openspace/interaction/joystickcamerastates.h>
#include <openspace/properties/stringproperty.h>
#include <openspace/properties/scalar/boolproperty.h>
#include <openspace/properties/scalar/floatproperty.h>
@@ -63,7 +65,7 @@ public:
void updateCamera(double deltaTime);
// Accessors
ghoul::Dictionary getCameraStateDictionary();
ghoul::Dictionary cameraStateDictionary();
SceneGraphNode* focusNode() const;
glm::dvec3 focusNodeToCameraVector() const;
glm::quat focusNodeToCameraRotation() const;
@@ -74,10 +76,33 @@ public:
// Callback functions
void keyboardCallback(Key key, KeyModifier modifier, KeyAction action);
void mouseButtonCallback(MouseButton button, MouseAction action);
void mousePositionCallback(double x, double y);
void mouseScrollWheelCallback(double pos);
void setJoystickInputStates(JoystickInputStates& states);
void setJoystickAxisMapping(
int axis,
JoystickCameraStates::AxisType mapping,
JoystickCameraStates::AxisInvert shouldInvert = JoystickCameraStates::AxisInvert::No,
JoystickCameraStates::AxisNormalize shouldNormalize = JoystickCameraStates::AxisNormalize::No
);
JoystickCameraStates::AxisInformation joystickAxisMapping(int axis) const;
void setJoystickAxisDeadzone(int axis, float deadzone);
float joystickAxisDeadzone(int axis) const;
void bindJoystickButtonCommand(int button, std::string command, JoystickAction action,
JoystickCameraStates::ButtonCommandRemote remote);
void clearJoystickButtonCommand(int button);
std::vector<std::string> joystickButtonCommand(int button) const;
void saveCameraStateToFile(const std::string& filepath);
void restoreCameraStateFromFile(const std::string& filepath);
@@ -28,7 +28,8 @@
#include <openspace/interaction/delayedvariable.h>
#include <openspace/interaction/inputstate.h>
#include <openspace/interaction/interpolator.h>
#include <openspace/interaction/mousestate.h>
#include <openspace/interaction/joystickcamerastates.h>
#include <openspace/interaction/mousecamerastates.h>
#include <openspace/properties/propertyowner.h>
#include <openspace/properties/scalar/boolproperty.h>
@@ -50,11 +51,14 @@ public:
OrbitalNavigator();
~OrbitalNavigator();
void updateMouseStatesFromInput(const InputState& inputState, double deltaTime);
void updateCameraStateFromMouseStates(Camera& camera, double deltaTime);
void updateStatesFromInput(const InputState& inputState, double deltaTime);
void updateCameraStateFromStates(Camera& camera, double deltaTime);
void setFocusNode(SceneGraphNode* focusNode);
void startInterpolateCameraDirection(const Camera& camera);
JoystickCameraStates& joystickStates();
bool followingNodeRotation() const;
SceneGraphNode* focusNode() const;
@@ -82,9 +86,12 @@ private:
properties::FloatProperty _followFocusNodeRotationDistance;
properties::FloatProperty _minimumAllowedDistance;
properties::FloatProperty _sensitivity;
properties::FloatProperty _mouseSensitivity;
properties::FloatProperty _joystickSensitivity;
MouseStates _mouseStates;
MouseCameraStates _mouseStates;
JoystickCameraStates _joystickStates;
SceneGraphNode* _focusNode = nullptr;
glm::dvec3 _previousFocusNodePosition;
@@ -116,14 +123,14 @@ private:
* \returns a local camera rotation modified with two degrees of freedom.
*/
glm::dquat rotateLocally(double deltaTime,
const glm::dquat& localCameraRotation) const;
const glm::dquat& localCameraRotation) const;
/**
* Interpolates the local rotation towards a 0 rotation.
* \returns a modified local rotation interpolated towards 0.
*/
glm::dquat interpolateLocalRotation(double deltaTime,
const glm::dquat& localCameraRotation);
const glm::dquat& localCameraRotation);
/**
* Translates the horizontal direction. If far from the focus object, this will
@@ -132,10 +139,9 @@ private:
* \returns a position vector adjusted in the horizontal direction.
*/
glm::dvec3 translateHorizontally(double deltaTime, const glm::dvec3& cameraPosition,
const glm::dvec3& objectPosition,
const glm::dquat& focusNodeRotationDiff,
const glm::dquat& globalCameraRotation,
const SurfacePositionHandle& positionHandle) const;
const glm::dvec3& objectPosition, const glm::dquat& focusNodeRotationDiff,
const glm::dquat& globalCameraRotation,
const SurfacePositionHandle& positionHandle) const;
/*
* Adds rotation to the camera position so that it follows the rotation of the focus
@@ -143,35 +149,32 @@ private:
* \returns a position updated with the rotation defined by focusNodeRotationDiff
*/
glm::dvec3 followFocusNodeRotation(const glm::dvec3& cameraPosition,
const glm::dvec3& objectPosition,
const glm::dquat& focusNodeRotationDiff) const;
const glm::dvec3& objectPosition, const glm::dquat& focusNodeRotationDiff) const;
/**
* Updates the global rotation so that it points towards the focus node.
* \returns a global rotation quaternion defining a rotation towards the focus node.
*/
glm::dquat rotateGlobally(const glm::dquat& globalCameraRotation,
const glm::dvec3& objectPosition,
const glm::dquat& focusNodeRotationDiff,
const glm::dvec3& cameraPosition,
const SurfacePositionHandle& positionHandle) const;
const glm::dvec3& objectPosition, const glm::dquat& focusNodeRotationDiff,
const glm::dvec3& cameraPosition,
const SurfacePositionHandle& positionHandle) const;
/**
* Translates the camera position towards or away from the focus node.
* \returns a position vector adjusted in the vertical direction.
*/
glm::dvec3 translateVertically(double deltaTime, const glm::dvec3& cameraPosition,
const glm::dvec3& objectPosition,
const SurfacePositionHandle& positionHandle) const;
const glm::dvec3& objectPosition,
const SurfacePositionHandle& positionHandle) const;
/**
* Rotates the camera around the out vector of the surface.
* \returns a quaternion adjusted to rotate around the out vector of the surface.
*/
glm::dquat rotateHorizontally(double deltaTime,
const glm::dquat& globalCameraRotation,
const glm::dvec3& cameraPosition,
const SurfacePositionHandle& positionHandle) const;
const glm::dquat& globalCameraRotation, const glm::dvec3& cameraPosition,
const SurfacePositionHandle& positionHandle) const;
/**
* Push the camera out to the surface of the object.
@@ -179,19 +182,16 @@ private:
* above the actual surface of the object
*/
glm::dvec3 pushToSurface(double minHeightAboveGround,
const glm::dvec3& cameraPosition,
const glm::dvec3& objectPosition,
const SurfacePositionHandle& positionHandle) const;
const glm::dvec3& cameraPosition, const glm::dvec3& objectPosition,
const SurfacePositionHandle& positionHandle) const;
/**
* Interpolates between rotationDiff and a 0 rotation.
*/
glm::dquat interpolateRotationDifferential(
double deltaTime, double interpolationTime,
const glm::dquat& rotationDiff,
const glm::dvec3& objectPosition,
const glm::dvec3& cameraPosition,
const SurfacePositionHandle& positionHandle);
glm::dquat interpolateRotationDifferential(double deltaTime,
double interpolationTime, const glm::dquat& rotationDiff,
const glm::dvec3& objectPosition, const glm::dvec3& cameraPosition,
const SurfacePositionHandle& positionHandle);
/**
* Calculates a SurfacePositionHandle given a camera position in world space.
+2
View File
@@ -33,6 +33,7 @@ set(HEADER_FILES
${CMAKE_CURRENT_SOURCE_DIR}/include/guifilepathcomponent.h
${CMAKE_CURRENT_SOURCE_DIR}/include/guiglobebrowsingcomponent.h
${CMAKE_CURRENT_SOURCE_DIR}/include/guihelpcomponent.h
${CMAKE_CURRENT_SOURCE_DIR}/include/guijoystickcomponent.h
${CMAKE_CURRENT_SOURCE_DIR}/include/guimissioncomponent.h
${CMAKE_CURRENT_SOURCE_DIR}/include/guiperformancecomponent.h
${CMAKE_CURRENT_SOURCE_DIR}/include/guiparallelcomponent.h
@@ -51,6 +52,7 @@ set(SOURCE_FILES
${CMAKE_CURRENT_SOURCE_DIR}/src/guifilepathcomponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guiglobebrowsingcomponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guihelpcomponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guijoystickcomponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guimissioncomponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guiperformancecomponent.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/guiparallelcomponent.cpp
+1 -1
View File
@@ -31,9 +31,9 @@
#include <openspace/engine/wrapper/windowwrapper.h>
#include <openspace/engine/moduleengine.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/luaconsole.h>
#include <openspace/network/parallelconnection.h>
#include <openspace/rendering/dashboard.h>
#include <openspace/rendering/luaconsole.h>
#include <openspace/rendering/renderengine.h>
#include <openspace/rendering/screenspacerenderable.h>
#include <openspace/scene/scene.h>
+2
View File
@@ -31,6 +31,7 @@
#include <modules/imgui/include/guiglobebrowsingcomponent.h>
#include <modules/imgui/include/guihelpcomponent.h>
#include <modules/imgui/include/guiiswacomponent.h>
#include <modules/imgui/include/guijoystickcomponent.h>
#include <modules/imgui/include/guimissioncomponent.h>
#include <modules/imgui/include/guiparallelcomponent.h>
#include <modules/imgui/include/guiperformancecomponent.h>
@@ -87,6 +88,7 @@ public:
#ifdef OPENSPACE_MODULE_ISWA_ENABLED
GuiIswaComponent _iswa;
#endif // OPENSPACE_MODULE_ISWA_ENABLED
GuiJoystickComponent _joystick;
GuiParallelComponent _parallel;
GuiPropertyComponent _featuredProperties;
@@ -22,15 +22,20 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/interaction/controller.h>
#ifndef __OPENSPACE_MODULE_IMGUI___GUIJOYSTICKCOMPONENT___H__
#define __OPENSPACE_MODULE_IMGUI___GUIJOYSTICKCOMPONENT___H__
#include <openspace/interaction/navigationhandler.h>
#include <modules/imgui/include/guicomponent.h>
namespace openspace::interaction {
namespace openspace::gui {
void Controller::setHandler(NavigationHandler* handler) {
_handler = handler;
}
class GuiJoystickComponent : public GuiComponent {
public:
GuiJoystickComponent();
} // namespace openspace::interaction
void render() override;
};
} // namespace openspace::gui
#endif // __OPENSPACE_MODULE_IMGUI___GUIJOYSTICKCOMPONENT___H__
+16 -54
View File
@@ -160,60 +160,6 @@ static void RenderDrawLists(ImDrawData* drawData) {
}
}
//// Grow our buffer according to what we need
//size_t totalVertexCount = 0;
//for (int i = 0; i < nCommandLists; ++i)
// totalVertexCount += commandLists[i]->vtx_buffer.size();
//glBindBuffer(GL_ARRAY_BUFFER, vbo);
//size_t neededBufferSize = totalVertexCount * sizeof(ImDrawVert);
//if (neededBufferSize > vboMaxSize) {
// // Grow buffer
// vboMaxSize = neededBufferSize * 1.25f;
// glBufferData(GL_ARRAY_BUFFER, vboMaxSize, NULL, GL_STREAM_DRAW);
//}
//// Copy and convert all vertices into a single contiguous buffer
//unsigned char* bufferData = reinterpret_cast<unsigned char*>(
// glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY)
// );
//if (!bufferData) {
// LFATAL("Error mapping ImGui buffer");
// return;
//}
//for (int i = 0; i < nCommandLists; ++i) {
// const ImDrawList* cmd_list = commandLists[i];
// memcpy(
// bufferData,
// &cmd_list->vtx_buffer[0],
// cmd_list->vtx_buffer.size() * sizeof(ImDrawVert)
// );
// bufferData += (cmd_list->vtx_buffer.size() * sizeof(ImDrawVert));
//}
//glUnmapBuffer(GL_ARRAY_BUFFER);
//glBindBuffer(GL_ARRAY_BUFFER, 0);
//glBindVertexArray(vao);
//int cmdOffset = 0;
//for (int i = 0; i < nCommandLists; ++i) {
// const ImDrawList* cmd_list = commandLists[i];
// int vtxOffset = cmdOffset;
// for (const auto& pcmd : cmd_list->commands) {
// glScissor(
// static_cast<int>(pcmd.clip_rect.x),
// static_cast<int>(height - pcmd.clip_rect.w),
// static_cast<int>(pcmd.clip_rect.z - pcmd.clip_rect.x),
// static_cast<int>(pcmd.clip_rect.w - pcmd.clip_rect.y)
// );
// glDrawArrays(GL_TRIANGLES, vtxOffset, pcmd.vtx_count);
// vtxOffset += pcmd.vtx_count;
// }
// cmdOffset = vtxOffset;
//}
glBindVertexArray(0);
_program->deactivate();
glDisable(GL_SCISSOR_TEST);
@@ -310,6 +256,7 @@ GUI::GUI()
#ifdef GLOBEBROWSING_USE_GDAL
addPropertySubOwner(_globeBrowsing);
#endif // GLOBEBROWSING_USE_GDAL
addPropertySubOwner(_joystick);
addPropertySubOwner(_filePath);
addPropertySubOwner(_asset);
_spaceTime.setEnabled(true);
@@ -337,6 +284,7 @@ GUI::GUI()
#ifdef OPENSPACE_MODULE_ISWA_ENABLED
_iswa.setShowHelpTooltip(_showHelpText);
#endif // OPENSPACE_MODULE_ISWA_ENABLED
_joystick.setShowHelpTooltip(_showHelpText);
_parallel.setShowHelpTooltip(_showHelpText);
_featuredProperties.setShowHelpTooltip(_showHelpText);
};
@@ -363,6 +311,7 @@ GUI::GUI()
#ifdef OPENSPACE_MODULE_ISWA_ENABLED
_iswa.setShowHelpTooltipDelay(_helpTextDelay);
#endif // OPENSPACE_MODULE_ISWA_ENABLED
_joystick.setShowHelpTooltipDelay(_helpTextDelay);
_parallel.setShowHelpTooltipDelay(_helpTextDelay);
_featuredProperties.setShowHelpTooltipDelay(_helpTextDelay);
};
@@ -502,6 +451,7 @@ void GUI::initialize() {
#ifdef GLOBEBROWSING_USE_GDAL
_globeBrowsing.initialize();
#endif // GLOBEBROWSING_USE_GDAL
_joystick.initialize();
_performance.initialize();
_help.initialize();
_parallel.initialize();
@@ -525,6 +475,7 @@ void GUI::deinitialize() {
_mission.deinitialize();
_parallel.deinitialize();
_help.deinitialize();
_joystick.deinitialize();
_performance.deinitialize();
_globalProperty.deinitialize();
_moduleProperty.deinitialize();
@@ -629,6 +580,7 @@ void GUI::initializeGL() {
_globalProperty.initializeGL();
_moduleProperty.initializeGL();
_featuredProperties.initializeGL();
_joystick.initializeGL();
_performance.initializeGL();
_help.initializeGL();
#ifdef GLOBEBROWSING_USE_GDAL
@@ -667,6 +619,7 @@ void GUI::deinitializeGL() {
_performance.deinitializeGL();
_featuredProperties.deinitializeGL();
_globalProperty.deinitializeGL();
_joystick.deinitializeGL();
_moduleProperty.deinitializeGL();
_screenSpaceProperty.deinitializeGL();
#ifdef GLOBEBROWSING_USE_GDAL
@@ -744,6 +697,11 @@ void GUI::endFrame() {
_iswa.render();
}
#endif // OPENSPACE_MODULE_ISWA_ENABLED
if (_joystick.isEnabled()) {
_joystick.render();
}
if (_filePath.isEnabled()) {
_filePath.render();
}
@@ -883,6 +841,10 @@ void GUI::render() {
ImGui::Checkbox("Mission Information", &mission);
_mission.setEnabled(mission);
bool joystick = _joystick.isEnabled();
ImGui::Checkbox("Joystick Information", &joystick);
_joystick.setEnabled(joystick);
bool filePath = _filePath.isEnabled();
ImGui::Checkbox("File Paths", &filePath);
_filePath.setEnabled(filePath);
+111
View File
@@ -0,0 +1,111 @@
/*****************************************************************************************
* *
* 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. *
****************************************************************************************/
#include <modules/imgui/include/guijoystickcomponent.h>
#include <modules/imgui/include/imgui_include.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/inputstate.h>
#include <openspace/interaction/joystickinputstate.h>
namespace {
const ImVec2 Size = ImVec2(350, 500);
} // namespace
namespace openspace::gui {
GuiJoystickComponent::GuiJoystickComponent()
: GuiComponent("joystick_information", "Joystick Information")
{}
void GuiJoystickComponent::render() {
using namespace interaction;
ImGui::SetNextWindowCollapsed(_isCollapsed);
bool v = _isEnabled;
ImGui::Begin("Joystick Information", &v, Size, 0.5f);
_isEnabled = v;
_isCollapsed = ImGui::IsWindowCollapsed();
const JoystickInputStates& states =
OsEng.navigationHandler().inputState().joystickInputStates();
for (int i = 0; i < states.size(); ++i) {
const JoystickInputState& state = states[i];
if (!state.isConnected) {
continue;
}
ImGui::Text("%s [%i]", state.name.c_str(), i);
ImGui::Text("%s", "Axes");
for (int j = 0; j < state.nAxes; ++j) {
float f = state.axes[j];
ImGui::SliderFloat(
std::to_string(j).c_str(),
&f,
-1.f,
1.f
);
}
ImGui::Text("%s", "Buttons");
for (int j = 0; j < state.nButtons; ++j) {
ImGui::RadioButton(
std::to_string(j).c_str(),
state.buttons[j] == JoystickAction::Press ||
state.buttons[j] == JoystickAction::Repeat
);
}
ImGui::Separator();
}
ImGui::Separator();
ImGui::Separator();
ImGui::Text("%s", "Summed contributions");
ImGui::Text("%s", "Axes");
for (int i = 0; i < JoystickInputState::MaxAxes; ++i) {
float f = states.axis(i);
ImGui::SliderFloat(
std::to_string(i).c_str(),
&f,
-1.f,
1.f
);
}
ImGui::Text("%s", "Buttons");
for (int i = 0; i < JoystickInputState::MaxButtons; ++i) {
ImGui::RadioButton(
std::to_string(i).c_str(),
states.button(i, JoystickAction::Press) ||
states.button(i, JoystickAction::Repeat)
);
}
ImGui::End();
}
} // namespace openspace::gui
@@ -24,7 +24,7 @@
#include <modules/server/include/jsonconverters.h>
#include <openspace/properties/property.h>
#include <openspace/interaction/luaconsole.h>
#include <openspace/rendering/luaconsole.h>
#include <openspace/network/parallelconnection.h>
#include <openspace/engine/wrapper/windowwrapper.h>
#include <openspace/interaction/navigationhandler.h>
+10 -6
View File
@@ -42,15 +42,16 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/engine/virtualpropertymanager.cpp
${OPENSPACE_BASE_DIR}/src/engine/wrapper/sgctwindowwrapper.cpp
${OPENSPACE_BASE_DIR}/src/engine/wrapper/windowwrapper.cpp
${OPENSPACE_BASE_DIR}/src/interaction/controller.cpp
${OPENSPACE_BASE_DIR}/src/interaction/camerainteractionstates.cpp
${OPENSPACE_BASE_DIR}/src/interaction/inputstate.cpp
${OPENSPACE_BASE_DIR}/src/interaction/joystickinputstate.cpp
${OPENSPACE_BASE_DIR}/src/interaction/joystickcamerastates.cpp
${OPENSPACE_BASE_DIR}/src/interaction/keybindingmanager.cpp
${OPENSPACE_BASE_DIR}/src/interaction/keybindingmanager_lua.inl
${OPENSPACE_BASE_DIR}/src/interaction/keyframenavigator.cpp
${OPENSPACE_BASE_DIR}/src/interaction/luaconsole.cpp
${OPENSPACE_BASE_DIR}/src/interaction/navigationhandler.cpp
${OPENSPACE_BASE_DIR}/src/interaction/navigationhandler_lua.inl
${OPENSPACE_BASE_DIR}/src/interaction/mousestate.cpp
${OPENSPACE_BASE_DIR}/src/interaction/mousecamerastates.cpp
${OPENSPACE_BASE_DIR}/src/interaction/orbitalnavigator.cpp
${OPENSPACE_BASE_DIR}/src/mission/mission.cpp
${OPENSPACE_BASE_DIR}/src/mission/missionmanager.cpp
@@ -128,6 +129,7 @@ set(OPENSPACE_SOURCE
${OPENSPACE_BASE_DIR}/src/rendering/framebufferrenderer.cpp
${OPENSPACE_BASE_DIR}/src/rendering/deferredcastermanager.cpp
${OPENSPACE_BASE_DIR}/src/rendering/loadingscreen.cpp
${OPENSPACE_BASE_DIR}/src/rendering/luaconsole.cpp
${OPENSPACE_BASE_DIR}/src/rendering/raycastermanager.cpp
${OPENSPACE_BASE_DIR}/src/rendering/renderable.cpp
${OPENSPACE_BASE_DIR}/src/rendering/renderengine.cpp
@@ -209,16 +211,17 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/engine/virtualpropertymanager.h
${OPENSPACE_BASE_DIR}/include/openspace/engine/wrapper/sgctwindowwrapper.h
${OPENSPACE_BASE_DIR}/include/openspace/engine/wrapper/windowwrapper.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/controller.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/delayedvariable.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/delayedvariable.inl
${OPENSPACE_BASE_DIR}/include/openspace/interaction/camerainteractionstates.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/inputstate.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/interpolator.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/interpolator.inl
${OPENSPACE_BASE_DIR}/include/openspace/interaction/joystickinputstate.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/joystickcamerastates.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/keybindingmanager.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/keyframenavigator.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/luaconsole.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/mousestate.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/mousecamerastates.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/navigationhandler.h
${OPENSPACE_BASE_DIR}/include/openspace/interaction/orbitalnavigator.h
${OPENSPACE_BASE_DIR}/include/openspace/mission/mission.h
@@ -305,6 +308,7 @@ set(OPENSPACE_HEADER
${OPENSPACE_BASE_DIR}/include/openspace/rendering/deferredcasterlistener.h
${OPENSPACE_BASE_DIR}/include/openspace/rendering/deferredcastermanager.h
${OPENSPACE_BASE_DIR}/include/openspace/rendering/loadingscreen.h
${OPENSPACE_BASE_DIR}/include/openspace/rendering/luaconsole.h
${OPENSPACE_BASE_DIR}/include/openspace/rendering/raycasterlistener.h
${OPENSPACE_BASE_DIR}/include/openspace/rendering/raycastermanager.h
${OPENSPACE_BASE_DIR}/include/openspace/rendering/renderable.h
+10 -6
View File
@@ -35,9 +35,8 @@
#include <openspace/engine/syncengine.h>
#include <openspace/engine/virtualpropertymanager.h>
#include <openspace/engine/wrapper/windowwrapper.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/keybindingmanager.h>
#include <openspace/interaction/luaconsole.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/network/networkengine.h>
#include <openspace/network/parallelpeer.h>
@@ -46,6 +45,7 @@
#include <openspace/rendering/dashboard.h>
#include <openspace/rendering/dashboarditem.h>
#include <openspace/rendering/loadingscreen.h>
#include <openspace/rendering/luaconsole.h>
#include <openspace/rendering/renderable.h>
#include <openspace/scripting/scriptscheduler.h>
#include <openspace/scripting/scriptengine.h>
@@ -293,7 +293,7 @@ void OpenSpaceEngine::create(int argc, char** argv,
// Parse commandline arguments
std::vector<std::string> args(argv, argv + argc);
const std::vector<std::string>& arguments =
std::vector<std::string> arguments =
_engine->_commandlineParser->setCommandLine(args);
bool showHelp = _engine->_commandlineParser->execute();
@@ -302,8 +302,8 @@ void OpenSpaceEngine::create(int argc, char** argv,
requestClose = true;
return;
}
std::vector<std::string> argumentsCopy = arguments;
sgctArguments = std::move(argumentsCopy);
sgctArguments = std::move(arguments);
// Find configuration
std::string configurationFilePath = commandlineArgumentPlaceholders.configurationName;
@@ -1283,7 +1283,7 @@ void OpenSpaceEngine::preSynchronization() {
}
_renderEngine->updateScene();
_navigationHandler->updateCamera(dt);
//_navigationHandler->updateCamera(dt);
Camera* camera = _renderEngine->camera();
if (camera) {
@@ -1510,6 +1510,10 @@ void OpenSpaceEngine::mouseScrollWheelCallback(double posX, double posY) {
_navigationHandler->mouseScrollWheelCallback(posY);
}
void OpenSpaceEngine::setJoystickInputStates(interaction::JoystickInputStates& states) {
_navigationHandler->setJoystickInputStates(states);
}
void OpenSpaceEngine::encode() {
_syncEngine->encodeSyncables();
+101
View File
@@ -0,0 +1,101 @@
/*****************************************************************************************
* *
* 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. *
****************************************************************************************/
#include <openspace/interaction/inputdevicestates.h>
#include <openspace/interaction/inputstate.h>
namespace openspace::interaction {
CameraInteractionStates::InteractionState::InteractionState(double scaleFactor)
: previousPosition(0.0, 0.0)
, velocity(scaleFactor, 1)
{}
void CameraInteractionStates::InteractionState::setFriction(double friction) {
velocity.setFriction(friction);
}
void CameraInteractionStates::InteractionState::setVelocityScaleFactor(double scaleFactor)
{
velocity.setScaleFactor(scaleFactor);
}
CameraInteractionStates::CameraInteractionStates(double sensitivity,
double velocityScaleFactor)
: _sensitivity(sensitivity)
, _globalRotationState(velocityScaleFactor)
, _localRotationState(velocityScaleFactor)
, _truckMovementState(velocityScaleFactor)
, _localRollState(velocityScaleFactor)
, _globalRollState(velocityScaleFactor)
{}
void CameraInteractionStates::setRotationalFriction(double friction) {
_localRotationState.setFriction(friction);
_localRollState.setFriction(friction);
_globalRollState.setFriction(friction);
}
void CameraInteractionStates::setHorizontalFriction(double friction) {
_globalRotationState.setFriction(friction);
}
void CameraInteractionStates::setVerticalFriction(double friction) {
_truckMovementState.setFriction(friction);
}
void CameraInteractionStates::setSensitivity(double sensitivity) {
_sensitivity = sensitivity;
}
void CameraInteractionStates::setVelocityScaleFactor(double scaleFactor) {
_globalRotationState.setVelocityScaleFactor(scaleFactor);
_localRotationState.setVelocityScaleFactor(scaleFactor);
_truckMovementState.setVelocityScaleFactor(scaleFactor);
_localRollState.setVelocityScaleFactor(scaleFactor);
_globalRollState.setVelocityScaleFactor(scaleFactor);
}
glm::dvec2 CameraInteractionStates::globalRotationVelocity() const{
return _globalRotationState.velocity.get();
}
glm::dvec2 CameraInteractionStates::localRotationVelocity() const{
return _localRotationState.velocity.get();
}
glm::dvec2 CameraInteractionStates::truckMovementVelocity() const{
return _truckMovementState.velocity.get();
}
glm::dvec2 CameraInteractionStates::localRollVelocity() const{
return _localRollState.velocity.get();
}
glm::dvec2 CameraInteractionStates::globalRollVelocity() const{
return _globalRollState.velocity.get();
}
} // namespace openspace::interaction
+101
View File
@@ -0,0 +1,101 @@
/*****************************************************************************************
* *
* 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. *
****************************************************************************************/
#include <openspace/interaction/camerainteractionstates.h>
#include <openspace/interaction/inputstate.h>
namespace openspace::interaction {
CameraInteractionStates::InteractionState::InteractionState(double scaleFactor)
: previousPosition(0.0, 0.0)
, velocity(scaleFactor, 1)
{}
void CameraInteractionStates::InteractionState::setFriction(double friction) {
velocity.setFriction(friction);
}
void CameraInteractionStates::InteractionState::setVelocityScaleFactor(double scaleFactor)
{
velocity.setScaleFactor(scaleFactor);
}
CameraInteractionStates::CameraInteractionStates(double sensitivity,
double velocityScaleFactor)
: _sensitivity(sensitivity)
, _globalRotationState(velocityScaleFactor)
, _localRotationState(velocityScaleFactor)
, _truckMovementState(velocityScaleFactor)
, _localRollState(velocityScaleFactor)
, _globalRollState(velocityScaleFactor)
{}
void CameraInteractionStates::setRotationalFriction(double friction) {
_localRotationState.setFriction(friction);
_localRollState.setFriction(friction);
_globalRollState.setFriction(friction);
}
void CameraInteractionStates::setHorizontalFriction(double friction) {
_globalRotationState.setFriction(friction);
}
void CameraInteractionStates::setVerticalFriction(double friction) {
_truckMovementState.setFriction(friction);
}
void CameraInteractionStates::setSensitivity(double sensitivity) {
_sensitivity = sensitivity;
}
void CameraInteractionStates::setVelocityScaleFactor(double scaleFactor) {
_globalRotationState.setVelocityScaleFactor(scaleFactor);
_localRotationState.setVelocityScaleFactor(scaleFactor);
_truckMovementState.setVelocityScaleFactor(scaleFactor);
_localRollState.setVelocityScaleFactor(scaleFactor);
_globalRollState.setVelocityScaleFactor(scaleFactor);
}
glm::dvec2 CameraInteractionStates::globalRotationVelocity() const{
return _globalRotationState.velocity.get();
}
glm::dvec2 CameraInteractionStates::localRotationVelocity() const{
return _localRotationState.velocity.get();
}
glm::dvec2 CameraInteractionStates::truckMovementVelocity() const{
return _truckMovementState.velocity.get();
}
glm::dvec2 CameraInteractionStates::localRollVelocity() const{
return _localRollState.velocity.get();
}
glm::dvec2 CameraInteractionStates::globalRollVelocity() const{
return _globalRollState.velocity.get();
}
} // namespace openspace::interaction
+22 -8
View File
@@ -24,8 +24,8 @@
#include <openspace/interaction/inputstate.h>
#include <ghoul/fmt.h>
#include <ghoul/logging/logmanager.h>
#include <algorithm>
namespace openspace::interaction {
@@ -46,9 +46,7 @@ void InputState::mouseButtonCallback(MouseButton button, MouseAction action) {
_mouseButtonsDown.push_back(button);
}
else if (action == MouseAction::Release) {
// Remove all key pressings for 'button'
_mouseButtonsDown.remove_if([button](MouseButton buttonInList)
{ return button == buttonInList; });
_mouseButtonsDown.remove(button);
}
}
@@ -60,19 +58,23 @@ void InputState::mouseScrollWheelCallback(double mouseScrollDelta) {
_mouseScrollDelta = mouseScrollDelta;
}
const std::list<std::pair<Key, KeyModifier> >& InputState::getPressedKeys() const {
void InputState::setJoystickInputStates(JoystickInputStates& states) {
_joystickInputStates = &states;
}
const std::list<std::pair<Key, KeyModifier>>& InputState::pressedKeys() const {
return _keysDown;
}
const std::list<MouseButton>& InputState::getPressedMouseButtons() const {
const std::list<MouseButton>& InputState::pressedMouseButtons() const {
return _mouseButtonsDown;
}
glm::dvec2 InputState::getMousePosition() const {
glm::dvec2 InputState::mousePosition() const {
return _mousePosition;
}
double InputState::getMouseScrollDelta() const {
double InputState::mouseScrollDelta() const {
return _mouseScrollDelta;
}
@@ -92,4 +94,16 @@ bool InputState::isMouseButtonPressed(MouseButton mouseButton) const {
mouseButton) != _mouseButtonsDown.end();
}
const JoystickInputStates& InputState::joystickInputStates() const {
return *_joystickInputStates;
}
float InputState::joystickAxis(int i) const {
return _joystickInputStates->axis(i);
}
bool InputState::joystickButton(int i) const{
return _joystickInputStates->button(i, JoystickAction::Press);
}
} // namespace openspace::interaction
+272
View File
@@ -0,0 +1,272 @@
/*****************************************************************************************
* *
* 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. *
****************************************************************************************/
#include <openspace/interaction/joystickcamerastates.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/interaction/inputstate.h>
#include <openspace/scripting/scriptengine.h>
#include <utility>
namespace openspace::interaction {
JoystickCameraStates::JoystickCameraStates(double sensitivity, double velocityScaleFactor)
: CameraInteractionStates(sensitivity, velocityScaleFactor)
{}
void JoystickCameraStates::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) };
for (int i = 0; i < JoystickInputState::MaxAxes; ++i) {
AxisInformation t = _axisMapping[i];
if (t.type == AxisType::None) {
continue;
}
bool hasValue = true;
float value = inputState.joystickAxis(i);
if (abs(value) <= t.deadzone) {
value = 0.f;
hasValue = false;
}
if (t.normalize) {
value = (value + 1.f) / 2.f;
}
if (t.invert) {
value *= -1.f;
}
value *= _sensitivity;
switch (t.type) {
case AxisType::None:
break;
case AxisType::OrbitX:
globalRotation.first = hasValue;
globalRotation.second.x = value;
break;
case AxisType::OrbitY:
globalRotation.first = hasValue;
globalRotation.second.y = value;
break;
case AxisType::ZoomIn:
zoom.first = hasValue;
zoom.second += value;
break;
case AxisType::ZoomOut:
zoom.first = hasValue;
zoom.second -= value;
break;
case AxisType::LocalRollX:
localRoll.first = hasValue;
localRoll.second.x = value;
break;
case AxisType::LocalRollY:
localRoll.first = hasValue;
localRoll.second.y = value;
break;
case AxisType::GlobalRollX:
globalRoll.first = hasValue;
globalRoll.second.x = value;
break;
case AxisType::GlobalRollY:
globalRoll.first = hasValue;
globalRoll.second.y = value;
break;
case AxisType::PanX:
localRotation.first = hasValue;
localRotation.second.x = value;
break;
case AxisType::PanY:
localRotation.first = hasValue;
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);
}
for (int i = 0; i < JoystickInputState::MaxButtons; ++i) {
auto itRange = _buttonMapping.equal_range(i);
for (auto it = itRange.first; it != itRange.second; ++it) {
bool active = inputState.joystickInputStates().button(i, it->second.action);
if (active) {
OsEng.scriptEngine().queueScript(
it->second.command,
scripting::ScriptEngine::RemoteScripting(it->second.synchronization)
);
}
}
}
}
void JoystickCameraStates::setAxisMapping(int axis, AxisType mapping,
AxisInvert shouldInvert,
AxisNormalize shouldNormalize)
{
ghoul_assert(axis < JoystickInputState::MaxAxes, "axis must be < MaxAxes");
_axisMapping[axis] = { mapping, shouldInvert, shouldNormalize };
}
JoystickCameraStates::AxisInformation JoystickCameraStates::axisMapping(int axis) const {
return _axisMapping[axis];
}
void JoystickCameraStates::setDeadzone(int axis, float deadzone) {
_axisMapping[axis].deadzone = deadzone;
}
float JoystickCameraStates::deadzone(int axis) const {
return _axisMapping[axis].deadzone;
}
void JoystickCameraStates::bindButtonCommand(int button, std::string command,
JoystickAction action,
ButtonCommandRemote remote)
{
_buttonMapping.insert({
button,
{ std::move(command), action, remote }
});
}
void JoystickCameraStates::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> JoystickCameraStates::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 std {
std::string to_string(const openspace::interaction::JoystickCameraStates::AxisType& type)
{
using T = openspace::interaction::JoystickCameraStates::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 "";
}
}
} // namespace std
namespace ghoul {
template <>
openspace::interaction::JoystickCameraStates::AxisType from_string(
const std::string& string)
{
using T = openspace::interaction::JoystickCameraStates::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
+100
View File
@@ -0,0 +1,100 @@
/*****************************************************************************************
* *
* 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. *
****************************************************************************************/
#include <openspace/interaction/joystickinputstate.h>
#include <ghoul/glm.h>
#include <ghoul/misc/invariants.h>
#include <algorithm>
#include <map>
#include <numeric>
namespace openspace::interaction {
float JoystickInputStates::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 JoystickInputState& state) {
if (state.isConnected) {
value += state.axes[axis];
}
return value;
}
);
// If multiple joysticks are connected, we might get values outside the -1,1 range by
// summing them up
glm::clamp(res, -1.f, 1.f);
return res;
}
bool JoystickInputStates::button(int button, JoystickAction action) const {
ghoul_precondition(button >= 0, "button must be 0 or positive");
bool res = std::any_of(
begin(),
end(),
[button, action](const JoystickInputState& state) {
return state.isConnected ? (state.buttons[button] == action) : false;
}
);
return res;
}
} // namespace openspace::interaction
namespace std {
std::string to_string(openspace::interaction::JoystickAction action) {
switch (action) {
case openspace::interaction::JoystickAction::Idle: return "Idle";
case openspace::interaction::JoystickAction::Press: return "Press";
case openspace::interaction::JoystickAction::Repeat: return "Repeat";
case openspace::interaction::JoystickAction::Release: return "Release";
default: return "";
}
}
} // namespace std
namespace ghoul {
template <>
openspace::interaction::JoystickAction from_string(const std::string& string) {
static const std::map<std::string, openspace::interaction::JoystickAction> Map = {
{ "Idle", openspace::interaction::JoystickAction::Idle },
{ "Press", openspace::interaction::JoystickAction::Press },
{ "Repeat", openspace::interaction::JoystickAction::Repeat },
{ "Release", openspace::interaction::JoystickAction::Release }
};
return Map.at(string);
}
} // namespace ghoul
+1 -1
View File
@@ -22,7 +22,7 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/interaction/luaconsole.h>
#include <openspace/rendering/luaconsole.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/wrapper/windowwrapper.h>
+125
View File
@@ -0,0 +1,125 @@
/*****************************************************************************************
* *
* 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. *
****************************************************************************************/
#include <openspace/interaction/mousecamerastates.h>
#include <openspace/interaction/inputstate.h>
namespace openspace::interaction {
MouseCameraStates::MouseCameraStates(double sensitivity, double velocityScaleFactor)
: CameraInteractionStates(sensitivity, velocityScaleFactor)
{}
void MouseCameraStates::updateStateFromInput(const InputState& inputState, double deltaTime) {
glm::dvec2 mousePosition = inputState.mousePosition();
bool button1Pressed = inputState.isMouseButtonPressed(MouseButton::Button1);
bool button2Pressed = inputState.isMouseButtonPressed(MouseButton::Button2);
bool button3Pressed = inputState.isMouseButtonPressed(MouseButton::Button3);
bool keyCtrlPressed = inputState.isKeyPressed(Key::LeftControl) |
inputState.isKeyPressed(Key::RightControl);
bool keyShiftPressed = inputState.isKeyPressed(Key::LeftShift) |
inputState.isKeyPressed(Key::RightShift);
bool keyAltPressed = inputState.isKeyPressed(Key::LeftAlt) |
inputState.isKeyPressed(Key::RightAlt);
// Update the mouse states
if (button1Pressed && !keyShiftPressed && !keyAltPressed) {
if (keyCtrlPressed) {
glm::dvec2 mousePositionDelta =
_localRotationState.previousPosition - mousePosition;
_localRotationState.velocity.set(
mousePositionDelta * _sensitivity,
deltaTime
);
_globalRotationState.previousPosition = mousePosition;
_globalRotationState.velocity.decelerate(deltaTime);
}
else {
glm::dvec2 mousePositionDelta =
_globalRotationState.previousPosition - mousePosition;
_globalRotationState.velocity.set(
mousePositionDelta * _sensitivity,
deltaTime
);
_localRotationState.previousPosition = mousePosition;
_localRotationState.velocity.decelerate(deltaTime);
}
}
else { // !button1Pressed
_localRotationState.previousPosition = mousePosition;
_localRotationState.velocity.decelerate(deltaTime);
_globalRotationState.previousPosition = mousePosition;
_globalRotationState.velocity.decelerate(deltaTime);
}
if (button2Pressed || (keyAltPressed && button1Pressed)) {
glm::dvec2 mousePositionDelta =
_truckMovementState.previousPosition - mousePosition;
_truckMovementState.velocity.set(
mousePositionDelta * _sensitivity,
deltaTime
);
}
else { // !button2Pressed
_truckMovementState.previousPosition = mousePosition;
_truckMovementState.velocity.decelerate(deltaTime);
}
if (button3Pressed || (keyShiftPressed && button1Pressed)) {
if (keyCtrlPressed) {
glm::dvec2 mousePositionDelta =
_localRollState.previousPosition - mousePosition;
_localRollState.velocity.set(
mousePositionDelta * _sensitivity,
deltaTime
);
_globalRollState.previousPosition = mousePosition;
_globalRollState.velocity.decelerate(deltaTime);
}
else {
glm::dvec2 mousePositionDelta =
_globalRollState.previousPosition - mousePosition;
_globalRollState.velocity.set(
mousePositionDelta * _sensitivity,
deltaTime
);
_localRollState.previousPosition = mousePosition;
_localRollState.velocity.decelerate(deltaTime);
}
}
else { // !button3Pressed
_globalRollState.previousPosition = mousePosition;
_globalRollState.velocity.decelerate(deltaTime);
_localRollState.previousPosition = mousePosition;
_localRollState.velocity.decelerate(deltaTime);
}
}
} // namespace openspace::interaction
-179
View File
@@ -1,179 +0,0 @@
/*****************************************************************************************
* *
* 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. *
****************************************************************************************/
#include <openspace/interaction/mousestate.h>
namespace openspace::interaction {
MouseState::MouseState(double scaleFactor)
: previousPosition(0.0, 0.0)
, velocity(scaleFactor, 1)
{}
void MouseState::setFriction(double friction) {
velocity.setFriction(friction);
}
void MouseState::setVelocityScaleFactor(double scaleFactor) {
velocity.setScaleFactor(scaleFactor);
}
MouseStates::MouseStates(double sensitivity, double velocityScaleFactor)
: _sensitivity(sensitivity)
, _globalRotationMouseState(velocityScaleFactor)
, _localRotationMouseState(velocityScaleFactor)
, _truckMovementMouseState(velocityScaleFactor)
, _localRollMouseState(velocityScaleFactor)
, _globalRollMouseState(velocityScaleFactor)
{ }
void MouseStates::updateMouseStatesFromInput(const InputState& inputState,
double deltaTime)
{
glm::dvec2 mousePosition = inputState.getMousePosition();
bool button1Pressed = inputState.isMouseButtonPressed(MouseButton::Button1);
bool button2Pressed = inputState.isMouseButtonPressed(MouseButton::Button2);
bool button3Pressed = inputState.isMouseButtonPressed(MouseButton::Button3);
bool keyCtrlPressed = inputState.isKeyPressed(Key::LeftControl) |
inputState.isKeyPressed(Key::RightControl);
bool keyShiftPressed = inputState.isKeyPressed(Key::LeftShift) |
inputState.isKeyPressed(Key::RightShift);
bool keyAltPressed = inputState.isKeyPressed(Key::LeftAlt) |
inputState.isKeyPressed(Key::RightAlt);
// Update the mouse states
if (button1Pressed && !keyShiftPressed && !keyAltPressed) {
if (keyCtrlPressed) {
glm::dvec2 mousePositionDelta =
_localRotationMouseState.previousPosition - mousePosition;
_localRotationMouseState.velocity.set(
mousePositionDelta * _sensitivity, deltaTime);
_globalRotationMouseState.previousPosition = mousePosition;
_globalRotationMouseState.velocity.decelerate(deltaTime);
}
else {
glm::dvec2 mousePositionDelta =
_globalRotationMouseState.previousPosition - mousePosition;
_globalRotationMouseState.velocity.set(
mousePositionDelta * _sensitivity, deltaTime);
_localRotationMouseState.previousPosition = mousePosition;
_localRotationMouseState.velocity.decelerate(deltaTime);
}
}
else { // !button1Pressed
_localRotationMouseState.previousPosition = mousePosition;
_localRotationMouseState.velocity.decelerate(deltaTime);
_globalRotationMouseState.previousPosition = mousePosition;
_globalRotationMouseState.velocity.decelerate(deltaTime);
}
if (button2Pressed || (keyAltPressed && button1Pressed)) {
glm::dvec2 mousePositionDelta =
_truckMovementMouseState.previousPosition - mousePosition;
_truckMovementMouseState.velocity.set(
mousePositionDelta * _sensitivity, deltaTime);
}
else { // !button2Pressed
_truckMovementMouseState.previousPosition = mousePosition;
_truckMovementMouseState.velocity.decelerate(deltaTime);
}
if (button3Pressed || (keyShiftPressed && button1Pressed)) {
if (keyCtrlPressed) {
glm::dvec2 mousePositionDelta =
_localRollMouseState.previousPosition - mousePosition;
_localRollMouseState.velocity.set(
mousePositionDelta * _sensitivity, deltaTime);
_globalRollMouseState.previousPosition = mousePosition;
_globalRollMouseState.velocity.decelerate(deltaTime);
}
else {
glm::dvec2 mousePositionDelta =
_globalRollMouseState.previousPosition - mousePosition;
_globalRollMouseState.velocity.set(
mousePositionDelta * _sensitivity, deltaTime);
_localRollMouseState.previousPosition = mousePosition;
_localRollMouseState.velocity.decelerate(deltaTime);
}
}
else { // !button3Pressed
_globalRollMouseState.previousPosition = mousePosition;
_globalRollMouseState.velocity.decelerate(deltaTime);
_localRollMouseState.previousPosition = mousePosition;
_localRollMouseState.velocity.decelerate(deltaTime);
}
}
void MouseStates::setRotationalFriction(double friction) {
_localRotationMouseState.setFriction(friction);
_localRollMouseState.setFriction(friction);
_globalRollMouseState.setFriction(friction);
}
void MouseStates::setHorizontalFriction(double friction) {
_globalRotationMouseState.setFriction(friction);
}
void MouseStates::setVerticalFriction(double friction) {
_truckMovementMouseState.setFriction(friction);
}
void MouseStates::setSensitivity(double sensitivity) {
_sensitivity = sensitivity;
}
void MouseStates::setVelocityScaleFactor(double scaleFactor) {
_globalRotationMouseState.setVelocityScaleFactor(scaleFactor);
_localRotationMouseState.setVelocityScaleFactor(scaleFactor);
_truckMovementMouseState.setVelocityScaleFactor(scaleFactor);
_localRollMouseState.setVelocityScaleFactor(scaleFactor);
_globalRollMouseState.setVelocityScaleFactor(scaleFactor);
}
glm::dvec2 MouseStates::globalRotationMouseVelocity() const{
return _globalRotationMouseState.velocity.get();
}
glm::dvec2 MouseStates::localRotationMouseVelocity() const{
return _localRotationMouseState.velocity.get();
}
glm::dvec2 MouseStates::truckMovementMouseVelocity() const{
return _truckMovementMouseState.velocity.get();
}
glm::dvec2 MouseStates::localRollMouseVelocity() const{
return _localRollMouseState.velocity.get();
}
glm::dvec2 MouseStates::globalRollMouseVelocity() const{
return _globalRollMouseState.velocity.get();
}
} // namespace openspace::interaction
+110 -4
View File
@@ -153,8 +153,8 @@ void NavigationHandler::updateCamera(double deltaTime) {
_keyframeNavigator->updateCamera(*_camera);
}
else {
_orbitalNavigator->updateMouseStatesFromInput(*_inputState, deltaTime);
_orbitalNavigator->updateCameraStateFromMouseStates(*_camera, deltaTime);
_orbitalNavigator->updateStatesFromInput(*_inputState, deltaTime);
_orbitalNavigator->updateCameraStateFromStates(*_camera, deltaTime);
}
_camera->setFocusPositionVec3(focusNode()->worldPosition());
}
@@ -201,6 +201,10 @@ void NavigationHandler::keyboardCallback(Key key, KeyModifier modifier, KeyActio
_inputState->keyboardCallback(key, modifier, action);
}
void NavigationHandler::setJoystickInputStates(JoystickInputStates& states) {
_inputState->setJoystickInputStates(states);
}
void NavigationHandler::setCameraStateFromDictionary(const ghoul::Dictionary& cameraDict)
{
bool readSuccessful = true;
@@ -226,7 +230,7 @@ void NavigationHandler::setCameraStateFromDictionary(const ghoul::Dictionary& ca
cameraRotation.x, cameraRotation.y, cameraRotation.z, cameraRotation.w));
}
ghoul::Dictionary NavigationHandler::getCameraStateDictionary() {
ghoul::Dictionary NavigationHandler::cameraStateDictionary() {
glm::dvec3 cameraPosition;
glm::dquat quat;
glm::dvec4 cameraRotation;
@@ -248,7 +252,7 @@ void NavigationHandler::saveCameraStateToFile(const std::string& filepath) {
std::string fullpath = absPath(filepath);
LINFO(fmt::format("Saving camera position: {}", filepath));
ghoul::Dictionary cameraDict = getCameraStateDictionary();
ghoul::Dictionary cameraDict = cameraStateDictionary();
// TODO : Should get the camera state as a dictionary and save the dictionary to
// a file in form of a lua state and not use ofstreams here.
@@ -293,6 +297,52 @@ void NavigationHandler::restoreCameraStateFromFile(const std::string& filepath)
}
}
void NavigationHandler::setJoystickAxisMapping(int axis, JoystickCameraStates::AxisType mapping,
JoystickCameraStates::AxisInvert shouldInvert,
JoystickCameraStates::AxisNormalize shouldNormalize)
{
_orbitalNavigator->joystickStates().setAxisMapping(
axis,
mapping,
shouldInvert,
shouldNormalize
);
}
JoystickCameraStates::AxisInformation NavigationHandler::joystickAxisMapping(int axis) const {
return _orbitalNavigator->joystickStates().axisMapping(axis);
}
void NavigationHandler::setJoystickAxisDeadzone(int axis, float deadzone) {
_orbitalNavigator->joystickStates().setDeadzone(axis, deadzone);
}
float NavigationHandler::joystickAxisDeadzone(int axis) const {
return _orbitalNavigator->joystickStates().deadzone(axis);
}
void NavigationHandler::bindJoystickButtonCommand(int button, std::string command,
JoystickAction action,
JoystickCameraStates::ButtonCommandRemote remote)
{
_orbitalNavigator->joystickStates().bindButtonCommand(
button,
std::move(command),
action,
remote
);
}
void NavigationHandler::clearJoystickButtonCommand(int button) {
_orbitalNavigator->joystickStates().clearButtonCommand(button);
}
std::vector<std::string> NavigationHandler::joystickButtonCommand(int button) const {
return _orbitalNavigator->joystickStates().buttonCommand(button);
}
scripting::LuaLibrary NavigationHandler::luaLibrary() {
return {
"navigation",
@@ -324,6 +374,62 @@ scripting::LuaLibrary NavigationHandler::luaLibrary() {
{},
"void",
"Reset the camera direction to point at the focus node"
},
{
"bindJoystickAxis",
&luascriptfunctions::bindJoystickAxis,
{},
"int, axisType [, isInverted, isNormalized]",
"Binds the axis identified by the first argument to be used as the type "
"identified by the second argument. If 'isInverted' is 'true', the axis "
"value is inverted, if 'isNormalized' is true the axis value is "
"normalized from [-1, 1] to [0,1]."
},
{
"joystickAxis",
&luascriptfunctions::joystickAxis,
{},
"int",
"Returns the joystick axis information for the passed axis. The "
"information that is returned is the current axis binding as a string, "
"whether the values are inverted as bool, and whether the value are "
"normalized as a bool"
},
{
"setAxisDeadZone",
&luascriptfunctions::setJoystickAxisDeadzone,
{},
"int, float",
"Sets the deadzone for a particular joystick axis which means that any "
"input less than this value is completely ignored."
},
{
"bindJoystickButton",
&luascriptfunctions::bindJoystickButton,
{},
"int, string [, string, bool]",
"Binds a Lua script to be executed when the joystick button identified "
"by the first argument is triggered. The third argument determines when "
"the script should be executed, this defaults to 'pressed', which means "
"that the script is run when the user presses the button. The last "
"argument determines whether the command is going to be executable "
"locally or remotely. The latter being the default."
},
{
"clearJoystickButotn",
&luascriptfunctions::clearJoystickButton,
{},
"int",
"Removes all commands that are currently bound to the button identified "
"by the first argument"
},
{
"joystickButton",
&luascriptfunctions::joystickButton,
{},
"int",
"Returns the script that is currently bound to be executed when the "
"provided button is pressed"
}
}
};
+129
View File
@@ -22,6 +22,9 @@
* OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
****************************************************************************************/
#include <openspace/interaction/joystickcamerastates.h>
#include <numeric>
namespace openspace::luascriptfunctions {
int restoreCameraStateFromFile(lua_State* L) {
@@ -88,4 +91,130 @@ int resetCameraDirection(lua_State* L) {
return 0;
}
int bindJoystickAxis(lua_State* L) {
int n = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::bindJoystickAxis");
int axis = static_cast<int>(lua_tonumber(L, 1));
std::string axisType = lua_tostring(L, 2);
bool shouldInvert = false;
if (n > 2) {
shouldInvert = lua_toboolean(L, 3);
}
bool shouldNormalize = false;
if (n > 3) {
shouldNormalize = lua_toboolean(L, 4);
}
OsEng.navigationHandler().setJoystickAxisMapping(
axis,
ghoul::from_string<interaction::JoystickCameraStates::AxisType>(axisType),
interaction::JoystickCameraStates::AxisInvert(shouldInvert),
interaction::JoystickCameraStates::AxisNormalize(shouldNormalize)
);
return 0;
}
int joystickAxis(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::joystickAxis");
int axis = static_cast<int>(lua_tonumber(L, 1));
using AI = interaction::JoystickCameraStates::AxisInformation;
AI info = OsEng.navigationHandler().joystickAxisMapping(axis);
lua_settop(L, 0);
lua_pushstring(L, std::to_string(info.type).c_str());
lua_pushboolean(L, info.invert);
lua_pushboolean(L, info.normalize);
return 3;
}
int setJoystickAxisDeadzone(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 2, "lua::setJoystickAxisDeadzone");
int axis = static_cast<int>(lua_tointeger(L, 1));
float deadzone = static_cast<float>(lua_tonumber(L, 2));
OsEng.navigationHandler().setJoystickAxisDeadzone(axis, deadzone);
return 0;
}
int joystickAxisDeadzone(lua_State* L) {
ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::setJoystickAxisDeadzone");
int axis = static_cast<int>(lua_tointeger(L, 1));
float deadzone = OsEng.navigationHandler().joystickAxisDeadzone(axis);
lua_pushnumber(L, deadzone);
return 1;
}
int bindJoystickButton(lua_State* L) {
int n = ghoul::lua::checkArgumentsAndThrow(L, { 2, 4 }, "lua::bindJoystickButton");
int button = static_cast<int>(lua_tonumber(L, 1));
std::string command = lua_tostring(L, 2);
interaction::JoystickAction action = interaction::JoystickAction::Press;
if (n >= 3) {
action = ghoul::from_string<interaction::JoystickAction>(lua_tostring(L, 3));
}
bool isRemote = true;
if (n == 4) {
isRemote = lua_toboolean(L, 4);
}
OsEng.navigationHandler().bindJoystickButtonCommand(
button,
std::move(command),
action,
interaction::JoystickCameraStates::ButtonCommandRemote(isRemote)
);
lua_settop(L, 0);
return 0;
}
int clearJoystickButton(lua_State* L) {
int n = ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::bindJoystickButton");
int button = static_cast<int>(lua_tonumber(L, 1));
OsEng.navigationHandler().clearJoystickButtonCommand(button);
lua_settop(L, 0);
return 0;
}
int joystickButton(lua_State* L) {
int n = ghoul::lua::checkArgumentsAndThrow(L, 1, "lua::bindJoystickButton");
int button = static_cast<int>(lua_tonumber(L, 1));
std::vector<std::string> cmds = OsEng.navigationHandler().joystickButtonCommand(
button
);
std::string cmd = std::accumulate(
cmds.begin(),
cmds.end(),
std::string(),
[](std::string lhs, std::string rhs) {
return lhs + ";" + rhs;
}
);
lua_settop(L, 0);
lua_pushstring(L, cmd.c_str());
return 1;
}
} // namespace openspace::luascriptfunctions
+76 -35
View File
@@ -58,11 +58,18 @@ namespace {
"disabled, the camera will zoom in or out forever."
};
static const openspace::properties::Property::PropertyInfo SensitivityInfo = {
"Sensitivity",
"Sensitivity",
"Determines the sensitivity of the camera motion. The lower the sensitivity is "
"the less impact a mouse mothion will have."
static const openspace::properties::Property::PropertyInfo MouseSensitivityInfo = {
"MouseSensitivity",
"Mouse Sensitivity",
"Determines the sensitivity of the camera motion thorugh the mouse. The lower "
"the sensitivity is the less impact a mouse motion will have."
};
static const openspace::properties::Property::PropertyInfo JoystickSensitivityInfo = {
"JoystickSensitivity",
"Joystick Sensitivity",
"Determines the sensitivity of the camera motion thorugh a joystick. The lower "
"the sensitivity is the less impact a joystick motion will have."
};
static const openspace::properties::Property::PropertyInfo FrictionInfo = {
@@ -105,8 +112,10 @@ OrbitalNavigator::OrbitalNavigator()
: properties::PropertyOwner({ "OrbitalNavigator" })
, _followFocusNodeRotationDistance(FollowFocusNodeInfo, 5.0f, 0.0f, 20.f)
, _minimumAllowedDistance(MinimumDistanceInfo, 10.0f, 0.0f, 10000.f)
, _sensitivity(SensitivityInfo, 15.0f, 1.0f, 50.f)
, _mouseStates(_sensitivity * pow(10.0, -4), 1 / (_friction.friction + 0.0000001))
, _mouseSensitivity(MouseSensitivityInfo, 15.0f, 1.0f, 50.f)
, _joystickSensitivity(JoystickSensitivityInfo, 10.0f, 1.0f, 50.f)
, _mouseStates(_mouseSensitivity * 0.0001, 1 / (_friction.friction + 0.0000001))
, _joystickStates(_joystickSensitivity * 0.1, 1 / (_friction.friction + 0.0000001))
{
auto smoothStep =
[](double t) {
@@ -138,37 +147,47 @@ OrbitalNavigator::OrbitalNavigator()
// Define callback functions for changed properties
_friction.roll.onChange([&]() {
_mouseStates.setRotationalFriction(_friction.roll);
_joystickStates.setRotationalFriction(_friction.roll);
});
_friction.rotational.onChange([&]() {
_mouseStates.setHorizontalFriction(_friction.rotational);
_joystickStates.setHorizontalFriction(_friction.rotational);
});
_friction.zoom.onChange([&]() {
_mouseStates.setVerticalFriction(_friction.zoom);
_joystickStates.setVerticalFriction(_friction.zoom);
});
_friction.friction.onChange([&]() {
_mouseStates.setVelocityScaleFactor(1 / (_friction.friction + 0.0000001));
_joystickStates.setVelocityScaleFactor(1 / (_friction.friction + 0.0000001));
});
_sensitivity.onChange([&]() {
_mouseStates.setSensitivity(_sensitivity * pow(10.0,-4));
_mouseSensitivity.onChange([&]() {
_mouseStates.setSensitivity(_mouseSensitivity * pow(10.0, -4));
});
_joystickSensitivity.onChange([&]() {
_joystickStates.setSensitivity(_joystickSensitivity * pow(10.0, -4));
});
addPropertySubOwner(_friction);
addProperty(_followFocusNodeRotationDistance);
addProperty(_minimumAllowedDistance);
addProperty(_sensitivity);
addProperty(_mouseSensitivity);
addProperty(_joystickSensitivity);
}
OrbitalNavigator::~OrbitalNavigator() {}
void OrbitalNavigator::updateMouseStatesFromInput(const InputState& inputState,
void OrbitalNavigator::updateStatesFromInput(const InputState& inputState,
double deltaTime)
{
_mouseStates.updateMouseStatesFromInput(inputState, deltaTime);
_mouseStates.updateStateFromInput(inputState, deltaTime);
_joystickStates.updateStateFromInput(inputState, deltaTime);
}
void OrbitalNavigator::updateCameraStateFromMouseStates(Camera& camera, double deltaTime){
void OrbitalNavigator::updateCameraStateFromStates(Camera& camera, double deltaTime){
if (_focusNode) {
// Read the current state of the camera
glm::dvec3 camPos = camera.positionVec3();
@@ -347,23 +366,31 @@ OrbitalNavigator::CameraRotationDecomposition
glm::dquat OrbitalNavigator::roll(double deltaTime,
const glm::dquat& localCameraRotation) const
{
glm::dquat rollQuat = glm::angleAxis(
_mouseStates.localRollMouseVelocity().x * deltaTime,
glm::dquat mouseRollQuat = glm::angleAxis(
_mouseStates.localRollVelocity().x * deltaTime +
_joystickStates.localRollVelocity().x * deltaTime,
glm::dvec3(0.0, 0.0, 1.0)
);
return localCameraRotation * rollQuat;
return localCameraRotation * mouseRollQuat;
}
glm::dquat OrbitalNavigator::rotateLocally(double deltaTime,
const glm::dquat& localCameraRotation) const
{
glm::dvec3 eulerAngles(
_mouseStates.localRotationMouseVelocity().y,
_mouseStates.localRotationMouseVelocity().x,
glm::dquat mouseRotationDiff = glm::dquat(glm::dvec3(
_mouseStates.localRotationVelocity().y,
_mouseStates.localRotationVelocity().x,
0.0
);
glm::dquat rotationDiff = glm::dquat(eulerAngles * deltaTime);
return localCameraRotation * rotationDiff;
) * deltaTime);
glm::dquat joystickRotationDiff = glm::dquat(glm::dvec3(
_joystickStates.localRotationVelocity().y,
_joystickStates.localRotationVelocity().x,
0.0
) * deltaTime);
return localCameraRotation * joystickRotationDiff * mouseRotationDiff;
}
glm::dquat OrbitalNavigator::interpolateLocalRotation(double deltaTime,
@@ -425,16 +452,21 @@ glm::dvec3 OrbitalNavigator::translateHorizontally(double deltaTime,
1.0;
// Get rotation in camera space
glm::dvec3 eulerAngles = glm::dvec3(
-_mouseStates.globalRotationMouseVelocity().y * deltaTime,
-_mouseStates.globalRotationMouseVelocity().x * deltaTime,
0) * speedScale;
glm::dquat rotationDiffCamSpace = glm::dquat(eulerAngles);
glm::dquat mouseRotationDiffCamSpace = glm::dquat(glm::dvec3(
-_mouseStates.globalRotationVelocity().y * deltaTime,
-_mouseStates.globalRotationVelocity().x * deltaTime,
0) * speedScale);
glm::dquat joystickRotationDiffCamSpace = glm::dquat(glm::dvec3(
-_joystickStates.globalRotationVelocity().y * deltaTime,
-_joystickStates.globalRotationVelocity().x * deltaTime,
0) * speedScale);
// Transform to world space
glm::dquat rotationDiffWorldSpace =
globalCameraRotation *
rotationDiffCamSpace *
joystickRotationDiffCamSpace *
mouseRotationDiffCamSpace *
glm::inverse(globalCameraRotation);
// Rotate and find the difference vector
@@ -501,8 +533,12 @@ glm::dvec3 OrbitalNavigator::translateVertically(
glm::dmat3(modelTransform) * centerToActualSurfaceModelSpace;
glm::dvec3 actualSurfaceToCamera = posDiff - centerToActualSurface;
const double totalVelocity =
_joystickStates.truckMovementVelocity().y +
_mouseStates.truckMovementVelocity().y;
return cameraPosition -
actualSurfaceToCamera * _mouseStates.truckMovementMouseVelocity().y * deltaTime;
actualSurfaceToCamera * totalVelocity * deltaTime;
}
glm::dquat OrbitalNavigator::rotateHorizontally(
@@ -518,12 +554,12 @@ glm::dquat OrbitalNavigator::rotateHorizontally(
glm::dvec3 directionFromSurfaceToCamera =
glm::normalize(glm::dmat3(modelTransform) * directionFromSurfaceToCameraModelSpace);
glm::dquat cameraRollRotation =
glm::angleAxis(
_mouseStates.globalRollMouseVelocity().x *
deltaTime, directionFromSurfaceToCamera
);
return cameraRollRotation * globalCameraRotation;
glm::dquat mouseCameraRollRotation = glm::angleAxis(
_mouseStates.globalRollVelocity().x * deltaTime +
_joystickStates.globalRollVelocity().x * deltaTime,
directionFromSurfaceToCamera
);
return mouseCameraRollRotation * globalCameraRotation;
}
glm::dvec3 OrbitalNavigator::pushToSurface(
@@ -597,4 +633,9 @@ SurfacePositionHandle OrbitalNavigator::calculateSurfacePositionHandle(
return posHandle;
}
JoystickCameraStates& OrbitalNavigator::joystickStates() {
return _joystickStates;
}
} // namespace openspace::interaction
+916
View File
@@ -0,0 +1,916 @@
/*****************************************************************************************
* *
* 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. *
****************************************************************************************/
#include <openspace/rendering/luaconsole.h>
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/wrapper/windowwrapper.h>
#include <openspace/network/parallelpeer.h>
#include <ghoul/filesystem/cachemanager.h>
#include <ghoul/filesystem/filesystem.h>
#include <ghoul/font/font.h>
#include <ghoul/font/fontmanager.h>
#include <ghoul/font/fontrenderer.h>
#include <ghoul/misc/clipboard.h>
#include <ghoul/opengl/ghoul_gl.h>
#include <ghoul/opengl/programobject.h>
#include <fstream>
#include <string>
namespace {
const char* HistoryFile = "ConsoleHistory";
const int NoAutoComplete = -1;
const int MaximumHistoryLength = 1000;
// A high number is chosen since we didn't have a version number before
// any small number might also be equal to the console history length
const uint64_t CurrentVersion = 0xFEEE'FEEE'0000'0001;
const openspace::Key CommandInputButton = openspace::Key::GraveAccent;
const char* FontName = "Console";
const float EntryFontSize = 14.0f;
const float HistoryFontSize = 11.0f;
// Additional space between the entry text and the history (in pixels)
const float SeparatorSpace = 30.f;
// Determines at which speed the console opens.
const float ConsoleOpenSpeed = 2.5;
// The number of characters to display after the cursor
// when horizontal scrolling is required.
const int NVisibleCharsAfterCursor = 5;
const static openspace::properties::Property::PropertyInfo VisibleInfo = {
"IsVisible",
"Is Visible",
"Determines whether the Lua console is shown on the screen or not. Toggling it "
"will fade the console in and out."
};
const static openspace::properties::Property::PropertyInfo RemoveScriptingInfo = {
"RemoteScripting",
"Remote scripting",
"Determines whether the entered commands will only be executed locally (if this "
"is disabled), or whether they will be send to connected remove instances."
};
const static openspace::properties::Property::PropertyInfo BackgroundColorInfo = {
"BackgroundColor",
"Background Color",
"Sets the background color of the console."
};
const static openspace::properties::Property::PropertyInfo HighlightColorInfo = {
"HighlightColor",
"Highlight Color",
"Sets the color of the lines below the console."
};
const static openspace::properties::Property::PropertyInfo SeparatorColorInfo = {
"SeparatorColor",
"Separator Color",
"Sets the color of the separator between the history part and the entry part of "
"the console."
};
const static openspace::properties::Property::PropertyInfo EntryTextColorInfo = {
"EntryTextColor",
"Entry Text Color",
"Sets the text color of the entry area of the console."
};
const static openspace::properties::Property::PropertyInfo HistoryTextColorInfo = {
"HistoryTextColor",
"History Text Color",
"Sets the text color of the history area of the console."
};
const static openspace::properties::Property::PropertyInfo HistoryLengthInfo = {
"HistoryLength",
"History Length",
"Determines the length of the history in number of lines."
};
} // namespace
namespace openspace {
LuaConsole::LuaConsole()
: properties::PropertyOwner({ "LuaConsole" })
, _isVisible(VisibleInfo, false)
, _remoteScripting(RemoveScriptingInfo, false)
, _backgroundColor(
BackgroundColorInfo,
glm::vec4(21.f / 255.f, 23.f / 255.f, 28.f / 255.f, 0.8f),
glm::vec4(0.f),
glm::vec4(1.f)
)
, _highlightColor(
HighlightColorInfo,
glm::vec4(1.f, 1.f, 1.f, 0.f),
glm::vec4(0.f),
glm::vec4(1.f)
)
, _separatorColor(
SeparatorColorInfo,
glm::vec4(0.4f, 0.4f, 0.4f, 0.f),
glm::vec4(0.f),
glm::vec4(1.f)
)
, _entryTextColor(
EntryTextColorInfo,
glm::vec4(1.f, 1.f, 1.f, 1.f),
glm::vec4(0.f),
glm::vec4(1.f)
)
, _historyTextColor(
HistoryTextColorInfo,
glm::vec4(1.0f, 1.0f, 1.0f, 0.65f),
glm::vec4(0.f),
glm::vec4(1.f)
)
, _historyLength(HistoryLengthInfo, 13, 0, 100)
, _inputPosition(0)
, _activeCommand(0)
, _autoCompleteInfo({NoAutoComplete, false, ""})
, _currentHeight(0.f)
, _targetHeight(0.f)
, _fullHeight(0.f)
{
addProperty(_isVisible);
addProperty(_remoteScripting);
addProperty(_historyLength);
_backgroundColor.setViewOption(properties::Property::ViewOptions::Color);
addProperty(_backgroundColor);
_highlightColor.setViewOption(properties::Property::ViewOptions::Color);
addProperty(_highlightColor);
_separatorColor.setViewOption(properties::Property::ViewOptions::Color);
addProperty(_separatorColor);
_entryTextColor.setViewOption(properties::Property::ViewOptions::Color);
addProperty(_entryTextColor);
_historyTextColor.setViewOption(properties::Property::ViewOptions::Color);
addProperty(_historyTextColor);
}
void LuaConsole::initialize() {
const std::string filename = FileSys.cacheManager()->cachedFilename(
HistoryFile,
"",
ghoul::filesystem::CacheManager::Persistent::Yes
);
if (FileSys.fileExists(filename)) {
std::ifstream file(filename, std::ios::binary | std::ios::in);
if (file.good()) {
// Read the number of commands from the history
uint64_t version;
file.read(reinterpret_cast<char*>(&version), sizeof(uint64_t));
if (version != CurrentVersion) {
LWARNINGC(
"LuaConsole",
fmt::format("Outdated console history version: {}", version)
);
}
else {
int64_t nCommands;
file.read(reinterpret_cast<char*>(&nCommands), sizeof(int64_t));
for (int64_t i = 0; i < nCommands; ++i) {
int64_t length;
file.read(reinterpret_cast<char*>(&length), sizeof(int64_t));
std::vector<char> tmp(length);
file.read(tmp.data(), length);
_commandsHistory.emplace_back(std::string(tmp.begin(), tmp.end()));
}
}
}
}
_commands = _commandsHistory;
_commands.push_back("");
_activeCommand = _commands.size() - 1;
_program = ghoul::opengl::ProgramObject::Build(
"Console",
absPath("${SHADERS}/luaconsole.vert"),
absPath("${SHADERS}/luaconsole.frag")
);
_uniformCache.res = _program->uniformLocation("res");
_uniformCache.color = _program->uniformLocation("color");
_uniformCache.height = _program->uniformLocation("height");
_uniformCache.ortho = _program->uniformLocation("ortho");
GLfloat data[] = {
0.f, 0.f,
1.f, 1.f,
0.f, 1.f,
0.f, 0.f,
1.f, 0.f,
1.f, 1.f
};
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
glGenBuffers(1, &_vbo);
glBindBuffer(GL_ARRAY_BUFFER, _vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(
0,
2,
GL_FLOAT,
GL_FALSE,
2 * sizeof(GLfloat),
nullptr
);
glBindVertexArray(0);
_font = OsEng.fontManager().font(
FontName,
EntryFontSize,
ghoul::fontrendering::FontManager::Outline::No
);
_historyFont = OsEng.fontManager().font(
FontName,
HistoryFontSize,
ghoul::fontrendering::FontManager::Outline::No
);
OsEng.parallelPeer().connectionEvent()->subscribe(
"luaConsole",
"statusChanged",
[this]() {
ParallelConnection::Status status = OsEng.parallelPeer().status();
parallelConnectionChanged(status);
}
);
}
void LuaConsole::deinitialize() {
const std::string filename = FileSys.cacheManager()->cachedFilename(
HistoryFile,
"",
ghoul::filesystem::CacheManager::Persistent::Yes
);
// We want to limit the command history to a realistic value, so that it doesn't
// grow without bounds
if (_commandsHistory.size() > MaximumHistoryLength) {
_commandsHistory = std::vector<std::string>(
_commandsHistory.end() - MaximumHistoryLength,
_commandsHistory.end()
);
}
std::ofstream file(filename, std::ios::binary);
if (file.good()) {
uint64_t version = CurrentVersion;
file.write(reinterpret_cast<const char*>(&version), sizeof(uint64_t));
int64_t nCommands = _commandsHistory.size();
file.write(reinterpret_cast<const char*>(&nCommands), sizeof(int64_t));
for (const std::string& s : _commandsHistory) {
int64_t length = s.length();
file.write(reinterpret_cast<const char*>(&length), sizeof(int64_t));
// We don't write the \0 at the end on purpose
file.write(s.c_str(), length);
}
}
_program = nullptr;
OsEng.parallelPeer().connectionEvent()->unsubscribe("luaConsole");
}
bool LuaConsole::keyboardCallback(Key key, KeyModifier modifier, KeyAction action) {
if (action != KeyAction::Press && action != KeyAction::Repeat) {
return false;
}
if (key == CommandInputButton) {
// Button left of 1 and above TAB
// How to deal with different keyboard languages? ---abock
if (_isVisible) {
if (_remoteScripting) {
_remoteScripting = false;
}
else {
_isVisible = false;
_commands.back() = "";
_inputPosition = 0;
}
}
else {
_isVisible = true;
if (OsEng.parallelPeer().status() == ParallelConnection::Status::Host) {
_remoteScripting = true;
}
}
return true;
}
if (!_isVisible) {
return false;
}
if (key == Key::Escape) {
_isVisible = false;
return true;
}
const bool modifierControl = (modifier == KeyModifier::Control);
const bool modifierShift = (modifier == KeyModifier::Shift);
// Paste from clipboard
if (modifierControl && (key == Key::V || key == Key::Y)) {
addToCommand(sanitizeInput(ghoul::clipboardText()));
return true;
}
// Copy to clipboard
if (modifierControl && key == Key::C) {
ghoul::setClipboardText(_commands.at(_activeCommand));
return true;
}
// Cut to clipboard
if (modifierControl && key == Key::X) {
ghoul::setClipboardText(_commands.at(_activeCommand));
_commands.at(_activeCommand).clear();
_inputPosition = 0;
}
// Cut part after cursor to clipboard ("Kill")
if (modifierControl && key == Key::K) {
auto here = _commands.at(_activeCommand).begin() + _inputPosition;
auto end = _commands.at(_activeCommand).end();
ghoul::setClipboardText(std::string(here, end));
_commands.at(_activeCommand).erase(here, end);
}
// Go to the previous character
if (key == Key::Left || (modifierControl && key == Key::B)) {
if (_inputPosition > 0) {
--_inputPosition;
}
return true;
}
// Go to the next character
if (key == Key::Right || (modifierControl && key == Key::F)) {
_inputPosition = std::min(
_inputPosition + 1,
_commands.at(_activeCommand).length()
);
return true;
}
// Go to previous command
if (key == Key::Up) {
if (_activeCommand > 0) {
--_activeCommand;
}
_inputPosition = _commands.at(_activeCommand).length();
return true;
}
// Go to next command (the last is empty)
if (key == Key::Down) {
if (_activeCommand < _commands.size() - 1) {
++_activeCommand;
}
_inputPosition = _commands.at(_activeCommand).length();
return true;
}
// Remove character before _inputPosition
if (key == Key::BackSpace) {
if (_inputPosition > 0) {
_commands.at(_activeCommand).erase(_inputPosition - 1, 1);
--_inputPosition;
}
return true;
}
// Remove character after _inputPosition
if (key == Key::Delete) {
if (_inputPosition <= _commands.at(_activeCommand).size()) {
_commands.at(_activeCommand).erase(_inputPosition, 1);
}
return true;
}
// Go to the beginning of command string
if (key == Key::Home || (modifierControl && key == Key::A)) {
_inputPosition = 0;
return true;
}
// Go to the end of command string
if (key == Key::End || (modifierControl && key == Key::E)) {
_inputPosition = _commands.at(_activeCommand).size();
return true;
}
if (key == Key::Enter || key == Key::KeypadEnter) {
std::string cmd = _commands.at(_activeCommand);
if (cmd != "") {
using RemoteScripting = scripting::ScriptEngine::RemoteScripting;
OsEng.scriptEngine().queueScript(
cmd,
_remoteScripting ? RemoteScripting::Yes : RemoteScripting::No
);
// Only add the current command to the history if it hasn't been
// executed before. We don't want two of the same commands in a row
if (_commandsHistory.empty() || (cmd != _commandsHistory.back())) {
_commandsHistory.push_back(_commands.at(_activeCommand));
}
}
// Some clean up after the execution of the command
_commands = _commandsHistory;
_commands.push_back("");
_activeCommand = _commands.size() - 1;
_inputPosition = 0;
return true;
}
if (key == Key::Tab) {
// We get a list of all the available commands and initially find the first
// command that starts with how much we typed sofar. We store the index so
// that in subsequent "tab" presses, we will discard previous commands. This
// implements the 'hop-over' behavior. As soon as another key is pressed,
// everything is set back to normal
// If the shift key is pressed, we decrement the current index so that we will
// find the value before the one that was previously found
if (_autoCompleteInfo.lastIndex != NoAutoComplete && modifierShift) {
_autoCompleteInfo.lastIndex -= 2;
}
std::vector<std::string> allCommands = OsEng.scriptEngine().allLuaFunctions();
std::sort(allCommands.begin(), allCommands.end());
std::string currentCommand = _commands.at(_activeCommand);
// Check if it is the first time the tab has been pressed. If so, we need to
// store the already entered command so that we can later start the search
// from there. We will overwrite the 'currentCommand' thus making the storage
// necessary
if (!_autoCompleteInfo.hasInitialValue) {
_autoCompleteInfo.initialValue = currentCommand;
_autoCompleteInfo.hasInitialValue = true;
}
for (int i = 0; i < static_cast<int>(allCommands.size()); ++i) {
const std::string& command = allCommands[i];
// Check if the command has enough length (we don't want crashes here)
// Then check if the iterator-command's start is equal to what we want
// then check if we need to skip the first found values as the user has
// pressed TAB repeatedly
size_t fullLength = _autoCompleteInfo.initialValue.length();
bool correctLength = command.length() >= fullLength;
std::string commandLowerCase;
std::transform(
command.begin(), command.end(),
std::back_inserter(commandLowerCase),
[](char v) { return static_cast<char>(tolower(v)); }
);
std::string initialValueLowerCase;
std::transform(
_autoCompleteInfo.initialValue.begin(),
_autoCompleteInfo.initialValue.end(),
std::back_inserter(initialValueLowerCase),
[](char v) { return static_cast<char>(tolower(v)); }
);
bool correctCommand =
commandLowerCase.substr(0, fullLength) == initialValueLowerCase;
if (correctLength && correctCommand && (i > _autoCompleteInfo.lastIndex)) {
// We found our index, so store it
_autoCompleteInfo.lastIndex = i;
// We only want to auto-complete until the next separator "."
size_t pos = command.find('.', fullLength);
if (pos == std::string::npos) {
// If we don't find a separator, we autocomplete until the end
// Set the found command as active command
_commands.at(_activeCommand) = command + "();";
// Set the cursor position to be between the brackets
_inputPosition = _commands.at(_activeCommand).size() - 2;
}
else {
// If we find a separator, we autocomplete until and including the
// separator unless the autocompletion would be the same that we
// already have (the case if there are multiple commands in the
// same group
std::string subCommand = command.substr(0, pos + 1);
if (subCommand == _commands.at(_activeCommand)) {
continue;
}
else {
_commands.at(_activeCommand) = command.substr(0, pos + 1);
_inputPosition = _commands.at(_activeCommand).length();
// We only want to remove the autocomplete info if we just
// entered the 'default' openspace namespace
if (command.substr(0, pos + 1) == "openspace.") {
_autoCompleteInfo = { NoAutoComplete, false, "" };
}
}
}
break;
}
}
return true;
}
else {
// If any other key is pressed, we want to remove our previous findings
// The special case for Shift is necessary as we want to allow Shift+TAB
if (!modifierShift) {
_autoCompleteInfo = { NoAutoComplete, false, "" };
}
}
// We want to ignore the function keys as they don't translate to text anyway
if (key >= Key::F1 && key <= Key::F25) {
return false;
}
// Do not consume modifier keys
switch (key) {
case Key::LeftShift:
case Key::RightShift:
case Key::LeftAlt:
case Key::RightAlt:
case Key::LeftControl:
case Key::RightControl:
return false;
default:
return true;
}
}
void LuaConsole::charCallback(unsigned int codepoint,
[[maybe_unused]] KeyModifier modifier)
{
if (!_isVisible) {
return;
}
if (codepoint == static_cast<unsigned int>(CommandInputButton)) {
return;
}
#ifndef WIN32
const bool modifierControl = (modifier == KeyModifier::Control);
const int codepoint_C = 99;
const int codepoint_V = 118;
if (modifierControl && (codepoint == codepoint_C || codepoint == codepoint_V)) {
return;
}
#endif
// Disallow all non ASCII characters for now
if (codepoint > 0x7f) {
return;
}
addToCommand(std::string(1, static_cast<const char>(codepoint)));
}
void LuaConsole::update() {
// Compute the height by simulating _historyFont number of lines and checking
// what the bounding box for that text would be.
using namespace ghoul::fontrendering;
const size_t nLines = std::min(
static_cast<size_t>(_historyLength),
_commandsHistory.size()
);
const auto bbox = FontRenderer::defaultRenderer().boundingBox(
*_historyFont,
std::string(nLines, '\n').c_str()
);
// Update the full height and the target height.
// Add the height of the entry line and space for a separator.
_fullHeight = (bbox.boundingBox.y + EntryFontSize + SeparatorSpace);
_targetHeight = _isVisible ? _fullHeight : 0;
// The first frame is going to be finished in approx 10 us, which causes a floating
// point overflow when computing dHeight
const double frametime = std::max(
OsEng.windowWrapper().deltaTime(),
1e-4
);
// Update the current height.
// The current height is the offset that is used to slide
// the console in from the top.
const glm::ivec2 res = OsEng.windowWrapper().currentWindowResolution();
const glm::vec2 dpiScaling = OsEng.windowWrapper().dpiScaling();
const double dHeight = (_targetHeight - _currentHeight) *
std::pow(0.98, 1.0 / (ConsoleOpenSpeed / dpiScaling.y * frametime));
_currentHeight += static_cast<float>(dHeight);
_currentHeight = std::max(0.0f, _currentHeight);
_currentHeight = std::min(static_cast<float>(res.y), _currentHeight);
}
void LuaConsole::render() {
using namespace ghoul::fontrendering;
// Don't render the console if it's collapsed.
if (_currentHeight < 1.0f) {
return;
}
if (_program->isDirty()) {
_program->rebuildFromFile();
_uniformCache.res = _program->uniformLocation("res");
_uniformCache.color = _program->uniformLocation("color");
_uniformCache.height = _program->uniformLocation("height");
_uniformCache.ortho = _program->uniformLocation("ortho");
}
const glm::vec2 dpiScaling = OsEng.windowWrapper().dpiScaling();
const glm::ivec2 res =
glm::vec2(OsEng.windowWrapper().currentWindowResolution()) / dpiScaling;
// Render background
glDisable(GL_CULL_FACE);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_DEPTH_TEST);
_program->activate();
_program->setUniform(_uniformCache.res, res);
_program->setUniform(_uniformCache.color, _backgroundColor);
_program->setUniform(_uniformCache.height, _currentHeight / res.y);
_program->setUniform(
_uniformCache.ortho,
glm::ortho(
0.f, static_cast<float>(res.x), 0.f, static_cast<float>(res.y)
)
);
// Draw the background color
glBindVertexArray(_vao);
glDrawArrays(GL_TRIANGLES, 0, 6);
// Draw the highlight lines above and below the background
_program->setUniform(_uniformCache.color, _highlightColor);
glDrawArrays(GL_LINES, 1, 4);
// Draw the separator between the current entry box and the history
_program->setUniform(_uniformCache.color, _separatorColor);
_program->setUniform(
_uniformCache.height,
_currentHeight / res.y - 2.5f * EntryFontSize / res.y
);
glDrawArrays(GL_LINES, 1, 2);
_program->deactivate();
glEnable(GL_CULL_FACE);
glEnable(GL_DEPTH_TEST);
// Render text on top of the background
glm::vec2 inputLocation = glm::vec2(
EntryFontSize / 2.f,
res.y - _currentHeight + EntryFontSize
);
// Render the current command
std::string currentCommand = _commands.at(_activeCommand);
// We chop off the beginning and end of the string until it fits on the screen (with
// a margin) this should be replaced as soon as the mono-spaced fonts work properly.
// Right now, every third character is a bit wider than the others
size_t nChoppedCharsBeginning = 0, nChoppedCharsEnd = 0;
const size_t inputPositionFromEnd = currentCommand.size() - _inputPosition;
while (true) {
using namespace ghoul::fontrendering;
// Compute the current width of the string and console prefix.
const float currentWidth = FontRenderer::defaultRenderer().boundingBox(
*_font,
"> %s",
currentCommand.c_str()
).boundingBox.x + inputLocation.x;
// Compute the overflow in pixels
const float overflow = currentWidth - res.x * 0.995f;
if (overflow <= 0.f) {
break;
}
// Since the overflow is positive, at least one character needs to be removed.
const size_t nCharsOverflow = static_cast<size_t>(std::min(
std::max(1.f, overflow / _font->glyph('m')->width()),
static_cast<float>(currentCommand.size())
));
// Do not hide the cursor and `NVisibleCharsAfterCursor` characters in the end.
const size_t maxAdditionalCharsToChopEnd = std::max(
0,
static_cast<int>(inputPositionFromEnd) -
(NVisibleCharsAfterCursor + 1) -
static_cast<int>(nChoppedCharsEnd)
);
// Do not hide the cursor in the beginning.
const size_t maxAdditionalCharsToChopBeginning = std::max(
0,
static_cast<int>(_inputPosition) - 1 -
static_cast<int>(nChoppedCharsBeginning)
);
// Prioritize chopping in the end of the string.
const size_t nCharsToChopEnd = std::min(
nCharsOverflow,
maxAdditionalCharsToChopEnd
);
const size_t nCharsToChopBeginning = std::min(
nCharsOverflow - nCharsToChopEnd,
maxAdditionalCharsToChopBeginning
);
nChoppedCharsBeginning += nCharsToChopBeginning;
nChoppedCharsEnd += nCharsToChopEnd;
const size_t displayLength =
_commands.at(_activeCommand).size() -
nChoppedCharsBeginning - nChoppedCharsEnd;
currentCommand = _commands.at(_activeCommand).substr(
nChoppedCharsBeginning,
displayLength
);
}
RenderFontCr(
*_font,
inputLocation,
_entryTextColor,
"> %s",
currentCommand.c_str()
);
// Just offset the ^ marker slightly for a nicer look
inputLocation.y += 3 * dpiScaling.y;
// Render the ^ marker below the text to show where the current entry point is
RenderFont(
*_font,
inputLocation,
_entryTextColor,
(std::string(_inputPosition - nChoppedCharsBeginning + 2, ' ') + "^").c_str()
);
glm::vec2 historyInputLocation = glm::vec2(
HistoryFontSize / 2.f,
res.y - HistoryFontSize * 1.5f + _fullHeight - _currentHeight
);
// @CPP: Replace with array_view
std::vector<std::string> commandSubset;
if (_commandsHistory.size() < static_cast<size_t>(_historyLength)) {
commandSubset = _commandsHistory;
}
else {
commandSubset = std::vector<std::string>(
_commandsHistory.end() - _historyLength,
_commandsHistory.end()
);
}
for (const std::string& cmd : commandSubset) {
RenderFontCr(
*_historyFont,
historyInputLocation,
_historyTextColor,
"%s",
cmd.c_str()
);
}
// Computes the location for right justified text on the same y height as the entry
auto locationForRightJustifiedText = [&](const std::string& text) {
using namespace ghoul::fontrendering;
const glm::vec2 loc = glm::vec2(
EntryFontSize / 2.f,
res.y - _currentHeight + EntryFontSize
);
const auto bbox = FontRenderer::defaultRenderer().boundingBox(
*_font, text.c_str()
);
return glm::vec2(
loc.x + res.x - bbox.boundingBox.x - 10.f,
loc.y
);
};
if (_remoteScripting) {
const glm::vec4 red(1, 0, 0, 1);
ParallelConnection::Status status = OsEng.parallelPeer().status();
const int nClients =
status != ParallelConnection::Status::Disconnected ?
OsEng.parallelPeer().nConnections() - 1 :
0;
const std::string nClientsText =
nClients == 1 ?
"Broadcasting script to 1 client" :
"Broadcasting script to " + std::to_string(nClients) + " clients";
const glm::vec2 loc = locationForRightJustifiedText(nClientsText);
RenderFont(*_font, loc, red, nClientsText.c_str());
} else if (OsEng.parallelPeer().isHost()) {
const glm::vec4 lightBlue(0.4, 0.4, 1, 1);
const std::string localExecutionText = "Local script execution";
const glm::vec2 loc = locationForRightJustifiedText(localExecutionText);
RenderFont(*_font, loc, lightBlue, localExecutionText.c_str());
}
}
float LuaConsole::currentHeight() const {
return _currentHeight;
}
void LuaConsole::addToCommand(std::string c) {
const size_t length = c.length();
_commands.at(_activeCommand).insert(_inputPosition, std::move(c));
_inputPosition += length;
}
std::string LuaConsole::sanitizeInput(std::string str) {
// Remove carriage returns.
str.erase(std::remove(str.begin(), str.end(), '\r'), str.end());
// Replace newlines with spaces.
const std::function<char(char)> replace = [](char c) {
return c == '\n' ? ' ' : c;
};
std::transform(str.begin(), str.end(), str.begin(), replace);
return str;
}
void LuaConsole::parallelConnectionChanged(const ParallelConnection::Status& status) {
_remoteScripting = (status == ParallelConnection::Status::Host);
}
} // namespace openspace
+2 -2
View File
@@ -31,15 +31,15 @@
#include <openspace/engine/openspaceengine.h>
#include <openspace/engine/wrapper/windowwrapper.h>
#include <openspace/interaction/navigationhandler.h>
#include <openspace/interaction/luaconsole.h>
#include <openspace/mission/missionmanager.h>
#include <openspace/performance/performancemanager.h>
#include <openspace/performance/performancemeasurement.h>
#include <openspace/rendering/abufferrenderer.h>
#include <openspace/rendering/dashboard.h>
#include <openspace/rendering/dashboarditem.h>
#include <openspace/rendering/framebufferrenderer.h>
#include <openspace/rendering/deferredcastermanager.h>
#include <openspace/rendering/framebufferrenderer.h>
#include <openspace/rendering/luaconsole.h>
#include <openspace/rendering/raycastermanager.h>
#include <openspace/rendering/renderer.h>
#include <openspace/rendering/screenspacerenderable.h>