diff --git a/CMakeLists.txt b/CMakeLists.txt index e2e2621a3..ea673d68d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/externals/sdl3 b/externals/sdl3 index 4e2fd57e7..9c51f451c 160000 --- a/externals/sdl3 +++ b/externals/sdl3 @@ -1 +1 @@ -Subproject commit 4e2fd57e77fb4a28c0eeef0670fc4121cc2cf1f9 +Subproject commit 9c51f451c67653fc2e73ed734213308ee7db0707 diff --git a/src/common/assert.cpp b/src/common/assert.cpp index 64f061a0d..be0feb71d 100644 --- a/src/common/assert.cpp +++ b/src/common/assert.cpp @@ -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 diff --git a/src/core/libraries/move/move.h b/src/core/libraries/move/move.h index 7300226e3..e868f9072 100644 --- a/src/core/libraries/move/move.h +++ b/src/core/libraries/move/move.h @@ -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; diff --git a/src/core/libraries/pad/pad.cpp b/src/core/libraries/pad/pad.cpp index 7cb8d6db2..fa036d4ca 100644 --- a/src/core/libraries/pad/pad.cpp +++ b/src/core/libraries/pad/pad.cpp @@ -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); } diff --git a/src/input/controller.cpp b/src/input/controller.cpp index 19d4ae1e0..af0097580 100644 --- a/src/input/controller.cpp +++ b/src/input/controller.cpp @@ -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); diff --git a/src/input/controller.h b/src/input/controller.h index 14017fef8..b917033f3 100644 --- a/src/input/controller.h +++ b/src/input/controller.h @@ -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 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 controllers; + std::array 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; } diff --git a/src/input/move_controller.cpp b/src/input/move_controller.cpp deleted file mode 100644 index d4008f3a6..000000000 --- a/src/input/move_controller.cpp +++ /dev/null @@ -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 assigned_ids; - std::array 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 diff --git a/src/input/move_controller.h b/src/input/move_controller.h deleted file mode 100644 index ecaf3a5c5..000000000 --- a/src/input/move_controller.h +++ /dev/null @@ -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 -#include - -#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 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 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 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 m_states_queue; -}; - -class MoveControllers { - std::array 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