diff --git a/cmake/OssiaDeps.cmake b/cmake/OssiaDeps.cmake index 3b5f3de885f..72d67a4e793 100644 --- a/cmake/OssiaDeps.cmake +++ b/cmake/OssiaDeps.cmake @@ -213,7 +213,7 @@ endif() if(OSSIA_ENABLE_SDL) include(deps/sdl) - if(NOT TARGET ossia::sdl2) + if(NOT TARGET ossia::sdl3) set(OSSIA_ENABLE_SDL FALSE CACHE "" INTERNAL FORCE) set(OSSIA_PROTOCOL_JOYSTICK FALSE CACHE "" INTERNAL FORCE) endif() diff --git a/cmake/OssiaOptions.cmake b/cmake/OssiaOptions.cmake index 4b4befd04e9..60ed7c507c1 100644 --- a/cmake/OssiaOptions.cmake +++ b/cmake/OssiaOptions.cmake @@ -76,7 +76,7 @@ option(OSSIA_PROTOCOL_HTTP "Enable HTTP protocol" ON) # Requires Qt option(OSSIA_PROTOCOL_WEBSOCKETS "Enable WebSockets protocol" OFF) # Requires Qt option(OSSIA_PROTOCOL_SERIAL "Enable Serial port protocol" OFF) # Requires Qt option(OSSIA_PROTOCOL_PHIDGETS "Enable Phidgets protocol" OFF) # Requires Phidgets library -option(OSSIA_PROTOCOL_JOYSTICK "Enable Joystick protocol" ON) # Requires SDL2 library +option(OSSIA_PROTOCOL_JOYSTICK "Enable Joystick protocol" ON) # Requires SDL3 library option(OSSIA_PROTOCOL_WIIMOTE "Enable Wiimote Protocol" ON) #use wiiuse option(OSSIA_PROTOCOL_ARTNET "Enable artnet protocol" ON) option(OSSIA_PROTOCOL_LIBMAPPER "Enable libmapper protocol" OFF) #use external libmapper @@ -111,8 +111,7 @@ set(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};${PROJECT_SOURCE_DIR}/CMake;${PROJEC set(OSSIA_SUBMODULE_AUTOUPDATE ON CACHE BOOL "Auto update submodule") set(CMAKE_PREFIX_PATH - "${OSSIA_SDK}/SDL2" - "${OSSIA_SDK}/SDL2/cmake" + "${OSSIA_SDK}/SDL3" "${OSSIA_SDK}/portaudio/lib/cmake" "${CMAKE_PREFIX_PATH}" ) diff --git a/cmake/deps/sdl.cmake b/cmake/deps/sdl.cmake index fd90c868464..ace70ba0a32 100644 --- a/cmake/deps/sdl.cmake +++ b/cmake/deps/sdl.cmake @@ -1,29 +1,29 @@ set(SDL_BUILDING_LIBRARY TRUE) if(CMAKE_SYSTEM_NAME MATCHES Emscripten) - add_library(ossia_sdl2 INTERFACE IMPORTED GLOBAL) - add_library(ossia::sdl2 ALIAS ossia_sdl2) + add_library(ossia_sdl3 INTERFACE IMPORTED GLOBAL) + add_library(ossia::sdl3 ALIAS ossia_sdl3) - target_compile_options(ossia_sdl2 INTERFACE "SHELL:-s USE_SDL=2") - target_link_options(ossia_sdl2 INTERFACE "SHELL:-s USE_SDL=2") + target_compile_options(ossia_sdl3 INTERFACE "SHELL:-s USE_SDL=3") + target_link_options(ossia_sdl3 INTERFACE "SHELL:-s USE_SDL=3") return() else() - find_package(SDL2 CONFIG GLOBAL) + find_package(SDL3 CONFIG GLOBAL) endif() -if(TARGET SDL2::SDL2) - add_library(ossia_sdl2 INTERFACE IMPORTED GLOBAL) - add_library(ossia::sdl2 ALIAS ossia_sdl2) +if(TARGET SDL3::SDL3) + add_library(ossia_sdl3 INTERFACE IMPORTED GLOBAL) + add_library(ossia::sdl3 ALIAS ossia_sdl3) - target_link_libraries(ossia_sdl2 INTERFACE SDL2::SDL2) -elseif(TARGET SDL2::SDL2-static) - add_library(ossia_sdl2 INTERFACE IMPORTED GLOBAL) - add_library(ossia::sdl2 ALIAS ossia_sdl2) + target_link_libraries(ossia_sdl3 INTERFACE SDL3::SDL3) +elseif(TARGET SDL3::SDL3-static) + add_library(ossia_sdl3 INTERFACE IMPORTED GLOBAL) + add_library(ossia::sdl3 ALIAS ossia_sdl3) - target_link_libraries(ossia_sdl2 INTERFACE SDL2::SDL2-static) -elseif(SDL2_LIBRARIES AND SDL2_INCLUDE_DIRS) - add_library(ossia_sdl2 INTERFACE IMPORTED GLOBAL) - add_library(ossia::sdl2 ALIAS ossia_sdl2) + target_link_libraries(ossia_sdl3 INTERFACE SDL3::SDL3-static) +elseif(SDL3_LIBRARIES AND SDL3_INCLUDE_DIRS) + add_library(ossia_sdl3 INTERFACE IMPORTED GLOBAL) + add_library(ossia::sdl3 ALIAS ossia_sdl3) - target_include_directories(ossia_sdl2 PUBLIC "${SDL2_INCLUDE_DIRS}") - target_link_libraries(ossia_sdl2 INTERFACE "${SDL2_LIBRARIES}") + target_include_directories(ossia_sdl3 PUBLIC "${SDL3_INCLUDE_DIRS}") + target_link_libraries(ossia_sdl3 INTERFACE "${SDL3_LIBRARIES}") endif() diff --git a/src/ossia/audio/sdl_protocol.hpp b/src/ossia/audio/sdl_protocol.hpp index 8458fc48294..a35baf0c57f 100644 --- a/src/ossia/audio/sdl_protocol.hpp +++ b/src/ossia/audio/sdl_protocol.hpp @@ -2,14 +2,16 @@ #include #if defined(OSSIA_ENABLE_SDL) -#if __has_include() -#include -#if !defined(SDL_AUDIO_DISABLED) +#if __has_include() #include #include -#include -#include +#include +#include + +#include +#include +#include #define OSSIA_AUDIO_SDL 1 @@ -24,27 +26,32 @@ class sdl_protocol final : public audio_engine sdl_protocol(int rate, int bs) { SDL_Init(SDL_INIT_AUDIO); - m_desired.freq = rate; - m_desired.format = AUDIO_F32SYS; - m_desired.channels = outputs; - m_desired.samples = bs; - m_desired.callback = SDLCallback; - m_desired.userdata = this; - m_deviceId = SDL_OpenAudioDevice(nullptr, 0, &m_desired, &m_obtained, 0); + SDL_SetHint(SDL_HINT_AUDIO_DEVICE_SAMPLE_FRAMES, std::to_string(bs).c_str()); + + m_spec.freq = rate; + m_spec.format = SDL_AUDIO_F32; + m_spec.channels = outputs; + + m_stream = SDL_OpenAudioDeviceStream( + SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &m_spec, SDLCallback, this); - if(m_deviceId < 2) + if(!m_stream) { using namespace std::literals; throw std::runtime_error("SDL: Couldn't open audio: "s + SDL_GetError()); } - this->effective_sample_rate = m_obtained.freq; - this->effective_buffer_size = m_obtained.samples; + this->effective_sample_rate = m_spec.freq; + this->effective_buffer_size = bs; this->effective_inputs = 0; - this->effective_outputs = m_obtained.channels; + this->effective_outputs = m_spec.channels; - SDL_PauseAudioDevice(m_deviceId, 0); + m_interleaved.resize(std::size_t(bs) * m_spec.channels); + m_planar.resize(std::size_t(bs) * m_spec.channels); + m_channels.resize(m_spec.channels); + + SDL_ResumeAudioStreamDevice(m_stream); m_activated = true; } @@ -52,7 +59,7 @@ class sdl_protocol final : public audio_engine bool running() const override { - return m_activated && SDL_GetAudioDeviceStatus(m_deviceId) == SDL_AUDIO_PLAYING; + return m_activated && !SDL_AudioStreamDevicePaused(m_stream); } void stop() override @@ -60,14 +67,16 @@ class sdl_protocol final : public audio_engine audio_engine::stop(); if(m_activated) { - SDL_CloseAudioDevice(m_deviceId); + SDL_DestroyAudioStream(m_stream); + m_stream = nullptr; m_activated = false; } SDL_Quit(); } private: - static void SDLCallback(void* userData, Uint8* data, int bytes) + static void SDLCallback( + void* userData, SDL_AudioStream* stream, int additional_amount, int total_amount) { [[maybe_unused]] static const thread_local auto _ @@ -77,35 +86,37 @@ class sdl_protocol final : public audio_engine return 0; }(); - auto& self = *static_cast(userData); - self.tick_start(); - if(!self.m_start) - self.m_start = std::chrono::steady_clock::now(); + if(additional_amount <= 0) + return; - auto audio_out = reinterpret_cast(data); - const int out_chan = self.m_obtained.channels; - const int frames = self.m_obtained.samples; + auto& self = *static_cast(userData); + const int out_chan = self.m_spec.channels; + const int frames = self.effective_buffer_size; assert(out_chan > 0); assert(frames > 0); - assert(frames * out_chan * sizeof(float) == bytes); - if(self.stop_processing) - { - self.tick_clear(); - memset(data, 0, bytes); - return; - } + const int block_bytes = int(frames * out_chan * sizeof(float)); + while(additional_amount > 0) { - auto float_data = (float*)alloca(sizeof(float) * frames * out_chan); - memset(float_data, 0, sizeof(sizeof(float) * frames * out_chan)); + self.tick_start(); + if(!self.m_start) + self.m_start = std::chrono::steady_clock::now(); - auto float_output = (float**)alloca(sizeof(float*) * out_chan); + if(self.stop_processing) + { + self.tick_clear(); + std::fill(self.m_interleaved.begin(), self.m_interleaved.end(), 0.f); + SDL_PutAudioStreamData(stream, self.m_interleaved.data(), block_bytes); + return; + } + + float* const float_data = self.m_planar.data(); + float** const float_output = self.m_channels.data(); + std::fill_n(float_data, std::size_t(frames) * out_chan, 0.f); for(int c = 0; c < out_chan; c++) - { float_output[c] = float_data + c * frames; - } // if one day there's input... samples[j++] / 32768.; @@ -119,17 +130,25 @@ class sdl_protocol final : public audio_engine out_chan, (uint64_t)frames, nsecs}; self.audio_tick(ts); + float* audio_out = self.m_interleaved.data(); for(int j = 0; j < frames; j++) for(int c = 0; c < out_chan; c++) *audio_out++ = float_output[c][j]; + SDL_PutAudioStreamData(stream, self.m_interleaved.data(), block_bytes); + self.tick_end(); self.m_total_frames += frames; + + additional_amount -= block_bytes; } } - SDL_AudioDeviceID m_deviceId{}; - SDL_AudioSpec m_desired, m_obtained; + SDL_AudioStream* m_stream{}; + SDL_AudioSpec m_spec{}; + std::vector m_interleaved; + std::vector m_planar; + std::vector m_channels; uint64_t m_total_frames{}; std::optional m_start; bool m_activated{}; @@ -138,4 +157,3 @@ class sdl_protocol final : public audio_engine #endif #endif -#endif diff --git a/src/ossia/protocols/joystick/game_controller_protocol.cpp b/src/ossia/protocols/joystick/game_controller_protocol.cpp index cd11442ca1e..b105321b664 100644 --- a/src/ossia/protocols/joystick/game_controller_protocol.cpp +++ b/src/ossia/protocols/joystick/game_controller_protocol.cpp @@ -14,11 +14,11 @@ game_controller_protocol::game_controller_protocol( , m_processor{joystick_event_processor::instance(m_manager)} , m_ctx{ptr} , m_joystick_id{joystick_id} - , m_joystick_index{joystick_index} { // Check That (ID, Index) is a valid combination // Could happen if a joystick is unplugged between settings and here - if(joystick_id != SDL_JoystickGetDeviceInstanceID(joystick_index)) + const SDL_JoystickID sdl_id = sdl_joystick_ids{}[joystick_index]; + if(sdl_id == 0 || joystick_id != static_cast(sdl_id)) throw std::runtime_error("Invalid Settings"); // Check that this ID is not already registered @@ -26,10 +26,10 @@ game_controller_protocol::game_controller_protocol( throw std::runtime_error("This Joystick is already open"); // Open The Joystick - if(!SDL_IsGameController(joystick_index)) + if(!SDL_IsGamepad(sdl_id)) throw std::runtime_error("This Joystick is not a game controller"); - m_joystick = SDL_GameControllerOpen(joystick_index); + m_joystick = SDL_OpenGamepad(sdl_id); if(m_joystick == nullptr) throw std::runtime_error("Failed to open Joystick"); @@ -49,17 +49,15 @@ void game_controller_protocol::set_device(ossia::net::device_base& dev) { m_device = &dev; auto& root = dev.get_root_node(); - switch(SDL_GameControllerTypeForIndex(m_joystick_index)) + switch(SDL_GetGamepadTypeForID(static_cast(m_joystick_id))) { - case SDL_CONTROLLER_TYPE_XBOX360: - case SDL_CONTROLLER_TYPE_XBOXONE: + case SDL_GAMEPAD_TYPE_XBOX360: + case SDL_GAMEPAD_TYPE_XBOXONE: SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_XBOX, "1"); break; - case SDL_CONTROLLER_TYPE_PS4: - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS4_RUMBLE, "1"); - break; - case SDL_CONTROLLER_TYPE_PS5: - SDL_SetHint(SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1"); + case SDL_GAMEPAD_TYPE_PS4: + case SDL_GAMEPAD_TYPE_PS5: + SDL_SetHint(SDL_HINT_JOYSTICK_ENHANCED_REPORTS, "1"); break; default: // TODO @@ -102,24 +100,22 @@ void game_controller_protocol::set_device(ossia::net::device_base& dev) // clang-format on using namespace std::literals; - for(int i = SDL_CONTROLLER_AXIS_LEFTX; i <= SDL_CONTROLLER_AXIS_TRIGGERRIGHT; i++) + for(int i = SDL_GAMEPAD_AXIS_LEFTX; i <= SDL_GAMEPAD_AXIS_RIGHT_TRIGGER; i++) { - if(SDL_GameControllerHasAxis(m_joystick, static_cast(i)) - == SDL_TRUE) + if(SDL_GamepadHasAxis(m_joystick, static_cast(i))) { // Triggers range from 0 to 1, while sticks range from -1 to 1. - const bool is_trigger = (i == SDL_CONTROLLER_AXIS_TRIGGERLEFT - || i == SDL_CONTROLLER_AXIS_TRIGGERRIGHT); + const bool is_trigger = (i == SDL_GAMEPAD_AXIS_LEFT_TRIGGER + || i == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER); m_axis_parameters[i] = device_parameter::create_device_parameter( root, axes[i], 0.0, val_type::FLOAT, bounding_mode::CLIP, access_mode::GET, is_trigger ? make_domain(0.0f, 1.0f) : make_domain(-1.0f, 1.0f)); } } - for(int i = SDL_CONTROLLER_BUTTON_A; i <= SDL_CONTROLLER_BUTTON_TOUCHPAD; i++) + for(int i = SDL_GAMEPAD_BUTTON_SOUTH; i <= SDL_GAMEPAD_BUTTON_TOUCHPAD; i++) { - if(SDL_GameControllerHasButton(m_joystick, static_cast(i)) - == SDL_TRUE) + if(SDL_GamepadHasButton(m_joystick, static_cast(i))) { m_button_parameters[i] = device_parameter::create_device_parameter( root, buttons[i], false, val_type::BOOL, bounding_mode::CLIP, access_mode::GET, @@ -127,32 +123,21 @@ void game_controller_protocol::set_device(ossia::net::device_base& dev) } } - const int max_sensor = -#if SDL_VERSION_ATLEAST(2, 26, 0) - SDL_SENSOR_GYRO_R -#else - SDL_SENSOR_GYRO -#endif - ; - - for(int i = SDL_SENSOR_UNKNOWN; i <= max_sensor; i++) + for(int i = SDL_SENSOR_UNKNOWN; i <= SDL_SENSOR_GYRO_R; i++) { - if(SDL_GameControllerHasSensor(m_joystick, static_cast(i)) - == SDL_TRUE) + if(SDL_GamepadHasSensor(m_joystick, static_cast(i))) { - if(SDL_GameControllerSetSensorEnabled( - m_joystick, static_cast(i), SDL_TRUE) - >= 0) + if(SDL_SetGamepadSensorEnabled(m_joystick, static_cast(i), true)) m_sensor_parameters[i] = device_parameter::create_device_parameter( root, sensors[i], ossia::vec3f{}, val_type::VEC3F, bounding_mode::CLIP, access_mode::GET, make_domain(-1.0f, 1.0f)); } } - for(int i = 0, N = SDL_GameControllerGetNumTouchpads(m_joystick); i < N; i++) + for(int i = 0, N = SDL_GetNumGamepadTouchpads(m_joystick); i < N; i++) { touchpad tp; - const int fingers = SDL_GameControllerGetNumTouchpadFingers(m_joystick, i); + const int fingers = SDL_GetNumGamepadTouchpadFingers(m_joystick, i); tp.fingers.resize(fingers); for(int f = 0; f < fingers; f++) { @@ -171,7 +156,9 @@ void game_controller_protocol::set_device(ossia::net::device_base& dev) m_touchpads[i] = tp; } - if(SDL_GameControllerHasRumble(m_joystick)) + const SDL_PropertiesID props = SDL_GetGamepadProperties(m_joystick); + + if(SDL_GetBooleanProperty(props, SDL_PROP_GAMEPAD_CAP_RUMBLE_BOOLEAN, false)) { // Gamepads have two motors : a low-frequency one (left) and a high-frequency one (right) rumble.lo_freq = device_parameter::create_device_parameter( @@ -185,7 +172,7 @@ void game_controller_protocol::set_device(ossia::net::device_base& dev) access_mode::SET, make_domain(10.0f, 1000000.0f)); } - if(SDL_GameControllerHasRumbleTriggers(m_joystick)) + if(SDL_GetBooleanProperty(props, SDL_PROP_GAMEPAD_CAP_TRIGGER_RUMBLE_BOOLEAN, false)) { rumble_triggers.left = device_parameter::create_device_parameter( root, "/rumble/triggers/left", 0.0f, val_type::FLOAT, bounding_mode::CLIP, @@ -216,7 +203,7 @@ bool game_controller_protocol::push( uint16_t hi = std::clamp(ossia::convert(rumble.hi_freq->value()), 0.f, 1.f) * 65535; uint32_t dur = ossia::convert(rumble.duration->value()); - SDL_GameControllerRumble(m_joystick, lo, hi, dur); + SDL_RumbleGamepad(m_joystick, lo, hi, dur); } if(¶m == rumble_triggers.duration) @@ -228,7 +215,7 @@ bool game_controller_protocol::push( = std::clamp(ossia::convert(rumble_triggers.right->value()), 0.f, 1.f) * 65535; uint32_t dur = ossia::convert(rumble_triggers.duration->value()); - SDL_GameControllerRumbleTriggers(m_joystick, left, right, dur); + SDL_RumbleGamepadTriggers(m_joystick, left, right, dur); } return true; } @@ -253,7 +240,7 @@ void game_controller_protocol::stop() if(m_joystick != nullptr) { m_manager.unregister_protocol(*this); - SDL_GameControllerClose(m_joystick); + SDL_CloseGamepad(m_joystick); m_joystick = nullptr; } } diff --git a/src/ossia/protocols/joystick/game_controller_protocol.hpp b/src/ossia/protocols/joystick/game_controller_protocol.hpp index 3eefd4ca6cd..fa54312aeba 100644 --- a/src/ossia/protocols/joystick/game_controller_protocol.hpp +++ b/src/ossia/protocols/joystick/game_controller_protocol.hpp @@ -7,7 +7,7 @@ #include #include -typedef struct _SDL_GameController SDL_GameController; +typedef struct SDL_Gamepad SDL_Gamepad; namespace ossia::net { class joystick_protocol_manager; @@ -75,9 +75,8 @@ class OSSIA_EXPORT game_controller_protocol final : public ossia::net::protocol_ ossia::small_flat_map m_touchpads; int32_t m_joystick_id{}; - int32_t m_joystick_index{}; - SDL_GameController* m_joystick{}; + SDL_Gamepad* m_joystick{}; }; } diff --git a/src/ossia/protocols/joystick/joystick_manager.hpp b/src/ossia/protocols/joystick/joystick_manager.hpp index 3fc7529a6eb..73e61149b09 100644 --- a/src/ossia/protocols/joystick/joystick_manager.hpp +++ b/src/ossia/protocols/joystick/joystick_manager.hpp @@ -6,8 +6,8 @@ #include #include -#if __has_include() -#include +#if __has_include() +#include #else #include #endif @@ -25,17 +25,17 @@ struct sdl_joystick_context // Prevent SDL from setting SIGINT handler on Posix Systems SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1"); - if(int ret = SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMECONTROLLER); ret < 0) + if(!SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD)) throw std::runtime_error(fmt::format("SDL Init failure: {}", SDL_GetError())); // Optional: absent from some SDL builds (the Emscripten port has no haptic // support at all), and no joystick API here needs them to be up. Sensors - // are read through SDL_GameControllerHasSensor, which simply reports none. + // are read through SDL_GamepadHasSensor, which simply reports none. SDL_InitSubSystem(SDL_INIT_HAPTIC); SDL_InitSubSystem(SDL_INIT_SENSOR); - SDL_JoystickEventState(SDL_ENABLE); - SDL_GameControllerEventState(SDL_ENABLE); + SDL_SetJoystickEventsEnabled(true); + SDL_SetGamepadEventsEnabled(true); } static sdl_joystick_context& instance() @@ -48,13 +48,32 @@ struct sdl_joystick_context { // To be sure to quit the event loop SDL_Event ev; - ev.type = SDL_FIRSTEVENT; + ev.type = SDL_EVENT_FIRST; SDL_PushEvent(&ev); SDL_Quit(); } }; +struct sdl_joystick_ids +{ + sdl_joystick_ids() { m_ids = SDL_GetJoysticks(&m_count); } + sdl_joystick_ids(const sdl_joystick_ids&) = delete; + sdl_joystick_ids& operator=(const sdl_joystick_ids&) = delete; + ~sdl_joystick_ids() { SDL_free(m_ids); } + + int count() const noexcept { return m_ids ? m_count : 0; } + + SDL_JoystickID operator[](int index) const noexcept + { + return (m_ids && index >= 0 && index < m_count) ? m_ids[index] : 0; + } + +private: + SDL_JoystickID* m_ids{}; + int m_count{}; +}; + class joystick_protocol_manager { public: @@ -216,7 +235,7 @@ struct joystick_event_processor using namespace std::literals; // To be sure to quit the event loop SDL_Event ev; - ev.type = SDL_FIRSTEVENT; + ev.type = SDL_EVENT_FIRST; SDL_PushEvent(&ev); for(auto& tm : m_timers) @@ -238,7 +257,7 @@ struct joystick_event_processor } } - void push_axis(const SDL_ControllerAxisEvent& ev) + void push_axis(const SDL_GamepadAxisEvent& ev) { if(auto p = m_manager.get_protocol_by_id(ev.which)) { @@ -251,19 +270,19 @@ struct joystick_event_processor { if(auto p = m_manager.get_protocol_by_id(ev.which)) { - push(p, p->m_button_parameters[ev.button], bool(ev.state == SDL_PRESSED)); + push(p, p->m_button_parameters[ev.button], bool(ev.down)); } } - void push_button(const SDL_ControllerButtonEvent& ev) + void push_button(const SDL_GamepadButtonEvent& ev) { if(auto p = m_manager.get_protocol_by_id(ev.which)) { - push(p, p->m_button_parameters[ev.button], bool(ev.state == SDL_PRESSED)); + push(p, p->m_button_parameters[ev.button], bool(ev.down)); } } - void push_sensor(const SDL_ControllerSensorEvent& ev) + void push_sensor(const SDL_GamepadSensorEvent& ev) { if(auto p = m_manager.get_protocol_by_id(ev.which)) { @@ -273,7 +292,7 @@ struct joystick_event_processor } } - void push_touchpad(const SDL_ControllerTouchpadEvent& ev) + void push_touchpad(const SDL_GamepadTouchpadEvent& ev) { if(auto p = m_manager.get_protocol_by_id(ev.which)) { @@ -317,36 +336,34 @@ struct joystick_event_processor { switch(ev.type) { - case SDL_JOYAXISMOTION: + case SDL_EVENT_JOYSTICK_AXIS_MOTION: push_axis(ev.jaxis); break; - case SDL_JOYBUTTONDOWN: - case SDL_JOYBUTTONUP: + case SDL_EVENT_JOYSTICK_BUTTON_DOWN: + case SDL_EVENT_JOYSTICK_BUTTON_UP: push_button(ev.jbutton); break; - case SDL_JOYHATMOTION: + case SDL_EVENT_JOYSTICK_HAT_MOTION: push_hat(ev.jhat); break; - case SDL_CONTROLLERAXISMOTION: - push_axis(ev.caxis); + case SDL_EVENT_GAMEPAD_AXIS_MOTION: + push_axis(ev.gaxis); break; - case SDL_CONTROLLERBUTTONDOWN: - case SDL_CONTROLLERBUTTONUP: - push_button(ev.cbutton); + case SDL_EVENT_GAMEPAD_BUTTON_DOWN: + case SDL_EVENT_GAMEPAD_BUTTON_UP: + push_button(ev.gbutton); break; - case SDL_CONTROLLERTOUCHPADDOWN: - case SDL_CONTROLLERTOUCHPADMOTION: - case SDL_CONTROLLERTOUCHPADUP: - push_touchpad(ev.ctouchpad); + case SDL_EVENT_GAMEPAD_TOUCHPAD_DOWN: + case SDL_EVENT_GAMEPAD_TOUCHPAD_MOTION: + case SDL_EVENT_GAMEPAD_TOUCHPAD_UP: + push_touchpad(ev.gtouchpad); break; - case SDL_CONTROLLERSENSORUPDATE: - push_sensor(ev.csensor); + case SDL_EVENT_GAMEPAD_SENSOR_UPDATE: + push_sensor(ev.gsensor); break; - // case SDL_CONTROLLERUPDATECOMPLETE_RESERVED_FOR_SDL3: - // case SDL_CONTROLLERSTEAMHANDLEUPDATED: default: break; diff --git a/src/ossia/protocols/joystick/joystick_protocol.cpp b/src/ossia/protocols/joystick/joystick_protocol.cpp index 4e4969d3bcc..4eb922669b5 100644 --- a/src/ossia/protocols/joystick/joystick_protocol.cpp +++ b/src/ossia/protocols/joystick/joystick_protocol.cpp @@ -17,7 +17,8 @@ joystick_protocol::joystick_protocol( { // Check That (ID, Index) is a valid combination // Could happen if a joystick is unplugged between settings and here - if(joystick_id != SDL_JoystickGetDeviceInstanceID(joystick_index)) + const SDL_JoystickID sdl_id = sdl_joystick_ids{}[joystick_index]; + if(sdl_id == 0 || joystick_id != static_cast(sdl_id)) throw std::runtime_error("Invalid Settings"); // Check that this ID is not already registered @@ -25,7 +26,7 @@ joystick_protocol::joystick_protocol( throw std::runtime_error("This Joystick is already open"); // Open The Joystick - m_joystick = SDL_JoystickOpen(joystick_index); + m_joystick = SDL_OpenJoystick(sdl_id); if(m_joystick == nullptr) throw std::runtime_error("Failed to open Joystick"); @@ -47,10 +48,10 @@ void joystick_protocol::set_device(ossia::net::device_base& dev) auto& root = dev.get_root_node(); // Retrieve Joystick Info - const int axis_count = SDL_JoystickNumAxes(m_joystick); - // const int ball_count = SDL_JoystickNumBalls(m_joystick); - const int hat_count = SDL_JoystickNumHats(m_joystick); - const int button_count = SDL_JoystickNumButtons(m_joystick); + const int axis_count = SDL_GetNumJoystickAxes(m_joystick); + // const int ball_count = SDL_GetNumJoystickBalls(m_joystick); + const int hat_count = SDL_GetNumJoystickHats(m_joystick); + const int button_count = SDL_GetNumJoystickButtons(m_joystick); // Build Parameters Tree @@ -112,7 +113,7 @@ void joystick_protocol::stop() if(m_joystick != nullptr) { m_manager.unregister_protocol(*this); - SDL_JoystickClose(m_joystick); + SDL_CloseJoystick(m_joystick); m_joystick = nullptr; } } @@ -120,27 +121,27 @@ void joystick_protocol::stop() unsigned int joystick_info::get_joystick_count() { sdl_joystick_context::instance(); - SDL_JoystickUpdate(); - return static_cast(SDL_NumJoysticks()); + SDL_UpdateJoysticks(); + return static_cast(sdl_joystick_ids{}.count()); } const char* joystick_info::get_joystick_name(const int index) { sdl_joystick_context::instance(); - return SDL_JoystickNameForIndex(index); + return SDL_GetJoystickNameForID(sdl_joystick_ids{}[index]); } bool joystick_info::get_joystick_is_gamepad(const int index) { sdl_joystick_context::instance(); - return SDL_IsGameController(index); + return SDL_IsGamepad(sdl_joystick_ids{}[index]); } bool joystick_info::get_joystick_is_available(const int index) { sdl_joystick_context::instance(); - const auto id = SDL_JoystickGetDeviceInstanceID(index); - if(id != -1) + const auto id = sdl_joystick_ids{}[index]; + if(id != 0) return !joystick_protocol_manager::instance().joystick_is_registered(id); return false; } @@ -148,13 +149,14 @@ bool joystick_info::get_joystick_is_available(const int index) int32_t joystick_info::get_joystick_id(const int index) { sdl_joystick_context::instance(); - return SDL_JoystickGetDeviceInstanceID(index); + const auto id = sdl_joystick_ids{}[index]; + return id != 0 ? static_cast(id) : -1; } void joystick_info::write_joystick_uuid(const int index, uint8_t* dst) { sdl_joystick_context::instance(); - const auto uid = SDL_JoystickGetDeviceGUID(index); + const auto uid = SDL_GetJoystickGUIDForID(sdl_joystick_ids{}[index]); std::copy_n(&uid.data[0], 16, dst); } @@ -162,17 +164,18 @@ std::pair joystick_info::get_available_id_for_uid(const uint8_t* request) { auto& mgr = joystick_protocol_manager::instance(); - SDL_JoystickUpdate(); - for(int i = 0, N = SDL_NumJoysticks(); i < N; i++) + SDL_UpdateJoysticks(); + const sdl_joystick_ids ids; + for(int i = 0, N = ids.count(); i < N; i++) { - const auto uid = SDL_JoystickGetDeviceGUID(i); + const auto uid = SDL_GetJoystickGUIDForID(ids[i]); if(std::equal(std::begin(uid.data), std::end(uid.data), request)) { - auto id = SDL_JoystickGetDeviceInstanceID(i); + const auto id = ids[i]; if(mgr.joystick_is_registered(id)) continue; - return {id, i}; + return {static_cast(id), i}; } } return {-1, -1}; diff --git a/src/ossia/protocols/joystick/joystick_protocol.hpp b/src/ossia/protocols/joystick/joystick_protocol.hpp index b6eb44bd45b..0f48f45d123 100644 --- a/src/ossia/protocols/joystick/joystick_protocol.hpp +++ b/src/ossia/protocols/joystick/joystick_protocol.hpp @@ -8,7 +8,7 @@ #include -typedef struct _SDL_Joystick SDL_Joystick; +typedef struct SDL_Joystick SDL_Joystick; namespace ossia::net { diff --git a/src/ossia_features.cmake b/src/ossia_features.cmake index 23ff00b2491..1b79946674f 100644 --- a/src/ossia_features.cmake +++ b/src/ossia_features.cmake @@ -134,7 +134,7 @@ endif() if(OSSIA_PROTOCOL_JOYSTICK) target_sources(ossia PRIVATE ${OSSIA_JOYSTICK_SRCS} ${OSSIA_JOYSTICK_HEADERS}) - target_link_libraries(ossia PRIVATE $) + target_link_libraries(ossia PRIVATE $) set(OSSIA_PROTOCOLS ${OSSIA_PROTOCOLS} Joystick) endif() @@ -273,7 +273,7 @@ if(OSSIA_DATAFLOW) #SDL support if(OSSIA_ENABLE_SDL) - target_link_libraries(ossia PRIVATE $) + target_link_libraries(ossia PRIVATE $) endif() # MiniAudio (WASAPI on Windows, CoreAudio on macOS, ALSA on Linux, Web Audio