Browse Source

SDL3: Convert events to render coordinates

Fixes mouse clicks with hardware cursor + integer scaling.
pull/8224/head
Gleb Mazovetskiy 5 months ago
parent
commit
fc1d447918
  1. 18
      Source/DiabloUI/diabloui.cpp
  2. 15
      Source/engine/events.cpp
  3. 1
      Source/platform/switch/CMakeLists.txt
  4. 44
      Source/utils/display.h
  5. 31
      Source/utils/sdl_compat.h

18
Source/DiabloUI/diabloui.cpp

@ -11,6 +11,7 @@
#include <vector>
#ifdef USE_SDL3
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_keyboard.h>
#include <SDL3/SDL_rect.h>
@ -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<tl::function_ref<bool(SDL_Event &)>> 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<UiItemBase *> &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::vector<std::unique_ptr<UiIte
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.get())) {

15
Source/engine/events.cpp

@ -3,6 +3,7 @@
#include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_events.h>
#else
#include <SDL.h>
@ -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;

1
Source/platform/switch/CMakeLists.txt

@ -22,4 +22,5 @@ endif()
target_link_libraries(libdevilutionx_switch PUBLIC
DevilutionX::SDL
libdevilutionx_log
)

44
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<std::is_arithmetic<T>::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<T>(outX);
*y = static_cast<T>(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<T>(*x / scale);
*y = static_cast<T>(*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<std::is_arithmetic<T>::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<T>(outX);
*y = static_cast<T>(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<T>(*x * scale);

31
Source/utils/sdl_compat.h

@ -6,12 +6,15 @@
#include <SDL3/SDL_keyboard.h>
#include <SDL3/SDL_keycode.h>
#include <SDL3/SDL_pixels.h>
#include <SDL3/SDL_render.h>
#include <SDL3/SDL_scancode.h>
#include <SDL3/SDL_surface.h>
#include <SDL3/SDL_version.h>
#else
#include <SDL.h>
#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.

Loading…
Cancel
Save