mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-13 07:49:19 +01:00
Merge pull request #8747 from iwubcode/map-freelook
Support controlling Free Look via input bindings (motion controls, gamepad, etc!)
This commit is contained in:
commit
ce8e87c64b
@ -4,6 +4,8 @@
|
|||||||
|
|
||||||
#include "Common/Matrix.h"
|
#include "Common/Matrix.h"
|
||||||
|
|
||||||
|
#include "Common/MathUtil.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
@ -121,6 +123,32 @@ Vec3 operator*(const Quaternion& lhs, const Vec3& rhs)
|
|||||||
return Vec3(result.data.x, result.data.y, result.data.z);
|
return Vec3(result.data.x, result.data.y, result.data.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Vec3 FromQuaternionToEuler(const Quaternion& q)
|
||||||
|
{
|
||||||
|
Vec3 result;
|
||||||
|
|
||||||
|
const float qx = q.data.x;
|
||||||
|
const float qy = q.data.y;
|
||||||
|
const float qz = q.data.z;
|
||||||
|
const float qw = q.data.w;
|
||||||
|
|
||||||
|
const float sinr_cosp = 2 * (qw * qx + qy * qz);
|
||||||
|
const float cosr_cosp = 1 - 2 * (qx * qx + qy * qy);
|
||||||
|
result.x = std::atan2(sinr_cosp, cosr_cosp);
|
||||||
|
|
||||||
|
const float sinp = 2 * (qw * qy - qz * qx);
|
||||||
|
if (std::abs(sinp) >= 1)
|
||||||
|
result.y = std::copysign(MathUtil::PI / 2, sinp); // use 90 degrees if out of range
|
||||||
|
else
|
||||||
|
result.y = std::asin(sinp);
|
||||||
|
|
||||||
|
const float siny_cosp = 2 * (qw * qz + qx * qy);
|
||||||
|
const float cosy_cosp = 1 - 2 * (qy * qy + qz * qz);
|
||||||
|
result.z = std::atan2(siny_cosp, cosy_cosp);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
Matrix33 Matrix33::Identity()
|
Matrix33 Matrix33::Identity()
|
||||||
{
|
{
|
||||||
Matrix33 mtx = {};
|
Matrix33 mtx = {};
|
||||||
|
@ -359,6 +359,8 @@ public:
|
|||||||
Quaternion operator*(Quaternion lhs, const Quaternion& rhs);
|
Quaternion operator*(Quaternion lhs, const Quaternion& rhs);
|
||||||
Vec3 operator*(const Quaternion& lhs, const Vec3& rhs);
|
Vec3 operator*(const Quaternion& lhs, const Vec3& rhs);
|
||||||
|
|
||||||
|
Vec3 FromQuaternionToEuler(const Quaternion& q);
|
||||||
|
|
||||||
class Matrix33
|
class Matrix33
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include "Core/FreeLookConfig.h"
|
#include "Core/FreeLookConfig.h"
|
||||||
|
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h"
|
#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h"
|
||||||
|
#include "InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.h"
|
||||||
#include "InputCommon/InputConfig.h"
|
#include "InputCommon/InputConfig.h"
|
||||||
|
|
||||||
#include "VideoCommon/FreeLookCamera.h"
|
#include "VideoCommon/FreeLookCamera.h"
|
||||||
@ -60,6 +61,19 @@ enum FieldOfViewButtons
|
|||||||
DecreaseY,
|
DecreaseY,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace GyroButtons
|
||||||
|
{
|
||||||
|
enum GyroButtons
|
||||||
|
{
|
||||||
|
PitchUp,
|
||||||
|
PitchDown,
|
||||||
|
RollLeft,
|
||||||
|
RollRight,
|
||||||
|
YawLeft,
|
||||||
|
YawRight,
|
||||||
|
};
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
FreeLookController::FreeLookController(const unsigned int index) : m_index(index)
|
FreeLookController::FreeLookController(const unsigned int index) : m_index(index)
|
||||||
@ -89,6 +103,9 @@ FreeLookController::FreeLookController(const unsigned int index) : m_index(index
|
|||||||
m_fov_buttons->AddInput(ControllerEmu::Translate, _trans("Decrease X"));
|
m_fov_buttons->AddInput(ControllerEmu::Translate, _trans("Decrease X"));
|
||||||
m_fov_buttons->AddInput(ControllerEmu::Translate, _trans("Increase Y"));
|
m_fov_buttons->AddInput(ControllerEmu::Translate, _trans("Increase Y"));
|
||||||
m_fov_buttons->AddInput(ControllerEmu::Translate, _trans("Decrease Y"));
|
m_fov_buttons->AddInput(ControllerEmu::Translate, _trans("Decrease Y"));
|
||||||
|
|
||||||
|
groups.emplace_back(m_rotation_gyro = new ControllerEmu::IMUGyroscope(
|
||||||
|
_trans("Incremental Rotation"), _trans("Incremental Rotation")));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string FreeLookController::GetName() const
|
std::string FreeLookController::GetName() const
|
||||||
@ -125,6 +142,35 @@ void FreeLookController::LoadDefaults(const ControllerInterface& ciface)
|
|||||||
hotkey_string({"Shift", "`Axis Z+`"}));
|
hotkey_string({"Shift", "`Axis Z+`"}));
|
||||||
m_fov_buttons->SetControlExpression(FieldOfViewButtons::DecreaseY,
|
m_fov_buttons->SetControlExpression(FieldOfViewButtons::DecreaseY,
|
||||||
hotkey_string({"Shift", "`Axis Z-`"}));
|
hotkey_string({"Shift", "`Axis Z-`"}));
|
||||||
|
|
||||||
|
#if defined HAVE_X11 && HAVE_X11
|
||||||
|
m_rotation_gyro->SetControlExpression(GyroButtons::PitchUp,
|
||||||
|
"if(`Click 3`,`RelativeMouse Y-` * 0.10, 0)");
|
||||||
|
m_rotation_gyro->SetControlExpression(GyroButtons::PitchDown,
|
||||||
|
"if(`Click 3`,`RelativeMouse Y+` * 0.10, 0)");
|
||||||
|
#else
|
||||||
|
m_rotation_gyro->SetControlExpression(GyroButtons::PitchUp,
|
||||||
|
"if(`Click 1`,`RelativeMouse Y-` * 0.10, 0)");
|
||||||
|
m_rotation_gyro->SetControlExpression(GyroButtons::PitchDown,
|
||||||
|
"if(`Click 1`,`RelativeMouse Y+` * 0.10, 0)");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_rotation_gyro->SetControlExpression(GyroButtons::RollLeft,
|
||||||
|
"if(`Click 2`,`RelativeMouse X-` * 0.10, 0)");
|
||||||
|
m_rotation_gyro->SetControlExpression(GyroButtons::RollRight,
|
||||||
|
"if(`Click 2`,`RelativeMouse X+` * 0.10, 0)");
|
||||||
|
|
||||||
|
#if defined HAVE_X11 && HAVE_X11
|
||||||
|
m_rotation_gyro->SetControlExpression(GyroButtons::YawLeft,
|
||||||
|
"if(`Click 3`,`RelativeMouse X-` * 0.10, 0)");
|
||||||
|
m_rotation_gyro->SetControlExpression(GyroButtons::YawRight,
|
||||||
|
"if(`Click 3`,`RelativeMouse X+` * 0.10, 0)");
|
||||||
|
#else
|
||||||
|
m_rotation_gyro->SetControlExpression(GyroButtons::YawLeft,
|
||||||
|
"if(`Click 1`,`RelativeMouse X-` * 0.10, 0)");
|
||||||
|
m_rotation_gyro->SetControlExpression(GyroButtons::YawRight,
|
||||||
|
"if(`Click 1`,`RelativeMouse X+` * 0.10, 0)");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
ControllerEmu::ControlGroup* FreeLookController::GetGroup(FreeLookGroup group) const
|
ControllerEmu::ControlGroup* FreeLookController::GetGroup(FreeLookGroup group) const
|
||||||
@ -139,6 +185,8 @@ ControllerEmu::ControlGroup* FreeLookController::GetGroup(FreeLookGroup group) c
|
|||||||
return m_fov_buttons;
|
return m_fov_buttons;
|
||||||
case FreeLookGroup::Other:
|
case FreeLookGroup::Other:
|
||||||
return m_other_buttons;
|
return m_other_buttons;
|
||||||
|
case FreeLookGroup::Rotation:
|
||||||
|
return m_rotation_gyro;
|
||||||
default:
|
default:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -151,41 +199,63 @@ void FreeLookController::Update()
|
|||||||
|
|
||||||
const auto lock = GetStateLock();
|
const auto lock = GetStateLock();
|
||||||
|
|
||||||
|
float dt = 1.0;
|
||||||
|
if (m_last_free_look_rotate_time)
|
||||||
|
{
|
||||||
|
using seconds = std::chrono::duration<float, std::ratio<1>>;
|
||||||
|
dt = std::chrono::duration_cast<seconds>(std::chrono::steady_clock::now() -
|
||||||
|
*m_last_free_look_rotate_time)
|
||||||
|
.count();
|
||||||
|
}
|
||||||
|
m_last_free_look_rotate_time = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
const auto gyro_motion_rad_velocity =
|
||||||
|
m_rotation_gyro->GetState() ? *m_rotation_gyro->GetState() : Common::Vec3{};
|
||||||
|
|
||||||
|
// Due to gyroscope implementation we need to swap the yaw and roll values
|
||||||
|
// and because of the different axis used for Wii and the PS3 motion directions,
|
||||||
|
// we need to invert the yaw and roll as well
|
||||||
|
const Common::Vec3 gyro_motion_rad_velocity_converted{
|
||||||
|
gyro_motion_rad_velocity.x, gyro_motion_rad_velocity.z * -1, gyro_motion_rad_velocity.y * -1};
|
||||||
|
const auto gyro_motion_quat =
|
||||||
|
Common::Quaternion::RotateXYZ(gyro_motion_rad_velocity_converted * dt);
|
||||||
|
|
||||||
|
g_freelook_camera.Rotate(gyro_motion_quat);
|
||||||
if (m_move_buttons->controls[MoveButtons::Up]->GetState<bool>())
|
if (m_move_buttons->controls[MoveButtons::Up]->GetState<bool>())
|
||||||
g_freelook_camera.MoveVertical(-g_freelook_camera.GetSpeed());
|
g_freelook_camera.MoveVertical(-g_freelook_camera.GetSpeed() * dt);
|
||||||
|
|
||||||
if (m_move_buttons->controls[MoveButtons::Down]->GetState<bool>())
|
if (m_move_buttons->controls[MoveButtons::Down]->GetState<bool>())
|
||||||
g_freelook_camera.MoveVertical(g_freelook_camera.GetSpeed());
|
g_freelook_camera.MoveVertical(g_freelook_camera.GetSpeed() * dt);
|
||||||
|
|
||||||
if (m_move_buttons->controls[MoveButtons::Left]->GetState<bool>())
|
if (m_move_buttons->controls[MoveButtons::Left]->GetState<bool>())
|
||||||
g_freelook_camera.MoveHorizontal(g_freelook_camera.GetSpeed());
|
g_freelook_camera.MoveHorizontal(g_freelook_camera.GetSpeed() * dt);
|
||||||
|
|
||||||
if (m_move_buttons->controls[MoveButtons::Right]->GetState<bool>())
|
if (m_move_buttons->controls[MoveButtons::Right]->GetState<bool>())
|
||||||
g_freelook_camera.MoveHorizontal(-g_freelook_camera.GetSpeed());
|
g_freelook_camera.MoveHorizontal(-g_freelook_camera.GetSpeed() * dt);
|
||||||
|
|
||||||
if (m_move_buttons->controls[MoveButtons::Forward]->GetState<bool>())
|
if (m_move_buttons->controls[MoveButtons::Forward]->GetState<bool>())
|
||||||
g_freelook_camera.MoveForward(g_freelook_camera.GetSpeed());
|
g_freelook_camera.MoveForward(g_freelook_camera.GetSpeed() * dt);
|
||||||
|
|
||||||
if (m_move_buttons->controls[MoveButtons::Backward]->GetState<bool>())
|
if (m_move_buttons->controls[MoveButtons::Backward]->GetState<bool>())
|
||||||
g_freelook_camera.MoveForward(-g_freelook_camera.GetSpeed());
|
g_freelook_camera.MoveForward(-g_freelook_camera.GetSpeed() * dt);
|
||||||
|
|
||||||
if (m_fov_buttons->controls[FieldOfViewButtons::IncreaseX]->GetState<bool>())
|
if (m_fov_buttons->controls[FieldOfViewButtons::IncreaseX]->GetState<bool>())
|
||||||
g_freelook_camera.IncreaseFovX(g_freelook_camera.GetFovStepSize());
|
g_freelook_camera.IncreaseFovX(g_freelook_camera.GetFovStepSize() * dt);
|
||||||
|
|
||||||
if (m_fov_buttons->controls[FieldOfViewButtons::DecreaseX]->GetState<bool>())
|
if (m_fov_buttons->controls[FieldOfViewButtons::DecreaseX]->GetState<bool>())
|
||||||
g_freelook_camera.IncreaseFovX(-1.0f * g_freelook_camera.GetFovStepSize());
|
g_freelook_camera.IncreaseFovX(-1.0f * g_freelook_camera.GetFovStepSize() * dt);
|
||||||
|
|
||||||
if (m_fov_buttons->controls[FieldOfViewButtons::IncreaseY]->GetState<bool>())
|
if (m_fov_buttons->controls[FieldOfViewButtons::IncreaseY]->GetState<bool>())
|
||||||
g_freelook_camera.IncreaseFovY(g_freelook_camera.GetFovStepSize());
|
g_freelook_camera.IncreaseFovY(g_freelook_camera.GetFovStepSize() * dt);
|
||||||
|
|
||||||
if (m_fov_buttons->controls[FieldOfViewButtons::DecreaseY]->GetState<bool>())
|
if (m_fov_buttons->controls[FieldOfViewButtons::DecreaseY]->GetState<bool>())
|
||||||
g_freelook_camera.IncreaseFovY(-1.0f * g_freelook_camera.GetFovStepSize());
|
g_freelook_camera.IncreaseFovY(-1.0f * g_freelook_camera.GetFovStepSize() * dt);
|
||||||
|
|
||||||
if (m_speed_buttons->controls[SpeedButtons::Decrease]->GetState<bool>())
|
if (m_speed_buttons->controls[SpeedButtons::Decrease]->GetState<bool>())
|
||||||
g_freelook_camera.ModifySpeed(1.0f / 1.1f);
|
g_freelook_camera.ModifySpeed(g_freelook_camera.GetSpeed() * -0.9 * dt);
|
||||||
|
|
||||||
if (m_speed_buttons->controls[SpeedButtons::Increase]->GetState<bool>())
|
if (m_speed_buttons->controls[SpeedButtons::Increase]->GetState<bool>())
|
||||||
g_freelook_camera.ModifySpeed(1.1f);
|
g_freelook_camera.ModifySpeed(g_freelook_camera.GetSpeed() * 1.1 * dt);
|
||||||
|
|
||||||
if (m_speed_buttons->controls[SpeedButtons::Reset]->GetState<bool>())
|
if (m_speed_buttons->controls[SpeedButtons::Reset]->GetState<bool>())
|
||||||
g_freelook_camera.ResetSpeed();
|
g_freelook_camera.ResetSpeed();
|
||||||
|
@ -4,6 +4,9 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "InputCommon/ControllerEmu/ControllerEmu.h"
|
#include "InputCommon/ControllerEmu/ControllerEmu.h"
|
||||||
|
|
||||||
@ -13,6 +16,7 @@ namespace ControllerEmu
|
|||||||
{
|
{
|
||||||
class ControlGroup;
|
class ControlGroup;
|
||||||
class Buttons;
|
class Buttons;
|
||||||
|
class IMUGyroscope;
|
||||||
} // namespace ControllerEmu
|
} // namespace ControllerEmu
|
||||||
|
|
||||||
enum class FreeLookGroup
|
enum class FreeLookGroup
|
||||||
@ -20,7 +24,8 @@ enum class FreeLookGroup
|
|||||||
Move,
|
Move,
|
||||||
Speed,
|
Speed,
|
||||||
FieldOfView,
|
FieldOfView,
|
||||||
Other
|
Other,
|
||||||
|
Rotation,
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace FreeLook
|
namespace FreeLook
|
||||||
@ -52,6 +57,8 @@ private:
|
|||||||
ControllerEmu::Buttons* m_speed_buttons;
|
ControllerEmu::Buttons* m_speed_buttons;
|
||||||
ControllerEmu::Buttons* m_fov_buttons;
|
ControllerEmu::Buttons* m_fov_buttons;
|
||||||
ControllerEmu::Buttons* m_other_buttons;
|
ControllerEmu::Buttons* m_other_buttons;
|
||||||
|
ControllerEmu::IMUGyroscope* m_rotation_gyro;
|
||||||
|
|
||||||
const unsigned int m_index;
|
const unsigned int m_index;
|
||||||
|
std::optional<std::chrono::steady_clock::time_point> m_last_free_look_rotate_time;
|
||||||
};
|
};
|
||||||
|
@ -655,6 +655,7 @@ void UpdateDevices()
|
|||||||
|
|
||||||
// Update inputs at the rate of SI
|
// Update inputs at the rate of SI
|
||||||
// Typically 120hz but is variable
|
// Typically 120hz but is variable
|
||||||
|
g_controller_interface.SetCurrentInputChannel(ciface::InputChannel::SerialInterface);
|
||||||
g_controller_interface.UpdateInput();
|
g_controller_interface.UpdateInput();
|
||||||
|
|
||||||
// Update channels and set the status bit if there's new data
|
// Update channels and set the status bit if there's new data
|
||||||
|
@ -339,6 +339,7 @@ void BluetoothEmuDevice::Update()
|
|||||||
|
|
||||||
if (now - m_last_ticks > interval)
|
if (now - m_last_ticks > interval)
|
||||||
{
|
{
|
||||||
|
g_controller_interface.SetCurrentInputChannel(ciface::InputChannel::Bluetooth);
|
||||||
g_controller_interface.UpdateInput();
|
g_controller_interface.UpdateInput();
|
||||||
for (auto& wiimote : m_wiimotes)
|
for (auto& wiimote : m_wiimotes)
|
||||||
wiimote->UpdateInput();
|
wiimote->UpdateInput();
|
||||||
|
@ -122,6 +122,8 @@ add_executable(dolphin-emu
|
|||||||
Config/LogWidget.h
|
Config/LogWidget.h
|
||||||
Config/Mapping/FreeLookGeneral.cpp
|
Config/Mapping/FreeLookGeneral.cpp
|
||||||
Config/Mapping/FreeLookGeneral.h
|
Config/Mapping/FreeLookGeneral.h
|
||||||
|
Config/Mapping/FreeLookRotation.cpp
|
||||||
|
Config/Mapping/FreeLookRotation.h
|
||||||
Config/Mapping/GCKeyboardEmu.cpp
|
Config/Mapping/GCKeyboardEmu.cpp
|
||||||
Config/Mapping/GCKeyboardEmu.h
|
Config/Mapping/GCKeyboardEmu.h
|
||||||
Config/Mapping/GCMicrophone.cpp
|
Config/Mapping/GCMicrophone.cpp
|
||||||
|
62
Source/Core/DolphinQt/Config/Mapping/FreeLookRotation.cpp
Normal file
62
Source/Core/DolphinQt/Config/Mapping/FreeLookRotation.cpp
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
// Copyright 2021 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "DolphinQt/Config/Mapping/FreeLookRotation.h"
|
||||||
|
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QPushButton>
|
||||||
|
|
||||||
|
#include "Core/FreeLookManager.h"
|
||||||
|
#include "DolphinQt/Config/ControllerInterface/ControllerInterfaceWindow.h"
|
||||||
|
#include "InputCommon/InputConfig.h"
|
||||||
|
|
||||||
|
FreeLookRotation::FreeLookRotation(MappingWindow* window) : MappingWidget(window)
|
||||||
|
{
|
||||||
|
CreateMainLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeLookRotation::CreateMainLayout()
|
||||||
|
{
|
||||||
|
m_main_layout = new QGridLayout;
|
||||||
|
|
||||||
|
auto* alternate_input_layout = new QHBoxLayout();
|
||||||
|
auto* note_label = new QLabel(
|
||||||
|
tr("Note: motion input may require configuring alternate input sources before use."));
|
||||||
|
note_label->setWordWrap(true);
|
||||||
|
auto* alternate_input_sources_button = new QPushButton(tr("Alternate Input Sources"));
|
||||||
|
alternate_input_layout->addWidget(note_label, 1);
|
||||||
|
alternate_input_layout->addWidget(alternate_input_sources_button, 0, Qt::AlignRight);
|
||||||
|
connect(alternate_input_sources_button, &QPushButton::clicked, this, [this] {
|
||||||
|
ControllerInterfaceWindow* window = new ControllerInterfaceWindow(this);
|
||||||
|
window->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||||
|
window->setWindowModality(Qt::WindowModality::WindowModal);
|
||||||
|
window->show();
|
||||||
|
});
|
||||||
|
m_main_layout->addLayout(alternate_input_layout, 0, 0, 1, -1);
|
||||||
|
|
||||||
|
m_main_layout->addWidget(
|
||||||
|
CreateGroupBox(tr("Incremental Rotation (rad/sec)"),
|
||||||
|
FreeLook::GetInputGroup(GetPort(), FreeLookGroup::Rotation)),
|
||||||
|
1, 0);
|
||||||
|
|
||||||
|
setLayout(m_main_layout);
|
||||||
|
}
|
||||||
|
|
||||||
|
InputConfig* FreeLookRotation::GetConfig()
|
||||||
|
{
|
||||||
|
return FreeLook::GetInputConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeLookRotation::LoadSettings()
|
||||||
|
{
|
||||||
|
FreeLook::LoadInputConfig();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FreeLookRotation::SaveSettings()
|
||||||
|
{
|
||||||
|
FreeLook::GetInputConfig()->SaveConfig();
|
||||||
|
}
|
26
Source/Core/DolphinQt/Config/Mapping/FreeLookRotation.h
Normal file
26
Source/Core/DolphinQt/Config/Mapping/FreeLookRotation.h
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2021 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "DolphinQt/Config/Mapping/MappingWidget.h"
|
||||||
|
|
||||||
|
class QGridLayout;
|
||||||
|
|
||||||
|
class FreeLookRotation final : public MappingWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit FreeLookRotation(MappingWindow* window);
|
||||||
|
|
||||||
|
InputConfig* GetConfig() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void LoadSettings() override;
|
||||||
|
void SaveSettings() override;
|
||||||
|
void CreateMainLayout();
|
||||||
|
|
||||||
|
// Main
|
||||||
|
QGridLayout* m_main_layout;
|
||||||
|
};
|
@ -23,6 +23,7 @@
|
|||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
|
||||||
#include "DolphinQt/Config/Mapping/FreeLookGeneral.h"
|
#include "DolphinQt/Config/Mapping/FreeLookGeneral.h"
|
||||||
|
#include "DolphinQt/Config/Mapping/FreeLookRotation.h"
|
||||||
#include "DolphinQt/Config/Mapping/GCKeyboardEmu.h"
|
#include "DolphinQt/Config/Mapping/GCKeyboardEmu.h"
|
||||||
#include "DolphinQt/Config/Mapping/GCMicrophone.h"
|
#include "DolphinQt/Config/Mapping/GCMicrophone.h"
|
||||||
#include "DolphinQt/Config/Mapping/GCPadEmu.h"
|
#include "DolphinQt/Config/Mapping/GCPadEmu.h"
|
||||||
@ -436,6 +437,7 @@ void MappingWindow::SetMappingType(MappingWindow::Type type)
|
|||||||
{
|
{
|
||||||
widget = new FreeLookGeneral(this);
|
widget = new FreeLookGeneral(this);
|
||||||
AddWidget(tr("General"), widget);
|
AddWidget(tr("General"), widget);
|
||||||
|
AddWidget(tr("Rotation"), new FreeLookRotation(this));
|
||||||
setWindowTitle(tr("Free Look Controller %1").arg(GetPort() + 1));
|
setWindowTitle(tr("Free Look Controller %1").arg(GetPort() + 1));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -80,6 +80,7 @@
|
|||||||
<ClCompile Include="Config\LogConfigWidget.cpp" />
|
<ClCompile Include="Config\LogConfigWidget.cpp" />
|
||||||
<ClCompile Include="Config\LogWidget.cpp" />
|
<ClCompile Include="Config\LogWidget.cpp" />
|
||||||
<ClCompile Include="Config\Mapping\FreeLookGeneral.cpp" />
|
<ClCompile Include="Config\Mapping\FreeLookGeneral.cpp" />
|
||||||
|
<ClCompile Include="Config\Mapping\FreeLookRotation.cpp" />
|
||||||
<ClCompile Include="Config\Mapping\GCKeyboardEmu.cpp" />
|
<ClCompile Include="Config\Mapping\GCKeyboardEmu.cpp" />
|
||||||
<ClCompile Include="Config\Mapping\GCMicrophone.cpp" />
|
<ClCompile Include="Config\Mapping\GCMicrophone.cpp" />
|
||||||
<ClCompile Include="Config\Mapping\GCPadEmu.cpp" />
|
<ClCompile Include="Config\Mapping\GCPadEmu.cpp" />
|
||||||
@ -254,6 +255,7 @@
|
|||||||
<QtMoc Include="Config\LogConfigWidget.h" />
|
<QtMoc Include="Config\LogConfigWidget.h" />
|
||||||
<QtMoc Include="Config\LogWidget.h" />
|
<QtMoc Include="Config\LogWidget.h" />
|
||||||
<QtMoc Include="Config\Mapping\FreeLookGeneral.h" />
|
<QtMoc Include="Config\Mapping\FreeLookGeneral.h" />
|
||||||
|
<QtMoc Include="Config\Mapping\FreeLookRotation.h" />
|
||||||
<QtMoc Include="Config\Mapping\GCKeyboardEmu.h" />
|
<QtMoc Include="Config\Mapping\GCKeyboardEmu.h" />
|
||||||
<QtMoc Include="Config\Mapping\GCMicrophone.h" />
|
<QtMoc Include="Config\Mapping\GCMicrophone.h" />
|
||||||
<QtMoc Include="Config\Mapping\GCPadEmu.h" />
|
<QtMoc Include="Config\Mapping\GCPadEmu.h" />
|
||||||
|
@ -139,10 +139,14 @@ void HotkeyScheduler::Run()
|
|||||||
|
|
||||||
while (!m_stop_requested.IsSet())
|
while (!m_stop_requested.IsSet())
|
||||||
{
|
{
|
||||||
Common::SleepCurrentThread(1000 / 60);
|
Common::SleepCurrentThread(5);
|
||||||
|
|
||||||
if (Core::GetState() == Core::State::Uninitialized || Core::GetState() == Core::State::Paused)
|
g_controller_interface.SetCurrentInputChannel(ciface::InputChannel::FreeLook);
|
||||||
g_controller_interface.UpdateInput();
|
g_controller_interface.UpdateInput();
|
||||||
|
FreeLook::UpdateInput();
|
||||||
|
|
||||||
|
g_controller_interface.SetCurrentInputChannel(ciface::InputChannel::Host);
|
||||||
|
g_controller_interface.UpdateInput();
|
||||||
|
|
||||||
if (!HotkeyManagerEmu::IsEnabled())
|
if (!HotkeyManagerEmu::IsEnabled())
|
||||||
continue;
|
continue;
|
||||||
@ -546,8 +550,6 @@ void HotkeyScheduler::Run()
|
|||||||
OSD::AddMessage(StringFromFormat("Free Look: %s", new_value ? "Enabled" : "Disabled"));
|
OSD::AddMessage(StringFromFormat("Free Look: %s", new_value ? "Enabled" : "Disabled"));
|
||||||
}
|
}
|
||||||
|
|
||||||
FreeLook::UpdateInput();
|
|
||||||
|
|
||||||
// Savestates
|
// Savestates
|
||||||
for (u32 i = 0; i < State::NUM_STATES; i++)
|
for (u32 i = 0; i < State::NUM_STATES; i++)
|
||||||
{
|
{
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Flag.h"
|
#include "Common/Flag.h"
|
||||||
#include "InputCommon/InputProfile.h"
|
#include "InputCommon/InputProfile.h"
|
||||||
|
|
||||||
|
@ -32,9 +32,7 @@
|
|||||||
#include "DolphinQt/Resources.h"
|
#include "DolphinQt/Resources.h"
|
||||||
#include "DolphinQt/Settings.h"
|
#include "DolphinQt/Settings.h"
|
||||||
|
|
||||||
#include "VideoCommon/FreeLookCamera.h"
|
|
||||||
#include "VideoCommon/RenderBase.h"
|
#include "VideoCommon/RenderBase.h"
|
||||||
#include "VideoCommon/VertexShaderManager.h"
|
|
||||||
#include "VideoCommon/VideoConfig.h"
|
#include "VideoCommon/VideoConfig.h"
|
||||||
|
|
||||||
RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent)
|
RenderWidget::RenderWidget(QWidget* parent) : QWidget(parent)
|
||||||
@ -180,11 +178,6 @@ bool RenderWidget::event(QEvent* event)
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case QEvent::MouseMove:
|
|
||||||
if (g_freelook_camera.IsActive())
|
|
||||||
OnFreeLookMouseMove(static_cast<QMouseEvent*>(event));
|
|
||||||
[[fallthrough]];
|
|
||||||
|
|
||||||
case QEvent::MouseButtonPress:
|
case QEvent::MouseButtonPress:
|
||||||
if (!Settings::Instance().GetHideCursor() && isActiveWindow())
|
if (!Settings::Instance().GetHideCursor() && isActiveWindow())
|
||||||
{
|
{
|
||||||
@ -237,23 +230,6 @@ bool RenderWidget::event(QEvent* event)
|
|||||||
return QWidget::event(event);
|
return QWidget::event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderWidget::OnFreeLookMouseMove(QMouseEvent* event)
|
|
||||||
{
|
|
||||||
const auto mouse_move = event->pos() - m_last_mouse;
|
|
||||||
m_last_mouse = event->pos();
|
|
||||||
|
|
||||||
if (event->buttons() & Qt::RightButton)
|
|
||||||
{
|
|
||||||
// Camera Pitch and Yaw:
|
|
||||||
g_freelook_camera.Rotate(Common::Vec3{mouse_move.y() / 200.f, mouse_move.x() / 200.f, 0.f});
|
|
||||||
}
|
|
||||||
else if (event->buttons() & Qt::MiddleButton)
|
|
||||||
{
|
|
||||||
// Camera Roll:
|
|
||||||
g_freelook_camera.Rotate({0.f, 0.f, mouse_move.x() / 200.f});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RenderWidget::PassEventToImGui(const QEvent* event)
|
void RenderWidget::PassEventToImGui(const QEvent* event)
|
||||||
{
|
{
|
||||||
if (!Core::IsRunningAndStarted())
|
if (!Core::IsRunningAndStarted())
|
||||||
|
@ -33,7 +33,6 @@ private:
|
|||||||
void HandleCursorTimer();
|
void HandleCursorTimer();
|
||||||
void OnHideCursorChanged();
|
void OnHideCursorChanged();
|
||||||
void OnKeepOnTopChanged(bool top);
|
void OnKeepOnTopChanged(bool top);
|
||||||
void OnFreeLookMouseMove(QMouseEvent* event);
|
|
||||||
void PassEventToImGui(const QEvent* event);
|
void PassEventToImGui(const QEvent* event);
|
||||||
void SetImGuiKeyMap();
|
void SetImGuiKeyMap();
|
||||||
void dragEnterEvent(QDragEnterEvent* event) override;
|
void dragEnterEvent(QDragEnterEvent* event) override;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.h"
|
#include "InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "Common/Common.h"
|
#include "Common/Common.h"
|
||||||
@ -124,7 +125,8 @@ auto IMUGyroscope::GetRawState() const -> StateData
|
|||||||
|
|
||||||
std::optional<IMUGyroscope::StateData> IMUGyroscope::GetState() const
|
std::optional<IMUGyroscope::StateData> IMUGyroscope::GetState() const
|
||||||
{
|
{
|
||||||
if (controls[0]->control_ref->BoundCount() == 0)
|
if (std::all_of(controls.begin(), controls.end(),
|
||||||
|
[](const auto& control) { return control->control_ref->BoundCount() == 0; }))
|
||||||
{
|
{
|
||||||
// Set calibration to zero.
|
// Set calibration to zero.
|
||||||
m_calibration = {};
|
m_calibration = {};
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
|
|
||||||
ControllerInterface g_controller_interface;
|
ControllerInterface g_controller_interface;
|
||||||
|
|
||||||
|
static thread_local ciface::InputChannel tls_input_channel = ciface::InputChannel::Host;
|
||||||
|
|
||||||
void ControllerInterface::Initialize(const WindowSystemInfo& wsi)
|
void ControllerInterface::Initialize(const WindowSystemInfo& wsi)
|
||||||
{
|
{
|
||||||
if (m_is_init)
|
if (m_is_init)
|
||||||
@ -274,6 +276,16 @@ void ControllerInterface::UpdateInput()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ControllerInterface::SetCurrentInputChannel(ciface::InputChannel input_channel)
|
||||||
|
{
|
||||||
|
tls_input_channel = input_channel;
|
||||||
|
}
|
||||||
|
|
||||||
|
ciface::InputChannel ControllerInterface::GetCurrentInputChannel()
|
||||||
|
{
|
||||||
|
return tls_input_channel;
|
||||||
|
}
|
||||||
|
|
||||||
void ControllerInterface::SetAspectRatioAdjustment(float value)
|
void ControllerInterface::SetAspectRatioAdjustment(float value)
|
||||||
{
|
{
|
||||||
m_aspect_ratio_adjustment = value;
|
m_aspect_ratio_adjustment = value;
|
||||||
|
@ -32,6 +32,23 @@
|
|||||||
#endif
|
#endif
|
||||||
#define CIFACE_USE_DUALSHOCKUDPCLIENT
|
#define CIFACE_USE_DUALSHOCKUDPCLIENT
|
||||||
|
|
||||||
|
namespace ciface
|
||||||
|
{
|
||||||
|
// A thread local "input channel" is maintained to handle the state of relative inputs.
|
||||||
|
// This allows simultaneous use of relative inputs across different input contexts.
|
||||||
|
// e.g. binding relative mouse movements to both GameCube controllers and FreeLook.
|
||||||
|
// These operate at different rates and processing one would break the other without separate state.
|
||||||
|
enum class InputChannel
|
||||||
|
{
|
||||||
|
Host,
|
||||||
|
SerialInterface,
|
||||||
|
Bluetooth,
|
||||||
|
FreeLook,
|
||||||
|
Count,
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ciface
|
||||||
|
|
||||||
//
|
//
|
||||||
// ControllerInterface
|
// ControllerInterface
|
||||||
//
|
//
|
||||||
@ -66,6 +83,9 @@ public:
|
|||||||
void UnregisterDevicesChangedCallback(const HotplugCallbackHandle& handle);
|
void UnregisterDevicesChangedCallback(const HotplugCallbackHandle& handle);
|
||||||
void InvokeDevicesChangedCallbacks() const;
|
void InvokeDevicesChangedCallbacks() const;
|
||||||
|
|
||||||
|
static void SetCurrentInputChannel(ciface::InputChannel);
|
||||||
|
static ciface::InputChannel GetCurrentInputChannel();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::list<std::function<void()>> m_devices_changed_callbacks;
|
std::list<std::function<void()>> m_devices_changed_callbacks;
|
||||||
mutable std::mutex m_callbacks_mutex;
|
mutable std::mutex m_callbacks_mutex;
|
||||||
@ -75,4 +95,37 @@ private:
|
|||||||
std::atomic<float> m_aspect_ratio_adjustment = 1;
|
std::atomic<float> m_aspect_ratio_adjustment = 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace ciface
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
class RelativeInputState
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void Update()
|
||||||
|
{
|
||||||
|
const auto channel = int(ControllerInterface::GetCurrentInputChannel());
|
||||||
|
|
||||||
|
m_value[channel] = m_delta[channel];
|
||||||
|
m_delta[channel] = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
T GetValue() const
|
||||||
|
{
|
||||||
|
const auto channel = int(ControllerInterface::GetCurrentInputChannel());
|
||||||
|
|
||||||
|
return m_value[channel];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Move(T delta)
|
||||||
|
{
|
||||||
|
for (auto& d : m_delta)
|
||||||
|
d += delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::array<T, int(InputChannel::Count)> m_value;
|
||||||
|
std::array<T, int(InputChannel::Count)> m_delta;
|
||||||
|
};
|
||||||
|
} // namespace ciface
|
||||||
|
|
||||||
extern ControllerInterface g_controller_interface;
|
extern ControllerInterface g_controller_interface;
|
||||||
|
@ -93,6 +93,12 @@ public:
|
|||||||
virtual bool IsChild(const Input*) const { return false; }
|
virtual bool IsChild(const Input*) const { return false; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RelativeInput : public Input
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
bool IsDetectable() const override { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
//
|
//
|
||||||
// Output
|
// Output
|
||||||
//
|
//
|
||||||
|
@ -2,11 +2,14 @@
|
|||||||
// Licensed under GPLv2+
|
// Licensed under GPLv2+
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include <fmt/format.h>
|
||||||
|
|
||||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||||
#include "InputCommon/ControllerInterface/DInput/DInput.h"
|
#include "InputCommon/ControllerInterface/DInput/DInput.h"
|
||||||
#include "InputCommon/ControllerInterface/DInput/DInputKeyboardMouse.h"
|
|
||||||
|
|
||||||
// (lower would be more sensitive) user can lower sensitivity by setting range
|
// (lower would be more sensitive) user can lower sensitivity by setting range
|
||||||
// seems decent here ( at 8 ), I don't think anyone would need more sensitive than this
|
// seems decent here ( at 8 ), I don't think anyone would need more sensitive than this
|
||||||
@ -19,6 +22,30 @@
|
|||||||
|
|
||||||
namespace ciface::DInput
|
namespace ciface::DInput
|
||||||
{
|
{
|
||||||
|
class RelativeMouseAxis final : public Core::Device::RelativeInput
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string GetName() const override
|
||||||
|
{
|
||||||
|
return fmt::format("RelativeMouse {}{}", char('X' + m_index), (m_scale > 0) ? '+' : '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
RelativeMouseAxis(u8 index, bool positive, const RelativeMouseState* state)
|
||||||
|
: m_state(*state), m_index(index), m_scale(positive * 2 - 1)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlState GetState() const override
|
||||||
|
{
|
||||||
|
return ControlState(m_state.GetValue().data[m_index] * m_scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const RelativeMouseState& m_state;
|
||||||
|
const u8 m_index;
|
||||||
|
const s8 m_scale;
|
||||||
|
};
|
||||||
|
|
||||||
static const struct
|
static const struct
|
||||||
{
|
{
|
||||||
const BYTE code;
|
const BYTE code;
|
||||||
@ -108,9 +135,17 @@ KeyboardMouse::KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device,
|
|||||||
AddInput(new Axis(i, ax, (2 == i) ? -1 : -MOUSE_AXIS_SENSITIVITY));
|
AddInput(new Axis(i, ax, (2 == i) ? -1 : -MOUSE_AXIS_SENSITIVITY));
|
||||||
AddInput(new Axis(i, ax, -(2 == i) ? 1 : MOUSE_AXIS_SENSITIVITY));
|
AddInput(new Axis(i, ax, -(2 == i) ? 1 : MOUSE_AXIS_SENSITIVITY));
|
||||||
}
|
}
|
||||||
|
|
||||||
// cursor, with a hax for-loop
|
// cursor, with a hax for-loop
|
||||||
for (unsigned int i = 0; i < 4; ++i)
|
for (unsigned int i = 0; i < 4; ++i)
|
||||||
AddInput(new Cursor(!!(i & 2), (&m_state_in.cursor.x)[i / 2], !!(i & 1)));
|
AddInput(new Cursor(!!(i & 2), (&m_state_in.cursor.x)[i / 2], !!(i & 1)));
|
||||||
|
|
||||||
|
// Raw relative mouse movement.
|
||||||
|
for (unsigned int i = 0; i != mouse_caps.dwAxes; ++i)
|
||||||
|
{
|
||||||
|
AddInput(new RelativeMouseAxis(i, false, &m_state_in.relative_mouse));
|
||||||
|
AddInput(new RelativeMouseAxis(i, true, &m_state_in.relative_mouse));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void KeyboardMouse::UpdateCursorInput()
|
void KeyboardMouse::UpdateCursorInput()
|
||||||
@ -147,6 +182,8 @@ void KeyboardMouse::UpdateInput()
|
|||||||
{
|
{
|
||||||
// set axes to zero
|
// set axes to zero
|
||||||
m_state_in.mouse = {};
|
m_state_in.mouse = {};
|
||||||
|
m_state_in.relative_mouse = {};
|
||||||
|
|
||||||
// skip this input state
|
// skip this input state
|
||||||
m_mo_device->GetDeviceState(sizeof(tmp_mouse), &tmp_mouse);
|
m_mo_device->GetDeviceState(sizeof(tmp_mouse), &tmp_mouse);
|
||||||
}
|
}
|
||||||
@ -162,14 +199,17 @@ void KeyboardMouse::UpdateInput()
|
|||||||
if (DIERR_INPUTLOST == mo_hr || DIERR_NOTACQUIRED == mo_hr)
|
if (DIERR_INPUTLOST == mo_hr || DIERR_NOTACQUIRED == mo_hr)
|
||||||
m_mo_device->Acquire();
|
m_mo_device->Acquire();
|
||||||
|
|
||||||
if (SUCCEEDED(kb_hr) && SUCCEEDED(mo_hr))
|
if (SUCCEEDED(mo_hr))
|
||||||
{
|
{
|
||||||
|
m_state_in.relative_mouse.Move({tmp_mouse.lX, tmp_mouse.lY, tmp_mouse.lZ});
|
||||||
|
m_state_in.relative_mouse.Update();
|
||||||
|
|
||||||
// need to smooth out the axes, otherwise it doesn't work for shit
|
// need to smooth out the axes, otherwise it doesn't work for shit
|
||||||
for (unsigned int i = 0; i < 3; ++i)
|
for (unsigned int i = 0; i < 3; ++i)
|
||||||
((&m_state_in.mouse.lX)[i] += (&tmp_mouse.lX)[i]) /= 2;
|
((&m_state_in.mouse.lX)[i] += (&tmp_mouse.lX)[i]) /= 2;
|
||||||
|
|
||||||
// copy over the buttons
|
// copy over the buttons
|
||||||
memcpy(m_state_in.mouse.rgbButtons, tmp_mouse.rgbButtons, sizeof(m_state_in.mouse.rgbButtons));
|
std::copy_n(tmp_mouse.rgbButtons, std::size(tmp_mouse.rgbButtons), m_state_in.mouse.rgbButtons);
|
||||||
|
|
||||||
UpdateCursorInput();
|
UpdateCursorInput();
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
#include "Common/Matrix.h"
|
#include "Common/Matrix.h"
|
||||||
|
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||||
#include "InputCommon/ControllerInterface/CoreDevice.h"
|
#include "InputCommon/ControllerInterface/CoreDevice.h"
|
||||||
#include "InputCommon/ControllerInterface/DInput/DInput8.h"
|
#include "InputCommon/ControllerInterface/DInput/DInput8.h"
|
||||||
|
|
||||||
@ -14,14 +15,23 @@ namespace ciface::DInput
|
|||||||
{
|
{
|
||||||
void InitKeyboardMouse(IDirectInput8* const idi8, HWND hwnd);
|
void InitKeyboardMouse(IDirectInput8* const idi8, HWND hwnd);
|
||||||
|
|
||||||
|
using RelativeMouseState = RelativeInputState<Common::TVec3<LONG>>;
|
||||||
|
|
||||||
class KeyboardMouse : public Core::Device
|
class KeyboardMouse : public Core::Device
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
struct State
|
struct State
|
||||||
{
|
{
|
||||||
BYTE keyboard[256];
|
BYTE keyboard[256];
|
||||||
|
|
||||||
|
// Old smoothed relative mouse movement.
|
||||||
DIMOUSESTATE2 mouse;
|
DIMOUSESTATE2 mouse;
|
||||||
|
|
||||||
|
// Normalized mouse cursor position.
|
||||||
Common::TVec2<ControlState> cursor;
|
Common::TVec2<ControlState> cursor;
|
||||||
|
|
||||||
|
// Raw relative mouse movement.
|
||||||
|
RelativeMouseState relative_mouse;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Key : public Input
|
class Key : public Input
|
||||||
@ -53,6 +63,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
Axis(u8 index, const LONG& axis, LONG range) : m_axis(axis), m_range(range), m_index(index) {}
|
Axis(u8 index, const LONG& axis, LONG range) : m_axis(axis), m_range(range), m_index(index) {}
|
||||||
std::string GetName() const override;
|
std::string GetName() const override;
|
||||||
|
bool IsDetectable() const override { return false; }
|
||||||
ControlState GetState() const override;
|
ControlState GetState() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -197,6 +197,11 @@ KeyboardMouse::KeyboardMouse(Window window, int opcode, int pointer, int keyboar
|
|||||||
// Mouse Axis, X-/+ and Y-/+
|
// Mouse Axis, X-/+ and Y-/+
|
||||||
for (int i = 0; i != 4; ++i)
|
for (int i = 0; i != 4; ++i)
|
||||||
AddInput(new Axis(!!(i & 2), !!(i & 1), (i & 2) ? &m_state.axis.y : &m_state.axis.x));
|
AddInput(new Axis(!!(i & 2), !!(i & 1), (i & 2) ? &m_state.axis.y : &m_state.axis.x));
|
||||||
|
|
||||||
|
// Relative Mouse, X-/+ and Y-/+
|
||||||
|
for (int i = 0; i != 4; ++i)
|
||||||
|
AddInput(new RelativeMouse(!!(i & 2), !!(i & 1),
|
||||||
|
(i & 2) ? &m_state.relative_mouse.y : &m_state.relative_mouse.x));
|
||||||
}
|
}
|
||||||
|
|
||||||
KeyboardMouse::~KeyboardMouse()
|
KeyboardMouse::~KeyboardMouse()
|
||||||
@ -302,6 +307,9 @@ void KeyboardMouse::UpdateInput()
|
|||||||
XFreeEventData(m_display, &event.xcookie);
|
XFreeEventData(m_display, &event.xcookie);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_state.relative_mouse.x = delta_x;
|
||||||
|
m_state.relative_mouse.y = delta_y;
|
||||||
|
|
||||||
// apply axis smoothing
|
// apply axis smoothing
|
||||||
m_state.axis.x *= MOUSE_AXIS_SMOOTHING;
|
m_state.axis.x *= MOUSE_AXIS_SMOOTHING;
|
||||||
m_state.axis.x += delta_x;
|
m_state.axis.x += delta_x;
|
||||||
@ -391,8 +399,20 @@ KeyboardMouse::Axis::Axis(u8 index, bool positive, const float* axis)
|
|||||||
name = fmt::format("Axis {}{}", static_cast<char>('X' + m_index), (m_positive ? '+' : '-'));
|
name = fmt::format("Axis {}{}", static_cast<char>('X' + m_index), (m_positive ? '+' : '-'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
KeyboardMouse::RelativeMouse::RelativeMouse(u8 index, bool positive, const float* axis)
|
||||||
|
: m_axis(axis), m_index(index), m_positive(positive)
|
||||||
|
{
|
||||||
|
name =
|
||||||
|
fmt::format("RelativeMouse {}{}", static_cast<char>('X' + m_index), (m_positive ? '+' : '-'));
|
||||||
|
}
|
||||||
|
|
||||||
ControlState KeyboardMouse::Axis::GetState() const
|
ControlState KeyboardMouse::Axis::GetState() const
|
||||||
{
|
{
|
||||||
return std::max(0.0f, *m_axis / (m_positive ? MOUSE_AXIS_SENSITIVITY : -MOUSE_AXIS_SENSITIVITY));
|
return std::max(0.0f, *m_axis / (m_positive ? MOUSE_AXIS_SENSITIVITY : -MOUSE_AXIS_SENSITIVITY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ControlState KeyboardMouse::RelativeMouse::GetState() const
|
||||||
|
{
|
||||||
|
return std::max(0.0f, *m_axis / (m_positive ? MOUSE_AXIS_SENSITIVITY : -MOUSE_AXIS_SENSITIVITY));
|
||||||
|
}
|
||||||
} // namespace ciface::XInput2
|
} // namespace ciface::XInput2
|
||||||
|
@ -30,6 +30,7 @@ private:
|
|||||||
unsigned int buttons;
|
unsigned int buttons;
|
||||||
Common::Vec2 cursor;
|
Common::Vec2 cursor;
|
||||||
Common::Vec2 axis;
|
Common::Vec2 axis;
|
||||||
|
Common::Vec2 relative_mouse;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Key : public Input
|
class Key : public Input
|
||||||
@ -91,6 +92,21 @@ private:
|
|||||||
std::string name;
|
std::string name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class RelativeMouse : public Input
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
std::string GetName() const override { return name; }
|
||||||
|
bool IsDetectable() const override { return false; }
|
||||||
|
RelativeMouse(u8 index, bool positive, const float* axis);
|
||||||
|
ControlState GetState() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
const float* m_axis;
|
||||||
|
const u8 m_index;
|
||||||
|
const bool m_positive;
|
||||||
|
std::string name;
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SelectEventsForDevice(XIEventMask* mask, int deviceid);
|
void SelectEventsForDevice(XIEventMask* mask, int deviceid);
|
||||||
void UpdateCursor();
|
void UpdateCursor();
|
||||||
|
@ -102,15 +102,20 @@ public:
|
|||||||
|
|
||||||
void Rotate(const Common::Vec3& amt) override
|
void Rotate(const Common::Vec3& amt) override
|
||||||
{
|
{
|
||||||
|
if (amt.Length() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
m_rotation += amt;
|
m_rotation += amt;
|
||||||
|
|
||||||
using Common::Quaternion;
|
using Common::Quaternion;
|
||||||
const auto quat =
|
m_rotate_quat =
|
||||||
(Quaternion::RotateX(m_rotation.x) * Quaternion::RotateY(m_rotation.y)).Normalized();
|
(Quaternion::RotateX(m_rotation.x) * Quaternion::RotateY(m_rotation.y)).Normalized();
|
||||||
Rotate(quat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rotate(const Common::Quaternion& quat) override { m_rotate_quat = quat; }
|
void Rotate(const Common::Quaternion& quat) override
|
||||||
|
{
|
||||||
|
Rotate(Common::FromQuaternionToEuler(quat));
|
||||||
|
}
|
||||||
|
|
||||||
void Reset() override
|
void Reset() override
|
||||||
{
|
{
|
||||||
@ -153,15 +158,20 @@ public:
|
|||||||
|
|
||||||
void Rotate(const Common::Vec3& amt) override
|
void Rotate(const Common::Vec3& amt) override
|
||||||
{
|
{
|
||||||
|
if (amt.Length() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
m_rotation += amt;
|
m_rotation += amt;
|
||||||
|
|
||||||
using Common::Quaternion;
|
using Common::Quaternion;
|
||||||
const auto quat =
|
m_rotate_quat =
|
||||||
(Quaternion::RotateX(m_rotation.x) * Quaternion::RotateY(m_rotation.y)).Normalized();
|
(Quaternion::RotateX(m_rotation.x) * Quaternion::RotateY(m_rotation.y)).Normalized();
|
||||||
Rotate(quat);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rotate(const Common::Quaternion& quat) override { m_rotate_quat = quat; }
|
void Rotate(const Common::Quaternion& quat) override
|
||||||
|
{
|
||||||
|
Rotate(Common::FromQuaternionToEuler(quat));
|
||||||
|
}
|
||||||
|
|
||||||
void Reset() override
|
void Reset() override
|
||||||
{
|
{
|
||||||
@ -246,21 +256,27 @@ void FreeLookCamera::Rotate(const Common::Vec3& amt)
|
|||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FreeLookCamera::Rotate(const Common::Quaternion& amt)
|
||||||
|
{
|
||||||
|
m_camera_controller->Rotate(amt);
|
||||||
|
m_dirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
void FreeLookCamera::IncreaseFovX(float fov)
|
void FreeLookCamera::IncreaseFovX(float fov)
|
||||||
{
|
{
|
||||||
m_fov_x += fov;
|
m_fov_x += fov;
|
||||||
m_fov_x = std::clamp(m_fov_x, m_fov_step_size, m_fov_x);
|
m_fov_x = std::clamp(m_fov_x, m_min_fov_multiplier, m_fov_x);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeLookCamera::IncreaseFovY(float fov)
|
void FreeLookCamera::IncreaseFovY(float fov)
|
||||||
{
|
{
|
||||||
m_fov_y += fov;
|
m_fov_y += fov;
|
||||||
m_fov_y = std::clamp(m_fov_y, m_fov_step_size, m_fov_y);
|
m_fov_y = std::clamp(m_fov_y, m_min_fov_multiplier, m_fov_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
float FreeLookCamera::GetFovStepSize() const
|
float FreeLookCamera::GetFovStepSize() const
|
||||||
{
|
{
|
||||||
return m_fov_step_size;
|
return 1.5f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeLookCamera::Reset()
|
void FreeLookCamera::Reset()
|
||||||
@ -271,14 +287,15 @@ void FreeLookCamera::Reset()
|
|||||||
m_dirty = true;
|
m_dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeLookCamera::ModifySpeed(float multiplier)
|
void FreeLookCamera::ModifySpeed(float amt)
|
||||||
{
|
{
|
||||||
m_speed *= multiplier;
|
m_speed += amt;
|
||||||
|
m_speed = std::clamp(m_speed, 0.0f, m_speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FreeLookCamera::ResetSpeed()
|
void FreeLookCamera::ResetSpeed()
|
||||||
{
|
{
|
||||||
m_speed = 1.0f;
|
m_speed = 60.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
float FreeLookCamera::GetSpeed() const
|
float FreeLookCamera::GetSpeed() const
|
||||||
|
@ -52,6 +52,7 @@ public:
|
|||||||
void MoveForward(float amt);
|
void MoveForward(float amt);
|
||||||
|
|
||||||
void Rotate(const Common::Vec3& amt);
|
void Rotate(const Common::Vec3& amt);
|
||||||
|
void Rotate(const Common::Quaternion& amt);
|
||||||
|
|
||||||
void IncreaseFovX(float fov);
|
void IncreaseFovX(float fov);
|
||||||
void IncreaseFovY(float fov);
|
void IncreaseFovY(float fov);
|
||||||
@ -77,8 +78,8 @@ private:
|
|||||||
std::optional<FreeLook::ControlType> m_current_type;
|
std::optional<FreeLook::ControlType> m_current_type;
|
||||||
std::unique_ptr<CameraController> m_camera_controller;
|
std::unique_ptr<CameraController> m_camera_controller;
|
||||||
|
|
||||||
float m_fov_step_size = 0.025f;
|
float m_min_fov_multiplier = 0.025f;
|
||||||
float m_speed = 1.0f;
|
float m_speed = 60.0f;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern FreeLookCamera g_freelook_camera;
|
extern FreeLookCamera g_freelook_camera;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user