Browse Source

SDL3: Even more migration

pull/8214/head
Gleb Mazovetskiy 5 months ago
parent
commit
1bbe8bfe08
  1. 4
      .github/workflows/Linux_x86_64_SDL3_test.yml
  2. 7
      CMakeLists.txt
  3. 13
      Source/DiabloUI/button.cpp
  4. 18
      Source/DiabloUI/credits.cpp
  5. 183
      Source/DiabloUI/diabloui.cpp
  6. 6
      Source/DiabloUI/diabloui.h
  7. 54
      Source/DiabloUI/dialogs.cpp
  8. 5
      Source/DiabloUI/hero/selhero.cpp
  9. 5
      Source/DiabloUI/mainmenu.cpp
  10. 5
      Source/DiabloUI/multi/selconn.cpp
  11. 7
      Source/DiabloUI/multi/selgame.cpp
  12. 39
      Source/DiabloUI/progress.cpp
  13. 4
      Source/DiabloUI/selok.cpp
  14. 2
      Source/DiabloUI/title.cpp
  15. 20
      Source/capture.cpp
  16. 32
      Source/control.cpp
  17. 4
      Source/controls/axis_direction.cpp
  18. 6
      Source/controls/controller.cpp
  19. 13
      Source/controls/devices/game_controller.h
  20. 12
      Source/controls/devices/joystick.cpp
  21. 14
      Source/controls/input.h
  22. 23
      Source/controls/keymapper.cpp
  23. 4
      Source/controls/keymapper.hpp
  24. 54
      Source/controls/menu_controls.cpp
  25. 7
      Source/controls/menu_controls.h
  26. 131
      Source/controls/plrctrls.cpp
  27. 4
      Source/controls/plrctrls.h
  28. 5
      Source/controls/remap_keyboard.h
  29. 113
      Source/controls/touch/event_handlers.cpp
  30. 4
      Source/controls/touch/event_handlers.h
  31. 28
      Source/controls/touch/renderers.cpp
  32. 4
      Source/controls/touch/renderers.h
  33. 21
      Source/cursor.cpp
  34. 6
      Source/diablo_msg.cpp
  35. 155
      Source/engine/demomode.cpp
  36. 4
      Source/engine/demomode.h
  37. 65
      Source/engine/dx.cpp
  38. 5
      Source/engine/dx.h
  39. 101
      Source/engine/events.cpp
  40. 8
      Source/engine/events.hpp
  41. 2
      Source/engine/palette.cpp
  42. 31
      Source/engine/render/scrollrt.cpp
  43. 14
      Source/gmenu.cpp
  44. 6
      Source/gmenu.h
  45. 93
      Source/hwcursor.cpp
  46. 17
      Source/hwcursor.hpp
  47. 52
      Source/init.cpp
  48. 4
      Source/init.hpp
  49. 59
      Source/interfac.cpp
  50. 12
      Source/inv.cpp
  51. 5
      Source/items.cpp
  52. 1
      Source/loadsave.cpp
  53. 11
      Source/menu.cpp
  54. 33
      Source/movie.cpp
  55. 6
      Source/msg.cpp
  56. 4
      Source/nthread.cpp
  57. 48
      Source/panels/console.cpp
  58. 28
      Source/pfile.cpp
  59. 7
      Source/player.cpp
  60. 8
      Source/plrmsg.cpp
  61. 2
      Source/plrmsg.h
  62. 14
      Source/restrict.cpp
  63. 75
      Source/storm/storm_svid.cpp
  64. 7
      Source/tmsg.cpp
  65. 2
      Source/track.cpp
  66. 228
      Source/utils/display.cpp
  67. 35
      Source/utils/display.h
  68. 16
      Source/utils/png.h
  69. 30
      Source/utils/sdl_bilinear_scale.cpp
  70. 10
      Source/utils/sdl_bilinear_scale.hpp
  71. 64
      Source/utils/sdl_compat.h
  72. 45
      Source/utils/sdl_mutex.h
  73. 5
      test/palette_blending_benchmark.cpp
  74. 5
      test/palette_blending_test.cpp

4
.github/workflows/Linux_x86_64_SDL3_test.yml

@ -36,8 +36,8 @@ jobs:
uses: actions/cache@v4 uses: actions/cache@v4
with: with:
path: build path: build
key: ${{ github.workflow }}-v2-${{ github.sha }} key: ${{ github.workflow }}-v3-${{ github.sha }}
restore-keys: ${{ github.workflow }}-v2- restore-keys: ${{ github.workflow }}-v3-
# We specify `-DDEVILUTIONX_SYSTEM_BENCHMARK=OFF` to work around the following error: # We specify `-DDEVILUTIONX_SYSTEM_BENCHMARK=OFF` to work around the following error:
# lto1: fatal error: bytecode stream in file ‘/usr/lib/x86_64-linux-gnu/libbenchmark_main.a’ generated with LTO version 11.2 instead of the expected 11.3 # lto1: fatal error: bytecode stream in file ‘/usr/lib/x86_64-linux-gnu/libbenchmark_main.a’ generated with LTO version 11.2 instead of the expected 11.3

7
CMakeLists.txt

@ -112,7 +112,12 @@ endif()
# Graphics options # Graphics options
if(NOT USE_SDL1) if(NOT USE_SDL1)
set(DEVILUTIONX_DISPLAY_TEXTURE_FORMAT "SDL_PIXELFORMAT_RGB888" CACHE STRING "Texture format for DevilutionX textures when using the GPU renderer") if(USE_SDL3)
set(_texture_format_default "SDL_PIXELFORMAT_XRGB8888")
else()
set(_texture_format_default "SDL_PIXELFORMAT_RGB888")
endif()
set(DEVILUTIONX_DISPLAY_TEXTURE_FORMAT "${_texture_format_default}" CACHE STRING "Texture format for DevilutionX textures when using the GPU renderer")
mark_as_advanced(DEVILUTIONX_DISPLAY_TEXTURE_FORMAT) mark_as_advanced(DEVILUTIONX_DISPLAY_TEXTURE_FORMAT)
endif() endif()

13
Source/DiabloUI/button.cpp

