Merge remote-tracking branch 'origin/master' into feature/skybrowser

This commit is contained in:
Ylva Selling
2022-04-29 18:03:06 -04:00
40 changed files with 591 additions and 161 deletions

View File

@@ -207,6 +207,71 @@ LONG WINAPI generateMiniDump(EXCEPTION_POINTERS* exceptionPointers) {
}
#endif // WIN32
void checkJoystickStatus() {
using namespace interaction;
for (int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_LAST; ++i) {
ZoneScopedN("Joystick state");
JoystickInputState& state = global::joystickInputStates->at(i);
int present = glfwJoystickPresent(i);
if (present == GLFW_FALSE) {
state.isConnected = false;
continue;
}
if (!state.isConnected) {
// Joystick was added
state.isConnected = true;
state.name = glfwGetJoystickName(i);
std::fill(state.axes.begin(), state.axes.end(), 0.f);
std::fill(state.buttons.begin(), state.buttons.end(), JoystickAction::Idle);
// Check axes and buttons
glfwGetJoystickAxes(i, &state.nAxes);
glfwGetJoystickButtons(i, &state.nButtons);
}
const float* axes = glfwGetJoystickAxes(i, &state.nAxes);
state.axes.resize(state.nAxes);
std::memcpy(state.axes.data(), axes, state.nAxes * sizeof(float));
const unsigned char* buttons = glfwGetJoystickButtons(i, &state.nButtons);
state.buttons.resize(state.nButtons);
for (int j = 0; j < state.nButtons; ++j) {
const 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;
}
}
}
}
}
//
// Init function
//
@@ -319,6 +384,9 @@ void mainInitFunc(GLFWwindow*) {
#endif // OPENSPACE_HAS_SPOUT
}
// Query joystick status, those connected before start up
checkJoystickStatus();
LTRACE("main::mainInitFunc(end)");
}
@@ -336,87 +404,8 @@ void mainPreSyncFunc() {
Engine::instance().terminate();
}
// Query joystick status
using namespace interaction;
for (int i = GLFW_JOYSTICK_1; i <= GLFW_JOYSTICK_LAST; ++i) {
ZoneScopedN("Joystick state");
JoystickInputState& state = global::joystickInputStates->at(i);
int present = glfwJoystickPresent(i);
if (present == GLFW_FALSE) {
state.isConnected = false;
continue;
}
if (!state.isConnected) {
// Joystick was added
state.isConnected = true;
state.name = glfwGetJoystickName(i);
std::fill(state.axes.begin(), state.axes.end(), 0.f);
std::fill(state.buttons.begin(), state.buttons.end(), JoystickAction::Idle);
// Check axes and buttons
glfwGetJoystickAxes(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
));
}
glfwGetJoystickButtons(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
));
}
}
const float* axes = glfwGetJoystickAxes(i, &state.nAxes);
if (state.nAxes > JoystickInputState::MaxAxes) {
state.nAxes = JoystickInputState::MaxAxes;
}
std::memcpy(state.axes.data(), axes, state.nAxes * sizeof(float));
const unsigned char* buttons = glfwGetJoystickButtons(i, &state.nButtons);
if (state.nButtons > JoystickInputState::MaxButtons) {
state.nButtons = JoystickInputState::MaxButtons;
}
for (int j = 0; j < state.nButtons; ++j) {
const 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;
}
}
}
}
// Query joystick status, those connected at run time
checkJoystickStatus();
LTRACE("main::mainPreSyncFunc(end)");
}

View File

@@ -25,8 +25,8 @@
-- First - Name of the joystick that should be bound
-- Second - Which axis should be bound of this joystick
-- Third - The property uri
-- Fourth - (optional) The smallest value that you wnat to allow this property on the joystick
-- Fifth - (optional) The largest value that you wnat to allow this property on the joystick
-- Fourth - (optional) The smallest value that you want to allow this property on the joystick
-- Fifth - (optional) The largest value that you want to allow this property on the joystick
-- Sixth - (optional) Determines whether the axis should be inverted
-- Seventh - (optional) Should this property change be sent to other connected remote sessions

View File

@@ -1,6 +1,6 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://asgard.sci.utah.edu/Earth/Bmng/tile/${z}/${y}/${x}</ServerUrl>
<ServerUrl>http://openspace.sci.utah.edu/Earth/Bmng/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>

View File

@@ -1,6 +1,6 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://asgard.sci.utah.edu/Earth/Gebco/tile/${z}/${y}/${x}</ServerUrl>
<ServerUrl>http://openspace.sci.utah.edu/Earth/Gebco/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>

View File

@@ -1,6 +1,6 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://asgard.sci.utah.edu/Moon/ClemUvvis/tile/${z}/${y}/${x}</ServerUrl>
<ServerUrl>http://openspace.sci.utah.edu/Moon/ClemUvvis/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>

View File

@@ -1,6 +1,6 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://asgard.sci.utah.edu/Moon/Kaguya/tile/${z}/${y}/${x}</ServerUrl>
<ServerUrl>http://openspace.sci.utah.edu/Moon/Kaguya/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>

