Merge pull request #9848 from german77/metroid_motion
input_common: Implement dedicated motion from mouse
This commit is contained in:
		| @@ -363,7 +363,17 @@ void EmulatedController::ReloadInput() { | |||||||
|                     SetMotion(callback, index); |                     SetMotion(callback, index); | ||||||
|                 }, |                 }, | ||||||
|         }); |         }); | ||||||
|         motion_devices[index]->ForceUpdate(); |  | ||||||
|  |         // Restore motion state | ||||||
|  |         auto& emulated_motion = controller.motion_values[index].emulated; | ||||||
|  |         auto& motion = controller.motion_state[index]; | ||||||
|  |         emulated_motion.ResetRotations(); | ||||||
|  |         emulated_motion.ResetQuaternion(); | ||||||
|  |         motion.accel = emulated_motion.GetAcceleration(); | ||||||
|  |         motion.gyro = emulated_motion.GetGyroscope(); | ||||||
|  |         motion.rotation = emulated_motion.GetRotations(); | ||||||
|  |         motion.orientation = emulated_motion.GetOrientation(); | ||||||
|  |         motion.is_at_rest = !emulated_motion.IsMoving(motion_sensitivity); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     for (std::size_t index = 0; index < camera_devices.size(); ++index) { |     for (std::size_t index = 0; index < camera_devices.size(); ++index) { | ||||||
|   | |||||||
| @@ -10,6 +10,8 @@ MotionInput::MotionInput() { | |||||||
|     // Initialize PID constants with default values |     // Initialize PID constants with default values | ||||||
|     SetPID(0.3f, 0.005f, 0.0f); |     SetPID(0.3f, 0.005f, 0.0f); | ||||||
|     SetGyroThreshold(ThresholdStandard); |     SetGyroThreshold(ThresholdStandard); | ||||||
|  |     ResetQuaternion(); | ||||||
|  |     ResetRotations(); | ||||||
| } | } | ||||||
|  |  | ||||||
| void MotionInput::SetPID(f32 new_kp, f32 new_ki, f32 new_kd) { | void MotionInput::SetPID(f32 new_kp, f32 new_ki, f32 new_kd) { | ||||||
| @@ -20,11 +22,19 @@ void MotionInput::SetPID(f32 new_kp, f32 new_ki, f32 new_kd) { | |||||||
|  |  | ||||||
| void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) { | void MotionInput::SetAcceleration(const Common::Vec3f& acceleration) { | ||||||
|     accel = acceleration; |     accel = acceleration; | ||||||
|  |  | ||||||
|  |     accel.x = std::clamp(accel.x, -AccelMaxValue, AccelMaxValue); | ||||||
|  |     accel.y = std::clamp(accel.y, -AccelMaxValue, AccelMaxValue); | ||||||
|  |     accel.z = std::clamp(accel.z, -AccelMaxValue, AccelMaxValue); | ||||||
| } | } | ||||||
|  |  | ||||||
| void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) { | void MotionInput::SetGyroscope(const Common::Vec3f& gyroscope) { | ||||||
|     gyro = gyroscope - gyro_bias; |     gyro = gyroscope - gyro_bias; | ||||||
|  |  | ||||||
|  |     gyro.x = std::clamp(gyro.x, -GyroMaxValue, GyroMaxValue); | ||||||
|  |     gyro.y = std::clamp(gyro.y, -GyroMaxValue, GyroMaxValue); | ||||||
|  |     gyro.z = std::clamp(gyro.z, -GyroMaxValue, GyroMaxValue); | ||||||
|  |  | ||||||
|     // Auto adjust drift to minimize drift |     // Auto adjust drift to minimize drift | ||||||
|     if (!IsMoving(IsAtRestRelaxed)) { |     if (!IsMoving(IsAtRestRelaxed)) { | ||||||
|         gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f); |         gyro_bias = (gyro_bias * 0.9999f) + (gyroscope * 0.0001f); | ||||||
| @@ -61,6 +71,10 @@ void MotionInput::ResetRotations() { | |||||||
|     rotations = {}; |     rotations = {}; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void MotionInput::ResetQuaternion() { | ||||||
|  |     quat = {{0.0f, 0.0f, -1.0f}, 0.0f}; | ||||||
|  | } | ||||||
|  |  | ||||||
| bool MotionInput::IsMoving(f32 sensitivity) const { | bool MotionInput::IsMoving(f32 sensitivity) const { | ||||||
|     return gyro.Length() >= sensitivity || accel.Length() <= 0.9f || accel.Length() >= 1.1f; |     return gyro.Length() >= sensitivity || accel.Length() <= 0.9f || accel.Length() >= 1.1f; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -20,6 +20,9 @@ public: | |||||||
|     static constexpr float IsAtRestStandard = 0.01f; |     static constexpr float IsAtRestStandard = 0.01f; | ||||||
|     static constexpr float IsAtRestThight = 0.005f; |     static constexpr float IsAtRestThight = 0.005f; | ||||||
|  |  | ||||||
|  |     static constexpr float GyroMaxValue = 5.0f; | ||||||
|  |     static constexpr float AccelMaxValue = 7.0f; | ||||||
|  |  | ||||||
|     explicit MotionInput(); |     explicit MotionInput(); | ||||||
|  |  | ||||||
|     MotionInput(const MotionInput&) = default; |     MotionInput(const MotionInput&) = default; | ||||||
| @@ -40,6 +43,7 @@ public: | |||||||
|  |  | ||||||
|     void EnableReset(bool reset); |     void EnableReset(bool reset); | ||||||
|     void ResetRotations(); |     void ResetRotations(); | ||||||
|  |     void ResetQuaternion(); | ||||||
|  |  | ||||||
|     void UpdateRotation(u64 elapsed_time); |     void UpdateRotation(u64 elapsed_time); | ||||||
|     void UpdateOrientation(u64 elapsed_time); |     void UpdateOrientation(u64 elapsed_time); | ||||||
| @@ -69,7 +73,7 @@ private: | |||||||
|     Common::Vec3f derivative_error; |     Common::Vec3f derivative_error; | ||||||
|  |  | ||||||
|     // Quaternion containing the device orientation |     // Quaternion containing the device orientation | ||||||
|     Common::Quaternion<f32> quat{{0.0f, 0.0f, -1.0f}, 0.0f}; |     Common::Quaternion<f32> quat; | ||||||
|  |  | ||||||
|     // Number of full rotations in each axis |     // Number of full rotations in each axis | ||||||
|     Common::Vec3f rotations; |     Common::Vec3f rotations; | ||||||
|   | |||||||
| @@ -10,17 +10,25 @@ | |||||||
| #include "input_common/drivers/mouse.h" | #include "input_common/drivers/mouse.h" | ||||||
|  |  | ||||||
| namespace InputCommon { | namespace InputCommon { | ||||||
|  | constexpr int update_time = 10; | ||||||
|  | constexpr float default_stick_sensitivity = 0.022f; | ||||||
|  | constexpr float default_motion_sensitivity = 0.008f; | ||||||
| constexpr int mouse_axis_x = 0; | constexpr int mouse_axis_x = 0; | ||||||
| constexpr int mouse_axis_y = 1; | constexpr int mouse_axis_y = 1; | ||||||
| constexpr int wheel_axis_x = 2; | constexpr int wheel_axis_x = 2; | ||||||
| constexpr int wheel_axis_y = 3; | constexpr int wheel_axis_y = 3; | ||||||
| constexpr int motion_wheel_y = 4; |  | ||||||
| constexpr PadIdentifier identifier = { | constexpr PadIdentifier identifier = { | ||||||
|     .guid = Common::UUID{}, |     .guid = Common::UUID{}, | ||||||
|     .port = 0, |     .port = 0, | ||||||
|     .pad = 0, |     .pad = 0, | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | constexpr PadIdentifier motion_identifier = { | ||||||
|  |     .guid = Common::UUID{}, | ||||||
|  |     .port = 0, | ||||||
|  |     .pad = 1, | ||||||
|  | }; | ||||||
|  |  | ||||||
| constexpr PadIdentifier real_mouse_identifier = { | constexpr PadIdentifier real_mouse_identifier = { | ||||||
|     .guid = Common::UUID{}, |     .guid = Common::UUID{}, | ||||||
|     .port = 1, |     .port = 1, | ||||||
| @@ -37,47 +45,87 @@ Mouse::Mouse(std::string input_engine_) : InputEngine(std::move(input_engine_)) | |||||||
|     PreSetController(identifier); |     PreSetController(identifier); | ||||||
|     PreSetController(real_mouse_identifier); |     PreSetController(real_mouse_identifier); | ||||||
|     PreSetController(touch_identifier); |     PreSetController(touch_identifier); | ||||||
|  |     PreSetController(motion_identifier); | ||||||
|  |  | ||||||
|     // Initialize all mouse axis |     // Initialize all mouse axis | ||||||
|     PreSetAxis(identifier, mouse_axis_x); |     PreSetAxis(identifier, mouse_axis_x); | ||||||
|     PreSetAxis(identifier, mouse_axis_y); |     PreSetAxis(identifier, mouse_axis_y); | ||||||
|     PreSetAxis(identifier, wheel_axis_x); |     PreSetAxis(identifier, wheel_axis_x); | ||||||
|     PreSetAxis(identifier, wheel_axis_y); |     PreSetAxis(identifier, wheel_axis_y); | ||||||
|     PreSetAxis(identifier, motion_wheel_y); |  | ||||||
|     PreSetAxis(real_mouse_identifier, mouse_axis_x); |     PreSetAxis(real_mouse_identifier, mouse_axis_x); | ||||||
|     PreSetAxis(real_mouse_identifier, mouse_axis_y); |     PreSetAxis(real_mouse_identifier, mouse_axis_y); | ||||||
|     PreSetAxis(touch_identifier, mouse_axis_x); |     PreSetAxis(touch_identifier, mouse_axis_x); | ||||||
|     PreSetAxis(touch_identifier, mouse_axis_y); |     PreSetAxis(touch_identifier, mouse_axis_y); | ||||||
|  |  | ||||||
|  |     // Initialize variables | ||||||
|  |     mouse_origin = {}; | ||||||
|  |     last_mouse_position = {}; | ||||||
|  |     wheel_position = {}; | ||||||
|  |     last_mouse_change = {}; | ||||||
|  |     last_motion_change = {}; | ||||||
|  |  | ||||||
|     update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); }); |     update_thread = std::jthread([this](std::stop_token stop_token) { UpdateThread(stop_token); }); | ||||||
| } | } | ||||||
|  |  | ||||||
| void Mouse::UpdateThread(std::stop_token stop_token) { | void Mouse::UpdateThread(std::stop_token stop_token) { | ||||||
|     Common::SetCurrentThreadName("Mouse"); |     Common::SetCurrentThreadName("Mouse"); | ||||||
|     constexpr int update_time = 10; |  | ||||||
|     while (!stop_token.stop_requested()) { |     while (!stop_token.stop_requested()) { | ||||||
|         if (Settings::values.mouse_panning) { |         UpdateStickInput(); | ||||||
|             // Slow movement by 4% |         UpdateMotionInput(); | ||||||
|             last_mouse_change *= 0.96f; |  | ||||||
|             const float sensitivity = |  | ||||||
|                 Settings::values.mouse_panning_sensitivity.GetValue() * 0.022f; |  | ||||||
|             SetAxis(identifier, mouse_axis_x, last_mouse_change.x * sensitivity); |  | ||||||
|             SetAxis(identifier, mouse_axis_y, -last_mouse_change.y * sensitivity); |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         SetAxis(identifier, motion_wheel_y, 0.0f); |         if (mouse_panning_timeout++ > 20) { | ||||||
|  |  | ||||||
|         if (mouse_panning_timout++ > 20) { |  | ||||||
|             StopPanning(); |             StopPanning(); | ||||||
|         } |         } | ||||||
|         std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); |         std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void Mouse::UpdateStickInput() { | ||||||
|  |     if (!Settings::values.mouse_panning) { | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const float sensitivity = | ||||||
|  |         Settings::values.mouse_panning_sensitivity.GetValue() * default_stick_sensitivity; | ||||||
|  |  | ||||||
|  |     // Slow movement by 4% | ||||||
|  |     last_mouse_change *= 0.96f; | ||||||
|  |     SetAxis(identifier, mouse_axis_x, last_mouse_change.x * sensitivity); | ||||||
|  |     SetAxis(identifier, mouse_axis_y, -last_mouse_change.y * sensitivity); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void Mouse::UpdateMotionInput() { | ||||||
|  |     const float sensitivity = | ||||||
|  |         Settings::values.mouse_panning_sensitivity.GetValue() * default_motion_sensitivity; | ||||||
|  |  | ||||||
|  |     // Slow movement by 7% | ||||||
|  |     if (Settings::values.mouse_panning) { | ||||||
|  |         last_motion_change *= 0.93f; | ||||||
|  |     } else { | ||||||
|  |         last_motion_change.z *= 0.93f; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     const BasicMotion motion_data{ | ||||||
|  |         .gyro_x = last_motion_change.x * sensitivity, | ||||||
|  |         .gyro_y = last_motion_change.y * sensitivity, | ||||||
|  |         .gyro_z = last_motion_change.z * sensitivity, | ||||||
|  |         .accel_x = 0, | ||||||
|  |         .accel_y = 0, | ||||||
|  |         .accel_z = 0, | ||||||
|  |         .delta_timestamp = update_time * 1000, | ||||||
|  |     }; | ||||||
|  |  | ||||||
|  |     SetMotion(motion_identifier, 0, motion_data); | ||||||
|  | } | ||||||
|  |  | ||||||
| void Mouse::Move(int x, int y, int center_x, int center_y) { | void Mouse::Move(int x, int y, int center_x, int center_y) { | ||||||
|     if (Settings::values.mouse_panning) { |     if (Settings::values.mouse_panning) { | ||||||
|  |         mouse_panning_timeout = 0; | ||||||
|  |  | ||||||
|         auto mouse_change = |         auto mouse_change = | ||||||
|             (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>(); |             (Common::MakeVec(x, y) - Common::MakeVec(center_x, center_y)).Cast<float>(); | ||||||
|         mouse_panning_timout = 0; |         Common::Vec3<float> motion_change{-mouse_change.y, -mouse_change.x, last_motion_change.z}; | ||||||
|  |  | ||||||
|         const auto move_distance = mouse_change.Length(); |         const auto move_distance = mouse_change.Length(); | ||||||
|         if (move_distance == 0) { |         if (move_distance == 0) { | ||||||
| @@ -93,6 +141,7 @@ void Mouse::Move(int x, int y, int center_x, int center_y) { | |||||||
|  |  | ||||||
|         // Average mouse movements |         // Average mouse movements | ||||||
|         last_mouse_change = (last_mouse_change * 0.91f) + (mouse_change * 0.09f); |         last_mouse_change = (last_mouse_change * 0.91f) + (mouse_change * 0.09f); | ||||||
|  |         last_motion_change = (last_motion_change * 0.69f) + (motion_change * 0.31f); | ||||||
|  |  | ||||||
|         const auto last_move_distance = last_mouse_change.Length(); |         const auto last_move_distance = last_mouse_change.Length(); | ||||||
|  |  | ||||||
| @@ -116,6 +165,12 @@ void Mouse::Move(int x, int y, int center_x, int center_y) { | |||||||
|         const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.0012f; |         const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.0012f; | ||||||
|         SetAxis(identifier, mouse_axis_x, static_cast<float>(mouse_move.x) * sensitivity); |         SetAxis(identifier, mouse_axis_x, static_cast<float>(mouse_move.x) * sensitivity); | ||||||
|         SetAxis(identifier, mouse_axis_y, static_cast<float>(-mouse_move.y) * sensitivity); |         SetAxis(identifier, mouse_axis_y, static_cast<float>(-mouse_move.y) * sensitivity); | ||||||
|  |  | ||||||
|  |         last_motion_change = { | ||||||
|  |             static_cast<float>(-mouse_move.y) / 50.0f, | ||||||
|  |             static_cast<float>(-mouse_move.x) / 50.0f, | ||||||
|  |             last_motion_change.z, | ||||||
|  |         }; | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -157,15 +212,19 @@ void Mouse::ReleaseButton(MouseButton button) { | |||||||
|         SetAxis(identifier, mouse_axis_x, 0); |         SetAxis(identifier, mouse_axis_x, 0); | ||||||
|         SetAxis(identifier, mouse_axis_y, 0); |         SetAxis(identifier, mouse_axis_y, 0); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     last_motion_change.x = 0; | ||||||
|  |     last_motion_change.y = 0; | ||||||
|  |  | ||||||
|     button_pressed = false; |     button_pressed = false; | ||||||
| } | } | ||||||
|  |  | ||||||
| void Mouse::MouseWheelChange(int x, int y) { | void Mouse::MouseWheelChange(int x, int y) { | ||||||
|     wheel_position.x += x; |     wheel_position.x += x; | ||||||
|     wheel_position.y += y; |     wheel_position.y += y; | ||||||
|  |     last_motion_change.z += static_cast<f32>(y) / 100.0f; | ||||||
|     SetAxis(identifier, wheel_axis_x, static_cast<f32>(wheel_position.x)); |     SetAxis(identifier, wheel_axis_x, static_cast<f32>(wheel_position.x)); | ||||||
|     SetAxis(identifier, wheel_axis_y, static_cast<f32>(wheel_position.y)); |     SetAxis(identifier, wheel_axis_y, static_cast<f32>(wheel_position.y)); | ||||||
|     SetAxis(identifier, motion_wheel_y, static_cast<f32>(y) / 100.0f); |  | ||||||
| } | } | ||||||
|  |  | ||||||
| void Mouse::ReleaseAllButtons() { | void Mouse::ReleaseAllButtons() { | ||||||
| @@ -234,6 +293,9 @@ Common::Input::ButtonNames Mouse::GetUIName(const Common::ParamPackage& params) | |||||||
|     if (params.Has("axis_x") && params.Has("axis_y") && params.Has("axis_z")) { |     if (params.Has("axis_x") && params.Has("axis_y") && params.Has("axis_z")) { | ||||||
|         return Common::Input::ButtonNames::Engine; |         return Common::Input::ButtonNames::Engine; | ||||||
|     } |     } | ||||||
|  |     if (params.Has("motion")) { | ||||||
|  |         return Common::Input::ButtonNames::Engine; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     return Common::Input::ButtonNames::Invalid; |     return Common::Input::ButtonNames::Invalid; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -96,6 +96,8 @@ public: | |||||||
|  |  | ||||||
| private: | private: | ||||||
|     void UpdateThread(std::stop_token stop_token); |     void UpdateThread(std::stop_token stop_token); | ||||||
|  |     void UpdateStickInput(); | ||||||
|  |     void UpdateMotionInput(); | ||||||
|     void StopPanning(); |     void StopPanning(); | ||||||
|  |  | ||||||
|     Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const; |     Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const; | ||||||
| @@ -103,9 +105,10 @@ private: | |||||||
|     Common::Vec2<int> mouse_origin; |     Common::Vec2<int> mouse_origin; | ||||||
|     Common::Vec2<int> last_mouse_position; |     Common::Vec2<int> last_mouse_position; | ||||||
|     Common::Vec2<float> last_mouse_change; |     Common::Vec2<float> last_mouse_change; | ||||||
|  |     Common::Vec3<float> last_motion_change; | ||||||
|     Common::Vec2<int> wheel_position; |     Common::Vec2<int> wheel_position; | ||||||
|     bool button_pressed; |     bool button_pressed; | ||||||
|     int mouse_panning_timout{}; |     int mouse_panning_timeout{}; | ||||||
|     std::jthread update_thread; |     std::jthread update_thread; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|   | |||||||
| @@ -142,14 +142,10 @@ void MappingFactory::RegisterMotion(const MappingData& data) { | |||||||
|     new_input.Set("port", static_cast<int>(data.pad.port)); |     new_input.Set("port", static_cast<int>(data.pad.port)); | ||||||
|     new_input.Set("pad", static_cast<int>(data.pad.pad)); |     new_input.Set("pad", static_cast<int>(data.pad.pad)); | ||||||
|  |  | ||||||
|     // If engine is mouse map the mouse position as 3 axis motion |     // If engine is mouse map it automatically to mouse motion | ||||||
|     if (data.engine == "mouse") { |     if (data.engine == "mouse") { | ||||||
|         new_input.Set("axis_x", 1); |         new_input.Set("motion", 0); | ||||||
|         new_input.Set("invert_x", "-"); |         new_input.Set("pad", 1); | ||||||
|         new_input.Set("axis_y", 0); |  | ||||||
|         new_input.Set("axis_z", 4); |  | ||||||
|         new_input.Set("range", 1.0f); |  | ||||||
|         new_input.Set("deadzone", 0.0f); |  | ||||||
|         input_queue.Push(new_input); |         input_queue.Push(new_input); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 liamwhite
					liamwhite