1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-22 03:40:49 +00:00

Implement gyro camera for controllers

This commit is contained in:
uramer 2022-01-18 22:47:49 +01:00
parent 9fa0faf944
commit a496f16cdb
9 changed files with 203 additions and 105 deletions

View File

@ -27,7 +27,7 @@ add_openmw_dir (mwrender
add_openmw_dir (mwinput
actions actionmanager bindingsmanager controllermanager controlswitch
inputmanagerimp mousemanager keyboardmanager sensormanager
inputmanagerimp mousemanager keyboardmanager gyroaxis sensormanager gyromanager
)
add_openmw_dir (mwgui

View File

@ -0,0 +1,22 @@
#include "gyroaxis.hpp"
namespace MWInput
{
GyroscopeAxis gyroscopeAxisFromString(std::string_view s)
{
if (s == "x")
return GyroscopeAxis::X;
else if (s == "y")
return GyroscopeAxis::Y;
else if (s == "z")
return GyroscopeAxis::Z;
else if (s == "-x")
return GyroscopeAxis::Minus_X;
else if (s == "-y")
return GyroscopeAxis::Minus_Y;
else if (s == "-z")
return GyroscopeAxis::Minus_Z;
return GyroscopeAxis::Unknown;
}
}

View File

@ -0,0 +1,22 @@
#ifndef MWINPUT_GYROAXIS
#define MWINPUT_GYROAXIS
#include <string_view>
namespace MWInput
{
enum GyroscopeAxis
{
Unknown = 0,
X = 1,
Y = 2,
Z = 3,
Minus_X = -1,
Minus_Y = -2,
Minus_Z = -3
};
GyroscopeAxis gyroscopeAxisFromString(std::string_view s);
}
#endif // !MWINPUT_GYROAXIS

View File

@ -0,0 +1,95 @@
#include "gyromanager.hpp"
#include "../mwbase/inputmanager.hpp"
#include "../mwbase/environment.hpp"
#include "../mwbase/world.hpp"
#include "../mwworld/player.hpp"
namespace MWInput
{
GyroManager::GyroManager()
: mEnabled(Settings::Manager::getBool("enable gyroscope", "Input"))
, mGuiCursorEnabled(true)
, mSensitivityH(Settings::Manager::getFloat("gyro horizontal sensitivity", "Input"))
, mSensitivityV(Settings::Manager::getFloat("gyro vertical sensitivity", "Input"))
, mInvertH(Settings::Manager::getBool("invert x axis", "Input"))
, mInvertV(Settings::Manager::getBool("invert y axis", "Input"))
, mInputThreshold(Settings::Manager::getFloat("gyro input threshold", "Input"))
, mAxisH(gyroscopeAxisFromString(Settings::Manager::getString("gyro horizontal axis", "Input")))
, mAxisV(gyroscopeAxisFromString(Settings::Manager::getString("gyro vertical axis", "Input")))
{};
void GyroManager::update(float dt, std::array<float, 3> values) const
{
if (!mGuiCursorEnabled)
{
float gyroH = getAxisValue(mAxisH, values);
float gyroV = getAxisValue(mAxisV, values);
if (gyroH == 0 && gyroV == 0)
return;
float rot[3];
rot[0] = -gyroV * dt * mSensitivityV * 4 * (mInvertV ? -1 : 1);
rot[1] = 0.0f;
rot[2] = -gyroH * dt * mSensitivityH * 4 * (mInvertH ? -1 : 1);
// Only actually turn player when we're not in vanity mode
bool playerLooking = MWBase::Environment::get().getInputManager()->getControlSwitch("playerlooking");
if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && playerLooking)
{
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
player.yaw(-rot[2]);
player.pitch(-rot[0]);
}
else if (!playerLooking)
MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation();
MWBase::Environment::get().getInputManager()->resetIdleTime();
}
}
void GyroManager::processChangedSettings(const Settings::CategorySettingVector& changed)
{
for (const auto& setting : changed)
{
if (setting.first != "Input")
continue;
if (setting.second == "enable gyroscope")
mEnabled = Settings::Manager::getBool("enable gyroscope", "Input");
else if (setting.second == "gyro horizontal sensitivity")
mSensitivityH = Settings::Manager::getFloat("gyro horizontal sensitivity", "Input");
else if (setting.second == "gyro vertical sensitivity")
mSensitivityV = Settings::Manager::getFloat("gyro vertical sensitivity", "Input");
else if (setting.second == "invert x axis")
mInvertH = Settings::Manager::getBool("invert x axis", "Input");
else if (setting.second == "invert y axis")
mInvertV = Settings::Manager::getBool("invert y axis", "Input");
else if (setting.second == "gyro input threshold")
mInputThreshold = Settings::Manager::getFloat("gyro input threshold", "Input");
else if (setting.second == "gyro horizontal axis")
mAxisH = gyroscopeAxisFromString(Settings::Manager::getString("gyro horizontal axis", "Input"));
else if (setting.second == "gyro vertical axis")
mAxisV = gyroscopeAxisFromString(Settings::Manager::getString("gyro vertical axis", "Input"));
}
}
namespace
{
int signum(int x)
{
return 0 < x - x < 0;
}
}
float GyroManager::getAxisValue(GyroscopeAxis axis, std::array<float, 3> values) const
{
if (axis == GyroscopeAxis::Unknown)
return 0;
float value = values[std::abs(axis) - 1] * signum(axis);
//if (std::abs(value) <= mInputThreshold)
// value = 0;
return value;
}
}

View File

@ -0,0 +1,38 @@
#ifndef MWINPUT_GYROMANAGER
#define MWINPUT_GYROMANAGER
#include <components/settings/settings.hpp>
#include "gyroaxis.hpp"
namespace MWInput
{
class GyroManager
{
public:
GyroManager();
bool isEnabled() const { return mEnabled; }
void update(float dt, std::array<float, 3> values) const;
void processChangedSettings(const Settings::CategorySettingVector& changed);
void setGuiCursorEnabled(bool enabled) { mGuiCursorEnabled = enabled; }
private:
bool mEnabled;
bool mGuiCursorEnabled;
float mSensitivityH;
float mSensitivityV;
bool mInvertH;
bool mInvertV;
float mInputThreshold;
GyroscopeAxis mAxisH;
GyroscopeAxis mAxisV;
float getAxisValue(GyroscopeAxis axis, std::array<float, 3> values) const;
};
}
#endif // !MWINPUT_GYROMANAGER

View File

@ -19,6 +19,7 @@
#include "keyboardmanager.hpp"
#include "mousemanager.hpp"
#include "sensormanager.hpp"
#include "gyromanager.hpp"
namespace MWInput
{
@ -51,6 +52,8 @@ namespace MWInput
mSensorManager = new SensorManager();
mInputWrapper->setSensorEventCallback(mSensorManager);
mGyroManager = new GyroManager();
}
void InputManager::clear()
@ -72,6 +75,8 @@ namespace MWInput
delete mBindingsManager;
delete mInputWrapper;
delete mGyroManager;
}
void InputManager::setAttemptJump(bool jumping)
@ -100,6 +105,17 @@ namespace MWInput
mMouseManager->update(dt);
mSensorManager->update(dt);
mActionManager->update(dt, controllerMove);
if (mGyroManager->isEnabled())
{
bool controllerAvailable = mControllerManager->isGyroAvailable();
bool sensorAvailable = mSensorManager->isGyroAvailable();
if (controllerAvailable || sensorAvailable)
{
mGyroManager->update(dt,
controllerAvailable ? mControllerManager->getGyroValues() : mSensorManager->getGyroValues());
}
}
}
void InputManager::setDragDrop(bool dragDrop)
@ -117,6 +133,7 @@ namespace MWInput
mControllerManager->setGuiCursorEnabled(guiMode);
mMouseManager->setGuiCursorEnabled(guiMode);
mSensorManager->setGuiCursorEnabled(guiMode);
mGyroManager->setGuiCursorEnabled(guiMode);
mMouseManager->setMouseLookEnabled(!guiMode);
if (guiMode)
MWBase::Environment::get().getWindowManager()->showCrosshair(false);
@ -130,6 +147,7 @@ namespace MWInput
{
mMouseManager->processChangedSettings(changed);
mSensorManager->processChangedSettings(changed);
mGyroManager->processChangedSettings(changed);
}
bool InputManager::getControlSwitch(std::string_view sw)