View File

@@ -1,6 +1,6 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://asgard.sci.utah.edu/Moon/LolaClrShade/tile/${z}/${y}/${x}</ServerUrl>
<ServerUrl>http://openspace.sci.utah.edu/Moon/LolaClrShade/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>

View File

@@ -1,6 +1,6 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://asgard.sci.utah.edu/Moon/LolaShade/tile/${z}/${y}/${x}</ServerUrl>
<ServerUrl>http://openspace.sci.utah.edu/Moon/LolaShade/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>

View File

@@ -1,6 +1,6 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://asgard.sci.utah.edu/Moon/UvvisHybrid/tile/${z}/${y}/${x}</ServerUrl>
<ServerUrl>http://openspace.sci.utah.edu/Moon/UvvisHybrid/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>

View File

@@ -1,6 +1,6 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://asgard.sci.utah.edu/Moon/Wac/tile/${z}/${y}/${x}</ServerUrl>
<ServerUrl>http://openspace.sci.utah.edu/Moon/Wac/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>

View File

@@ -1,6 +1,6 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://asgard.sci.utah.edu/Moon/LolaDem/tile/${z}/${y}/${x}</ServerUrl>
<ServerUrl>http://openspace.sci.utah.edu/Moon/LolaDem/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>

View File

@@ -1,6 +1,6 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://asgard.sci.utah.edu/Mars/CTX/tile/${z}/${y}/${x}</ServerUrl>
<ServerUrl>http://openspace.sci.utah.edu/Mars/CTX/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>

View File

@@ -1,6 +1,6 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://asgard.sci.utah.edu/Mars/MolaPseudoColor/tile/${z}/${y}/${x}</ServerUrl>
<ServerUrl>http://openspace.sci.utah.edu/Mars/MolaPseudoColor/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>

View File

@@ -1,6 +1,6 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://asgard.sci.utah.edu/Mars/ThemisIRDay/tile/${z}/${y}/${x}</ServerUrl>
<ServerUrl>http://openspace.sci.utah.edu/Mars/ThemisIRDay/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>

View File

@@ -1,6 +1,6 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://asgard.sci.utah.edu/Mars/ThemisIRNight/tile/${z}/${y}/${x}</ServerUrl>
<ServerUrl>http://openspace.sci.utah.edu/Mars/ThemisIRNight/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>

View File

@@ -1,6 +1,6 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://asgard.sci.utah.edu/Mars/Mdim/tile/${z}/${y}/${x}</ServerUrl>
<ServerUrl>http://openspace.sci.utah.edu/Mars/Mdim/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>

View File

@@ -1,6 +1,6 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://asgard.sci.utah.edu/Mars/MolaElevation/tile/${z}/${y}/${x}</ServerUrl>
<ServerUrl>http://openspace.sci.utah.edu/Mars/MolaElevation/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>

View File

@@ -1,6 +1,6 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://asgard.sci.utah.edu/Mercury/MessengerMdis/tile/${z}/${y}/${x}</ServerUrl>
<ServerUrl>http://openspace.sci.utah.edu/Mercury/MessengerMdis/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>

View File

@@ -1,6 +1,6 @@
<GDAL_WMS>
<Service name="TMS">
<ServerUrl>http://asgard.sci.utah.edu/Mercury/MessengerMosaic/tile/${z}/${y}/${x}</ServerUrl>
<ServerUrl>http://openspace.sci.utah.edu/Mercury/MessengerMosaic/tile/${z}/${y}/${x}</ServerUrl>
</Service>
<DataWindow>
<UpperLeftX>-180.0</UpperLeftX>

View File

@@ -0,0 +1,72 @@
local propertyHelper = asset.require("../property_helper")
local joystickHelper = asset.require("./joystick_helper")
local initializeAll = false
-- Add the asset cooresponding to the joystick name
local function addJoystickAsset(joystick)
if joystick == "Wireless Controller" then
openspace.asset.add("./util/joysticks/ps4")
elseif joystick == "Xbox Controller" then
openspace.asset.add("./util/joysticks/xbox")
elseif joystick == "Wireless Xbox Controller" then
openspace.asset.add("./util/joysticks/xbox-wireless")
elseif joystick == "SpaceNavigator" then
openspace.asset.add("./util/joysticks/space-mouse-compact")
elseif joystick == "SpaceMouse Enterprise" then
openspace.asset.add("./util/joysticks/space-mouse-enterprise")
elseif joystick == "3Dconnexion Universal Receiver" then
openspace.printWarning("SpaceMouse in wireless mode cannot be automatically detected and added. Please add the matching asset file manually.")
else
openspace.printWarning("Could not find a matching asset for joystick: " .. joystick)
end
end
asset.onInitialize(function()
local rawJoysticks = openspace.navigation.listAllJoysticks()
local numJoysticks = #rawJoysticks
local joystick = ""
-- Remove the SpaceMouse emulator if it exists
local joysticks = {}
for _, joyStickName in ipairs(rawJoysticks) do
if joyStickName == "3Dconnexion KMJ Emulator" then
numJoysticks = numJoysticks - 1
else
table.insert(joysticks, joyStickName)
end
end
if numJoysticks == 0 then
openspace.printWarning("Could not find any connected joysticks")
elseif numJoysticks == 1 then
addJoystickAsset(joysticks[1])
elseif numJoysticks > 1 and initializeAll then
for _, joyStickName in ipairs(joysticks) do
addJoystickAsset(joyStickName)
end
else
openspace.printWarning("Cannot auto detect and add several joysticks")
end
end)
asset.onDeinitialize(function()
if openspace.asset.isLoaded("./util/joysticks/ps4") then
openspace.asset.remove("./util/joysticks/ps4")
end
if openspace.asset.isLoaded("./util/joysticks/xbox") then
openspace.asset.remove("./util/joysticks/xbox")
end
if openspace.asset.isLoaded("./util/joysticks/xbox-wireless") then
openspace.asset.remove("./util/joysticks/xbox-wireless")
end
if openspace.asset.isLoaded("./util/joysticks/space-mouse-compact") then
openspace.asset.remove("./util/joysticks/space-mouse-compact")
end
if openspace.asset.isLoaded("./util/joysticks/space-mouse-enterprise") then
openspace.asset.remove("./util/joysticks/space-mouse-enterprise")
end
end)

