we like to Move it Move it

This commit is contained in:
kalaposfos13 2026-03-03 10:19:48 +01:00
parent 54906660c7
commit b1bf54727e
9 changed files with 142 additions and 284 deletions

View File

@ -232,10 +232,11 @@ find_package(nlohmann_json 3.12 CONFIG)
find_package(PNG 1.6 MODULE)
find_package(OpenAL CONFIG)
find_package(RenderDoc 1.6.0 MODULE)
find_package(SDL3_mixer 2.8.1 CONFIG)
if (SDL3_mixer_FOUND)
find_package(SDL3 3.1.2 CONFIG)
endif()
# Since we use a non-upstream version of SDL3, we can't check for local packages.
# find_package(SDL3_mixer 2.8.1 CONFIG)
# if (SDL3_mixer_FOUND)
# find_package(SDL3 3.1.2 CONFIG)
# endif()
find_package(stb MODULE)
find_package(toml11 4.2.0 CONFIG)
find_package(tsl-robin-map 1.3.0 CONFIG)

2
externals/sdl3 vendored

@ -1 +1 @@
Subproject commit 4e2fd57e77fb4a28c0eeef0670fc4121cc2cf1f9
Subproject commit 9c51f451c67653fc2e73ed734213308ee7db0707

View File

@ -6,7 +6,7 @@
#include "common/logging/backend.h"
#if defined(ARCH_X86_64)
#define Crash() quick_exit(1)
#define Crash() __asm__ __volatile__("int $3")
#elif defined(ARCH_ARM64)
#define Crash() __asm__ __volatile__("brk 0")
#else

View File

