mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-03-29 23:19:43 -06:00
KBM -> joystick input smoothing v2
This commit is contained in:
parent
d0ea7f04c4
commit
e1ad33155d
@ -28,7 +28,15 @@ void State::OnButton(OrbisPadButtonDataOffset button, bool isPressed) {
|
||||
}
|
||||
}
|
||||
|
||||
void State::OnAxis(Axis axis, int value) {
|
||||
void State::OnAxis(Axis axis, int value, bool smooth) {
|
||||
auto const i = std::to_underlying(axis);
|
||||
// forcibly finish the previous smoothing task by jumping to the end
|
||||
axes[i] = axis_smoothing_end_values[i];
|
||||
|
||||
axis_smoothing_start_times[i] = time;
|
||||
axis_smoothing_start_values[i] = axes[i];
|
||||
axis_smoothing_end_values[i] = value;
|
||||
axis_smoothing_flags[i] = smooth;
|
||||
const auto toggle = [&](const auto button) {
|
||||
if (value > 0) {
|
||||
buttonsState |= button;
|
||||
@ -46,7 +54,6 @@ void State::OnAxis(Axis axis, int value) {
|
||||
default:
|
||||
break;
|
||||
}
|
||||
axes[static_cast<int>(axis)] = value;
|
||||
}
|
||||
|
||||
void State::OnTouchpad(int touchIndex, bool isDown, float x, float y) {
|
||||
@ -67,6 +74,22 @@ void State::OnAccel(const float accel[3]) {
|
||||
acceleration.z = accel[2];
|
||||
}
|
||||
|
||||
void State::UpdateAxisSmoothing() {
|
||||
for (int i = 0; i < std::to_underlying(Axis::AxisMax); i++) {
|
||||
// if it's not to be smoothed or close enough, just jump to the end
|
||||
if (!axis_smoothing_flags[i] || std::abs(axes[i] - axis_smoothing_end_values[i]) < 16) {
|
||||
if (axes[i] != axis_smoothing_end_values[i]) {
|
||||
axes[i] = axis_smoothing_end_values[i];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
auto now = Libraries::Kernel::sceKernelGetProcessTime();
|
||||
f32 t = std::clamp((now - axis_smoothing_start_times[i]) / f32{axis_smoothing_time},
|
||||
0.f, 1.f);
|
||||
axes[i] = s32(axis_smoothing_start_values[i] * (1 - t) + axis_smoothing_end_values[i] * t);
|
||||
}
|
||||
}
|
||||
|
||||
GameController::GameController() : m_states_queue(64) {}
|
||||
|
||||
void GameController::ReadState(State* state, bool* isConnected, int* connectedCount) {
|
||||
@ -99,8 +122,8 @@ void GameController::Button(OrbisPadButtonDataOffset button, bool is_pressed) {
|
||||
PushState();
|
||||
}
|
||||
|
||||
void GameController::Axis(Input::Axis axis, int value) {
|
||||
m_state.OnAxis(axis, value);
|
||||
void GameController::Axis(Input::Axis axis, int value, bool smooth) {
|
||||
m_state.OnAxis(axis, value, smooth);
|
||||
PushState();
|
||||
}
|
||||
|
||||
@ -124,6 +147,10 @@ void GameController::UpdateAcceleration(const float acceleration[3]) {
|
||||
std::memcpy(accel_buf, acceleration, sizeof(accel_buf));
|
||||
}
|
||||
|
||||
void GameController::UpdateAxisSmoothing() {
|
||||
m_state.UpdateAxisSmoothing();
|
||||
}
|
||||
|
||||
void GameController::CalculateOrientation(Libraries::Pad::OrbisFVector3& acceleration,
|
||||
Libraries::Pad::OrbisFVector3& angularVelocity,
|
||||
float deltaTime,
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <SDL3/SDL_gamepad.h>
|
||||
@ -11,6 +12,7 @@
|
||||
#include "common/assert.h"
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/pad/pad.h"
|
||||
#include "core/libraries/system/userservice.h"
|
||||
|
||||
struct SDL_Gamepad;
|
||||
|
||||
@ -35,15 +37,27 @@ struct TouchpadEntry {
|
||||
};
|
||||
|
||||
struct State {
|
||||
private:
|
||||
template <typename T>
|
||||
using AxisArray = std::array<T, std::to_underlying(Axis::AxisMax)>;
|
||||
static constexpr AxisArray<s32> axis_defaults{128, 128, 128, 128, 0, 0};
|
||||
static constexpr u64 axis_smoothing_time{33000};
|
||||
AxisArray<bool> axis_smoothing_flags{true};
|
||||
AxisArray<u64> axis_smoothing_start_times{0};
|
||||
AxisArray<int> axis_smoothing_start_values{axis_defaults};
|
||||
AxisArray<int> axis_smoothing_end_values{axis_defaults};
|
||||
|
||||
public:
|
||||
void OnButton(Libraries::Pad::OrbisPadButtonDataOffset, bool);
|
||||
void OnAxis(Axis, int);
|
||||
void OnAxis(Axis, int, bool smooth = true);
|
||||
void OnTouchpad(int touchIndex, bool isDown, float x, float y);
|
||||
void OnGyro(const float[3]);
|
||||
void OnAccel(const float[3]);
|
||||
void UpdateAxisSmoothing();
|
||||
|
||||
Libraries::Pad::OrbisPadButtonDataOffset buttonsState{};
|
||||
u64 time = 0;
|
||||
int axes[static_cast<int>(Axis::AxisMax)] = {128, 128, 128, 128, 0, 0};
|
||||
AxisArray<s32> axes{axis_defaults};
|
||||
TouchpadEntry touchpad[2] = {{false, 0, 0}, {false, 0, 0}};
|
||||
Libraries::Pad::OrbisFVector3 acceleration = {0.0f, -9.81f, 0.0f};
|
||||
Libraries::Pad::OrbisFVector3 angularVelocity = {0.0f, 0.0f, 0.0f};
|
||||
@ -97,11 +111,12 @@ public:
|
||||
int ReadStates(State* states, int states_num, bool* isConnected, int* connectedCount);
|
||||
|
||||
void Button(Libraries::Pad::OrbisPadButtonDataOffset button, bool isPressed);
|
||||
void Axis(Input::Axis axis, int value);
|
||||
void Axis(Input::Axis axis, int value, bool smooth = true);
|
||||
void Gyro(int id);
|
||||
void Acceleration(int id);
|
||||
void UpdateGyro(const float gyro[3]);
|
||||
void UpdateAcceleration(const float acceleration[3]);
|
||||
void UpdateAxisSmoothing();
|
||||
void SetLightBarRGB(u8 r, u8 g, u8 b);
|
||||
bool SetVibration(u8 smallMotor, u8 largeMotor);
|
||||
void SetTouchpadState(int touchIndex, bool touchDown, float x, float y);
|
||||
@ -128,11 +143,8 @@ public:
|
||||
float gyro_poll_rate;
|
||||
float accel_poll_rate;
|
||||
float gyro_buf[3] = {0.0f, 0.0f, 0.0f}, accel_buf[3] = {0.0f, 9.81f, 0.0f};
|
||||
u32 user_id = -1; // ORBIS_USER_SERVICE_USER_ID_INVALID
|
||||
u32 user_id = Libraries::UserService::ORBIS_USER_SERVICE_USER_ID_INVALID;
|
||||
SDL_Gamepad* m_sdl_gamepad = nullptr;
|
||||
static constexpr int max_smoothing_ticks = 2;
|
||||
int axis_smoothing_ticks[static_cast<int>(Input::Axis::AxisMax)]{0};
|
||||
int axis_smoothing_values[static_cast<int>(Input::Axis::AxisMax)]{0};
|
||||
|
||||
private:
|
||||
void PushState();
|
||||
|
||||
@ -77,11 +77,11 @@ void EmulateJoystick(GameController* controller, u32 interval) {
|
||||
float a_x = cos(angle) * output_speed, a_y = sin(angle) * output_speed;
|
||||
|
||||
if (d_x != 0 || d_y != 0) {
|
||||
controller->Axis(axis_x, GetAxis(-0x80, 0x7f, a_x));
|
||||
controller->Axis(axis_y, GetAxis(-0x80, 0x7f, a_y));
|
||||
controller->Axis(axis_x, GetAxis(-0x80, 0x7f, a_x), false);
|
||||
controller->Axis(axis_y, GetAxis(-0x80, 0x7f, a_y), false);
|
||||
} else {
|
||||
controller->Axis(axis_x, GetAxis(-0x80, 0x7f, 0));
|
||||
controller->Axis(axis_y, GetAxis(-0x80, 0x7f, 0));
|
||||
controller->Axis(axis_x, GetAxis(-0x80, 0x7f, 0), false);
|
||||
controller->Axis(axis_y, GetAxis(-0x80, 0x7f, 0), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -68,8 +68,9 @@ static OrbisPadButtonDataOffset SDLGamepadToOrbisButton(u8 button) {
|
||||
}
|
||||
}
|
||||
|
||||
static Uint32 SDLCALL PollGyroAndAccel(void* userdata, SDL_TimerID timer_id, Uint32 interval) {
|
||||
static Uint32 SDLCALL PollController(void* userdata, SDL_TimerID timer_id, Uint32 interval) {
|
||||
auto* controller = reinterpret_cast<Input::GameController*>(userdata);
|
||||
controller->UpdateAxisSmoothing();
|
||||
controller->Gyro(0);
|
||||
controller->Acceleration(0);
|
||||
return 4;
|
||||
@ -280,7 +281,7 @@ void WindowSDL::WaitEvent() {
|
||||
|
||||
void WindowSDL::InitTimers() {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
SDL_AddTimer(4, &PollGyroAndAccel, controllers[i]);
|
||||
SDL_AddTimer(4, &PollController, controllers[i]);
|
||||
}
|
||||
SDL_AddTimer(33, Input::MousePolling, (void*)controllers[0]);
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user