View File

@@ -63,8 +63,27 @@ local unbindRoll = function(name, axis)
]]
end
-- Function that will find the first connected joystick with a name that matches one of
-- the given possible names
local findJoystick = function(possibleNames)
-- Will only catch the joysticks that are connected before start up
local joysticks = openspace.navigation.listAllJoysticks()
for _, joyStickName in ipairs(joysticks) do
for _, name in ipairs(possibleNames) do
if joyStickName == name then
return name
end
end
end
return nil
end
asset.export("bindLocalRoll", bindLocalRoll)
asset.export("bindGlobalRoll", bindGlobalRoll)
asset.export("permaBindLocalRoll", permaBindLocalRoll)
asset.export("permaBindGlobalRoll", permaBindGlobalRoll)
asset.export("unbindRoll", unbindRoll)
asset.export("findJoystick", findJoystick)

View File

@@ -52,12 +52,14 @@ asset.onInitialize(function()
local controller = PS4Controller;
local name = "Wireless Controller";
openspace.navigation.setAxisDeadZone(name, controller.LeftThumbStick[1], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.LeftThumbStick[2], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.RightThumbStick[1], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.RightThumbStick[2], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.L2, 0.05)
openspace.navigation.setAxisDeadZone(name, controller.R2, 0.05)
local deadzoneJoysticks = 0.15
local deadzoneTriggers = 0.05
openspace.navigation.setAxisDeadZone(name, controller.LeftThumbStick[1], deadzoneJoysticks)
openspace.navigation.setAxisDeadZone(name, controller.LeftThumbStick[2], deadzoneJoysticks)
openspace.navigation.setAxisDeadZone(name, controller.RightThumbStick[1], deadzoneJoysticks)
openspace.navigation.setAxisDeadZone(name, controller.RightThumbStick[2], deadzoneJoysticks)
openspace.navigation.setAxisDeadZone(name, controller.L2, deadzoneTriggers)
openspace.navigation.setAxisDeadZone(name, controller.R2, deadzoneTriggers)
openspace.navigation.bindJoystickAxis(name, controller.LeftThumbStick[1], "Orbit X");
openspace.navigation.bindJoystickAxis(name, controller.LeftThumbStick[2], "Orbit Y", true);
@@ -116,9 +118,9 @@ asset.onInitialize(function()
name,
controller.Square,
[[
"openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.Aim", "");
"openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.Anchor", "Earth");
"openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.RetargetAnchor", nil);
openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.Aim", "");
openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.Anchor", "Earth");
openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.RetargetAnchor", nil);
]],
"Switch target to Earth"
)

View File

