From fc1d447918d3568582ea6970c6506e37b610c634 Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Sat, 18 Oct 2025 12:59:51 +0100 Subject: [PATCH] SDL3: Convert events to render coordinates Fixes mouse clicks with hardware cursor + integer scaling. --- Source/DiabloUI/diabloui.cpp | 18 +++-------- Source/engine/events.cpp | 15 ++++----- Source/platform/switch/CMakeLists.txt | 1 + Source/utils/display.h | 44 ++++++++++++++------------- Source/utils/sdl_compat.h | 31 ++++++++++++++++++- 5 files changed, 65 insertions(+), 44 deletions(-) diff --git a/Source/DiabloUI/diabloui.cpp b/Source/DiabloUI/diabloui.cpp index 0fb754469..e7d4caa88 100644 --- a/Source/DiabloUI/diabloui.cpp +++ b/Source/DiabloUI/diabloui.cpp @@ -11,6 +11,7 @@ #include #ifdef USE_SDL3 +#include #include #include #include @@ -490,9 +491,6 @@ void UiFocusNavigation(SDL_Event *event) void UiHandleEvents(SDL_Event *event) { if (event->type == SDL_EVENT_MOUSE_MOTION) { -#ifdef USE_SDL1 - OutputToLogical(&event->motion.x, &event->motion.y); -#endif MousePosition = { SDLC_EventMotionIntX(*event), SDLC_EventMotionIntY(*event) }; return; } @@ -836,6 +834,10 @@ void UiPollAndRender(std::optional> eventHan while (PollEvent(&event)) { if (eventHandler && (*eventHandler)(event)) continue; + if (!SDLC_ConvertEventToRenderCoordinates(renderer, &event)) { + LogWarn(LogCategory::Application, "SDL_ConvertEventToRenderCoordinates: {}", SDL_GetError()); + SDL_ClearError(); + } UiFocusNavigation(&event); UiHandleEvents(&event); } @@ -1145,11 +1147,6 @@ bool UiItemMouseEvents(SDL_Event *event, const std::vector &items) return false; } - // In SDL2 mouse events already use logical coordinates. -#ifdef USE_SDL1 - OutputToLogical(&event->button.x, &event->button.y); -#endif - bool handled = false; for (const auto &item : items) { if (HandleMouseEvent(*event, item)) { @@ -1178,11 +1175,6 @@ bool UiItemMouseEvents(SDL_Event *event, const std::vectorbutton.x, &event->button.y); -#endif - bool handled = false; for (const auto &item : items) { if (HandleMouseEvent(*event, item.get())) { diff --git a/Source/engine/events.cpp b/Source/engine/events.cpp index 1fbd15a80..0895accba 100644 --- a/Source/engine/events.cpp +++ b/Source/engine/events.cpp @@ -3,6 +3,7 @@ #include #ifdef USE_SDL3 +#include #include #else #include @@ -20,13 +21,12 @@ #include "movie.h" #include "options.h" #include "panels/console.hpp" +#include "utils/display.h" #include "utils/is_of.hpp" #include "utils/log.hpp" #include "utils/sdl_compat.h" -#ifdef USE_SDL1 -#include "utils/display.h" -#else +#ifndef USE_SDL1 #include "controls/touch/event_handlers.h" #endif @@ -93,13 +93,10 @@ bool FetchMessage_Real(SDL_Event *event, uint16_t *modState) } #endif -#ifdef USE_SDL1 - if (e.type == SDL_MOUSEMOTION) { - OutputToLogical(&e.motion.x, &e.motion.y); - } else if (IsAnyOf(e.type, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP)) { - OutputToLogical(&e.button.x, &e.button.y); + if (!SDLC_ConvertEventToRenderCoordinates(renderer, &e)) { + LogWarn(LogCategory::Application, "SDL_ConvertEventToRenderCoordinates: {}", SDL_GetError()); + SDL_ClearError(); } -#endif if (HandleControllerAddedOrRemovedEvent(e)) return true; diff --git a/Source/platform/switch/CMakeLists.txt b/Source/platform/switch/CMakeLists.txt index 92684961f..5e7553bd8 100644 --- a/Source/platform/switch/CMakeLists.txt +++ b/Source/platform/switch/CMakeLists.txt @@ -22,4 +22,5 @@ endif() target_link_libraries(libdevilutionx_switch PUBLIC DevilutionX::SDL + libdevilutionx_log ) diff --git a/Source/utils/display.h b/Source/utils/display.h index 68b6a6a07..0ddbc73b3 100644 --- a/Source/utils/display.h +++ b/Source/utils/display.h @@ -18,6 +18,7 @@ #endif #include "utils/attributes.h" +#include "utils/log.hpp" #include "utils/sdl_ptrs.h" #include "utils/ui_fwd.h" @@ -64,27 +65,27 @@ template < typename = typename std::enable_if::value, T>::type> void OutputToLogical(T *x, T *y) { -#ifndef USE_SDL1 - if (!renderer) +#ifdef USE_SDL3 + if (renderer == nullptr) return; + float outX, outY; + if (!SDL_RenderCoordinatesFromWindow(renderer, *x, *y, &outX, &outY)) { + LogError("SDL_RenderCoordinatesFromWindow: {}", SDL_GetError()); + SDL_ClearError(); return; - + } + *x = static_cast(outX); + *y = static_cast(outY); +#elif !defined(USE_SDL1) + if (renderer == nullptr) return; float scaleX; -#ifdef USE_SDL3 - SDL_GetRenderScale(renderer, &scaleX, nullptr); -#else SDL_RenderGetScale(renderer, &scaleX, nullptr); -#endif float scaleDpi = GetDpiScalingFactor(); float scale = scaleX / scaleDpi; *x = static_cast(*x / scale); *y = static_cast(*y / scale); SDL_Rect view; -#ifdef USE_SDL3 - SDL_GetRenderViewport(renderer, &view); -#else SDL_RenderGetViewport(renderer, &view); -#endif *x -= view.x; *y -= view.y; #else @@ -101,24 +102,25 @@ template < typename = typename std::enable_if::value, T>::type> void LogicalToOutput(T *x, T *y) { -#ifndef USE_SDL1 - if (!renderer) +#ifdef USE_SDL3 + if (renderer == nullptr) return; + float outX, outY; + if (!SDL_RenderCoordinatesToWindow(renderer, *x, *y, &outX, &outY)) { + LogError("SDL_RenderCoordinatesFromWindow: {}", SDL_GetError()); + SDL_ClearError(); return; + } + *x = static_cast(outX); + *y = static_cast(outY); +#elif !defined(USE_SDL1) + if (renderer == nullptr) return; SDL_Rect view; -#ifdef USE_SDL3 - SDL_GetRenderViewport(renderer, &view); -#else SDL_RenderGetViewport(renderer, &view); -#endif *x += view.x; *y += view.y; float scaleX; -#ifdef USE_SDL3 - SDL_GetRenderScale(renderer, &scaleX, nullptr); -#else SDL_RenderGetScale(renderer, &scaleX, nullptr); -#endif float scaleDpi = GetDpiScalingFactor(); float scale = scaleX / scaleDpi; *x = static_cast(*x * scale); diff --git a/Source/utils/sdl_compat.h b/Source/utils/sdl_compat.h index 51c29bdab..fed7e2e08 100644 --- a/Source/utils/sdl_compat.h +++ b/Source/utils/sdl_compat.h @@ -6,12 +6,15 @@ #include #include #include +#include #include #include #include #else #include -#ifndef USE_SDL1 +#ifdef USE_SDL1 +#include "utils/display.h" +#else #include "utils/sdl2_backports.h" #endif #endif @@ -387,6 +390,32 @@ inline const Uint8 *SDLC_GetKeyState() #endif } +// Convert events to renderer coordinates. +// This is done automatically in SDL2 but not in SDL3 and SDL1.2. +inline bool SDLC_ConvertEventToRenderCoordinates( +#ifndef USE_SDL1 + SDL_Renderer *renderer, +#else + void *, +#endif + SDL_Event *event) +{ +#ifdef USE_SDL3 + if (renderer != nullptr) { + return SDL_ConvertEventToRenderCoordinates(renderer, event); + } +#elif !defined(USE_SDL1) + // No-op in SDL2. +#else + if (event->type == SDL_MOUSEMOTION) { + devilution::OutputToLogical(&event->motion.x, &event->motion.y); + } else if (event->type == SDL_MOUSEBUTTONDOWN || event->type == SDL_MOUSEBUTTONUP) { + devilution::OutputToLogical(&event->button.x, &event->button.y); + } +#endif + return true; +} + // Sets the palette's colors and: // SDL3 and SDL2: Points the surface's palette to the given palette if necessary. // SDL1: Sets the surface's colors.