From a496f16cdb6939df27949da07c1fa8b1cd40f320 Mon Sep 17 00:00:00 2001 From: uramer Date: Tue, 18 Jan 2022 22:47:49 +0100 Subject: [PATCH] Implement gyro camera for controllers --- apps/openmw/CMakeLists.txt | 2 +- apps/openmw/mwinput/gyroaxis.cpp | 22 ++++++ apps/openmw/mwinput/gyroaxis.hpp | 22 ++++++ apps/openmw/mwinput/gyromanager.cpp | 95 +++++++++++++++++++++++++ apps/openmw/mwinput/gyromanager.hpp | 38 ++++++++++ apps/openmw/mwinput/inputmanagerimp.cpp | 18 +++++ apps/openmw/mwinput/inputmanagerimp.hpp | 2 + apps/openmw/mwinput/sensormanager.cpp | 89 +---------------------- apps/openmw/mwinput/sensormanager.hpp | 20 +----- 9 files changed, 203 insertions(+), 105 deletions(-) create mode 100644 apps/openmw/mwinput/gyroaxis.cpp create mode 100644 apps/openmw/mwinput/gyroaxis.hpp create mode 100644 apps/openmw/mwinput/gyromanager.cpp create mode 100644 apps/openmw/mwinput/gyromanager.hpp diff --git a/apps/openmw/CMakeLists.txt b/apps/openmw/CMakeLists.txt index ea1d48885c..79cb6f30bd 100644 --- a/apps/openmw/CMakeLists.txt +++ b/apps/openmw/CMakeLists.txt @@ -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 diff --git a/apps/openmw/mwinput/gyroaxis.cpp b/apps/openmw/mwinput/gyroaxis.cpp new file mode 100644 index 0000000000..3eb71fb30b --- /dev/null +++ b/apps/openmw/mwinput/gyroaxis.cpp @@ -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; + } +} diff --git a/apps/openmw/mwinput/gyroaxis.hpp b/apps/openmw/mwinput/gyroaxis.hpp new file mode 100644 index 0000000000..542217351d --- /dev/null +++ b/apps/openmw/mwinput/gyroaxis.hpp @@ -0,0 +1,22 @@ +#ifndef MWINPUT_GYROAXIS +#define MWINPUT_GYROAXIS + +#include + +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 diff --git a/apps/openmw/mwinput/gyromanager.cpp b/apps/openmw/mwinput/gyromanager.cpp new file mode 100644 index 0000000000..5a2b532186 --- /dev/null +++ b/apps/openmw/mwinput/gyromanager.cpp @@ -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 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 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; + } +} diff --git a/apps/openmw/mwinput/gyromanager.hpp b/apps/openmw/mwinput/gyromanager.hpp new file mode 100644 index 0000000000..2c4a13905f --- /dev/null +++ b/apps/openmw/mwinput/gyromanager.hpp @@ -0,0 +1,38 @@ +#ifndef MWINPUT_GYROMANAGER +#define MWINPUT_GYROMANAGER + +#include + +#include "gyroaxis.hpp" + +namespace MWInput +{ + class GyroManager + { + public: + GyroManager(); + + bool isEnabled() const { return mEnabled; } + + void update(float dt, std::array 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 values) const; + }; +} + +#endif // !MWINPUT_GYROMANAGER diff --git a/apps/openmw/mwinput/inputmanagerimp.cpp b/apps/openmw/mwinput/inputmanagerimp.cpp index 4ebe56bf94..8beead5803 100644 --- a/apps/openmw/mwinput/inputmanagerimp.cpp +++ b/apps/openmw/mwinput/inputmanagerimp.cpp @@ -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) diff --git a/apps/openmw/mwinput/inputmanagerimp.hpp b/apps/openmw/mwinput/inputmanagerimp.hpp index 41478d5dcb..3f9f1b3be1 100644 --- a/apps/openmw/mwinput/inputmanagerimp.hpp +++ b/apps/openmw/mwinput/inputmanagerimp.hpp @@ -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 diff --git a/apps/openmw/mwinput/sensormanager.cpp b/apps/openmw/mwinput/sensormanager.cpp index 601924fa16..fed25b88ce 100644 --- a/apps/openmw/mwinput/sensormanager.cpp +++ b/apps/openmw/mwinput/sensormanager.cpp @@ -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(); } } diff --git a/apps/openmw/mwinput/sensormanager.hpp b/apps/openmw/mwinput/sensormanager.hpp index e096a89260..92d0a036e8 100644 --- a/apps/openmw/mwinput/sensormanager.hpp +++ b/apps/openmw/mwinput/sensormanager.hpp @@ -6,6 +6,8 @@ #include #include +#include "gyroaxis.hpp" + namespace SDLUtil { class InputWrapper; @@ -39,33 +41,15 @@ namespace MWInput std::array 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 mGyroValues; float mGyroUpdateTimer; - float mGyroHSensitivity; - float mGyroVSensitivity; GyroscopeAxis mGyroHAxis; GyroscopeAxis mGyroVAxis; - float mGyroInputThreshold; SDL_Sensor* mGyroscope;