dolphin/Source/Core/Core/FreeLookManager.cpp

348 lines
12 KiB
C++

// Copyright 2020 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "Core/FreeLookManager.h"
#include "Common/Common.h"
#include "Common/CommonTypes.h"
#include "Common/Config/Config.h"
#include "Core/ConfigManager.h"
#include "Core/FreeLookConfig.h"
#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h"
#include "InputCommon/ControllerEmu/ControlGroup/IMUGyroscope.h"
#include "InputCommon/InputConfig.h"
#include "VideoCommon/FreeLookCamera.h"
#include "VideoCommon/OnScreenDisplay.h"
namespace
{
namespace MoveButtons
{
enum MoveButtons
{
Up,
Down,
Left,
Right,
Forward,
Backward,
};
}
namespace SpeedButtons
{
enum SpeedButtons
{
Decrease,
Increase,
Reset,
};
}
namespace OtherButtons
{
enum OtherButtons
{
ResetView,
};
}
namespace FieldOfViewButtons
{
enum FieldOfViewButtons
{
IncreaseX,
DecreaseX,
IncreaseY,
DecreaseY,
};
}
namespace GyroButtons
{
enum GyroButtons
{
PitchUp,
PitchDown,
RollLeft,
RollRight,
YawLeft,
YawRight,
};
}
} // namespace
FreeLookController::FreeLookController(const unsigned int index) : m_index(index)
{
groups.emplace_back(m_move_buttons = new ControllerEmu::Buttons(_trans("Move")));
m_move_buttons->AddInput(ControllerEmu::Translate, _trans("Up"));
m_move_buttons->AddInput(ControllerEmu::Translate, _trans("Down"));
m_move_buttons->AddInput(ControllerEmu::Translate, _trans("Left"));
m_move_buttons->AddInput(ControllerEmu::Translate, _trans("Right"));
m_move_buttons->AddInput(ControllerEmu::Translate, _trans("Forward"));
m_move_buttons->AddInput(ControllerEmu::Translate, _trans("Backward"));
groups.emplace_back(m_speed_buttons = new ControllerEmu::Buttons(_trans("Speed")));
m_speed_buttons->AddInput(ControllerEmu::Translate, _trans("Decrease"));
m_speed_buttons->AddInput(ControllerEmu::Translate, _trans("Increase"));
m_speed_buttons->AddInput(ControllerEmu::Translate, _trans("Reset"));
groups.emplace_back(m_other_buttons = new ControllerEmu::Buttons(_trans("Other")));
m_other_buttons->AddInput(ControllerEmu::Translate, _trans("Reset View"));
groups.emplace_back(m_fov_buttons = new ControllerEmu::Buttons(_trans("Field of View")));
m_fov_buttons->AddInput(ControllerEmu::Translate, _trans("Increase 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("Decrease Y"));
groups.emplace_back(m_rotation_gyro = new ControllerEmu::IMUGyroscope(
_trans("Incremental Rotation"), _trans("Incremental Rotation")));
}
std::string FreeLookController::GetName() const
{
return std::string("FreeLook") + char('1' + m_index);
}
void FreeLookController::LoadDefaults(const ControllerInterface& ciface)
{
EmulatedController::LoadDefaults(ciface);
auto hotkey_string = [](std::vector<std::string> inputs) {
return "@(" + JoinStrings(inputs, "+") + ')';
};
m_move_buttons->SetControlExpression(MoveButtons::Up, hotkey_string({"Shift", "E"}));
m_move_buttons->SetControlExpression(MoveButtons::Down, hotkey_string({"Shift", "Q"}));
m_move_buttons->SetControlExpression(MoveButtons::Left, hotkey_string({"Shift", "A"}));
m_move_buttons->SetControlExpression(MoveButtons::Right, hotkey_string({"Shift", "D"}));
m_move_buttons->SetControlExpression(MoveButtons::Forward, hotkey_string({"Shift", "W"}));
m_move_buttons->SetControlExpression(MoveButtons::Backward, hotkey_string({"Shift", "S"}));
m_speed_buttons->SetControlExpression(SpeedButtons::Decrease, hotkey_string({"Shift", "`1`"}));
m_speed_buttons->SetControlExpression(SpeedButtons::Increase, hotkey_string({"Shift", "`2`"}));
m_speed_buttons->SetControlExpression(SpeedButtons::Reset, hotkey_string({"Shift", "F"}));
m_other_buttons->SetControlExpression(OtherButtons::ResetView, hotkey_string({"Shift", "R"}));
m_fov_buttons->SetControlExpression(FieldOfViewButtons::IncreaseX,
hotkey_string({"Shift", "`Axis Z+`"}));
m_fov_buttons->SetControlExpression(FieldOfViewButtons::DecreaseX,
hotkey_string({"Shift", "`Axis Z-`"}));
m_fov_buttons->SetControlExpression(FieldOfViewButtons::IncreaseY,
hotkey_string({"Shift", "`Axis Z+`"}));
m_fov_buttons->SetControlExpression(FieldOfViewButtons::DecreaseY,
hotkey_string({"Shift", "`Axis Z-`"}));
// Left Click
#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)");
#elif __APPLE__
m_rotation_gyro->SetControlExpression(GyroButtons::PitchUp,
"if(`Left Click`,`RelativeMouse Y-` * 0.10, 0)");
m_rotation_gyro->SetControlExpression(GyroButtons::PitchDown,
"if(`Left Click`,`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
// Middle Click
#ifdef __APPLE__
m_rotation_gyro->SetControlExpression(GyroButtons::RollLeft,
"if(`Middle Click`,`RelativeMouse X-` * 0.10, 0)");
m_rotation_gyro->SetControlExpression(GyroButtons::RollRight,
"if(`Middle Click`,`RelativeMouse X+` * 0.10, 0)");
#else
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)");
#endif
// Right Click
#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)");
#elif __APPLE__
m_rotation_gyro->SetControlExpression(GyroButtons::YawLeft,
"if(`Right Click`,`RelativeMouse X-` * 0.10, 0)");
m_rotation_gyro->SetControlExpression(GyroButtons::YawRight,
"if(`Right Click`,`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
{
switch (group)
{
case FreeLookGroup::Move:
return m_move_buttons;
case FreeLookGroup::Speed:
return m_speed_buttons;
case FreeLookGroup::FieldOfView:
return m_fov_buttons;
case FreeLookGroup::Other:
return m_other_buttons;
case FreeLookGroup::Rotation:
return m_rotation_gyro;
default:
return nullptr;
}
}
void FreeLookController::Update()
{
if (!g_freelook_camera.IsActive())
return;
auto* camera_controller = g_freelook_camera.GetController();
if (camera_controller->SupportsInput())
{
UpdateInput(static_cast<CameraControllerInput*>(camera_controller));
}
}
void FreeLookController::UpdateInput(CameraControllerInput* camera_controller)
{
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);
camera_controller->Rotate(gyro_motion_quat);
if (m_move_buttons->controls[MoveButtons::Up]->GetState<bool>())
camera_controller->MoveVertical(-camera_controller->GetSpeed() * dt);
if (m_move_buttons->controls[MoveButtons::Down]->GetState<bool>())
camera_controller->MoveVertical(camera_controller->GetSpeed() * dt);
if (m_move_buttons->controls[MoveButtons::Left]->GetState<bool>())
camera_controller->MoveHorizontal(camera_controller->GetSpeed() * dt);
if (m_move_buttons->controls[MoveButtons::Right]->GetState<bool>())
camera_controller->MoveHorizontal(-camera_controller->GetSpeed() * dt);
if (m_move_buttons->controls[MoveButtons::Forward]->GetState<bool>())
camera_controller->MoveForward(camera_controller->GetSpeed() * dt);
if (m_move_buttons->controls[MoveButtons::Backward]->GetState<bool>())
camera_controller->MoveForward(-camera_controller->GetSpeed() * dt);
if (m_fov_buttons->controls[FieldOfViewButtons::IncreaseX]->GetState<bool>())
camera_controller->IncreaseFovX(camera_controller->GetFovStepSize() * dt);
if (m_fov_buttons->controls[FieldOfViewButtons::DecreaseX]->GetState<bool>())
camera_controller->IncreaseFovX(-1.0f * camera_controller->GetFovStepSize() * dt);
if (m_fov_buttons->controls[FieldOfViewButtons::IncreaseY]->GetState<bool>())
camera_controller->IncreaseFovY(camera_controller->GetFovStepSize() * dt);
if (m_fov_buttons->controls[FieldOfViewButtons::DecreaseY]->GetState<bool>())
camera_controller->IncreaseFovY(-1.0f * camera_controller->GetFovStepSize() * dt);
if (m_speed_buttons->controls[SpeedButtons::Decrease]->GetState<bool>())
camera_controller->ModifySpeed(camera_controller->GetSpeed() * -0.9 * dt);
if (m_speed_buttons->controls[SpeedButtons::Increase]->GetState<bool>())
camera_controller->ModifySpeed(camera_controller->GetSpeed() * 1.1 * dt);
if (m_speed_buttons->controls[SpeedButtons::Reset]->GetState<bool>())
camera_controller->ResetSpeed();
if (m_other_buttons->controls[OtherButtons::ResetView]->GetState<bool>())
camera_controller->Reset();
}
namespace FreeLook
{
static InputConfig s_config("FreeLookController", _trans("FreeLook"), "FreeLookController");
InputConfig* GetInputConfig()
{
return &s_config;
}
void Shutdown()
{
s_config.UnregisterHotplugCallback();
s_config.ClearControllers();
}
void Initialize()
{
if (s_config.ControllersNeedToBeCreated())
{
s_config.CreateController<FreeLookController>(0);
}
s_config.RegisterHotplugCallback();
FreeLook::GetConfig().Refresh();
s_config.LoadConfig(InputConfig::InputClass::GC);
}
void LoadInputConfig()
{
s_config.LoadConfig(InputConfig::InputClass::GC);
}
bool IsInitialized()
{
return !s_config.ControllersNeedToBeCreated();
}
ControllerEmu::ControlGroup* GetInputGroup(int pad_num, FreeLookGroup group)
{
return static_cast<FreeLookController*>(s_config.GetController(pad_num))->GetGroup(group);
}
void UpdateInput()
{
for (int i = 0; i < s_config.GetControllerCount(); i++)
{
static_cast<FreeLookController*>(s_config.GetController(i))->Update();
}
}
} // namespace FreeLook