@@ -21,27 +21,28 @@ local joystickHelper = asset.require("./joystick_helper")
-- The axis values can either go back to 0 when the joystick is released or it can
-- stay at the value it was before the joystick was released.
-- The latter is called a sticky axis, when the values don't go back to 0.
-- This version of the SpaceMouse is NOT Sticky.
-- This version of the SpaceMouse IS Sticky.
-- Seventh parameter is the sensitivity for the axis
local SpaceMouse = {
Push = {0, 1, 2}, -- left/right, back/forth, up/down
Twist = {5}, -- left/right
Tilt = {4, 3}, -- left/right, back/forth
LeftButton = 0,
RightButton = 1
}
asset.onInitialize(function()
local controller = SpaceMouse;
local name = "SpaceNavigator";
local name = "3Dconnexion Universal Receiver";
openspace.navigation.bindJoystickAxis(name, controller.Push[1], "Orbit X");
openspace.navigation.bindJoystickAxis(name, controller.Push[2], "Orbit Y");
openspace.navigation.bindJoystickAxis(name, controller.Twist[1], "Pan X", true);
openspace.navigation.bindJoystickAxis(name, controller.Tilt[2], "Pan Y");
openspace.navigation.bindJoystickAxis(name, controller.Push[3], "Zoom");
openspace.navigation.bindJoystickAxis(name, controller.Tilt[1], "LocalRoll X");
openspace.navigation.bindJoystickAxis(name, controller.Push[1], "Orbit X", false, "JoystickLike", true, 40.0);
openspace.navigation.bindJoystickAxis(name, controller.Push[2], "Orbit Y", false, "JoystickLike", true, 40.0);
openspace.navigation.bindJoystickAxis(name, controller.Twist[1], "Pan X", true, "JoystickLike", true, 40.0);
openspace.navigation.bindJoystickAxis(name, controller.Tilt[2], "Pan Y", false, "JoystickLike", true, 35.0);
openspace.navigation.bindJoystickAxis(name, controller.Push[3], "Zoom", false, "JoystickLike", true, 40.0);
openspace.navigation.bindJoystickAxis(name, controller.Tilt[1], "LocalRoll X", false, "JoystickLike", true, 35.0);
openspace.navigation.bindJoystickButton(
name,

View File

@@ -28,6 +28,7 @@ local SpaceMouse = {
Push = {0, 1, 2}, -- left/right, back/forth, up/down
Twist = {5}, -- left/right
Tilt = {4, 3}, -- left/right, back/forth
LeftButton = 0,
RightButton = 1
}

View File

@@ -0,0 +1,54 @@
local propertyHelper = asset.require("../property_helper")
local joystickHelper = asset.require("./joystick_helper")
-- Allowed values for the third parameter of bindJoystickAxis:
-- "None"
-- "Orbit X"
-- "Orbit Y"
-- "Zoom" -- both in and out
-- "Zoom In"
-- "Zoom Out"
-- "LocalRoll X"
-- "LocalRoll Y"
-- "GlobalRoll X"
-- "GlobalRoll Y"
-- "Pan X"
-- "Pan Y"
-- Fourth parameter determines whether the axis should be inverted
-- Fifth parameter determines whether the axis behaves like a joystick or a Trigger.
-- Allowed values are "JoystickLike" and "TriggerLike", the first one is the default
-- Sixth parameters determins if the axis should be "Sticky" or not.
-- The axis values can either go back to 0 when the joystick is released or it can
-- stay at the value it was before the joystick was released.
-- The latter is called a sticky axis, when the values don't go back to 0.
-- This version of the SpaceMouse is NOT Sticky.
-- Seventh parameter is the sensitivity for the axis
local SpaceMouse = {
Push = {0, 1, 2}, -- left/right, back/forth, up/down
Twist = {5}, -- left/right
Tilt = {4, 3}, -- left/right, back/forth
-- Buttons on the Enterprise version of the SpaceMouse is not detectable, use regular
-- keybindings instead, for more information see our wiki page.
}
asset.onInitialize(function()
local controller = SpaceMouse;
local name = "3Dconnexion Universal Receiver";
local deadzone = 0.15
openspace.navigation.setAxisDeadZone(name, controller.Push[1], deadzone)
openspace.navigation.setAxisDeadZone(name, controller.Push[2], deadzone)
openspace.navigation.setAxisDeadZone(name, controller.Twist[1], deadzone)
openspace.navigation.setAxisDeadZone(name, controller.Tilt[2], deadzone)
openspace.navigation.setAxisDeadZone(name, controller.Push[3], deadzone)
openspace.navigation.setAxisDeadZone(name, controller.Tilt[1], deadzone)
openspace.navigation.bindJoystickAxis(name, controller.Push[1], "Orbit X");
openspace.navigation.bindJoystickAxis(name, controller.Push[2], "Orbit Y");
openspace.navigation.bindJoystickAxis(name, controller.Twist[1], "Pan X", true);
openspace.navigation.bindJoystickAxis(name, controller.Tilt[2], "Pan Y");
openspace.navigation.bindJoystickAxis(name, controller.Push[3], "Zoom");
openspace.navigation.bindJoystickAxis(name, controller.Tilt[1], "LocalRoll X");
end)

View File

@@ -0,0 +1,54 @@
local propertyHelper = asset.require("../property_helper")
local joystickHelper = asset.require("./joystick_helper")
-- Allowed values for the third parameter of bindJoystickAxis:
-- "None"
-- "Orbit X"
-- "Orbit Y"
-- "Zoom" -- both in and out
-- "Zoom In"
-- "Zoom Out"
-- "LocalRoll X"
-- "LocalRoll Y"
-- "GlobalRoll X"
-- "GlobalRoll Y"
-- "Pan X"
-- "Pan Y"
-- Fourth parameter determines whether the axis should be inverted
-- Fifth parameter determines whether the axis behaves like a joystick or a Trigger.
-- Allowed values are "JoystickLike" and "TriggerLike", the first one is the default
-- Sixth parameters determins if the axis should be "Sticky" or not.
-- The axis values can either go back to 0 when the joystick is released or it can
-- stay at the value it was before the joystick was released.
-- The latter is called a sticky axis, when the values don't go back to 0.
-- This version of the SpaceMouse is NOT Sticky.
-- Seventh parameter is the sensitivity for the axis
local SpaceMouse = {
Push = {0, 1, 2}, -- left/right, back/forth, up/down
Twist = {5}, -- left/right
Tilt = {4, 3}, -- left/right, back/forth
-- Buttons on the Enterprise version of the SpaceMouse is not detectable, use regular
-- keybindings instead, for more information see our wiki page.
}
asset.onInitialize(function()
local controller = SpaceMouse;
local name = "SpaceMouse Enterprise";
local deadzone = 0.15
openspace.navigation.setAxisDeadZone(name, controller.Push[1], deadzone)
openspace.navigation.setAxisDeadZone(name, controller.Push[2], deadzone)
openspace.navigation.setAxisDeadZone(name, controller.Twist[1], deadzone)
openspace.navigation.setAxisDeadZone(name, controller.Tilt[2], deadzone)
openspace.navigation.setAxisDeadZone(name, controller.Push[3], deadzone)
openspace.navigation.setAxisDeadZone(name, controller.Tilt[1], deadzone)
openspace.navigation.bindJoystickAxis(name, controller.Push[1], "Orbit X");
openspace.navigation.bindJoystickAxis(name, controller.Push[2], "Orbit Y");
openspace.navigation.bindJoystickAxis(name, controller.Twist[1], "Pan X", true);
openspace.navigation.bindJoystickAxis(name, controller.Tilt[2], "Pan Y");
openspace.navigation.bindJoystickAxis(name, controller.Push[3], "Zoom");
openspace.navigation.bindJoystickAxis(name, controller.Tilt[1], "LocalRoll X");
end)

View File

@@ -0,0 +1,135 @@
local propertyHelper = asset.require("../property_helper")
local joystickHelper = asset.require("./joystick_helper")
-- Allowed values for the third parameter of bindJoystickAxis:
-- "None"
-- "Orbit X"
-- "Orbit Y"
-- "Zoom" -- both in and out
-- "Zoom In"
-- "Zoom Out"
-- "LocalRoll X"
-- "LocalRoll Y"
-- "GlobalRoll X"
-- "GlobalRoll Y"
-- "Pan X"
-- "Pan Y"
-- Fourth parameter determines whether the axis should be inverted
-- Fifth parameter determines whether the axis behaves like a joystick or a Trigger.
-- Allowed values are "JoystickLike" and "TriggerLike", the first one is the default
-- Sixth parameters determins if the axis should be "Sticky" or not.
-- The axis values can either go back to 0 when the joystick is released or it can
-- stay at the value it was before the joystick was released.
-- The latter is called a sticky axis, when the values don't go back to 0.
-- Seventh parameter is the sensitivity for the axis
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,
LeftStickButton = 8,
RightStickButton = 9,
DPad = {
Up = 10,
Right = 11,
Down = 12,
Left = 13
}
}
asset.onInitialize(function()
local controller = XBoxController;
local name = "Wireless Xbox Controller";
local deadzoneJoysticks = 0.15
local deadzoneTriggers = 0.05
openspace.navigation.setAxisDeadZone(name, controller.LeftThumbStick[1], deadzoneJoysticks)
openspace.navigation.setAxisDeadZone(name, controller.LeftThumbStick[2], deadzoneJoysticks)
openspace.navigation.setAxisDeadZone(name, controller.RightThumbStick[1], deadzoneJoysticks)
openspace.navigation.setAxisDeadZone(name, controller.RightThumbStick[2], deadzoneJoysticks)
openspace.navigation.setAxisDeadZone(name, controller.LeftTrigger, deadzoneTriggers)
openspace.navigation.setAxisDeadZone(name, controller.RightTrigger, deadzoneTriggers)
openspace.navigation.bindJoystickAxis(name, controller.LeftThumbStick[1], "Orbit X");
openspace.navigation.bindJoystickAxis(name, controller.LeftThumbStick[2], "Orbit Y", true);
openspace.navigation.bindJoystickAxis(name, controller.RightThumbStick[1], "Pan X", true);
openspace.navigation.bindJoystickAxis(name, controller.RightThumbStick[2], "Pan Y", true);
openspace.navigation.bindJoystickAxis(name, controller.LeftTrigger, "Zoom Out", false, "TriggerLike");
openspace.navigation.bindJoystickAxis(name, controller.RightTrigger, "Zoom In", false, "TriggerLike");
openspace.navigation.bindJoystickButton(
name,
controller.LB,
joystickHelper.bindLocalRoll(name, controller.RightThumbStick[1]),
"Switch to local roll mode"
)
openspace.navigation.bindJoystickButton(
name,
controller.LB,
joystickHelper.unbindRoll(name, controller.RightThumbStick[1]),
"Switch back to normal mode",
"Release"
)
openspace.navigation.bindJoystickButton(
name,
controller.RB,
joystickHelper.bindGlobalRoll(name, controller.RightThumbStick[1]),
"Switch to global roll mode"
)
openspace.navigation.bindJoystickButton(
name,
controller.RB,
joystickHelper.unbindRoll(name, controller.RightThumbStick[1]),
"Switch back to normal mode",
"Release"
)
openspace.navigation.bindJoystickButton(
name,
controller.A,
propertyHelper.invert("NavigationHandler.OrbitalNavigator.Friction.ZoomFriction"),
"Toggle zoom friction"
)
openspace.navigation.bindJoystickButton(
name,
controller.B,
propertyHelper.invert("NavigationHandler.OrbitalNavigator.Friction.RotationalFriction"),
"Toggle rotational friction"
)
openspace.navigation.bindJoystickButton(
name,
controller.DPad.Left,
propertyHelper.invert("NavigationHandler.OrbitalNavigator.Friction.RollFriction"),
"Toggle roll friction"
)
openspace.navigation.bindJoystickButton(
name,
controller.X,
[[
openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.Aim", "");
openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.Anchor", "Earth");
openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.RetargetAnchor", nil);
]],
"Switch target to Earth"
)
openspace.navigation.bindJoystickButton(
name,
controller.Y,
[[
openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.Aim", "");
openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.Anchor", "Mars");
openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.RetargetAnchor", nil);
]],
"Switch target to Mars"
)
end)

View File

@@ -50,12 +50,14 @@ asset.onInitialize(function()
local controller = XBoxController;
local name = "Xbox Controller";
openspace.navigation.setAxisDeadZone(name, controller.LeftThumbStick[1], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.LeftThumbStick[2], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.RightThumbStick[1], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.RightThumbStick[2], 0.15)
openspace.navigation.setAxisDeadZone(name, controller.LeftTrigger, 0.05)
openspace.navigation.setAxisDeadZone(name, controller.RightTrigger, 0.05)
local deadzoneJoysticks = 0.15
local deadzoneTriggers = 0.05
openspace.navigation.setAxisDeadZone(name, controller.LeftThumbStick[1], deadzoneJoysticks)
openspace.navigation.setAxisDeadZone(name, controller.LeftThumbStick[2], deadzoneJoysticks)
openspace.navigation.setAxisDeadZone(name, controller.RightThumbStick[1], deadzoneJoysticks)
openspace.navigation.setAxisDeadZone(name, controller.RightThumbStick[2], deadzoneJoysticks)
openspace.navigation.setAxisDeadZone(name, controller.LeftTrigger, deadzoneTriggers)
openspace.navigation.setAxisDeadZone(name, controller.RightTrigger, deadzoneTriggers)
openspace.navigation.bindJoystickAxis(name, controller.LeftThumbStick[1], "Orbit X");
openspace.navigation.bindJoystickAxis(name, controller.LeftThumbStick[2], "Orbit Y", true);
@@ -114,9 +116,9 @@ asset.onInitialize(function()
name,
controller.X,
[[
"openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.Aim", "");
"openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.Anchor", "Earth");
"openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.RetargetAnchor", nil);
openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.Aim", "");
openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.Anchor", "Earth");
openspace.setPropertyValueSingle("NavigationHandler.OrbitalNavigator.RetargetAnchor", nil);
]],
"Switch target to Earth"
)