@ -3,6 +3,7 @@
#pragma once
#include "common/enum.h"
#include "common/types.h"
#include "core/libraries/system/userservice.h"
@ -17,6 +18,19 @@ struct OrbisMoveDeviceInfo {
float accelerometer_offset[3];
};
enum class OrbisMoveButtonDataOffset : u16 {
Select = (1 << 0),
T = (1 << 1),
Move = (1 << 2),
Start = (1 << 3),
Triangle = (1 << 4),
Circle = (1 << 5),
Cross = (1 << 6),
Square = (1 << 7),
Intercepted = (1 << 15),
};
DECLARE_ENUM_FLAG_OPERATORS(OrbisMoveButtonDataOffset)
struct OrbisMoveButtonData {
u16 button_data;
u16 trigger_data;

View File

@ -330,8 +330,8 @@ int ProcessStates(s32 handle, OrbisPadData* pData, Input::GameController& contro
controller.SetLastUpdate(now);
Libraries::Pad::OrbisFQuaternion lastOrientation = controller.GetLastOrientation();
Libraries::Pad::OrbisFQuaternion outputOrientation = {0.0f, 0.0f, 0.0f, 1.0f};
GameController::CalculateOrientation(pData->acceleration, pData->angularVelocity,
deltaTime, lastOrientation, outputOrientation);
GameControllers::CalculateOrientation(pData->acceleration, pData->angularVelocity,
deltaTime, lastOrientation, outputOrientation);
pData[i].orientation = outputOrientation;
controller.SetLastOrientation(outputOrientation);
}

View File

@ -150,11 +150,37 @@ void GameController::UpdateAxisSmoothing() {
m_state.UpdateAxisSmoothing();
}
void GameController::CalculateOrientation(Libraries::Pad::OrbisFVector3& acceleration,
Libraries::Pad::OrbisFVector3& angularVelocity,
float deltaTime,
Libraries::Pad::OrbisFQuaternion& lastOrientation,
Libraries::Pad::OrbisFQuaternion& orientation) {
void GameController::SetLightBarRGB(u8 r, u8 g, u8 b) {
if (m_sdl_gamepad != nullptr) {
SDL_SetGamepadLED(m_sdl_gamepad, r, g, b);
}
}
bool GameController::SetVibration(u8 smallMotor, u8 largeMotor) {
if (m_sdl_gamepad != nullptr) {
return SDL_RumbleGamepad(m_sdl_gamepad, (smallMotor / 255.0f) * 0xFFFF,
(largeMotor / 255.0f) * 0xFFFF, -1);
}
return true;
}
void GameController::SetTouchpadState(int touchIndex, bool touchDown, float x, float y) {
if (touchIndex < 2) {
m_state.OnTouchpad(touchIndex, touchDown, x, y);
PushState();
}
}
MoveController::MoveController() : m_states_queue(64) {}
bool GameControllers::override_controller_color = false;
Colour GameControllers::controller_override_color{};
void GameControllers::CalculateOrientation(Libraries::Pad::OrbisFVector3& acceleration,
Libraries::Pad::OrbisFVector3& angularVelocity,
float deltaTime,
Libraries::Pad::OrbisFQuaternion& lastOrientation,
Libraries::Pad::OrbisFQuaternion& orientation) {
// avoid wildly off values coming from elapsed time between two samples
// being too high, such as on the first time the controller is polled
if (deltaTime > 1.0f) {
@ -191,30 +217,6 @@ void GameController::CalculateOrientation(Libraries::Pad::OrbisFVector3& acceler
orientation.y, orientation.z, orientation.w);
}
void GameController::SetLightBarRGB(u8 r, u8 g, u8 b) {
if (m_sdl_gamepad != nullptr) {
SDL_SetGamepadLED(m_sdl_gamepad, r, g, b);
}
}
bool GameController::SetVibration(u8 smallMotor, u8 largeMotor) {
if (m_sdl_gamepad != nullptr) {
return SDL_RumbleGamepad(m_sdl_gamepad, (smallMotor / 255.0f) * 0xFFFF,
(largeMotor / 255.0f) * 0xFFFF, -1);
}
return true;
}
void GameController::SetTouchpadState(int touchIndex, bool touchDown, float x, float y) {
if (touchIndex < 2) {
m_state.OnTouchpad(touchIndex, touchDown, x, y);
PushState();
}
}
bool GameControllers::override_controller_color = false;
Colour GameControllers::controller_override_color{};
bool is_first_check = true;
void GameControllers::TryOpenSDLControllers(GameControllers& controllers) {
@ -231,6 +233,17 @@ void GameControllers::TryOpenSDLControllers(GameControllers& controllers) {
SDL_JoystickID id = SDL_GetGamepadID(pad);
bool still_connected = false;
for (int j = 0; j < controller_count; j++) {
ControllerType type = ControllerType::Standard;
SDL_GUID guid = SDL_GetJoystickGUID(SDL_GetJoystickFromID(new_joysticks[j]));
Uint16 vendor = 0, product = 0;
SDL_GetJoystickGUIDInfo(guid, &vendor, &product, nullptr, nullptr);
if (vendor == 0x054C && // Sony
(product == 0x03D5 || // PSMove ZCM1
product == 0x0C5E)) { // PSMove ZCM2
LOG_INFO(Input, "PS Move controller found at slot {}!", j);
type = ControllerType::Move;
UNREACHABLE_MSG("todo refactor this entire function");
}
if (new_joysticks[j] == id) {
still_connected = true;
assigned_ids.insert(id);

View File

@ -11,6 +11,7 @@
#include "SDL3/SDL_joystick.h"
#include "common/assert.h"
#include "common/types.h"
#include "core/libraries/move/move.h"
#include "core/libraries/pad/pad.h"
#include "core/libraries/system/userservice.h"
@ -18,6 +19,11 @@ struct SDL_Gamepad;
namespace Input {
enum class ControllerType {
Standard,
Move,
};
enum class Axis {
LeftX = 0,
LeftY = 1,
@ -134,6 +140,67 @@ public:
bool WasSecondaryTouchReset();
void UnsetSecondaryTouchResetBool();
void SetLastOrientation(Libraries::Pad::OrbisFQuaternion& orientation);
Libraries::Pad::OrbisFQuaternion GetLastOrientation();
std::chrono::steady_clock::time_point GetLastUpdate();
void SetLastUpdate(std::chrono::steady_clock::time_point lastUpdate);
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 = Libraries::UserService::ORBIS_USER_SERVICE_USER_ID_INVALID;
SDL_Gamepad* m_sdl_gamepad = nullptr;
SDL_JoystickID m_sdl_joystickid{};
private:
void PushState();
bool m_connected = true;
int m_connected_count = 1;
u8 m_touch_count = 0;
u8 m_secondary_touch_count = 0;
u8 m_previous_touchnum = 0;
bool m_was_secondary_reset = false;
std::chrono::steady_clock::time_point m_last_update = {};
Libraries::Pad::OrbisFQuaternion m_orientation = {0.0f, 0.0f, 0.0f, 1.0f};
u8 player_index = -1;
State m_state;
std::mutex m_states_queue_mutex;
RingBufferQueue<State> m_states_queue;
};
class MoveController {
friend class GameControllers;
public:
MoveController();
virtual ~MoveController() = default;
void ReadState(State* state, bool* isConnected, int* connectedCount);
int ReadStates(State* states, int states_num, bool* isConnected, int* connectedCount);
void Button(Libraries::Move::OrbisMoveButtonDataOffset button, bool isPressed);
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);
u8 GetTouchCount();
void SetTouchCount(u8 touchCount);
u8 GetSecondaryTouchCount();
void SetSecondaryTouchCount(u8 touchCount);
u8 GetPreviousTouchNum();
void SetPreviousTouchNum(u8 touchNum);
bool WasSecondaryTouchReset();
void UnsetSecondaryTouchResetBool();
void SetLastOrientation(Libraries::Pad::OrbisFQuaternion& orientation);
Libraries::Pad::OrbisFQuaternion GetLastOrientation();
std::chrono::steady_clock::time_point GetLastUpdate();
@ -171,13 +238,17 @@ private:
class GameControllers {
std::array<GameController*, 4> controllers;
std::array<MoveController*, 4> move_controllers;
static bool override_controller_color;
static Colour controller_override_color;
public:
GameControllers()
: controllers({new GameController(), new GameController(), new GameController(),
new GameController()}) {};
new GameController()}),
move_controllers({new MoveController(), new MoveController(), new MoveController(),
new MoveController()}) {};
virtual ~GameControllers() = default;
GameController* operator[](const size_t& i) const {
if (i > 3) {
@ -188,6 +259,11 @@ public:
static void TryOpenSDLControllers(GameControllers& controllers);
static u8 GetGamepadIndexFromJoystickId(SDL_JoystickID id);
static void CalculateOrientation(Libraries::Pad::OrbisFVector3& acceleration,
Libraries::Pad::OrbisFVector3& angularVelocity,
float deltaTime,
Libraries::Pad::OrbisFQuaternion& lastOrientation,
Libraries::Pad::OrbisFQuaternion& orientation);
static void SetOverrideControllerColor(bool set) {
override_controller_color = set;
}

View File

@ -1,106 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "move_controller.h"
#include "common/logging/log.h"
#include "core/emulator_settings.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
#include "core/libraries/move/move.h"
#include "core/libraries/move/move_error.h"
namespace Input {
static bool is_first_check = true;
void MoveControllers::TryOpenSDLControllers(MoveControllers& controllers) {
using namespace Libraries::UserService;
int controller_count;
SDL_JoystickID* new_joysticks = SDL_GetGamepads(&controller_count);
std::unordered_set<SDL_JoystickID> assigned_ids;
std::array<bool, 4> slot_taken{false, false, false, false};
for (int i = 0; i < 4; i++) {
SDL_Gamepad* pad = controllers[i]->m_sdl_gamepad;
if (pad) {
SDL_JoystickID id = SDL_GetGamepadID(pad);
bool still_connected = false;
for (int j = 0; j < controller_count; j++) {
SDL_GUID guid = SDL_GetJoystickGUID(SDL_GetJoystickFromID(new_joysticks[j]));
Uint16 vendor = 0, product = 0;
SDL_GetJoystickGUIDInfo(guid, &vendor, &product, nullptr, nullptr);
if (vendor != VendorSony || product != ProductMoveZCM1 ||
product != ProductMoveZCM2) {
continue; // not a Move controller
}
if (new_joysticks[j] == id) {
still_connected = true;
assigned_ids.insert(id);
slot_taken[i] = true;
break;
}
}
if (!still_connected) {
AddUserServiceEvent({OrbisUserServiceEventType::Logout, i + 1});
SDL_CloseGamepad(pad);
controllers[i]->m_sdl_gamepad = nullptr;
controllers[i]->user_id = -1;
slot_taken[i] = false;
} else {
controllers[i]->player_index = i;
}
}
}
for (int j = 0; j < controller_count; j++) {
SDL_JoystickID id = new_joysticks[j];
if (assigned_ids.contains(id))
continue;
SDL_Gamepad* pad = SDL_OpenGamepad(id);
if (!pad)
continue;
for (int i = 0; i < 4; i++) {
if (!slot_taken[i]) {
auto* c = controllers[i];
c->m_sdl_gamepad = pad;
LOG_INFO(Input, "Gamepad registered for slot {}! Handle: {}", i,
SDL_GetGamepadID(pad));
c->user_id = i + 1;
slot_taken[i] = true;
c->player_index = i;
AddUserServiceEvent({OrbisUserServiceEventType::Login, i + 1});
if (SDL_SetGamepadSensorEnabled(c->m_sdl_gamepad, SDL_SENSOR_GYRO, true)) {
c->gyro_poll_rate =
SDL_GetGamepadSensorDataRate(c->m_sdl_gamepad, SDL_SENSOR_GYRO);
LOG_INFO(Input, "Gyro initialized, poll rate: {}", c->gyro_poll_rate);
} else {
LOG_ERROR(Input, "Failed to initialize gyro controls for gamepad {}",
c->user_id);
}
if (SDL_SetGamepadSensorEnabled(c->m_sdl_gamepad, SDL_SENSOR_ACCEL, true)) {
c->accel_poll_rate =
SDL_GetGamepadSensorDataRate(c->m_sdl_gamepad, SDL_SENSOR_ACCEL);
LOG_INFO(Input, "Accel initialized, poll rate: {}", c->accel_poll_rate);
} else {
LOG_ERROR(Input, "Failed to initialize accel controls for gamepad {}",
c->user_id);
}
break;
}
}
}
if (is_first_check) [[unlikely]] {
is_first_check = false;
if (controller_count == 0) {
controllers[0]->user_id = 1;
AddUserServiceEvent({OrbisUserServiceEventType::Login, 1});
}
}
SDL_free(new_joysticks);
}
} // namespace Input

View File

@ -1,140 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/libraries/pad/pad.h"
#include "core/libraries/system/userservice.h"
#include <unordered_set>
#include <SDL3/SDL.h>
#pragma once
namespace Input {
static constexpr int VendorSony = 0x054C;
static constexpr int ProductMoveZCM1 = 0x03D5;
static constexpr int ProductMoveZCM2 = 0x0C5E;
struct OrbisFQuaternion {
float x, y, z, w;
};
struct OrbisFVector3 {
float x, y, z;
};
template <class T>
class RingBufferQueue {
public:
RingBufferQueue(size_t size) : m_storage(size) {}
void Push(T item) {
const size_t index = (m_begin + m_size) % m_storage.size();
m_storage[index] = std::move(item);
if (m_size < m_storage.size()) {
m_size += 1;
} else {
m_begin = (m_begin + 1) % m_storage.size();
}
}
std::optional<T> Pop() {
if (m_size == 0) {
return {};
}
const size_t index = m_begin;
m_begin = (m_begin + 1) % m_storage.size();
m_size -= 1;
return std::move(m_storage[index]);
}
private:
size_t m_begin = 0;
size_t m_size = 0;
std::vector<T> m_storage;
};
struct State {};
class MoveController {
friend class MoveControllers;
public:
MoveController();
virtual ~MoveController() = default;
// void ReadState(State* state, bool* isConnected, int* connectedCount);
// 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, 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);
u8 GetTouchCount();
void SetTouchCount(u8 touchCount);
u8 GetSecondaryTouchCount();
void SetSecondaryTouchCount(u8 touchCount);
u8 GetPreviousTouchNum();
void SetPreviousTouchNum(u8 touchNum);
bool WasSecondaryTouchReset();
void UnsetSecondaryTouchResetBool();
void SetLastOrientation(OrbisFQuaternion& orientation);
OrbisFQuaternion GetLastOrientation();
std::chrono::steady_clock::time_point GetLastUpdate();
void SetLastUpdate(std::chrono::steady_clock::time_point lastUpdate);
static void CalculateOrientation(OrbisFVector3& acceleration, OrbisFVector3& angularVelocity,
float deltaTime, OrbisFQuaternion& lastOrientation,
OrbisFQuaternion& orientation);
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 = Libraries::UserService::ORBIS_USER_SERVICE_USER_ID_INVALID;
SDL_Gamepad* m_sdl_gamepad = nullptr;
private:
void PushState();
bool m_connected = true;
int m_connected_count = 1;
u8 m_touch_count = 0;
u8 m_secondary_touch_count = 0;
u8 m_previous_touchnum = 0;
bool m_was_secondary_reset = false;
std::chrono::steady_clock::time_point m_last_update = {};
OrbisFQuaternion m_orientation = {0.0f, 0.0f, 0.0f, 1.0f};
u8 player_index = -1;
State m_state;
std::mutex m_states_queue_mutex;
RingBufferQueue<State> m_states_queue;
};
class MoveControllers {
std::array<MoveController*, 4> controllers;
public:
MoveControllers()
: controllers({new MoveController(), new MoveController(), new MoveController(),
new MoveController()}) {};
virtual ~MoveControllers() = default;
MoveController* operator[](const size_t& i) const {
if (i > 3) {
UNREACHABLE_MSG("Index {} is out of bounds for MoveControllers!", i);
}
return controllers[i];
}
static void TryOpenSDLControllers(MoveControllers& controllers);
static u8 GetGamepadIndexFromJoystickId(SDL_JoystickID id);
};
} // namespace Input