mirror of
https://gitlab.com/OpenMW/openmw.git
synced 2025-02-22 12:39:59 +00:00
Implement gyro camera for controllers
This commit is contained in:
parent
9fa0faf944
commit
a496f16cdb
@ -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
|
||||
|
22
apps/openmw/mwinput/gyroaxis.cpp
Normal file
22
apps/openmw/mwinput/gyroaxis.cpp
Normal 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;
|
||||
}
|
||||
}
|
22
apps/openmw/mwinput/gyroaxis.hpp
Normal file
22
apps/openmw/mwinput/gyroaxis.hpp
Normal 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
|
95
apps/openmw/mwinput/gyromanager.cpp
Normal file
95
apps/openmw/mwinput/gyromanager.cpp
Normal 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;
|
||||
}
|
||||
}
|
38
apps/openmw/mwinput/gyromanager.hpp
Normal file
38
apps/openmw/mwinput/gyromanager.hpp
Normal 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
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user