@ -2,7 +2,12 @@
#include <optional> #include <optional>
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_mouse.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include "DiabloUI/diabloui.h" #include "DiabloUI/diabloui.h"
#include "DiabloUI/ui_flags.hpp" #include "DiabloUI/ui_flags.hpp"
@ -60,13 +65,21 @@ bool HandleMouseEventButton(const SDL_Event &event, UiButton *button)
if (event.button.button != SDL_BUTTON_LEFT) if (event.button.button != SDL_BUTTON_LEFT)
return false; return false;
switch (event.type) { switch (event.type) {
#ifdef USE_SDL3
case SDL_EVENT_MOUSE_BUTTON_UP:
#else
case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONUP:
#endif
if (button->IsPressed()) { if (button->IsPressed()) {
button->Activate(); button->Activate();
return true; return true;
} }
return false; return false;
#ifdef USE_SDL3
case SDL_EVENT_MOUSE_BUTTON_DOWN:
#else
case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONDOWN:
#endif
button->Press(); button->Press();
return true; return true;
default: default:

18
Source/DiabloUI/credits.cpp

@ -6,7 +6,14 @@
#include <string_view> #include <string_view>
#include <vector> #include <vector>
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_surface.h>
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include "DiabloUI/credits_lines.h" #include "DiabloUI/credits_lines.h"
#include "DiabloUI/diabloui.h" #include "DiabloUI/diabloui.h"
@ -102,7 +109,11 @@ void CreditsRenderer::Render()
return; return;
prev_offset_y_ = offsetY; prev_offset_y_ = offsetY;
#ifdef USE_SDL3
SDL_FillSurfaceRect(DiabloUiSurface(), nullptr, 0);
#else
SDL_FillRect(DiabloUiSurface(), nullptr, 0x000000); SDL_FillRect(DiabloUiSurface(), nullptr, 0x000000);
#endif
const Point uiPosition = GetUIRectangle().position; const Point uiPosition = GetUIRectangle().position;
if (ArtBackgroundWidescreen) if (ArtBackgroundWidescreen)
RenderClxSprite(Surface(DiabloUiSurface()), (*ArtBackgroundWidescreen)[0], uiPosition - Displacement { 320, 0 }); RenderClxSprite(Surface(DiabloUiSurface()), (*ArtBackgroundWidescreen)[0], uiPosition - Displacement { 320, 0 });
@ -152,10 +163,15 @@ bool TextDialog(const char *const *text, std::size_t textLines)
do { do {
creditsRenderer.Render(); creditsRenderer.Render();
UiFadeIn(); UiFadeIn();
while (PollEvent(&event) != 0) { while (PollEvent(&event)) {
switch (event.type) { switch (event.type) {
#ifdef USE_SDL3
case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP:
#else
case SDL_KEYDOWN: case SDL_KEYDOWN:
case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONUP:
#endif
endMenu = true; endMenu = true;
break; break;
default: default:

183
Source/DiabloUI/diabloui.cpp

@ -10,7 +10,16 @@
#include <string_view> #include <string_view>
#include <vector> #include <vector>
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_keyboard.h>
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_surface.h>
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include <function_ref.hpp> #include <function_ref.hpp>
#include "DiabloUI/button.h" #include "DiabloUI/button.h"
@ -401,17 +410,34 @@ void UiOnBackgroundChange()
// of single-player characters. // of single-player characters.
// //
// Black out the screen immediately to make it appear more smooth. // Black out the screen immediately to make it appear more smooth.
#ifdef USE_SDL3
SDL_FillSurfaceRect(DiabloUiSurface(), nullptr, 0);
#else
SDL_FillRect(DiabloUiSurface(), nullptr, 0x000000); SDL_FillRect(DiabloUiSurface(), nullptr, 0x000000);
#endif
if (DiabloUiSurface() == PalSurface) if (DiabloUiSurface() == PalSurface)
BltFast(nullptr, nullptr); BltFast(nullptr, nullptr);
RenderPresent(); RenderPresent();
} }
} // namespace
void UiFocusNavigation(SDL_Event *event) void UiFocusNavigation(SDL_Event *event)
{ {
switch (event->type) { switch (event->type) {
#ifdef USE_SDL3
case SDL_EVENT_KEY_UP:
case SDL_EVENT_MOUSE_BUTTON_UP:
case SDL_EVENT_MOUSE_MOTION:
case SDL_EVENT_MOUSE_WHEEL:
case SDL_EVENT_JOYSTICK_BUTTON_UP:
case SDL_EVENT_JOYSTICK_AXIS_MOTION:
case SDL_EVENT_JOYSTICK_BALL_MOTION:
case SDL_EVENT_JOYSTICK_HAT_MOTION:
case SDL_EVENT_FINGER_UP:
case SDL_EVENT_FINGER_MOTION:
case SDL_EVENT_GAMEPAD_BUTTON_UP:
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
case SDL_EVENT_WINDOW_EXPOSED:
#else
case SDL_KEYUP: case SDL_KEYUP:
case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONUP:
case SDL_MOUSEMOTION: case SDL_MOUSEMOTION:
@ -430,8 +456,11 @@ void UiFocusNavigation(SDL_Event *event)
case SDL_WINDOWEVENT: case SDL_WINDOWEVENT:
#endif #endif
case SDL_SYSWMEVENT: case SDL_SYSWMEVENT:
#endif
mainmenu_restart_repintro(); mainmenu_restart_repintro();
break; break;
default:
break;
} }
bool menuActionHandled = false; bool menuActionHandled = false;
@ -440,7 +469,16 @@ void UiFocusNavigation(SDL_Event *event)
if (menuActionHandled) if (menuActionHandled)
return; return;
#if SDL_VERSION_ATLEAST(2, 0, 0) #ifdef USE_SDL3
if (event->type == SDL_EVENT_MOUSE_WHEEL) {
if (event->wheel.integer_y > 0) {
UiFocusUp();
} else if (event->wheel.integer_y < 0) {
UiFocusDown();
}
return;
}
#elif SDL_VERSION_ATLEAST(2, 0, 0)
if (event->type == SDL_MOUSEWHEEL) { if (event->type == SDL_MOUSEWHEEL) {
if (event->wheel.y > 0) { if (event->wheel.y > 0) {
UiFocusUp(); UiFocusUp();
@ -466,15 +504,29 @@ void UiFocusNavigation(SDL_Event *event)
return; return;
} }
if (event->type == SDL_MOUSEBUTTONDOWN || event->type == SDL_MOUSEBUTTONUP) { if (IsAnyOf(event->type,
if (UiItemMouseEvents(event, gUiItems)) #ifdef USE_SDL3
return; SDL_EVENT_MOUSE_BUTTON_DOWN, SDL_EVENT_MOUSE_BUTTON_UP
#else
SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP
#endif
)
&& UiItemMouseEvents(event, gUiItems)) {
return;
} }
} }
} // namespace
void UiHandleEvents(SDL_Event *event) void UiHandleEvents(SDL_Event *event)
{ {
if (event->type == SDL_MOUSEMOTION) { if (event->type ==
#ifdef USE_SDL3
SDL_EVENT_MOUSE_MOTION
#else
SDL_MOUSEMOTION
#endif
) {
#ifdef USE_SDL1 #ifdef USE_SDL1
OutputToLogical(&event->motion.x, &event->motion.y); OutputToLogical(&event->motion.x, &event->motion.y);
#endif #endif
@ -482,8 +534,13 @@ void UiHandleEvents(SDL_Event *event)
return; return;
} }
if (event->type == SDL_KEYDOWN && event->key.keysym.sym == SDLK_RETURN) { #ifdef USE_SDL3
const Uint8 *state = SDLC_GetKeyState(); if (event->type == SDL_EVENT_KEY_DOWN && event->key.key == SDLK_RETURN)
#else
if (event->type == SDL_KEYDOWN && event->key.keysym.sym == SDLK_RETURN)
#endif
{
const auto *state = SDLC_GetKeyState();
if (state[SDLC_KEYSTATE_LALT] != 0 || state[SDLC_KEYSTATE_RALT] != 0) { if (state[SDLC_KEYSTATE_LALT] != 0 || state[SDLC_KEYSTATE_RALT] != 0) {
GetOptions().Graphics.fullscreen.SetValue(!IsFullScreen()); GetOptions().Graphics.fullscreen.SetValue(!IsFullScreen());
SaveOptions(); SaveOptions();
@ -493,12 +550,41 @@ void UiHandleEvents(SDL_Event *event)
} }
} }
if (event->type == SDL_QUIT) if (event->type ==
#ifdef USE_SDL3
SDL_EVENT_QUIT
#else
SDL_QUIT
#endif
) {
diablo_quit(0); diablo_quit(0);
}
#ifndef USE_SDL1 #ifndef USE_SDL1
HandleControllerAddedOrRemovedEvent(*event); HandleControllerAddedOrRemovedEvent(*event);
#ifdef USE_SDL3
switch (event->type) {
case SDL_EVENT_WINDOW_SHOWN:
case SDL_EVENT_WINDOW_EXPOSED:
case SDL_EVENT_WINDOW_RESTORED:
gbActive = true;
break;
case SDL_EVENT_WINDOW_HIDDEN:
case SDL_EVENT_WINDOW_MINIMIZED:
gbActive = false;
break;
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
DoReinitializeHardwareCursor();
break;
case SDL_EVENT_WINDOW_FOCUS_LOST:
if (*GetOptions().Gameplay.pauseOnFocusLoss) music_mute();
break;
case SDL_EVENT_WINDOW_FOCUS_GAINED:
if (*GetOptions().Gameplay.pauseOnFocusLoss) diablo_focus_unpause();
break;
}
#else
if (event->type == SDL_WINDOWEVENT) { if (event->type == SDL_WINDOWEVENT) {
if (IsAnyOf(event->window.event, SDL_WINDOWEVENT_SHOWN, SDL_WINDOWEVENT_EXPOSED, SDL_WINDOWEVENT_RESTORED)) { if (IsAnyOf(event->window.event, SDL_WINDOWEVENT_SHOWN, SDL_WINDOWEVENT_EXPOSED, SDL_WINDOWEVENT_RESTORED)) {
gbActive = true; gbActive = true;
@ -517,6 +603,7 @@ void UiHandleEvents(SDL_Event *event)
diablo_focus_unpause(); diablo_focus_unpause();
} }
} }
#endif
#else #else
if (event->type == SDL_ACTIVEEVENT && (event->active.state & SDL_APPINPUTFOCUS) != 0) { if (event->type == SDL_ACTIVEEVENT && (event->active.state & SDL_APPINPUTFOCUS) != 0) {
if (event->active.gain == 0) if (event->active.gain == 0)
@ -786,14 +873,19 @@ void DrawSelector(const SDL_Rect &rect)
void UiClearScreen() void UiClearScreen()
{ {
if (!ArtBackground || gnScreenWidth > (*ArtBackground)[0].width() || gnScreenHeight > (*ArtBackground)[0].height()) if (!ArtBackground || gnScreenWidth > (*ArtBackground)[0].width() || gnScreenHeight > (*ArtBackground)[0].height()) {
#ifdef USE_SDL3
SDL_FillSurfaceRect(DiabloUiSurface(), nullptr, 0);
#else
SDL_FillRect(DiabloUiSurface(), nullptr, 0x000000); SDL_FillRect(DiabloUiSurface(), nullptr, 0x000000);
#endif
}
} }
void UiPollAndRender(std::optional<tl::function_ref<bool(SDL_Event &)>> eventHandler) void UiPollAndRender(std::optional<tl::function_ref<bool(SDL_Event &)>> eventHandler)
{ {
SDL_Event event; SDL_Event event;
while (PollEvent(&event) != 0) { while (PollEvent(&event)) {
if (eventHandler && (*eventHandler)(event)) if (eventHandler && (*eventHandler)(event))
continue; continue;
UiFocusNavigation(&event); UiFocusNavigation(&event);
@ -942,7 +1034,13 @@ void Render(const UiEdit &uiEdit)
bool HandleMouseEventArtTextButton(const SDL_Event &event, const UiArtTextButton *uiButton) bool HandleMouseEventArtTextButton(const SDL_Event &event, const UiArtTextButton *uiButton)
{ {
if (event.type != SDL_MOUSEBUTTONUP || event.button.button != SDL_BUTTON_LEFT) { if (event.type !=
#ifdef USE_SDL3
SDL_EVENT_MOUSE_BUTTON_UP
#else
SDL_MOUSEBUTTONUP
#endif
|| event.button.button != SDL_BUTTON_LEFT) {
return false; return false;
} }
@ -959,17 +1057,37 @@ bool HandleMouseEventList(const SDL_Event &event, UiList *uiList)
if (event.button.button != SDL_BUTTON_LEFT) if (event.button.button != SDL_BUTTON_LEFT)
return false; return false;
if (event.type != SDL_MOUSEBUTTONUP && event.type != SDL_MOUSEBUTTONDOWN) if (!IsAnyOf(event.type,
#ifdef USE_SDL3
SDL_EVENT_MOUSE_BUTTON_UP, SDL_EVENT_MOUSE_BUTTON_DOWN
#else
SDL_MOUSEBUTTONUP, SDL_MOUSEBUTTONDOWN
#endif
)) {
return false; return false;
}
std::size_t index = uiList->indexAt(event.button.y); std::size_t index = uiList->indexAt(event.button.y);
if (event.type == SDL_MOUSEBUTTONDOWN) { if (event.type ==
#ifdef USE_SDL3
SDL_EVENT_MOUSE_BUTTON_DOWN
#else
SDL_MOUSEBUTTONDOWN
#endif
) {
uiList->Press(index); uiList->Press(index);
return true; return true;
} }
if (event.type == SDL_MOUSEBUTTONUP && !uiList->IsPressed(index)) if (event.type ==
#ifdef USE_SDL3
SDL_EVENT_MOUSE_BUTTON_UP
#else
SDL_MOUSEBUTTONUP
#endif
&& !uiList->IsPressed(index)) {
return false; return false;
}
index += listOffset; index += listOffset;
@ -998,7 +1116,13 @@ bool HandleMouseEventScrollBar(const SDL_Event &event, const UiScrollbar *uiSb)
{ {
if (event.button.button != SDL_BUTTON_LEFT) if (event.button.button != SDL_BUTTON_LEFT)
return false; return false;
if (event.type == SDL_MOUSEBUTTONUP) { if (event.type ==
#ifdef USE_SDL3
SDL_EVENT_MOUSE_BUTTON_UP
#else
SDL_MOUSEBUTTONUP
#endif
) {
if (scrollBarState.upArrowPressed && IsInsideRect(event, UpArrowRect(*uiSb))) { if (scrollBarState.upArrowPressed && IsInsideRect(event, UpArrowRect(*uiSb))) {
UiFocusUp(); UiFocusUp();
return true; return true;
@ -1007,7 +1131,14 @@ bool HandleMouseEventScrollBar(const SDL_Event &event, const UiScrollbar *uiSb)
UiFocusDown(); UiFocusDown();
return true; return true;
} }
} else if (event.type == SDL_MOUSEBUTTONDOWN) { } else if (event.type ==
#ifdef USE_SDL3
SDL_EVENT_MOUSE_BUTTON_DOWN
#else
SDL_MOUSEBUTTONDOWN
#endif
) {
if (IsInsideRect(event, BarRect(*uiSb))) { if (IsInsideRect(event, BarRect(*uiSb))) {
// Scroll up or down based on thumb position. // Scroll up or down based on thumb position.
const SDL_Rect thumbRect = ThumbRect(*uiSb, SelectedItem, SelectedItemMax + 1); const SDL_Rect thumbRect = ThumbRect(*uiSb, SelectedItem, SelectedItemMax + 1);
@ -1116,7 +1247,13 @@ bool UiItemMouseEvents(SDL_Event *event, const std::vector<UiItemBase *> &items)
} }
} }
if (event->type == SDL_MOUSEBUTTONUP && event->button.button == SDL_BUTTON_LEFT) { if (event->type ==
#ifdef USE_SDL3
SDL_EVENT_MOUSE_BUTTON_UP
#else
SDL_MOUSEBUTTONUP
#endif
&& event->button.button == SDL_BUTTON_LEFT) {
scrollBarState.downArrowPressed = scrollBarState.upArrowPressed = false; scrollBarState.downArrowPressed = scrollBarState.upArrowPressed = false;
for (const auto &item : items) { for (const auto &item : items) {
if (item->IsType(UiType::Button)) { if (item->IsType(UiType::Button)) {
@ -1149,7 +1286,13 @@ bool UiItemMouseEvents(SDL_Event *event, const std::vector<std::unique_ptr<UiIte
} }
} }
if (event->type == SDL_MOUSEBUTTONUP && event->button.button == SDL_BUTTON_LEFT) { if (event->type ==
#ifdef USE_SDL3
SDL_EVENT_MOUSE_BUTTON_UP
#else
SDL_MOUSEBUTTONUP
#endif
&& event->button.button == SDL_BUTTON_LEFT) {
scrollBarState.downArrowPressed = scrollBarState.upArrowPressed = false; scrollBarState.downArrowPressed = scrollBarState.upArrowPressed = false;
for (const auto &item : items) { for (const auto &item : items) {
if (item->IsType(UiType::Button)) { if (item->IsType(UiType::Button)) {

6
Source/DiabloUI/diabloui.h

@ -5,7 +5,13 @@
#include <cstdint> #include <cstdint>
#include <optional> #include <optional>
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_surface.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include <function_ref.hpp> #include <function_ref.hpp>
#include "DiabloUI/ui_item.h" #include "DiabloUI/ui_item.h"

54
Source/DiabloUI/dialogs.cpp

@ -7,7 +7,16 @@
#include <string_view> #include <string_view>
#include <vector> #include <vector>
#ifdef USE_SDL3
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_messagebox.h>
#include <SDL3/SDL_mouse.h>
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_surface.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include "DiabloUI/button.h" #include "DiabloUI/button.h"
#include "DiabloUI/diabloui.h" #include "DiabloUI/diabloui.h"
@ -68,7 +77,13 @@ bool Init(std::string_view caption, std::string_view text, bool error, bool rend
{ {
if (!renderBehind) { if (!renderBehind) {
if (!UiLoadBlackBackground()) { if (!UiLoadBlackBackground()) {
if (SDL_ShowCursor(SDL_ENABLE) <= -1) if (
#ifdef USE_SDL3
SDL_ShowCursor()
#else
SDL_ShowCursor(SDL_ENABLE) <= -1
#endif
)
LogError("{}", SDL_GetError()); LogError("{}", SDL_GetError());
} }
} }
@ -123,10 +138,15 @@ void DialogLoop(const std::vector<std::unique_ptr<UiItemBase>> &items, const std
SDL_Event event; SDL_Event event;
dialogEnd = false; dialogEnd = false;
do { do {
while (PollEvent(&event) != 0) { while (PollEvent(&event)) {
switch (event.type) { switch (event.type) {
#ifdef USE_SDL3
case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP:
#else
case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONUP:
#endif
UiItemMouseEvents(&event, items); UiItemMouseEvents(&event, items);
break; break;
default: default:
@ -162,8 +182,15 @@ void UiOkDialog(std::string_view caption, std::string_view text, bool error, con
if (!gbActive || inDialog) { if (!gbActive || inDialog) {
if (!HeadlessMode) { if (!HeadlessMode) {
if (SDL_ShowCursor(SDL_ENABLE) <= -1) if (
#ifdef USE_SDL3
SDL_ShowCursor()
#else
SDL_ShowCursor(SDL_ENABLE) <= -1
#endif
) {
LogError("{}", SDL_GetError()); LogError("{}", SDL_GetError());
}
const std::string captionStr = std::string(caption); const std::string captionStr = std::string(caption);
const std::string textStr = std::string(text); const std::string textStr = std::string(text);
if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, captionStr.c_str(), textStr.c_str(), nullptr) <= -1) { if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, captionStr.c_str(), textStr.c_str(), nullptr) <= -1) {
@ -174,21 +201,38 @@ void UiOkDialog(std::string_view caption, std::string_view text, bool error, con
} }
if (IsHardwareCursor()) { if (IsHardwareCursor()) {
if (SDL_ShowCursor(SDL_ENABLE) <= -1) if (
#ifdef USE_SDL3
SDL_ShowCursor()
#else
SDL_ShowCursor(SDL_ENABLE) <= -1
#endif
) {
LogError("{}", SDL_GetError()); LogError("{}", SDL_GetError());
}
} }
if (!Init(caption, text, error, !renderBehind.empty())) { if (!Init(caption, text, error, !renderBehind.empty())) {
LogError("{}\n{}", caption, text); LogError("{}\n{}", caption, text);
const std::string captionStr = std::string(caption); const std::string captionStr = std::string(caption);
const std::string textStr = std::string(text); const std::string textStr = std::string(text);
if (SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, captionStr.c_str(), textStr.c_str(), nullptr) <= -1) { if (
#ifdef USE_SDL3
!SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, captionStr.c_str(), textStr.c_str(), nullptr)
#else
SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, captionStr.c_str(), textStr.c_str(), nullptr) <= -1
#endif
) {
LogError("{}", SDL_GetError()); LogError("{}", SDL_GetError());
} }
} }
inDialog = true; inDialog = true;
#ifdef USE_SDL3
SDL_SetSurfaceClipRect(DiabloUiSurface(), nullptr);
#else
SDL_SetClipRect(DiabloUiSurface(), nullptr); SDL_SetClipRect(DiabloUiSurface(), nullptr);
#endif
DialogLoop(vecOkDialog, renderBehind); DialogLoop(vecOkDialog, renderBehind);
Deinit(); Deinit();
inDialog = false; inDialog = false;

5
Source/DiabloUI/hero/selhero.cpp

@ -10,7 +10,12 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#ifdef USE_SDL3
#include <SDL3/SDL_rect.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include <fmt/core.h> #include <fmt/core.h>
#include "DiabloUI/diabloui.h" #include "DiabloUI/diabloui.h"

5
Source/DiabloUI/mainmenu.cpp

@ -4,7 +4,12 @@
#include <optional> #include <optional>
#include <vector> #include <vector>
#ifdef USE_SDL3
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include "DiabloUI/diabloui.h" #include "DiabloUI/diabloui.h"
#include "DiabloUI/ui_flags.hpp" #include "DiabloUI/ui_flags.hpp"

5
Source/DiabloUI/multi/selconn.cpp

@ -4,7 +4,12 @@
#include <string_view> #include <string_view>
#include <vector> #include <vector>
#ifdef USE_SDL3
#include <SDL3/SDL_rect.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include <fmt/core.h> #include <fmt/core.h>
#include "DiabloUI/diabloui.h" #include "DiabloUI/diabloui.h"

7
Source/DiabloUI/multi/selgame.cpp

@ -9,7 +9,14 @@
#include <string_view> #include <string_view>
#include <vector> #include <vector>
#ifdef USE_SDL3
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include <fmt/core.h> #include <fmt/core.h>
#include "DiabloUI/diabloui.h" #include "DiabloUI/diabloui.h"

39
Source/DiabloUI/progress.cpp

@ -2,7 +2,13 @@
#include <optional> #include <optional>
#include <vector> #include <vector>
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_surface.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include "DiabloUI/button.h" #include "DiabloUI/button.h"
#include "DiabloUI/diabloui.h" #include "DiabloUI/diabloui.h"
@ -71,7 +77,11 @@ Point GetPosition()
void ProgressRenderBackground() void ProgressRenderBackground()
{ {
#ifdef USE_SDL3
SDL_FillSurfaceRect(DiabloUiSurface(), nullptr, 0);
#else
SDL_FillRect(DiabloUiSurface(), nullptr, 0x000000); SDL_FillRect(DiabloUiSurface(), nullptr, 0x000000);
#endif
const Surface &out = Surface(DiabloUiSurface()); const Surface &out = Surface(DiabloUiSurface());
const Point position = GetPosition(); const Point position = GetPosition();
@ -128,19 +138,36 @@ bool UiProgressDialog(int (*fnfunc)())
DrawMouse(); DrawMouse();
UiFadeIn(); UiFadeIn();
while (PollEvent(&event) != 0) { while (PollEvent(&event)) {
switch (event.type) { switch (event.type) {
#ifdef USE_SDL3
case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP:
#else
case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONUP:
#endif
UiItemMouseEvents(&event, vecProgress); UiItemMouseEvents(&event, vecProgress);
break; break;
#ifdef USE_SDL3
case SDL_EVENT_KEY_DOWN:
switch (event.key.key)
#else
case SDL_KEYDOWN:
switch (event.key.keysym.sym)
#endif
{
#ifndef USE_SDL1 #ifndef USE_SDL1
case SDLK_KP_ENTER: case SDLK_KP_ENTER:
#endif #endif
case SDLK_ESCAPE: case SDLK_ESCAPE:
case SDLK_RETURN: case SDLK_RETURN:
case SDLK_SPACE: case SDLK_SPACE:
endMenu = true; endMenu = true;
break;
default:
break;
}
break; break;
default: default:
for (const MenuAction menuAction : GetMenuActions(event)) { for (const MenuAction menuAction : GetMenuActions(event)) {

4
Source/DiabloUI/selok.cpp

@ -5,7 +5,11 @@
#include <optional> #include <optional>
#include <vector> #include <vector>
#ifdef USE_SDL3
#include <SDL3/SDL_rect.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include "DiabloUI/diabloui.h" #include "DiabloUI/diabloui.h"
#include "DiabloUI/ui_flags.hpp" #include "DiabloUI/ui_flags.hpp"

2
Source/DiabloUI/title.cpp

@ -77,7 +77,7 @@ void UiTitleDialog()
discord_manager::UpdateMenu(); discord_manager::UpdateMenu();
while (PollEvent(&event) != 0) { while (PollEvent(&event)) {
if (c_any_of(GetMenuActions(event), [](MenuAction menuAction) { return menuAction != MenuAction_NONE; })) { if (c_any_of(GetMenuActions(event), [](MenuAction menuAction) { return menuAction != MenuAction_NONE; })) {
endMenu = true; endMenu = true;
break; break;

20
Source/capture.cpp

@ -9,7 +9,14 @@
#include <cstring> #include <cstring>
#include <ctime> #include <ctime>
#ifdef USE_SDL3
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_iostream.h>
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include <expected.hpp> #include <expected.hpp>
#define DEVILUTIONX_SCREENSHOT_FORMAT_PCX 0 #define DEVILUTIONX_SCREENSHOT_FORMAT_PCX 0
@ -34,7 +41,12 @@
namespace devilution { namespace devilution {
namespace { namespace {
SDL_RWops *CaptureFile(std::string *dstPath) #ifdef USE_SDL3
SDL_IOStream *
#else
SDL_RWops *
#endif
CaptureFile(std::string *dstPath)
{ {
const char *ext = const char *ext =
#if DEVILUTIONX_SCREENSHOT_FORMAT == DEVILUTIONX_SCREENSHOT_FORMAT_PCX #if DEVILUTIONX_SCREENSHOT_FORMAT == DEVILUTIONX_SCREENSHOT_FORMAT_PCX
@ -55,7 +67,11 @@ SDL_RWops *CaptureFile(std::string *dstPath)
i++; i++;
*dstPath = StrCat(paths::PrefPath(), filename, "-", i, ext); *dstPath = StrCat(paths::PrefPath(), filename, "-", i, ext);
} }
#ifdef USE_SDL3
return SDL_IOFromFile(dstPath->c_str(), "wb");
#else
return SDL_RWFromFile(dstPath->c_str(), "wb"); return SDL_RWFromFile(dstPath->c_str(), "wb");
#endif
} }
/** /**
@ -79,7 +95,7 @@ void CaptureScreen()
std::string fileName; std::string fileName;
const uint32_t startTime = SDL_GetTicks(); const uint32_t startTime = SDL_GetTicks();
SDL_RWops *outStream = CaptureFile(&fileName); auto *outStream = CaptureFile(&fileName);
if (outStream == nullptr) { if (outStream == nullptr) {
LogError("Failed to open {} for writing: {}", fileName, SDL_GetError()); LogError("Failed to open {} for writing: {}", fileName, SDL_GetError());
SDL_ClearError(); SDL_ClearError();

32
Source/control.cpp

@ -15,6 +15,7 @@
#ifdef USE_SDL3 #ifdef USE_SDL3
#include <SDL3/SDL_events.h> #include <SDL3/SDL_events.h>
#include <SDL3/SDL_keyboard.h>
#include <SDL3/SDL_keycode.h> #include <SDL3/SDL_keycode.h>
#include <SDL3/SDL_rect.h> #include <SDL3/SDL_rect.h>
#else #else
@ -1248,7 +1249,14 @@ void CheckMainPanelButton()
SetPanelObjectPosition(UiPanels::Main, spellSelectButton); SetPanelObjectPosition(UiPanels::Main, spellSelectButton);
if (!SpellSelectFlag && spellSelectButton.contains(MousePosition)) { if (!SpellSelectFlag && spellSelectButton.contains(MousePosition)) {
if ((SDL_GetModState() & KMOD_SHIFT) != 0) { if ((SDL_GetModState() &
#ifdef USE_SDL3
SDL_KMOD_SHIFT
#else
KMOD_SHIFT
#endif
)
!= 0) {
Player &myPlayer = *MyPlayer; Player &myPlayer = *MyPlayer;
myPlayer._pRSpell = SpellID::Invalid; myPlayer._pRSpell = SpellID::Invalid;
myPlayer._pRSplType = SpellType::Invalid; myPlayer._pRSplType = SpellType::Invalid;
@ -1922,21 +1930,31 @@ void TypeChatMessage()
.value = TalkMessage, .value = TalkMessage,
.cursor = &ChatCursor, .cursor = &ChatCursor,
.maxLength = sizeof(TalkMessage) - 1 }); .maxLength = sizeof(TalkMessage) - 1 });
SDL_Rect rect = MakeSdlRect(GetMainPanel().position.x + 200, GetMainPanel().position.y + 22, 0, 27);
SDL_SetTextInputRect(&rect);
for (bool &talkButtonDown : TalkButtonsDown) { for (bool &talkButtonDown : TalkButtonsDown) {
talkButtonDown = false; talkButtonDown = false;
} }
sgbPlrTalkTbl = GetMainPanel().size.height + PanelPaddingHeight; sgbPlrTalkTbl = GetMainPanel().size.height + PanelPaddingHeight;
RedrawEverything(); RedrawEverything();
TalkSaveIndex = NextTalkSave; TalkSaveIndex = NextTalkSave;
SDL_Rect rect = MakeSdlRect(GetMainPanel().position.x + 200, GetMainPanel().position.y + 22, 0, 27);
#ifdef USE_SDL3
SDL_SetTextInputArea(ghMainWnd, &rect, /*cursor=*/0);
SDL_StartTextInput(ghMainWnd);
#else
SDL_SetTextInputRect(&rect);
SDL_StartTextInput(); SDL_StartTextInput();
#endif
} }
void ResetChat() void ResetChat()
{ {
ChatFlag = false; ChatFlag = false;
#ifdef USE_SDL3
SDL_StopTextInput(ghMainWnd);
#else
SDL_StopTextInput(); SDL_StopTextInput();
#endif
ChatCursor = {}; ChatCursor = {};
ChatInputState = std::nullopt; ChatInputState = std::nullopt;
sgbPlrTalkTbl = 0; sgbPlrTalkTbl = 0;
@ -2042,14 +2060,22 @@ void OpenGoldDrop(int8_t invIndex, int max)
.min = 0, .min = 0,
.max = max, .max = max,
}); });
#ifdef USE_SDL3
SDL_StartTextInput(ghMainWnd);
#else
SDL_StartTextInput(); SDL_StartTextInput();
#endif
} }
void CloseGoldDrop() void CloseGoldDrop()
{ {
if (!DropGoldFlag) if (!DropGoldFlag)
return; return;
#ifdef USE_SDL3
SDL_StopTextInput(ghMainWnd);
#else
SDL_StopTextInput(); SDL_StopTextInput();
#endif
DropGoldFlag = false; DropGoldFlag = false;
GoldDropInputState = std::nullopt; GoldDropInputState = std::nullopt;
GoldDropInvIndex = 0; GoldDropInvIndex = 0;

4
Source/controls/axis_direction.cpp

@ -1,6 +1,10 @@
#include "axis_direction.h" #include "axis_direction.h"
#ifdef USE_SDL3
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
namespace devilution { namespace devilution {

6
Source/controls/controller.cpp

@ -36,11 +36,17 @@ StaticVector<ControllerButtonEvent, 4> ToControllerButtonEvents(const SDL_Event
{ {
ControllerButtonEvent result { ControllerButton_NONE, false }; ControllerButtonEvent result { ControllerButton_NONE, false };
switch (event.type) { switch (event.type) {
#ifdef USE_SDL3
case SDL_EVENT_GAMEPAD_BUTTON_UP:
case SDL_EVENT_JOYSTICK_BUTTON_UP:
case SDL_EVENT_KEY_UP:
#else
#ifndef USE_SDL1 #ifndef USE_SDL1
case SDL_CONTROLLERBUTTONUP: case SDL_CONTROLLERBUTTONUP:
#endif #endif
case SDL_JOYBUTTONUP: case SDL_JOYBUTTONUP:
case SDL_KEYUP: case SDL_KEYUP:
#endif
result.up = true; result.up = true;
break; break;
default: default:

13
Source/controls/devices/game_controller.h

@ -2,7 +2,13 @@
#include <vector> #include <vector>
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_gamepad.h>
#include <SDL3/SDL_joystick.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include "controls/controller_buttons.h" #include "controls/controller_buttons.h"
#include "controls/game_controls.h" #include "controls/game_controls.h"
@ -41,7 +47,12 @@ public:
static GamepadLayout getLayout(const SDL_Event &event); static GamepadLayout getLayout(const SDL_Event &event);
private: private:
SDL_GameController *sdl_game_controller_ = NULL; #ifdef USE_SDL3
SDL_Gamepad *sdl_game_controller_ = nullptr;
#else
SDL_GameController *sdl_game_controller_ = nullptr;
#endif
SDL_JoystickID instance_id_ = -1; SDL_JoystickID instance_id_ = -1;
ControllerButton trigger_left_state_ = ControllerButton_NONE; ControllerButton trigger_left_state_ = ControllerButton_NONE;

12
Source/controls/devices/joystick.cpp

@ -320,14 +320,22 @@ bool Joystick::IsPressed(ControllerButton button) const
const int joyButton = ToSdlJoyButton(button); const int joyButton = ToSdlJoyButton(button);
if (joyButton == -1) if (joyButton == -1)
return false; return false;
#ifdef USE_SDL3
const int numButtons = SDL_GetNumJoystickButtons(sdl_joystick_);
return joyButton < numButtons && SDL_GetJoystickButton(sdl_joystick_, joyButton);
#else
const int numButtons = SDL_JoystickNumButtons(sdl_joystick_); const int numButtons = SDL_JoystickNumButtons(sdl_joystick_);
return joyButton < numButtons && SDL_JoystickGetButton(sdl_joystick_, joyButton) != 0; return joyButton < numButtons && SDL_JoystickGetButton(sdl_joystick_, joyButton) != 0;
#endif
} }
bool Joystick::ProcessAxisMotion(const SDL_Event &event) bool Joystick::ProcessAxisMotion(const SDL_Event &event)
{ {
if (event.type != SDL_JOYAXISMOTION) #ifdef USE_SDL3
return false; if (event.type != SDL_EVENT_JOYSTICK_AXIS_MOTION) return false;
#else
if (event.type != SDL_JOYAXISMOTION) return false;
#endif
#if defined(JOY_AXIS_LEFTX) || defined(JOY_AXIS_LEFTY) || defined(JOY_AXIS_RIGHTX) || defined(JOY_AXIS_RIGHTY) #if defined(JOY_AXIS_LEFTX) || defined(JOY_AXIS_LEFTY) || defined(JOY_AXIS_RIGHTX) || defined(JOY_AXIS_RIGHTY)
switch (event.jaxis.axis) { switch (event.jaxis.axis) {

14
Source/controls/input.h

@ -1,16 +1,24 @@
#pragma once #pragma once
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include "controls/controller.h" #include "controls/controller.h"
#include "controls/controller_motion.h" #include "controls/controller_motion.h"
namespace devilution { namespace devilution {
inline int PollEvent(SDL_Event *event) inline bool PollEvent(SDL_Event *event)
{ {
int result = SDL_PollEvent(event); #ifdef USE_SDL3
if (result != 0) { const bool result = SDL_PollEvent(event);
#else
const bool result = SDL_PollEvent(event) >= 0;
#endif
if (result) {
UnlockControllerState(*event); UnlockControllerState(*event);
ProcessControllerMotion(*event); ProcessControllerMotion(*event);
} }

23
Source/controls/keymapper.cpp

@ -1,10 +1,16 @@
#include "controls/keymapper.hpp" #include "controls/keymapper.hpp"
#include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_keycode.h>
#else
#include <SDL.h> #include <SDL.h>
#ifdef USE_SDL1 #ifdef USE_SDL1
#include "utils/sdl2_to_1_2_backports.h" #include "utils/sdl2_to_1_2_backports.h"
#endif #endif
#endif
#include "control.h" #include "control.h"
#include "options.h" #include "options.h"
@ -15,7 +21,12 @@ namespace {
bool IsTextEntryKey(SDL_Keycode vkey) bool IsTextEntryKey(SDL_Keycode vkey)
{ {
return IsAnyOf(vkey, SDLK_ESCAPE, SDLK_RETURN, SDLK_KP_ENTER, SDLK_BACKSPACE, SDLK_DOWN, SDLK_UP) || (vkey >= SDLK_SPACE && vkey <= SDLK_z); return IsAnyOf(vkey, SDLK_ESCAPE, SDLK_RETURN, SDLK_KP_ENTER, SDLK_BACKSPACE, SDLK_DOWN, SDLK_UP)
#ifdef USE_SDL3
|| (vkey >= SDLK_SPACE && vkey <= SDLK_Z);
#else
|| (vkey >= SDLK_SPACE && vkey <= SDLK_z);
#endif
} }
bool IsNumberEntryKey(SDL_Keycode vkey) bool IsNumberEntryKey(SDL_Keycode vkey)
@ -25,8 +36,14 @@ bool IsNumberEntryKey(SDL_Keycode vkey)
SDL_Keycode ToAsciiUpper(SDL_Keycode key) SDL_Keycode ToAsciiUpper(SDL_Keycode key)
{ {
if (key >= SDLK_a && key <= SDLK_z) { if (
return static_cast<SDL_Keycode>(static_cast<Sint32>(key) - ('a' - 'A')); #ifdef USE_SDL3
key >= SDLK_A && key <= SDLK_Z
#else
key >= SDLK_a && key <= SDLK_z
#endif
) {
return static_cast<SDL_Keycode>(static_cast<int32_t>(key) - ('a' - 'A'));
} }
return key; return key;
} }

4
Source/controls/keymapper.hpp

@ -2,11 +2,15 @@
#include <cstdint> #include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_keycode.h>
#else
#include <SDL.h> #include <SDL.h>
#ifdef USE_SDL1 #ifdef USE_SDL1
#include "utils/sdl2_to_1_2_backports.h" #include "utils/sdl2_to_1_2_backports.h"
#endif #endif
#endif
namespace devilution { namespace devilution {

54
Source/controls/menu_controls.cpp

@ -1,5 +1,13 @@
#include "controls/menu_controls.h" #include "controls/menu_controls.h"
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_keyboard.h>
#include <SDL3/SDL_keycode.h>
#else
#include <SDL.h>
#endif
#include "DiabloUI/diabloui.h" #include "DiabloUI/diabloui.h"
#include "controls/axis_direction.h" #include "controls/axis_direction.h"
#include "controls/control_mode.hpp" #include "controls/control_mode.hpp"
@ -78,7 +86,13 @@ std::vector<MenuAction> GetMenuActions(const SDL_Event &event)
return menuActions; return menuActions;
} }
if (event.type == SDL_MOUSEBUTTONDOWN) { if (event.type ==
#ifdef USE_SDL3
SDL_EVENT_MOUSE_BUTTON_DOWN
#else
SDL_MOUSEBUTTONDOWN
#endif
) {
switch (event.button.button) { switch (event.button.button) {
case SDL_BUTTON_X1: case SDL_BUTTON_X1:
#if !SDL_VERSION_ATLEAST(2, 0, 0) #if !SDL_VERSION_ATLEAST(2, 0, 0)
@ -89,8 +103,20 @@ std::vector<MenuAction> GetMenuActions(const SDL_Event &event)
} }
#if HAS_KBCTRL == 0 #if HAS_KBCTRL == 0
if (event.type == SDL_KEYDOWN) { if (
SDL_Keycode sym = event.key.keysym.sym; event.type ==
#ifdef USE_SDL3
SDL_EVENT_KEY_DOWN
#else
SDL_KEYDOWN
#endif
) {
SDL_Keycode sym =
#ifdef USE_SDL3
event.key.key;
#else
event.key.keysym.sym;
#endif
remap_keyboard_key(&sym); remap_keyboard_key(&sym);
switch (sym) { switch (sym) {
case SDLK_UP: case SDLK_UP:
@ -98,16 +124,30 @@ std::vector<MenuAction> GetMenuActions(const SDL_Event &event)
case SDLK_DOWN: case SDLK_DOWN:
return { MenuAction_DOWN }; return { MenuAction_DOWN };
case SDLK_TAB: case SDLK_TAB:
if ((SDL_GetModState() & KMOD_SHIFT) != 0) if ((SDL_GetModState() &
#ifdef USE_SDL3
SDL_KMOD_SHIFT
#else
KMOD_SHIFT
#endif
)
!= 0) {
return { MenuAction_UP }; return { MenuAction_UP };
else }
return { MenuAction_DOWN }; return { MenuAction_DOWN };
case SDLK_PAGEUP: case SDLK_PAGEUP:
return { MenuAction_PAGE_UP }; return { MenuAction_PAGE_UP };
case SDLK_PAGEDOWN: case SDLK_PAGEDOWN:
return { MenuAction_PAGE_DOWN }; return { MenuAction_PAGE_DOWN };
case SDLK_RETURN: case SDLK_RETURN:
if ((SDL_GetModState() & KMOD_ALT) == 0) { if ((SDL_GetModState() &
#ifdef USE_SDL3
SDL_KMOD_ALT
#else
KMOD_ALT
#endif
)
== 0) {
return { MenuAction_SELECT }; return { MenuAction_SELECT };
} }
break; break;

7
Source/controls/menu_controls.h

@ -1,9 +1,14 @@
#pragma once #pragma once
#include <SDL.h>
#include <cstdint> #include <cstdint>
#include <vector> #include <vector>
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#else
#include <SDL.h>
#endif
namespace devilution { namespace devilution {
enum MenuAction : uint8_t { enum MenuAction : uint8_t {

131
Source/controls/plrctrls.cpp

@ -5,9 +5,17 @@
#include <cstdint> #include <cstdint>
#include <list> #include <list>
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_gamepad.h>
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h>
#ifdef USE_SDL1 #ifdef USE_SDL1
#include "utils/sdl2_to_1_2_backports.h" #include "utils/sdl2_to_1_2_backports.h"
#endif #endif
#endif
#include "automap.h" #include "automap.h"
#include "control.h" #include "control.h"
@ -1592,34 +1600,102 @@ bool IsStickMovementSignificant()
ControlTypes GetInputTypeFromEvent(const SDL_Event &event) ControlTypes GetInputTypeFromEvent(const SDL_Event &event)
{ {
if (IsAnyOf(event.type, SDL_KEYDOWN, SDL_KEYUP)) switch (event.type) {
#ifdef USE_SDL3
case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_KEY_UP:
#else
case SDL_KEYDOWN:
case SDL_KEYUP:
#endif
return ControlTypes::KeyboardAndMouse; return ControlTypes::KeyboardAndMouse;
#ifdef USE_SDL1 #ifdef USE_SDL1
if (IsAnyOf(event.type, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP, SDL_MOUSEMOTION)) case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
case SDL_MOUSEMOTION:
return ControlTypes::KeyboardAndMouse; return ControlTypes::KeyboardAndMouse;
#else #else
if (IsAnyOf(event.type, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP)) // SDL 2/3-only events (touch / gamepad):
#ifdef USE_SDL3
case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP:
#else
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
#endif
return event.button.which == SDL_TOUCH_MOUSEID ? ControlTypes::VirtualGamepad : ControlTypes::KeyboardAndMouse; return event.button.which == SDL_TOUCH_MOUSEID ? ControlTypes::VirtualGamepad : ControlTypes::KeyboardAndMouse;
if (event.type == SDL_MOUSEMOTION) #ifdef USE_SDL3
case SDL_EVENT_MOUSE_MOTION:
#else
case SDL_MOUSEMOTION:
#endif
return event.motion.which == SDL_TOUCH_MOUSEID ? ControlTypes::VirtualGamepad : ControlTypes::KeyboardAndMouse; return event.motion.which == SDL_TOUCH_MOUSEID ? ControlTypes::VirtualGamepad : ControlTypes::KeyboardAndMouse;
if (event.type == SDL_MOUSEWHEEL) #ifdef USE_SDL3
case SDL_EVENT_MOUSE_WHEEL:
#else
case SDL_MOUSEWHEEL:
#endif
return event.wheel.which == SDL_TOUCH_MOUSEID ? ControlTypes::VirtualGamepad : ControlTypes::KeyboardAndMouse; return event.wheel.which == SDL_TOUCH_MOUSEID ? ControlTypes::VirtualGamepad : ControlTypes::KeyboardAndMouse;
if (IsAnyOf(event.type, SDL_FINGERDOWN, SDL_FINGERUP, SDL_FINGERMOTION)) #ifdef USE_SDL3
case SDL_EVENT_FINGER_DOWN:
case SDL_EVENT_FINGER_UP:
case SDL_EVENT_FINGER_MOTION:
#else
case SDL_FINGERDOWN:
case SDL_FINGERUP:
case SDL_FINGERMOTION:
#endif
return ControlTypes::VirtualGamepad; return ControlTypes::VirtualGamepad;
if (event.type == SDL_CONTROLLERAXISMOTION #ifdef USE_SDL3
&& (event.caxis.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT || event.caxis.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT case SDL_EVENT_GAMEPAD_AXIS_MOTION:
|| IsStickMovementSignificant())) #else
return ControlTypes::Gamepad; case SDL_CONTROLLERAXISMOTION:
if (event.type >= SDL_CONTROLLERBUTTONDOWN && event.type <= SDL_CONTROLLERDEVICEREMAPPED) #endif
return ControlTypes::Gamepad; if (
if (IsAnyOf(event.type, SDL_JOYDEVICEADDED, SDL_JOYDEVICEREMOVED)) #ifdef USE_SDL3
return ControlTypes::Gamepad; IsAnyOf(event.gaxis.axis, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER)
#else
IsAnyOf(event.caxis.axis, SDL_CONTROLLER_AXIS_TRIGGERLEFT, SDL_CONTROLLER_AXIS_TRIGGERRIGHT)
#endif
|| IsStickMovementSignificant()) {
return ControlTypes::Gamepad;
}
break;
#endif // !USE_SDL1
#ifdef USE_SDL3
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
case SDL_EVENT_GAMEPAD_BUTTON_UP:
case SDL_EVENT_GAMEPAD_ADDED:
case SDL_EVENT_JOYSTICK_BALL_MOTION:
case SDL_EVENT_JOYSTICK_HAT_MOTION:
case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
case SDL_EVENT_JOYSTICK_BUTTON_UP:
#else
#ifndef USE_SDL1
case SDL_CONTROLLERBUTTONDOWN:
case SDL_CONTROLLERBUTTONUP:
case SDL_CONTROLLERDEVICEADDED:
#endif
case SDL_JOYBALLMOTION:
case SDL_JOYHATMOTION:
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
#endif #endif
if (event.type == SDL_JOYAXISMOTION && IsStickMovementSignificant())
return ControlTypes::Gamepad;
if (event.type >= SDL_JOYBALLMOTION && event.type <= SDL_JOYBUTTONUP)
return ControlTypes::Gamepad; return ControlTypes::Gamepad;
#ifdef USE_SDL3
case SDL_EVENT_JOYSTICK_AXIS_MOTION:
case SDL_EVENT_JOYSTICK_ADDED:
#else
case SDL_JOYAXISMOTION:
#ifndef USE_SDL1
case SDL_JOYDEVICEADDED:
#endif
#endif
if (IsStickMovementSignificant()) return ControlTypes::Gamepad;
break;
default:
break;
}
return ControlTypes::None; return ControlTypes::None;
} }
@ -1631,9 +1707,16 @@ bool ContinueSimulatedMouseEvent(const SDL_Event &event, const ControllerButtonE
return false; return false;
#if !defined(USE_SDL1) && !defined(JOY_AXIS_RIGHTX) && !defined(JOY_AXIS_RIGHTY) #if !defined(USE_SDL1) && !defined(JOY_AXIS_RIGHTX) && !defined(JOY_AXIS_RIGHTY)
if (IsAnyOf(event.type, SDL_JOYAXISMOTION, SDL_JOYHATMOTION, SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP)) { if (IsAnyOf(event.type,
if (!GameController::All().empty()) #ifdef USE_SDL3
return true; SDL_EVENT_JOYSTICK_AXIS_MOTION, SDL_EVENT_JOYSTICK_HAT_MOTION,
SDL_EVENT_JOYSTICK_BUTTON_DOWN, SDL_EVENT_JOYSTICK_BUTTON_UP
#else
SDL_JOYAXISMOTION, SDL_JOYHATMOTION, SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP
#endif
)
&& !GameController::All().empty()) {
return true;
} }
#endif #endif
@ -1662,8 +1745,7 @@ std::string_view ControlTypeToString(ControlTypes controlType)
void LogControlDeviceAndModeChange(ControlTypes newControlDevice, ControlTypes newControlMode) void LogControlDeviceAndModeChange(ControlTypes newControlDevice, ControlTypes newControlMode)
{ {
if (SDL_LogGetPriority(SDL_LOG_CATEGORY_APPLICATION) > SDL_LOG_PRIORITY_VERBOSE) if (!IsLogLevel(LogCategory::Application, SDL_LOG_PRIORITY_VERBOSE)) return;
return;
if (newControlDevice == ControlDevice && newControlMode == ControlMode) if (newControlDevice == ControlDevice && newControlMode == ControlMode)
return; return;
constexpr auto DebugChange = [](ControlTypes before, ControlTypes after) -> std::string { constexpr auto DebugChange = [](ControlTypes before, ControlTypes after) -> std::string {
@ -1692,8 +1774,7 @@ std::string_view GamepadTypeToString(GamepadLayout gamepadLayout)
void LogGamepadChange(GamepadLayout newGamepad) void LogGamepadChange(GamepadLayout newGamepad)
{ {
if (SDL_LogGetPriority(SDL_LOG_CATEGORY_APPLICATION) > SDL_LOG_PRIORITY_VERBOSE) if (!IsLogLevel(LogCategory::Application, SDL_LOG_PRIORITY_VERBOSE)) return;
return;
constexpr auto DebugChange = [](GamepadLayout before, GamepadLayout after) -> std::string { constexpr auto DebugChange = [](GamepadLayout before, GamepadLayout after) -> std::string {
if (before == after) if (before == after)
return std::string { GamepadTypeToString(before) }; return std::string { GamepadTypeToString(before) };

4
Source/controls/plrctrls.h

@ -4,7 +4,11 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include "controls/controller.h" #include "controls/controller.h"
#include "controls/game_controls.h" #include "controls/game_controls.h"

5
Source/controls/remap_keyboard.h

@ -2,11 +2,14 @@
#include <cstddef> #include <cstddef>
#ifdef USE_SDL3
#include <SDL3/SDL_keycode.h>
#else
#include <SDL.h> #include <SDL.h>
#ifdef USE_SDL1 #ifdef USE_SDL1
#include "utils/sdl2_to_1_2_backports.h" #include "utils/sdl2_to_1_2_backports.h"
#endif #endif
#endif
namespace devilution { namespace devilution {

113
Source/controls/touch/event_handlers.cpp

@ -1,5 +1,12 @@
#include "controls/touch/event_handlers.h" #include "controls/touch/event_handlers.h"
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_version.h>
#else
#include <SDL.h>
#endif
#include "control.h" #include "control.h"
#include "controls/plrctrls.h" #include "controls/plrctrls.h"
#include "cursor.h" #include "cursor.h"
@ -36,6 +43,42 @@ Point ScaleToScreenCoordinates(float x, float y)
}; };
} }
constexpr bool IsFingerDown(const SDL_Event &event)
{
#ifdef USE_SDL3
return event.type == SDL_EVENT_FINGER_DOWN;
#else
return event.type == SDL_FINGERDOWN;
#endif
}
constexpr bool IsFingerUp(const SDL_Event &event)
{
#ifdef USE_SDL3
return event.type == SDL_EVENT_FINGER_UP;
#else
return event.type == SDL_FINGERUP;
#endif
}
constexpr bool IsFingerMotion(const SDL_Event &event)
{
#ifdef USE_SDL3
return event.type == SDL_EVENT_FINGER_MOTION;
#else
return event.type == SDL_FINGERMOTION;
#endif
}
constexpr SDL_FingerID FingerId(const SDL_TouchFingerEvent &event)
{
#ifdef USE_SDL3
return event.fingerID;
#else
return event.fingerId;
#endif
}
void SimulateMouseMovement(const SDL_Event &event) void SimulateMouseMovement(const SDL_Event &event)
{ {
const Point position = ScaleToScreenCoordinates(event.tfinger.x, event.tfinger.y); const Point position = ScaleToScreenCoordinates(event.tfinger.x, event.tfinger.y);
@ -62,18 +105,18 @@ bool HandleGameMenuInteraction(const SDL_Event &event)
{ {
if (!gmenu_is_active()) if (!gmenu_is_active())
return false; return false;
if (event.type == SDL_FINGERDOWN && gmenu_left_mouse(true)) if (IsFingerDown(event) && gmenu_left_mouse(true))
return true; return true;
if (event.type == SDL_FINGERMOTION && gmenu_on_mouse_move()) if (IsFingerMotion(event) && gmenu_on_mouse_move())
return true; return true;
return event.type == SDL_FINGERUP && gmenu_left_mouse(false); return IsFingerUp(event) && gmenu_left_mouse(false);
} }
bool HandleStoreInteraction(const SDL_Event &event) bool HandleStoreInteraction(const SDL_Event &event)
{ {
if (!IsPlayerInStore()) if (!IsPlayerInStore())
return false; return false;
if (event.type == SDL_FINGERDOWN) if (IsFingerDown(event))
CheckStoreBtn(); CheckStoreBtn();
return true; return true;
} }
@ -83,7 +126,7 @@ void HandleSpellBookInteraction(const SDL_Event &event)
if (!SpellbookFlag) if (!SpellbookFlag)
return; return;
if (event.type == SDL_FINGERUP) if (IsFingerUp(event))
CheckSBook(); CheckSBook();
} }
@ -91,7 +134,7 @@ bool HandleSpeedBookInteraction(const SDL_Event &event)
{ {
if (!SpellSelectFlag) if (!SpellSelectFlag)
return false; return false;
if (event.type == SDL_FINGERUP) if (IsFingerUp(event))
SetSpell(); SetSpell();
return true; return true;
} }
@ -103,7 +146,7 @@ void HandleBottomPanelInteraction(const SDL_Event &event)
ResetMainPanelButtons(); ResetMainPanelButtons();
if (event.type != SDL_FINGERUP) { if (!IsFingerUp(event)) {
SpellSelectFlag = true; SpellSelectFlag = true;
CheckMainPanelButton(); CheckMainPanelButton();
SpellSelectFlag = false; SpellSelectFlag = false;
@ -119,9 +162,9 @@ void HandleCharacterPanelInteraction(const SDL_Event &event)
if (!CharFlag) if (!CharFlag)
return; return;
if (event.type == SDL_FINGERDOWN) if (IsFingerDown(event))
CheckChrBtns(); CheckChrBtns();
else if (event.type == SDL_FINGERUP && CharPanelButtonActive) else if (IsFingerUp(event) && CharPanelButtonActive)
ReleaseChrBtns(false); ReleaseChrBtns(false);
} }
@ -130,7 +173,7 @@ void HandleStashPanelInteraction(const SDL_Event &event)
if (!IsStashOpen || !MyPlayer->HoldItem.isEmpty()) if (!IsStashOpen || !MyPlayer->HoldItem.isEmpty())
return; return;
if (event.type != SDL_FINGERUP) { if (!IsFingerUp(event)) {
CheckStashButtonPress(MousePosition); CheckStashButtonPress(MousePosition);
} else { } else {
CheckStashButtonRelease(MousePosition); CheckStashButtonRelease(MousePosition);
@ -158,7 +201,7 @@ void HandleTouchEvent(const SDL_Event &event)
return; return;
} }
if (!IsAnyOf(event.type, SDL_FINGERDOWN, SDL_FINGERUP, SDL_FINGERMOTION)) { if (!IsFingerDown(event) && !IsFingerUp(event) && !IsFingerMotion(event)) {
return; return;
} }
@ -189,7 +232,7 @@ void DeactivateTouchEventHandlers()
bool VirtualGamepadEventHandler::Handle(const SDL_Event &event) bool VirtualGamepadEventHandler::Handle(const SDL_Event &event)
{ {
if (!IsDeactivateEvent(event)) { if (!IsDeactivateEvent(event)) {
if (!VirtualGamepadState.isActive || !IsAnyOf(event.type, SDL_FINGERDOWN, SDL_FINGERUP, SDL_FINGERMOTION)) { if (!VirtualGamepadState.isActive || (!IsFingerDown(event) && !IsFingerUp(event) && !IsFingerMotion(event))) {
VirtualGamepadState.primaryActionButton.didStateChange = false; VirtualGamepadState.primaryActionButton.didStateChange = false;
VirtualGamepadState.secondaryActionButton.didStateChange = false; VirtualGamepadState.secondaryActionButton.didStateChange = false;
VirtualGamepadState.spellActionButton.didStateChange = false; VirtualGamepadState.spellActionButton.didStateChange = false;
@ -244,19 +287,10 @@ bool VirtualDirectionPadEventHandler::Handle(const SDL_Event &event)
return false; return false;
} }
switch (event.type) { if (IsFingerDown(event)) return HandleFingerDown(event.tfinger);
case SDL_FINGERDOWN: if (IsFingerUp(event)) return HandleFingerUp(event.tfinger);
return HandleFingerDown(event.tfinger); if (IsFingerMotion(event)) return HandleFingerMotion(event.tfinger);
return false;
case SDL_FINGERUP:
return HandleFingerUp(event.tfinger);
case SDL_FINGERMOTION:
return HandleFingerMotion(event.tfinger);
default:
return false;
}
} }
bool VirtualDirectionPadEventHandler::HandleFingerDown(const SDL_TouchFingerEvent &event) bool VirtualDirectionPadEventHandler::HandleFingerDown(const SDL_TouchFingerEvent &event)
@ -272,14 +306,14 @@ bool VirtualDirectionPadEventHandler::HandleFingerDown(const SDL_TouchFingerEven
return false; return false;
virtualDirectionPad->UpdatePosition(touchCoordinates); virtualDirectionPad->UpdatePosition(touchCoordinates);
activeFinger = event.fingerId; activeFinger = FingerId(event);
isActive = true; isActive = true;
return true; return true;
} }
bool VirtualDirectionPadEventHandler::HandleFingerUp(const SDL_TouchFingerEvent &event) bool VirtualDirectionPadEventHandler::HandleFingerUp(const SDL_TouchFingerEvent &event)
{ {
if (!isActive || event.fingerId != activeFinger) if (!isActive || FingerId(event) != activeFinger)
return false; return false;
const Point position = virtualDirectionPad->area.position; const Point position = virtualDirectionPad->area.position;
@ -290,7 +324,7 @@ bool VirtualDirectionPadEventHandler::HandleFingerUp(const SDL_TouchFingerEvent
bool VirtualDirectionPadEventHandler::HandleFingerMotion(const SDL_TouchFingerEvent &event) bool VirtualDirectionPadEventHandler::HandleFingerMotion(const SDL_TouchFingerEvent &event)
{ {
if (!isActive || event.fingerId != activeFinger) if (!isActive || FingerId(event) != activeFinger)
return false; return false;
const float x = event.x; const float x = event.x;
@ -316,19 +350,10 @@ bool VirtualButtonEventHandler::Handle(const SDL_Event &event)
virtualButton->didStateChange = false; virtualButton->didStateChange = false;
switch (event.type) { if (IsFingerDown(event)) return HandleFingerDown(event.tfinger);
case SDL_FINGERDOWN: if (IsFingerUp(event)) return HandleFingerUp(event.tfinger);
return HandleFingerDown(event.tfinger); if (IsFingerMotion(event)) return HandleFingerMotion(event.tfinger);
return false;
case SDL_FINGERUP:
return HandleFingerUp(event.tfinger);
case SDL_FINGERMOTION:
return HandleFingerMotion(event.tfinger);
default:
return false;
}
} }
bool VirtualButtonEventHandler::HandleFingerDown(const SDL_TouchFingerEvent &event) bool VirtualButtonEventHandler::HandleFingerDown(const SDL_TouchFingerEvent &event)
@ -349,14 +374,14 @@ bool VirtualButtonEventHandler::HandleFingerDown(const SDL_TouchFingerEvent &eve
virtualButton->isHeld = true; virtualButton->isHeld = true;
virtualButton->didStateChange = true; virtualButton->didStateChange = true;
activeFinger = event.fingerId; activeFinger = FingerId(event);
isActive = true; isActive = true;
return true; return true;
} }
bool VirtualButtonEventHandler::HandleFingerUp(const SDL_TouchFingerEvent &event) bool VirtualButtonEventHandler::HandleFingerUp(const SDL_TouchFingerEvent &event)
{ {
if (!isActive || event.fingerId != activeFinger) if (!isActive || FingerId(event) != activeFinger)
return false; return false;
if (!toggles) { if (!toggles) {
@ -371,7 +396,7 @@ bool VirtualButtonEventHandler::HandleFingerUp(const SDL_TouchFingerEvent &event
bool VirtualButtonEventHandler::HandleFingerMotion(const SDL_TouchFingerEvent &event) bool VirtualButtonEventHandler::HandleFingerMotion(const SDL_TouchFingerEvent &event)
{ {
if (!isActive || event.fingerId != activeFinger) if (!isActive || FingerId(event) != activeFinger)
return false; return false;
if (toggles) if (toggles)

4
Source/controls/touch/event_handlers.h

@ -1,6 +1,10 @@
#pragma once #pragma once
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include "controls/touch/gamepad.h" #include "controls/touch/gamepad.h"

28
Source/controls/touch/renderers.cpp

@ -1,5 +1,11 @@
#include "controls/touch/renderers.h" #include "controls/touch/renderers.h"
#ifdef USE_SDL
#include <SDL3/SDL_surface.h>
#else
#include <SDL.h>
#endif
#include "control.h" #include "control.h"
#include "cursor.h" #include "cursor.h"
#include "diablo.h" #include "diablo.h"
@ -127,14 +133,19 @@ void LoadPotionArt(ButtonTexture *potionArt)
SDL_PIXELFORMAT_INDEX8); SDL_PIXELFORMAT_INDEX8);
auto palette = SDLWrap::AllocPalette(); auto palette = SDLWrap::AllocPalette();
if (SDLC_SetSurfaceAndPaletteColors(surface.get(), palette.get(), logical_palette.data(), 0, 256) < 0) if (!SDLC_SetSurfaceAndPaletteColors(surface.get(), palette.get(), logical_palette.data(), 0, 256))
ErrSdl(); ErrSdl();
const Uint32 bgColor = SDL_MapRGB(surface->format, logical_palette[1].r, logical_palette[1].g, logical_palette[1].b); const Uint32 bgColor = SDL_MapRGB(surface->format, logical_palette[1].r, logical_palette[1].g, logical_palette[1].b);
#ifdef USE_SDL3
if (!SDL_FillSurfaceRect(surface.get(), nullptr, bgColor)) ErrSdl();
if (!SDL_SetSurfaceColorKey(surface.get(), true, bgColor)) ErrSdl();
#else
if (SDL_FillRect(surface.get(), nullptr, bgColor) < 0) if (SDL_FillRect(surface.get(), nullptr, bgColor) < 0)
ErrSdl(); ErrSdl();
if (SDL_SetColorKey(surface.get(), SDL_TRUE, bgColor) < 0) if (SDL_SetColorKey(surface.get(), SDL_TRUE, bgColor) < 0)
ErrSdl(); ErrSdl();
#endif
Point position { 0, 0 }; Point position { 0, 0 };
for (const item_cursor_graphic graphic : potionGraphics) { for (const item_cursor_graphic graphic : potionGraphics) {
@ -145,7 +156,13 @@ void LoadPotionArt(ButtonTexture *potionArt)
potionArt->numFrames = sizeof(potionGraphics); potionArt->numFrames = sizeof(potionGraphics);
potionArt->surface.reset(SDL_ConvertSurfaceFormat(surface.get(), SDL_PIXELFORMAT_ARGB8888, 0)); potionArt->surface.reset(
#ifdef USE_SDL3
SDL_ConvertSurface(surface.get(), SDL_PIXELFORMAT_ARGB8888)
#else
SDL_ConvertSurfaceFormat(surface.get(), SDL_PIXELFORMAT_ARGB8888, 0)
#endif
);
} }
bool InteractsWithCharButton(Point point) bool InteractsWithCharButton(Point point)
@ -191,8 +208,11 @@ void RenderVirtualGamepad(SDL_Renderer *renderer)
if (art.texture == nullptr) if (art.texture == nullptr)
return; return;
if (SDL_RenderCopy(renderer, art.texture.get(), src, dst) <= -1) #ifdef USE_SDL3
ErrSdl(); if (!SDL_RenderTexture(renderer, art.texture.get(), src, dst)) ErrSdl();
#else
if (SDL_RenderCopy(renderer, art.texture.get(), src, dst) <= -1) ErrSdl();
#endif
}; };
Renderer.Render(renderFunction); Renderer.Render(renderFunction);

4
Source/controls/touch/renderers.h

@ -3,7 +3,11 @@
#include <cstdint> #include <cstdint>
#include <optional> #include <optional>
#ifdef USE_SDL3
#include <SDL3/SDL_render.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include "controls/plrctrls.h" #include "controls/plrctrls.h"
#include "controls/touch/gamepad.h" #include "controls/touch/gamepad.h"

21
Source/cursor.cpp

@ -11,6 +11,13 @@
#include <string_view> #include <string_view>
#include <vector> #include <vector>
#ifdef USE_SDL3
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_surface.h>
#else
#include <SDL.h>
#endif
#include <fmt/format.h> #include <fmt/format.h>
#include "DiabloUI/diabloui.h" #include "DiabloUI/diabloui.h"
@ -501,17 +508,31 @@ void CreateHalfSizeItemSprites()
} }
const Surface itemSurface = ownedItemSurface.subregion(0, 0, itemSprite.width(), itemSprite.height()); const Surface itemSurface = ownedItemSurface.subregion(0, 0, itemSprite.width(), itemSprite.height());
const SDL_Rect itemSurfaceRect = MakeSdlRect(0, 0, itemSurface.w(), itemSurface.h()); const SDL_Rect itemSurfaceRect = MakeSdlRect(0, 0, itemSurface.w(), itemSurface.h());
#ifdef USE_SDL3
SDL_SetSurfaceClipRect(itemSurface.surface, &itemSurfaceRect);
SDL_FillSurfaceRect(itemSurface.surface, nullptr, 1);
#else
SDL_SetClipRect(itemSurface.surface, &itemSurfaceRect); SDL_SetClipRect(itemSurface.surface, &itemSurfaceRect);
SDL_FillRect(itemSurface.surface, nullptr, 1); SDL_FillRect(itemSurface.surface, nullptr, 1);
#endif
ClxDraw(itemSurface, { 0, itemSurface.h() }, itemSprite); ClxDraw(itemSurface, { 0, itemSurface.h() }, itemSprite);
const Surface halfSurface = ownedHalfSurface.subregion(0, 0, itemSurface.w() / 2, itemSurface.h() / 2); const Surface halfSurface = ownedHalfSurface.subregion(0, 0, itemSurface.w() / 2, itemSurface.h() / 2);
const SDL_Rect halfSurfaceRect = MakeSdlRect(0, 0, halfSurface.w(), halfSurface.h()); const SDL_Rect halfSurfaceRect = MakeSdlRect(0, 0, halfSurface.w(), halfSurface.h());
#ifdef USE_SDL3
SDL_SetSurfaceClipRect(halfSurface.surface, &halfSurfaceRect);
#else
SDL_SetClipRect(halfSurface.surface, &halfSurfaceRect); SDL_SetClipRect(halfSurface.surface, &halfSurfaceRect);
#endif
BilinearDownscaleByHalf8(itemSurface.surface, paletteTransparencyLookup, halfSurface.surface, 1); BilinearDownscaleByHalf8(itemSurface.surface, paletteTransparencyLookup, halfSurface.surface, 1);
HalfSizeItemSprites[outputIndex].emplace(SurfaceToClx(halfSurface, 1, 1)); HalfSizeItemSprites[outputIndex].emplace(SurfaceToClx(halfSurface, 1, 1));
#ifdef USE_SDL3
SDL_FillSurfaceRect(itemSurface.surface, nullptr, 1);
#else
SDL_FillRect(itemSurface.surface, nullptr, 1); SDL_FillRect(itemSurface.surface, nullptr, 1);
#endif
ClxDrawTRN(itemSurface, { 0, itemSurface.h() }, itemSprite, redTrn); ClxDrawTRN(itemSurface, { 0, itemSurface.h() }, itemSprite, redTrn);
BilinearDownscaleByHalf8(itemSurface.surface, paletteTransparencyLookup, halfSurface.surface, 1); BilinearDownscaleByHalf8(itemSurface.surface, paletteTransparencyLookup, halfSurface.surface, 1);
HalfSizeItemSpritesRed[outputIndex].emplace(SurfaceToClx(halfSurface, 1, 1)); HalfSizeItemSpritesRed[outputIndex].emplace(SurfaceToClx(halfSurface, 1, 1));

6
Source/diablo_msg.cpp

@ -8,6 +8,12 @@
#include <cstdint> #include <cstdint>
#include <deque> #include <deque>
#ifdef USE_SDL3
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h>
#endif
#include "diablo_msg.hpp" #include "diablo_msg.hpp"
#include "DiabloUI/ui_flags.hpp" #include "DiabloUI/ui_flags.hpp"

155
Source/engine/demomode.cpp

@ -5,9 +5,17 @@
#include <limits> #include <limits>
#include <optional> #include <optional>
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_keyboard.h>
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h>
#ifdef USE_SDL1 #ifdef USE_SDL1
#include "utils/sdl2_to_1_2_backports.h" #include "utils/sdl2_to_1_2_backports.h"
#endif #endif
#endif
#include "controls/control_mode.hpp" #include "controls/control_mode.hpp"
#include "controls/plrctrls.h" #include "controls/plrctrls.h"
@ -247,23 +255,44 @@ bool CreateSdlEvent(const DemoMsg &dmsg, SDL_Event &event, uint16_t &modState)
const uint8_t type = dmsg.type; const uint8_t type = dmsg.type;
switch (type) { switch (type) {
case DemoMsg::MouseMotionEvent: case DemoMsg::MouseMotionEvent:
#ifdef USE_SDL3
event.type = SDL_EVENT_MOUSE_MOTION;
event.motion.state = 0;
event.motion.xrel = 0.F;
event.motion.yrel = 0.F;
#else
event.type = SDL_MOUSEMOTION; event.type = SDL_MOUSEMOTION;
#endif
event.motion.which = 0; event.motion.which = 0;
event.motion.x = dmsg.motion.x; event.motion.x = dmsg.motion.x;
event.motion.y = dmsg.motion.y; event.motion.y = dmsg.motion.y;
return true; return true;
case DemoMsg::MouseButtonDownEvent: case DemoMsg::MouseButtonDownEvent:
case DemoMsg::MouseButtonUpEvent: case DemoMsg::MouseButtonUpEvent:
#ifdef USE_SDL3
event.type = type == DemoMsg::MouseButtonDownEvent ? SDL_EVENT_MOUSE_BUTTON_DOWN : SDL_EVENT_MOUSE_BUTTON_UP;
event.button.down = type == DemoMsg::MouseButtonDownEvent;
event.button.clicks = 1;
#else
event.type = type == DemoMsg::MouseButtonDownEvent ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP; event.type = type == DemoMsg::MouseButtonDownEvent ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
event.button.state = type == DemoMsg::MouseButtonDownEvent ? SDL_PRESSED : SDL_RELEASED;
#endif
event.button.which = 0; event.button.which = 0;
event.button.button = dmsg.button.button; event.button.button = dmsg.button.button;
event.button.state = type == DemoMsg::MouseButtonDownEvent ? SDL_PRESSED : SDL_RELEASED;
event.button.x = dmsg.button.x; event.button.x = dmsg.button.x;
event.button.y = dmsg.button.y; event.button.y = dmsg.button.y;
modState = dmsg.button.mod; modState = dmsg.button.mod;
return true; return true;
case DemoMsg::MouseWheelEvent: case DemoMsg::MouseWheelEvent:
#ifdef USE_SDL3
event.type = SDL_EVENT_MOUSE_WHEEL;
event.wheel.integer_x = dmsg.wheel.x;
event.wheel.integer_y = dmsg.wheel.y;
event.wheel.mouse_x = 0;
event.wheel.mouse_y = 0;
#else
event.type = SDL_MOUSEWHEEL; event.type = SDL_MOUSEWHEEL;
#endif
event.wheel.which = 0; event.wheel.which = 0;
event.wheel.x = dmsg.wheel.x; event.wheel.x = dmsg.wheel.x;
event.wheel.y = dmsg.wheel.y; event.wheel.y = dmsg.wheel.y;
@ -271,11 +300,19 @@ bool CreateSdlEvent(const DemoMsg &dmsg, SDL_Event &event, uint16_t &modState)
return true; return true;
case DemoMsg::KeyDownEvent: case DemoMsg::KeyDownEvent:
case DemoMsg::KeyUpEvent: case DemoMsg::KeyUpEvent:
#ifdef USE_SDL3
event.type = type == DemoMsg::KeyDownEvent ? SDL_EVENT_KEY_DOWN : SDL_EVENT_KEY_UP;
event.key.down = type == DemoMsg::KeyDownEvent;
event.key.scancode = SDL_GetScancodeFromKey(dmsg.key.sym, nullptr);
event.key.key = dmsg.key.sym;
event.key.mod = dmsg.key.mod;
#else
event.type = type == DemoMsg::KeyDownEvent ? SDL_KEYDOWN : SDL_KEYUP; event.type = type == DemoMsg::KeyDownEvent ? SDL_KEYDOWN : SDL_KEYUP;
event.key.state = type == DemoMsg::KeyDownEvent ? SDL_PRESSED : SDL_RELEASED; event.key.state = type == DemoMsg::KeyDownEvent ? SDL_PRESSED : SDL_RELEASED;
event.key.keysym.scancode = SDL_GetScancodeFromKey(dmsg.key.sym); event.key.keysym.scancode = SDL_GetScancodeFromKey(dmsg.key.sym);
event.key.keysym.sym = dmsg.key.sym; event.key.keysym.sym = dmsg.key.sym;
event.key.keysym.mod = dmsg.key.mod; event.key.keysym.mod = dmsg.key.mod;
#endif
return true; return true;
default: default:
if (type >= DemoMsg::MinCustomEvent) { if (type >= DemoMsg::MinCustomEvent) {
@ -688,27 +725,51 @@ bool FetchMessage(SDL_Event *event, uint16_t *modState)
return false; return false;
SDL_Event e; SDL_Event e;
if (SDL_PollEvent(&e) != 0) { if (
if (e.type == SDL_QUIT) { #ifdef USE_SDL3
SDL_PollEvent(&e)
#else
SDL_PollEvent(&e) != 0
#endif
) {
if (e.type ==
#ifdef USE_SDL3
SDL_EVENT_QUIT
#else
SDL_QUIT
#endif
) {
*event = e; *event = e;
return true; return true;
} }
if (e.type == SDL_KEYDOWN && e.key.keysym.sym == SDLK_ESCAPE) { if (e.type ==
CloseDemoFile(); #ifdef USE_SDL3
CurrentDemoMessage = std::nullopt; SDL_EVENT_KEY_DOWN
DemoNumber = -1; #else
Timedemo = false; SDL_KEYDOWN
last_tick = SDL_GetTicks(); #endif
} ) {
if (e.type == SDL_KEYDOWN && IsAnyOf(e.key.keysym.sym, SDLK_KP_PLUS, SDLK_PLUS) && sgGameInitInfo.nTickRate < 255) { const SDL_Keycode key =
sgGameInitInfo.nTickRate++; #ifdef USE_SDL3
GetOptions().Gameplay.tickRate.SetValue(sgGameInitInfo.nTickRate); e.key.key;
gnTickDelay = 1000 / sgGameInitInfo.nTickRate; #else
} e.key.keysym.sym;
if (e.type == SDL_KEYDOWN && IsAnyOf(e.key.keysym.sym, SDLK_KP_MINUS, SDLK_MINUS) && sgGameInitInfo.nTickRate > 1) { #endif
sgGameInitInfo.nTickRate--; if (key == SDLK_ESCAPE) {
GetOptions().Gameplay.tickRate.SetValue(sgGameInitInfo.nTickRate); CloseDemoFile();
gnTickDelay = 1000 / sgGameInitInfo.nTickRate; CurrentDemoMessage = std::nullopt;
DemoNumber = -1;
Timedemo = false;
last_tick = SDL_GetTicks();
} else if (IsAnyOf(key, SDLK_KP_PLUS, SDLK_PLUS) && sgGameInitInfo.nTickRate < 255) {
sgGameInitInfo.nTickRate++;
GetOptions().Gameplay.tickRate.SetValue(sgGameInitInfo.nTickRate);
gnTickDelay = 1000 / sgGameInitInfo.nTickRate;
} else if (IsAnyOf(key, SDLK_KP_MINUS, SDLK_MINUS) && sgGameInitInfo.nTickRate > 1) {
sgGameInitInfo.nTickRate--;
GetOptions().Gameplay.tickRate.SetValue(sgGameInitInfo.nTickRate);
gnTickDelay = 1000 / sgGameInitInfo.nTickRate;
}
} }
} }
@ -743,13 +804,22 @@ void RecordMessage(const SDL_Event &event, uint16_t modState)
if (CurrentEventHandler == DisableInputEventHandler) if (CurrentEventHandler == DisableInputEventHandler)
return; return;
switch (event.type) { switch (event.type) {
#ifdef USE_SDL3
case SDL_EVENT_MOUSE_MOTION:
#else
case SDL_MOUSEMOTION: case SDL_MOUSEMOTION:
#endif
WriteDemoMsgHeader(DemoMsg::MouseMotionEvent); WriteDemoMsgHeader(DemoMsg::MouseMotionEvent);
WriteLE16(DemoRecording, event.motion.x); WriteLE16(DemoRecording, event.motion.x);
WriteLE16(DemoRecording, event.motion.y); WriteLE16(DemoRecording, event.motion.y);
break; break;
#ifdef USE_SDL3
case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP:
#else
case SDL_MOUSEBUTTONDOWN: case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONUP:
#endif
#ifdef USE_SDL1 #ifdef USE_SDL1
if (event.button.button == SDL_BUTTON_WHEELUP || event.button.button == SDL_BUTTON_WHEELDOWN) { if (event.button.button == SDL_BUTTON_WHEELUP || event.button.button == SDL_BUTTON_WHEELDOWN) {
WriteDemoMsgHeader(DemoMsg::MouseWheelEvent); WriteDemoMsgHeader(DemoMsg::MouseWheelEvent);
@ -758,7 +828,14 @@ void RecordMessage(const SDL_Event &event, uint16_t modState)
WriteLE16(DemoRecording, modState); WriteLE16(DemoRecording, modState);
} else { } else {
#endif #endif
WriteDemoMsgHeader(event.type == SDL_MOUSEBUTTONDOWN ? DemoMsg::MouseButtonDownEvent : DemoMsg::MouseButtonUpEvent); WriteDemoMsgHeader(
#ifdef USE_SDL3
event.button.down
#else
event.type == SDL_MOUSEBUTTONDOWN
#endif
? DemoMsg::MouseButtonDownEvent
: DemoMsg::MouseButtonUpEvent);
WriteByte(DemoRecording, event.button.button); WriteByte(DemoRecording, event.button.button);
WriteLE16(DemoRecording, event.button.x); WriteLE16(DemoRecording, event.button.x);
WriteLE16(DemoRecording, event.button.y); WriteLE16(DemoRecording, event.button.y);
@ -768,8 +845,24 @@ void RecordMessage(const SDL_Event &event, uint16_t modState)
#endif #endif
break; break;
#ifndef USE_SDL1 #ifndef USE_SDL1
#ifdef USE_SDL3
case SDL_EVENT_MOUSE_WHEEL:
#else
case SDL_MOUSEWHEEL: case SDL_MOUSEWHEEL:
#endif
WriteDemoMsgHeader(DemoMsg::MouseWheelEvent); WriteDemoMsgHeader(DemoMsg::MouseWheelEvent);
#ifdef USE_SDL3
if (event.wheel.integer_x < std::numeric_limits<int16_t>::min()
|| event.wheel.integer_x > std::numeric_limits<int16_t>::max()
|| event.wheel.integer_y < std::numeric_limits<int16_t>::min()
|| event.wheel.integer_y > std::numeric_limits<int16_t>::max()) {
app_fatal(StrCat("Mouse wheel event integer_x/y out of int16_t range. x=",
event.wheel.integer_x, " y=", event.wheel.integer_y));
}
WriteLE16(DemoRecording, event.wheel.integer_x);
WriteLE16(DemoRecording, event.wheel.integer_y);
#else
if (event.wheel.x < std::numeric_limits<int16_t>::min() if (event.wheel.x < std::numeric_limits<int16_t>::min()
|| event.wheel.x > std::numeric_limits<int16_t>::max() || event.wheel.x > std::numeric_limits<int16_t>::max()
|| event.wheel.y < std::numeric_limits<int16_t>::min() || event.wheel.y < std::numeric_limits<int16_t>::min()
@ -779,23 +872,39 @@ void RecordMessage(const SDL_Event &event, uint16_t modState)
} }
WriteLE16(DemoRecording, event.wheel.x); WriteLE16(DemoRecording, event.wheel.x);
WriteLE16(DemoRecording, event.wheel.y); WriteLE16(DemoRecording, event.wheel.y);
#endif
WriteLE16(DemoRecording, modState); WriteLE16(DemoRecording, modState);
break; break;
#endif #endif
#ifdef USE_SDL3
case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_KEY_UP:
WriteDemoMsgHeader(event.key.down ? DemoMsg::KeyDownEvent : DemoMsg::KeyUpEvent);
WriteLE32(DemoRecording, static_cast<uint32_t>(event.key.key));
WriteLE16(DemoRecording, static_cast<uint16_t>(event.key.mod));
break;
#else
case SDL_KEYDOWN: case SDL_KEYDOWN:
case SDL_KEYUP: case SDL_KEYUP:
WriteDemoMsgHeader(event.type == SDL_KEYDOWN ? DemoMsg::KeyDownEvent : DemoMsg::KeyUpEvent); WriteDemoMsgHeader(event.type == SDL_KEYDOWN ? DemoMsg::KeyDownEvent : DemoMsg::KeyUpEvent);
WriteLE32(DemoRecording, static_cast<uint32_t>(event.key.keysym.sym)); WriteLE32(DemoRecording, static_cast<uint32_t>(event.key.keysym.sym));
WriteLE16(DemoRecording, static_cast<uint16_t>(event.key.keysym.mod)); WriteLE16(DemoRecording, static_cast<uint16_t>(event.key.keysym.mod));
break; break;
#endif
#ifndef USE_SDL1 #ifndef USE_SDL1
#ifndef USE_SDL3
case SDL_WINDOWEVENT: case SDL_WINDOWEVENT:
if (event.window.type == SDL_WINDOWEVENT_CLOSE) { if (event.window.type == SDL_WINDOWEVENT_CLOSE) {
WriteDemoMsgHeader(DemoMsg::QuitEvent); WriteDemoMsgHeader(DemoMsg::QuitEvent);
} }
break; break;
#endif #endif
#endif
#ifdef USE_SDL3
case SDL_EVENT_QUIT:
#else
case SDL_QUIT: case SDL_QUIT:
#endif
WriteDemoMsgHeader(DemoMsg::QuitEvent); WriteDemoMsgHeader(DemoMsg::QuitEvent);
break; break;
default: default:
@ -843,17 +952,17 @@ void NotifyGameLoopEnd()
if (IsRunning() && !HeadlessMode) { if (IsRunning() && !HeadlessMode) {
const float seconds = (SDL_GetTicks() - StartTime) / 1000.0F; const float seconds = (SDL_GetTicks() - StartTime) / 1000.0F;
SDL_Log("%d frames, %.2f seconds: %.1f fps", LogicTick, seconds, LogicTick / seconds); Log("{} frames, {:.2f} seconds: {:.1f} fps", LogicTick, seconds, LogicTick / seconds);
gbRunGameResult = false; gbRunGameResult = false;
gbRunGame = false; gbRunGame = false;
HeroCompareResult compareResult = pfile_compare_hero_demo(DemoNumber, false); HeroCompareResult compareResult = pfile_compare_hero_demo(DemoNumber, false);
switch (compareResult.status) { switch (compareResult.status) {
case HeroCompareResult::ReferenceNotFound: case HeroCompareResult::ReferenceNotFound:
SDL_Log("Timedemo: No final comparison because reference is not present."); Log("Timedemo: No final comparison because reference is not present.");
break; break;
case HeroCompareResult::Same: case HeroCompareResult::Same:
SDL_Log("Timedemo: Same outcome as initial run. :)"); Log("Timedemo: Same outcome as initial run. :)");
break; break;
case HeroCompareResult::Difference: case HeroCompareResult::Difference:
Log("Timedemo: Different outcome than initial run. ;(\n{}", compareResult.message); Log("Timedemo: Different outcome than initial run. ;(\n{}", compareResult.message);

4
Source/engine/demomode.h

@ -7,7 +7,11 @@
#include <cstdint> #include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
namespace devilution { namespace devilution {

65
Source/engine/dx.cpp

@ -5,9 +5,17 @@
*/ */
#include "engine/dx.h" #include "engine/dx.h"
#include <SDL.h>
#include <cstdint> #include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_render.h>
#include <SDL3/SDL_surface.h>
#include <SDL3/SDL_video.h>
#else
#include <SDL.h>
#endif
#include "controls/control_mode.hpp" #include "controls/control_mode.hpp"
#include "controls/plrctrls.h" #include "controls/plrctrls.h"
#include "engine/render/primitive_render.hpp" #include "engine/render/primitive_render.hpp"
@ -144,7 +152,9 @@ void CreateBackBuffer()
PalSurface = PinnedPalSurface.get(); PalSurface = PinnedPalSurface.get();
} }
#ifndef USE_SDL1 #if defined(USE_SDL3)
if (!SDL_SetSurfacePalette(PalSurface, Palette.get())) ErrSdl();
#elif !defined(USE_SDL1)
// In SDL2, `PalSurface` points to the global `palette`. // In SDL2, `PalSurface` points to the global `palette`.
if (SDL_SetSurfacePalette(PalSurface, Palette.get()) < 0) if (SDL_SetSurfacePalette(PalSurface, Palette.get()) < 0)
ErrSdl(); ErrSdl();
@ -168,7 +178,9 @@ void Blit(SDL_Surface *src, SDL_Rect *srcRect, SDL_Rect *dstRect)
return; return;
SDL_Surface *dst = GetOutputSurface(); SDL_Surface *dst = GetOutputSurface();
#ifndef USE_SDL1 #if defined(USE_SDL3)
if (!SDL_BlitSurface(src, srcRect, dst, dstRect)) ErrSdl();
#elif !defined(USE_SDL1)
if (SDL_BlitSurface(src, srcRect, dst, dstRect) < 0) if (SDL_BlitSurface(src, srcRect, dst, dstRect) < 0)
ErrSdl(); ErrSdl();
#else #else
@ -229,21 +241,32 @@ void RenderPresent()
#ifndef USE_SDL1 #ifndef USE_SDL1
if (renderer != nullptr) { if (renderer != nullptr) {
if (SDL_UpdateTexture(texture.get(), nullptr, surface->pixels, surface->pitch) <= -1) { // pitch is 2560 #ifdef USE_SDL3
ErrSdl(); if (!SDL_UpdateTexture(texture.get(), nullptr, surface->pixels, surface->pitch)) ErrSdl();
} #else
if (SDL_UpdateTexture(texture.get(), nullptr, surface->pixels, surface->pitch) <= -1) ErrSdl();
#endif
// Clear buffer to avoid artifacts in case the window was resized // Clear buffer to avoid artifacts in case the window was resized
if (SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255) <= -1) { // TODO only do this if window was resized // TODO only do this if window was resized
ErrSdl(); #ifdef USE_SDL3
} if (!SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255)) ErrSdl();
#else
if (SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255) <= -1) ErrSdl();
#endif
#ifdef USE_SDL3
if (!SDL_RenderClear(renderer)) ErrSdl();
#else
if (SDL_RenderClear(renderer) <= -1) ErrSdl();
#endif
#ifdef USE_SDL3
if (!SDL_RenderCopy(renderer, texture.get(), nullptr, nullptr)) ErrSdl();
#else
if (SDL_RenderCopy(renderer, texture.get(), nullptr, nullptr) <= -1) ErrSdl();
#endif
if (SDL_RenderClear(renderer) <= -1) {
ErrSdl();
}
if (SDL_RenderCopy(renderer, texture.get(), nullptr, nullptr) <= -1) {
ErrSdl();
}
if (ControlMode == ControlTypes::VirtualGamepad) { if (ControlMode == ControlTypes::VirtualGamepad) {
RenderVirtualGamepad(renderer); RenderVirtualGamepad(renderer);
} }
@ -256,9 +279,13 @@ void RenderPresent()
if (ControlMode == ControlTypes::VirtualGamepad) { if (ControlMode == ControlTypes::VirtualGamepad) {
RenderVirtualGamepad(surface); RenderVirtualGamepad(surface);
} }
if (SDL_UpdateWindowSurface(ghMainWnd) <= -1) {
ErrSdl(); #ifdef USE_SDL3
} if (!SDL_UpdateWindowSurface(ghMainWnd)) ErrSdl();
#else
if (SDL_UpdateWindowSurface(ghMainWnd) <= -1) ErrSdl();
#endif
if (RenderDirectlyToOutputSurface) if (RenderDirectlyToOutputSurface)
PalSurface = GetOutputSurface(); PalSurface = GetOutputSurface();
LimitFrameRate(); LimitFrameRate();

5
Source/engine/dx.h

@ -5,7 +5,12 @@
*/ */
#pragma once #pragma once
#ifdef USE_SDL3
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_surface.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include "engine/surface.hpp" #include "engine/surface.hpp"

101
Source/engine/events.cpp

@ -2,6 +2,16 @@
#include <cstdint> #include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#else
#include <SDL.h>
#ifdef USE_SDL1
#include "utils/sdl2_to_1_2_backports.h"
#endif
#endif
#include "controls/input.h" #include "controls/input.h"
#include "controls/padmapper.hpp" #include "controls/padmapper.hpp"
#include "engine/demomode.h" #include "engine/demomode.h"
@ -46,9 +56,7 @@ bool FetchMessage_Real(SDL_Event *event, uint16_t *modState)
#endif #endif
SDL_Event e; SDL_Event e;
if (PollEvent(&e) == 0) { if (!PollEvent(&e)) return false;
return false;
}
event->type = static_cast<SDL_EventType>(0); event->type = static_cast<SDL_EventType>(0);
*modState = SDL_GetModState(); *modState = SDL_GetModState();
@ -59,25 +67,54 @@ bool FetchMessage_Real(SDL_Event *event, uint16_t *modState)
HandleTouchEvent(e); HandleTouchEvent(e);
#endif #endif
if (e.type == SDL_QUIT || IsCustomEvent(e.type)) { if (e.type ==
#ifdef USE_SDL3
SDL_EVENT_QUIT
#else
SDL_QUIT
#endif
|| IsCustomEvent(e.type)) {
*event = e; *event = e;
return true; return true;
} }
if (IsAnyOf(e.type, SDL_KEYUP, SDL_KEYDOWN) && e.key.keysym.sym == SDLK_UNKNOWN) { // Erroneous events generated by RG350 kernel.
// Erroneous events generated by RG350 kernel. #ifdef USE_SDL3
return true; if (IsAnyOf(e.type, SDL_EVENT_KEY_DOWN, SDL_EVENT_KEY_UP) && e.key.key == SDLK_UNKNOWN) return true;
} #else
if (IsAnyOf(e.type, SDL_KEYUP, SDL_KEYDOWN) && e.key.keysym.sym == SDLK_UNKNOWN) return true;
#endif
#if !defined(USE_SDL1) && !defined(__vita__) #if !defined(USE_SDL1) && !defined(__vita__)
if (!movie_playing) { if (!movie_playing) {
// SDL generates mouse events from touch-based inputs to provide basic // SDL generates mouse events from touch-based inputs to provide basic
// touchscreeen support for apps that don't explicitly handle touch events // touchscreeen support for apps that don't explicitly handle touch events
if (IsAnyOf(e.type, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP) && e.button.which == SDL_TOUCH_MOUSEID) if (IsAnyOf(e.type,
#ifdef USE_SDL3
SDL_EVENT_MOUSE_BUTTON_DOWN, SDL_EVENT_MOUSE_BUTTON_UP
#else
SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP
#endif
)
&& e.button.which == SDL_TOUCH_MOUSEID) {
return true; return true;
if (e.type == SDL_MOUSEMOTION && e.motion.which == SDL_TOUCH_MOUSEID) }
if (e.type ==
#ifdef USE_SDL3
SDL_EVENT_MOUSE_MOTION
#else
SDL_MOUSEMOTION
#endif
&& e.motion.which == SDL_TOUCH_MOUSEID) {
return true; return true;
if (e.type == SDL_MOUSEWHEEL && e.wheel.which == SDL_TOUCH_MOUSEID) }
if (e.type ==
#ifdef USE_SDL3
SDL_EVENT_MOUSE_WHEEL
#else
SDL_MOUSEWHEEL
#endif
&& e.wheel.which == SDL_TOUCH_MOUSEID)
return true; return true;
} }
#endif #endif
@ -94,6 +131,47 @@ bool FetchMessage_Real(SDL_Event *event, uint16_t *modState)
return true; return true;
switch (e.type) { switch (e.type) {
#ifdef USE_SDL3
case SDL_EVENT_GAMEPAD_AXIS_MOTION:
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
case SDL_EVENT_GAMEPAD_BUTTON_UP:
case SDL_EVENT_FINGER_DOWN:
case SDL_EVENT_FINGER_UP:
case SDL_EVENT_TEXT_EDITING:
case SDL_EVENT_TEXT_INPUT:
case SDL_EVENT_WINDOW_RESIZED:
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
case SDL_EVENT_WINDOW_SHOWN:
case SDL_EVENT_WINDOW_MINIMIZED:
case SDL_EVENT_WINDOW_MAXIMIZED:
case SDL_EVENT_WINDOW_RESTORED:
case SDL_EVENT_WINDOW_HDR_STATE_CHANGED:
case SDL_EVENT_WINDOW_FOCUS_GAINED:
case SDL_EVENT_WINDOW_FOCUS_LOST:
case SDL_EVENT_MOUSE_WHEEL:
case SDL_EVENT_JOYSTICK_AXIS_MOTION:
case SDL_EVENT_JOYSTICK_HAT_MOTION:
case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
case SDL_EVENT_JOYSTICK_BUTTON_UP:
case SDL_EVENT_MOUSE_MOTION:
case SDL_EVENT_MOUSE_BUTTON_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP:
*event = e;
break;
case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_KEY_UP:
if (e.key.key == SDLK_UNKNOWN) {
return FalseAvail(e.key.down ? "SDL_EVENT_KEY_DOWN" : "SDL_EVENT_KEY_UP", e.key.key);
}
*event = e;
break;
case SDL_EVENT_AUDIO_DEVICE_ADDED:
return FalseAvail("SDL_EVENT_AUDIO_DEVICE_ADDED", e.adevice.which);
case SDL_EVENT_AUDIO_DEVICE_REMOVED:
return FalseAvail("SDL_EVENT_AUDIO_DEVICE_REMOVED", e.adevice.which);
case SDL_EVENT_KEYMAP_CHANGED:
return FalseAvail("SDL_EVENT_KEYMAP_CHANGED", 0);
#else
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
case SDL_CONTROLLERAXISMOTION: case SDL_CONTROLLERAXISMOTION:
case SDL_CONTROLLERBUTTONDOWN: case SDL_CONTROLLERBUTTONDOWN:
@ -131,6 +209,7 @@ bool FetchMessage_Real(SDL_Event *event, uint16_t *modState)
case SDL_KEYMAPCHANGED: case SDL_KEYMAPCHANGED:
return FalseAvail("SDL_KEYMAPCHANGED", 0); return FalseAvail("SDL_KEYMAPCHANGED", 0);
#endif #endif
#endif
#endif #endif
default: default:
return FalseAvail("unknown", e.type); return FalseAvail("unknown", e.type);

8
Source/engine/events.hpp

@ -2,13 +2,17 @@
#include <cstdint> #include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#else
#include <SDL.h> #include <SDL.h>
#include "engine/point.hpp"
#ifdef USE_SDL1 #ifdef USE_SDL1
#include "utils/sdl2_to_1_2_backports.h" #include "utils/sdl2_to_1_2_backports.h"
#endif #endif
#endif
#include "engine/point.hpp"
namespace devilution { namespace devilution {

2
Source/engine/palette.cpp

@ -161,7 +161,7 @@ void SystemPaletteUpdated(int first, int ncolor)
return; return;
assert(Palette); assert(Palette);
if (SDLC_SetSurfaceAndPaletteColors(PalSurface, Palette.get(), system_palette.data() + first, first, ncolor) < 0) { if (!SDLC_SetSurfaceAndPaletteColors(PalSurface, Palette.get(), system_palette.data() + first, first, ncolor)) {
ErrSdl(); ErrSdl();
} }
} }

31
Source/engine/render/scrollrt.cpp

@ -9,6 +9,14 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_keyboard.h>
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h>
#endif
#include <ankerl/unordered_dense.h> #include <ankerl/unordered_dense.h>
#include "DiabloUI/ui_flags.hpp" #include "DiabloUI/ui_flags.hpp"
@ -530,8 +538,16 @@ void DrawCell(const Surface &out, const Lightmap lightmap, Point tilePosition, P
bool transparency = TileHasAny(tilePosition, TileProperties::Transparent) && TransList[dTransVal[tilePosition.x][tilePosition.y]]; bool transparency = TileHasAny(tilePosition, TileProperties::Transparent) && TransList[dTransVal[tilePosition.x][tilePosition.y]];
#ifdef _DEBUG #ifdef _DEBUG
if ((SDL_GetModState() & KMOD_ALT) != 0) if ((SDL_GetModState() &
#ifdef USE_SDL3
SDL_KMOD_ALT
#else
KMOD_ALT
#endif
)
!= 0) {
transparency = false; transparency = false;
}
#endif #endif
const auto getFirstTileMaskLeft = [=](TileType tile) -> MaskType { const auto getFirstTileMaskLeft = [=](TileType tile) -> MaskType {
@ -876,7 +892,14 @@ void DrawDungeon(const Surface &out, const Lightmap &lightmap, Point tilePositio
bool transparency = TransList[bMap]; bool transparency = TransList[bMap];
#ifdef _DEBUG #ifdef _DEBUG
// Turn transparency off here for debugging // Turn transparency off here for debugging
transparency = transparency && (SDL_GetModState() & KMOD_ALT) == 0; transparency = transparency && (SDL_GetModState() &
#ifdef USE_SDL3
SDL_KMOD_ALT
#else
KMOD_ALT
#endif
)
== 0;
#endif #endif
if (perPixelLighting) { if (perPixelLighting) {
// Create a special lightmap buffer to bleed light up walls // Create a special lightmap buffer to bleed light up walls
@ -1629,7 +1652,11 @@ void ClearScreenBuffer()
return; return;
assert(PalSurface != nullptr); assert(PalSurface != nullptr);
#ifdef USE_SDL3
SDL_FillSurfaceRect(PalSurface, nullptr, 0);
#else
SDL_FillRect(PalSurface, nullptr, 0); SDL_FillRect(PalSurface, nullptr, 0);
#endif
} }
#ifdef _DEBUG #ifdef _DEBUG

14
Source/gmenu.cpp

@ -9,7 +9,17 @@
#include <cstdint> #include <cstdint>
#include <optional> #include <optional>
#ifdef USE_SDL3
#include <SDL3/SDL_keycode.h>
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_surface.h>
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h>
#endif
#include "DiabloUI/ui_flags.hpp" #include "DiabloUI/ui_flags.hpp"
#include "appfat.h"
#include "control.h" #include "control.h"
#include "controls/axis_direction.h" #include "controls/axis_direction.h"
#include "controls/controller_motion.h" #include "controls/controller_motion.h"
@ -125,7 +135,11 @@ void GmenuDrawMenuItem(const Surface &out, TMenuItem *pItem, int y)
const uint16_t steps = std::max<uint16_t>(pItem->sliderSteps(), 2); const uint16_t steps = std::max<uint16_t>(pItem->sliderSteps(), 2);
const uint16_t pos = SliderFillMin + step * (SliderFillMax - SliderFillMin) / steps; const uint16_t pos = SliderFillMin + step * (SliderFillMax - SliderFillMin) / steps;
SDL_Rect rect = MakeSdlRect(SliderValueLeft + uiPositionX, y + SliderValuePaddingTop, pos, SliderValueHeight); SDL_Rect rect = MakeSdlRect(SliderValueLeft + uiPositionX, y + SliderValuePaddingTop, pos, SliderValueHeight);
#ifdef USE_SDL3
SDL_FillSurfaceRect(out.surface, &rect, 205);
#else
SDL_FillRect(out.surface, &rect, 205); SDL_FillRect(out.surface, &rect, 205);
#endif
ClxDraw(out, { SliderValueLeft + pos - SliderMarkerWidth / 2 + uiPositionX, y + SliderValuePaddingTop + SliderValueHeight - 1 }, (*option_cel)[0]); ClxDraw(out, { SliderValueLeft + pos - SliderMarkerWidth / 2 + uiPositionX, y + SliderValuePaddingTop + SliderValueHeight - 1 }, (*option_cel)[0]);
} }

6
Source/gmenu.h

@ -7,6 +7,12 @@
#include <cstdint> #include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_keycode.h>
#else
#include <SDL.h>
#endif
#include "engine/surface.hpp" #include "engine/surface.hpp"
namespace devilution { namespace devilution {

93
Source/hwcursor.cpp

@ -3,11 +3,21 @@
#include <cstdint> #include <cstdint>
#include <tuple> #include <tuple>
#if SDL_VERSION_ATLEAST(2, 0, 0) #ifdef USE_SDL3
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_mouse.h>
#include <SDL3/SDL_render.h>
#include <SDL3/SDL_surface.h>
#include <SDL3/SDL_version.h>
#else
#include <SDL_version.h>
#ifndef USE_SDL1
#include <SDL_mouse.h> #include <SDL_mouse.h>
#include <SDL_render.h> #include <SDL_render.h>
#include <SDL_surface.h> #include <SDL_surface.h>
#endif #endif
#endif
#include "DiabloUI/diabloui.h" #include "DiabloUI/diabloui.h"
@ -35,9 +45,16 @@ enum class HotpointPosition : uint8_t {
Size ScaledSize(Size size) Size ScaledSize(Size size)
{ {
if (renderer != nullptr) { if (renderer != nullptr) {
float scaleX; float scaleX = 1.0F;
float scaleY; float scaleY = 1.0F;
#ifdef USE_SDL3
if (!SDL_GetRenderScale(renderer, &scaleX, &scaleY)) {
LogError("SDL_GetRenderScale: {}", SDL_GetError());
SDL_ClearError();
}
#else
SDL_RenderGetScale(renderer, &scaleX, &scaleY); SDL_RenderGetScale(renderer, &scaleX, &scaleY);
#endif
size.width = static_cast<int>(size.width * scaleX); size.width = static_cast<int>(size.width * scaleX);
size.height = static_cast<int>(size.height * scaleY); size.height = static_cast<int>(size.height * scaleY);
} }
@ -83,7 +100,13 @@ bool SetHardwareCursorFromSurface(SDL_Surface *surface, HotpointPosition hotpoin
newCursor = SDLCursorUniquePtr { SDL_CreateColorCursor(surface, hotpoint.x, hotpoint.y) }; newCursor = SDLCursorUniquePtr { SDL_CreateColorCursor(surface, hotpoint.x, hotpoint.y) };
} else { } else {
// SDL does not support BlitScaled from 8-bit to RGBA. // SDL does not support BlitScaled from 8-bit to RGBA.
const SDLSurfaceUniquePtr converted { SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0) }; const SDLSurfaceUniquePtr converted {
#ifdef USE_SDL3
SDL_ConvertSurface(surface, SDL_PIXELFORMAT_ARGB8888)
#else
SDL_ConvertSurfaceFormat(surface, SDL_PIXELFORMAT_ARGB8888, 0)
#endif
};
const SDLSurfaceUniquePtr scaledSurface = SDLWrap::CreateRGBSurfaceWithFormat(0, scaledSize.width, scaledSize.height, 32, SDL_PIXELFORMAT_ARGB8888); const SDLSurfaceUniquePtr scaledSurface = SDLWrap::CreateRGBSurfaceWithFormat(0, scaledSize.width, scaledSize.height, 32, SDL_PIXELFORMAT_ARGB8888);
if (ShouldUseBilinearScaling()) { if (ShouldUseBilinearScaling()) {
@ -97,7 +120,11 @@ bool SetHardwareCursorFromSurface(SDL_Surface *surface, HotpointPosition hotpoin
Log("hwcursor: SetHardwareCursorFromSurface {}x{} scaled to {}x{} using nearest neighbour scaling", Log("hwcursor: SetHardwareCursorFromSurface {}x{} scaled to {}x{} using nearest neighbour scaling",
size.width, size.height, scaledSize.width, scaledSize.height); size.width, size.height, scaledSize.width, scaledSize.height);
#endif #endif
#ifdef USE_SDL3
SDL_BlitSurfaceScaled(converted.get(), nullptr, scaledSurface.get(), nullptr, SDL_SCALEMODE_NEAREST);
#else
SDL_BlitScaled(converted.get(), nullptr, scaledSurface.get(), nullptr); SDL_BlitScaled(converted.get(), nullptr, scaledSurface.get(), nullptr);
#endif
} }
const Point hotpoint = GetHotpointPosition(*scaledSurface, hotpointPosition); const Point hotpoint = GetHotpointPosition(*scaledSurface, hotpointPosition);
newCursor = SDLCursorUniquePtr { SDL_CreateColorCursor(scaledSurface.get(), hotpoint.x, hotpoint.y) }; newCursor = SDLCursorUniquePtr { SDL_CreateColorCursor(scaledSurface.get(), hotpoint.x, hotpoint.y) };
@ -107,7 +134,15 @@ bool SetHardwareCursorFromSurface(SDL_Surface *surface, HotpointPosition hotpoin
SDL_ClearError(); SDL_ClearError();
return false; return false;
} }
#ifdef USE_SDL3
if (!SDL_SetCursor(newCursor.get())) {
LogError("SDL_SetCursor: {}", SDL_GetError());
SDL_ClearError();
return false;
}
#else
SDL_SetCursor(newCursor.get()); SDL_SetCursor(newCursor.get());
#endif
CurrentCursor = std::move(newCursor); CurrentCursor = std::move(newCursor);
return true; return true;
} }
@ -115,8 +150,29 @@ bool SetHardwareCursorFromSurface(SDL_Surface *surface, HotpointPosition hotpoin
bool SetHardwareCursorFromClxSprite(ClxSprite sprite, HotpointPosition hotpointPosition) bool SetHardwareCursorFromClxSprite(ClxSprite sprite, HotpointPosition hotpointPosition)
{ {
const OwnedSurface surface { sprite.width(), sprite.height() }; const OwnedSurface surface { sprite.width(), sprite.height() };
SDL_SetSurfacePalette(surface.surface, Palette.get()); #ifdef USE_SDL3
SDL_SetColorKey(surface.surface, SDL_TRUE, 0); if (!SDL_SetSurfacePalette(surface.surface, Palette.get())) {
LogError("SDL_SetSurfacePalette: {}", SDL_GetError());
SDL_ClearError();
return false;
}
if (!SDL_SetSurfaceColorKey(surface.surface, true, 0)) {
LogError("SDL_SetSurfaceColorKey: {}", SDL_GetError());
SDL_ClearError();
return false;
}
#else
if (SDL_SetSurfacePalette(surface.surface, Palette.get()) != 0) {
LogError("SDL_SetSurfacePalette: {}", SDL_GetError());
SDL_ClearError();
return false;
}
if (SDL_SetColorKey(surface.surface, SDL_TRUE, 0) != 0) {
LogError("SDL_SetColorKey: {}", SDL_GetError());
SDL_ClearError();
return false;
}
#endif
RenderClxSprite(surface, sprite, { 0, 0 }); RenderClxSprite(surface, sprite, { 0, 0 });
return SetHardwareCursorFromSurface(surface.surface, hotpointPosition); return SetHardwareCursorFromSurface(surface.surface, hotpointPosition);
} }
@ -142,8 +198,29 @@ bool SetHardwareCursorFromSprite(int pcurs)
// Transparent color must not be used in the sprite itself. // Transparent color must not be used in the sprite itself.
// Colors 1-127 are outside of the UI palette so are safe to use. // Colors 1-127 are outside of the UI palette so are safe to use.
constexpr std::uint8_t TransparentColor = 1; constexpr std::uint8_t TransparentColor = 1;
SDL_FillRect(out.surface, nullptr, TransparentColor); #ifdef USE_SDL3
SDL_SetColorKey(out.surface, 1, TransparentColor); if (!SDL_FillSurfaceRect(out.surface, nullptr, TransparentColor)) {
LogError("SDL_FillSurfaceRect: {}", SDL_GetError());
SDL_ClearError();
return false;
}
if (!SDL_SetSurfaceColorKey(out.surface, true, TransparentColor)) {
LogError("SDL_SetSurfaceColorKey: {}", SDL_GetError());
SDL_ClearError();
return false;
}
#else
if (SDL_FillRect(out.surface, nullptr, TransparentColor) != 0) {
LogError("SDL_FillRect: {}", SDL_GetError());
SDL_ClearError();
return false;
}
if (SDL_SetColorKey(out.surface, 1, TransparentColor) != 0) {
LogError("SDL_SetColorKey: {}", SDL_GetError());
SDL_ClearError();
return false;
}
#endif
DrawSoftwareCursor(out, { outlineWidth, size.height - outlineWidth - 1 }, pcurs); DrawSoftwareCursor(out, { outlineWidth, size.height - outlineWidth - 1 }, pcurs);
const bool result = SetHardwareCursorFromSurface( const bool result = SetHardwareCursorFromSurface(

17
Source/hwcursor.hpp

@ -7,7 +7,12 @@
#include <cstdint> #include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_version.h>
#else
#include <SDL_version.h> #include <SDL_version.h>
#endif
#include "options.h" #include "options.h"
#include "utils/log.hpp" #include "utils/log.hpp"
@ -139,7 +144,9 @@ inline void DoReinitializeHardwareCursor()
inline bool IsHardwareCursorVisible() inline bool IsHardwareCursorVisible()
{ {
#if SDL_VERSION_ATLEAST(2, 0, 0) #ifdef USE_SDL3
return SDL_CursorVisible();
#elif SDL_VERSION_ATLEAST(2, 0, 0)
return SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE; return SDL_ShowCursor(SDL_QUERY) == SDL_ENABLE;
#else #else
return false; return false;
@ -157,7 +164,13 @@ inline void SetHardwareCursorVisible(bool visible)
#if LOG_HWCURSOR #if LOG_HWCURSOR
Log("hwcursor: SetHardwareCursorVisible {}", visible); Log("hwcursor: SetHardwareCursorVisible {}", visible);
#endif #endif
if (SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE) < 0) { if (
#ifdef USE_SDL3
visible ? SDL_ShowCursor() : SDL_HideCursor()
#else
SDL_ShowCursor(visible ? SDL_ENABLE : SDL_DISABLE) < 0
#endif
) {
LogError("{}", SDL_GetError()); LogError("{}", SDL_GetError());
SDL_ClearError(); SDL_ClearError();
} }

52
Source/init.cpp

@ -9,7 +9,13 @@
#include <string> #include <string>
#include <vector> #include <vector>
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_video.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include <config.h> #include <config.h>
#include "DiabloUI/diabloui.h" #include "DiabloUI/diabloui.h"
@ -138,38 +144,77 @@ void init_create_window()
void MainWndProc(const SDL_Event &event) void MainWndProc(const SDL_Event &event)
{ {
#ifndef USE_SDL1 #ifndef USE_SDL1
if (event.type != SDL_WINDOWEVENT) #ifdef USE_SDL3
return; switch (event.type)
switch (event.window.event) { #else
if (event.type != SDL_WINDOWEVENT) return;
switch (event.window.event)
#endif
{
#ifdef USE_SDL3
case SDL_EVENT_WINDOW_HIDDEN:
case SDL_EVENT_WINDOW_MINIMIZED:
#else
case SDL_WINDOWEVENT_HIDDEN: case SDL_WINDOWEVENT_HIDDEN:
case SDL_WINDOWEVENT_MINIMIZED: case SDL_WINDOWEVENT_MINIMIZED:
#endif
gbActive = false; gbActive = false;
break; break;
#ifdef USE_SDL3
case SDL_EVENT_WINDOW_SHOWN:
case SDL_EVENT_WINDOW_EXPOSED:
case SDL_EVENT_WINDOW_RESTORED:
#else
case SDL_WINDOWEVENT_SHOWN: case SDL_WINDOWEVENT_SHOWN:
case SDL_WINDOWEVENT_EXPOSED: case SDL_WINDOWEVENT_EXPOSED:
case SDL_WINDOWEVENT_RESTORED: case SDL_WINDOWEVENT_RESTORED:
#endif
gbActive = true; gbActive = true;
RedrawEverything(); RedrawEverything();
break; break;
#ifdef USE_SDL3
case SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED:
#else
case SDL_WINDOWEVENT_SIZE_CHANGED: case SDL_WINDOWEVENT_SIZE_CHANGED:
#endif
ReinitializeHardwareCursor(); ReinitializeHardwareCursor();
break; break;
#ifdef USE_SDL3
case SDL_EVENT_WINDOW_MOUSE_LEAVE:
#else
case SDL_WINDOWEVENT_LEAVE: case SDL_WINDOWEVENT_LEAVE:
#endif
sgbMouseDown = CLICK_NONE; sgbMouseDown = CLICK_NONE;
LastPlayerAction = PlayerActionType::None; LastPlayerAction = PlayerActionType::None;
RedrawEverything(); RedrawEverything();
break; break;
#ifdef USE_SDL3
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
#else
case SDL_WINDOWEVENT_CLOSE: case SDL_WINDOWEVENT_CLOSE:
#endif
diablo_quit(0); diablo_quit(0);
break; break;
#ifdef USE_SDL3
case SDL_EVENT_WINDOW_FOCUS_LOST:
#else
case SDL_WINDOWEVENT_FOCUS_LOST: case SDL_WINDOWEVENT_FOCUS_LOST:
#endif
if (*GetOptions().Gameplay.pauseOnFocusLoss) if (*GetOptions().Gameplay.pauseOnFocusLoss)
diablo_focus_pause(); diablo_focus_pause();
break; break;
#ifdef USE_SDL3
case SDL_EVENT_WINDOW_FOCUS_GAINED:
#else
case SDL_WINDOWEVENT_FOCUS_GAINED: case SDL_WINDOWEVENT_FOCUS_GAINED:
#endif
if (*GetOptions().Gameplay.pauseOnFocusLoss) if (*GetOptions().Gameplay.pauseOnFocusLoss)
diablo_focus_unpause(); diablo_focus_unpause();
break; break;
#ifdef USE_SDL3
default:
break;
#else
case SDL_WINDOWEVENT_MOVED: case SDL_WINDOWEVENT_MOVED:
case SDL_WINDOWEVENT_RESIZED: case SDL_WINDOWEVENT_RESIZED:
case SDL_WINDOWEVENT_MAXIMIZED: case SDL_WINDOWEVENT_MAXIMIZED:
@ -179,6 +224,7 @@ void MainWndProc(const SDL_Event &event)
default: default:
LogVerbose("Unhandled SDL_WINDOWEVENT event: {:d}", event.window.event); LogVerbose("Unhandled SDL_WINDOWEVENT event: {:d}", event.window.event);
break; break;
#endif
} }
#else #else
if (event.type != SDL_ACTIVEEVENT) if (event.type != SDL_ACTIVEEVENT)

4
Source/init.hpp

@ -9,7 +9,11 @@
// https://github.com/bebbo/amiga-gcc/issues/413 // https://github.com/bebbo/amiga-gcc/issues/413
#include <cstdint> #include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#ifdef UNPACKED_MPQS #ifdef UNPACKED_MPQS
#include <string_view> #include <string_view>

59
Source/interfac.cpp

@ -9,7 +9,12 @@
#include <string> #include <string>
#ifdef USE_SDL3 #ifdef USE_SDL3
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_events.h> #include <SDL3/SDL_events.h>
#include <SDL3/SDL_keyboard.h>
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_surface.h>
#include <SDL3/SDL_timer.h>
#include <SDL3/SDL_version.h> #include <SDL3/SDL_version.h>
#else #else
#include <SDL.h> #include <SDL.h>
@ -66,7 +71,11 @@ const int BarPos[3][2] = { { 53, 37 }, { 53, 421 }, { 53, 37 } };
OptionalOwnedClxSpriteList ArtCutsceneWidescreen; OptionalOwnedClxSpriteList ArtCutsceneWidescreen;
#ifdef USE_SDL3
SdlEventType CustomEventType = SDL_EVENT_USER;
#else
SdlEventType CustomEventType = SDL_USEREVENT; SdlEventType CustomEventType = SDL_USEREVENT;
#endif
Cutscenes GetCutSceneFromLevelType(dungeon_type type) Cutscenes GetCutSceneFromLevelType(dungeon_type type)
{ {
@ -220,7 +229,11 @@ void DrawCutsceneBackground()
{ {
const Rectangle &uiRectangle = GetUIRectangle(); const Rectangle &uiRectangle = GetUIRectangle();
const Surface &out = GlobalBackBuffer(); const Surface &out = GlobalBackBuffer();
#ifdef USE_SDL3
SDL_FillSurfaceRect(out.surface, nullptr, 0);
#else
SDL_FillRect(out.surface, nullptr, 0x000000); SDL_FillRect(out.surface, nullptr, 0x000000);
#endif
if (ArtCutsceneWidescreen) { if (ArtCutsceneWidescreen) {
const ClxSprite sprite = (*ArtCutsceneWidescreen)[0]; const ClxSprite sprite = (*ArtCutsceneWidescreen)[0];
RenderClxSprite(out, sprite, { uiRectangle.position.x - (sprite.width() - uiRectangle.size.width) / 2, uiRectangle.position.y }); RenderClxSprite(out, sprite, { uiRectangle.position.x - (sprite.width() - uiRectangle.size.width) / 2, uiRectangle.position.y });
@ -238,7 +251,11 @@ void DrawCutsceneForeground()
out.region.y + BarPos[progress_id][1] + uiRectangle.position.y, out.region.y + BarPos[progress_id][1] + uiRectangle.position.y,
sgdwProgress, sgdwProgress,
ProgressHeight); ProgressHeight);
#ifdef USE_SDL3
SDL_FillSurfaceRect(out.surface, &rect, BarColor[progress_id]);
#else
SDL_FillRect(out.surface, &rect, BarColor[progress_id]); SDL_FillRect(out.surface, &rect, BarColor[progress_id]);
#endif
if (DiabloUiSurface() == PalSurface) if (DiabloUiSurface() == PalSurface)
BltFast(&rect, &rect); BltFast(&rect, &rect);
@ -293,9 +310,15 @@ bool HandleProgressBarUpdate()
SDL_Event event; SDL_Event event;
// We use the real `PollEvent` here instead of `FetchMessage` // We use the real `PollEvent` here instead of `FetchMessage`
// to process real events rather than the recorded ones in demo mode. // to process real events rather than the recorded ones in demo mode.
while (PollEvent(&event) != 0) { while (PollEvent(&event)) {
CheckShouldSkipRendering(); CheckShouldSkipRendering();
if (event.type != SDL_QUIT) { if (event.type !=
#ifdef USE_SDL3
SDL_EVENT_QUIT
#else
SDL_QUIT
#endif
) {
HandleMessage(event, SDL_GetModState()); HandleMessage(event, SDL_GetModState());
} }
if (ProgressEventHandlerState.done) return false; if (ProgressEventHandlerState.done) return false;
@ -465,7 +488,13 @@ void DoLoad(interface_mode uMsg)
SDL_Event event; SDL_Event event;
CustomEventToSdlEvent(event, WM_ERROR); CustomEventToSdlEvent(event, WM_ERROR);
event.user.data1 = new std::string(std::move(loadResult).error()); event.user.data1 = new std::string(std::move(loadResult).error());
if (SDL_PushEvent(&event) < 0) { if (
#ifdef USE_SDL3
!SDL_PushEvent(&event)
#else
SDL_PushEvent(&event) < 0
#endif
) {
LogError("Failed to send WM_ERROR {}", SDL_GetError()); LogError("Failed to send WM_ERROR {}", SDL_GetError());
SDL_ClearError(); SDL_ClearError();
} }
@ -477,7 +506,13 @@ void DoLoad(interface_mode uMsg)
SDL_Event event; SDL_Event event;
CustomEventToSdlEvent(event, WM_DONE); CustomEventToSdlEvent(event, WM_DONE);
if (SDL_PushEvent(&event) < 0) { if (
#ifdef USE_SDL3
!SDL_PushEvent(&event)
#else
SDL_PushEvent(&event) < 0
#endif
) {
LogError("Failed to send WM_DONE {}", SDL_GetError()); LogError("Failed to send WM_DONE {}", SDL_GetError());
SDL_ClearError(); SDL_ClearError();
} }
@ -592,7 +627,13 @@ void interface_msg_pump()
SDL_Event event; SDL_Event event;
uint16_t modState; uint16_t modState;
while (FetchMessage(&event, &modState)) { while (FetchMessage(&event, &modState)) {
if (event.type != SDL_QUIT) { if (event.type !=
#ifdef USE_SDL3
SDL_EVENT_QUIT
#else
SDL_QUIT
#endif
) {
HandleMessage(event, modState); HandleMessage(event, modState);
} }
} }
@ -609,7 +650,13 @@ void IncProgress(uint32_t steps)
if (!HeadlessMode && sgdwProgress != prevProgress) { if (!HeadlessMode && sgdwProgress != prevProgress) {
SDL_Event event; SDL_Event event;
CustomEventToSdlEvent(event, WM_PROGRESS); CustomEventToSdlEvent(event, WM_PROGRESS);
if (SDL_PushEvent(&event) < 0) { if (
#ifdef USE_SDL3
!SDL_PushEvent(&event)
#else
SDL_PushEvent(&event) < 0
#endif
) {
LogError("Failed to send WM_PROGRESS {}", SDL_GetError()); LogError("Failed to send WM_PROGRESS {}", SDL_GetError());
SDL_ClearError(); SDL_ClearError();
} }

12
Source/inv.cpp

@ -9,6 +9,13 @@
#include <optional> #include <optional>
#include <utility> #include <utility>
#ifdef USE_SDL3
#include <SDL3/SDL_keyboard.h>
#include <SDL3/SDL_rect.h>
#else
#include <SDL.h>
#endif
#include <fmt/format.h> #include <fmt/format.h>
#include "DiabloUI/ui_flags.hpp" #include "DiabloUI/ui_flags.hpp"
@ -34,6 +41,7 @@
#include "qol/stash.h" #include "qol/stash.h"
#include "stores.h" #include "stores.h"
#include "towners.h" #include "towners.h"
#include "utils/display.h"
#include "utils/format_int.hpp" #include "utils/format_int.hpp"
#include "utils/is_of.hpp" #include "utils/is_of.hpp"
#include "utils/language.h" #include "utils/language.h"
@ -1088,7 +1096,11 @@ void StartGoldDrop()
const Point start = GetPanelPosition(UiPanels::Inventory, { 67, 128 }); const Point start = GetPanelPosition(UiPanels::Inventory, { 67, 128 });
SDL_Rect rect = MakeSdlRect(start.x, start.y, 180, 20); SDL_Rect rect = MakeSdlRect(start.x, start.y, 180, 20);
#ifdef USE_SDL3
SDL_SetTextInputArea(ghMainWnd, &rect, 0);
#else
SDL_SetTextInputRect(&rect); SDL_SetTextInputRect(&rect);
#endif
OpenGoldDrop(invIndex, max); OpenGoldDrop(invIndex, max);
} }

5
Source/items.cpp

@ -19,7 +19,12 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#ifdef USE_SDL3
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include <fmt/core.h> #include <fmt/core.h>
#include "DiabloUI/ui_flags.hpp" #include "DiabloUI/ui_flags.hpp"

1
Source/loadsave.cpp

@ -12,7 +12,6 @@
#include <numeric> #include <numeric>
#include <string> #include <string>
#include <SDL.h>
#include <ankerl/unordered_dense.h> #include <ankerl/unordered_dense.h>
#include <expected.hpp> #include <expected.hpp>

11
Source/menu.cpp

@ -6,6 +6,13 @@
#include <cstdint> #include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_surface.h>
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h>
#endif
#include "DiabloUI/diabloui.h" #include "DiabloUI/diabloui.h"
#include "DiabloUI/settingsmenu.h" #include "DiabloUI/settingsmenu.h"
#include "engine/assets.hpp" #include "engine/assets.hpp"
@ -137,7 +144,11 @@ bool mainmenu_select_hero_dialog(GameData *gameData)
void mainmenu_wait_for_button_sound() void mainmenu_wait_for_button_sound()
{ {
#ifdef USE_SDL3
SDL_FillSurfaceRect(DiabloUiSurface(), nullptr, 0);
#else
SDL_FillRect(DiabloUiSurface(), nullptr, 0x000000); SDL_FillRect(DiabloUiSurface(), nullptr, 0x000000);
#endif
UiFadeIn(); UiFadeIn();
SDL_Delay(350); // delay to let button pressed sound finish playing SDL_Delay(350); // delay to let button pressed sound finish playing
} }

33
Source/movie.cpp

@ -6,6 +6,13 @@
#include <cstdint> #include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_keycode.h>
#else
#include <SDL.h>
#endif
#include "controls/control_mode.hpp" #include "controls/control_mode.hpp"
#include "controls/plrctrls.h" #include "controls/plrctrls.h"
#include "diablo.h" #include "diablo.h"
@ -53,12 +60,30 @@ void play_movie(const char *pszMovie, bool userCanClose)
} }
} }
switch (event.type) { switch (event.type) {
#ifdef USE_SDL3
case SDL_EVENT_KEY_DOWN:
case SDL_EVENT_MOUSE_BUTTON_UP:
#else
case SDL_KEYDOWN: case SDL_KEYDOWN:
case SDL_MOUSEBUTTONUP: case SDL_MOUSEBUTTONUP:
if (userCanClose || (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE)) #endif
if (userCanClose || (
#ifdef USE_SDL3
event.type == SDL_EVENT_KEY_DOWN && event.key.key == SDLK_ESCAPE
#else
event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_ESCAPE
#endif
))
movie_playing = false; movie_playing = false;
break; break;
#ifndef USE_SDL1 #ifdef USE_SDL3
case SDL_EVENT_WINDOW_FOCUS_LOST:
if (*GetOptions().Gameplay.pauseOnFocusLoss) diablo_focus_pause();
break;
case SDL_EVENT_WINDOW_FOCUS_GAINED:
if (*GetOptions().Gameplay.pauseOnFocusLoss) diablo_focus_unpause();
break;
#elif !defined(USE_SDL1)
case SDL_WINDOWEVENT: case SDL_WINDOWEVENT:
if (*GetOptions().Gameplay.pauseOnFocusLoss) { if (*GetOptions().Gameplay.pauseOnFocusLoss) {
if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST) if (event.window.event == SDL_WINDOWEVENT_FOCUS_LOST)
@ -77,7 +102,11 @@ void play_movie(const char *pszMovie, bool userCanClose)
} }
break; break;
#endif #endif
#ifdef USE_SDL3
case SDL_EVENT_QUIT:
#else
case SDL_QUIT: case SDL_QUIT:
#endif
SVidPlayEnd(); SVidPlayEnd();
diablo_quit(0); diablo_quit(0);
} }

6
Source/msg.cpp

@ -11,6 +11,12 @@
#include <list> #include <list>
#include <memory> #include <memory>
#ifdef USE_SDL3
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h>
#endif
#include <ankerl/unordered_dense.h> #include <ankerl/unordered_dense.h>
#include <fmt/format.h> #include <fmt/format.h>

4
Source/nthread.cpp

@ -8,7 +8,11 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include "diablo.h" #include "diablo.h"
#include "engine/animationinfo.h" #include "engine/animationinfo.h"

48
Source/panels/console.cpp

@ -9,6 +9,9 @@
#ifdef USE_SDL3 #ifdef USE_SDL3
#include <SDL3/SDL_events.h> #include <SDL3/SDL_events.h>
#include <SDL3/SDL_keyboard.h>
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_scancode.h>
#else #else
#include <SDL.h> #include <SDL.h>
@ -31,6 +34,7 @@
#include "lua/autocomplete.hpp" #include "lua/autocomplete.hpp"
#include "lua/repl.hpp" #include "lua/repl.hpp"
#include "utils/algorithm/container.hpp" #include "utils/algorithm/container.hpp"
#include "utils/display.h"
#include "utils/sdl_geometry.h" #include "utils/sdl_geometry.h"
#include "utils/str_cat.hpp" #include "utils/str_cat.hpp"
#include "utils/str_split.hpp" #include "utils/str_split.hpp"
@ -452,7 +456,13 @@ bool ConsoleHandleEvent(const SDL_Event &event)
{ {
if (!IsConsoleVisible) { if (!IsConsoleVisible) {
// Make console open on the top-left keyboard key even if it is not a backtick. // Make console open on the top-left keyboard key even if it is not a backtick.
if (event.type == SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_GRAVE) { if (
#ifdef USE_SDL3
event.type == SDL_EVENT_KEY_DOWN && event.key.scancode == SDL_SCANCODE_GRAVE
#else
event.type == SDL_KEYDOWN && event.key.keysym.scancode == SDL_SCANCODE_GRAVE
#endif
) {
OpenConsole(); OpenConsole();
return true; return true;
} }
@ -463,10 +473,23 @@ bool ConsoleHandleEvent(const SDL_Event &event)
return true; return true;
} }
const auto modState = SDL_GetModState(); const auto modState = SDL_GetModState();
const bool isShift = (modState & KMOD_SHIFT) != 0; const bool isShift = (modState &
#ifdef USE_SDL3
SDL_KMOD_SHIFT
#else
KMOD_SHIFT
#endif
)
!= 0;
switch (event.type) { switch (event.type) {
#ifdef USE_SDL3
case SDL_EVENT_KEY_DOWN:
switch (event.key.key)
#else
case SDL_KEYDOWN: case SDL_KEYDOWN:
switch (event.key.keysym.sym) { switch (event.key.keysym.sym)
#endif
{
case SDLK_ESCAPE: case SDLK_ESCAPE:
if (!AutocompleteSuggestions.empty()) { if (!AutocompleteSuggestions.empty()) {
AutocompleteSuggestions.clear(); AutocompleteSuggestions.clear();
@ -517,14 +540,26 @@ bool ConsoleHandleEvent(const SDL_Event &event)
case SDLK_PAGEDOWN: case SDLK_PAGEDOWN:
--PendingScrollPages; --PendingScrollPages;
return true; return true;
#ifdef USE_SDL3
case SDLK_L:
#else
case SDLK_l: case SDLK_l:
#endif
ClearConsole(); ClearConsole();
return true; return true;
default: default:
return false; return false;
} }
break; break;
#if SDL_VERSION_ATLEAST(2, 0, 0) #ifdef USE_SDL3
case SDL_EVENT_MOUSE_WHEEL:
if (event.wheel.integer_y > 0) {
ScrollOffset += ScrollStep;
} else if (event.wheel.integer_y < 0) {
ScrollOffset -= ScrollStep;
}
return true;
#elif SDL_VERSION_ATLEAST(2, 0, 0)
case SDL_MOUSEWHEEL: case SDL_MOUSEWHEEL:
if (event.wheel.y > 0) { if (event.wheel.y > 0) {
ScrollOffset += ScrollStep; ScrollOffset += ScrollStep;
@ -585,8 +620,13 @@ void DrawConsole(const Surface &out)
if (FirstRender) { if (FirstRender) {
SDL_Rect sdlInputRect = MakeSdlRect(InputRect); SDL_Rect sdlInputRect = MakeSdlRect(InputRect);
#ifdef USE_SDL3
SDL_SetTextInputArea(ghMainWnd, &sdlInputRect, ConsoleInputState.cursorPosition());
SDL_StartTextInput(ghMainWnd);
#else
SDL_SetTextInputRect(&sdlInputRect); SDL_SetTextInputRect(&sdlInputRect);
SDL_StartTextInput(); SDL_StartTextInput();
#endif
FirstRender = false; FirstRender = false;
if (ConsoleLines.empty()) { if (ConsoleLines.empty()) {
InitConsole(); InitConsole();

28
Source/pfile.cpp

@ -12,6 +12,13 @@
#include <ankerl/unordered_dense.h> #include <ankerl/unordered_dense.h>
#include <expected.hpp> #include <expected.hpp>
#ifdef USE_SDL3
#include <SDL3/SDL_iostream.h>
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h>
#endif
#include "codec.h" #include "codec.h"
#include "engine/load_file.hpp" #include "engine/load_file.hpp"
#include "engine/render/primitive_render.hpp" #include "engine/render/primitive_render.hpp"
@ -281,20 +288,37 @@ void CreateDetailDiffs(std::string_view prefix, std::string_view memoryMapFile,
// Note: Detail diffs are currently only supported in unit tests // Note: Detail diffs are currently only supported in unit tests
const std::string memoryMapFileAssetName = StrCat(paths::BasePath(), "/test/fixtures/memory_map/", memoryMapFile, ".txt"); const std::string memoryMapFileAssetName = StrCat(paths::BasePath(), "/test/fixtures/memory_map/", memoryMapFile, ".txt");
#ifdef USE_SDL3
SDL_IOStream *handle = SDL_IOFromFile(memoryMapFileAssetName.c_str(), "r");
#else
SDL_RWops *handle = SDL_RWFromFile(memoryMapFileAssetName.c_str(), "r"); SDL_RWops *handle = SDL_RWFromFile(memoryMapFileAssetName.c_str(), "r");
#endif
if (handle == nullptr) { if (handle == nullptr) {
app_fatal(StrCat("MemoryMapFile ", memoryMapFile, " is missing")); app_fatal(StrCat("MemoryMapFile ", memoryMapFile, " is missing"));
return; return;
} }
const size_t readBytes = static_cast<size_t>(SDL_RWsize(handle)); const size_t readBytes = static_cast<size_t>(
#ifdef USE_SDL3
SDL_GetIOSize(handle)
#else
SDL_RWsize(handle)
#endif
);
const std::unique_ptr<std::byte[]> memoryMapFileData { new std::byte[readBytes] }; const std::unique_ptr<std::byte[]> memoryMapFileData { new std::byte[readBytes] };
#if SDL_VERSION_ATLEAST(2, 0, 0) #ifdef USE_SDL3
SDL_ReadIO(handle, memoryMapFileData.get(), readBytes);
#elif SDL_VERSION_ATLEAST(2, 0, 0)
SDL_RWread(handle, memoryMapFileData.get(), readBytes, 1); SDL_RWread(handle, memoryMapFileData.get(), readBytes, 1);
#else #else
SDL_RWread(handle, memoryMapFileData.get(), static_cast<int>(readBytes), 1); SDL_RWread(handle, memoryMapFileData.get(), static_cast<int>(readBytes), 1);
#endif #endif
#ifdef USE_SDL3
SDL_CloseIO(handle);
#else
SDL_RWclose(handle); SDL_RWclose(handle);
#endif
const std::string_view buffer(reinterpret_cast<const char *>(memoryMapFileData.get()), readBytes); const std::string_view buffer(reinterpret_cast<const char *>(memoryMapFileData.get()), readBytes);

7
Source/player.cpp

@ -7,6 +7,13 @@
#include <cmath> #include <cmath>
#include <cstdint> #include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h>
#endif
#include <fmt/core.h> #include <fmt/core.h>
#include "control.h" #include "control.h"

8
Source/plrmsg.cpp

@ -9,6 +9,12 @@
#include <array> #include <array>
#include <cstdint> #include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h>
#endif
#include <fmt/format.h> #include <fmt/format.h>
#include "control.h" #include "control.h"
@ -27,7 +33,7 @@ namespace {
struct PlayerMessage { struct PlayerMessage {
/** Time message was received */ /** Time message was received */
Uint32 time; uint32_t time;
/** The default text color */ /** The default text color */
UiFlags style; UiFlags style;
/** The text message to display on screen */ /** The text message to display on screen */

2
Source/plrmsg.h

@ -9,8 +9,6 @@
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <SDL.h>
#include "DiabloUI/ui_flags.hpp" #include "DiabloUI/ui_flags.hpp"
#include "engine/surface.hpp" #include "engine/surface.hpp"
#include "player.h" #include "player.h"

14
Source/restrict.cpp

@ -4,23 +4,37 @@
* Implementation of functionality for checking if the game will be able run on the system. * Implementation of functionality for checking if the game will be able run on the system.
*/ */
#include <string>
#include "appfat.h" #include "appfat.h"
#include "utils/file_util.h" #include "utils/file_util.h"
#include "utils/paths.h" #include "utils/paths.h"
#ifdef USE_SDL3
#include <SDL3/SDL_iostream.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
namespace devilution { namespace devilution {
void ReadOnlyTest() void ReadOnlyTest()
{ {
const std::string path = paths::PrefPath() + "Diablo1ReadOnlyTest.foo"; const std::string path = paths::PrefPath() + "Diablo1ReadOnlyTest.foo";
#ifdef USE_SDL3
SDL_IOStream *file = SDL_IOFromFile(path.c_str(), "w");
#else
SDL_RWops *file = SDL_RWFromFile(path.c_str(), "w"); SDL_RWops *file = SDL_RWFromFile(path.c_str(), "w");
#endif
if (file == nullptr) { if (file == nullptr) {
DirErrorDlg(paths::PrefPath()); DirErrorDlg(paths::PrefPath());
} }
#ifdef USE_SDL3
SDL_CloseIO(file);
#else
SDL_RWclose(file); SDL_RWclose(file);
#endif
RemoveFile(path.c_str()); RemoveFile(path.c_str());
} }

75
Source/storm/storm_svid.cpp

@ -5,6 +5,16 @@
#include <cstring> #include <cstring>
#include <optional> #include <optional>
#ifdef USE_SDL3
#include <SDL3/SDL_pixels.h>
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_render.h>
#include <SDL3/SDL_surface.h>
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h>
#endif
#include <SmackerDecoder.h> #include <SmackerDecoder.h>
#ifndef NOSOUND #ifndef NOSOUND
@ -39,7 +49,7 @@ constexpr uint64_t TimeMsToSmk(uint64_t ms) { return ms * SmackerTimeUnit; }
constexpr uint64_t TimeSmkToMs(uint64_t time) { return time / SmackerTimeUnit; }; constexpr uint64_t TimeSmkToMs(uint64_t time) { return time / SmackerTimeUnit; };
uint64_t GetTicksSmk() uint64_t GetTicksSmk()
{ {
#if SDL_VERSION_ATLEAST(2, 0, 18) #if SDL_VERSION_ATLEAST(2, 0, 18) && !defined(USE_SDL3)
return TimeMsToSmk(SDL_GetTicks64()); return TimeMsToSmk(SDL_GetTicks64());
#else #else
return TimeMsToSmk(SDL_GetTicks()); return TimeMsToSmk(SDL_GetTicks());
@ -180,7 +190,15 @@ void UpdatePalette()
if (SDL_SetSurfacePalette(SVidSurface.get(), SVidPalette.get()) <= -1) { if (SDL_SetSurfacePalette(SVidSurface.get(), SVidPalette.get()) <= -1) {
ErrSdl(); ErrSdl();
} }
if (GetOutputSurface()->format->BitsPerPixel == 8) {
const SDL_Surface *surface = GetOutputSurface();
if (
#ifdef USE_SDL3
SDL_BITSPERPIXEL(surface->format)
#else
surface->format->BitsPerPixel
#endif
== 8) {
if (SDL_SetSurfacePalette(GetOutputSurface(), SVidPalette.get()) <= -1) { if (SDL_SetSurfacePalette(GetOutputSurface(), SVidPalette.get()) <= -1) {
ErrSdl(); ErrSdl();
} }
@ -192,7 +210,13 @@ bool BlitFrame()
{ {
#ifndef USE_SDL1 #ifndef USE_SDL1
if (renderer != nullptr) { if (renderer != nullptr) {
if (SDL_BlitSurface(SVidSurface.get(), nullptr, GetOutputSurface(), nullptr) <= -1) { if (
#ifdef USE_SDL3
SDL_BlitSurface(SVidSurface.get(), nullptr, GetOutputSurface(), nullptr)
#else
SDL_BlitSurface(SVidSurface.get(), nullptr, GetOutputSurface(), nullptr) <= -1
#endif
) {
Log("{}", SDL_GetError()); Log("{}", SDL_GetError());
return false; return false;
} }
@ -203,7 +227,12 @@ bool BlitFrame()
#ifdef USE_SDL1 #ifdef USE_SDL1
const bool isIndexedOutputFormat = SDLBackport_IsPixelFormatIndexed(outputSurface->format); const bool isIndexedOutputFormat = SDLBackport_IsPixelFormatIndexed(outputSurface->format);
#else #else
#ifdef USE_SDL3
const SDL_PixelFormat wndFormat = SDL_GetWindowPixelFormat(ghMainWnd);
#else
const Uint32 wndFormat = SDL_GetWindowPixelFormat(ghMainWnd); const Uint32 wndFormat = SDL_GetWindowPixelFormat(ghMainWnd);
#endif
const bool isIndexedOutputFormat = SDL_ISPIXELFORMAT_INDEXED(wndFormat); const bool isIndexedOutputFormat = SDL_ISPIXELFORMAT_INDEXED(wndFormat);
#endif #endif
SDL_Rect outputRect; SDL_Rect outputRect;
@ -224,7 +253,13 @@ bool BlitFrame()
if (isIndexedOutputFormat if (isIndexedOutputFormat
|| outputSurface->w == static_cast<int>(SVidWidth) || outputSurface->w == static_cast<int>(SVidWidth)
|| outputSurface->h == static_cast<int>(SVidHeight)) { || outputSurface->h == static_cast<int>(SVidHeight)) {
if (SDL_BlitSurface(SVidSurface.get(), nullptr, outputSurface, &outputRect) <= -1) { if (
#ifdef USE_SDL3
SDL_BlitSurface(SVidSurface.get(), nullptr, outputSurface, &outputRect)
#else
SDL_BlitSurface(SVidSurface.get(), nullptr, outputSurface, &outputRect) <= -1
#endif
) {
ErrSdl(); ErrSdl();
} }
} else { } else {
@ -235,7 +270,13 @@ bool BlitFrame()
#else #else
SDLSurfaceUniquePtr converted = SDLWrap::ConvertSurfaceFormat(SVidSurface.get(), wndFormat, 0); SDLSurfaceUniquePtr converted = SDLWrap::ConvertSurfaceFormat(SVidSurface.get(), wndFormat, 0);
#endif #endif
if (SDL_BlitScaled(converted.get(), nullptr, outputSurface, &outputRect) <= -1) { if (
#ifdef USE_SDL3
SDL_BlitSurfaceScaled(converted.get(), nullptr, outputSurface, &outputRect, SDL_SCALEMODE_LINEAR)
#else
SDL_BlitScaled(converted.get(), nullptr, outputSurface, &outputRect) <= -1
#endif
) {
Log("{}", SDL_GetError()); Log("{}", SDL_GetError());
return false; return false;
} }
@ -264,7 +305,7 @@ bool SVidPlayBegin(const char *filename, int flags)
// 0x800000 // Edge detection // 0x800000 // Edge detection
// 0x200800 // Clear FB // 0x200800 // Clear FB
SDL_RWops *videoStream = OpenAssetAsSdlRwOps(filename); auto *videoStream = OpenAssetAsSdlRwOps(filename);
SVidHandle = Smacker_Open(videoStream); SVidHandle = Smacker_Open(videoStream);
if (!SVidHandle.isValid) { if (!SVidHandle.isValid) {
return false; return false;
@ -312,7 +353,14 @@ bool SVidPlayBegin(const char *filename, int flags)
const int renderWidth = static_cast<int>(SVidWidth); const int renderWidth = static_cast<int>(SVidWidth);
const int renderHeight = static_cast<int>(SVidHeight); const int renderHeight = static_cast<int>(SVidHeight);
texture = SDLWrap::CreateTexture(renderer, DEVILUTIONX_DISPLAY_TEXTURE_FORMAT, SDL_TEXTUREACCESS_STREAMING, renderWidth, renderHeight); texture = SDLWrap::CreateTexture(renderer, DEVILUTIONX_DISPLAY_TEXTURE_FORMAT, SDL_TEXTUREACCESS_STREAMING, renderWidth, renderHeight);
if (SDL_RenderSetLogicalSize(renderer, renderWidth, renderHeight) <= -1) { if (
#ifdef USE_SDL3
!SDL_SetRenderLogicalPresentation(renderer, renderWidth, renderHeight,
*GetOptions().Graphics.integerScaling ? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE : SDL_LOGICAL_PRESENTATION_STRETCH)
#else
SDL_RenderSetLogicalSize(renderer, renderWidth, renderHeight) <= -1
#endif
) {
ErrSdl(); ErrSdl();
} }
} }
@ -330,7 +378,11 @@ bool SVidPlayBegin(const char *filename, int flags)
#endif #endif
// Set the background to black. // Set the background to black.
#ifdef USE_SDL3
SDL_FillSurfaceRect(GetOutputSurface(), nullptr, 0x000000);
#else
SDL_FillRect(GetOutputSurface(), nullptr, 0x000000); SDL_FillRect(GetOutputSurface(), nullptr, 0x000000);
#endif
// The buffer for the frame. It is not the same as the SDL surface because the SDL surface also has pitch padding. // The buffer for the frame. It is not the same as the SDL surface because the SDL surface also has pitch padding.
SVidFrameBuffer = std::unique_ptr<uint8_t[]> { new uint8_t[static_cast<size_t>(SVidWidth * SVidHeight)] }; SVidFrameBuffer = std::unique_ptr<uint8_t[]> { new uint8_t[static_cast<size_t>(SVidWidth * SVidHeight)] };
@ -415,7 +467,14 @@ void SVidPlayEnd()
#ifndef USE_SDL1 #ifndef USE_SDL1
if (renderer != nullptr) { if (renderer != nullptr) {
texture = SDLWrap::CreateTexture(renderer, DEVILUTIONX_DISPLAY_TEXTURE_FORMAT, SDL_TEXTUREACCESS_STREAMING, gnScreenWidth, gnScreenHeight); texture = SDLWrap::CreateTexture(renderer, DEVILUTIONX_DISPLAY_TEXTURE_FORMAT, SDL_TEXTUREACCESS_STREAMING, gnScreenWidth, gnScreenHeight);
if (renderer != nullptr && SDL_RenderSetLogicalSize(renderer, gnScreenWidth, gnScreenHeight) <= -1) { if (
#ifdef USE_SDL3
!SDL_SetRenderLogicalPresentation(renderer, gnScreenWidth, gnScreenHeight,
*GetOptions().Graphics.integerScaling ? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE : SDL_LOGICAL_PRESENTATION_STRETCH)
#else
SDL_RenderSetLogicalSize(renderer, gnScreenWidth, gnScreenHeight) <= -1
#endif
) {
ErrSdl(); ErrSdl();
} }
} }

7
Source/tmsg.cpp

@ -3,9 +3,14 @@
* *
* Implementation of functionality transmitting chat messages. * Implementation of functionality transmitting chat messages.
*/ */
#include <cstdint>
#include <list> #include <list>
#include <cstdint> #ifdef USE_SDL3
#include <SDL3/SDL_timer.h>
#else
#include <SDL.h>
#endif
#include "diablo.h" #include "diablo.h"
#include "tmsg.h" #include "tmsg.h"

2
Source/track.cpp

@ -5,8 +5,6 @@
*/ */
#include "track.h" #include "track.h"
#include <SDL.h>
#include "controls/control_mode.hpp" #include "controls/control_mode.hpp"
#include "controls/game_controls.h" #include "controls/game_controls.h"
#include "controls/plrctrls.h" #include "controls/plrctrls.h"

228
Source/utils/display.cpp

@ -5,6 +5,22 @@
#include <cstdint> #include <cstdint>
#include <utility> #include <utility>
#ifdef USE_SDL3
#include <SDL3/SDL_hints.h>
#include <SDL3/SDL_init.h>
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_render.h>
#include <SDL3/SDL_surface.h>
#include <SDL3/SDL_video.h>
#else
#include <SDL.h>
#ifdef USE_SDL1
#include "utils/sdl2_to_1_2_backports.h"
#else
#include "utils/sdl2_backports.h"
#endif
#endif
#ifdef __vita__ #ifdef __vita__
#include <psp2/power.h> #include <psp2/power.h>
#endif #endif
@ -136,11 +152,16 @@ const auto OptionChangeHandlerFullscreen = (GetOptions().Graphics.fullscreen.Set
void OptionGrabInputChanged() void OptionGrabInputChanged()
{ {
#ifdef USE_SDL1 #ifdef USE_SDL3
SDL_WM_GrabInput(*GetOptions().Gameplay.grabInput ? SDL_GRAB_ON : SDL_GRAB_OFF); if (ghMainWnd != nullptr) {
#else SDL_SetWindowMouseGrab(ghMainWnd, *GetOptions().Gameplay.grabInput);
if (ghMainWnd != nullptr) }
#elif !defined(USE_SDL1)
if (ghMainWnd != nullptr) {
SDL_SetWindowGrab(ghMainWnd, *GetOptions().Gameplay.grabInput ? SDL_TRUE : SDL_FALSE); SDL_SetWindowGrab(ghMainWnd, *GetOptions().Gameplay.grabInput ? SDL_TRUE : SDL_FALSE);
}
#else
SDL_WM_GrabInput(*GetOptions().Gameplay.grabInput ? SDL_GRAB_ON : SDL_GRAB_OFF);
#endif #endif
} }
const auto OptionChangeHandlerGrabInput = (GetOptions().Gameplay.grabInput.SetValueChangedCallback(OptionGrabInputChanged), true); const auto OptionChangeHandlerGrabInput = (GetOptions().Gameplay.grabInput.SetValueChangedCallback(OptionGrabInputChanged), true);
@ -267,11 +288,23 @@ const auto OptionChangeHandlerVSync = (GetOptions().Graphics.frameRateControl.Se
struct DisplayModeComparator { struct DisplayModeComparator {
Size size; Size size;
#ifdef USE_SDL3
SDL_PixelFormat pixelFormat;
#else
SDL_PixelFormatEnum pixelFormat; SDL_PixelFormatEnum pixelFormat;
#endif
// Is `a` better than `b`? // Is `a` better than `b`?
#ifdef USE_SDL3
[[nodiscard]] bool operator()(const SDL_DisplayMode *aPtr, const SDL_DisplayMode *bPtr)
#else
[[nodiscard]] bool operator()(const SDL_DisplayMode &a, const SDL_DisplayMode &b) [[nodiscard]] bool operator()(const SDL_DisplayMode &a, const SDL_DisplayMode &b)
#endif
{ {
#ifdef USE_SDL3
const SDL_DisplayMode &a = *aPtr;
const SDL_DisplayMode &b = *bPtr;
#endif
const int dwa = a.w - size.width; const int dwa = a.w - size.width;
const int dha = a.h - size.height; const int dha = a.h - size.height;
const int dwb = b.w - size.width; const int dwb = b.w - size.width;
@ -302,11 +335,29 @@ struct DisplayModeComparator {
} // namespace } // namespace
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_DisplayMode GetNearestDisplayMode(Size preferredSize, SDL_PixelFormatEnum preferredPixelFormat) SDL_DisplayMode GetNearestDisplayMode(Size preferredSize,
#ifdef USE_SDL3
SDL_PixelFormat preferredPixelFormat
#else
SDL_PixelFormatEnum preferredPixelFormat
#endif
)
{ {
SDL_DisplayMode nearestDisplayMode; SDL_DisplayMode *nearestDisplayMode = nullptr;
if (SDL_GetWindowDisplayMode(ghMainWnd, &nearestDisplayMode) != 0) #ifdef USE_SDL3
ErrSdl(); const SDL_DisplayMode *fullscreenMode = SDL_GetWindowFullscreenMode(ghMainWnd);
if (fullscreenMode == nullptr) ErrSdl();
const SDL_DisplayID displayId = SDL_GetDisplayForWindow(ghMainWnd);
if (displayId == 0) ErrSdl();
int modeCount;
SDLUniquePtr<SDL_DisplayMode *> modes { SDL_GetFullscreenDisplayModes(displayId, &modeCount) };
if (modes == nullptr) ErrSdl();
nearestDisplayMode = *std::min_element(
modes.get(), modes.get() + modeCount, DisplayModeComparator { preferredSize, preferredPixelFormat });
#else
SDL_DisplayMode ownedNearestDisplayMode;
if (SDL_GetWindowDisplayMode(ghMainWnd, &ownedNearestDisplayMode) != 0) ErrSdl();
nearestDisplayMode = &ownedNearestDisplayMode;
const int displayIndex = SDL_GetWindowDisplayIndex(ghMainWnd); const int displayIndex = SDL_GetWindowDisplayIndex(ghMainWnd);
const int modeCount = SDL_GetNumDisplayModes(displayIndex); const int modeCount = SDL_GetNumDisplayModes(displayIndex);
@ -321,17 +372,18 @@ SDL_DisplayMode GetNearestDisplayMode(Size preferredSize, SDL_PixelFormatEnum pr
modes.push_back(displayMode); modes.push_back(displayMode);
} }
if (!modes.empty()) { if (!modes.empty()) {
nearestDisplayMode = *std::min_element( nearestDisplayMode = &*std::min_element(
modes.begin(), modes.end(), DisplayModeComparator { preferredSize, preferredPixelFormat }); modes.begin(), modes.end(), DisplayModeComparator { preferredSize, preferredPixelFormat });
} }
#endif
LogVerbose("Nearest display mode to {}x{} is {}x{} {}bpp {}Hz", LogVerbose("Nearest display mode to {}x{} is {}x{} {}bpp {}Hz",
preferredSize.width, preferredSize.height, preferredSize.width, preferredSize.height,
nearestDisplayMode.w, nearestDisplayMode.h, nearestDisplayMode->w, nearestDisplayMode->h,
SDL_BITSPERPIXEL(nearestDisplayMode.format), SDL_BITSPERPIXEL(nearestDisplayMode->format),
nearestDisplayMode.refresh_rate); nearestDisplayMode->refresh_rate);
return nearestDisplayMode; return *nearestDisplayMode;
} }
#endif #endif
@ -353,7 +405,11 @@ float GetDpiScalingFactor()
int renderWidth; int renderWidth;
int renderHeight; int renderHeight;
#ifdef USE_SDL3
SDL_GetCurrentRenderOutputSize(renderer, &renderWidth, &renderHeight);
#else
SDL_GetRendererOutputSize(renderer, &renderWidth, &renderHeight); SDL_GetRendererOutputSize(renderer, &renderWidth, &renderHeight);
#endif
int windowWidth; int windowWidth;
int windowHeight; int windowHeight;
@ -399,10 +455,12 @@ void SetVideoModeToPrimary(bool fullscreen, int width, int height)
bool IsFullScreen() bool IsFullScreen()
{ {
#ifdef USE_SDL1 #ifdef USE_SDL3
return (SDL_GetVideoSurface()->flags & SDL_FULLSCREEN) != 0; return (SDL_GetWindowFlags(ghMainWnd) & SDL_WINDOW_FULLSCREEN) != 0;
#else #elif !defined(USE_SDL1)
return (SDL_GetWindowFlags(ghMainWnd) & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)) != 0; return (SDL_GetWindowFlags(ghMainWnd) & (SDL_WINDOW_FULLSCREEN | SDL_WINDOW_FULLSCREEN_DESKTOP)) != 0;
#else
return (SDL_GetVideoSurface()->flags & SDL_FULLSCREEN) != 0;
#endif #endif
} }
@ -424,7 +482,10 @@ bool SpawnWindow(const char *lpWindowName)
} }
#endif #endif
#if SDL_VERSION_ATLEAST(2, 0, 4) #ifdef USE_SDL3
SDL_SetHint(SDL_HINT_RETURN_KEY_HIDES_IME, "1");
#endif
#if SDL_VERSION_ATLEAST(2, 0, 4) && !defined(USE_SDL3)
SDL_SetHint(SDL_HINT_IME_INTERNAL_EDITING, "1"); SDL_SetHint(SDL_HINT_IME_INTERNAL_EDITING, "1");
#endif #endif
#if SDL_VERSION_ATLEAST(2, 0, 6) && defined(__vita__) #if SDL_VERSION_ATLEAST(2, 0, 6) && defined(__vita__)
@ -433,10 +494,12 @@ bool SpawnWindow(const char *lpWindowName)
#if SDL_VERSION_ATLEAST(2, 0, 10) #if SDL_VERSION_ATLEAST(2, 0, 10)
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0"); SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
#endif #endif
#if SDL_VERSION_ATLEAST(2, 0, 2) #ifdef USE_SDL3
SDL_SetHint(SDL_HINT_GAMECONTROLLER_SENSOR_FUSION, "0");
#elif SDL_VERSION_ATLEAST(2, 0, 2)
SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0"); SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
#endif #endif
#if SDL_VERSION_ATLEAST(2, 0, 12) #if SDL_VERSION_ATLEAST(2, 0, 12) && !defined(USE_SDL3)
SDL_SetHint(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, "0"); SDL_SetHint(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, "0");
#endif #endif
@ -445,7 +508,11 @@ bool SpawnWindow(const char *lpWindowName)
initFlags |= SDL_INIT_AUDIO; initFlags |= SDL_INIT_AUDIO;
#endif #endif
#ifndef USE_SDL1 #ifndef USE_SDL1
#ifdef USE_SDL3
initFlags |= SDL_INIT_GAMEPAD;
#else
initFlags |= SDL_INIT_GAMECONTROLLER; initFlags |= SDL_INIT_GAMECONTROLLER;
#endif
SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft LandscapeRight"); SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft LandscapeRight");
#endif #endif
@ -456,7 +523,11 @@ bool SpawnWindow(const char *lpWindowName)
#ifndef USE_SDL1 #ifndef USE_SDL1
if (GetOptions().Controller.szMapping[0] != '\0') { if (GetOptions().Controller.szMapping[0] != '\0') {
#ifdef USE_SDL3
SDL_AddGamepadMapping(GetOptions().Controller.szMapping);
#else
SDL_GameControllerAddMapping(GetOptions().Controller.szMapping); SDL_GameControllerAddMapping(GetOptions().Controller.szMapping);
#endif
} }
#endif #endif
@ -478,31 +549,52 @@ bool SpawnWindow(const char *lpWindowName)
if (*GetOptions().Gameplay.grabInput) if (*GetOptions().Gameplay.grabInput)
SDL_WM_GrabInput(SDL_GRAB_ON); SDL_WM_GrabInput(SDL_GRAB_ON);
atexit(SDL_VideoQuit); // Without this video mode is not restored after fullscreen. atexit(SDL_VideoQuit); // Without this video mode is not restored after fullscreen.
#else
#ifdef USE_SDL3
int flags = SDL_WINDOW_HIGH_PIXEL_DENSITY;
#else #else
int flags = SDL_WINDOW_ALLOW_HIGHDPI; int flags = SDL_WINDOW_ALLOW_HIGHDPI;
#endif
if (*GetOptions().Graphics.upscale) { if (*GetOptions().Graphics.upscale) {
if (*GetOptions().Graphics.fullscreen) { if (*GetOptions().Graphics.fullscreen) {
#ifdef USE_SDL3
flags |= SDL_WINDOW_FULLSCREEN;
#else
flags |= SDL_WINDOW_FULLSCREEN_DESKTOP; flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
#endif
} }
flags |= SDL_WINDOW_RESIZABLE; flags |= SDL_WINDOW_RESIZABLE;
} else if (*GetOptions().Graphics.fullscreen) { } else if (*GetOptions().Graphics.fullscreen) {
flags |= SDL_WINDOW_FULLSCREEN; flags |= SDL_WINDOW_FULLSCREEN;
} }
#ifdef USE_SDL3
ghMainWnd = SDL_CreateWindow(lpWindowName, windowSize.width, windowSize.height, flags);
#else
ghMainWnd = SDL_CreateWindow(lpWindowName, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, windowSize.width, windowSize.height, flags); ghMainWnd = SDL_CreateWindow(lpWindowName, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, windowSize.width, windowSize.height, flags);
#endif
#if defined(DEVILUTIONX_DISPLAY_PIXELFORMAT) #if defined(DEVILUTIONX_DISPLAY_PIXELFORMAT)
SDL_DisplayMode nearestDisplayMode = GetNearestDisplayMode(windowSize, DEVILUTIONX_DISPLAY_PIXELFORMAT); SDL_DisplayMode nearestDisplayMode = GetNearestDisplayMode(windowSize, DEVILUTIONX_DISPLAY_PIXELFORMAT);
if (SDL_SetWindowDisplayMode(ghMainWnd, &nearestDisplayMode) != 0) { #if USE_SDL3
ErrSdl(); if (SDL_SetWindowFullscreenMode(ghMainWnd, &nearestDisplayMode) != 0) ErrSdl();
} #else
if (SDL_SetWindowDisplayMode(ghMainWnd, &nearestDisplayMode) != 0) ErrSdl();
#endif
#endif #endif
// Note: https://github.com/libsdl-org/SDL/issues/962 // Note: https://github.com/libsdl-org/SDL/issues/962
// This is a solution to a problem related to SDL mouse grab. // This is a solution to a problem related to SDL mouse grab.
// See https://github.com/diasurgical/devilutionX/issues/4251 // See https://github.com/diasurgical/devilutionX/issues/4251
if (ghMainWnd != nullptr) #ifdef USE_SDL3
if (ghMainWnd != nullptr) {
SDL_SetWindowMouseGrab(ghMainWnd, *GetOptions().Gameplay.grabInput);
}
#else
if (ghMainWnd != nullptr) {
SDL_SetWindowGrab(ghMainWnd, *GetOptions().Gameplay.grabInput ? SDL_TRUE : SDL_FALSE); SDL_SetWindowGrab(ghMainWnd, *GetOptions().Gameplay.grabInput ? SDL_TRUE : SDL_FALSE);
}
#endif
#endif #endif
if (ghMainWnd == nullptr) { if (ghMainWnd == nullptr) {
@ -511,11 +603,21 @@ bool SpawnWindow(const char *lpWindowName)
int refreshRate = 60; int refreshRate = 60;
#ifndef USE_SDL1 #ifndef USE_SDL1
#ifdef USE_SDL3
const SDL_DisplayID displayId = SDL_GetDisplayForWindow(ghMainWnd);
if (displayId == 0) ErrSdl();
const SDL_DisplayMode *displayMode = SDL_GetCurrentDisplayMode(displayId);
if (displayMode == nullptr) ErrSdl();
if (displayMode->refresh_rate != 0.F) {
refreshRate = static_cast<int>(displayMode->refresh_rate);
}
#else
SDL_DisplayMode mode; SDL_DisplayMode mode;
SDL_GetDisplayMode(0, 0, &mode); SDL_GetDisplayMode(0, 0, &mode);
if (mode.refresh_rate != 0) { if (mode.refresh_rate != 0) {
refreshRate = mode.refresh_rate; refreshRate = mode.refresh_rate;
} }
#endif
#endif #endif
refreshDelay = 1000000 / refreshRate; refreshDelay = 1000000 / refreshRate;
@ -539,9 +641,16 @@ void ReinitializeTexture()
return; return;
auto quality = StrCat(static_cast<int>(*GetOptions().Graphics.scaleQuality)); auto quality = StrCat(static_cast<int>(*GetOptions().Graphics.scaleQuality));
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, quality.c_str());
#ifdef USE_SDL3
texture = SDLWrap::CreateTexture(renderer, DEVILUTIONX_DISPLAY_TEXTURE_FORMAT, SDL_TEXTUREACCESS_STREAMING, gnScreenWidth, gnScreenHeight); texture = SDLWrap::CreateTexture(renderer, DEVILUTIONX_DISPLAY_TEXTURE_FORMAT, SDL_TEXTUREACCESS_STREAMING, gnScreenWidth, gnScreenHeight);
if (quality == "nearest") {
SDL_SetTextureScaleMode(texture.get(), SDL_SCALEMODE_NEAREST);
}
#else
SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, quality.c_str());
texture = SDLWrap::CreateTexture(renderer, DEVILUTIONX_DISPLAY_TEXTURE_FORMAT, SDL_TEXTUREACCESS_STREAMING, gnScreenWidth, gnScreenHeight);
#endif
} }
void ReinitializeIntegerScale() void ReinitializeIntegerScale()
@ -550,10 +659,21 @@ void ReinitializeIntegerScale()
ResizeWindow(); ResizeWindow();
return; return;
} }
if (renderer == nullptr) return;
if (renderer != nullptr && SDL_RenderSetIntegerScale(renderer, *GetOptions().Graphics.integerScaling ? SDL_TRUE : SDL_FALSE) < 0) { #ifdef USE_SDL3
int w, h;
SDL_RendererLogicalPresentation mode;
if (!SDL_GetRenderLogicalPresentation(renderer, &w, &h, &mode)) ErrSdl();
const SDL_RendererLogicalPresentation newMode = *GetOptions().Graphics.integerScaling
? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE
: SDL_LOGICAL_PRESENTATION_LETTERBOX;
if (mode != newMode) SDL_SetRenderLogicalPresentation(renderer, w, h, newMode);
#else
if (SDL_RenderSetIntegerScale(renderer, *GetOptions().Graphics.integerScaling ? SDL_TRUE : SDL_FALSE) < 0) {
ErrSdl(); ErrSdl();
} }
#endif
} }
#endif #endif
@ -573,18 +693,32 @@ void ReinitializeRenderer()
if (*GetOptions().Graphics.upscale) { if (*GetOptions().Graphics.upscale) {
// We don't recreate the renderer, because this can result in a freezing (not refreshing) rendering // We don't recreate the renderer, because this can result in a freezing (not refreshing) rendering
if (renderer == nullptr) { if (renderer == nullptr) {
#ifdef USE_SDL3
renderer = SDL_CreateRenderer(ghMainWnd, nullptr);
#else
renderer = SDL_CreateRenderer(ghMainWnd, -1, 0); renderer = SDL_CreateRenderer(ghMainWnd, -1, 0);
#endif
if (renderer == nullptr) { if (renderer == nullptr) {
ErrSdl(); ErrSdl();
} }
} }
#if SDL_VERSION_ATLEAST(2, 0, 18) #ifdef USE_SDL3
SDL_SetRenderVSync(renderer, *GetOptions().Graphics.frameRateControl == FrameRateControl::VerticalSync ? 1 : 0);
#elif SDL_VERSION_ATLEAST(2, 0, 18)
SDL_RenderSetVSync(renderer, *GetOptions().Graphics.frameRateControl == FrameRateControl::VerticalSync ? 1 : 0); SDL_RenderSetVSync(renderer, *GetOptions().Graphics.frameRateControl == FrameRateControl::VerticalSync ? 1 : 0);
#endif #endif
ReinitializeTexture(); ReinitializeTexture();
#ifdef USE_SDL3
if (!SDL_SetRenderLogicalPresentation(renderer, gnScreenWidth, gnScreenHeight,
*GetOptions().Graphics.integerScaling
? SDL_LOGICAL_PRESENTATION_INTEGER_SCALE
: SDL_LOGICAL_PRESENTATION_LETTERBOX)) {
ErrSdl();
}
#else
if (SDL_RenderSetIntegerScale(renderer, *GetOptions().Graphics.integerScaling ? SDL_TRUE : SDL_FALSE) < 0) { if (SDL_RenderSetIntegerScale(renderer, *GetOptions().Graphics.integerScaling ? SDL_TRUE : SDL_FALSE) < 0) {
ErrSdl(); ErrSdl();
} }
@ -592,11 +726,16 @@ void ReinitializeRenderer()
if (SDL_RenderSetLogicalSize(renderer, gnScreenWidth, gnScreenHeight) <= -1) { if (SDL_RenderSetLogicalSize(renderer, gnScreenWidth, gnScreenHeight) <= -1) {
ErrSdl(); ErrSdl();
} }
#endif
#ifdef USE_SDL3
RendererTextureSurface = SDLSurfaceUniquePtr { SDL_CreateSurface(gnScreenWidth, gnScreenHeight, texture->format) };
if (RendererTextureSurface == nullptr) ErrSdl();
#else
Uint32 format; Uint32 format;
if (SDL_QueryTexture(texture.get(), &format, nullptr, nullptr, nullptr) < 0) if (SDL_QueryTexture(texture.get(), &format, nullptr, nullptr, nullptr) < 0) ErrSdl();
ErrSdl();
RendererTextureSurface = SDLWrap::CreateRGBSurfaceWithFormat(0, gnScreenWidth, gnScreenHeight, SDL_BITSPERPIXEL(format), format); RendererTextureSurface = SDLWrap::CreateRGBSurfaceWithFormat(0, gnScreenWidth, gnScreenHeight, SDL_BITSPERPIXEL(format), format);
#endif
} else { } else {
Size windowSize = {}; Size windowSize = {};
SDL_GetWindowSize(ghMainWnd, &windowSize.width, &windowSize.height); SDL_GetWindowSize(ghMainWnd, &windowSize.width, &windowSize.height);
@ -623,14 +762,20 @@ void SetFullscreenMode()
if (*GetOptions().Graphics.fullscreen && !*GetOptions().Graphics.upscale) { if (*GetOptions().Graphics.fullscreen && !*GetOptions().Graphics.upscale) {
const Size windowSize = GetPreferredWindowSize(); const Size windowSize = GetPreferredWindowSize();
const SDL_DisplayMode displayMode = GetNearestDisplayMode(windowSize); const SDL_DisplayMode displayMode = GetNearestDisplayMode(windowSize);
if (SDL_SetWindowDisplayMode(ghMainWnd, &displayMode) != 0) { #ifdef USE_SDL3
ErrSdl(); if (!SDL_SetWindowFullscreenMode(ghMainWnd, &displayMode)) ErrSdl();
} #else
if (SDL_SetWindowDisplayMode(ghMainWnd, &displayMode) != 0) ErrSdl();
#endif
} }
Uint32 flags = 0; Uint32 flags = 0;
if (*GetOptions().Graphics.fullscreen) { if (*GetOptions().Graphics.fullscreen) {
#if USE_SDL3
flags = SDL_WINDOW_FULLSCREEN;
#else
flags = *GetOptions().Graphics.upscale ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN; flags = *GetOptions().Graphics.upscale ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN;
#endif
} }
if (SDL_SetWindowFullscreen(ghMainWnd, flags) != 0) { if (SDL_SetWindowFullscreen(ghMainWnd, flags) != 0) {
ErrSdl(); ErrSdl();
@ -666,14 +811,21 @@ void ResizeWindow()
const bool trueFullscreen = *GetOptions().Graphics.fullscreen && !*GetOptions().Graphics.upscale; const bool trueFullscreen = *GetOptions().Graphics.fullscreen && !*GetOptions().Graphics.upscale;
if (trueFullscreen) { if (trueFullscreen) {
const SDL_DisplayMode displayMode = GetNearestDisplayMode(windowSize); const SDL_DisplayMode displayMode = GetNearestDisplayMode(windowSize);
if (SDL_SetWindowDisplayMode(ghMainWnd, &displayMode) != 0) #ifdef USE_SDL3
ErrSdl(); if (!SDL_SetWindowFullscreenMode(ghMainWnd, &displayMode)) ErrSdl();
#else
if (SDL_SetWindowDisplayMode(ghMainWnd, &displayMode) != 0) ErrSdl();
#endif
} }
// Handle switching between "fake fullscreen" and "true fullscreen" when upscale is toggled // Handle switching between "fake fullscreen" and "true fullscreen" when upscale is toggled
const bool upscaleChanged = *GetOptions().Graphics.upscale != (renderer != nullptr); const bool upscaleChanged = *GetOptions().Graphics.upscale != (renderer != nullptr);
if (upscaleChanged && *GetOptions().Graphics.fullscreen) { if (upscaleChanged && *GetOptions().Graphics.fullscreen) {
#ifdef USE_SDL3
const Uint32 flags = SDL_WINDOW_FULLSCREEN;
#else
const Uint32 flags = *GetOptions().Graphics.upscale ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN; const Uint32 flags = *GetOptions().Graphics.upscale ? SDL_WINDOW_FULLSCREEN_DESKTOP : SDL_WINDOW_FULLSCREEN;
#endif
if (SDL_SetWindowFullscreen(ghMainWnd, flags) != 0) if (SDL_SetWindowFullscreen(ghMainWnd, flags) != 0)
ErrSdl(); ErrSdl();
if (!*GetOptions().Graphics.fullscreen) if (!*GetOptions().Graphics.fullscreen)
@ -687,7 +839,11 @@ void ResizeWindow()
ReinitializeRenderer(); ReinitializeRenderer();
#ifndef USE_SDL1 #ifndef USE_SDL1
#ifdef USE_SDL3
SDL_SetWindowResizable(ghMainWnd, renderer != nullptr);
#else
SDL_SetWindowResizable(ghMainWnd, renderer != nullptr ? SDL_TRUE : SDL_FALSE); SDL_SetWindowResizable(ghMainWnd, renderer != nullptr ? SDL_TRUE : SDL_FALSE);
#endif
InitializeVirtualGamepad(); InitializeVirtualGamepad();
#endif #endif

35
Source/utils/display.h

@ -3,12 +3,19 @@
#include <cstdint> #include <cstdint>
#include <type_traits> #include <type_traits>
#ifdef USE_SDL3
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_render.h>
#include <SDL3/SDL_surface.h>
#include <SDL3/SDL_video.h>
#else
#include <SDL.h> #include <SDL.h>
#ifdef USE_SDL1 #ifdef USE_SDL1
#include "utils/sdl2_to_1_2_backports.h" #include "utils/sdl2_to_1_2_backports.h"
#else #else
#include "utils/sdl2_backports.h" #include "utils/sdl2_backports.h"
#endif #endif
#endif
#include "utils/attributes.h" #include "utils/attributes.h"
#include "utils/sdl_ptrs.h" #include "utils/sdl_ptrs.h"
@ -62,14 +69,22 @@ void OutputToLogical(T *x, T *y)
return; return;
float scaleX; float scaleX;
SDL_RenderGetScale(renderer, &scaleX, NULL); #ifdef USE_SDL3
SDL_GetRenderScale(renderer, &scaleX, nullptr);
#else
SDL_RenderGetScale(renderer, &scaleX, nullptr);
#endif
float scaleDpi = GetDpiScalingFactor(); float scaleDpi = GetDpiScalingFactor();
float scale = scaleX / scaleDpi; float scale = scaleX / scaleDpi;
*x = static_cast<T>(*x / scale); *x = static_cast<T>(*x / scale);
*y = static_cast<T>(*y / scale); *y = static_cast<T>(*y / scale);
SDL_Rect view; SDL_Rect view;
#ifdef USE_SDL3
SDL_GetRenderViewport(renderer, &view);
#else
SDL_RenderGetViewport(renderer, &view); SDL_RenderGetViewport(renderer, &view);
#endif
*x -= view.x; *x -= view.x;
*y -= view.y; *y -= view.y;
#else #else
@ -90,12 +105,20 @@ void LogicalToOutput(T *x, T *y)
if (!renderer) if (!renderer)
return; return;
SDL_Rect view; SDL_Rect view;
#ifdef USE_SDL3
SDL_GetRenderViewport(renderer, &view);
#else
SDL_RenderGetViewport(renderer, &view); SDL_RenderGetViewport(renderer, &view);
#endif
*x += view.x; *x += view.x;
*y += view.y; *y += view.y;
float scaleX; float scaleX;
SDL_RenderGetScale(renderer, &scaleX, NULL); #ifdef USE_SDL3
SDL_GetRenderScale(renderer, &scaleX, nullptr);
#else
SDL_RenderGetScale(renderer, &scaleX, nullptr);
#endif
float scaleDpi = GetDpiScalingFactor(); float scaleDpi = GetDpiScalingFactor();
float scale = scaleX / scaleDpi; float scale = scaleX / scaleDpi;
*x = static_cast<T>(*x * scale); *x = static_cast<T>(*x * scale);
@ -110,7 +133,13 @@ void LogicalToOutput(T *x, T *y)
} }
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
SDL_DisplayMode GetNearestDisplayMode(Size preferredSize, SDL_PixelFormatEnum preferredPixelFormat = SDL_PIXELFORMAT_UNKNOWN); SDL_DisplayMode GetNearestDisplayMode(Size preferredSize,
#ifdef USE_SDL3
SDL_PixelFormat preferredPixelFormat = SDL_PIXELFORMAT_UNKNOWN
#else
SDL_PixelFormatEnum preferredPixelFormat = SDL_PIXELFORMAT_UNKNOWN
#endif
);
#endif #endif
} // namespace devilution } // namespace devilution

16
Source/utils/png.h

@ -1,9 +1,15 @@
#pragma once #pragma once
#ifdef USE_SDL3
#include <SDL3/SDL_iostream.h>
#include <SDL3_image/SDL_image.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include "engine/assets.hpp" #include "engine/assets.hpp"
#ifndef USE_SDL3
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
@ -26,9 +32,11 @@ inline SDL_Surface *IMG_LoadPNG(const char *file)
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif
namespace devilution { namespace devilution {
#ifndef USE_SDL3
inline int InitPNG() inline int InitPNG()
{ {
return IMG_Init(IMG_INIT_PNG); return IMG_Init(IMG_INIT_PNG);
@ -38,12 +46,18 @@ inline void QuitPNG()
{ {
IMG_Quit(); IMG_Quit();
} }
#endif
inline SDL_Surface *LoadPNG(const char *file) inline SDL_Surface *LoadPNG(const char *file)
{ {
SDL_RWops *rwops = OpenAssetAsSdlRwOps(file); auto *rwops = OpenAssetAsSdlRwOps(file);
#ifdef USE_SDL3
SDL_Surface *surface = IMG_LoadPNG_IO(rwops);
SDL_CloseIO(rwops);
#else
SDL_Surface *surface = IMG_LoadPNG_RW(rwops); SDL_Surface *surface = IMG_LoadPNG_RW(rwops);
SDL_RWclose(rwops); SDL_RWclose(rwops);
#endif
return surface; return surface;
} }

30
Source/utils/sdl_bilinear_scale.cpp

@ -1,8 +1,19 @@
#include "utils/sdl_bilinear_scale.hpp" #include "utils/sdl_bilinear_scale.hpp"
#include <cstddef>
#include <cstdint> #include <cstdint>
#include <memory> #include <memory>
#ifdef USE_SDL3
#include <SDL3/SDL_error.h>
#include <SDL3/SDL_rect.h>
#include <SDL3/SDL_surface.h>
#else
#include <SDL.h>
#endif
#include "appfat.h"
// Performs bilinear scaling using fixed-width integer math. // Performs bilinear scaling using fixed-width integer math.
namespace devilution { namespace devilution {
@ -148,16 +159,25 @@ void BilinearScale32(SDL_Surface *src, SDL_Surface *dst)
} }
} }
void BilinearDownscaleByHalf8(const SDL_Surface *src, const Uint8 paletteBlendingTable[256][256], SDL_Surface *dst, uint8_t transparentIndex) void BilinearDownscaleByHalf8(SDL_Surface *src, const uint8_t paletteBlendingTable[256][256], SDL_Surface *dst, uint8_t transparentIndex)
{ {
SDL_Rect srcClipRect, dstClipRect;
#ifdef USE_SDL3
if (!SDL_GetSurfaceClipRect(src, &srcClipRect)) app_fatal(SDL_GetError());
if (!SDL_GetSurfaceClipRect(dst, &dstClipRect)) app_fatal(SDL_GetError());
#else
srcClipRect = src->clip_rect;
dstClipRect = dst->clip_rect;
#endif
const auto *const srcPixelsBegin = static_cast<const uint8_t *>(src->pixels) const auto *const srcPixelsBegin = static_cast<const uint8_t *>(src->pixels)
+ static_cast<size_t>(src->clip_rect.y * src->pitch + src->clip_rect.x); + static_cast<size_t>((srcClipRect.y * src->pitch) + srcClipRect.x);
auto *const dstPixelsBegin = static_cast<uint8_t *>(dst->pixels) auto *const dstPixelsBegin = static_cast<uint8_t *>(dst->pixels)
+ static_cast<size_t>(dst->clip_rect.y * dst->pitch + dst->clip_rect.x); + static_cast<size_t>((dstClipRect.y * dst->pitch) + dstClipRect.x);
for (unsigned y = 0, h = static_cast<unsigned>(dst->clip_rect.h); y < h; ++y) { for (unsigned y = 0, h = static_cast<unsigned>(dstClipRect.h); y < h; ++y) {
const uint8_t *srcPixels = srcPixelsBegin + static_cast<size_t>(2 * y * src->pitch); const uint8_t *srcPixels = srcPixelsBegin + static_cast<size_t>(2 * y * src->pitch);
uint8_t *dstPixels = dstPixelsBegin + static_cast<size_t>(y * dst->pitch); uint8_t *dstPixels = dstPixelsBegin + static_cast<size_t>(y * dst->pitch);
for (unsigned x = 0, w = static_cast<unsigned>(dst->clip_rect.w); x < w; ++x) { for (unsigned x = 0, w = static_cast<unsigned>(dstClipRect.w); x < w; ++x) {
uint8_t quad[] = { uint8_t quad[] = {
srcPixels[0], srcPixels[0],
srcPixels[1], srcPixels[1],

10
Source/utils/sdl_bilinear_scale.hpp

@ -2,12 +2,10 @@
#include <cstdint> #include <cstdint>
#include <SDL_version.h> #ifdef USE_SDL3
#include <SDL3/SDL_surface.h>
#if SDL_VERSION_ATLEAST(2, 0, 0)
#include <SDL_surface.h>
#else #else
#include <SDL_video.h> #include <SDL.h>
#endif #endif
namespace devilution { namespace devilution {
@ -22,6 +20,6 @@ void BilinearScale32(SDL_Surface *src, SDL_Surface *dst);
* @brief Streamlined bilinear downscaling using blended transparency table. * @brief Streamlined bilinear downscaling using blended transparency table.
* Requires `src` and `dst` to have the same pixel format (INDEX8). * Requires `src` and `dst` to have the same pixel format (INDEX8).
*/ */
void BilinearDownscaleByHalf8(const SDL_Surface *src, const Uint8 paletteBlendingTable[256][256], SDL_Surface *dst, uint8_t transparentIndex); void BilinearDownscaleByHalf8(SDL_Surface *src, const uint8_t paletteBlendingTable[256][256], SDL_Surface *dst, uint8_t transparentIndex);
} // namespace devilution } // namespace devilution

64
Source/utils/sdl_compat.h

@ -1,6 +1,13 @@
// Compatibility wrappers for SDL 1 & 2. // Compatibility wrappers for SDL 1 & 2.
#pragma once #pragma once
#ifdef USE_SDL3
#include <SDL3/SDL_keyboard.h>
#include <SDL3/SDL_pixels.h>
#include <SDL3/SDL_surface.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#ifndef USE_SDL1 #ifndef USE_SDL1
#define SDLC_KEYSTATE_LEFTCTRL SDL_SCANCODE_LCTRL #define SDLC_KEYSTATE_LEFTCTRL SDL_SCANCODE_LCTRL
@ -26,49 +33,28 @@
#define SDLC_KEYSTATE_RIGHT SDLK_RIGHT #define SDLC_KEYSTATE_RIGHT SDLK_RIGHT
#endif #endif
inline const Uint8 *SDLC_GetKeyState() #ifdef USE_SDL3
{ inline const bool *SDLC_GetKeyState()
#ifndef USE_SDL1
return SDL_GetKeyboardState(NULL);
#else
return SDL_GetKeyState(NULL);
#endif
}
inline int SDLC_SetColorKey(SDL_Surface *surface, Uint32 key)
{
#ifdef USE_SDL1
return SDL_SetColorKey(surface, SDL_SRCCOLORKEY, key);
#else #else
return SDL_SetColorKey(surface, SDL_TRUE, key); inline const Uint8 *SDLC_GetKeyState()
#endif #endif
}
// Copies the colors into the surface's palette.
inline int SDLC_SetSurfaceColors(SDL_Surface *surface, SDL_Color *colors, int firstcolor, int ncolors)
{ {
#ifdef USE_SDL1 #ifndef USE_SDL1
return SDL_SetPalette(surface, SDL_LOGPAL, colors, firstcolor, ncolors) - 1; return SDL_GetKeyboardState(nullptr);
#else #else
return SDL_SetPaletteColors(surface->format->palette, colors, firstcolor, ncolors); return SDL_GetKeyState(nullptr);
#endif #endif
} }
// Copies the colors into the surface's palette.
inline int SDLC_SetSurfaceColors(SDL_Surface *surface, SDL_Palette *palette)
{
return SDLC_SetSurfaceColors(surface, palette->colors, 0, palette->ncolors);
}
// Sets the palette's colors and: // Sets the palette's colors and:
// SDL2: Points the surface's palette to the given palette if necessary. // SDL3 and SDL2: Points the surface's palette to the given palette if necessary.
// SDL1: Sets the surface's colors. // SDL1: Sets the surface's colors.
inline int SDLC_SetSurfaceAndPaletteColors(SDL_Surface *surface, SDL_Palette *palette, SDL_Color *colors, int firstcolor, int ncolors) inline bool SDLC_SetSurfaceAndPaletteColors(SDL_Surface *surface, SDL_Palette *palette, SDL_Color *colors, int firstcolor, int ncolors)
{ {
#ifdef USE_SDL1 #if defined(USE_SDL1)
if (ncolors > (palette->ncolors - firstcolor)) { if (ncolors > (palette->ncolors - firstcolor)) {
SDL_SetError("ncolors > (palette->ncolors - firstcolor)"); SDL_SetError("ncolors > (palette->ncolors - firstcolor)");
return -1; return false;
} }
if (colors != (palette->colors + firstcolor)) if (colors != (palette->colors + firstcolor))
SDL_memcpy(palette->colors + firstcolor, colors, ncolors * sizeof(*colors)); SDL_memcpy(palette->colors + firstcolor, colors, ncolors * sizeof(*colors));
@ -77,16 +63,22 @@ inline int SDLC_SetSurfaceAndPaletteColors(SDL_Surface *surface, SDL_Palette *pa
// When the video surface is 8bit, we need to set the output palette as well. // When the video surface is 8bit, we need to set the output palette as well.
SDL_Surface *videoSurface = SDL_GetVideoSurface(); SDL_Surface *videoSurface = SDL_GetVideoSurface();
SDL_SetColors(videoSurface, colors, firstcolor, ncolors); SDL_SetColors(videoSurface, colors, firstcolor, ncolors);
if (videoSurface == surface) return 0; if (videoSurface == surface) return true;
#endif #endif
// In SDL1, the surface always has its own distinct palette, so we need to // In SDL1, the surface always has its own distinct palette, so we need to
// update it as well. // update it as well.
return SDL_SetPalette(surface, SDL_LOGPAL, colors, firstcolor, ncolors) - 1; return SDL_SetPalette(surface, SDL_LOGPAL, colors, firstcolor, ncolors) == 0;
#else // !USE_SDL1 #elif defined(USE_SDL3)
if (!SDL_SetPaletteColors(palette, colors, firstcolor, ncolors)) return false;
if (SDL_GetSurfacePalette(surface) != palette) {
if (!SDL_SetSurfacePalette(surface, palette)) return false;
}
return true;
#else
if (SDL_SetPaletteColors(palette, colors, firstcolor, ncolors) < 0) if (SDL_SetPaletteColors(palette, colors, firstcolor, ncolors) < 0)
return -1; return false;
if (surface->format->palette != palette) if (surface->format->palette != palette)
return SDL_SetSurfacePalette(surface, palette); return SDL_SetSurfacePalette(surface, palette);
return 0; return true;
#endif #endif
} }

45
Source/utils/sdl_mutex.h

@ -2,8 +2,13 @@
#include <memory> #include <memory>
#ifdef USE_SDL3
#include <SDL3/SDL_mutex.h>
#include <SDL3/SDL_version.h>
#else
#include <SDL_mutex.h> #include <SDL_mutex.h>
#include <SDL_version.h> #include <SDL_version.h>
#endif
#include "appfat.h" #include "appfat.h"
@ -51,35 +56,49 @@ public:
void lock() noexcept // NOLINT(readability-identifier-naming) void lock() noexcept // NOLINT(readability-identifier-naming)
{ {
#ifdef USE_SDL3
SDL_LockMutex(mutex_);
#else
int err = SDL_LockMutex(mutex_); int err = SDL_LockMutex(mutex_);
if (err == -1) if (err == -1) ErrSdl();
ErrSdl(); #endif
} }
#if SDL_VERSION_ATLEAST(2, 0, 0) #if SDL_VERSION_ATLEAST(2, 0, 0)
bool try_lock() noexcept // NOLINT(readability-identifier-naming) [[nodiscard]] bool try_lock() noexcept // NOLINT(readability-identifier-naming)
{ {
int err = SDL_TryLockMutex(mutex_); const bool ok =
if (err == -1) #ifdef USE_SDL3
ErrSdl(); SDL_TryLockMutex(mutex_);
return err == 0; #else
SDL_TryLockMutex(mutex_) == 0;
#endif
return ok;
} }
#endif #endif
void unlock() noexcept // NOLINT(readability-identifier-naming) void unlock() noexcept // NOLINT(readability-identifier-naming)
{ {
#ifdef USE_SDL3
SDL_UnlockMutex(mutex_);
#else
int err = SDL_UnlockMutex(mutex_); int err = SDL_UnlockMutex(mutex_);
if (err == -1) if (err == -1) ErrSdl();
ErrSdl(); #endif
} }
SDL_mutex *get() #ifdef USE_SDL3
{ SDL_Mutex *get() { return mutex_; }
return mutex_; #else
} SDL_mutex *get() { return mutex_; }
#endif
private: private:
#ifdef USE_SDL3
SDL_Mutex *mutex_;
#else
SDL_mutex *mutex_; SDL_mutex *mutex_;
#endif
}; };
#endif #endif

5
test/palette_blending_benchmark.cpp

@ -3,7 +3,12 @@
#include <array> #include <array>
#include <cstdint> #include <cstdint>
#ifdef USE_SDL3
#include <SDL3/SDL_pixels.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include <benchmark/benchmark.h> #include <benchmark/benchmark.h>
#include "utils/palette_kd_tree.hpp" #include "utils/palette_kd_tree.hpp"

5
test/palette_blending_test.cpp

@ -4,7 +4,12 @@
#include <array> #include <array>
#include <iostream> #include <iostream>
#ifdef USE_SDL3
#include <SDL3/SDL_pixels.h>
#else
#include <SDL.h> #include <SDL.h>
#endif
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>

Loading…
Cancel
Save