View File

@ -39,6 +39,7 @@ namespace MWInput
class KeyboardManager;
class MouseManager;
class SensorManager;
class GyroManager;
/**
* @brief Class that provides a high-level API for game input
@ -128,6 +129,7 @@ namespace MWInput
KeyboardManager* mKeyboardManager;
MouseManager* mMouseManager;
SensorManager* mSensorManager;
GyroManager* mGyroManager;
};
}
#endif

View File

@ -11,15 +11,10 @@
namespace MWInput
{
SensorManager::SensorManager()
: mInvertX(Settings::Manager::getBool("invert x axis", "Input"))
, mInvertY(Settings::Manager::getBool("invert y axis", "Input"))
, mGyroValues()
: mGyroValues()
, mGyroUpdateTimer(0.f)
, mGyroHSensitivity(Settings::Manager::getFloat("gyro horizontal sensitivity", "Input"))
, mGyroVSensitivity(Settings::Manager::getFloat("gyro vertical sensitivity", "Input"))
, mGyroHAxis(GyroscopeAxis::Minus_X)
, mGyroVAxis(GyroscopeAxis::Y)
, mGyroInputThreshold(Settings::Manager::getFloat("gyro input threshold", "Input"))
, mGyroscope(nullptr)
, mGuiCursorEnabled(true)
{
@ -41,24 +36,6 @@ namespace MWInput
}
}
SensorManager::GyroscopeAxis SensorManager::mapGyroscopeAxis(const std::string& axis)
{
if (axis == "x")
return GyroscopeAxis::X;
else if (axis == "y")
return GyroscopeAxis::Y;
else if (axis == "z")
return GyroscopeAxis::Z;
else if (axis == "-x")
return GyroscopeAxis::Minus_X;
else if (axis == "-y")
return GyroscopeAxis::Minus_Y;
else if (axis == "-z")
return GyroscopeAxis::Minus_Z;
return GyroscopeAxis::Unknown;
}
void SensorManager::correctGyroscopeAxes()
{
if (!Settings::Manager::getBool("enable gyroscope", "Input"))
@ -67,8 +44,8 @@ namespace MWInput
// Treat setting from config as axes for landscape mode.
// If the device does not support orientation change, do nothing.
// Note: in is unclear how to correct axes for devices with non-standart Z axis direction.
mGyroHAxis = mapGyroscopeAxis(Settings::Manager::getString("gyro horizontal axis", "Input"));
mGyroVAxis = mapGyroscopeAxis(Settings::Manager::getString("gyro vertical axis", "Input"));
mGyroHAxis = gyroscopeAxisFromString(Settings::Manager::getString("gyro horizontal axis", "Input"));
mGyroVAxis = gyroscopeAxisFromString(Settings::Manager::getString("gyro vertical axis", "Input"));
SDL_DisplayOrientation currentOrientation = SDL_GetDisplayOrientation(Settings::Manager::getInt("screen", "Video"));
switch (currentOrientation)
@ -148,18 +125,6 @@ namespace MWInput
{
for (const auto& setting : changed)
{
if (setting.first == "Input" && setting.second == "invert x axis")
mInvertX = Settings::Manager::getBool("invert x axis", "Input");
if (setting.first == "Input" && setting.second == "invert y axis")
mInvertY = Settings::Manager::getBool("invert y axis", "Input");
if (setting.first == "Input" && setting.second == "gyro horizontal sensitivity")
mGyroHSensitivity = Settings::Manager::getFloat("gyro horizontal sensitivity", "Input");
if (setting.first == "Input" && setting.second == "gyro vertical sensitivity")
mGyroVSensitivity = Settings::Manager::getFloat("gyro vertical sensitivity", "Input");
if (setting.first == "Input" && setting.second == "enable gyroscope")
init();
@ -168,26 +133,6 @@ namespace MWInput
if (setting.first == "Input" && setting.second == "gyro vertical axis")
correctGyroscopeAxes();
if (setting.first == "Input" && setting.second == "gyro input threshold")
mGyroInputThreshold = Settings::Manager::getFloat("gyro input threshold", "Input");
}
}
float SensorManager::getGyroAxisSpeed(GyroscopeAxis axis) const
{
switch (axis)
{
case GyroscopeAxis::X:
case GyroscopeAxis::Y:
case GyroscopeAxis::Z:
return std::abs(mGyroValues[0]) >= mGyroInputThreshold ? mGyroValues[axis - 1] : 0.f;
case GyroscopeAxis::Minus_X:
case GyroscopeAxis::Minus_Y:
case GyroscopeAxis::Minus_Z:
return std::abs(mGyroValues[0]) >= mGyroInputThreshold ? -mGyroValues[std::abs(axis) - 1] : 0.f;
default:
return 0.f;
}
}
@ -236,34 +181,6 @@ namespace MWInput
// Reset current rotation speed and wait for update.
mGyroValues = { 0, 0, 0 };
mGyroUpdateTimer = 0.f;
return;
}
if (!mGuiCursorEnabled)
{
float gyroH = getGyroAxisSpeed(mGyroHAxis);
float gyroV = getGyroAxisSpeed(mGyroVAxis);
if (gyroH == 0 && gyroV == 0)
return;
float rot[3];
rot[0] = -gyroV * dt * mGyroVSensitivity * 4 * (mInvertY ? -1 : 1);
rot[1] = 0.0f;
rot[2] = -gyroH * dt * mGyroHSensitivity * 4 * (mInvertX ? -1 : 1);
// Only actually turn player when we're not in vanity mode
bool playerLooking = MWBase::Environment::get().getInputManager()->getControlSwitch("playerlooking");
if (!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot) && playerLooking)
{
MWWorld::Player& player = MWBase::Environment::get().getWorld()->getPlayer();
player.yaw(-rot[2]);
player.pitch(-rot[0]);
}
else if (!playerLooking)
MWBase::Environment::get().getWorld()->disableDeferredPreviewRotation();
MWBase::Environment::get().getInputManager()->resetIdleTime();
}
}

View File

@ -6,6 +6,8 @@
#include <components/settings/settings.hpp>
#include <components/sdlutil/events.hpp>
#include "gyroaxis.hpp"
namespace SDLUtil
{
class InputWrapper;
@ -39,33 +41,15 @@ namespace MWInput
std::array<float, 3> getGyroValues() const;
private:
enum GyroscopeAxis
{
Unknown = 0,
X = 1,
Y = 2,
Z = 3,
Minus_X = -1,
Minus_Y = -2,
Minus_Z = -3
};
void updateSensors();
void correctGyroscopeAxes();
GyroscopeAxis mapGyroscopeAxis(const std::string& axis);
float getGyroAxisSpeed(GyroscopeAxis axis) const;
bool mInvertX;
bool mInvertY;
std::array<float, 3> mGyroValues;
float mGyroUpdateTimer;
float mGyroHSensitivity;
float mGyroVSensitivity;
GyroscopeAxis mGyroHAxis;
GyroscopeAxis mGyroVAxis;
float mGyroInputThreshold;
SDL_Sensor* mGyroscope;