View File

@@ -3,7 +3,7 @@ asset.require("./static_server")
local guiCustomization = asset.require("customization/gui")
-- Select which commit hashes to use for the frontend and backend
local frontendHash = "caac0fabfd7e8b8060c346eb2670cdeaaa585336"
local frontendHash = "ab0b74ceca72789b31fd2ccf9cc8a1f1cddbea26"
local dataProvider = "data.openspaceproject.com/files/webgui"
local frontend = asset.syncedResource({

View File

@@ -115,15 +115,13 @@ private:
struct JoystickCameraState {
std::string joystickName;
// 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;
// We use a vector 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
std::vector<AxisInformation> axisMapping;
// This array is used to store the old axis values from the previous frame, it is
// This vector is used to store the old axis values from the previous frame, it is
// used to calculate the difference in the values in the case of a sticky axis
std::array<float, JoystickInputState::MaxAxes> prevAxisValues;
std::vector<float> prevAxisValues;
struct ButtonInformation {
// The script that is run when the button is activated

View File

@@ -54,12 +54,6 @@ enum class JoystickAction : uint8_t {
* The input state of a single joystick.
*/
struct JoystickInputState {
/// These two are just randomly selected numbers that can be increased if needed
/// The maximum number of supported axes
static constexpr const int MaxAxes = 8;
/// The maximum number of supported buttons
static constexpr const int MaxButtons = 48;
/// Marks whether this joystick is connected. If this value is \c false, all other
/// members of this struct are undefined
bool isConnected = false;
@@ -69,15 +63,13 @@ struct JoystickInputState {
/// 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 values for each axis. Each value is in the range [-1, 1]
std::vector<float> 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 status of each button
std::vector<JoystickAction> buttons;
};
/// The maximum number of joysticks that are supported by this system. This number is
@@ -88,12 +80,31 @@ struct JoystickInputStates : public std::array<JoystickInputState, MaxJoysticks>
/// derived from the available GLFW constants
static constexpr const int MaxNumJoysticks = 16;
/**
* This function return the number of axes the joystick with the given name has
*
* \param joystickName The name of the joystick to check how many axes it has,
* if empty the max number of axes for all joysticks are returned
* \return The number of axes for the joystick with the given name
*/
int numAxes(const std::string& joystickName = "") const;
/**
* This function return the number of buttons the joystick with the given name has
*
* \param joystickName The name of the joystick to check how many buttons it has,
* if empty the max number of buttons for all joysticks are returned
* \return The number of buttons for the joystick with the given name
*/
int numButtons(const std::string& joystickName = "") const;
/**
* 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 joystickName The name of the joystick, if empty all joysticks are combined
* \param axis The numerical axis for which the values are added
* \return The summed axis values of all connected joysticks
*
@@ -106,6 +117,7 @@ struct JoystickInputStates : public std::array<JoystickInputState, MaxJoysticks>
* passed \p action. Any joystick that does not posses the \p button, it will be
* ignored.
*
* \param joystickName The name of the joystick, if empty all joysticks are combined
* \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

View File

@@ -94,6 +94,7 @@ public:
void mousePositionCallback(double x, double y);
void mouseScrollWheelCallback(double pos);
std::vector<std::string> listAllJoysticks() const;
void setJoystickAxisMapping(std::string joystickName,
int axis, JoystickCameraStates::AxisType mapping,
JoystickCameraStates::AxisInvert shouldInvert =

View File

@@ -60,8 +60,9 @@ void GuiJoystickComponent::render() {
ImGui::Text("%s", "Axes");
for (int j = 0; j < state.nAxes; ++j) {
float f = state.axes[j];
std::string id = std::to_string(j) + "##" + state.name + "Axis";
ImGui::SliderFloat(
std::to_string(j).c_str(),
id.c_str(),
&f,
-1.f,
1.f
@@ -69,8 +70,9 @@ void GuiJoystickComponent::render() {
}
ImGui::Text("%s", "Buttons");
for (int j = 0; j < state.nButtons; ++j) {
std::string id = std::to_string(j) + "##" + state.name + "Button";
ImGui::RadioButton(
std::to_string(j).c_str(),
id.c_str(),
state.buttons[j] == JoystickAction::Press ||
state.buttons[j] == JoystickAction::Repeat
);
@@ -84,19 +86,21 @@ void GuiJoystickComponent::render() {
ImGui::Text("%s", "Summed contributions");
ImGui::Text("%s", "Axes");
for (int i = 0; i < JoystickInputState::MaxAxes; ++i) {
for (int i = 0; i < global::joystickInputStates->numAxes(); ++i) {
float f = global::joystickInputStates->axis("", i);
std::string id = std::to_string(i) + "##" + "TotalAxis";
ImGui::SliderFloat(
std::to_string(i).c_str(),
id.c_str(),
&f,
-1.f,
1.f
);
}
ImGui::Text("%s", "Buttons");
for (int i = 0; i < JoystickInputState::MaxButtons; ++i) {
for (int i = 0; i < global::joystickInputStates->numButtons(); ++i) {
std::string id = std::to_string(i) + "##" + "TotalButton";
ImGui::RadioButton(
std::to_string(i).c_str(),
id.c_str(),
global::joystickInputStates->button("", i, JoystickAction::Press) ||
global::joystickInputStates->button("", i, JoystickAction::Repeat)
);

View File

@@ -1,3 +1,5 @@
set(DEFAULT_MODULE ON)
set(OPENSPACE_DEPENDENCIES
webbrowser
webgui

View File

@@ -91,7 +91,7 @@ void SpoutMain::saveGLState() {
_defaultReadBuffer = static_cast<unsigned int>(buf);
glGetIntegerv(GL_DRAW_BUFFER0, &buf);
_defaultReadBuffer = static_cast<unsigned int>(buf);
_defaultDrawBuffer[0] = static_cast<unsigned int>(buf);
saveGLTextureState();
}

View File

@@ -62,7 +62,8 @@ void JoystickCameraStates::updateStateFromInput(
continue;
}
for (int i = 0; i < JoystickInputState::MaxAxes; ++i) {
int nAxes = joystickInputStates.numAxes(joystickInputState.name);
for (int i = 0; i < nAxes; ++i) {
AxisInformation t = joystick->axisMapping[i];
if (t.type == AxisType::None) {
continue;
@@ -166,7 +167,8 @@ void JoystickCameraStates::updateStateFromInput(
}
}
for (int i = 0; i < JoystickInputState::MaxButtons; ++i) {
int nButtons = joystickInputStates.numButtons(joystickInputState.name);
for (int i = 0; i < nButtons; ++i) {
auto itRange = joystick->buttonMapping.equal_range(i);
for (auto it = itRange.first; it != itRange.second; ++it) {
bool active = global::joystickInputStates->button(
@@ -230,13 +232,17 @@ void JoystickCameraStates::setAxisMapping(std::string joystickName,
bool isSticky,
double sensitivity)
{
ghoul_assert(axis < JoystickInputState::MaxAxes, "axis must be < MaxAxes");
JoystickCameraState* joystickCameraState = findOrAddJoystickCameraState(joystickName);
if (!joystickCameraState) {
return;
}
// If the axis index is too big for the vector then resize it to have room
if (axis >= joystickCameraState->axisMapping.size()) {
joystickCameraState->axisMapping.resize(axis + 1);
joystickCameraState->prevAxisValues.resize(axis + 1);
}
joystickCameraState->axisMapping[axis].type = mapping;
joystickCameraState->axisMapping[axis].invert = shouldInvert;
joystickCameraState->axisMapping[axis].joystickType = joystickType;
@@ -254,13 +260,17 @@ void JoystickCameraStates::setAxisMappingProperty(std::string joystickName,
AxisInvert shouldInvert,
bool isRemote)
{
ghoul_assert(axis < JoystickInputState::MaxAxes, "axis must be < MaxAxes");
JoystickCameraState* joystickCameraState = findOrAddJoystickCameraState(joystickName);
if (!joystickCameraState) {
return;
}
// If the axis index is too big for the vector then resize it to have room
if (axis >= joystickCameraState->axisMapping.size()) {
joystickCameraState->axisMapping.resize(axis + 1);
joystickCameraState->prevAxisValues.resize(axis + 1);
}
joystickCameraState->axisMapping[axis].type = AxisType::Property;
joystickCameraState->axisMapping[axis].invert = shouldInvert;
joystickCameraState->axisMapping[axis].propertyUri = propertyUri;
@@ -282,6 +292,11 @@ JoystickCameraStates::AxisInformation JoystickCameraStates::axisMapping(
return dummy;
}
if (axis >= joystick->axisMapping.size()) {
JoystickCameraStates::AxisInformation dummy;
return dummy;
}
return joystick->axisMapping[axis];
}
@@ -293,6 +308,12 @@ void JoystickCameraStates::setDeadzone(const std::string& joystickName, int axis
return;
}
// If the axis index is too big for the vector then resize it to have room
if (axis >= joystickCameraState->axisMapping.size()) {
joystickCameraState->axisMapping.resize(axis + 1);
joystickCameraState->prevAxisValues.resize(axis + 1);
}
joystickCameraState->axisMapping[axis].deadzone = deadzone;
}
@@ -302,6 +323,10 @@ float JoystickCameraStates::deadzone(const std::string& joystickName, int axis)
return 0.f;
}
if (axis >= joystick->axisMapping.size()) {
return 0.f;
}
return joystick->axisMapping[axis].deadzone;
}

View File

@@ -33,6 +33,44 @@
namespace openspace::interaction {
int JoystickInputStates::numAxes(const std::string& joystickName) const {
if (joystickName.empty()) {
int maxNumAxes = -1;
for (auto it = begin(); it < end(); ++it) {
if (it->nAxes > maxNumAxes) {
maxNumAxes = it->nAxes;
}
}
return maxNumAxes;
}
for (auto it = begin(); it < end(); ++it) {
if (it->name == joystickName) {
return it->nAxes;
}
}
return -1;
}
int JoystickInputStates::numButtons(const std::string& joystickName) const {
if (joystickName.empty()) {
int maxNumButtons = -1;
for (auto it = begin(); it < end(); ++it) {
if (it->nButtons > maxNumButtons) {
maxNumButtons = it->nButtons;
}
}
return maxNumButtons;
}
for (auto it = begin(); it < end(); ++it) {
if (it->name == joystickName) {
return it->nButtons;
}
}
return -1;
}
float JoystickInputStates::axis(const std::string& joystickName, int axis) const {
ghoul_precondition(axis >= 0, "axis must be 0 or positive");

View File

@@ -477,6 +477,18 @@ void NavigationHandler::loadNavigationState(const std::string& filepath) {
}
}
std::vector<std::string> NavigationHandler::listAllJoysticks() const {
std::vector<std::string> result;
result.reserve(global::joystickInputStates->size());
for (const JoystickInputState& joystickInputState : *global::joystickInputStates) {
if (!joystickInputState.name.empty()) {
result.push_back(joystickInputState.name);
}
}
return result;
}
void NavigationHandler::setJoystickAxisMapping(std::string joystickName, int axis,
JoystickCameraStates::AxisType mapping,
JoystickCameraStates::AxisInvert shouldInvert,
@@ -604,7 +616,8 @@ scripting::LuaLibrary NavigationHandler::luaLibrary() {
codegen::lua::AddTruckMovement,
codegen::lua::AddLocalRoll,
codegen::lua::AddGlobalRoll,
codegen::lua::TriggerIdleBehavior
codegen::lua::TriggerIdleBehavior,
codegen::lua::ListAllJoysticks
}
};
}

View File

@@ -354,6 +354,14 @@ joystickAxis(std::string joystickName, int axis)
}
}
/**
* Return the complete list of connected joysticks
*/
[[codegen::luawrap]] std::vector<std::string> listAllJoysticks() {
using namespace openspace;
return global::navigationHandler->listAllJoysticks();
}
#include "navigationhandler_lua_codegen.cpp"
} // namespace