Browse Source

update SDL3 to libsdl-org/SDL@038a380 (3.3 development)

Sasha Szpakowski 5 months ago
parent
commit
ab332aa6ef
100 changed files with 3098 additions and 545 deletions
  1. 102 0
      libs/SDL3/.github/actions/setup-ngage-sdk/action.yml
  2. 23 3
      libs/SDL3/.github/workflows/create-test-plan.py
  3. 5 0
      libs/SDL3/.github/workflows/generic.yml
  4. 3 0
      libs/SDL3/.github/workflows/release.yml
  5. 2 1
      libs/SDL3/.wikiheaders-options
  6. 1 0
      libs/SDL3/Android.mk
  7. 113 12
      libs/SDL3/CMakeLists.txt
  8. 13 5
      libs/SDL3/VisualC-GDK/SDL/SDL.vcxproj
  9. 11 3
      libs/SDL3/VisualC-GDK/SDL/SDL.vcxproj.filters
  10. 18 29
      libs/SDL3/VisualC-GDK/tests/testgdk/src/testgdk.cpp
  11. 73 1
      libs/SDL3/VisualC/SDL.sln
  12. 36 3
      libs/SDL3/VisualC/SDL/SDL.vcxproj
  13. 35 12
      libs/SDL3/VisualC/SDL/SDL.vcxproj.filters
  14. 13 0
      libs/SDL3/VisualC/examples/asyncio/01-load-bitmaps/01-load-bitmaps.vcxproj
  15. 13 0
      libs/SDL3/VisualC/examples/audio/04-multiple-streams/04-multiple-streams.vcxproj
  16. 13 0
      libs/SDL3/VisualC/examples/demo/04-bytepusher/04-bytepusher.vcxproj
  17. 2 1
      libs/SDL3/VisualC/examples/generate.py
  18. 13 0
      libs/SDL3/VisualC/examples/input/01-joystick-polling/01-joystick-polling.vcxproj
  19. 13 0
      libs/SDL3/VisualC/examples/input/02-joystick-events/02-joystick-events.vcxproj
  20. 13 0
      libs/SDL3/VisualC/examples/renderer/19-affine-textures/19-affine-textures.vcxproj
  21. 2 2
      libs/SDL3/Xcode/SDL/Info-Framework.plist
  22. 42 6
      libs/SDL3/Xcode/SDL/SDL.xcodeproj/project.pbxproj
  23. 1 1
      libs/SDL3/Xcode/SDL/pkg-support/SDL.info
  24. 1 1
      libs/SDL3/Xcode/SDL/pkg-support/share/cmake/SDL3/SDL3Config.cmake
  25. 2 1
      libs/SDL3/android-project/app/proguard-rules.pro
  26. 20 10
      libs/SDL3/android-project/app/src/main/java/org/libsdl/app/HIDDeviceBLESteamController.java
  27. 17 13
      libs/SDL3/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java
  28. 2 2
      libs/SDL3/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java
  29. 6 6
      libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDL.java
  30. 41 2
      libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
  31. 14 14
      libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLAudioManager.java
  32. 66 66
      libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java
  33. 2 2
      libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLDummyEdit.java
  34. 2 2
      libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLInputConnection.java
  35. 8 7
      libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLSurface.java
  36. 4 3
      libs/SDL3/build-scripts/build-release.py
  37. 90 45
      libs/SDL3/build-scripts/wikiheaders.pl
  38. 1 0
      libs/SDL3/cmake/PreseedMSVCCache.cmake
  39. 189 0
      libs/SDL3/cmake/PreseedNokiaNGageCache.cmake
  40. 0 3
      libs/SDL3/cmake/macros.cmake
  41. 38 6
      libs/SDL3/cmake/sdlchecks.cmake
  42. 0 0
      libs/SDL3/cmake/sdlcommands.cmake
  43. 3 3
      libs/SDL3/cmake/sdlcpu.cmake
  44. 2 0
      libs/SDL3/cmake/sdlplatform.cmake
  45. 8 6
      libs/SDL3/cmake/test/CMakeLists.txt
  46. 24 11
      libs/SDL3/cmake/test/main_gui.c
  47. 17 2
      libs/SDL3/cmake/test/sdltest.c
  48. 1 1
      libs/SDL3/docs/README-android.md
  49. 4 4
      libs/SDL3/docs/README-cmake.md
  50. 39 1
      libs/SDL3/docs/README-documentation-rules.md
  51. 2 2
      libs/SDL3/docs/README-emscripten.md
  52. 28 24
      libs/SDL3/docs/README-highdpi.md
  53. 3 2
      libs/SDL3/docs/README-linux.md
  54. 1 1
      libs/SDL3/docs/README-migration.md
  55. 62 3
      libs/SDL3/docs/README-ngage.md
  56. 2 2
      libs/SDL3/docs/README-platforms.md
  57. 2 2
      libs/SDL3/docs/README-psp.md
  58. 30 42
      libs/SDL3/docs/README-versions.md
  59. 9 0
      libs/SDL3/docs/README-wayland.md
  60. 2 0
      libs/SDL3/docs/release_checklist.md
  61. 6 0
      libs/SDL3/examples/CMakeLists.txt
  62. 1 1
      libs/SDL3/examples/audio/04-multiple-streams/README.txt
  63. 1 1
      libs/SDL3/examples/audio/04-multiple-streams/multiple-streams.c
  64. 7 0
      libs/SDL3/examples/audio/05-planar-data/README.txt
  65. BIN
      libs/SDL3/examples/audio/05-planar-data/onmouseover.webp
  66. 366 0
      libs/SDL3/examples/audio/05-planar-data/planar-data.c
  67. BIN
      libs/SDL3/examples/audio/05-planar-data/thumbnail.png
  68. 47 1
      libs/SDL3/examples/demo/01-snake/snake.c
  69. 11 12
      libs/SDL3/examples/demo/04-bytepusher/bytepusher.c
  70. 1 1
      libs/SDL3/examples/input/01-joystick-polling/joystick-polling.c
  71. 3 0
      libs/SDL3/examples/renderer/19-affine-textures/README.txt
  72. 145 0
      libs/SDL3/examples/renderer/19-affine-textures/affine-textures.c
  73. BIN
      libs/SDL3/examples/renderer/19-affine-textures/onmouseover.webp
  74. BIN
      libs/SDL3/examples/renderer/19-affine-textures/thumbnail.png
  75. 1 1
      libs/SDL3/include/SDL3/SDL.h
  76. 1 1
      libs/SDL3/include/SDL3/SDL_assert.h
  77. 219 9
      libs/SDL3/include/SDL3/SDL_audio.h
  78. 70 3
      libs/SDL3/include/SDL3/SDL_begin_code.h
  79. 37 2
      libs/SDL3/include/SDL3/SDL_events.h
  80. 2 2
      libs/SDL3/include/SDL3/SDL_filesystem.h
  81. 8 4
      libs/SDL3/include/SDL3/SDL_gamepad.h
  82. 285 48
      libs/SDL3/include/SDL3/SDL_gpu.h
  83. 46 26
      libs/SDL3/include/SDL3/SDL_haptic.h
  84. 97 7
      libs/SDL3/include/SDL3/SDL_hints.h
  85. 2 2
      libs/SDL3/include/SDL3/SDL_init.h
  86. 12 12
      libs/SDL3/include/SDL3/SDL_iostream.h
  87. 4 0
      libs/SDL3/include/SDL3/SDL_joystick.h
  88. 3 0
      libs/SDL3/include/SDL3/SDL_log.h
  89. 10 10
      libs/SDL3/include/SDL3/SDL_main.h
  90. 67 9
      libs/SDL3/include/SDL3/SDL_mouse.h
  91. 1 1
      libs/SDL3/include/SDL3/SDL_mutex.h
  92. 5 5
      libs/SDL3/include/SDL3/SDL_pixels.h
  93. 12 1
      libs/SDL3/include/SDL3/SDL_platform_defines.h
  94. 11 0
      libs/SDL3/include/SDL3/SDL_process.h
  95. 1 1
      libs/SDL3/include/SDL3/SDL_rect.h
  96. 293 4
      libs/SDL3/include/SDL3/SDL_render.h
  97. 7 3
      libs/SDL3/include/SDL3/SDL_stdinc.h
  98. 4 0
      libs/SDL3/include/SDL3/SDL_storage.h
  99. 8 8
      libs/SDL3/include/SDL3/SDL_surface.h
  100. 2 2
      libs/SDL3/include/SDL3/SDL_system.h

+ 102 - 0
libs/SDL3/.github/actions/setup-ngage-sdk/action.yml

@@ -0,0 +1,102 @@
+name: 'Setup Nonka N-Gage SDK'
+description: 'Download and setup Nokia N-Gage SDK'
+inputs:
+  path:
+    description: 'Installation path'
+    default: 'default'
+runs:
+  using: 'composite'
+  steps:
+    - uses: actions/setup-python@v5
+      with:
+        python-version: '3.x'
+    - name: 'Verify platform'
+      id: calc
+      shell: sh
+      run: |
+        case "${{ runner.os }}-${{ runner.arch }}" in
+          "Windows-X86" | "Windows-X64")
+            echo "ok!"
+            echo "cache-key=ngage-sdk-windows" >> ${GITHUB_OUTPUT}
+            default_install_path="C:/ngagesdk"
+            ;;
+          *)
+            echo "Unsupported ${{ runner.os }}-${{ runner.arch }}"
+            exit 1;
+            ;;
+        esac
+        install_path="${{ inputs.path }}"
+        if [ "x$install_path" = "xdefault" ]; then
+          install_path="$default_install_path"
+        fi
+        echo "install-path=$install_path" >> ${GITHUB_OUTPUT}
+
+        toolchain_repo="https://github.com/ngagesdk/ngage-toolchain"
+        toolchain_branch="main"
+        echo "toolchain-repo=${toolchain_repo}"     >> ${GITHUB_OUTPUT}
+        echo "toolchain-branch=${toolchain_branch}" >> ${GITHUB_OUTPUT}
+
+        sdk_repo="https://github.com/ngagesdk/sdk"
+        sdk_branch="main"
+        echo "sdk-repo=${sdk_repo}"       >> ${GITHUB_OUTPUT}
+        echo "sdk-branch=${sdk_branch}"   >> ${GITHUB_OUTPUT}
+
+        tools_repo="https://github.com/ngagesdk/tools"
+        tools_branch="main"
+        echo "tools-repo=${tools_repo}"       >> ${GITHUB_OUTPUT}
+        echo "tools-branch=${tools_branch}"   >> ${GITHUB_OUTPUT}
+
+        extras_repo="https://github.com/ngagesdk/extras"
+        extras_branch="main"
+        echo "extras-repo=${extras_repo}"       >> ${GITHUB_OUTPUT}
+        echo "extras-branch=${extras_branch}"   >> ${GITHUB_OUTPUT}
+#    - name: 'Restore cached ${{ steps.calc.outputs.archive }}'
+#      id: cache-restore
+#      uses: actions/cache/restore@v4
+#      with:
+#        path: '${{ runner.temp }}'
+#        key: ${{ steps.calc.outputs.cache-key }}
+    - name: 'Download N-Gage SDK'
+#      if: ${{ !steps.cache-restore.outputs.cache-hit || steps.cache-restore.outputs.cache-hit == 'false' }}
+      shell: pwsh
+      run: |
+
+        Invoke-WebRequest "${{ steps.calc.outputs.toolchain-repo }}/archive/refs/heads/${{ steps.calc.outputs.toolchain-branch }}.zip"  -OutFile "${{ runner.temp }}/ngage-toolchain.zip"
+        Invoke-WebRequest "${{ steps.calc.outputs.sdk-repo }}/archive/refs/heads/${{ steps.calc.outputs.sdk-branch }}.zip"              -OutFile "${{ runner.temp }}/sdk.zip"
+        Invoke-WebRequest "${{ steps.calc.outputs.tools-repo }}/archive/refs/heads/${{ steps.calc.outputs.tools-branch }}.zip"          -OutFile "${{ runner.temp }}/tools.zip"
+        Invoke-WebRequest "${{ steps.calc.outputs.extras-repo }}/archive/refs/heads/${{ steps.calc.outputs.extras-branch }}.zip"        -OutFile "${{ runner.temp }}/extras.zip"
+
+#    - name: 'Cache ${{ steps.calc.outputs.archive }}'
+#      if: ${{ !steps.cache-restore.outputs.cache-hit || steps.cache-restore.outputs.cache-hit == 'false' }}
+#      uses: actions/cache/save@v4
+#      with:
+#        path: |
+#          ${{ runner.temp }}/apps.zip
+#          ${{ runner.temp }}/sdk.zip
+#          ${{ runner.temp }}/tools.zip
+#        key: ${{ steps.calc.outputs.cache-key }}
+    - name: 'Extract N-Gage SDK'
+      shell: pwsh
+      run: |
+        New-Item -ItemType Directory -Path "${{ steps.calc.outputs.install-path }}" -Force
+
+        New-Item -ItemType Directory -Path "${{ runner.temp }}/ngage-toolchain-temp" -Force 
+        7z "-o${{ runner.temp }}/ngage-toolchain-temp"      x "${{ runner.temp }}/ngage-toolchain.zip"
+        Move-Item -Path "${{ runner.temp }}/ngage-toolchain-temp/ngage-toolchain-${{ steps.calc.outputs.toolchain-branch }}/*" -Destination "${{ steps.calc.outputs.install-path }}"
+
+        7z "-o${{ steps.calc.outputs.install-path }}/sdk"   x "${{ runner.temp }}/sdk.zip"
+        Move-Item -Path "${{ steps.calc.outputs.install-path }}/sdk/sdk-${{ steps.calc.outputs.sdk-branch }}"       -Destination "${{ steps.calc.outputs.install-path }}/sdk/sdk"
+
+        7z "-o${{ steps.calc.outputs.install-path }}/sdk"   x "${{ runner.temp }}/tools.zip"
+        Move-Item -Path "${{ steps.calc.outputs.install-path }}/sdk/tools-${{ steps.calc.outputs.tools-branch }}"   -Destination "${{ steps.calc.outputs.install-path }}/sdk/tools"
+
+        7z "-o${{ steps.calc.outputs.install-path }}/sdk"   x "${{ runner.temp }}/extras.zip"
+        Move-Item -Path "${{ steps.calc.outputs.install-path }}/sdk/extras-${{ steps.calc.outputs.extras-branch }}" -Destination "${{ steps.calc.outputs.install-path }}/sdk/extras"
+    - name: 'Set output variables'
+      id: final
+      shell: sh
+      run: |
+        echo "${{ steps.calc.outputs.install-path }}/sdk/sdk/6.1/Shared/EPOC32/gcc/bin" >> $GITHUB_PATH
+        echo "${{ steps.calc.outputs.install-path }}/sdk/sdk/6.1/Shared/EPOC32/ngagesdk/bin" >> $GITHUB_PATH
+        echo "NGAGESDK=${{ steps.calc.outputs.install-path }}" >> $GITHUB_ENV
+        echo "CMAKE_TOOLCHAIN_FILE=${{ steps.calc.outputs.install-path }}/cmake/ngage-toolchain.cmake" >> $GITHUB_ENV

+ 23 - 3
libs/SDL3/.github/workflows/create-test-plan.py

@@ -54,6 +54,7 @@ class SdlPlatform(Enum):
     Riscos = "riscos"
     FreeBSD = "freebsd"
     NetBSD = "netbsd"
+    NGage = "ngage"
 
 
 class Msys2Platform(Enum):
@@ -113,7 +114,8 @@ JOB_SPECS = {
     "msvc-gdk-x64": JobSpec(name="GDK (MSVC, x64)",                         os=JobOs.WindowsLatest,     platform=SdlPlatform.Msvc,        artifact="SDL-VC-GDK",             msvc_arch=MsvcArch.X64,   msvc_project="VisualC-GDK/SDL.sln", gdk=True, no_cmake=True, ),
     "ubuntu-22.04": JobSpec(name="Ubuntu 22.04",                            os=JobOs.Ubuntu22_04,       platform=SdlPlatform.Linux,       artifact="SDL-ubuntu22.04", ),
     "ubuntu-24.04-arm64": JobSpec(name="Ubuntu 24.04 (ARM64)",              os=JobOs.Ubuntu24_04_arm,   platform=SdlPlatform.Linux,       artifact="SDL-ubuntu24.04-arm64", ),
-    "steamrt-sniper": JobSpec(name="Steam Linux Runtime (Sniper)",          os=JobOs.UbuntuLatest,      platform=SdlPlatform.Linux,       artifact="SDL-slrsniper",          container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk:beta", ),
+    "steamrt3": JobSpec(name="Steam Linux Runtime 3.0 (x86_64)",            os=JobOs.UbuntuLatest,      platform=SdlPlatform.Linux,       artifact="SDL-steamrt3",           container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk:latest", ),
+    "steamrt3-arm64": JobSpec(name="Steam Linux Runtime 3.0 (arm64)",       os=JobOs.Ubuntu24_04_arm,   platform=SdlPlatform.Linux,       artifact="SDL-steamrt3-arm64",     container="registry.gitlab.steamos.cloud/steamrt/sniper/sdk/arm64:latest", ),
     "ubuntu-intel-icx": JobSpec(name="Ubuntu 22.04 (Intel oneAPI)",         os=JobOs.Ubuntu22_04,       platform=SdlPlatform.Linux,       artifact="SDL-ubuntu22.04-oneapi", intel=IntelCompiler.Icx, ),
     "ubuntu-intel-icc": JobSpec(name="Ubuntu 22.04 (Intel Compiler)",       os=JobOs.Ubuntu22_04,       platform=SdlPlatform.Linux,       artifact="SDL-ubuntu22.04-icc",    intel=IntelCompiler.Icc, ),
     "macos-framework-x64":  JobSpec(name="MacOS (Framework) (x64)",         os=JobOs.Macos13,           platform=SdlPlatform.MacOS,       artifact="SDL-macos-framework",    apple_framework=True,  apple_archs={AppleArch.Aarch64, AppleArch.X86_64, }, xcode=True, ),
@@ -138,11 +140,12 @@ JOB_SPECS = {
     "riscos": JobSpec(name="RISC OS",                                       os=JobOs.UbuntuLatest,      platform=SdlPlatform.Riscos,      artifact="SDL-riscos",             container="riscosdotinfo/riscos-gccsdk-4.7:latest", ),
     "netbsd": JobSpec(name="NetBSD",                                        os=JobOs.UbuntuLatest,      platform=SdlPlatform.NetBSD,      artifact="SDL-netbsd-x64", ),
     "freebsd": JobSpec(name="FreeBSD",                                      os=JobOs.UbuntuLatest,      platform=SdlPlatform.FreeBSD,     artifact="SDL-freebsd-x64", ),
+    "ngage": JobSpec(name="N-Gage",                                         os=JobOs.WindowsLatest,     platform=SdlPlatform.NGage,       artifact="SDL-ngage", ),
 }
 
 
 class StaticLibType(Enum):
-    MSVC = "SDL3-static.lib"
+    STATIC_LIB = "SDL3-static.lib"
     A = "libSDL3.a"
 
 
@@ -222,6 +225,7 @@ class JobDetails:
     check_sources: bool = False
     setup_python: bool = False
     pypi_packages: list[str] = dataclasses.field(default_factory=list)
+    setup_gage_sdk_path: str = ""
 
     def to_workflow(self, enable_artifacts: bool) -> dict[str, str|bool]:
         data = {
@@ -289,6 +293,7 @@ class JobDetails:
             "check-sources": self.check_sources,
             "setup-python": self.setup_python,
             "pypi-packages": my_shlex_join(self.pypi_packages),
+            "setup-ngage-sdk-path": self.setup_gage_sdk_path,
         }
         return {k: v for k, v in data.items() if v != ""}
 
@@ -364,7 +369,7 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
             job.msvc_project_flags.append("-p:TreatWarningsAsError=true")
             job.test_pkg_config = False
             job.shared_lib = SharedLibType.WIN32
-            job.static_lib = StaticLibType.MSVC
+            job.static_lib = StaticLibType.STATIC_LIB
             job.cmake_arguments.extend((
                 "-DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=ProgramDatabase",
                 "-DCMAKE_EXE_LINKER_FLAGS=-DEBUG",
@@ -381,9 +386,11 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
                 match spec.msvc_arch:
                     case MsvcArch.X86:
                         job.cflags.append("/clang:-m32")
+                        job.cxxflags.append("/clang:-m32")
                         job.ldflags.append("/MACHINE:X86")
                     case MsvcArch.X64:
                         job.cflags.append("/clang:-m64")
+                        job.cxxflags.append("/clang:-m64")
                         job.ldflags.append("/MACHINE:X64")
                     case _:
                         raise ValueError(f"Unsupported clang-cl architecture (arch={spec.msvc_arch})")
@@ -737,6 +744,19 @@ def spec_to_job(spec: JobSpec, key: str, trackmem_symbol_names: bool) -> JobDeta
                     job.cpactions_arch = "x86-64"
                     job.cpactions_setup_cmd = "export PATH=\"/usr/pkg/sbin:/usr/pkg/bin:/sbin:$PATH\"; export PKG_CONFIG_PATH=\"/usr/pkg/lib/pkgconfig\";export PKG_PATH=\"https://cdn.netBSD.org/pub/pkgsrc/packages/NetBSD/$(uname -p)/$(uname -r|cut -f \"1 2\" -d.)/All/\";echo \"PKG_PATH=$PKG_PATH\";echo \"uname -a -> \"$(uname -a)\"\";sudo -E sysctl -w security.pax.aslr.enabled=0;sudo -E sysctl -w security.pax.aslr.global=0;sudo -E pkgin clean;sudo -E pkgin update"
                     job.cpactions_install_cmd = "sudo -E pkgin -y install cmake dbus pkgconf ninja-build pulseaudio libxkbcommon wayland wayland-protocols libinotify libusb1"
+        case SdlPlatform.NGage:
+            build_parallel = False
+            job.cmake_build_type = "Release"
+            job.setup_ninja = True
+            job.static_lib = StaticLibType.STATIC_LIB
+            job.shared_lib = None
+            job.clang_tidy = False
+            job.werror = False  # FIXME: enable SDL_WERROR
+            job.shared = False
+            job.run_tests = False
+            job.setup_gage_sdk_path = "C:/ngagesdk"
+            job.cmake_toolchain_file = "C:/ngagesdk/cmake/ngage-toolchain.cmake"
+            job.test_pkg_config = False
         case _:
             raise ValueError(f"Unsupported platform={spec.platform}")
 

+ 5 - 0
libs/SDL3/.github/workflows/generic.yml

@@ -93,6 +93,11 @@ jobs:
         with:
           arch: ${{ matrix.platform.msvc-vcvars-arch }}
           sdk: ${{ matrix.platform.msvc-vcvars-sdk }}
+      - name: 'Set up Nokia N-Gage SDK'
+        uses: ./.github/actions/setup-ngage-sdk
+        if: ${{ matrix.platform.setup-ngage-sdk-path != '' }}
+        with:
+          path: '${{ matrix.platform.setup-ngage-sdk-path }}'
       - name: 'Set up Windows GDK Desktop'
         uses: ./.github/actions/setup-gdk-desktop
         if: ${{ matrix.platform.setup-gdk-folder != '' }}

+ 3 - 0
libs/SDL3/.github/workflows/release.yml

@@ -532,6 +532,7 @@ jobs:
         with:
           sparse-checkout: 'build-scripts/build-release.py'
       - name: 'Setup Android NDK'
+        id: setup-ndk
         uses: nttld/setup-ndk@v1
         with:
           local-cache: true
@@ -561,6 +562,8 @@ jobs:
         run: |
           python build-scripts/build-release.py \
             --actions android \
+            --android-api 23 \
+            --android-ndk-home "${{ steps.setup-ndk.outputs.ndk-path }}" \
             --commit ${{ inputs.commit }} \
             --root "${{ steps.tar.outputs.path }}" \
             --github \

+ 2 - 1
libs/SDL3/.wikiheaders-options

@@ -9,6 +9,7 @@ versionfname = include/SDL3/SDL_version.h
 versionmajorregex = \A\#define\s+SDL_MAJOR_VERSION\s+(\d+)\Z
 versionminorregex = \A\#define\s+SDL_MINOR_VERSION\s+(\d+)\Z
 versionmicroregex = \A\#define\s+SDL_MICRO_VERSION\s+(\d+)\Z
+apipropertyregex = \A\s*\#\s*define\s+SDL_PROP_
 selectheaderregex = \ASDL.*?\.h\Z
 projecturl = https://libsdl.org/
 wikiurl = https://wiki.libsdl.org
@@ -25,7 +26,7 @@ manpagesymbolfilterregex = \A[US]int\d+\Z
 headercategoryeval = s/\ASDL_test_?.*?\.h\Z//; s/\ASDL_?(.*?)\.h\Z/$1/; ucfirst();
 
 quickrefenabled = 1
-quickrefcategoryorder = Init,Hints,Error,Version,Properties,Log,Video,Events,Keyboard,Mouse,Touch,Gamepad,Joystick,Haptic,Audio,Time,Timer,Render,SharedObject,Thread,Mutex,Atomic,Filesystem,IOStream,AsyncIO,Storage,Pixels,Surface,Blendmode,Rect,Camera,Clipboard,Dialog,GPU,Messagebox,Vulkan,Metal,Platform,Power,Sensor,Process,Bits,Endian,Assert,CPUInfo,Intrinsics,Locale,System,Misc,GUID,Main,Stdinc
+quickrefcategoryorder = Init,Hints,Error,Version,Properties,Log,Video,Events,Keyboard,Mouse,Touch,Gamepad,Joystick,Haptic,Audio,Time,Timer,Render,SharedObject,Thread,Mutex,Atomic,Filesystem,IOStream,AsyncIO,Storage,Pixels,Surface,Blendmode,Rect,Camera,Clipboard,Dialog,Tray,Messagebox,GPU,Vulkan,Metal,Platform,Power,Sensor,Process,Bits,Endian,Assert,CPUInfo,Intrinsics,Locale,System,Misc,GUID,Main,Stdinc
 quickreftitle = SDL3 API Quick Reference
 quickrefurl = https://libsdl.org/
 quickrefdesc = The latest version of this document can be found at https://wiki.libsdl.org/SDL3/QuickReference

+ 1 - 0
libs/SDL3/Android.mk

@@ -42,6 +42,7 @@ LOCAL_SRC_FILES := \
 	$(wildcard $(LOCAL_PATH)/src/haptic/*.c) \
 	$(wildcard $(LOCAL_PATH)/src/haptic/android/*.c) \
 	$(wildcard $(LOCAL_PATH)/src/haptic/dummy/*.c) \
+	$(wildcard $(LOCAL_PATH)/src/haptic/hidapi/*.c) \
 	$(wildcard $(LOCAL_PATH)/src/hidapi/*.c) \
 	$(wildcard $(LOCAL_PATH)/src/hidapi/android/*.cpp) \
 	$(wildcard $(LOCAL_PATH)/src/joystick/*.c) \

+ 113 - 12
libs/SDL3/CMakeLists.txt

@@ -5,7 +5,7 @@ if(NOT DEFINED CMAKE_BUILD_TYPE)
 endif()
 
 # See docs/release_checklist.md
-project(SDL3 LANGUAGES C VERSION "3.2.10")
+project(SDL3 LANGUAGES C VERSION "3.3.0")
 
 if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
   set(SDL3_MAINPROJECT ON)
@@ -67,15 +67,16 @@ find_package(PkgConfig)
 list(APPEND CMAKE_MODULE_PATH "${SDL3_SOURCE_DIR}/cmake")
 include("${SDL3_SOURCE_DIR}/cmake/macros.cmake")
 include("${SDL3_SOURCE_DIR}/cmake/sdlchecks.cmake")
+include("${SDL3_SOURCE_DIR}/cmake/sdlcommands.cmake")
 include("${SDL3_SOURCE_DIR}/cmake/sdlcompilers.cmake")
 include("${SDL3_SOURCE_DIR}/cmake/sdlcpu.cmake")
 include("${SDL3_SOURCE_DIR}/cmake/sdlmanpages.cmake")
 include("${SDL3_SOURCE_DIR}/cmake/sdlplatform.cmake")
-include("${SDL3_SOURCE_DIR}/cmake/sdltargets.cmake")
 include("${SDL3_SOURCE_DIR}/cmake/GetGitRevisionDescription.cmake")
 include("${SDL3_SOURCE_DIR}/cmake/3rdparty.cmake")
 include("${SDL3_SOURCE_DIR}/cmake/PreseedMSVCCache.cmake")
 include("${SDL3_SOURCE_DIR}/cmake/PreseedEmscriptenCache.cmake")
+include("${SDL3_SOURCE_DIR}/cmake/PreseedNokiaNGageCache.cmake")
 
 SDL_DetectCompiler()
 SDL_DetectTargetCPUArchitectures(SDL_CPUS)
@@ -155,7 +156,7 @@ endif()
 # The hidraw support doesn't catch Xbox, PS4 and Nintendo controllers,
 #  so we'll just use libusb when it's available. libusb does not support iOS,
 #  so we default to yes on iOS.
-if(IOS OR TVOS OR VISIONOS OR WATCHOS OR ANDROID)
+if(IOS OR TVOS OR VISIONOS OR WATCHOS OR ANDROID OR NGAGE)
   set(SDL_HIDAPI_LIBUSB_AVAILABLE FALSE)
 else()
   set(SDL_HIDAPI_LIBUSB_AVAILABLE TRUE)
@@ -219,7 +220,7 @@ if(EMSCRIPTEN)
   set(SDL_SHARED_AVAILABLE OFF)
 endif()
 
-if(VITA OR PSP OR PS2 OR N3DS OR RISCOS)
+if(VITA OR PSP OR PS2 OR N3DS OR RISCOS OR NGAGE)
   set(SDL_SHARED_AVAILABLE OFF)
 endif()
 
@@ -357,6 +358,7 @@ dep_option(SDL_X11_XRANDR          "Enable Xrandr support" "${SDL_X11_XRANDR_DEF
 dep_option(SDL_X11_XSCRNSAVER      "Enable Xscrnsaver support" ON SDL_X11 OFF)
 dep_option(SDL_X11_XSHAPE          "Enable XShape support" ON SDL_X11 OFF)
 dep_option(SDL_X11_XSYNC           "Enable Xsync support" ON SDL_X11 OFF)
+dep_option(SDL_X11_XTEST           "Enable XTest support" ON SDL_X11 OFF)
 dep_option(SDL_WAYLAND             "Use Wayland video driver" ${UNIX_SYS} "SDL_VIDEO" OFF)
 dep_option(SDL_WAYLAND_SHARED      "Dynamically load Wayland support" ON "SDL_WAYLAND;SDL_DEPS_SHARED" OFF)
 dep_option(SDL_WAYLAND_LIBDECOR    "Use client-side window decorations on Wayland" ON "SDL_WAYLAND" OFF)
@@ -413,6 +415,24 @@ if(VITA)
   set_option(VIDEO_VITA_PVR  "Build with PSVita PVR gles/gles2 support" OFF)
 endif()
 
+if (NGAGE)
+  set(SDL_GPU              OFF)
+  set(SDL_CAMERA           OFF)
+  set(SDL_JOYSTICK         OFF)
+  set(SDL_HAPTIC           OFF)
+  set(SDL_HIDAPI           OFF)
+  set(SDL_POWER            OFF)
+  set(SDL_SENSOR           OFF)
+  set(SDL_DIALOG           OFF)
+  set(SDL_DISKAUDIO        OFF)
+  set(SDL_DUMMYAUDIO       OFF)
+  set(SDL_DUMMYCAMERA      OFF)
+  set(SDL_DUMMYVIDEO       OFF)
+  set(SDL_OFFSCREEN        OFF)
+  set(SDL_RENDER_GPU       OFF)
+  set(SDL_VIRTUAL_JOYSTICK OFF)
+endif()
+
 if(NOT (SDL_SHARED OR SDL_STATIC))
   message(FATAL_ERROR "SDL_SHARED and SDL_STATIC cannot both be disabled")
 endif()
@@ -1103,6 +1123,8 @@ if(SDL_LIBC)
     check_symbol_exists(poll "poll.h" HAVE_POLL)
     check_symbol_exists(memfd_create "sys/mman.h" HAVE_MEMFD_CREATE)
     check_symbol_exists(posix_fallocate "fcntl.h" HAVE_POSIX_FALLOCATE)
+    check_symbol_exists(posix_spawn_file_actions_addchdir "spawn.h" HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR)
+    check_symbol_exists(posix_spawn_file_actions_addchdir_np "spawn.h" HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP)
 
     if(SDL_SYSTEM_ICONV)
       check_c_source_compiles("
@@ -1291,8 +1313,8 @@ if(ANDROID)
   list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake/android")
 
   sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/android/*.c")
-  sdl_sources("${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c")
-  set_property(SOURCE "${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-declaration-after-statement")
+  sdl_sources("${CMAKE_ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c")
+  set_property(SOURCE "${CMAKE_ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c" APPEND_STRING PROPERTY COMPILE_FLAGS " -Wno-declaration-after-statement")
 
   sdl_glob_sources("${SDL3_SOURCE_DIR}/src/misc/android/*.c")
   set(HAVE_SDL_MISC TRUE)
@@ -1546,7 +1568,6 @@ elseif(EMSCRIPTEN)
 
     #enable gles
     if(SDL_OPENGLES)
-      set(SDL_VIDEO_OPENGL_EGL 1)
       set(HAVE_OPENGLES TRUE)
       set(SDL_VIDEO_OPENGL_ES2 1)
       set(SDL_VIDEO_RENDER_OGL_ES2 1)
@@ -1734,6 +1755,7 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
       sdl_sources(
         "${SDL3_SOURCE_DIR}/src/core/linux/SDL_dbus.c"
         "${SDL3_SOURCE_DIR}/src/core/linux/SDL_system_theme.c"
+        "${SDL3_SOURCE_DIR}/src/core/linux/SDL_progressbar.c"
       )
     endif()
 
@@ -1891,11 +1913,13 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
     set (USE_POSIX_SPAWN 1)
   endif()
 elseif(WINDOWS)
+  enable_language(CXX)
   check_c_source_compiles("
     #include <windows.h>
     int main(int argc, char **argv) { return 0; }" HAVE_WIN32_CC)
 
   sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/windows/*.c")
+  sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/windows/*.cpp")
   sdl_glob_sources("${SDL3_SOURCE_DIR}/src/main/windows/*.c")
   sdl_glob_sources("${SDL3_SOURCE_DIR}/src/io/windows/*.c")
 
@@ -1978,6 +2002,7 @@ elseif(WINDOWS)
   check_include_file(audioclient.h HAVE_AUDIOCLIENT_H)
   check_include_file(sensorsapi.h HAVE_SENSORSAPI_H)
   check_include_file(shellscalingapi.h HAVE_SHELLSCALINGAPI_H)
+  check_include_file(shobjidl_core.h HAVE_SHOBJIDL_CORE_H)
   check_c_source_compiles("
     #include <windows.h>
     #include <mfapi.h>
@@ -2005,6 +2030,7 @@ elseif(WINDOWS)
   if(SDL_VIDEO)
     set(SDL_VIDEO_DRIVER_WINDOWS 1)
     sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/windows/*.c")
+    sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/windows/*.cpp")
 
     CheckOpenVR()
 
@@ -2132,7 +2158,7 @@ elseif(WINDOWS)
       set(SDL_JOYSTICK_WGI 1)
     endif()
     if(HAVE_GAMEINPUT_H)
-      sdl_glob_sources("${SDL3_SOURCE_DIR}/src/joystick/gdk/*.c")
+      sdl_glob_sources("${SDL3_SOURCE_DIR}/src/joystick/gdk/*.cpp")
       set(SDL_JOYSTICK_GAMEINPUT 1)
     endif()
     set(HAVE_SDL_JOYSTICK TRUE)
@@ -2924,6 +2950,81 @@ elseif(N3DS)
   set(HAVE_SDL_LOCALE TRUE)
 
   sdl_glob_sources("${SDL3_SOURCE_DIR}/src/io/n3ds/*.c")
+
+elseif(NGAGE)
+
+  enable_language(CXX)
+
+  set(SDL_MAIN_USE_CALLBACKS 1)
+  sdl_glob_sources("${SDL3_SOURCE_DIR}/src/main/ngage/*.c")
+  sdl_glob_sources("${SDL3_SOURCE_DIR}/src/main/ngage/*.cpp")
+  sdl_glob_sources("${SDL3_SOURCE_DIR}/src/core/ngage/*.cpp")
+  set(HAVE_SDL_MAIN_CALLBACKS TRUE)
+
+  if(SDL_AUDIO)
+    set(SDL_AUDIO_DRIVER_NGAGE 1)
+    sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/ngage/*.c")
+    sdl_glob_sources("${SDL3_SOURCE_DIR}/src/audio/ngage/*.cpp")
+    set(HAVE_SDL_AUDIO TRUE)
+  endif()
+
+  set(SDL_FILESYSTEM_NGAGE 1)
+  sdl_glob_sources("${SDL3_SOURCE_DIR}/src/filesystem/ngage/*.c")
+  sdl_glob_sources("${SDL3_SOURCE_DIR}/src/filesystem/ngage/*.cpp")
+  sdl_glob_sources("${SDL3_SOURCE_DIR}/src/filesystem/posix/*.c")
+  set(HAVE_SDL_FILESYSTEM TRUE)
+
+  sdl_glob_sources("${SDL3_SOURCE_DIR}/src/locale/ngage/*.cpp")
+
+  if(SDL_RENDER)
+    set(SDL_VIDEO_RENDER_NGAGE 1)
+    sdl_glob_sources("${SDL3_SOURCE_DIR}/src/render/ngage/*.c")
+  endif()
+
+  sdl_glob_sources("${SDL3_SOURCE_DIR}/src/time/ngage/*.cpp")
+  set(SDL_TIME_NGAGE 1)
+
+  sdl_glob_sources("${SDL3_SOURCE_DIR}/src/render/ngage/*.cpp")
+  sdl_glob_sources("${SDL3_SOURCE_DIR}/src/time/unix/*.c")
+
+  set(SDL_TIMER_NGAGE 1)
+  sdl_glob_sources("${SDL3_SOURCE_DIR}/src/timer/ngage/*.cpp")
+
+  set(SDL_FSOPS_POSIX        1)
+
+  set(SDL_VIDEO_DRIVER_NGAGE 1)
+  sdl_glob_sources("${SDL3_SOURCE_DIR}/src/video/ngage/*.c")
+  set(HAVE_SDL_TIMERS TRUE)
+
+  set_option(SDL_LEAN_AND_MEAN "Enable lean and mean" ON)
+  if(SDL_LEAN_AND_MEAN)
+    sdl_compile_definitions(
+      PRIVATE
+      SDL_LEAN_AND_MEAN
+    )
+  endif()
+
+  sdl_link_dependency(ngage
+    LINK_OPTIONS "SHELL:-s MAIN_COMPAT=0"
+    PKG_CONFIG_LINK_OPTIONS "-s;MAIN_COMPAT=0"
+    LIBS
+      NRenderer
+      3dtypes
+      cone
+      libgcc
+      libgcc_ngage
+      mediaclientaudiostream
+      charconv
+      bitgdi
+      euser
+      estlib
+      ws32
+      hal
+      fbscli
+      efsrv
+      scdv
+      gdi
+  )
 endif()
 
 sdl_sources(${SDL3_SOURCE_DIR}/src/dialog/SDL_dialog.c)
@@ -3017,7 +3118,7 @@ if(SDL_GPU)
     set(SDL_GPU_D3D11 1)
     set(HAVE_SDL_GPU TRUE)
   endif()
-  if(SDL_RENDER_D3D12)
+  if(WINDOWS)
     sdl_glob_sources("${SDL3_SOURCE_DIR}/src/gpu/d3d12/*.c")
     set(SDL_GPU_D3D12 1)
     set(HAVE_SDL_GPU TRUE)
@@ -3104,8 +3205,8 @@ endif()
 
 # We always need to have threads and timers around
 if(NOT HAVE_SDL_THREADS)
-  # The emscripten platform has been carefully vetted to work without threads
-  if(EMSCRIPTEN)
+  # The Emscripten and N-Gage platform has been carefully vetted to work without threads
+  if(EMSCRIPTEN OR NGAGE)
     set(SDL_THREADS_DISABLED 1)
     sdl_glob_sources("${SDL3_SOURCE_DIR}/src/thread/generic/*.c")
   else()
@@ -3288,7 +3389,7 @@ else()
 endif()
 
 if(ANDROID)
-  sdl_include_directories(PRIVATE SYSTEM "${ANDROID_NDK}/sources/android/cpufeatures")
+  sdl_include_directories(PRIVATE SYSTEM "${CMAKE_ANDROID_NDK}/sources/android/cpufeatures")
 endif()
 
 if(APPLE)

+ 13 - 5
libs/SDL3/VisualC-GDK/SDL/SDL.vcxproj

@@ -168,8 +168,8 @@
     </Link>
     <PreBuildEvent>
       <Command>
-        call $(ProjectDir)..\..\src\render\direct3d12\compile_shaders_xbox.bat $(ProjectDir)..\
-        call $(ProjectDir)..\..\src\gpu\d3d12\compile_shaders_xbox.bat $(ProjectDir)..\
+        call "$(ProjectDir)..\..\src\render\direct3d12\compile_shaders_xbox.bat" "$(ProjectDir)..\"
+        call "$(ProjectDir)..\..\src\gpu\d3d12\compile_shaders_xbox.bat" "$(ProjectDir)..\"
       </Command>
     </PreBuildEvent>
     <PreBuildEvent>
@@ -454,8 +454,10 @@
     <ClInclude Include="..\..\src\io\SDL_sysasyncio.h" />
     <ClInclude Include="..\..\src\haptic\SDL_haptic_c.h" />
     <ClInclude Include="..\..\src\haptic\SDL_syshaptic.h" />
+    <ClInclude Include="..\..\src\haptic\SDL_hidapihaptic.h" />
     <ClInclude Include="..\..\src\haptic\windows\SDL_dinputhaptic_c.h" />
     <ClInclude Include="..\..\src\haptic\windows\SDL_windowshaptic_c.h" />
+    <ClInclude Include="..\..\src\haptic\hidapi\SDL_hidapihaptic_c.h" />
     <ClInclude Include="..\..\src\hidapi\hidapi\hidapi.h" />
     <ClInclude Include="..\..\src\hidapi\SDL_hidapi_c.h" />
     <ClInclude Include="..\..\src\joystick\controller_type.h" />
@@ -643,7 +645,7 @@
     <ClCompile Include="..\..\src\audio\SDL_wave.c" />
     <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
     <ClCompile Include="..\..\src\core\SDL_core_unsupported.c" />
-    <ClCompile Include="..\..\src\core\windows\SDL_gameinput.c"/>
+    <ClCompile Include="..\..\src\core\windows\SDL_gameinput.cpp"/>
     <ClCompile Include="..\..\src\core\windows\SDL_hid.c" />
     <ClCompile Include="..\..\src\core\windows\SDL_immdevice.c" />
     <ClCompile Include="..\..\src\core\windows\SDL_windows.c" />
@@ -703,13 +705,18 @@
       <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.Scarlett.x64'">stdcpp17</LanguageStandard>
       <LanguageStandard Condition="'$(Configuration)|$(Platform)'=='Release|Gaming.Xbox.XboxOne.x64'">stdcpp17</LanguageStandard>
     </ClCompile>
+    <ClCompile Include="..\..\src\haptic\hidapi\SDL_hidapihaptic.c" />
+    <ClCompile Include="..\..\src\haptic\hidapi\SDL_hidapihaptic_lg4ff.c" />
     <ClCompile Include="..\..\src\hidapi\SDL_hidapi.c" />
     <ClCompile Include="..\..\src\joystick\controller_type.c" />
     <ClCompile Include="..\..\src\joystick\dummy\SDL_sysjoystick.c" />
-    <ClCompile Include="..\..\src\joystick\gdk\SDL_gameinputjoystick.c" />
+    <ClCompile Include="..\..\src\joystick\gdk\SDL_gameinputjoystick.cpp" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapijoystick.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_8bitdo.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_flydigi.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_combined.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_gamecube.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_gip.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_luna.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_ps3.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_ps4.c" />
@@ -725,6 +732,7 @@
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360w.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xboxone.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_lg4ff.c" />
     <ClCompile Include="..\..\src\joystick\SDL_gamepad.c" />
     <ClCompile Include="..\..\src\joystick\SDL_joystick.c" />
     <ClCompile Include="..\..\src\joystick\SDL_steam_virtual_gamepad.c" />
@@ -885,7 +893,7 @@
     <ClCompile Include="..\..\src\video\windows\SDL_windowsevents.c" />
     <ClCompile Include="..\..\src\video\windows\SDL_windowsframebuffer.c" />
     <ClCompile Include="..\..\src\video\windows\SDL_windowskeyboard.c" />
-    <ClCompile Include="..\..\src\video\windows\SDL_windowsgameinput.c" />
+    <ClCompile Include="..\..\src\video\windows\SDL_windowsgameinput.cpp" />
     <ClCompile Include="..\..\src\video\windows\SDL_windowsmessagebox.c" />
     <ClCompile Include="..\..\src\video\windows\SDL_windowsmodes.c" />
     <ClCompile Include="..\..\src\video\windows\SDL_windowsmouse.c" />

+ 11 - 3
libs/SDL3/VisualC-GDK/SDL/SDL.vcxproj.filters

@@ -27,7 +27,7 @@
     <ClCompile Include="..\..\src\audio\SDL_wave.c" />
     <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
     <ClCompile Include="..\..\src\core\SDL_core_unsupported.c" />
-    <ClCompile Include="..\..\src\core\windows\SDL_gameinput.c" />
+    <ClCompile Include="..\..\src\core\windows\SDL_gameinput.cpp" />
     <ClCompile Include="..\..\src\core\windows\SDL_hid.c" />
     <ClCompile Include="..\..\src\core\windows\SDL_immdevice.c" />
     <ClCompile Include="..\..\src\core\windows\SDL_windows.c" />
@@ -56,13 +56,18 @@
     <ClCompile Include="..\..\src\haptic\SDL_haptic.c" />
     <ClCompile Include="..\..\src\haptic\windows\SDL_dinputhaptic.c" />
     <ClCompile Include="..\..\src\haptic\windows\SDL_windowshaptic.c" />
+    <ClCompile Include="..\..\src\haptic\hidapi\SDL_hidapihaptic.c" />
+    <ClCompile Include="..\..\src\haptic\hidapi\SDL_hidapihaptic_lg4ff.c" />
     <ClCompile Include="..\..\src\hidapi\SDL_hidapi.c" />
     <ClCompile Include="..\..\src\joystick\controller_type.c" />
     <ClCompile Include="..\..\src\joystick\dummy\SDL_sysjoystick.c" />
-    <ClCompile Include="..\..\src\joystick\gdk\SDL_gameinputjoystick.c" />
+    <ClCompile Include="..\..\src\joystick\gdk\SDL_gameinputjoystick.cpp" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapijoystick.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_8bitdo.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_flydigi.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_combined.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_gamecube.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_gip.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_luna.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_ps3.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_ps4.c" />
@@ -78,6 +83,7 @@
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360w.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xboxone.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_lg4ff.c" />
     <ClCompile Include="..\..\src\joystick\SDL_gamepad.c" />
     <ClCompile Include="..\..\src\joystick\SDL_joystick.c" />
     <ClCompile Include="..\..\src\joystick\SDL_steam_virtual_gamepad.c" />
@@ -189,7 +195,7 @@
     <ClCompile Include="..\..\src\video\windows\SDL_windowsevents.c" />
     <ClCompile Include="..\..\src\video\windows\SDL_windowsframebuffer.c" />
     <ClCompile Include="..\..\src\video\windows\SDL_windowskeyboard.c" />
-    <ClCompile Include="..\..\src\video\windows\SDL_windowsgameinput.c" />
+    <ClCompile Include="..\..\src\video\windows\SDL_windowsgameinput.cpp" />
     <ClCompile Include="..\..\src\video\windows\SDL_windowsmessagebox.c" />
     <ClCompile Include="..\..\src\video\windows\SDL_windowsmodes.c" />
     <ClCompile Include="..\..\src\video\windows\SDL_windowsmouse.c" />
@@ -343,8 +349,10 @@
     <ClInclude Include="..\..\src\gpu\SDL_sysgpu.h" />
     <ClInclude Include="..\..\src\haptic\SDL_haptic_c.h" />
     <ClInclude Include="..\..\src\haptic\SDL_syshaptic.h" />
+    <ClInclude Include="..\..\src\haptic\SDL_hidapihaptic.h" />
     <ClInclude Include="..\..\src\haptic\windows\SDL_dinputhaptic_c.h" />
     <ClInclude Include="..\..\src\haptic\windows\SDL_windowshaptic_c.h" />
+    <ClInclude Include="..\..\src\haptic\hidapi\SDL_hidapihaptic_c.h" />
     <ClInclude Include="..\..\src\hidapi\hidapi\hidapi.h" />
     <ClInclude Include="..\..\src\hidapi\SDL_hidapi_c.h" />
     <ClInclude Include="..\..\src\joystick\controller_type.h" />

+ 18 - 29
libs/SDL3/VisualC-GDK/tests/testgdk/src/testgdk.cpp

@@ -56,8 +56,7 @@ static struct
 static SDL_AudioStream *stream;
 
 /* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
-static void
-quit(int rc)
+static void quit(int rc)
 {
     SDL_free(sprites);
     SDL_DestroyAudioStream(stream);
@@ -80,8 +79,7 @@ static int fillerup(void)
     return 0;
 }
 
-void
-UserLoggedIn(XUserHandle user)
+static void UserLoggedIn(XUserHandle user)
 {
     HRESULT hr;
     char gamertag[128];
@@ -96,8 +94,7 @@ UserLoggedIn(XUserHandle user)
     XUserCloseHandle(user);
 }
 
-void
-AddUserUICallback(XAsyncBlock *asyncBlock)
+static void AddUserUICallback(XAsyncBlock *asyncBlock)
 {
     HRESULT hr;
     XUserHandle user = NULL;
@@ -123,8 +120,7 @@ AddUserUICallback(XAsyncBlock *asyncBlock)
     delete asyncBlock;
 }
 
-void
-AddUserUI()
+static void AddUserUI()
 {
     HRESULT hr;
     XAsyncBlock *asyncBlock = new XAsyncBlock;
@@ -141,8 +137,7 @@ AddUserUI()
     }
 }
 
-void
-AddUserSilentCallback(XAsyncBlock *asyncBlock)
+static void AddUserSilentCallback(XAsyncBlock *asyncBlock)
 {
     HRESULT hr;
     XUserHandle user = NULL;
@@ -168,8 +163,7 @@ AddUserSilentCallback(XAsyncBlock *asyncBlock)
     delete asyncBlock;
 }
 
-void
-AddUserSilent()
+static void AddUserSilent()
 {
     HRESULT hr;
     XAsyncBlock *asyncBlock = new XAsyncBlock;
@@ -186,30 +180,27 @@ AddUserSilent()
     }
 }
 
-int
-LoadSprite(const char *file)
+static bool LoadSprite(const char *file)
 {
     int i;
 
     for (i = 0; i < state->num_windows; ++i) {
         /* This does the SDL_LoadBMP step repeatedly, but that's OK for test code. */
-        sprites[i] = LoadTexture(state->renderers[i], file, true, &sprite_w, &sprite_h);
+        sprites[i] = LoadTexture(state->renderers[i], file, true);
         if (!sprites[i]) {
-            return -1;
-        }
-        if (!SDL_SetTextureBlendMode(sprites[i], blendMode)) {
-            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set blend mode: %s", SDL_GetError());
-            SDL_DestroyTexture(sprites[i]);
-            return -1;
+            return false;
         }
+        sprite_w = sprites[i]->w;
+        sprite_h = sprites[i]->h;
+
+        SDL_SetTextureBlendMode(sprites[i], blendMode);
     }
 
     /* We're ready to roll. :) */
-    return 0;
+    return true;
 }
 
-void
-DrawSprites(SDL_Renderer * renderer, SDL_Texture * sprite)
+static void DrawSprites(SDL_Renderer * renderer, SDL_Texture * sprite)
 {
     SDL_Rect viewport;
     SDL_FRect temp;
@@ -300,8 +291,7 @@ DrawSprites(SDL_Renderer * renderer, SDL_Texture * sprite)
     SDL_RenderPresent(renderer);
 }
 
-void
-loop()
+static void loop()
 {
     int i;
     SDL_Event event;
@@ -329,8 +319,7 @@ loop()
     fillerup();
 }
 
-int
-main(int argc, char *argv[])
+int main(int argc, char *argv[])
 {
     int i;
     const char *icon = "icon.bmp";
@@ -413,7 +402,7 @@ main(int argc, char *argv[])
         SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF);
         SDL_RenderClear(renderer);
     }
-    if (LoadSprite(icon) < 0) {
+    if (!LoadSprite(icon)) {
         quit(2);
     }
 

+ 73 - 1
libs/SDL3/VisualC/SDL.sln

@@ -69,7 +69,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "camera", "camera", "{AAEC83
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "01-read-and-draw", "examples\camera\01-read-and-draw\01-read-and-draw.vcxproj", "{510ACF0C-4012-4216-98EF-E4F155DE33CE}"
 EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "game", "game", "{D1BF59F6-22DC-493B-BDEB-451A50DA793D}"
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "demo", "demo", "{D1BF59F6-22DC-493B-BDEB-451A50DA793D}"
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "01-snake", "examples\demo\01-snake\01-snake.vcxproj", "{7820969A-5B7B-4046-BB0A-82905D457FC5}"
 EndProject
@@ -115,6 +115,22 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "02-woodeneye-008", "example
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "03-infinite-monkeys", "examples\demo\03-infinite-monkeys\03-infinite-monkeys.vcxproj", "{75AEE75A-C016-4497-960B-D767B822237D}"
 EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "19-affine-textures", "examples\renderer\19-affine-textures\19-affine-textures.vcxproj", "{E21C50BF-54B4-434C-AA24-9A6469553987}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "04-multiple-streams", "examples\audio\04-multiple-streams\04-multiple-streams.vcxproj", "{7117A55C-BE4E-41DB-A4FC-4070E35A8B28}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "asyncio", "asyncio", "{02EA681E-C7D8-13C7-8484-4AC65E1B71E8}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "input", "input", "{8DEAE483-FDE7-463F-9FD5-F597BBAED1F9}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "01-load-bitmaps", "examples\asyncio\01-load-bitmaps\01-load-bitmaps.vcxproj", "{6A2BFA8B-C027-400D-A18B-3E9E1CC4DDD0}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "04-bytepusher", "examples\demo\04-bytepusher\04-bytepusher.vcxproj", "{3DB9B219-769E-43AC-8B8B-319DB6045DCF}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "01-joystick-polling", "examples\input\01-joystick-polling\01-joystick-polling.vcxproj", "{B3852DB7-E925-4026-8B9D-D2272EFEFF3C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "02-joystick-events", "examples\input\02-joystick-events\02-joystick-events.vcxproj", "{FCBDF2B2-1129-49AE-9406-3F219E65CA89}"
+EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
 		Debug|Win32 = Debug|Win32
@@ -515,6 +531,54 @@ Global
 		{75AEE75A-C016-4497-960B-D767B822237D}.Release|Win32.Build.0 = Release|Win32
 		{75AEE75A-C016-4497-960B-D767B822237D}.Release|x64.ActiveCfg = Release|x64
 		{75AEE75A-C016-4497-960B-D767B822237D}.Release|x64.Build.0 = Release|x64
+		{E21C50BF-54B4-434C-AA24-9A6469553987}.Debug|Win32.ActiveCfg = Debug|Win32
+		{E21C50BF-54B4-434C-AA24-9A6469553987}.Debug|Win32.Build.0 = Debug|Win32
+		{E21C50BF-54B4-434C-AA24-9A6469553987}.Debug|x64.ActiveCfg = Debug|x64
+		{E21C50BF-54B4-434C-AA24-9A6469553987}.Debug|x64.Build.0 = Debug|x64
+		{E21C50BF-54B4-434C-AA24-9A6469553987}.Release|Win32.ActiveCfg = Release|Win32
+		{E21C50BF-54B4-434C-AA24-9A6469553987}.Release|Win32.Build.0 = Release|Win32
+		{E21C50BF-54B4-434C-AA24-9A6469553987}.Release|x64.ActiveCfg = Release|x64
+		{E21C50BF-54B4-434C-AA24-9A6469553987}.Release|x64.Build.0 = Release|x64
+		{7117A55C-BE4E-41DB-A4FC-4070E35A8B28}.Debug|Win32.ActiveCfg = Debug|Win32
+		{7117A55C-BE4E-41DB-A4FC-4070E35A8B28}.Debug|Win32.Build.0 = Debug|Win32
+		{7117A55C-BE4E-41DB-A4FC-4070E35A8B28}.Debug|x64.ActiveCfg = Debug|x64
+		{7117A55C-BE4E-41DB-A4FC-4070E35A8B28}.Debug|x64.Build.0 = Debug|x64
+		{7117A55C-BE4E-41DB-A4FC-4070E35A8B28}.Release|Win32.ActiveCfg = Release|Win32
+		{7117A55C-BE4E-41DB-A4FC-4070E35A8B28}.Release|Win32.Build.0 = Release|Win32
+		{7117A55C-BE4E-41DB-A4FC-4070E35A8B28}.Release|x64.ActiveCfg = Release|x64
+		{7117A55C-BE4E-41DB-A4FC-4070E35A8B28}.Release|x64.Build.0 = Release|x64
+		{6A2BFA8B-C027-400D-A18B-3E9E1CC4DDD0}.Debug|Win32.ActiveCfg = Debug|Win32
+		{6A2BFA8B-C027-400D-A18B-3E9E1CC4DDD0}.Debug|Win32.Build.0 = Debug|Win32
+		{6A2BFA8B-C027-400D-A18B-3E9E1CC4DDD0}.Debug|x64.ActiveCfg = Debug|x64
+		{6A2BFA8B-C027-400D-A18B-3E9E1CC4DDD0}.Debug|x64.Build.0 = Debug|x64
+		{6A2BFA8B-C027-400D-A18B-3E9E1CC4DDD0}.Release|Win32.ActiveCfg = Release|Win32
+		{6A2BFA8B-C027-400D-A18B-3E9E1CC4DDD0}.Release|Win32.Build.0 = Release|Win32
+		{6A2BFA8B-C027-400D-A18B-3E9E1CC4DDD0}.Release|x64.ActiveCfg = Release|x64
+		{6A2BFA8B-C027-400D-A18B-3E9E1CC4DDD0}.Release|x64.Build.0 = Release|x64
+		{3DB9B219-769E-43AC-8B8B-319DB6045DCF}.Debug|Win32.ActiveCfg = Debug|Win32
+		{3DB9B219-769E-43AC-8B8B-319DB6045DCF}.Debug|Win32.Build.0 = Debug|Win32
+		{3DB9B219-769E-43AC-8B8B-319DB6045DCF}.Debug|x64.ActiveCfg = Debug|x64
+		{3DB9B219-769E-43AC-8B8B-319DB6045DCF}.Debug|x64.Build.0 = Debug|x64
+		{3DB9B219-769E-43AC-8B8B-319DB6045DCF}.Release|Win32.ActiveCfg = Release|Win32
+		{3DB9B219-769E-43AC-8B8B-319DB6045DCF}.Release|Win32.Build.0 = Release|Win32
+		{3DB9B219-769E-43AC-8B8B-319DB6045DCF}.Release|x64.ActiveCfg = Release|x64
+		{3DB9B219-769E-43AC-8B8B-319DB6045DCF}.Release|x64.Build.0 = Release|x64
+		{B3852DB7-E925-4026-8B9D-D2272EFEFF3C}.Debug|Win32.ActiveCfg = Debug|Win32
+		{B3852DB7-E925-4026-8B9D-D2272EFEFF3C}.Debug|Win32.Build.0 = Debug|Win32
+		{B3852DB7-E925-4026-8B9D-D2272EFEFF3C}.Debug|x64.ActiveCfg = Debug|x64
+		{B3852DB7-E925-4026-8B9D-D2272EFEFF3C}.Debug|x64.Build.0 = Debug|x64
+		{B3852DB7-E925-4026-8B9D-D2272EFEFF3C}.Release|Win32.ActiveCfg = Release|Win32
+		{B3852DB7-E925-4026-8B9D-D2272EFEFF3C}.Release|Win32.Build.0 = Release|Win32
+		{B3852DB7-E925-4026-8B9D-D2272EFEFF3C}.Release|x64.ActiveCfg = Release|x64
+		{B3852DB7-E925-4026-8B9D-D2272EFEFF3C}.Release|x64.Build.0 = Release|x64
+		{FCBDF2B2-1129-49AE-9406-3F219E65CA89}.Debug|Win32.ActiveCfg = Debug|Win32
+		{FCBDF2B2-1129-49AE-9406-3F219E65CA89}.Debug|Win32.Build.0 = Debug|Win32
+		{FCBDF2B2-1129-49AE-9406-3F219E65CA89}.Debug|x64.ActiveCfg = Debug|x64
+		{FCBDF2B2-1129-49AE-9406-3F219E65CA89}.Debug|x64.Build.0 = Debug|x64
+		{FCBDF2B2-1129-49AE-9406-3F219E65CA89}.Release|Win32.ActiveCfg = Release|Win32
+		{FCBDF2B2-1129-49AE-9406-3F219E65CA89}.Release|Win32.Build.0 = Release|Win32
+		{FCBDF2B2-1129-49AE-9406-3F219E65CA89}.Release|x64.ActiveCfg = Release|x64
+		{FCBDF2B2-1129-49AE-9406-3F219E65CA89}.Release|x64.Build.0 = Release|x64
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
@@ -572,6 +636,14 @@ Global
 		{608C6C67-7766-471F-BBFF-8B00086039AF} = {1B61A1B7-92DE-4C37-9151-D2928D6449AB}
 		{A3F601E0-B54C-4DD8-8A97-FDEF7624EE60} = {D1BF59F6-22DC-493B-BDEB-451A50DA793D}
 		{75AEE75A-C016-4497-960B-D767B822237D} = {D1BF59F6-22DC-493B-BDEB-451A50DA793D}
+		{E21C50BF-54B4-434C-AA24-9A6469553987} = {F91DDAF0-B74F-4516-A1A9-42ED8DFCBF6A}
+		{7117A55C-BE4E-41DB-A4FC-4070E35A8B28} = {1B61A1B7-92DE-4C37-9151-D2928D6449AB}
+		{02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {1498F0CD-F4DA-4847-9CB2-FB18D48061D5}
+		{8DEAE483-FDE7-463F-9FD5-F597BBAED1F9} = {1498F0CD-F4DA-4847-9CB2-FB18D48061D5}
+		{6A2BFA8B-C027-400D-A18B-3E9E1CC4DDD0} = {02EA681E-C7D8-13C7-8484-4AC65E1B71E8}
+		{3DB9B219-769E-43AC-8B8B-319DB6045DCF} = {D1BF59F6-22DC-493B-BDEB-451A50DA793D}
+		{B3852DB7-E925-4026-8B9D-D2272EFEFF3C} = {8DEAE483-FDE7-463F-9FD5-F597BBAED1F9}
+		{FCBDF2B2-1129-49AE-9406-3F219E65CA89} = {8DEAE483-FDE7-463F-9FD5-F597BBAED1F9}
 	EndGlobalSection
 	GlobalSection(ExtensibilityGlobals) = postSolution
 		SolutionGuid = {C320C9F2-1A8F-41D7-B02B-6338F872BCAD}

+ 36 - 3
libs/SDL3/VisualC/SDL/SDL.vcxproj

@@ -367,8 +367,10 @@
     <ClInclude Include="..\..\src\io\SDL_sysasyncio.h" />
     <ClInclude Include="..\..\src\haptic\SDL_haptic_c.h" />
     <ClInclude Include="..\..\src\haptic\SDL_syshaptic.h" />
+    <ClInclude Include="..\..\src\haptic\SDL_hidapihaptic.h" />
     <ClInclude Include="..\..\src\haptic\windows\SDL_dinputhaptic_c.h" />
     <ClInclude Include="..\..\src\haptic\windows\SDL_windowshaptic_c.h" />
+    <ClInclude Include="..\..\src\haptic\hidapi\SDL_hidapihaptic_c.h" />
     <ClInclude Include="..\..\src\hidapi\hidapi\hidapi.h" />
     <ClInclude Include="..\..\src\hidapi\SDL_hidapi_c.h" />
     <ClInclude Include="..\..\src\joystick\controller_type.h" />
@@ -422,6 +424,16 @@
     <ClCompile Include="..\..\src\camera\dummy\SDL_camera_dummy.c" />
     <ClCompile Include="..\..\src\camera\mediafoundation\SDL_camera_mediafoundation.c" />
     <ClCompile Include="..\..\src\camera\SDL_camera.c" />
+    <ClCompile Include="..\..\src\core\windows\pch_cpp.cpp">
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+    </ClCompile>
     <ClCompile Include="..\..\src\dialog\SDL_dialog.c" />
     <ClCompile Include="..\..\src\dialog\SDL_dialog_utils.c" />
     <ClCompile Include="..\..\src\filesystem\SDL_filesystem.c" />
@@ -541,7 +553,12 @@
     <ClCompile Include="..\..\src\audio\SDL_wave.c" />
     <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
     <ClCompile Include="..\..\src\core\SDL_core_unsupported.c" />
-    <ClCompile Include="..\..\src\core\windows\SDL_gameinput.c" />
+    <ClCompile Include="..\..\src\core\windows\SDL_gameinput.cpp">
+      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+    </ClCompile>
     <ClCompile Include="..\..\src\core\windows\SDL_hid.c" />
     <ClCompile Include="..\..\src\core\windows\SDL_immdevice.c" />
     <ClCompile Include="..\..\src\core\windows\SDL_windows.c" />
@@ -573,13 +590,23 @@
     <ClCompile Include="..\..\src\haptic\SDL_haptic.c" />
     <ClCompile Include="..\..\src\haptic\windows\SDL_dinputhaptic.c" />
     <ClCompile Include="..\..\src\haptic\windows\SDL_windowshaptic.c" />
+    <ClCompile Include="..\..\src\haptic\hidapi\SDL_hidapihaptic.c" />
+    <ClCompile Include="..\..\src\haptic\hidapi\SDL_hidapihaptic_lg4ff.c" />
     <ClCompile Include="..\..\src\hidapi\SDL_hidapi.c" />
     <ClCompile Include="..\..\src\joystick\controller_type.c" />
     <ClCompile Include="..\..\src\joystick\dummy\SDL_sysjoystick.c" />
-    <ClCompile Include="..\..\src\joystick\gdk\SDL_gameinputjoystick.c" />
+    <ClCompile Include="..\..\src\joystick\gdk\SDL_gameinputjoystick.cpp">
+      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+    </ClCompile>
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapijoystick.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_8bitdo.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_flydigi.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_combined.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_gamecube.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_gip.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_luna.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_ps3.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_ps4.c" />
@@ -595,6 +622,7 @@
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360w.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xboxone.c" />
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_lg4ff.c" />
     <ClCompile Include="..\..\src\joystick\SDL_gamepad.c" />
     <ClCompile Include="..\..\src\joystick\SDL_joystick.c" />
     <ClCompile Include="..\..\src\joystick\SDL_steam_virtual_gamepad.c" />
@@ -720,7 +748,12 @@
     <ClCompile Include="..\..\src\video\windows\SDL_windowsevents.c" />
     <ClCompile Include="..\..\src\video\windows\SDL_windowsframebuffer.c" />
     <ClCompile Include="..\..\src\video\windows\SDL_windowskeyboard.c" />
-    <ClCompile Include="..\..\src\video\windows\SDL_windowsgameinput.c" />
+    <ClCompile Include="..\..\src\video\windows\SDL_windowsgameinput.cpp">
+      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+      <PrecompiledHeaderOutputFile Condition="'$(Configuration)|$(Platform)'=='Release|x64'">$(IntDir)$(TargetName)_cpp.pch</PrecompiledHeaderOutputFile>
+    </ClCompile>
     <ClCompile Include="..\..\src\video\windows\SDL_windowsmessagebox.c" />
     <ClCompile Include="..\..\src\video\windows\SDL_windowsmodes.c" />
     <ClCompile Include="..\..\src\video\windows\SDL_windowsmouse.c" />

+ 35 - 12
libs/SDL3/VisualC/SDL/SDL.vcxproj.filters

@@ -82,6 +82,9 @@
     <Filter Include="haptic\windows">
       <UniqueIdentifier>{ebc2fca3-3c26-45e3-815e-3e0581d5e226}</UniqueIdentifier>
     </Filter>
+    <Filter Include="haptic\hidapi">
+      <UniqueIdentifier>{06DB01C0-65B5-4DE7-8ADC-C0B0CA3A1E69}</UniqueIdentifier>
+    </Filter>
     <Filter Include="haptic\dummy">
       <UniqueIdentifier>{47c445a2-7014-4e15-9660-7c89a27dddcf}</UniqueIdentifier>
     </Filter>
@@ -534,9 +537,6 @@
     <ClInclude Include="..\..\src\events\SDL_events_c.h">
       <Filter>events</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\src\events\SDL_eventfilter_c.h">
-      <Filter>events</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\src\events\SDL_keyboard_c.h">
       <Filter>events</Filter>
     </ClInclude>
@@ -564,6 +564,9 @@
     <ClInclude Include="..\..\src\haptic\SDL_syshaptic.h">
       <Filter>haptic</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\haptic\SDL_hidapihaptic.h">
+      <Filter>haptic</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\haptic\SDL_haptic_c.h">
       <Filter>haptic</Filter>
     </ClInclude>
@@ -621,6 +624,9 @@
     <ClInclude Include="..\..\src\haptic\windows\SDL_windowshaptic_c.h">
       <Filter>haptic\windows</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\src\haptic\hidapi\SDL_hidapihaptic_c.h">
+      <Filter>haptic\hidapi</Filter>
+    </ClInclude>
     <ClInclude Include="..\..\src\joystick\hidapi\SDL_hidapijoystick_c.h">
       <Filter>joystick\hidapi</Filter>
     </ClInclude>
@@ -953,6 +959,7 @@
     <ClInclude Include="..\..\include\SDL3\SDL_storage.h" />
     <ClInclude Include="..\..\include\SDL3\SDL_time.h" />
     <ClInclude Include="..\..\src\events\SDL_categories_c.h" />
+    <ClInclude Include="..\..\src\events\SDL_eventwatch_c.h" />
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\src\audio\wasapi\SDL_wasapi.c" />
@@ -1040,7 +1047,7 @@
     <ClCompile Include="..\..\src\core\SDL_core_unsupported.c">
       <Filter>core</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\core\windows\SDL_gameinput.c">
+    <ClCompile Include="..\..\src\core\windows\SDL_gameinput.cpp">
       <Filter>core\windows</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\core\windows\SDL_hid.c">
@@ -1079,9 +1086,6 @@
     <ClCompile Include="..\..\src\events\SDL_events.c">
       <Filter>events</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\events\SDL_eventfilter.c">
-      <Filter>events</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\src\events\SDL_keyboard.c">
       <Filter>events</Filter>
     </ClCompile>
@@ -1163,21 +1167,36 @@
     <ClCompile Include="..\..\src\haptic\windows\SDL_windowshaptic.c">
       <Filter>haptic\windows</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\haptic\hidapi\SDL_hidapihaptic.c">
+      <Filter>haptic\hidapi</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\haptic\hidapi\SDL_hidapihaptic_lg4ff.c">
+      <Filter>haptic\hidapi</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\haptic\dummy\SDL_syshaptic.c">
       <Filter>haptic\dummy</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\joystick\dummy\SDL_sysjoystick.c">
       <Filter>joystick\dummy</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\joystick\gdk\SDL_gameinputjoystick.c">
+    <ClCompile Include="..\..\src\joystick\gdk\SDL_gameinputjoystick.cpp">
       <Filter>joystick\gdk</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_8bitdo.c">
+      <Filter>joystick\hidapi</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_flydigi.c">
+      <Filter>joystick\hidapi</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_combined.c">
       <Filter>joystick\hidapi</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_gamecube.c">
       <Filter>joystick\hidapi</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_gip.c">
+      <Filter>joystick\hidapi</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_luna.c">
       <Filter>joystick\hidapi</Filter>
     </ClCompile>
@@ -1223,6 +1242,9 @@
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xboxone.c">
       <Filter>joystick\hidapi</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_lg4ff.c">
+      <Filter>joystick\hidapi</Filter>
+    </ClCompile>
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapijoystick.c">
       <Filter>joystick\hidapi</Filter>
     </ClCompile>
@@ -1346,7 +1368,7 @@
     <ClCompile Include="..\..\src\video\windows\SDL_windowskeyboard.c">
       <Filter>video\windows</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\src\video\windows\SDL_windowsgameinput.c">
+    <ClCompile Include="..\..\src\video\windows\SDL_windowsgameinput.cpp">
       <Filter>video\windows</Filter>
     </ClCompile>
     <ClCompile Include="..\..\src\video\windows\SDL_windowsmessagebox.c">
@@ -1585,11 +1607,12 @@
     <ClCompile Include="..\..\src\storage\generic\SDL_genericstorage.c" />
     <ClCompile Include="..\..\src\storage\steam\SDL_steamstorage.c" />
     <ClCompile Include="..\..\src\storage\SDL_storage.c" />
+    <ClCompile Include="..\..\src\events\SDL_eventwatch.c" />
+    <ClCompile Include="..\..\src\core\windows\pch_cpp.cpp">
+      <Filter>core\windows</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\..\src\core\windows\version.rc" />
   </ItemGroup>
-  <ItemGroup>
-    <MASM Include="..\..\src\stdlib\SDL_mslibc_x64.masm" />
-  </ItemGroup>
 </Project>

+ 13 - 0
libs/SDL3/VisualC/examples/asyncio/01-load-bitmaps/01-load-bitmaps.vcxproj

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{6A2BFA8B-C027-400D-A18B-3E9E1CC4DDD0}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ItemGroup>
+    <None Include="$(SolutionDir)\..\examples\asyncio\01-load-bitmaps\README.txt" />
+    <ClCompile Include="$(SolutionDir)\..\examples\asyncio\01-load-bitmaps\load-bitmaps.c" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>

+ 13 - 0
libs/SDL3/VisualC/examples/audio/04-multiple-streams/04-multiple-streams.vcxproj

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{7117A55C-BE4E-41DB-A4FC-4070E35A8B28}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ItemGroup>
+    <None Include="$(SolutionDir)\..\examples\audio\04-multiple-streams\README.txt" />
+    <ClCompile Include="$(SolutionDir)\..\examples\audio\04-multiple-streams\multiple-streams.c" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>

+ 13 - 0
libs/SDL3/VisualC/examples/demo/04-bytepusher/04-bytepusher.vcxproj

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{3DB9B219-769E-43AC-8B8B-319DB6045DCF}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ItemGroup>
+    <None Include="$(SolutionDir)\..\examples\demo\04-bytepusher\README.txt" />
+    <ClCompile Include="$(SolutionDir)\..\examples\demo\04-bytepusher\bytepusher.c" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>

+ 2 - 1
libs/SDL3/VisualC/examples/generate.py

@@ -47,7 +47,8 @@ def main():
     for category in path.iterdir():
         if category.is_dir():
             for example in category.iterdir():
-                generate(category.name, example.name, get_c_source_filename(example))
+                if example.is_dir():
+                     generate(category.name, example.name, get_c_source_filename(example))
 
 
 if __name__ == "__main__":

+ 13 - 0
libs/SDL3/VisualC/examples/input/01-joystick-polling/01-joystick-polling.vcxproj

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{B3852DB7-E925-4026-8B9D-D2272EFEFF3C}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ItemGroup>
+    <None Include="$(SolutionDir)\..\examples\input\01-joystick-polling\README.txt" />
+    <ClCompile Include="$(SolutionDir)\..\examples\input\01-joystick-polling\joystick-polling.c" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>

+ 13 - 0
libs/SDL3/VisualC/examples/input/02-joystick-events/02-joystick-events.vcxproj

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{FCBDF2B2-1129-49AE-9406-3F219E65CA89}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ItemGroup>
+    <None Include="$(SolutionDir)\..\examples\input\02-joystick-events\README.txt" />
+    <ClCompile Include="$(SolutionDir)\..\examples\input\02-joystick-events\joystick-events.c" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>

+ 13 - 0
libs/SDL3/VisualC/examples/renderer/19-affine-textures/19-affine-textures.vcxproj

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup Label="Globals">
+    <ProjectGuid>{E21C50BF-54B4-434C-AA24-9A6469553987}</ProjectGuid>
+  </PropertyGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+  <ItemGroup>
+    <None Include="$(SolutionDir)\..\examples\renderer\19-affine-textures\README.txt" />
+    <ClCompile Include="$(SolutionDir)\..\examples\renderer\19-affine-textures\affine-textures.c" />
+  </ItemGroup>
+  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>

+ 2 - 2
libs/SDL3/Xcode/SDL/Info-Framework.plist

@@ -19,10 +19,10 @@
 	<key>CFBundlePackageType</key>
 	<string>FMWK</string>
 	<key>CFBundleShortVersionString</key>
-	<string>3.2.10</string>
+	<string>3.3.0</string>
 	<key>CFBundleSignature</key>
 	<string>SDLX</string>
 	<key>CFBundleVersion</key>
-	<string>3.2.10</string>
+	<string>3.3.0</string>
 </dict>
 </plist>

+ 42 - 6
libs/SDL3/Xcode/SDL/SDL.xcodeproj/project.pbxproj

@@ -71,6 +71,10 @@
 		63134A262A7902FD0021E9A6 /* SDL_pen.c in Sources */ = {isa = PBXBuildFile; fileRef = 63134A242A7902FD0021E9A6 /* SDL_pen.c */; };
 		75E0915A241EA924004729E1 /* SDL_virtualjoystick.c in Sources */ = {isa = PBXBuildFile; fileRef = 75E09158241EA924004729E1 /* SDL_virtualjoystick.c */; };
 		75E09163241EA924004729E1 /* SDL_virtualjoystick_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 75E09159241EA924004729E1 /* SDL_virtualjoystick_c.h */; };
+		89E5801E2D03602200DAF6D3 /* SDL_hidapi_lg4ff.c in Sources */ = {isa = PBXBuildFile; fileRef = 89E5801D2D03602200DAF6D3 /* SDL_hidapi_lg4ff.c */; };
+		89E580232D03606400DAF6D3 /* SDL_hidapihaptic.c in Sources */ = {isa = PBXBuildFile; fileRef = 89E5801F2D03606400DAF6D3 /* SDL_hidapihaptic.c */; };
+		89E580242D03606400DAF6D3 /* SDL_hidapihaptic_lg4ff.c in Sources */ = {isa = PBXBuildFile; fileRef = 89E580212D03606400DAF6D3 /* SDL_hidapihaptic_lg4ff.c */; };
+		89E580252D03606400DAF6D3 /* SDL_hidapihaptic_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 89E580202D03606400DAF6D3 /* SDL_hidapihaptic_c.h */; };
 		9846B07C287A9020000C35C8 /* SDL_hidapi_shield.c in Sources */ = {isa = PBXBuildFile; fileRef = 9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */; };
 		A1626A3E2617006A003F1973 /* SDL_triangle.c in Sources */ = {isa = PBXBuildFile; fileRef = A1626A3D2617006A003F1973 /* SDL_triangle.c */; };
 		A1626A522617008D003F1973 /* SDL_triangle.h in Headers */ = {isa = PBXBuildFile; fileRef = A1626A512617008C003F1973 /* SDL_triangle.h */; };
@@ -384,6 +388,7 @@
 		F32DDAD42AB795A30041EAA5 /* SDL_audioresample.c in Sources */ = {isa = PBXBuildFile; fileRef = F32DDACE2AB795A30041EAA5 /* SDL_audioresample.c */; };
 		F338A1182D1B37D8007CDFDF /* SDL_tray.m in Sources */ = {isa = PBXBuildFile; fileRef = F338A1172D1B37D8007CDFDF /* SDL_tray.m */; };
 		F338A11A2D1B37E4007CDFDF /* SDL_tray.c in Sources */ = {isa = PBXBuildFile; fileRef = F338A1192D1B37E4007CDFDF /* SDL_tray.c */; };
+		F3395BA82D9A5971007246C8 /* SDL_hidapi_8bitdo.c in Sources */ = {isa = PBXBuildFile; fileRef = F3395BA72D9A5971007246C8 /* SDL_hidapi_8bitdo.c */; };
 		F34400342D40217A003F26D7 /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = F373DA182D388A1E002158FA /* LICENSE.txt */; };
 		F34400362D40217A003F26D7 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = F373DA192D388A1E002158FA /* README.md */; };
 		F344003D2D4022E1003F26D7 /* INSTALL.md in Resources */ = {isa = PBXBuildFile; fileRef = F344003C2D4022E1003F26D7 /* INSTALL.md */; };
@@ -433,6 +438,7 @@
 		F3B439532C935C2C00792030 /* SDL_posixprocess.c in Sources */ = {isa = PBXBuildFile; fileRef = F3B439522C935C2C00792030 /* SDL_posixprocess.c */; };
 		F3B439562C937DAB00792030 /* SDL_process.c in Sources */ = {isa = PBXBuildFile; fileRef = F3B439542C937DAB00792030 /* SDL_process.c */; };
 		F3B439572C937DAB00792030 /* SDL_sysprocess.h in Headers */ = {isa = PBXBuildFile; fileRef = F3B439552C937DAB00792030 /* SDL_sysprocess.h */; };
+		F3B6B80A2DC3EA54004954FD /* SDL_hidapi_gip.c in Sources */ = {isa = PBXBuildFile; fileRef = F3B6B8092DC3EA54004954FD /* SDL_hidapi_gip.c */; };
 		F3C1BD752D1F1A3000846529 /* SDL_tray_utils.c in Sources */ = {isa = PBXBuildFile; fileRef = F3C1BD742D1F1A3000846529 /* SDL_tray_utils.c */; };
 		F3C1BD762D1F1A3000846529 /* SDL_tray_utils.h in Headers */ = {isa = PBXBuildFile; fileRef = F3C1BD732D1F1A3000846529 /* SDL_tray_utils.h */; };
 		F3C2CB222C5DDDB2004D7998 /* SDL_categories_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3C2CB202C5DDDB2004D7998 /* SDL_categories_c.h */; };
@@ -535,6 +541,7 @@
 		F3FA5A232B59ACE000FEAD97 /* yuv_rgb_lsx.c in Sources */ = {isa = PBXBuildFile; fileRef = F3FA5A1A2B59ACE000FEAD97 /* yuv_rgb_lsx.c */; };
 		F3FA5A242B59ACE000FEAD97 /* yuv_rgb_lsx.h in Headers */ = {isa = PBXBuildFile; fileRef = F3FA5A1B2B59ACE000FEAD97 /* yuv_rgb_lsx.h */; };
 		F3FA5A252B59ACE000FEAD97 /* yuv_rgb_common.h in Headers */ = {isa = PBXBuildFile; fileRef = F3FA5A1C2B59ACE000FEAD97 /* yuv_rgb_common.h */; };
+		F3FBB1082DDF93AB0000F99F /* SDL_hidapi_flydigi.c in Sources */ = {isa = PBXBuildFile; fileRef = F3395BA72D9A5971007246C9 /* SDL_hidapi_flydigi.c */; };
 		F3FD042E2C9B755700824C4C /* SDL_hidapi_nintendo.h in Headers */ = {isa = PBXBuildFile; fileRef = F3FD042C2C9B755700824C4C /* SDL_hidapi_nintendo.h */; };
 		F3FD042F2C9B755700824C4C /* SDL_hidapi_steam_hori.c in Sources */ = {isa = PBXBuildFile; fileRef = F3FD042D2C9B755700824C4C /* SDL_hidapi_steam_hori.c */; };
 		FA73671D19A540EF004122E4 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA73671C19A540EF004122E4 /* CoreVideo.framework */; platformFilters = (ios, maccatalyst, macos, tvos, ); settings = {ATTRIBUTES = (Required, ); }; };
@@ -608,6 +615,10 @@
 		63134A242A7902FD0021E9A6 /* SDL_pen.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_pen.c; sourceTree = "<group>"; };
 		75E09158241EA924004729E1 /* SDL_virtualjoystick.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_virtualjoystick.c; sourceTree = "<group>"; };
 		75E09159241EA924004729E1 /* SDL_virtualjoystick_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_virtualjoystick_c.h; sourceTree = "<group>"; };
+		89E5801D2D03602200DAF6D3 /* SDL_hidapi_lg4ff.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_lg4ff.c; sourceTree = "<group>"; };
+		89E5801F2D03606400DAF6D3 /* SDL_hidapihaptic.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_hidapihaptic.c; sourceTree = "<group>"; };
+		89E580202D03606400DAF6D3 /* SDL_hidapihaptic_c.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_hidapihaptic_c.h; sourceTree = "<group>"; };
+		89E580212D03606400DAF6D3 /* SDL_hidapihaptic_lg4ff.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_hidapihaptic_lg4ff.c; sourceTree = "<group>"; };
 		9846B07B287A9020000C35C8 /* SDL_hidapi_shield.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_shield.c; sourceTree = "<group>"; };
 		A1626A3D2617006A003F1973 /* SDL_triangle.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_triangle.c; sourceTree = "<group>"; };
 		A1626A512617008C003F1973 /* SDL_triangle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_triangle.h; sourceTree = "<group>"; };
@@ -938,6 +949,8 @@
 		F32DDACE2AB795A30041EAA5 /* SDL_audioresample.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_audioresample.c; sourceTree = "<group>"; };
 		F338A1172D1B37D8007CDFDF /* SDL_tray.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDL_tray.m; sourceTree = "<group>"; };
 		F338A1192D1B37E4007CDFDF /* SDL_tray.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_tray.c; sourceTree = "<group>"; };
+		F3395BA72D9A5971007246C8 /* SDL_hidapi_8bitdo.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_8bitdo.c; sourceTree = "<group>"; };
+		F3395BA72D9A5971007246C9 /* SDL_hidapi_flydigi.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_flydigi.c; sourceTree = "<group>"; };
 		F344003C2D4022E1003F26D7 /* INSTALL.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = INSTALL.md; sourceTree = "<group>"; };
 		F362B9152B3349E200D30B94 /* controller_list.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = controller_list.h; sourceTree = "<group>"; };
 		F362B9162B3349E200D30B94 /* SDL_gamepad_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_gamepad_c.h; sourceTree = "<group>"; };
@@ -1002,6 +1015,7 @@
 		F3B439522C935C2C00792030 /* SDL_posixprocess.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_posixprocess.c; sourceTree = "<group>"; };
 		F3B439542C937DAB00792030 /* SDL_process.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_process.c; sourceTree = "<group>"; };
 		F3B439552C937DAB00792030 /* SDL_sysprocess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_sysprocess.h; sourceTree = "<group>"; };
+		F3B6B8092DC3EA54004954FD /* SDL_hidapi_gip.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_gip.c; sourceTree = "<group>"; };
 		F3C1BD732D1F1A3000846529 /* SDL_tray_utils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_tray_utils.h; sourceTree = "<group>"; };
 		F3C1BD742D1F1A3000846529 /* SDL_tray_utils.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SDL_tray_utils.c; sourceTree = "<group>"; };
 		F3C2CB202C5DDDB2004D7998 /* SDL_categories_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_categories_c.h; sourceTree = "<group>"; };
@@ -1477,6 +1491,16 @@
 			path = virtual;
 			sourceTree = "<group>";
 		};
+		89E580222D03606400DAF6D3 /* hidapi */ = {
+			isa = PBXGroup;
+			children = (
+				89E5801F2D03606400DAF6D3 /* SDL_hidapihaptic.c */,
+				89E580202D03606400DAF6D3 /* SDL_hidapihaptic_c.h */,
+				89E580212D03606400DAF6D3 /* SDL_hidapihaptic_lg4ff.c */,
+			);
+			path = hidapi;
+			sourceTree = "<group>";
+		};
 		A75FDAA423E2790500529352 /* ios */ = {
 			isa = PBXGroup;
 			children = (
@@ -1535,6 +1559,7 @@
 		A7D8A5C223E2513D00DCD162 /* haptic */ = {
 			isa = PBXGroup;
 			children = (
+				89E580222D03606400DAF6D3 /* hidapi */,
 				A7D8A5CD23E2513D00DCD162 /* darwin */,
 				A7D8A5C323E2513D00DCD162 /* dummy */,
 				A7D8A5C623E2513D00DCD162 /* SDL_haptic_c.h */,
@@ -1904,8 +1929,12 @@
 		A7D8A7BE23E2513E00DCD162 /* hidapi */ = {
 			isa = PBXGroup;
 			children = (
+				F3395BA72D9A5971007246C8 /* SDL_hidapi_8bitdo.c */,
 				F32305FE28939F6400E66D30 /* SDL_hidapi_combined.c */,
+				F3395BA72D9A5971007246C9 /* SDL_hidapi_flydigi.c */,
 				A7D8A7C923E2513E00DCD162 /* SDL_hidapi_gamecube.c */,
+				F3B6B8092DC3EA54004954FD /* SDL_hidapi_gip.c */,
+				89E5801D2D03602200DAF6D3 /* SDL_hidapi_lg4ff.c */,
 				F3F07D59269640160074468B /* SDL_hidapi_luna.c */,
 				F3FD042C2C9B755700824C4C /* SDL_hidapi_nintendo.h */,
 				F388C95428B5F6F600661ECF /* SDL_hidapi_ps3.c */,
@@ -2617,6 +2646,7 @@
 				F37E18642BAA40670098C111 /* SDL_time_c.h in Headers */,
 				F31013C82C24E98200FBE946 /* SDL_keymap_c.h in Headers */,
 				63134A252A7902FD0021E9A6 /* SDL_pen_c.h in Headers */,
+				89E580252D03606400DAF6D3 /* SDL_hidapihaptic_c.h in Headers */,
 				F36C34312C0F876500991150 /* SDL_offscreenvulkan.h in Headers */,
 				A7D8B2C023E2514200DCD162 /* SDL_pixels_c.h in Headers */,
 				F37E18622BAA40090098C111 /* SDL_sysfilesystem.h in Headers */,
@@ -2905,6 +2935,8 @@
 				A7D8BBDD23E2574800DCD162 /* SDL_uikitmodes.m in Sources */,
 				A7D8BA3723E2514400DCD162 /* SDL_d3dmath.c in Sources */,
 				F3A9AE9C2C8A13C100AAC390 /* SDL_pipeline_gpu.c in Sources */,
+				89E580232D03606400DAF6D3 /* SDL_hidapihaptic.c in Sources */,
+				89E580242D03606400DAF6D3 /* SDL_hidapihaptic_lg4ff.c in Sources */,
 				75E0915A241EA924004729E1 /* SDL_virtualjoystick.c in Sources */,
 				F338A11A2D1B37E4007CDFDF /* SDL_tray.c in Sources */,
 				A7D8ABEB23E2514100DCD162 /* SDL_nullvideo.c in Sources */,
@@ -2966,6 +2998,7 @@
 				A7D8B76423E2514300DCD162 /* SDL_mixer.c in Sources */,
 				A7D8BB5723E2514500DCD162 /* SDL_events.c in Sources */,
 				A7D8ADE623E2514100DCD162 /* SDL_blit_0.c in Sources */,
+				89E5801E2D03602200DAF6D3 /* SDL_hidapi_lg4ff.c in Sources */,
 				A7D8B8A823E2514400DCD162 /* SDL_diskaudio.c in Sources */,
 				56A2373329F9C113003CCA5F /* SDL_sysrwlock.c in Sources */,
 				F3A9AE9A2C8A13C100AAC390 /* SDL_shaders_gpu.c in Sources */,
@@ -3029,6 +3062,7 @@
 				A7D8BA5B23E2514400DCD162 /* SDL_shaders_gles2.c in Sources */,
 				A7D8B14023E2514200DCD162 /* SDL_blit_1.c in Sources */,
 				A7D8BBDB23E2574800DCD162 /* SDL_uikitmetalview.m in Sources */,
+				F3B6B80A2DC3EA54004954FD /* SDL_hidapi_gip.c in Sources */,
 				A7D8BB1523E2514500DCD162 /* SDL_mouse.c in Sources */,
 				F395C19C2569C68F00942BFF /* SDL_iokitjoystick.c in Sources */,
 				A7D8B4B223E2514300DCD162 /* SDL_sysjoystick.c in Sources */,
@@ -3051,9 +3085,11 @@
 				000028F8113A53F4333E0000 /* SDL_main_callbacks.c in Sources */,
 				000098E9DAA43EF6FF7F0000 /* SDL_camera.c in Sources */,
 				F310138E2C1F2CB700FBE946 /* SDL_random.c in Sources */,
+				F3395BA82D9A5971007246C8 /* SDL_hidapi_8bitdo.c in Sources */,
 				00001B2471F503DD3C1B0000 /* SDL_camera_dummy.c in Sources */,
 				00002B20A48E055EB0350000 /* SDL_camera_coremedia.m in Sources */,
 				000080903BC03006F24E0000 /* SDL_filesystem.c in Sources */,
+				F3FBB1082DDF93AB0000F99F /* SDL_hidapi_flydigi.c in Sources */,
 				0000481D255AF155B42C0000 /* SDL_sysfsops.c in Sources */,
 				0000494CC93F3E624D3C0000 /* SDL_systime.c in Sources */,
 				000095FA1BDE436CF3AF0000 /* SDL_time.c in Sources */,
@@ -3085,8 +3121,8 @@
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
 				DEPLOYMENT_POSTPROCESSING = YES;
-				DYLIB_COMPATIBILITY_VERSION = 201.0.0;
-				DYLIB_CURRENT_VERSION = 201.10.0;
+				DYLIB_COMPATIBILITY_VERSION = 301.0.0;
+				DYLIB_CURRENT_VERSION = 301.0.0;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				GCC_ALTIVEC_EXTENSIONS = YES;
@@ -3121,7 +3157,7 @@
 					"@loader_path/Frameworks",
 				);
 				MACOSX_DEPLOYMENT_TARGET = 10.13;
-				MARKETING_VERSION = 3.2.10;
+				MARKETING_VERSION = 3.3.0;
 				OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
 				PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;
 				PRODUCT_NAME = SDL3;
@@ -3149,8 +3185,8 @@
 				ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES;
 				CLANG_ENABLE_MODULES = YES;
 				CLANG_ENABLE_OBJC_ARC = YES;
-				DYLIB_COMPATIBILITY_VERSION = 201.0.0;
-				DYLIB_CURRENT_VERSION = 201.10.0;
+				DYLIB_COMPATIBILITY_VERSION = 301.0.0;
+				DYLIB_CURRENT_VERSION = 301.0.0;
 				DYLIB_INSTALL_NAME_BASE = "@rpath";
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
@@ -3182,7 +3218,7 @@
 					"@loader_path/Frameworks",
 				);
 				MACOSX_DEPLOYMENT_TARGET = 10.13;
-				MARKETING_VERSION = 3.2.10;
+				MARKETING_VERSION = 3.3.0;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_LDFLAGS = "$(CONFIG_FRAMEWORK_LDFLAGS)";
 				PRODUCT_BUNDLE_IDENTIFIER = org.libsdl.SDL3;

+ 1 - 1
libs/SDL3/Xcode/SDL/pkg-support/SDL.info

@@ -1,4 +1,4 @@
-Title SDL 3.2.10
+Title SDL 3.3.0
 Version 1
 Description SDL Library for macOS (http://www.libsdl.org)
 DefaultLocation /Library/Frameworks

+ 1 - 1
libs/SDL3/Xcode/SDL/pkg-support/share/cmake/SDL3/SDL3Config.cmake

@@ -92,7 +92,7 @@ if(NOT TARGET SDL3::Headers)
     add_library(SDL3::Headers INTERFACE IMPORTED)
     set_target_properties(SDL3::Headers
         PROPERTIES
-            INTERFACE_COMPILE_OPTIONS "SHELL:-F \"${_sdl3_framework_parent_path}\""
+            INTERFACE_COMPILE_OPTIONS "-F${_sdl3_framework_parent_path}"
     )
 endif()
 set(SDL3_Headers_FOUND TRUE)

+ 2 - 1
libs/SDL3/android-project/app/proguard-rules.pro

@@ -36,7 +36,6 @@
     int messageboxShowMessageBox(int, java.lang.String, java.lang.String, int[], int[], java.lang.String[], int[]);
     void minimizeWindow();
     boolean openURL(java.lang.String);
-    void onNativePen(int, int, int , float , float , float);
     void requestPermission(java.lang.String, int);
     boolean showToast(java.lang.String, int, int, int, int);
     boolean sendMessage(int, int);
@@ -51,6 +50,8 @@
     boolean supportsRelativeMouse();
     int openFileDescriptor(java.lang.String, java.lang.String);
     boolean showFileDialog(java.lang.String[], boolean, boolean, int);
+    java.lang.String getPreferredLocales();
+    java.lang.String formatLocale(java.util.Locale);
 }
 
 -keep,includedescriptorclasses,allowoptimization class org.libsdl.app.HIDDeviceManager {

+ 20 - 10
libs/SDL3/android-project/app/src/main/java/org/libsdl/app/HIDDeviceBLESteamController.java

@@ -44,9 +44,9 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
 
     private static final int CHROMEBOOK_CONNECTION_CHECK_INTERVAL = 10000;
 
-    static public final UUID steamControllerService = UUID.fromString("100F6C32-1735-4313-B402-38567131E5F3");
-    static public final UUID inputCharacteristic = UUID.fromString("100F6C33-1735-4313-B402-38567131E5F3");
-    static public final UUID reportCharacteristic = UUID.fromString("100F6C34-1735-4313-B402-38567131E5F3");
+    static final UUID steamControllerService = UUID.fromString("100F6C32-1735-4313-B402-38567131E5F3");
+    static final UUID inputCharacteristic = UUID.fromString("100F6C33-1735-4313-B402-38567131E5F3");
+    static final UUID reportCharacteristic = UUID.fromString("100F6C34-1735-4313-B402-38567131E5F3");
     static private final byte[] enterValveMode = new byte[] { (byte)0xC0, (byte)0x87, 0x03, 0x08, 0x07, 0x00 };
 
     static class GattOperation {
@@ -156,7 +156,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
         }
     }
 
-    public HIDDeviceBLESteamController(HIDDeviceManager manager, BluetoothDevice device) {
+    HIDDeviceBLESteamController(HIDDeviceManager manager, BluetoothDevice device) {
         mManager = manager;
         mDevice = device;
         mDeviceId = mManager.getDeviceIDForIdentifier(getIdentifier());
@@ -169,17 +169,17 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
         // final HIDDeviceBLESteamController finalThis = this;
         // mHandler.postDelayed(new Runnable() {
         //     @Override
-        //     public void run() {
+        //     void run() {
         //         finalThis.checkConnectionForChromebookIssue();
         //     }
         // }, CHROMEBOOK_CONNECTION_CHECK_INTERVAL);
     }
 
-    public String getIdentifier() {
+    String getIdentifier() {
         return String.format("SteamController.%s", mDevice.getAddress());
     }
 
-    public BluetoothGatt getGatt() {
+    BluetoothGatt getGatt() {
         return mGatt;
     }
 
@@ -219,7 +219,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
         return btManager.getConnectionState(mDevice, BluetoothProfile.GATT);
     }
 
-    public void reconnect() {
+    void reconnect() {
 
         if (getConnectionState() != BluetoothProfile.STATE_CONNECTED) {
             mGatt.disconnect();
@@ -401,12 +401,12 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
         queueGattOperation(op);
     }
 
-    public void writeCharacteristic(UUID uuid, byte[] value) {
+    void writeCharacteristic(UUID uuid, byte[] value) {
         GattOperation op = HIDDeviceBLESteamController.GattOperation.writeCharacteristic(mGatt, uuid, value);
         queueGattOperation(op);
     }
 
-    public void readCharacteristic(UUID uuid) {
+    void readCharacteristic(UUID uuid) {
         GattOperation op = HIDDeviceBLESteamController.GattOperation.readCharacteristic(mGatt, uuid);
         queueGattOperation(op);
     }
@@ -415,6 +415,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
     //////////////  BluetoothGattCallback overridden methods
     //////////////////////////////////////////////////////////////////////////////////////////////////////
 
+    @Override
     public void onConnectionStateChange(BluetoothGatt g, int status, int newState) {
         //Log.v(TAG, "onConnectionStateChange status=" + status + " newState=" + newState);
         mIsReconnecting = false;
@@ -437,6 +438,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
         // Disconnection is handled in SteamLink using the ACTION_ACL_DISCONNECTED Intent.
     }
 
+    @Override
     public void onServicesDiscovered(BluetoothGatt gatt, int status) {
         //Log.v(TAG, "onServicesDiscovered status=" + status);
         if (status == 0) {
@@ -453,6 +455,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
         }
     }
 
+    @Override
     public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
         //Log.v(TAG, "onCharacteristicRead status=" + status + " uuid=" + characteristic.getUuid());
 
@@ -463,6 +466,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
         finishCurrentGattOperation();
     }
 
+    @Override
     public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
         //Log.v(TAG, "onCharacteristicWrite status=" + status + " uuid=" + characteristic.getUuid());
 
@@ -478,6 +482,7 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
         finishCurrentGattOperation();
     }
 
+    @Override
     public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
     // Enable this for verbose logging of controller input reports
         //Log.v(TAG, "onCharacteristicChanged uuid=" + characteristic.getUuid() + " data=" + HexDump.dumpHexString(characteristic.getValue()));
@@ -487,10 +492,12 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
         }
     }
 
+    @Override
     public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
         //Log.v(TAG, "onDescriptorRead status=" + status);
     }
 
+    @Override
     public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
         BluetoothGattCharacteristic chr = descriptor.getCharacteristic();
         //Log.v(TAG, "onDescriptorWrite status=" + status + " uuid=" + chr.getUuid() + " descriptor=" + descriptor.getUuid());
@@ -508,14 +515,17 @@ class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDe
         finishCurrentGattOperation();
     }
 
+    @Override
     public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
         //Log.v(TAG, "onReliableWriteCompleted status=" + status);
     }
 
+    @Override
     public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
         //Log.v(TAG, "onReadRemoteRssi status=" + status);
     }
 
+    @Override
     public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
         //Log.v(TAG, "onMtuChanged status=" + status);
     }

+ 17 - 13
libs/SDL3/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java

@@ -32,7 +32,7 @@ public class HIDDeviceManager {
     private static HIDDeviceManager sManager;
     private static int sManagerRefCount = 0;
 
-    public static HIDDeviceManager acquire(Context context) {
+    static public HIDDeviceManager acquire(Context context) {
         if (sManagerRefCount == 0) {
             sManager = new HIDDeviceManager(context);
         }
@@ -40,7 +40,7 @@ public class HIDDeviceManager {
         return sManager;
     }
 
-    public static void release(HIDDeviceManager manager) {
+    static public void release(HIDDeviceManager manager) {
         if (manager == sManager) {
             --sManagerRefCount;
             if (sManagerRefCount == 0) {
@@ -121,11 +121,11 @@ public class HIDDeviceManager {
         }
     }
 
-    public Context getContext() {
+    Context getContext() {
         return mContext;
     }
 
-    public int getDeviceIDForIdentifier(String identifier) {
+    int getDeviceIDForIdentifier(String identifier) {
         SharedPreferences.Editor spedit = mSharedPreferences.edit();
 
         int result = mSharedPreferences.getInt(identifier, 0);
@@ -288,9 +288,13 @@ public class HIDDeviceManager {
             0x1532, // Razer Wildcat
             0x20d6, // PowerA
             0x24c6, // PowerA
+            0x294b, // Snakebyte
             0x2dc8, // 8BitDo
             0x2e24, // Hyperkin
+            0x2e95, // SCUF
+            0x3285, // Nacon
             0x3537, // GameSir
+            0x366c, // ByoWave
         };
 
         if (usbInterface.getId() == 0 &&
@@ -439,7 +443,7 @@ public class HIDDeviceManager {
     // Chromebooks do not pass along ACTION_ACL_CONNECTED / ACTION_ACL_DISCONNECTED properly.
     // This function provides a sort of dummy version of that, watching for changes in the
     // connected devices and attempting to add controllers as things change.
-    public void chromebookConnectionHandler() {
+    void chromebookConnectionHandler() {
         if (!mIsChromebook) {
             return;
         }
@@ -478,7 +482,7 @@ public class HIDDeviceManager {
         }, 10000);
     }
 
-    public boolean connectBluetoothDevice(BluetoothDevice bluetoothDevice) {
+    boolean connectBluetoothDevice(BluetoothDevice bluetoothDevice) {
         Log.v(TAG, "connectBluetoothDevice device=" + bluetoothDevice);
         synchronized (this) {
             if (mBluetoothDevices.containsKey(bluetoothDevice)) {
@@ -499,7 +503,7 @@ public class HIDDeviceManager {
         return true;
     }
 
-    public void disconnectBluetoothDevice(BluetoothDevice bluetoothDevice) {
+    void disconnectBluetoothDevice(BluetoothDevice bluetoothDevice) {
         synchronized (this) {
             HIDDeviceBLESteamController device = mBluetoothDevices.get(bluetoothDevice);
             if (device == null)
@@ -513,7 +517,7 @@ public class HIDDeviceManager {
         }
     }
 
-    public boolean isSteamController(BluetoothDevice bluetoothDevice) {
+    boolean isSteamController(BluetoothDevice bluetoothDevice) {
         // Sanity check.  If you pass in a null device, by definition it is never a Steam Controller.
         if (bluetoothDevice == null) {
             return false;
@@ -567,7 +571,7 @@ public class HIDDeviceManager {
     ////////// JNI interface functions
     //////////////////////////////////////////////////////////////////////////////////////////////////////
 
-    public boolean initialize(boolean usb, boolean bluetooth) {
+    boolean initialize(boolean usb, boolean bluetooth) {
         Log.v(TAG, "initialize(" + usb + ", " + bluetooth + ")");
 
         if (usb) {
@@ -579,7 +583,7 @@ public class HIDDeviceManager {
         return true;
     }
 
-    public boolean openDevice(int deviceID) {
+    boolean openDevice(int deviceID) {
         Log.v(TAG, "openDevice deviceID=" + deviceID);
         HIDDevice device = getDevice(deviceID);
         if (device == null) {
@@ -621,7 +625,7 @@ public class HIDDeviceManager {
         return false;
     }
 
-    public int writeReport(int deviceID, byte[] report, boolean feature) {
+    int writeReport(int deviceID, byte[] report, boolean feature) {
         try {
             //Log.v(TAG, "writeReport deviceID=" + deviceID + " length=" + report.length);
             HIDDevice device;
@@ -638,7 +642,7 @@ public class HIDDeviceManager {
         return -1;
     }
 
-    public boolean readReport(int deviceID, byte[] report, boolean feature) {
+    boolean readReport(int deviceID, byte[] report, boolean feature) {
         try {
             //Log.v(TAG, "readReport deviceID=" + deviceID);
             HIDDevice device;
@@ -655,7 +659,7 @@ public class HIDDeviceManager {
         return false;
     }
 
-    public void closeDevice(int deviceID) {
+    void closeDevice(int deviceID) {
         try {
             Log.v(TAG, "closeDevice deviceID=" + deviceID);
             HIDDevice device;

+ 2 - 2
libs/SDL3/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java

@@ -30,7 +30,7 @@ class HIDDeviceUSB implements HIDDevice {
         mRunning = false;
     }
 
-    public String getIdentifier() {
+    String getIdentifier() {
         return String.format("%s/%x/%x/%d", mDevice.getDeviceName(), mDevice.getVendorId(), mDevice.getProductId(), mInterfaceIndex);
     }
 
@@ -100,7 +100,7 @@ class HIDDeviceUSB implements HIDDevice {
         return mDevice;
     }
 
-    public String getDeviceName() {
+    String getDeviceName() {
         return getManufacturerName() + " " + getProductName() + "(0x" + String.format("%x", getVendorId()) + "/0x" + String.format("%x", getProductId()) + ")";
     }
 

+ 6 - 6
libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDL.java

@@ -12,14 +12,14 @@ public class SDL {
 
     // This function should be called first and sets up the native code
     // so it can call into the Java classes
-    public static void setupJNI() {
+    static public void setupJNI() {
         SDLActivity.nativeSetupJNI();
         SDLAudioManager.nativeSetupJNI();
         SDLControllerManager.nativeSetupJNI();
     }
 
     // This function should be called each time the activity is started
-    public static void initialize() {
+    static public void initialize() {
         setContext(null);
 
         SDLActivity.initialize();
@@ -28,20 +28,20 @@ public class SDL {
     }
 
     // This function stores the current activity (SDL or not)
-    public static void setContext(Context context) {
+    static public void setContext(Context context) {
         SDLAudioManager.setContext(context);
         mContext = context;
     }
 
-    public static Context getContext() {
+    static public Context getContext() {
         return mContext;
     }
 
-    public static void loadLibrary(String libraryName) throws UnsatisfiedLinkError, SecurityException, NullPointerException {
+    static void loadLibrary(String libraryName) throws UnsatisfiedLinkError, SecurityException, NullPointerException {
         loadLibrary(libraryName, mContext);
     }
 
-    public static void loadLibrary(String libraryName, Context context) throws UnsatisfiedLinkError, SecurityException, NullPointerException {
+    static void loadLibrary(String libraryName, Context context) throws UnsatisfiedLinkError, SecurityException, NullPointerException {
 
         if (libraryName == null) {
             throw new NullPointerException("No library name provided.");

+ 41 - 2
libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java

@@ -23,6 +23,7 @@ import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.LocaleList;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.util.DisplayMetrics;
@@ -59,8 +60,8 @@ import java.util.Locale;
 public class SDLActivity extends Activity implements View.OnSystemUiVisibilityChangeListener {
     private static final String TAG = "SDL";
     private static final int SDL_MAJOR_VERSION = 3;
-    private static final int SDL_MINOR_VERSION = 2;
-    private static final int SDL_MICRO_VERSION = 10;
+    private static final int SDL_MINOR_VERSION = 3;
+    private static final int SDL_MICRO_VERSION = 0;
 /*
     // Display InputType.SOURCE/CLASS of events and devices
     //
@@ -2116,6 +2117,44 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         int requestCode;
         boolean multipleChoice;
     }
+    
+    /**
+     * This method is called by SDL using JNI.
+     */
+    public static String getPreferredLocales() {
+        String result = "";
+        if (Build.VERSION.SDK_INT >= 24 /* Android 7 (N) */) {
+            LocaleList locales = LocaleList.getAdjustedDefault();
+            for (int i = 0; i < locales.size(); i++) {
+                if (i != 0) result += ",";
+                result += formatLocale(locales.get(i));
+            }
+        } else if (mCurrentLocale != null) {
+            result = formatLocale(mCurrentLocale);
+        }
+        return result;
+    }
+
+    public static String formatLocale(Locale locale) {
+        String result = "";
+        String lang = "";
+        if (locale.getLanguage() == "in") {
+            // Indonesian is "id" according to ISO 639.2, but on Android is "in" because of Java backwards compatibility
+            lang = "id";
+        } else if (locale.getLanguage() == "") {
+            // Make sure language is never empty
+            lang = "und";
+        } else {
+            lang = locale.getLanguage();
+        }
+
+        if (locale.getCountry() == "") {
+            result = lang;
+        } else {
+            result = lang + "_" + locale.getCountry();
+        }
+        return result;
+    }
 }
 
 /**

+ 14 - 14
libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLAudioManager.java

@@ -10,14 +10,14 @@ import android.util.Log;
 import java.util.Arrays;
 import java.util.ArrayList;
 
-public class SDLAudioManager {
+class SDLAudioManager {
     protected static final String TAG = "SDLAudio";
 
     protected static Context mContext;
 
     private static AudioDeviceCallback mAudioDeviceCallback;
 
-    public static void initialize() {
+    static void initialize() {
         mAudioDeviceCallback = null;
 
         if(Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */)
@@ -26,25 +26,25 @@ public class SDLAudioManager {
                 @Override
                 public void onAudioDevicesAdded(AudioDeviceInfo[] addedDevices) {
                     for (AudioDeviceInfo deviceInfo : addedDevices) {
-                        addAudioDevice(deviceInfo.isSink(), deviceInfo.getProductName().toString(), deviceInfo.getId());
+                        nativeAddAudioDevice(deviceInfo.isSink(), deviceInfo.getProductName().toString(), deviceInfo.getId());
                     }
                 }
 
                 @Override
                 public void onAudioDevicesRemoved(AudioDeviceInfo[] removedDevices) {
                     for (AudioDeviceInfo deviceInfo : removedDevices) {
-                        removeAudioDevice(deviceInfo.isSink(), deviceInfo.getId());
+                        nativeRemoveAudioDevice(deviceInfo.isSink(), deviceInfo.getId());
                     }
                 }
             };
         }
     }
 
-    public static void setContext(Context context) {
+    static void setContext(Context context) {
         mContext = context;
     }
 
-    public static void release(Context context) {
+    static void release(Context context) {
         // no-op atm
     }
 
@@ -74,7 +74,7 @@ public class SDLAudioManager {
         return null;
     }
 
-    public static void registerAudioDeviceCallback() {
+    static void registerAudioDeviceCallback() {
         if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
             AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
             // get an initial list now, before hotplug callbacks fire.
@@ -82,16 +82,16 @@ public class SDLAudioManager {
                 if (dev.getType() == AudioDeviceInfo.TYPE_TELEPHONY) {
                     continue;  // Device cannot be opened
                 }
-                addAudioDevice(dev.isSink(), dev.getProductName().toString(), dev.getId());
+                nativeAddAudioDevice(dev.isSink(), dev.getProductName().toString(), dev.getId());
             }
             for (AudioDeviceInfo dev : audioManager.getDevices(AudioManager.GET_DEVICES_INPUTS)) {
-                addAudioDevice(dev.isSink(), dev.getProductName().toString(), dev.getId());
+                nativeAddAudioDevice(dev.isSink(), dev.getProductName().toString(), dev.getId());
             }
             audioManager.registerAudioDeviceCallback(mAudioDeviceCallback, null);
         }
     }
 
-    public static void unregisterAudioDeviceCallback() {
+    static void unregisterAudioDeviceCallback() {
         if (Build.VERSION.SDK_INT >= 24 /* Android 7.0 (N) */) {
             AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
             audioManager.unregisterAudioDeviceCallback(mAudioDeviceCallback);
@@ -99,7 +99,7 @@ public class SDLAudioManager {
     }
 
     /** This method is called by SDL using JNI. */
-    public static void audioSetThreadPriority(boolean recording, int device_id) {
+    static void audioSetThreadPriority(boolean recording, int device_id) {
         try {
 
             /* Set thread name */
@@ -117,10 +117,10 @@ public class SDLAudioManager {
         }
     }
 
-    public static native int nativeSetupJNI();
+    static native int nativeSetupJNI();
 
-    public static native void removeAudioDevice(boolean recording, int deviceId);
+    static native void nativeRemoveAudioDevice(boolean recording, int deviceId);
 
-    public static native void addAudioDevice(boolean recording, String name, int deviceId);
+    static native void nativeAddAudioDevice(boolean recording, String name, int deviceId);
 
 }

+ 66 - 66
libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java

@@ -20,20 +20,20 @@ import android.view.View;
 public class SDLControllerManager
 {
 
-    public static native int nativeSetupJNI();
+    static native int nativeSetupJNI();
 
-    public static native void nativeAddJoystick(int device_id, String name, String desc,
+    static native void nativeAddJoystick(int device_id, String name, String desc,
                                                 int vendor_id, int product_id,
                                                 int button_mask,
                                                 int naxes, int axis_mask, int nhats, boolean can_rumble);
-    public static native void nativeRemoveJoystick(int device_id);
-    public static native void nativeAddHaptic(int device_id, String name);
-    public static native void nativeRemoveHaptic(int device_id);
-    public static native boolean onNativePadDown(int device_id, int keycode);
-    public static native boolean onNativePadUp(int device_id, int keycode);
-    public static native void onNativeJoy(int device_id, int axis,
+    static native void nativeRemoveJoystick(int device_id);
+    static native void nativeAddHaptic(int device_id, String name);
+    static native void nativeRemoveHaptic(int device_id);
+    static public native boolean onNativePadDown(int device_id, int keycode);
+    static public native boolean onNativePadUp(int device_id, int keycode);
+    static native void onNativeJoy(int device_id, int axis,
                                           float value);
-    public static native void onNativeHat(int device_id, int hat_id,
+    static native void onNativeHat(int device_id, int hat_id,
                                           int x, int y);
 
     protected static SDLJoystickHandler mJoystickHandler;
@@ -41,7 +41,7 @@ public class SDLControllerManager
 
     private static final String TAG = "SDLControllerManager";
 
-    public static void initialize() {
+    static void initialize() {
         if (mJoystickHandler == null) {
             if (Build.VERSION.SDK_INT >= 19 /* Android 4.4 (KITKAT) */) {
                 mJoystickHandler = new SDLJoystickHandler_API19();
@@ -62,48 +62,48 @@ public class SDLControllerManager
     }
 
     // Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance
-    public static boolean handleJoystickMotionEvent(MotionEvent event) {
+    static public boolean handleJoystickMotionEvent(MotionEvent event) {
         return mJoystickHandler.handleMotionEvent(event);
     }
 
     /**
      * This method is called by SDL using JNI.
      */
-    public static void pollInputDevices() {
+    static void pollInputDevices() {
         mJoystickHandler.pollInputDevices();
     }
 
     /**
      * This method is called by SDL using JNI.
      */
-    public static void pollHapticDevices() {
+    static void pollHapticDevices() {
         mHapticHandler.pollHapticDevices();
     }
 
     /**
      * This method is called by SDL using JNI.
      */
-    public static void hapticRun(int device_id, float intensity, int length) {
+    static void hapticRun(int device_id, float intensity, int length) {
         mHapticHandler.run(device_id, intensity, length);
     }
 
     /**
      * This method is called by SDL using JNI.
      */
-    public static void hapticRumble(int device_id, float low_frequency_intensity, float high_frequency_intensity, int length) {
+    static void hapticRumble(int device_id, float low_frequency_intensity, float high_frequency_intensity, int length) {
         mHapticHandler.rumble(device_id, low_frequency_intensity, high_frequency_intensity, length);
     }
 
     /**
      * This method is called by SDL using JNI.
      */
-    public static void hapticStop(int device_id)
+    static void hapticStop(int device_id)
     {
         mHapticHandler.stop(device_id);
     }
 
     // Check if a given device is considered a possible SDL joystick
-    public static boolean isDeviceSDLJoystick(int deviceId) {
+    static public boolean isDeviceSDLJoystick(int deviceId) {
         InputDevice device = InputDevice.getDevice(deviceId);
         // We cannot use InputDevice.isVirtual before API 16, so let's accept
         // only nonnegative device ids (VIRTUAL_KEYBOARD equals -1)
@@ -140,14 +140,14 @@ class SDLJoystickHandler {
      * @param event the event to be handled.
      * @return if given event was processed.
      */
-    public boolean handleMotionEvent(MotionEvent event) {
+    boolean handleMotionEvent(MotionEvent event) {
         return false;
     }
 
     /**
      * Handles adding and removing of input devices.
      */
-    public void pollInputDevices() {
+    void pollInputDevices() {
     }
 }
 
@@ -155,11 +155,11 @@ class SDLJoystickHandler {
 class SDLJoystickHandler_API16 extends SDLJoystickHandler {
 
     static class SDLJoystick {
-        public int device_id;
-        public String name;
-        public String desc;
-        public ArrayList<InputDevice.MotionRange> axes;
-        public ArrayList<InputDevice.MotionRange> hats;
+        int device_id;
+        String name;
+        String desc;
+        ArrayList<InputDevice.MotionRange> axes;
+        ArrayList<InputDevice.MotionRange> hats;
     }
     static class RangeComparator implements Comparator<InputDevice.MotionRange> {
         @Override
@@ -210,13 +210,13 @@ class SDLJoystickHandler_API16 extends SDLJoystickHandler {
 
     private final ArrayList<SDLJoystick> mJoysticks;
 
-    public SDLJoystickHandler_API16() {
+    SDLJoystickHandler_API16() {
 
         mJoysticks = new ArrayList<SDLJoystick>();
     }
 
     @Override
-    public void pollInputDevices() {
+    void pollInputDevices() {
         int[] deviceIds = InputDevice.getDeviceIds();
 
         for (int device_id : deviceIds) {
@@ -299,7 +299,7 @@ class SDLJoystickHandler_API16 extends SDLJoystickHandler {
     }
 
     @Override
-    public boolean handleMotionEvent(MotionEvent event) {
+    boolean handleMotionEvent(MotionEvent event) {
         int actionPointerIndex = event.getActionIndex();
         int action = event.getActionMasked();
         if (action == MotionEvent.ACTION_MOVE) {
@@ -321,7 +321,7 @@ class SDLJoystickHandler_API16 extends SDLJoystickHandler {
         return true;
     }
 
-    public String getJoystickDescriptor(InputDevice joystickDevice) {
+    String getJoystickDescriptor(InputDevice joystickDevice) {
         String desc = joystickDevice.getDescriptor();
 
         if (desc != null && !desc.isEmpty()) {
@@ -330,16 +330,16 @@ class SDLJoystickHandler_API16 extends SDLJoystickHandler {
 
         return joystickDevice.getName();
     }
-    public int getProductId(InputDevice joystickDevice) {
+    int getProductId(InputDevice joystickDevice) {
         return 0;
     }
-    public int getVendorId(InputDevice joystickDevice) {
+    int getVendorId(InputDevice joystickDevice) {
         return 0;
     }
-    public int getAxisMask(List<InputDevice.MotionRange> ranges) {
+    int getAxisMask(List<InputDevice.MotionRange> ranges) {
         return -1;
     }
-    public int getButtonMask(InputDevice joystickDevice) {
+    int getButtonMask(InputDevice joystickDevice) {
         return -1;
     }
 }
@@ -347,17 +347,17 @@ class SDLJoystickHandler_API16 extends SDLJoystickHandler {
 class SDLJoystickHandler_API19 extends SDLJoystickHandler_API16 {
 
     @Override
-    public int getProductId(InputDevice joystickDevice) {
+    int getProductId(InputDevice joystickDevice) {
         return joystickDevice.getProductId();
     }
 
     @Override
-    public int getVendorId(InputDevice joystickDevice) {
+    int getVendorId(InputDevice joystickDevice) {
         return joystickDevice.getVendorId();
     }
 
     @Override
-    public int getAxisMask(List<InputDevice.MotionRange> ranges) {
+    int getAxisMask(List<InputDevice.MotionRange> ranges) {
         // For compatibility, keep computing the axis mask like before,
         // only really distinguishing 2, 4 and 6 axes.
         int axis_mask = 0;
@@ -394,7 +394,7 @@ class SDLJoystickHandler_API19 extends SDLJoystickHandler_API16 {
     }
 
     @Override
-    public int getButtonMask(InputDevice joystickDevice) {
+    int getButtonMask(InputDevice joystickDevice) {
         int button_mask = 0;
         int[] keys = new int[] {
             KeyEvent.KEYCODE_BUTTON_A,
@@ -491,7 +491,7 @@ class SDLJoystickHandler_API19 extends SDLJoystickHandler_API16 {
 
 class SDLHapticHandler_API31 extends SDLHapticHandler {
     @Override
-    public void run(int device_id, float intensity, int length) {
+    void run(int device_id, float intensity, int length) {
         SDLHaptic haptic = getHaptic(device_id);
         if (haptic != null) {
             vibrate(haptic.vib, intensity, length);
@@ -499,7 +499,7 @@ class SDLHapticHandler_API31 extends SDLHapticHandler {
     }
 
     @Override
-    public void rumble(int device_id, float low_frequency_intensity, float high_frequency_intensity, int length) {
+    void rumble(int device_id, float low_frequency_intensity, float high_frequency_intensity, int length) {
         InputDevice device = InputDevice.getDevice(device_id);
         if (device == null) {
             return;
@@ -543,7 +543,7 @@ class SDLHapticHandler_API31 extends SDLHapticHandler {
 
 class SDLHapticHandler_API26 extends SDLHapticHandler {
     @Override
-    public void run(int device_id, float intensity, int length) {
+    void run(int device_id, float intensity, int length) {
         SDLHaptic haptic = getHaptic(device_id);
         if (haptic != null) {
             if (intensity == 0.0f) {
@@ -575,36 +575,36 @@ class SDLHapticHandler_API26 extends SDLHapticHandler {
 class SDLHapticHandler {
 
     static class SDLHaptic {
-        public int device_id;
-        public String name;
-        public Vibrator vib;
+        int device_id;
+        String name;
+        Vibrator vib;
     }
 
     private final ArrayList<SDLHaptic> mHaptics;
 
-    public SDLHapticHandler() {
+    SDLHapticHandler() {
         mHaptics = new ArrayList<SDLHaptic>();
     }
 
-    public void run(int device_id, float intensity, int length) {
+    void run(int device_id, float intensity, int length) {
         SDLHaptic haptic = getHaptic(device_id);
         if (haptic != null) {
             haptic.vib.vibrate(length);
         }
     }
 
-    public void rumble(int device_id, float low_frequency_intensity, float high_frequency_intensity, int length) {
+    void rumble(int device_id, float low_frequency_intensity, float high_frequency_intensity, int length) {
         // Not supported in older APIs
     }
 
-    public void stop(int device_id) {
+    void stop(int device_id) {
         SDLHaptic haptic = getHaptic(device_id);
         if (haptic != null) {
             haptic.vib.cancel();
         }
     }
 
-    public void pollHapticDevices() {
+    void pollHapticDevices() {
 
         final int deviceId_VIBRATOR_SERVICE = 999999;
         boolean hasVibratorService = false;
@@ -724,31 +724,31 @@ class SDLGenericMotionListener_API14 implements View.OnGenericMotionListener {
         return consumed;
     }
 
-    public boolean supportsRelativeMouse() {
+    boolean supportsRelativeMouse() {
         return false;
     }
 
-    public boolean inRelativeMode() {
+    boolean inRelativeMode() {
         return false;
     }
 
-    public boolean setRelativeMouseEnabled(boolean enabled) {
+    boolean setRelativeMouseEnabled(boolean enabled) {
         return false;
     }
 
-    public void reclaimRelativeMouseModeIfNeeded() {
+    void reclaimRelativeMouseModeIfNeeded() {
 
     }
 
-    public boolean checkRelativeEvent(MotionEvent event) {
+    boolean checkRelativeEvent(MotionEvent event) {
         return inRelativeMode();
     }
 
-    public float getEventX(MotionEvent event, int pointerIndex) {
+    float getEventX(MotionEvent event, int pointerIndex) {
         return event.getX(pointerIndex);
     }
 
-    public float getEventY(MotionEvent event, int pointerIndex) {
+    float getEventY(MotionEvent event, int pointerIndex) {
         return event.getY(pointerIndex);
     }
 
@@ -760,23 +760,23 @@ class SDLGenericMotionListener_API24 extends SDLGenericMotionListener_API14 {
     private boolean mRelativeModeEnabled;
 
     @Override
-    public boolean supportsRelativeMouse() {
+    boolean supportsRelativeMouse() {
         return true;
     }
 
     @Override
-    public boolean inRelativeMode() {
+    boolean inRelativeMode() {
         return mRelativeModeEnabled;
     }
 
     @Override
-    public boolean setRelativeMouseEnabled(boolean enabled) {
+    boolean setRelativeMouseEnabled(boolean enabled) {
         mRelativeModeEnabled = enabled;
         return true;
     }
 
     @Override
-    public float getEventX(MotionEvent event, int pointerIndex) {
+    float getEventX(MotionEvent event, int pointerIndex) {
         if (mRelativeModeEnabled && event.getToolType(pointerIndex) == MotionEvent.TOOL_TYPE_MOUSE) {
             return event.getAxisValue(MotionEvent.AXIS_RELATIVE_X, pointerIndex);
         } else {
@@ -785,7 +785,7 @@ class SDLGenericMotionListener_API24 extends SDLGenericMotionListener_API14 {
     }
 
     @Override
-    public float getEventY(MotionEvent event, int pointerIndex) {
+    float getEventY(MotionEvent event, int pointerIndex) {
         if (mRelativeModeEnabled && event.getToolType(pointerIndex) == MotionEvent.TOOL_TYPE_MOUSE) {
             return event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y, pointerIndex);
         } else {
@@ -799,17 +799,17 @@ class SDLGenericMotionListener_API26 extends SDLGenericMotionListener_API24 {
     private boolean mRelativeModeEnabled;
 
     @Override
-    public boolean supportsRelativeMouse() {
+    boolean supportsRelativeMouse() {
         return (!SDLActivity.isDeXMode() || Build.VERSION.SDK_INT >= 27 /* Android 8.1 (O_MR1) */);
     }
 
     @Override
-    public boolean inRelativeMode() {
+    boolean inRelativeMode() {
         return mRelativeModeEnabled;
     }
 
     @Override
-    public boolean setRelativeMouseEnabled(boolean enabled) {
+    boolean setRelativeMouseEnabled(boolean enabled) {
         if (!SDLActivity.isDeXMode() || Build.VERSION.SDK_INT >= 27 /* Android 8.1 (O_MR1) */) {
             if (enabled) {
                 SDLActivity.getContentView().requestPointerCapture();
@@ -824,25 +824,25 @@ class SDLGenericMotionListener_API26 extends SDLGenericMotionListener_API24 {
     }
 
     @Override
-    public void reclaimRelativeMouseModeIfNeeded() {
+    void reclaimRelativeMouseModeIfNeeded() {
         if (mRelativeModeEnabled && !SDLActivity.isDeXMode()) {
             SDLActivity.getContentView().requestPointerCapture();
         }
     }
 
     @Override
-    public boolean checkRelativeEvent(MotionEvent event) {
+    boolean checkRelativeEvent(MotionEvent event) {
         return event.getSource() == InputDevice.SOURCE_MOUSE_RELATIVE;
     }
 
     @Override
-    public float getEventX(MotionEvent event, int pointerIndex) {
+    float getEventX(MotionEvent event, int pointerIndex) {
         // Relative mouse in capture mode will only have relative for X/Y
         return event.getX(pointerIndex);
     }
 
     @Override
-    public float getEventY(MotionEvent event, int pointerIndex) {
+    float getEventY(MotionEvent event, int pointerIndex) {
         // Relative mouse in capture mode will only have relative for X/Y
         return event.getY(pointerIndex);
     }

+ 2 - 2
libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLDummyEdit.java

@@ -14,14 +14,14 @@ public class SDLDummyEdit extends View implements View.OnKeyListener
     InputConnection ic;
     int input_type;
 
-    public SDLDummyEdit(Context context) {
+    SDLDummyEdit(Context context) {
         super(context);
         setFocusableInTouchMode(true);
         setFocusable(true);
         setOnKeyListener(this);
     }
 
-    public void setInputType(int input_type) {
+    void setInputType(int input_type) {
         this.input_type = input_type;
     }
 

+ 2 - 2
libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLInputConnection.java

@@ -7,12 +7,12 @@ import android.view.*;
 import android.view.inputmethod.BaseInputConnection;
 import android.widget.EditText;
 
-public class SDLInputConnection extends BaseInputConnection
+class SDLInputConnection extends BaseInputConnection
 {
     protected EditText mEditText;
     protected String mCommittedText = "";
 
-    public SDLInputConnection(View targetView, boolean fullEditor) {
+    SDLInputConnection(View targetView, boolean fullEditor) {
         super(targetView, fullEditor);
         mEditText = new EditText(SDL.getContext());
     }

+ 8 - 7
libs/SDL3/android-project/app/src/main/java/org/libsdl/app/SDLSurface.java

@@ -40,10 +40,10 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
     protected float mWidth, mHeight;
 
     // Is SurfaceView ready for rendering
-    public boolean mIsSurfaceReady;
+    protected boolean mIsSurfaceReady;
 
     // Startup
-    public SDLSurface(Context context) {
+    protected SDLSurface(Context context) {
         super(context);
         getHolder().addCallback(this);
 
@@ -66,11 +66,11 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
         mIsSurfaceReady = false;
     }
 
-    public void handlePause() {
+    protected void handlePause() {
         enableSensor(Sensor.TYPE_ACCELEROMETER, false);
     }
 
-    public void handleResume() {
+    protected void handleResume() {
         setFocusable(true);
         setFocusableInTouchMode(true);
         requestFocus();
@@ -80,7 +80,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
         enableSensor(Sensor.TYPE_ACCELEROMETER, true);
     }
 
-    public Surface getNativeSurface() {
+    protected Surface getNativeSurface() {
         return getHolder().getSurface();
     }
 
@@ -299,7 +299,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
     }
 
     // Sensor events
-    public void enableSensor(int sensortype, boolean enabled) {
+    protected void enableSensor(int sensortype, boolean enabled) {
         // TODO: This uses getDefaultSensor - what if we have >1 accels?
         if (enabled) {
             mSensorManager.registerListener(this,
@@ -363,6 +363,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
     }
 
     // Captured pointer events for API 26.
+    @Override
     public boolean onCapturedPointerEvent(MotionEvent event)
     {
         int action = event.getActionMasked();
@@ -401,7 +402,7 @@ public class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
                     SDLActivity.onNativeMouse(button, action, x, y, true);
                     return true;
             }
-        }      
+        }
 
         return false;
     }

+ 4 - 3
libs/SDL3/build-scripts/build-release.py

@@ -1023,8 +1023,9 @@ class Releaser:
                     "cmake",
                     "-S", str(self.root),
                     "-B", str(build_dir),
-                    f'''-DCMAKE_C_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
-                    f'''-DCMAKE_CXX_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
+                    # NDK 21e does not support -ffile-prefix-map
+                    # f'''-DCMAKE_C_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
+                    # f'''-DCMAKE_CXX_FLAGS="-ffile-prefix-map={self.root}=/src/{self.project}"''',
                     f"-DCMAKE_TOOLCHAIN_FILE={cmake_toolchain_file}",
                     f"-DCMAKE_PREFIX_PATH={str(android_deps_path)}",
                     f"-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH",
@@ -1530,7 +1531,7 @@ def main(argv=None) -> int:
             parser.error("Invalid --android-api, and/or could not be detected")
         android_api_path = Path(args.android_home) / f"platforms/{args.android_api.name}"
         if not android_api_path.is_dir():
-            parser.error(f"Android API directory does not exist ({android_api_path})")
+            logger.warning(f"Android API directory does not exist ({android_api_path})")
         with section_printer.group("Android arguments"):
             print(f"android_home     = {args.android_home}")
             print(f"android_ndk_home = {args.android_ndk_home}")

+ 90 - 45
libs/SDL3/build-scripts/wikiheaders.pl

@@ -32,6 +32,7 @@ my $wikisubdir = '';
 my $incsubdir = 'include';
 my $readmesubdir = undef;
 my $apiprefixregex = undef;
+my $apipropertyregex = undef;
 my $versionfname = 'include/SDL_version.h';
 my $versionmajorregex = '\A\#define\s+SDL_MAJOR_VERSION\s+(\d+)\Z';
 my $versionminorregex = '\A\#define\s+SDL_MINOR_VERSION\s+(\d+)\Z';
@@ -43,7 +44,6 @@ my $wikiurl = 'https://wiki.libsdl.org';
 my $bugreporturl = 'https://github.com/libsdl-org/sdlwiki/issues/new';
 my $srcpath = undef;
 my $wikipath = undef;
-my $wikireadmesubdir = 'README';
 my $warn_about_missing = 0;
 my $copy_direction = 0;
 my $optionsfname = undef;
@@ -111,6 +111,7 @@ if (defined $optionsfname) {
             $srcpath = $val, next if $key eq 'srcpath';
             $wikipath = $val, next if $key eq 'wikipath';
             $apiprefixregex = $val, next if $key eq 'apiprefixregex';
+            $apipropertyregex = $val, next if $key eq 'apipropertyregex';
             $projectfullname = $val, next if $key eq 'projectfullname';
             $projectshortname = $val, next if $key eq 'projectshortname';
             $wikisubdir = $val, next if $key eq 'wikisubdir';
@@ -424,7 +425,11 @@ sub dewikify_chunk {
             $str .= "\n```$codelang\n$code\n```\n";
         }
     } elsif ($dewikify_mode eq 'manpage') {
-        $str =~ s/\./\\[char46]/gms;  # make sure these can't become control codes.
+        # make sure these can't become part of roff syntax.
+        $str =~ s/\./\\[char46]/gms;
+        $str =~ s/"/\\(dq/gms;
+        $str =~ s/'/\\(aq/gms;
+
         if ($wikitype eq 'mediawiki') {
             # Dump obvious wikilinks.
             if (defined $apiprefixregex) {
@@ -449,33 +454,52 @@ sub dewikify_chunk {
             # bullets
             $str =~ s/^\* /\n\\\(bu /gm;
         } elsif ($wikitype eq 'md') {
+            # bullets
+            $str =~ s/^\- /\n\\(bu /gm;
+            # merge paragraphs
+            $str =~ s/^[ \t]+//gm;
+            $str =~ s/([^\-\n])\n([^\-\n])/$1 $2/g;
+            $str =~ s/\n\n/\n.PP\n/g;
+
             # Dump obvious wikilinks.
             if (defined $apiprefixregex) {
-                $str =~ s/\[(\`?$apiprefixregex[a-zA-Z0-9_]+\`?)\]\($apiprefixregex[a-zA-Z0-9_]+\)/\n.BR $1\n/gms;
+                my $apr = $apiprefixregex;
+                if(!($apr =~ /\A\(.*\)\Z/s)) {
+                    # we're relying on the apiprefixregex having a capturing group.
+                    $apr = "(" . $apr . ")";
+                }
+                $str =~ s/(\S*?)\[\`?($apr[a-zA-Z0-9_]+)\`?\]\($apr[a-zA-Z0-9_]+\)(\S*)\s*/\n.BR "" "$1" "$2" "$5"\n/gm;
+                # handle cases like "[x](x), [y](y), [z](z)" being separated.
+                while($str =~ s/(\.BR[^\n]*)\n\n\.BR/$1\n.BR/gm) {}
             }
 
             # links
             $str =~ s/\[(.*?)]\((https?\:\/\/.*?)\)/\n.URL "$2" "$1"\n/g;
 
             # <code></code> is also popular.  :/
-            $str =~ s/\s*\`(.*?)\`\s*/\n.BR $1\n/gms;
+            $str =~ s/\s*(\S*?)\`([^\n]*?)\`(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
 
             # bold+italic (this looks bad, just make it bold).
-            $str =~ s/\s*\*\*\*(.*?)\*\*\*\s*/\n.B $1\n/gms;
+            $str =~ s/\s*(\S*?)\*\*\*([^\n]*?)\*\*\*(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
 
             # bold
-            $str =~ s/\s*\*\*(.*?)\*\*\s*/\n.B $1\n/gms;
+            $str =~ s/\s*(\S*?)\*\*([^\n]*?)\*\*(\S*)\s*/\n.BR "" "$1" "$2" "$3"\n/gms;
 
             # italic
-            $str =~ s/\s*\*(.*?)\*\s*/\n.I $1\n/gms;
-
-            # bullets
-            $str =~ s/^\- /\n\\\(bu /gm;
+            $str =~ s/\s*(\S*?)\*([^\n]*?)\*(\S*)\s*/\n.IR "" "$1" "$2" "$3"\n/gms;
         }
 
+        # cleanup unnecessary quotes
+        $str =~ s/(\.[IB]R?)(.*?) ""\n/$1$2\n/gm;
+        $str =~ s/(\.[IB]R?) "" ""(.*?)\n/$1$2\n/gm;
+        $str =~ s/"(\S+)"/$1/gm;
+        # cleanup unnecessary whitespace
+        $str =~ s/ +\n/\n/gm;
+
         if (defined $code) {
             $code =~ s/\A\n+//gms;
             $code =~ s/\n+\Z//gms;
+            $code =~ s/\\/\\(rs/gms;
             if ($dewikify_manpage_code_indent) {
                 $str .= "\n.IP\n"
             } else {
@@ -580,7 +604,7 @@ sub dewikify {
             $retval .= dewikify_chunk($wikitype, $1, $2, $3);
         }
     } elsif ($wikitype eq 'md') {
-        while ($str =~ s/\A(.*?)\n```(.*?)\n(.*?)\n```\n//ms) {
+        while ($str =~ s/\A(.*?)\n?```(.*?)\n(.*?)\n```\n//ms) {
             $retval .= dewikify_chunk($wikitype, $1, $2, $3);
         }
     }
@@ -803,21 +827,23 @@ sub print_big_ascii_string {
             die("Don't have a big ascii entry for '$ch'!\n") if not defined $rowsref;
             my $row = @$rowsref[$rownum];
 
+            my $outstr = '';
             if ($lowascii) {
                 my @x = split //, $row;
                 foreach (@x) {
-                    my $v = ($_ eq "\x{2588}") ? 'X' : ' ';
-                    print $fh $v;
+                    $outstr .= ($_ eq "\x{2588}") ? 'X' : ' ';
                 }
             } else {
-                print $fh $row;
+                $outstr = $row;
             }
 
             $charidx++;
-
-            if ($charidx < $charcount) {
-                print $fh " ";
+            if ($charidx == $charcount) {
+                $outstr =~ s/\s*\Z//;  # dump extra spaces at the end of the line.
+            } else {
+                $outstr .= ' ';   # space between glyphs.
             }
+            print $fh $outstr;
         }
         print $fh "\n";
     }
@@ -1011,7 +1037,6 @@ sub generate_quickref {
 my $incpath = "$srcpath";
 $incpath .= "/$incsubdir" if $incsubdir ne '';
 
-my $wikireadmepath = "$wikipath/$wikireadmesubdir";
 my $readmepath = undef;
 if (defined $readmesubdir) {
     $readmepath = "$srcpath/$readmesubdir";
@@ -1343,7 +1368,7 @@ while (my $d = readdir(DH)) {
                     # update strings now that we know everything pending is to be applied to this declaration. Add pending blank lines and the new text.
 
                     # At Sam's request, don't list property defines with functions. (See #9440)
-                    my $is_property = /\A\s*\#\s*define\s+SDL_PROP_/;
+                    my $is_property = (defined $apipropertyregex) ? /$apipropertyregex/ : 0;
                     if (!$is_property) {
                         if ($blank_lines > 0) {
                             while ($blank_lines > 0) {
@@ -2060,18 +2085,15 @@ if ($copy_direction == 1) {  # --copy-to-headers
     }
 
     if (defined $readmepath) {
-        if ( -d $wikireadmepath ) {
-            mkdir($readmepath);  # just in case
-            opendir(DH, $wikireadmepath) or die("Can't opendir '$wikireadmepath': $!\n");
-            while (readdir(DH)) {
-                my $dent = $_;
-                if ($dent =~ /\A(.*?)\.md\Z/) {  # we only bridge Markdown files here.
-                    next if $1 eq 'FrontPage';
-                    filecopy("$wikireadmepath/$dent", "$readmepath/README-$dent", "\n");
-                }
+        mkdir($readmepath);  # just in case
+        opendir(DH, $wikipath) or die("Can't opendir '$wikipath': $!\n");
+        while (readdir(DH)) {
+            my $dent = $_;
+            if ($dent =~ /\AREADME\-.*?\.md\Z/) {  # we only bridge Markdown files here that start with "README-".
+                filecopy("$wikipath/$dent", "$readmepath/$dent", "\n");
             }
-            closedir(DH);
         }
+        closedir(DH);
     }
 
 } elsif ($copy_direction == -1) { # --copy-to-wiki
@@ -2676,31 +2698,27 @@ __EOF__
     # Write out READMEs...
     if (defined $readmepath) {
         if ( -d $readmepath ) {
-            mkdir($wikireadmepath);  # just in case
+            mkdir($wikipath);  # just in case
             opendir(DH, $readmepath) or die("Can't opendir '$readmepath': $!\n");
             while (my $d = readdir(DH)) {
                 my $dent = $d;
-                if ($dent =~ /\AREADME\-(.*?\.md)\Z/) {  # we only bridge Markdown files here.
-                    my $wikifname = $1;
-                    next if $wikifname eq 'FrontPage.md';
-                    filecopy("$readmepath/$dent", "$wikireadmepath/$wikifname", "\n");
+                if ($dent =~ /\AREADME\-.*?\.md\Z/) {  # we only bridge Markdown files here that start with "README-".
+                    filecopy("$readmepath/$dent", "$wikipath/$dent", "\n");
                 }
             }
             closedir(DH);
 
             my @pages = ();
-            opendir(DH, $wikireadmepath) or die("Can't opendir '$wikireadmepath': $!\n");
+            opendir(DH, $wikipath) or die("Can't opendir '$wikipath': $!\n");
             while (my $d = readdir(DH)) {
                 my $dent = $d;
-                if ($dent =~ /\A(.*?)\.(mediawiki|md)\Z/) {
-                    my $wikiname = $1;
-                    next if $wikiname eq 'FrontPage';
-                    push @pages, $wikiname;
+                if ($dent =~ /\A(README\-.*?)\.md\Z/) {
+                    push @pages, $1;
                 }
             }
             closedir(DH);
 
-            open(FH, '>', "$wikireadmepath/FrontPage.md") or die("Can't open '$wikireadmepath/FrontPage.md': $!\n");
+            open(FH, '>', "$wikipath/READMEs.md") or die("Can't open '$wikipath/READMEs.md': $!\n");
             print FH "# All READMEs available here\n\n";
             foreach (sort @pages) {
                 my $wikiname = $_;
@@ -2765,7 +2783,6 @@ __EOF__
         my $wikitype = $wikitypes{$sym};
         my $sectionsref = $wikisyms{$sym};
         my $remarks = $sectionsref->{'Remarks'};
-        my $params = $sectionsref->{'Function Parameters'};
         my $returns = $sectionsref->{'Return Value'};
         my $version = $sectionsref->{'Version'};
         my $threadsafety = $sectionsref->{'Thread Safety'};
@@ -2773,6 +2790,23 @@ __EOF__
         my $examples = $sectionsref->{'Code Examples'};
         my $deprecated = $sectionsref->{'Deprecated'};
         my $headerfile = $manpageheaderfiletext;
+
+        my $params = undef;
+
+        if ($symtype == -1) {  # category documentation block.
+            # nothing to be done here.
+        } elsif (($symtype == 1) || (($symtype == 5))) {  # we'll assume a typedef (5) with a \param is a function pointer typedef.
+            $params = $sectionsref->{'Function Parameters'};
+        } elsif ($symtype == 2) {
+            $params = $sectionsref->{'Macro Parameters'};
+        } elsif ($symtype == 3) {
+            $params = $sectionsref->{'Fields'};
+        } elsif ($symtype == 4) {
+            $params = $sectionsref->{'Values'};
+        } else {
+            die("Unexpected symtype $symtype");
+        }
+
         $headerfile =~ s/\%fname\%/$headersymslocation{$sym}/g;
         $headerfile .= "\n";
 
@@ -2839,18 +2873,22 @@ __EOF__
             $str .= dewikify($wikitype, $deprecated) . "\n";
         }
 
+        my $incfile = $mainincludefname;
         if (defined $headerfile) {
-            $str .= ".SH HEADER FILE\n";
-            $str .= dewikify($wikitype, $headerfile) . "\n";
+            if($headerfile =~ /Defined in (.*)/) {
+                $incfile = $1;
+            }
         }
 
         $str .= ".SH SYNOPSIS\n";
         $str .= ".nf\n";
-        $str .= ".B #include \\(dq$mainincludefname\\(dq\n";
+        $str .= ".B #include <$incfile>\n";
         $str .= ".PP\n";
 
         my @decllines = split /\n/, $decl;
         foreach (@decllines) {
+            $_ =~ s/\\/\\(rs/g;  # fix multiline macro defs
+            $_ =~ s/"/\\(dq/g;
             $str .= ".BI \"$_\n";
         }
         $str .= ".fi\n";
@@ -2938,8 +2976,13 @@ __EOF__
         }
 
         if (defined $returns) {
+            # Check for md link in return type: ([SDL_Renderer](SDL_Renderer) *)
+            # This would've prevented the next regex from working properly (it'd leave " *)")
+            $returns =~ s/\A\(\[.*?\]\((.*?)\)/\($1/ms;
+            # Chop datatype in parentheses off the front.
+            $returns =~ s/\A\(.*?\) //;
+
             $returns = dewikify($wikitype, $returns);
-            $returns =~ s/\A\(.*?\)\s*//;  # Chop datatype in parentheses off the front.
             $str .= ".SH RETURN VALUE\n";
             $str .= "$returns\n";
         }
@@ -2975,6 +3018,8 @@ __EOF__
                 s/\A\/*//;
                 s/\A\.BR\s+//;  # dewikify added this, but we want to handle it.
                 s/\A\.I\s+//;  # dewikify added this, but we want to handle it.
+                s/\A\.PP\s*//;  # dewikify added this, but we want to handle it.
+                s/\\\(bu//;  # dewikify added this, but we want to handle it.
                 s/\A\s*[\:\*\-]\s*//;
                 s/\A\s+//;
                 s/\s+\Z//;

+ 1 - 0
libs/SDL3/cmake/PreseedMSVCCache.cmake

@@ -15,6 +15,7 @@ if(MSVC)
     set(HAVE_MMDEVICEAPI_H                               "1"   CACHE INTERNAL "Have include mmdeviceapi.h")
     set(HAVE_SENSORSAPI_H                                "1"   CACHE INTERNAL "Have include sensorsapi.h")
     set(HAVE_SHELLSCALINGAPI_H                           "1"   CACHE INTERNAL "Have include shellscalingapi.h")
+    set(HAVE_SHOBJIDL_CORE_H                             "1"   CACHE INTERNAL "Have include shobjidl_core.h")
     set(HAVE_TPCSHRD_H                                   "1"   CACHE INTERNAL "Have include tpcshrd.h")
     set(HAVE_WIN32_CC                                    "1"   CACHE INTERNAL "Test HAVE_WIN32_CC")
     set(HAVE_XINPUT_H                                    "1"   CACHE INTERNAL "Test HAVE_XINPUT_H")

+ 189 - 0
libs/SDL3/cmake/PreseedNokiaNGageCache.cmake

@@ -0,0 +1,189 @@
+if(NGAGESDK)
+  function(SDL_Preseed_CMakeCache)
+    set(COMPILER_SUPPORTS_ARMNEON                        ""    CACHE INTERNAL "Test COMPILER_SUPPORTS_ARMNEON")
+    set(COMPILER_SUPPORTS_FDIAGNOSTICS_COLOR_ALWAYS      ""    CACHE INTERNAL "Test COMPILER_SUPPORTS_FDIAGNOSTICS_COLOR_ALWAYS")
+    set(COMPILER_SUPPORTS_SYNC_LOCK_TEST_AND_SET         ""    CACHE INTERNAL "Test COMPILER_SUPPORTS_SYNC_LOCK_TEST_AND_SET")
+    set(HAVE_CLANG_COMMENT_BLOCK_COMMANDS                ""    CACHE INTERNAL "Test HAVE_CLANG_COMMENT_BLOCK_COMMANDS")
+    set(HAVE_ALLOCA_H                                    ""    CACHE INTERNAL "Have include alloca.h")
+    set(HAVE_LIBM                                        "1"   CACHE INTERNAL "Have library m")
+    set(HAVE_POSIX_SPAWN                                 ""    CACHE INTERNAL "Have symbol posix_spawn")
+    set(HAVE_MALLOC                                      "1"   CACHE INTERNAL "Have include malloc.h")
+    set(LIBC_HAS_ABS                                     "1"   CACHE INTERNAL "Have symbol abs")
+    set(LIBC_HAS_ACOS                                    "1"   CACHE INTERNAL "Have symbol acos")
+    set(LIBC_HAS_ACOSF                                   ""    CACHE INTERNAL "Have symbol acosf")
+    set(LIBC_HAS_ASIN                                    "1"   CACHE INTERNAL "Have symbol asin")
+    set(LIBC_HAS_ASINF                                   ""    CACHE INTERNAL "Have symbol asinf")
+    set(LIBC_HAS_ATAN                                    "1"   CACHE INTERNAL "Have symbol atan")
+    set(LIBC_HAS_ATAN2                                   "1"   CACHE INTERNAL "Have symbol atan2")
+    set(LIBC_HAS_ATAN2F                                  ""    CACHE INTERNAL "Have symbol atan2f")
+    set(LIBC_HAS_ATANF                                   ""    CACHE INTERNAL "Have symbol atanf")
+    set(LIBC_HAS_ATOF                                    ""    CACHE INTERNAL "Have symbol atof")
+    set(LIBC_HAS_ATOI                                    ""    CACHE INTERNAL "Have symbol atoi")
+    set(LIBC_HAS_BCOPY                                   "1"   CACHE INTERNAL "Have symbol bcopy")
+    set(LIBC_HAS_CALLOC                                  ""    CACHE INTERNAL "Have symbol calloc")
+    set(LIBC_HAS_CEIL                                    "1"   CACHE INTERNAL "Have symbol ceil")
+    set(LIBC_HAS_CEILF                                   ""    CACHE INTERNAL "Have symbol ceilf")
+    set(LIBC_HAS_COPYSIGN                                "1"   CACHE INTERNAL "Have symbol copysign")
+    set(LIBC_HAS_COPYSIGNF                               "1"   CACHE INTERNAL "Have symbol copysignf")
+    set(LIBC_HAS_COS                                     "1"   CACHE INTERNAL "Have symbol cos")
+    set(LIBC_HAS_COSF                                    ""    CACHE INTERNAL "Have symbol cosf")
+    set(LIBC_HAS_EXP                                     "1"   CACHE INTERNAL "Have symbol exp")
+    set(LIBC_HAS_EXPF                                    ""    CACHE INTERNAL "Have symbol expf")
+    set(LIBC_HAS_FABS                                    "1"   CACHE INTERNAL "Have symbol fabs")
+    set(LIBC_HAS_FABSF                                   "1"   CACHE INTERNAL "Have symbol fabsf")
+    set(LIBC_HAS_FLOAT_H                                 "1"   CACHE INTERNAL "Have include float.h")
+    set(LIBC_HAS_FLOOR                                   "1"   CACHE INTERNAL "Have symbol floor")
+    set(LIBC_HAS_FLOORF                                  ""    CACHE INTERNAL "Have symbol floorf")
+    set(LIBC_HAS_FMOD                                    ""    CACHE INTERNAL "Have symbol fmod")
+    set(LIBC_HAS_FMODF                                   ""    CACHE INTERNAL "Have symbol fmodf")
+    set(LIBC_HAS_FOPEN64                                 ""    CACHE INTERNAL "Have symbol fopen64")
+    set(LIBC_HAS_FREE                                    "1"   CACHE INTERNAL "Have symbol free")
+    set(LIBC_HAS_FSEEKO                                  ""    CACHE INTERNAL "Have symbol fseeko")
+    set(LIBC_HAS_FSEEKO64                                ""    CACHE INTERNAL "Have symbol fseeko64")
+    set(LIBC_HAS_GETENV                                  ""    CACHE INTERNAL "Have symbol getenv")
+    set(LIBC_HAS_ICONV_H                                 ""    CACHE INTERNAL "Have include iconv.h")
+    set(LIBC_HAS_INDEX                                   "1"   CACHE INTERNAL "Have symbol index")
+    set(LIBC_HAS_INTTYPES_H                              "1"   CACHE INTERNAL "Have include inttypes.h")
+    set(LIBC_HAS_ISINF                                   "1"   CACHE INTERNAL "Have include isinf(double)")
+    set(LIBC_ISINF_HANDLES_FLOAT                         "1"   CACHE INTERNAL "Have include isinf(float)")
+    set(LIBC_HAS_ISINFF                                  "1"   CACHE INTERNAL "Have include isinff(float)")
+    set(LIBC_HAS_ISNAN                                   "1"   CACHE INTERNAL "Have include isnan(double)")
+    set(LIBC_ISNAN_HANDLES_FLOAT                         "1"   CACHE INTERNAL "Have include isnan(float)")
+    set(LIBC_HAS_ISNANF                                  "1"   CACHE INTERNAL "Have include isnanf(float)")
+    set(LIBC_HAS_ITOA                                    ""    CACHE INTERNAL "Have symbol itoa")
+    set(LIBC_HAS_LIMITS_H                                "1"   CACHE INTERNAL "Have include limits.h")
+    set(LIBC_HAS_LOG                                     "1"   CACHE INTERNAL "Have symbol log")
+    set(LIBC_HAS_LOG10                                   ""    CACHE INTERNAL "Have symbol log10")
+    set(LIBC_HAS_LOG10F                                  ""    CACHE INTERNAL "Have symbol log10f")
+    set(LIBC_HAS_LOGF                                    ""    CACHE INTERNAL "Have symbol logf")
+    set(LIBC_HAS_LROUND                                  ""    CACHE INTERNAL "Have symbol lround")
+    set(LIBC_HAS_LROUNDF                                 ""    CACHE INTERNAL "Have symbol lroundf")
+    set(LIBC_HAS_MALLOC                                  "1"   CACHE INTERNAL "Have symbol malloc")
+    set(LIBC_HAS_MALLOC_H                                ""    CACHE INTERNAL "Have include malloc.h")
+    set(LIBC_HAS_MATH_H                                  "1"   CACHE INTERNAL "Have include math.h")
+    set(LIBC_HAS_MEMCMP                                  "1"   CACHE INTERNAL "Have symbol memcmp")
+    set(LIBC_HAS_MEMCPY                                  ""    CACHE INTERNAL "Have symbol memcpy")
+    set(LIBC_HAS_MEMMOVE                                 ""    CACHE INTERNAL "Have symbol memmove")
+    set(LIBC_HAS_MEMORY_H                                ""    CACHE INTERNAL "Have include memory.h")
+    set(LIBC_HAS_MEMSET                                  ""    CACHE INTERNAL "Have symbol memset")
+    set(LIBC_HAS_MODF                                    "1"   CACHE INTERNAL "Have symbol modf")
+    set(LIBC_HAS_MODFF                                   ""    CACHE INTERNAL "Have symbol modff")
+    set(LIBC_HAS_POW                                     "1"   CACHE INTERNAL "Have symbol pow")
+    set(LIBC_HAS_POWF                                    ""    CACHE INTERNAL "Have symbol powf")
+    set(LIBC_HAS_PUTENV                                  ""    CACHE INTERNAL "Have symbol putenv")
+    set(LIBC_HAS_REALLOC                                 ""    CACHE INTERNAL "Have symbol realloc")
+    set(LIBC_HAS_RINDEX                                  "1"   CACHE INTERNAL "Have symbol rindex")
+    set(LIBC_HAS_ROUND                                   ""    CACHE INTERNAL "Have symbol round")
+    set(LIBC_HAS_ROUNDF                                  ""    CACHE INTERNAL "Have symbol roundf")
+    set(LIBC_HAS_SCALBN                                  "1"   CACHE INTERNAL "Have symbol scalbn")
+    set(LIBC_HAS_SCALBNF                                 ""    CACHE INTERNAL "Have symbol scalbnf")
+    set(LIBC_HAS_SETENV                                  ""    CACHE INTERNAL "Have symbol setenv")
+    set(LIBC_HAS_SIGNAL_H                                ""    CACHE INTERNAL "Have include signal.h")
+    set(LIBC_HAS_SIN                                     "1"   CACHE INTERNAL "Have symbol sin")
+    set(LIBC_HAS_SINF                                    ""    CACHE INTERNAL "Have symbol sinf")
+    set(LIBC_HAS_SQR                                     ""    CACHE INTERNAL "Have symbol sqr")
+    set(LIBC_HAS_SQRT                                    "1"   CACHE INTERNAL "Have symbol sqrt")
+    set(LIBC_HAS_SQRTF                                   ""    CACHE INTERNAL "Have symbol sqrtf")
+    set(LIBC_HAS_SSCANF                                  "1"   CACHE INTERNAL "Have symbol sscanf")
+    set(LIBC_HAS_STDARG_H                                "1"   CACHE INTERNAL "Have include stdarg.h")
+    set(LIBC_HAS_STDBOOL_H                               "1"   CACHE INTERNAL "Have include stdbool.h")
+    set(LIBC_HAS_STDDEF_H                                "1"   CACHE INTERNAL "Have include stddef.h")
+    set(LIBC_HAS_STDINT_H                                "1"   CACHE INTERNAL "Have include stdint.h")
+    set(LIBC_HAS_STDIO_H                                 "1"   CACHE INTERNAL "Have include stdio.h")
+    set(LIBC_HAS_STDLIB_H                                "1"   CACHE INTERNAL "Have include stdlib.h")
+    set(LIBC_HAS_STRCASESTR                              ""    CACHE INTERNAL "Have symbol strcasestr")
+    set(LIBC_HAS_STRCHR                                  "1"   CACHE INTERNAL "Have symbol strchr")
+    set(LIBC_HAS_STRCMP                                  "1"   CACHE INTERNAL "Have symbol strcmp")
+    set(LIBC_HAS_STRINGS_H                               ""    CACHE INTERNAL "Have include strings.h")
+    set(LIBC_HAS_STRING_H                                "1"   CACHE INTERNAL "Have include string.h")
+    set(LIBC_HAS_STRLCAT                                 ""    CACHE INTERNAL "Have symbol strlcat")
+    set(LIBC_HAS_STRLCPY                                 ""    CACHE INTERNAL "Have symbol strlcpy")
+    set(LIBC_HAS_STRLEN                                  "1"   CACHE INTERNAL "Have symbol strlen")
+    set(LIBC_HAS_STRNCMP                                 "1"   CACHE INTERNAL "Have symbol strncmp")
+    set(LIBC_HAS_STRNLEN                                 ""    CACHE INTERNAL "Have symbol strnlen")
+    set(LIBC_HAS_STRNSTR                                 ""    CACHE INTERNAL "Have symbol strnstr")
+    set(LIBC_HAS_STRPBRK                                 "1"   CACHE INTERNAL "Have symbol strpbrk")
+    set(LIBC_HAS_STRRCHR                                 "1"   CACHE INTERNAL "Have symbol strrchr")
+    set(LIBC_HAS_STRSTR                                  "1"   CACHE INTERNAL "Have symbol strstr")
+    set(LIBC_HAS_STRTOD                                  ""    CACHE INTERNAL "Have symbol strtod")
+    set(LIBC_HAS_STRTOK_R                                ""    CACHE INTERNAL "Have symbol strtok_r")
+    set(LIBC_HAS_STRTOL                                  ""    CACHE INTERNAL "Have symbol strtol")
+    set(LIBC_HAS_STRTOLL                                 ""    CACHE INTERNAL "Have symbol strtoll")
+    set(LIBC_HAS_STRTOUL                                 ""    CACHE INTERNAL "Have symbol strtoul")
+    set(LIBC_HAS_STRTOULL                                ""    CACHE INTERNAL "Have symbol strtoull")
+    set(LIBC_HAS_SYS_TYPES_H                             "1"   CACHE INTERNAL "Have include sys/types.h")
+    set(LIBC_HAS_TAN                                     "1"   CACHE INTERNAL "Have symbol tan")
+    set(LIBC_HAS_TANF                                    ""    CACHE INTERNAL "Have symbol tanf")
+    set(LIBC_HAS_TIME_H                                  "1"   CACHE INTERNAL "Have include time.h")
+    set(LIBC_HAS_TRUNC                                   ""    CACHE INTERNAL "Have symbol trunc")
+    set(LIBC_HAS_TRUNCF                                  ""    CACHE INTERNAL "Have symbol truncf")
+    set(LIBC_HAS_UNSETENV                                ""    CACHE INTERNAL "Have symbol unsetenv")
+    set(LIBC_HAS_VSNPRINTF                               ""    CACHE INTERNAL "Have symbol vsnprintf")
+    set(LIBC_HAS_VSSCANF                                 ""    CACHE INTERNAL "Have symbol vsscanf")
+    set(LIBC_HAS_WCHAR_H                                 "1"   CACHE INTERNAL "Have include wchar.h")
+    set(LIBC_HAS_WCSCMP                                  ""    CACHE INTERNAL "Have symbol wcscmp")
+    set(LIBC_HAS_WCSDUP                                  ""    CACHE INTERNAL "Have symbol wcsdup")
+    set(LIBC_HAS_WCSLCAT                                 ""    CACHE INTERNAL "Have symbol wcslcat")
+    set(LIBC_HAS_WCSLCPY                                 ""    CACHE INTERNAL "Have symbol wcslcpy")
+    set(LIBC_HAS_WCSLEN                                  ""    CACHE INTERNAL "Have symbol wcslen")
+    set(LIBC_HAS_WCSNCMP                                 ""    CACHE INTERNAL "Have symbol wcsncmp")
+    set(LIBC_HAS_WCSNLEN                                 ""    CACHE INTERNAL "Have symbol wcsnlen")
+    set(LIBC_HAS_WCSSTR                                  ""    CACHE INTERNAL "Have symbol wcsstr")
+    set(LIBC_HAS_WCSTOL                                  ""    CACHE INTERNAL "Have symbol wcstol")
+    set(LIBC_HAS__EXIT                                   ""    CACHE INTERNAL "Have symbol _Exit")
+    set(LIBC_HAS__I64TOA                                 ""    CACHE INTERNAL "Have symbol _i64toa")
+    set(LIBC_HAS__LTOA                                   ""    CACHE INTERNAL "Have symbol _ltoa")
+    set(LIBC_HAS__STRREV                                 ""    CACHE INTERNAL "Have symbol _strrev")
+    set(LIBC_HAS__UI64TOA                                ""    CACHE INTERNAL "Have symbol _ui64toa")
+    set(LIBC_HAS__UITOA                                  ""    CACHE INTERNAL "Have symbol _uitoa")
+    set(LIBC_HAS__ULTOA                                  ""    CACHE INTERNAL "Have symbol _ultoa")
+    set(LIBC_HAS__WCSDUP                                 ""    CACHE INTERNAL "Have symbol _wcsdup")
+    set(LIBC_IS_GLIBC                                    ""    CACHE INTERNAL "Have symbol __GLIBC__")
+    set(_ALLOCA_IN_MALLOC_H                              ""    CACHE INTERNAL "Have symbol _alloca")
+    set(HAVE_GCC_WALL                                    "1"   CACHE INTERNAL "Test HAVE_GCC_WALL")
+    set(HAVE_GCC_WUNDEF                                  "1"   CACHE INTERNAL "Test HAVE_GCC_WUNDEF")
+    set(HAVE_GCC_WFLOAT_CONVERSION                       ""    CACHE INTERNAL "Test HAVE_GCC_WFLOAT_CONVERSION")
+    set(HAVE_GCC_NO_STRICT_ALIASING                      "1"   CACHE INTERNAL "Test HAVE_GCC_NO_STRICT_ALIASING")
+    set(HAVE_GCC_WDOCUMENTATION                          ""    CACHE INTERNAL "Test HAVE_GCC_WDOCUMENTATION")
+    set(HAVE_GCC_WDOCUMENTATION_UNKNOWN_COMMAND          ""    CACHE INTERNAL "Test HAVE_GCC_WDOCUMENTATION_UNKNOWN_COMMAND")
+    set(HAVE_GCC_COMMENT_BLOCK_COMMANDS                  ""    CACHE INTERNAL "Test HAVE_GCC_COMMENT_BLOCK_COMMANDS")
+    set(HAVE_GCC_WSHADOW                                 "1"   CACHE INTERNAL "Test HAVE_GCC_WSHADOW")
+    set(HAVE_GCC_WUNUSED_LOCAL_TYPEDEFS                  ""    CACHE INTERNAL "Test HAVE_GCC_WUNUSED_LOCAL_TYPEDEFS")
+    set(HAVE_GCC_WIMPLICIT_FALLTHROUGH                   ""    CACHE INTERNAL "Test HAVE_GCC_WIMPLICIT_FALLTHROUGH")
+    set(HAVE_GCC_FVISIBILITY                             ""    CACHE INTERNAL "Test HAVE_GCC_FVISIBILITY")
+    set(HAVE_ST_MTIM                                     ""    CACHE INTERNAL "Test HAVE_ST_MTIM")
+    #set(HAVE_O_CLOEXEC                                   ""    CACHE INTERNAL "Test HAVE_O_CLOEXEC")
+    #set(COMPILER_SUPPORTS_FDIAGNOSTICS_COLOR             ""    CACHE INTERNAL "Test COMPILER_SUPPORTS_FDIAGNOSTICS_COLOR")
+    set(COMPILER_SUPPORTS_GCC_ATOMICS                    ""    CACHE INTERNAL "Test COMPILER_SUPPORTS_GCC_ATOMICS")
+    set(LINKER_SUPPORTS_VERSION_SCRIPT                   ""    CACHE INTERNAL "Test LINKER_SUPPORTS_VERSION_SCRIPT")
+    set(LINKER_SUPPORTS_WL_NO_UNDEFINED                  ""    CACHE INTERNAL "Test LINKER_SUPPORTS_WL_NO_UNDEFINED")
+    set(ICONV_IN_LIBC                                    ""    CACHE INTERNAL "Test ICONV_IN_LIBC")
+    set(ICONV_IN_LIBICONV                                ""    CACHE INTERNAL "Test ICONV_IN_LIBICONV")
+    #set(LIBC_HAS_WORKING_LIBUNWIND                       ""    CACHE INTERNAL "Test LIBC_HAS_WORKING_LIBUNWIND")
+    #set(LIBUNWIND_HAS_WORKINGLIBUNWIND                   ""    CACHE INTERNAL "Test LIBUNWIND_HAS_WORKINGLIBUNWIND")
+    set(HAVE_GETPAGESIZE                                 ""    CACHE INTERNAL "Have symbol getpagesize")
+    set(HAVE_SIGACTION                                   ""    CACHE INTERNAL "Have symbol sigaction")
+    set(HAVE_SA_SIGACTION                                ""    CACHE INTERNAL "Have symbol sa_sigaction")
+    set(HAVE_SETJMP                                      ""    CACHE INTERNAL "Have symbol setjmp")
+    set(HAVE_NANOSLEEP                                   ""    CACHE INTERNAL "Have symbol nanosleep")
+    set(HAVE_GMTIME_R                                    ""    CACHE INTERNAL "Have symbol gmtime_r")
+    set(HAVE_LOCALTIME_R                                 ""    CACHE INTERNAL "Have symbol localtime_r")
+    set(HAVE_NL_LANGINFO                                 ""    CACHE INTERNAL "Have symbol nl_langinfo")
+    set(HAVE_SYSCONF                                     ""    CACHE INTERNAL "Have symbol sysconf")
+    set(HAVE_SYSCTLBYNAME                                ""    CACHE INTERNAL "Have symbol sysctlbyname")
+    set(HAVE_GETAUXVAL                                   ""    CACHE INTERNAL "Have symbol getauxval")
+    set(HAVE_ELF_AUX_INFO                                ""    CACHE INTERNAL "Have symbol elf_aux_info")
+    set(HAVE_POLL                                        ""    CACHE INTERNAL "Have symbol poll")
+    set(HAVE_MEMFD_CREATE                                ""    CACHE INTERNAL "Have symbol memfd_create")
+    set(HAVE_POSIX_FALLOCATE                             ""    CACHE INTERNAL "Have symbol posix_fallocate")
+    set(HAVE_DLOPEN_IN_LIBC                              ""    CACHE INTERNAL "Have symbol dlopen")
+
+    set(HAVE_GETHOSTNAME                                 ""    CACHE INTERNAL "Have symbol gethostname")
+    set(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR           ""    CACHE INTERNAL "Have symbol addchdir")
+    set(HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP        ""    CACHE INTERNAL "Have symbol addchdir_np")
+    set(HAVE_FDATASYNC                                   ""    CACHE INTERNAL "Have symbol fdatasync")
+
+    set(HAVE_SDL_FSOPS                                   "1"   CACHE INTERNAL "Enable SDL_FSOPS")
+    set(HAVE_SDL_LOCALE                                  "1"   CACHE INTERNAL "Enable SDL_LOCALE")
+  endfunction()
+endif()

+ 0 - 3
libs/SDL3/cmake/macros.cmake

@@ -362,9 +362,6 @@ function(SDL_PrintSummary)
   message(STATUS "")
   message(STATUS " Build Shared Library: ${SDL_SHARED}")
   message(STATUS " Build Static Library: ${SDL_STATIC}")
-  if(SDL_STATIC)
-    message(STATUS " Build Static Library with Position Independent Code: ${SDL_STATIC_PIC}")
-  endif()
   if(APPLE)
     message(STATUS " Build libraries as Apple Framework: ${SDL_FRAMEWORK}")
   endif()

+ 38 - 6
libs/SDL3/cmake/sdlchecks.cmake

@@ -1,3 +1,10 @@
+macro(check_c_source_compiles_static SOURCE VAR)
+  set(saved_CMAKE_TRY_COMPILE_TARGET_TYPE "${CMAKE_TRY_COMPILE_TARGET_TYPE}")
+  set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY")
+  check_c_source_compiles("${SOURCE}" ${VAR} ${ARGN})
+  set(CMAKE_TRY_COMPILE_TARGET_TYPE "${saved_CMAKE_TRY_COMPILE_TARGET_TYPE}")
+endmacro()
+
 macro(FindLibraryAndSONAME _LIB)
   cmake_parse_arguments(_FLAS "" "" "LIBDIRS" ${ARGN})
 
@@ -274,10 +281,11 @@ macro(CheckX11)
     set(Xrandr_PKG_CONFIG_SPEC xrandr)
     set(Xrender_PKG_CONFIG_SPEC xrender)
     set(Xss_PKG_CONFIG_SPEC xscrnsaver)
+    set(Xtst_PKG_CONFIG_SPEC xtst)
 
     find_package(X11)
 
-    foreach(_LIB X11 Xext Xcursor Xi Xfixes Xrandr Xrender Xss)
+    foreach(_LIB X11 Xext Xcursor Xi Xfixes Xrandr Xrender Xss Xtst)
       get_filename_component(_libdir "${X11_${_LIB}_LIB}" DIRECTORY)
       FindLibraryAndSONAME("${_LIB}" LIBDIRS ${_libdir})
     endforeach()
@@ -310,6 +318,7 @@ macro(CheckX11)
     find_file(HAVE_XSYNC_H NAMES "X11/extensions/sync.h" HINTS "${X11_INCLUDEDIR}")
     find_file(HAVE_XSS_H NAMES "X11/extensions/scrnsaver.h" HINTS "${X11_INCLUDEDIR}")
     find_file(HAVE_XSHAPE_H NAMES "X11/extensions/shape.h" HINTS "${X11_INCLUDEDIR}")
+    find_file(HAVE_XTEST_H NAMES "X11/extensions/XTest.h" HINTS "${X11_INCLUDEDIR}")
     find_file(HAVE_XDBE_H NAMES "X11/extensions/Xdbe.h" HINTS "${X11_INCLUDEDIR}")
     find_file(HAVE_XEXT_H NAMES "X11/extensions/Xext.h" HINTS "${X11_INCLUDEDIR}")
 
@@ -367,7 +376,7 @@ macro(CheckX11)
 
       list(APPEND CMAKE_REQUIRED_LIBRARIES ${X11_LIB})
 
-      check_c_source_compiles("
+      check_c_source_compiles_static("
           #include <X11/Xlib.h>
           int main(int argc, char **argv) {
             Display *display;
@@ -408,7 +417,7 @@ macro(CheckX11)
         set(SDL_VIDEO_DRIVER_X11_XINPUT2 1)
 
         # Check for multitouch
-        check_c_source_compiles("
+        check_c_source_compiles_static("
             #include <X11/Xlib.h>
             #include <X11/Xproto.h>
             #include <X11/extensions/XInput2.h>
@@ -425,7 +434,7 @@ macro(CheckX11)
 
       # check along with XInput2.h because we use Xfixes with XIBarrierReleasePointer
       if(SDL_X11_XFIXES AND HAVE_XFIXES_H_ AND HAVE_XINPUT2_H)
-        check_c_source_compiles("
+        check_c_source_compiles_static("
             #include <X11/Xlib.h>
             #include <X11/Xproto.h>
             #include <X11/extensions/XInput2.h>
@@ -472,6 +481,16 @@ macro(CheckX11)
         set(SDL_VIDEO_DRIVER_X11_XSHAPE 1)
         set(HAVE_X11_XSHAPE TRUE)
       endif()
+
+      if(SDL_X11_XTEST AND HAVE_XTEST_H AND XTST_LIB)
+        if(HAVE_X11_SHARED)
+          set(SDL_VIDEO_DRIVER_X11_DYNAMIC_XTEST "\"${XTST_LIB_SONAME}\"")
+        else()
+          sdl_link_dependency(xtst LIBS X11::Xtst CMAKE_MODULE X11 PKG_CONFIG_SPECS ${Xtst_PKG_CONFIG_SPEC})
+        endif()
+        set(SDL_VIDEO_DRIVER_X11_XTEST 1)
+        set(HAVE_X11_XTEST TRUE)
+      endif()
     endif()
   endif()
   if(NOT HAVE_X11)
@@ -575,6 +594,18 @@ macro(CheckWayland)
         sdl_link_dependency(wayland LIBS PkgConfig::PC_WAYLAND PKG_CONFIG_PREFIX PC_WAYLAND PKG_CONFIG_SPECS ${WAYLAND_PKG_CONFIG_SPEC})
       endif()
 
+      # xkbcommon doesn't provide internal version defines, so generate them here.
+      if (PC_WAYLAND_xkbcommon_VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)")
+        set(SDL_XKBCOMMON_VERSION_MAJOR ${CMAKE_MATCH_1})
+        set(SDL_XKBCOMMON_VERSION_MINOR ${CMAKE_MATCH_2})
+        set(SDL_XKBCOMMON_VERSION_PATCH ${CMAKE_MATCH_3})
+      else()
+        message(WARNING "Failed to parse xkbcommon version; defaulting to lowest supported (0.5.0)")
+        set(SDL_XKBCOMMON_VERSION_MAJOR 0)
+        set(SDL_XKBCOMMON_VERSION_MINOR 5)
+        set(SDL_XKBCOMMON_VERSION_PATCH 0)
+      endif()
+
       if(SDL_WAYLAND_LIBDECOR)
         set(LibDecor_PKG_CONFIG_SPEC libdecor-0)
         pkg_check_modules(PC_LIBDECOR IMPORTED_TARGET ${LibDecor_PKG_CONFIG_SPEC})
@@ -795,7 +826,7 @@ endmacro()
 macro(CheckPTHREAD)
   cmake_push_check_state()
   if(SDL_PTHREADS)
-    if(ANDROID)
+    if(ANDROID OR SDL_PTHREADS_PRIVATE)
       # the android libc provides built-in support for pthreads, so no
       # additional linking or compile flags are necessary
     elseif(LINUX)
@@ -1085,7 +1116,7 @@ macro(CheckHIDAPI)
       if(LibUSB_FOUND)
         cmake_push_check_state()
         list(APPEND CMAKE_REQUIRED_LIBRARIES LibUSB::LibUSB)
-        check_c_source_compiles("
+        check_c_source_compiles_static("
           #include <stddef.h>
           #include <libusb.h>
           int main(int argc, char **argv) {
@@ -1124,6 +1155,7 @@ macro(CheckHIDAPI)
         set(HAVE_SDL_JOYSTICK TRUE)
         set(HAVE_HIDAPI_JOYSTICK TRUE)
         sdl_glob_sources("${SDL3_SOURCE_DIR}/src/joystick/hidapi/*.c")
+        sdl_glob_sources("${SDL3_SOURCE_DIR}/src/haptic/hidapi/*.c")
       endif()
     else()
       set(SDL_HIDAPI_DISABLED 1)

+ 0 - 0
libs/SDL3/cmake/sdltargets.cmake → libs/SDL3/cmake/sdlcommands.cmake


+ 3 - 3
libs/SDL3/cmake/sdlcpu.cmake

@@ -4,15 +4,15 @@ function(SDL_DetectTargetCPUArchitectures DETECTED_ARCHS)
 
   if(APPLE AND CMAKE_OSX_ARCHITECTURES)
     foreach(known_arch IN LISTS known_archs)
-      set(SDL_CPU_${known_arch} "0")
+      set(SDL_CPU_${known_arch} "0" PARENT_SCOPE)
     endforeach()
     set(detected_archs)
     foreach(osx_arch IN LISTS CMAKE_OSX_ARCHITECTURES)
       if(osx_arch STREQUAL "x86_64")
-        set(SDL_CPU_X64 "1")
+        set(SDL_CPU_X64 "1" PARENT_SCOPE)
         list(APPEND detected_archs "X64")
       elseif(osx_arch STREQUAL "arm64")
-        set(SDL_CPU_ARM64 "1")
+        set(SDL_CPU_ARM64 "1" PARENT_SCOPE)
         list(APPEND detected_archs "ARM64")
       endif()
     endforeach()

+ 2 - 0
libs/SDL3/cmake/sdlplatform.cmake

@@ -22,6 +22,8 @@ function(SDL_DetectCMakePlatform)
     set(sdl_cmake_platform Haiku)
   elseif(NINTENDO_3DS)
     set(sdl_cmake_platform n3ds)
+  elseif(NGAGESDK)
+    set(sdl_cmake_platform ngage)
   elseif(PS2)
     set(sdl_cmake_platform ps2)
   elseif(VITA)

+ 8 - 6
libs/SDL3/cmake/test/CMakeLists.txt

@@ -96,12 +96,14 @@ if(TEST_STATIC)
     add_executable(gui-static WIN32 main_gui.c)
     target_link_libraries(gui-static PRIVATE SDL3::SDL3-static)
 
-    # Assume SDL library has been built with `set(CMAKE_POSITION_INDEPENDENT_CODE ON)`
-    add_library(sharedlib-static SHARED main_lib.c)
-    target_link_libraries(sharedlib-static PRIVATE SDL3::SDL3-static)
-    generate_export_header(sharedlib-static EXPORT_MACRO_NAME MYLIBRARY_EXPORT)
-    target_compile_definitions(sharedlib-static PRIVATE "EXPORT_HEADER=\"${CMAKE_CURRENT_BINARY_DIR}/sharedlib-static_export.h\"")
-    set_target_properties(sharedlib-static PROPERTIES C_VISIBILITY_PRESET "hidden")
+    if(TEST_SHARED)
+        # Assume SDL library has been built with `set(CMAKE_POSITION_INDEPENDENT_CODE ON)`
+        add_library(sharedlib-static SHARED main_lib.c)
+        target_link_libraries(sharedlib-static PRIVATE SDL3::SDL3-static)
+        generate_export_header(sharedlib-static EXPORT_MACRO_NAME MYLIBRARY_EXPORT)
+        target_compile_definitions(sharedlib-static PRIVATE "EXPORT_HEADER=\"${CMAKE_CURRENT_BINARY_DIR}/sharedlib-static_export.h\"")
+        set_target_properties(sharedlib-static PROPERTIES C_VISIBILITY_PRESET "hidden")
+    endif()
 
     if(TEST_TEST)
         add_executable(sdltest-static sdltest.c)

+ 24 - 11
libs/SDL3/cmake/test/main_gui.c

@@ -1,24 +1,37 @@
-#include <SDL3/SDL.h>
+#define SDL_MAIN_USE_CALLBACKS
 #include <SDL3/SDL_main.h>
+#include <SDL3/SDL.h>
+
+static SDL_Window *window;
 
-int main(int argc, char *argv[])
+SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
+{
+    return SDL_APP_CONTINUE;
+}
+
+SDL_AppResult SDL_AppIterate(void *appstate)
 {
-    SDL_Window *window = NULL;
     SDL_Surface *screenSurface = NULL;
+    screenSurface = SDL_GetWindowSurface(window);
+    SDL_FillSurfaceRect(screenSurface, NULL, SDL_MapSurfaceRGB(screenSurface, 0xff, 0xff, 0xff));
+    SDL_UpdateWindowSurface(window);
+    return SDL_APP_CONTINUE;
+}
+
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
+{
     if (!SDL_Init(SDL_INIT_VIDEO)) {
         SDL_Log("Could not initialize SDL: %s", SDL_GetError());
-        return 1;
+        return SDL_APP_FAILURE;
     }
     window = SDL_CreateWindow("Hello SDL", 640, 480, 0);
     if (!window) {
         SDL_Log("could not create window: %s", SDL_GetError());
-        return 1;
+        return SDL_APP_FAILURE;
     }
-    screenSurface = SDL_GetWindowSurface(window);
-    SDL_FillSurfaceRect(screenSurface, NULL, SDL_MapSurfaceRGB(screenSurface, 0xff, 0xff, 0xff));
-    SDL_UpdateWindowSurface(window);
-    SDL_Delay(100);
+    return SDL_APP_CONTINUE;
+}
+
+void SDL_AppQuit(void *appstate, SDL_AppResult result) {
     SDL_DestroyWindow(window);
-    SDL_Quit();
-    return 0;
 }

+ 17 - 2
libs/SDL3/cmake/test/sdltest.c

@@ -1,9 +1,24 @@
+#define SDL_MAIN_USE_CALLBACKS
 #include <SDL3/SDL.h>
+#include <SDL3/SDL_main.h>
 #include <SDL3/SDL_test.h>
 
+SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
+{
+    return SDL_APP_SUCCESS;
+}
+
+SDL_AppResult SDL_AppIterate(void *appstate)
+{
+    return SDL_APP_SUCCESS;
+}
 
-int main(int argc, char *argv[]) {
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
+{
     SDLTest_CommonState state;
     SDLTest_CommonDefaultArgs(&state, argc, argv);
-    return 0;
+    return SDL_APP_SUCCESS;
+}
+
+void SDL_AppQuit(void *appstate, SDL_AppResult result) {
 }

+ 1 - 1
libs/SDL3/docs/README-android.md

@@ -149,7 +149,7 @@ target_link_libraries(yourgame PRIVATE SDL3::SDL3)
 
 If you use ndk-build, add the following before `include $(BUILD_SHARED_LIBRARY)` to your `Android.mk`:
 ```
-LOCAL_SHARED_LIBARARIES := SDL3 SDL3-Headers
+LOCAL_SHARED_LIBRARIES := SDL3 SDL3-Headers
 ```
 And add the following at the bottom:
 ```

+ 4 - 4
libs/SDL3/docs/README-cmake.md

@@ -157,7 +157,7 @@ flags to the compiler.
 - Use [`CMAKE_EXE_LINKER_FLAGS`](https://cmake.org/cmake/help/latest/variable/CMAKE_EXE_LINKER_FLAGS.html) to pass extra option to the linker for executables.
 - Use [`CMAKE_SHARED_LINKER_FLAGS`](https://cmake.org/cmake/help/latest/variable/CMAKE_SHARED_LINKER_FLAGS.html) to pass extra options to the linker for shared libraries.
 
-#### Examples
+#### Compile Options Examples
 
 - build a SDL library optimized for (more) modern x64 microprocessor architectures.
 
@@ -240,7 +240,7 @@ Append with a version number to target a specific SDK revision: e.g. `iphoneos12
 
 CMake documentation: [link](https://cmake.org/cmake/help/latest/variable/CMAKE_OSX_SYSROOT.html)
 
-#### Examples
+#### Apple Examples
 
 - for macOS, building a dylib and/or static library for x86_64 and arm64:
 
@@ -328,8 +328,8 @@ Configure your project with `-DSDL_LIBC=ON` to make use of sanitizers.
 ### CMake fails to build without X11 or Wayland support
 
 Install the required system packages prior to running CMake.
-See [README-linux](linux#build-dependencies) for the list of dependencies on Linux.
-Other unix operationg systems should provide similar packages.
+See [README-linux.md](README-linux.md#build-dependencies) for the list of dependencies on Linux.
+Other unix operating systems should provide similar packages.
 
 If you **really** don't need to show windows, add `-DSDL_UNIX_CONSOLE_BUILD=ON` to the CMake configure command.
 

+ 39 - 1
libs/SDL3/docs/README-documentation-rules.md

@@ -34,6 +34,12 @@ things, you might confuse it. This is to the benefit of documentation, though,
 where we would rather you not do surprising things.
 
 
+## UTF-8 only!
+
+All text must be UTF-8 encoded. The wiki will refuse to update files that are
+malformed.
+
+
 ## We _sort of_ write in Doxygen format.
 
 To document a symbol, we use something that looks like Doxygen (and Javadoc)
@@ -156,6 +162,23 @@ wikiheaders will wordwrap header comments so they fit in 80 columns, so if you
 don't leave a blank line between paragraphs, they will smush into a single
 block of text when wordwrapping.
 
+## Lists must be the start of a new paragraph.
+
+If you write this:
+
+```
+Here is some text without a blank line
+before an unordered list!
+- item a
+- item b
+- item c
+```
+
+...then wikiheaders will word wrap this as a single paragraph, mangling the list.
+
+Put a blank line before the list, and everything will format and wrap correctly.
+
+This is a limitation of wikiheaders. Don't get bit by it!
 
 ## Don't worry about word wrapping.
 
@@ -304,6 +327,21 @@ to the headers:
 - "Version"
 - "See Also"
 
+## Unrecognized sections are removed from the headers!
+
+If you add Doxygen with a `##` (`###`, etc) section header, it'll
+migrate to the wiki and be _removed_ from the headers. Generally
+the correct thing to do is _never use section headers in the Doxygen_.
+
+## wikiheaders will reorder standard sections.
+
+The standard sections are always kept in a consistent order by
+wikiheaders, both in the headers and the wiki. If they're placed in
+a non-standard order, wikiheaders will reorder them.
+
+For sections that aren't standard, wikiheaders will place them at
+the end of the wiki page, in the order they were seen when it loaded
+the page for processing.
 
 ## It's okay to repeat yourself.
 
@@ -318,7 +356,7 @@ through, header users can search for the function name.
 
 You might be reading this document on the wiki! Any `README-*.md` files in
 the docs directory are bridged to the wiki, so `docs/README-linux.md` lands
-at https://wiki.libsdl.org/SDL3/README/linux ...these are just copied directly
+at https://wiki.libsdl.org/SDL3/README-linux ...these are just copied directly
 without any further processing by wikiheaders, and changes go in both
 directions.
 

+ 2 - 2
libs/SDL3/docs/README-emscripten.md

@@ -103,7 +103,7 @@ getting started.
 
 Another option is to use SDL' main callbacks, which handle this for you
 without platform-specific code in your app. Please refer to
-[the wiki](https://wiki.libsdl.org/SDL3/README/main-functions#main-callbacks-in-sdl3)
+[the wiki](https://wiki.libsdl.org/SDL3/README-main-functions#main-callbacks-in-sdl3)
 or `docs/README-main-functions.md` in the SDL source code.
 
 
@@ -230,7 +230,7 @@ tools.
 mkdir build
 cd build
 emcmake cmake ..
-# you can also do `emcmake cmake -G Ninja ..` and then use `ninja` instead of this command.
+# you can also try `emcmake cmake -G Ninja ..` and then use `ninja` instead of this command.
 emmake make -j4
 ```
 

+ 28 - 24
libs/SDL3/docs/README-highdpi.md

@@ -1,36 +1,40 @@
 
 SDL 3.0 has new support for high DPI displays. Interfaces provided by SDL uses the platform's native coordinates unless otherwise specified.
 
-To reconcile platform differences in their approach to high-density scaling, SDL provides the following interfaces:
-- `SDL_GetWindowSize()`          retrieves the window dimensions in native coordinates.
-- `SDL_GetWindowSizeInPixels()`  retrieves the window dimensions in pixels-addressable.
-- `SDL_GetDisplayContentScale()` retrieves the suggested amplification factor when drawing in native coordinates.
-- `SDL_GetWindowDisplayScale()`  retrieves the suggested amplification factor when drawing in pixels-addressable.
-- `SDL_GetWindowPixelDensity()`  retrieves how many addressable pixels correspond to one unit of native coordinates.
-- `SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED`    is emitted when the value retrievable from `SDL_GetWindowSizeInPixels()` changes.
-- `SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED` is emitted when the value retrievable from `SDL_GetWindowDisplayScale()` changes.
-- Windows created with `SDL_WINDOW_HIGH_PIXEL_DENSITY` will ask the platform to display addressable pixels at their natural scale.
+## Explanation
+
+Displays now have a content display scale, which is the expected scale for content based on the DPI settings of the display. For example, a 4K display might have a 2.0 (200%) display scale, which means that the user expects UI elements to be twice as big on this display, to aid in readability. You can query the display content scale using `SDL_GetDisplayContentScale()`, and when this changes you get an `SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED` event.
+
+The window size is now distinct from the window pixel size, and the ratio between the two is the window pixel density. If the window is created with the `SDL_WINDOW_HIGH_PIXEL_DENSITY` flag, SDL will try to match the native pixel density for the display, otherwise it will try to have the pixel size match the window size. You can query the window pixel density using `SDL_GetWindowPixelDensity()`. You can query the window pixel size using `SDL_GetWindowSizeInPixels()`, and when this changes you get an `SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED` event. You are guaranteed to get a `SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED` event when a window is created and resized, and you can use this event to create and resize your graphics context for the window.
+
+The window has a display scale, which is the scale from the pixel resolution to the desired content size, e.g. the combination of the pixel density and the content scale. For example, a 3840x2160 window displayed at 200% on Windows, and a 1920x1080 window with the high density flag on a 2x display on macOS will both have a pixel size of 3840x2160 and a display scale of 2.0.  You can query the window display scale using `SDL_GetWindowDisplayScale()`, and when this changes you get an `SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED` event.
 
 ## Numeric example
 
-Given a fullscreen window spanning a 3840x2160 monitor set to 2x display or 200% scaling, the following tabulates the effect of creating a window with or without `SDL_WINDOW_HIGH_PIXEL_DENSITY` on MacOS and Win32:
+Given a window spanning a 3840x2160 monitor set to 2x display or 200% scaling, the following tabulates the effect of creating a window with or without `SDL_WINDOW_HIGH_PIXEL_DENSITY` on macOS and Windows:
 
-| Value                          | MacOS (Default) | MacOS (HD) | Win32 (Default & HD) |
-|--------------------------------|-----------------|------------|----------------------|
-| `SDL_GetWindowSize()`          | 1920x1080       | 1920x1080  | 3840x2160            |
-| `SDL_GetWindowSizeInPixels()`  | 1920x1080       | 3840x2160  | 3840x2160            |
-| `SDL_GetDisplayContentScale()` | 1.0             | 1.0        | 2.0                  |
-| `SDL_GetWindowDisplayScale()`  | 1.0             | 2.0        | 2.0                  |
-| `SDL_GetWindowPixelDensity()`  | 1.0             | 2.0        | 1.0                  |
+| Value                          | macOS (Default) | macOS (HD) | Windows (Default & HD) |
+|--------------------------------|-----------------|------------|------------------------|
+| `SDL_GetWindowSize()`          | 1920x1080       | 1920x1080  | 3840x2160              |
+| `SDL_GetWindowSizeInPixels()`  | 1920x1080       | 3840x2160  | 3840x2160              |
+| `SDL_GetDisplayContentScale()` | 1.0             | 1.0        | 2.0                    |
+| `SDL_GetWindowDisplayScale()`  | 1.0             | 2.0        | 2.0                    |
+| `SDL_GetWindowPixelDensity()`  | 1.0             | 2.0        | 1.0                    |
 
-Observe the philosophical difference between the approaches taken by MacOS and Win32:
-- Win32 coordinate system always deals in physical device pixels, high DPI support is achieved by providing an advisory hint for the developer to enlarge drawn objects. Ignoring the advisory scale factor results in graphics appearing tiny.
-- MacOS coordinate system always deals in physical content sizes, high DPI support is achieved by providing an optional flag for the developer to request finer granularity. Omitting the granularity request results in graphics appearing coarse.
+Observe the difference between the approaches taken by macOS and Windows:
+- The Windows and Android coordinate system always deals in physical device pixels, high DPI support is achieved by providing a content scale that tells the developer to draw objects larger. Ignoring this scale factor results in graphics appearing tiny.
+- The macOS and iOS coordinate system always deals in window coordinates, high DPI support is achieved by providing an optional flag for the developer to request more pixels. Omitting this flag results in graphics having low detail.
+- On Linux, X11 uses a similar approach to Windows and Wayland uses a similar approach to macOS.
 
-## Explanation
+## Solution
 
-Displays now have a content display scale, which is the expected scale for content based on the DPI settings of the display. For example, a 4K display might have a 2.0 (200%) display scale, which means that the user expects UI elements to be twice as big on this display, to aid in readability. You can query the display content scale using `SDL_GetDisplayContentScale()`, and when this changes you get an `SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED` event.
+Proper high DPI support takes into account both the content scale and the pixel density.
 
-The window size is now distinct from the window pixel size, and the ratio between the two is the window pixel density. If the window is created with the `SDL_WINDOW_HIGH_PIXEL_DENSITY` flag, SDL will try to match the native pixel density for the display, otherwise it will try to have the pixel size match the window size. You can query the window pixel density using `SDL_GetWindowPixelDensity()`. You can query the window pixel size using `SDL_GetWindowSizeInPixels()`, and when this changes you get an `SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED` event. You are guaranteed to get a `SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED` event when a window is created and resized, and you can use this event to create and resize your graphics context for the window.
+First, you'd create your window with the `SDL_WINDOW_HIGH_PIXEL_DENSITY` flag, assuming you want the highest detail possible. Then you'd get the window display scale to see how much your UI elements should be enlarged to be readable.
+
+If you're using the SDL 2D renderer, SDL provides the function `SDL_ConvertEventToRenderCoordinates()` to convert mouse coordinates between window coordinates and rendering coordinates, and the more general functions `SDL_RenderCoordinatesFromWindow()` and `SDL_RenderCoordinatesToWindow()` to do other conversion between them.
+
+If you're not using the 2D renderer, you can implement this yourself using `SDL_GetWindowPixelDensity()` as scale factor to convert from window coordinates to pixels.
+
+Finally you'll want to test on both Windows and macOS if possible to make sure your high DPI support works in all environments.
 
-The window has a display scale, which is the scale from the pixel resolution to the desired content size, e.g. the combination of the pixel density and the content scale. For example, a 3840x2160 window displayed at 200% on Windows, and a 1920x1080 window with the high density flag on a 2x display on macOS will both have a pixel size of 3840x2160 and a display scale of 2.0.  You can query the window display scale using `SDL_GetWindowDisplayScale()`, and when this changes you get an `SDL_EVENT_WINDOW_DISPLAY_SCALE_CHANGED` event.

+ 3 - 2
libs/SDL3/docs/README-linux.md

@@ -17,7 +17,7 @@ Ubuntu 18.04, all available features enabled:
     sudo apt-get install build-essential git make \
     pkg-config cmake ninja-build gnome-desktop-testing libasound2-dev libpulse-dev \
     libaudio-dev libjack-dev libsndio-dev libx11-dev libxext-dev \
-    libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev \
+    libxrandr-dev libxcursor-dev libxfixes-dev libxi-dev libxss-dev libxtst-dev \
     libxkbcommon-dev libdrm-dev libgbm-dev libgl1-mesa-dev libgles2-mesa-dev \
     libegl1-mesa-dev libdbus-1-dev libibus-1.0-dev libudev-dev
 
@@ -46,7 +46,8 @@ openSUSE Tumbleweed:
     libgbm-devel pipewire-devel libpulse-devel sndio-devel Mesa-libEGL-devel
 
 Arch:
-    sudo pacman -S alsa-lib cmake hidapi ibus jack libdecor libgl libpulse libusb libx11 libxcursor libxext libxinerama libxkbcommon libxrandr libxrender libxss mesa ninja pipewire sndio vulkan-driver vulkan-headers wayland wayland-protocols
+
+    sudo pacman -S alsa-lib cmake hidapi ibus jack libdecor libgl libpulse libusb libx11 libxcursor libxext libxinerama libxkbcommon libxrandr libxrender libxss libxtst mesa ninja pipewire sndio vulkan-driver vulkan-headers wayland wayland-protocols
 
 
 Joystick does not work

+ 1 - 1
libs/SDL3/docs/README-migration.md

@@ -1459,7 +1459,7 @@ The following symbols have been removed:
 * SDL_RENDERER_PRESENTVSYNC - replaced with SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER during renderer creation and SDL_PROP_RENDERER_VSYNC_NUMBER after renderer creation
 * SDL_RENDERER_SOFTWARE - you can check whether the name of the renderer is `SDL_SOFTWARE_RENDERER`
 * SDL_RENDERER_TARGETTEXTURE - all renderers support target texture functionality
-* SDL_ScaleModeBest = use SDL_SCALEMODE_LINEAR instead
+* SDL_ScaleModeBest - use SDL_SCALEMODE_LINEAR instead
 
 ## SDL_rwops.h
 

+ 62 - 3
libs/SDL3/docs/README-ngage.md

@@ -1,5 +1,64 @@
-Support for the Nokia N-Gage has been removed from SDL3 (but will make a
-comeback when newer compilers are available for the platform).
+# Nokia N-Gage
 
-SDL2 still supports this platform.
+SDL port for the Nokia N-Gage
+[Homebrew toolchain](https://github.com/ngagesdk/ngage-toolchain)
+contributed by:
 
+- [Michael Fitzmayer](https://github.com/mupfdev)
+
+- [Anonymous Maarten](https://github.com/madebr)
+
+Many thanks to:
+
+- icculus and slouken for always making room for us, even when we show up in 2025
+ still waving the N-Gage flag.
+
+- The Nokia N-Gage [Discord community](https://discord.gg/dbUzqJ26vs)
+ who keeps the platform alive.
+
+- The staff and supporters of the
+ [Suomen pelimuseo](https://www.vapriikki.fi/nayttelyt/fantastinen-floppi/), and
+ to Heikki Jungmann, for their ongoing love and dedication for the Nokia N-Gage --
+ you guys are awesome!
+
+## History
+
+When SDL support was discontinued due to the lack of C99 support at the time,
+this version was rebuilt from the ground up after resolving the compiler issues.
+
+In contrast to the earlier SDL2 port, this version features a dedicated rendering
+backend and a functional, albeit limited, audio interface.  Support for the
+software renderer has been removed.
+
+The outcome is a significantly leaner and more efficient SDL port, which we hope
+will breathe new life into this beloved yet obscure platform.
+
+## To the Stubborn Legends of the DC Scene
+
+This port is lovingly dedicated to the ever-nostalgic Dreamcast homebrew scene --
+because if we managed to pull this off for the N-Gage (yes, the N-Gage), surely
+you guys can stop clinging to SDL2 like it's a rare Shenmue prototype and finally
+make the leap to SDL3.  It's 2025, not 1999 -- and let's be honest, you're rocking
+a state-of-the-art C23 compiler.  The irony writes itself.
+
+## Existing Issues and Limitations
+
+- For now, the new
+ [SDL3 main callbacks](https://wiki.libsdl.org/SDL3/README/main-functions#how-to-use-main-callbacks-in-sdl3)
+ are not optional and must be used. This is important as the callbacks
+ are optional on other platforms.
+
+- If the application is put in the background while sound is playing,
+ some of the audio is looped until the app is back in focus.
+
+- It is recommended initialising SDLs audio sub-system even when it
+ is not required. The backend is started at a higher level.  Initialising
+ SDLs audio sub-system ensures that the backend is properly deinitialised.
+
+- Because the audio sample rate can change during phone calls, the sample
+ rate is currently fixed at 8kHz to ensure stable behavior.  Although
+ dynamically adjusting the sample rate is theoretically possible, the
+ current implementation doesn't support it yet.  This limitation is
+ expected to be resolved in a future update.
+
+- Dependency tracking is currently non-functional.

+ 2 - 2
libs/SDL3/docs/README-platforms.md

@@ -11,7 +11,7 @@
 - [macOS](README-macos.md)
 - [NetBSD](README-bsd.md)
 - [Nintendo Switch](README-switch.md)
-- [Nintendo 3DS](README-3ds.md)
+- [Nintendo 3DS](README-n3ds.md)
 - [OpenBSD](README-bsd.md)
 - [PlayStation 2](README-ps2.md)
 - [PlayStation 4](README-ps4.md)
@@ -24,6 +24,7 @@
 - [Windows](README-windows.md)
 - [Windows GDK](README-gdk.md)
 - [Xbox](README-gdk.md)
+- [Nokia N-Gage](README-ngage.md)
 
 ## Unsupported Platforms
 
@@ -33,7 +34,6 @@ All of these still work with [SDL2](/SDL2), which is an incompatible API, but an
 
 - Google Stadia
 - NaCL
-- Nokia N-Gage
 - OS/2
 - QNX
 - WinPhone

+ 2 - 2
libs/SDL3/docs/README-psp.md

@@ -1,13 +1,13 @@
 PSP
 ======
 SDL port for the Sony PSP contributed by:
-- Captian Lex
+- Captain Lex
 - Francisco Javier Trujillo Mata
 - Wouter Wijsman
 
 
 Credit to
-   Marcus R.Brown,Jim Paris,Matthew H for the original SDL 1.2 for PSP
+   Marcus R.Brown, Jim Paris, Matthew H for the original SDL 1.2 for PSP
    Geecko for his PSP GU lib "Glib2d"
 
 ## Building

+ 30 - 42
libs/SDL3/docs/README-versions.md

@@ -1,60 +1,48 @@
 # Versioning
 
-## Since 2.23.0
+## Since 3.2.0
 
 SDL follows an "odd/even" versioning policy, similar to GLib, GTK, Flatpak
 and older versions of the Linux kernel:
 
-* The major version (first part) increases when backwards compatibility
-    is broken, which will happen infrequently.
-
-* If the minor version (second part) is divisible by 2
-    (for example 2.24.x, 2.26.x), this indicates a version of SDL that
-    is believed to be stable and suitable for production use.
+* If the minor version (second part) and the patch version (third part) is
+    divisible by 2 (for example 3.2.6, 3.4.0), this indicates a version of
+    SDL that is believed to be stable and suitable for production use.
 
     * In stable releases, the patchlevel or micro version (third part)
-        indicates bugfix releases. Bugfix releases should not add or
-        remove ABI, so the ".0" release (for example 2.24.0) should be
-        forwards-compatible with all the bugfix releases from the
-        same cycle (for example 2.24.1).
-
-    * The minor version increases when new API or ABI is added, or when
-        other significant changes are made. Newer minor versions are
-        backwards-compatible, but not fully forwards-compatible.
-        For example, programs built against SDL 2.24.x should work fine
-        with SDL 2.26.x, but programs built against SDL 2.26.x will not
-        necessarily work with 2.24.x.
-
-* If the minor version (second part) is not divisible by 2
-    (for example 2.23.x, 2.25.x), this indicates a development prerelease
-    of SDL that is not suitable for stable software distributions.
+        indicates bugfix releases. Bugfix releases may add small changes
+        to the ABI, so newer patch versions are backwards-compatible but
+        not fully forwards-compatible. For example, programs built against
+        SDL 3.2.0 should work fine with SDL 3.2.8, but programs built against
+        SDL 3.2.8 may not work with 3.2.0.
+
+    * The minor version increases when significant changes are made that
+        require longer development or testing time, e.g. major new functionality,
+        or revamping support for a platform. Newer minor versions are
+        backwards-compatible, but not fully forwards-compatible. For example,
+        programs built against SDL 3.2.x should work fine with SDL 3.4.x,
+        but programs built against SDL 3.4.x may not work with 3.2.x.
+
+* If the minor version (second part) or patch version (third part) is not
+    divisible by 2 (for example 3.2.9, 3.3.x), this indicates a development
+    prerelease of SDL that is not suitable for stable software distributions.
     Use with caution.
 
-    * The patchlevel or micro version (third part) increases with
-        each prerelease.
-
-    * Each prerelease might add new API and/or ABI.
+    * The patchlevel or micro version (third part) increases with each prerelease.
 
     * Prereleases are backwards-compatible with older stable branches.
-        For example, 2.25.x will be backwards-compatible with 2.24.x.
+        For example, programs built against SDL 3.2.x should work fine with
+        SDL 3.3.x, but programs built against SDL 3.3.x may not work with 3.2.x.
 
-    * Prereleases are not guaranteed to be backwards-compatible with
-        each other. For example, new API or ABI added in 2.25.1
-        might be removed or changed in 2.25.2.
-        If this would be a problem for you, please do not use prereleases.
+    * Prereleases are not guaranteed to be backwards-compatible with each other.
+        For example, new API or ABI added in 3.3.0 might be removed or changed in
+        3.3.1. If this would be a problem for you, please do not use prereleases.
 
-    * Only upgrade to a prerelease if you can guarantee that you will
-        promptly upgrade to the stable release that follows it.
-        For example, do not upgrade to 2.23.x unless you will be able to
-        upgrade to 2.24.0 when it becomes available.
+    * Only use a prerelease if you can guarantee that you will promptly upgrade
+        to the stable release that follows it. For example, do not use 3.3.x
+        unless you will be able to upgrade to 3.4.0 when it becomes available.
 
     * Software distributions that have a freeze policy (in particular Linux
         distributions with a release cycle, such as Debian and Fedora)
-        should usually only package stable releases, and not prereleases.
-
-## Before 2.23.0
+        should only package stable releases, and not prereleases.
 
-Older versions of SDL followed a similar policy, but instead of the
-odd/even rule applying to the minor version, it applied to the patchlevel
-(micro version, third part). For example, 2.0.22 was a stable release
-and 2.0.21 was a prerelease.

+ 9 - 0
libs/SDL3/docs/README-wayland.md

@@ -59,6 +59,15 @@ encounter limitations or behavior that is different from other windowing systems
   `SDL_APP_ID` hint string, the desktop entry file name should match the application ID. For example, if your
   application ID is set to `org.my_org.sdl_app`, the desktop entry file should be named `org.my_org.sdl_app.desktop`.
 
+### The application progress bar can't be set via ```SDL_SetWindowProgressState()``` or ```SDL_SetWindowProgressValue()```
+
+- Only some Desktop Environemnts support the underlying API. Known compatible DEs: Unity, KDE
+- The underlying API requires a desktop entry file, aka a `.desktop` file.
+  Please see the [Desktop Entry Specification](https://specifications.freedesktop.org/desktop-entry-spec/latest/) for
+  more information on the format of this file. Note that if your application manually sets the application ID via the
+  `SDL_APP_ID` hint string, the desktop entry file name should match the application ID. For example, if your
+  application ID is set to `org.my_org.sdl_app`, the desktop entry file should be named `org.my_org.sdl_app.desktop`.
+
 ### Keyboard grabs don't work when running under XWayland
 
 - On GNOME based desktops, the dconf setting `org/gnome/mutter/wayland/xwayland-allow-grabs` must be enabled.

+ 2 - 0
libs/SDL3/docs/release_checklist.md

@@ -15,6 +15,8 @@
 
 * Create a GitHub release and attach the archives you just generated.
 
+* If this is a feature release, also tag the sdlwiki with the same tag.
+
 ## New feature release
 
 * Update `WhatsNew.txt`

+ 6 - 0
libs/SDL3/examples/CMakeLists.txt

@@ -111,6 +111,10 @@ macro(add_sdl_example_executable TARGET)
     elseif(EMSCRIPTEN)
         set_property(TARGET ${TARGET} PROPERTY SUFFIX ".html")
         target_link_options(${TARGET} PRIVATE -sALLOW_MEMORY_GROWTH=1)
+    elseif(NGAGE)
+        string(MD5 TARGET_MD5 "${TARGET}")
+        string(SUBSTRING "${TARGET_MD5}" 0 8 TARGET_MD5_8)
+        target_link_options(${TARGET} PRIVATE "SHELL:-s UID3=0x${TARGET_MD5_8}")
     endif()
 
     if(OPENGL_FOUND)
@@ -136,10 +140,12 @@ add_sdl_example_executable(renderer-viewport SOURCES renderer/14-viewport/viewpo
 add_sdl_example_executable(renderer-cliprect SOURCES renderer/15-cliprect/cliprect.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.bmp)
 add_sdl_example_executable(renderer-read-pixels SOURCES renderer/17-read-pixels/read-pixels.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.bmp)
 add_sdl_example_executable(renderer-debug-text SOURCES renderer/18-debug-text/debug-text.c)
+add_sdl_example_executable(renderer-affine-textures SOURCES renderer/19-affine-textures/affine-textures.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.bmp)
 add_sdl_example_executable(audio-simple-playback SOURCES audio/01-simple-playback/simple-playback.c)
 add_sdl_example_executable(audio-simple-playback-callback SOURCES audio/02-simple-playback-callback/simple-playback-callback.c)
 add_sdl_example_executable(audio-load-wav SOURCES audio/03-load-wav/load-wav.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.wav)
 add_sdl_example_executable(audio-multiple-streams SOURCES audio/04-multiple-streams/multiple-streams.c DATAFILES ${CMAKE_CURRENT_SOURCE_DIR}/../test/sample.wav ${CMAKE_CURRENT_SOURCE_DIR}/../test/sword.wav)
+add_sdl_example_executable(audio-planar-data SOURCES audio/05-planar-data/planar-data.c)
 add_sdl_example_executable(input-joystick-polling SOURCES input/01-joystick-polling/joystick-polling.c)
 add_sdl_example_executable(input-joystick-events SOURCES input/02-joystick-events/joystick-events.c)
 add_sdl_example_executable(camera-read-and-draw SOURCES camera/01-read-and-draw/read-and-draw.c)

+ 1 - 1
libs/SDL3/examples/audio/04-multiple-streams/README.txt

@@ -1,5 +1,5 @@
 If you're running this in a web browser, you need to click the window before you'll hear anything!
 
-This example code loads two .wav files, puts them an audio streams and binds
+This example code loads two .wav files, puts them in audio streams and binds
 them for playback, repeating both sounds on loop. This shows several streams
 mixing into a single playback device.

+ 1 - 1
libs/SDL3/examples/audio/04-multiple-streams/multiple-streams.c

@@ -1,5 +1,5 @@
 /*
- * This example code loads two .wav files, puts them an audio streams and
+ * This example code loads two .wav files, puts them in audio streams and
  * binds them for playback, repeating both sounds on loop. This shows several
  * streams mixing into a single playback device.
  *

+ 7 - 0
libs/SDL3/examples/audio/05-planar-data/README.txt

@@ -0,0 +1,7 @@
+This example code draws two clickable buttons. Each causes a sound to play,
+fed to either the left or right audio channel through separate (planar)
+arrays.
+
+Planar audio can feed both channels at the same time from different arrays,
+as well, but this example only uses one channel at a time for clarity. A
+NULL array will supply silence for that channel.

BIN
libs/SDL3/examples/audio/05-planar-data/onmouseover.webp


+ 366 - 0
libs/SDL3/examples/audio/05-planar-data/planar-data.c

@@ -0,0 +1,366 @@
+/*
+ * This example code draws two clickable buttons. Each causes a sound to play,
+ * fed to either the left or right audio channel through separate ("planar")
+ * arrays.
+ *
+ * This code is public domain. Feel free to use it for any purpose!
+ */
+
+#define SDL_MAIN_USE_CALLBACKS 1  /* use the callbacks instead of main() */
+#include <SDL3/SDL.h>
+#include <SDL3/SDL_main.h>
+
+/* We will use this renderer to draw into this window every frame. */
+static SDL_Window *window = NULL;
+static SDL_Renderer *renderer = NULL;
+static SDL_AudioStream *stream = NULL;
+
+/* location of buttons on the screen. */
+static const SDL_FRect rect_left_button = { 100, 170, 100, 100 };
+static const SDL_FRect rect_right_button = { 440, 170, 100, 100 };
+
+/* -1 if we're currently playing left, 1 if playing right, 0 if not playing. */
+static int playing_sound = 0;
+
+/* Raw audio data. These arrays are at the end of the source file. */
+static const Uint8 left[1870];
+static const Uint8 right[1777];
+
+
+/* This function runs once at startup. */
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
+{
+    const SDL_AudioSpec spec = { SDL_AUDIO_U8, 2, 4000 };  /* Uint8 data, stereo, 4000Hz. */
+
+    SDL_SetAppMetadata("Example Audio Planar Data", "1.0", "com.example.audio-planar-data");
+
+    if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO)) {
+        SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
+        return SDL_APP_FAILURE;
+    }
+
+    if (!SDL_CreateWindowAndRenderer("examples/audio/planar-data", 640, 480, 0, &window, &renderer)) {
+        SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
+        return SDL_APP_FAILURE;
+    }
+
+    stream = SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, NULL, NULL);
+    if (!stream) {
+        SDL_Log("Couldn't open audio device stream: %s", SDL_GetError());
+        return SDL_APP_FAILURE;
+    }
+
+    SDL_ResumeAudioStreamDevice(stream);  /* SDL_OpenAudioDeviceStream starts the device paused. Resume it! */
+
+    return SDL_APP_CONTINUE;  /* carry on with the program! */
+}
+
+/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
+SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
+{
+    if (event->type == SDL_EVENT_QUIT) {
+        return SDL_APP_SUCCESS;  /* end the program, reporting success to the OS. */
+    } else if (event->type == SDL_EVENT_MOUSE_BUTTON_DOWN) {
+        if (playing_sound == 0) {  /* nothing currently playing? */
+            const SDL_FPoint point = { event->button.x, event->button.y };
+            if (SDL_PointInRectFloat(&point, &rect_left_button)) {  /* clicked left button? */
+                const Uint8 *planes[] = { left, NULL };  /* specify NULL to say "this specific channel is silent" */
+                SDL_PutAudioStreamPlanarData(stream, (const void * const *) planes, -1, SDL_arraysize(left));
+                SDL_FlushAudioStream(stream);  /* that's all we're playing until it completes. */
+                playing_sound = -1;  /* left is playing */
+            } else if (SDL_PointInRectFloat(&point, &rect_right_button)) {  /* clicked right button? */
+                const Uint8 *planes[] = { NULL, right };  /* specify NULL to say "this specific channel is silent" */
+                SDL_PutAudioStreamPlanarData(stream, (const void * const *) planes, -1, SDL_arraysize(right));
+                SDL_FlushAudioStream(stream);  /* that's all we're playing until it completes. */
+                playing_sound = 1;  /* right is playing */
+            }
+        }
+    }
+
+    return SDL_APP_CONTINUE;  /* carry on with the program! */
+}
+
+static void render_button(const SDL_FRect *rect, const char *str, int button_value)
+{
+    float x, y;
+
+    if (playing_sound == button_value) {
+        SDL_SetRenderDrawColor(renderer, 0, 255, 0, 255);  /* green while playing */
+    } else {
+        SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255);  /* blue while not playing */
+    }
+
+    SDL_RenderFillRect(renderer, rect);
+    SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
+
+    x = rect->x + ((rect->w - (SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE * SDL_strlen(str))) / 2.0f);
+    y = rect->y + ((rect->h - SDL_DEBUG_TEXT_FONT_CHARACTER_SIZE) / 2.0f);
+    SDL_RenderDebugText(renderer, x, y, str);
+}
+
+/* This function runs once per frame, and is the heart of the program. */
+SDL_AppResult SDL_AppIterate(void *appstate)
+{
+    if (playing_sound) {
+        if (SDL_GetAudioStreamQueued(stream) == 0) {  /* sound is done? We can play a new sound now. */
+            playing_sound = 0;
+        }
+    }
+
+    SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
+    SDL_RenderClear(renderer);
+
+    render_button(&rect_left_button, "LEFT", -1);
+    render_button(&rect_right_button, "RIGHT", 1);
+
+    SDL_RenderPresent(renderer);
+
+    return SDL_APP_CONTINUE;  /* carry on with the program! */
+}
+
+/* This function runs once at shutdown. */
+void SDL_AppQuit(void *appstate, SDL_AppResult result)
+{
+    SDL_DestroyAudioStream(stream);
+    /* SDL will clean up the window/renderer for us. */
+}
+
+
+
+/* This is the audio data, as raw PCM samples (Uint8, 1 channel, 4000Hz) packed into C byte arrays for convenience. */
+
+static const Uint8 left[1870] = {
+  0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x81, 0x80, 0x81, 0x82, 0x82,
+  0x83, 0x83, 0x83, 0x83, 0x83, 0x82, 0x82, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7d,
+  0x7b, 0x7b, 0x7b, 0x7b, 0x7c, 0x7d, 0x7d, 0x7e, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x85, 0x84,
+  0x84, 0x83, 0x81, 0x7f, 0x7d, 0x7c, 0x7a, 0x7a, 0x7a, 0x77, 0x77, 0x77, 0x76, 0x76, 0x76, 0x77,
+  0x78, 0x7d, 0x82, 0x89, 0x8e, 0x92, 0x95, 0x95, 0x91, 0x8b, 0x84, 0x7d, 0x77, 0x73, 0x72, 0x72,
+  0x74, 0x75, 0x75, 0x75, 0x76, 0x74, 0x73, 0x73, 0x74, 0x79, 0x81, 0x89, 0x8f, 0x96, 0x9b, 0x9c,
+  0x98, 0x91, 0x88, 0x7e, 0x77, 0x74, 0x73, 0x74, 0x77, 0x7b, 0x7c, 0x7a, 0x77, 0x73, 0x6d, 0x69,
+  0x68, 0x6a, 0x73, 0x7f, 0x87, 0x8e, 0x99, 0xa1, 0x9e, 0x97, 0x90, 0x86, 0x7c, 0x76, 0x77, 0x7b,
+  0x80, 0x89, 0x91, 0x93, 0x91, 0x8e, 0x87, 0x7c, 0x71, 0x6b, 0x65, 0x60, 0x5d, 0x5f, 0x60, 0x61,
+  0x6b, 0x7b, 0x84, 0x8d, 0xa0, 0xae, 0xae, 0xa8, 0xa1, 0x94, 0x81, 0x73, 0x6f, 0x70, 0x74, 0x7e,
+  0x8d, 0x95, 0x97, 0x98, 0x92, 0x83, 0x72, 0x69, 0x61, 0x5a, 0x56, 0x59, 0x5d, 0x5f, 0x65, 0x75,
+  0x82, 0x87, 0x95, 0xaa, 0xb4, 0xb0, 0xaa, 0xa0, 0x8d, 0x77, 0x6c, 0x6c, 0x6d, 0x72, 0x81, 0x91,
+  0x98, 0x9a, 0x9a, 0x8f, 0x7a, 0x6a, 0x61, 0x58, 0x4f, 0x50, 0x57, 0x5b, 0x61, 0x74, 0x85, 0x8a,
+  0x96, 0xab, 0xb4, 0xae, 0xa5, 0x9c, 0x88, 0x71, 0x67, 0x69, 0x6c, 0x73, 0x85, 0x96, 0x9d, 0xa1,
+  0xa3, 0x96, 0x7f, 0x6e, 0x63, 0x56, 0x4c, 0x4d, 0x52, 0x53, 0x58, 0x6b, 0x80, 0x86, 0x92, 0xaa,
+  0xb8, 0xb4, 0xac, 0xa5, 0x90, 0x75, 0x69, 0x6a, 0x6c, 0x73, 0x86, 0x98, 0x9c, 0xa2, 0xa7, 0x99,
+  0x7f, 0x6e, 0x61, 0x54, 0x4c, 0x4b, 0x4d, 0x4f, 0x54, 0x66, 0x7c, 0x85, 0x90, 0xa9, 0xbc, 0xba,
+  0xb4, 0xac, 0x95, 0x78, 0x69, 0x67, 0x67, 0x71, 0x86, 0x99, 0x9d, 0xa4, 0xab, 0x9b, 0x7f, 0x6e,
+  0x5f, 0x50, 0x4b, 0x4e, 0x4e, 0x4e, 0x54, 0x60, 0x77, 0x86, 0x8e, 0xa4, 0xbb, 0xbf, 0xb9, 0xb3,
+  0x9e, 0x7d, 0x68, 0x65, 0x63, 0x6b, 0x84, 0x9a, 0x9d, 0xa3, 0xb0, 0x9f, 0x83, 0x71, 0x5f, 0x4d,
+  0x4c, 0x51, 0x51, 0x51, 0x56, 0x5a, 0x64, 0x7d, 0x90, 0x99, 0xad, 0xc3, 0xc2, 0xb5, 0xaa, 0x92,
+  0x71, 0x62, 0x65, 0x6a, 0x78, 0x92, 0xa2, 0xa1, 0xa7, 0xa8, 0x91, 0x78, 0x66, 0x55, 0x4a, 0x50,
+  0x54, 0x50, 0x50, 0x58, 0x5a, 0x65, 0x8b, 0x9b, 0x9b, 0xb7, 0xc9, 0xb3, 0xa6, 0xa2, 0x7d, 0x5a,
+  0x66, 0x6f, 0x70, 0x94, 0xa2, 0x90, 0x9b, 0xa5, 0x8f, 0x82, 0x77, 0x5c, 0x58, 0x60, 0x50, 0x46,
+  0x56, 0x49, 0x3a, 0x54, 0x97, 0xbe, 0xa9, 0xb0, 0xad, 0x91, 0xa7, 0xb3, 0x83, 0x6f, 0x6c, 0x5b,
+  0x71, 0x91, 0x9c, 0xac, 0x98, 0x78, 0x8a, 0xa6, 0xad, 0x9e, 0x72, 0x4d, 0x4e, 0x4f, 0x4e, 0x4a,
+  0x48, 0x46, 0x42, 0x4e, 0x99, 0xd5, 0xae, 0xb0, 0xb1, 0x8a, 0xb3, 0xbd, 0x82, 0x6b, 0x53, 0x56,
+  0x8b, 0x97, 0xa7, 0xaf, 0x74, 0x6b, 0x92, 0xaf, 0xc1, 0x8f, 0x55, 0x47, 0x4e, 0x60, 0x5e, 0x45,
+  0x4a, 0x4f, 0x3a, 0x44, 0x9f, 0xdf, 0xac, 0xa8, 0x93, 0x79, 0xbf, 0xc3, 0x92, 0x67, 0x36, 0x5a,
+  0x90, 0x9b, 0xb6, 0xa1, 0x6b, 0x68, 0x8d, 0xc3, 0xca, 0x83, 0x4f, 0x3d, 0x53, 0x72, 0x63, 0x46,
+  0x44, 0x55, 0x4f, 0x4c, 0x78, 0xcb, 0xbb, 0x93, 0x99, 0x79, 0xad, 0xd0, 0x9f, 0x70, 0x37, 0x4f,
+  0x90, 0x9e, 0xaf, 0x94, 0x73, 0x71, 0x89, 0xc0, 0xc0, 0x8f, 0x5b, 0x45, 0x62, 0x79, 0x6f, 0x5b,
+  0x46, 0x56, 0x54, 0x53, 0x59, 0x90, 0xd8, 0x95, 0x8c, 0x8c, 0x88, 0xd6, 0xb8, 0x83, 0x4c, 0x2f,
+  0x80, 0xa2, 0xaa, 0x9c, 0x69, 0x74, 0x80, 0xb0, 0xc6, 0x99, 0x78, 0x54, 0x69, 0x80, 0x7c, 0x69,
+  0x4b, 0x4e, 0x57, 0x4e, 0x4c, 0x5f, 0xae, 0xc3, 0x82, 0x86, 0x83, 0xac, 0xd9, 0xa3, 0x6a, 0x31,
+  0x50, 0xa0, 0xad, 0xa6, 0x6d, 0x59, 0x7f, 0x9e, 0xc8, 0xaf, 0x81, 0x74, 0x70, 0x8b, 0x83, 0x76,
+  0x58, 0x50, 0x56, 0x59, 0x58, 0x49, 0x62, 0x7c, 0xce, 0x99, 0x71, 0x9c, 0x8d, 0xd4, 0xb1, 0x6c,
+  0x4f, 0x37, 0x95, 0xab, 0x9b, 0x7f, 0x4b, 0x82, 0xa2, 0xba, 0xb5, 0x7b, 0x7d, 0x7d, 0x8d, 0x8b,
+  0x71, 0x62, 0x54, 0x5b, 0x4e, 0x5d, 0x4c, 0x5e, 0x57, 0x9c, 0xd4, 0x67, 0x94, 0x83, 0xa2, 0xd8,
+  0x83, 0x70, 0x2e, 0x59, 0xb5, 0x9d, 0xa1, 0x51, 0x55, 0x97, 0xad, 0xcb, 0x86, 0x77, 0x78, 0x95,
+  0xa1, 0x76, 0x6d, 0x58, 0x67, 0x5b, 0x4f, 0x66, 0x55, 0x67, 0x4e, 0x67, 0xd9, 0x88, 0x89, 0x86,
+  0x6f, 0xcd, 0x9b, 0x89, 0x4e, 0x39, 0x9f, 0xa0, 0xa9, 0x7a, 0x47, 0x88, 0x99, 0xbe, 0xac, 0x6b,
+  0x88, 0x87, 0xaf, 0x9a, 0x67, 0x71, 0x63, 0x74, 0x62, 0x55, 0x5c, 0x5e, 0x65, 0x5c, 0x54, 0xb1,
+  0xb0, 0x79, 0x8d, 0x6f, 0xac, 0xb7, 0x8e, 0x73, 0x44, 0x7b, 0xa1, 0x99, 0x90, 0x5a, 0x70, 0x97,
+  0xa0, 0xb4, 0x89, 0x83, 0x8e, 0x96, 0xa3, 0x7e, 0x6f, 0x6c, 0x6a, 0x6b, 0x5b, 0x5a, 0x61, 0x5e,
+  0x5d, 0x63, 0x66, 0xa0, 0xa6, 0x7c, 0x8d, 0x83, 0xa4, 0xad, 0x88, 0x7b, 0x58, 0x75, 0x95, 0x91,
+  0x92, 0x70, 0x75, 0x93, 0x9c, 0xab, 0x92, 0x84, 0x8d, 0x91, 0x96, 0x81, 0x70, 0x6b, 0x6c, 0x68,
+  0x62, 0x59, 0x5e, 0x69, 0x5a, 0x5a, 0x68, 0x5f, 0xa2, 0xb0, 0x6d, 0x87, 0x7e, 0xa0, 0xba, 0x89,
+  0x78, 0x53, 0x73, 0xa6, 0x9b, 0x95, 0x6c, 0x65, 0x8e, 0x9a, 0xab, 0x97, 0x7b, 0x85, 0x8e, 0x9a,
+  0x91, 0x71, 0x6b, 0x68, 0x65, 0x6e, 0x58, 0x5d, 0x70, 0x5d, 0x6d, 0x67, 0x5e, 0x80, 0x78, 0x94,
+  0x98, 0x7c, 0x96, 0x90, 0xa1, 0xa5, 0x82, 0x7f, 0x70, 0x7e, 0x94, 0x87, 0x87, 0x80, 0x88, 0x92,
+  0x8e, 0x96, 0x8c, 0x89, 0x84, 0x73, 0x72, 0x6f, 0x71, 0x6d, 0x5e, 0x61, 0x6a, 0x70, 0x77, 0x6f,
+  0x6d, 0x79, 0x76, 0x7f, 0x77, 0x75, 0x7e, 0x90, 0xa8, 0x8c, 0x85, 0x98, 0x9b, 0xa7, 0x93, 0x79,
+  0x78, 0x79, 0x91, 0x94, 0x87, 0x86, 0x85, 0x86, 0x8b, 0x89, 0x82, 0x7c, 0x74, 0x6d, 0x6c, 0x75,
+  0x75, 0x6f, 0x64, 0x69, 0x74, 0x7e, 0x83, 0x76, 0x75, 0x85, 0x8a, 0x89, 0x88, 0x78, 0x81, 0x88,
+  0x83, 0x85, 0x7e, 0x80, 0x88, 0x89, 0x8c, 0x8d, 0x8a, 0x8b, 0x88, 0x88, 0x89, 0x85, 0x81, 0x81,
+  0x7e, 0x7c, 0x7c, 0x77, 0x7d, 0x76, 0x6f, 0x7d, 0x7f, 0x78, 0x73, 0x76, 0x83, 0x84, 0x80, 0x7f,
+  0x82, 0x86, 0x80, 0x81, 0x83, 0x81, 0x81, 0x7e, 0x7d, 0x7b, 0x83, 0x8b, 0x85, 0x7a, 0x76, 0x83,
+  0x87, 0x82, 0x7d, 0x76, 0x7b, 0x80, 0x83, 0x81, 0x7a, 0x79, 0x7d, 0x82, 0x81, 0x82, 0x82, 0x83,
+  0x86, 0x80, 0x80, 0x81, 0x7e, 0x80, 0x7d, 0x7a, 0x7e, 0x81, 0x7e, 0x7e, 0x80, 0x7f, 0x81, 0x82,
+  0x80, 0x81, 0x82, 0x7f, 0x7f, 0x7d, 0x7c, 0x7f, 0x7b, 0x7b, 0x7d, 0x7a, 0x7a, 0x7e, 0x7e, 0x7c,
+  0x7c, 0x7f, 0x80, 0x7f, 0x80, 0x82, 0x81, 0x81, 0x80, 0x7e, 0x80, 0x7f, 0x81, 0x7b, 0x7c, 0x7f,
+  0x7f, 0x81, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x83, 0x7e, 0x7f, 0x85, 0x81, 0x83,
+  0x84, 0x80, 0x84, 0x81, 0x81, 0x83, 0x81, 0x83, 0x80, 0x84, 0x80, 0x80, 0x85, 0x80, 0x81, 0x7f,
+  0x82, 0x82, 0x81, 0x81, 0x80, 0x81, 0x80, 0x87, 0x81, 0x7c, 0x80, 0x7f, 0x80, 0x7d, 0x7c, 0x7d,
+  0x80, 0x80, 0x80, 0x82, 0x7d, 0x81, 0x82, 0x7e, 0x82, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x82,
+  0x7f, 0x80, 0x7f, 0x7f, 0x81, 0x7f, 0x80, 0x7e, 0x81, 0x80, 0x7e, 0x80, 0x7e, 0x7f, 0x80, 0x80,
+  0x82, 0x7f, 0x83, 0x83, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x80,
+  0x80, 0x81, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7d, 0x7e, 0x7d, 0x7c, 0x7d, 0x7c, 0x7c,
+  0x7d, 0x7c, 0x7d, 0x7e, 0x7f, 0x7e, 0x7e, 0x7f, 0x7d, 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7f, 0x80,
+  0x7e, 0x80, 0x7e, 0x7e, 0x80, 0x7e, 0x80, 0x7e, 0x7f, 0x7e, 0x7d, 0x7f, 0x7d, 0x7d, 0x7d, 0x7d,
+  0x7d, 0x7d, 0x7e, 0x7f, 0x7f, 0x7d, 0x7e, 0x7f, 0x7e, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80,
+  0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x81, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f,
+  0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x80,
+  0x81, 0x80, 0x82, 0x83, 0x81, 0x82, 0x81, 0x82, 0x82, 0x82, 0x81, 0x81, 0x83, 0x82, 0x82, 0x82,
+  0x81, 0x83, 0x82, 0x81, 0x81, 0x80, 0x80, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7e, 0x80, 0x7d, 0x80,
+  0x81, 0x7e, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x81, 0x80, 0x81, 0x81, 0x80,
+  0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x81, 0x80, 0x7f, 0x81, 0x81, 0x82, 0x81,
+  0x80, 0x82, 0x82, 0x80, 0x81, 0x81, 0x80, 0x80, 0x7e, 0x7d, 0x7f, 0x7e, 0x81, 0x81, 0x7e, 0x7f,
+  0x82, 0x7f, 0x7d, 0x7f, 0x7d, 0x81, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80,
+  0x7f, 0x7e, 0x7f, 0x7f, 0x7e, 0x7c, 0x7d, 0x7e, 0x7d, 0x7d, 0x7e, 0x7d, 0x7e, 0x7c, 0x7e, 0x7e,
+  0x7c, 0x7e, 0x7d, 0x7e, 0x7e, 0x7e, 0x7d, 0x7d, 0x7c, 0x7b, 0x7c, 0x7b, 0x7b, 0x7b, 0x7b, 0x7b,
+  0x7b, 0x7c, 0x7c, 0x7d, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d, 0x7c, 0x7d, 0x7d, 0x7d, 0x7d, 0x7d,
+  0x7d, 0x7d, 0x7d, 0x7d, 0x7e, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f,
+  0x7f, 0x7f, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81,
+  0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81,
+  0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x81,
+  0x81, 0x81, 0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82, 0x82,
+  0x81, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x82, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f,
+  0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+  0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e,
+  0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f,
+  0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f,
+  0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x81, 0x80, 0x83, 0x80, 0x80, 0x80, 0x84, 0x84,
+  0x7b, 0x7e, 0x80, 0x80, 0x7e, 0x80, 0x7e, 0x7f, 0x81, 0x81, 0x80, 0x7f, 0x80, 0x7f, 0x7e, 0x7e,
+  0x7f, 0x80, 0x80, 0x7f, 0x81, 0x82, 0x80, 0x80, 0x81, 0x81, 0x80, 0x81, 0x7f, 0x80, 0x80, 0x81,
+  0x81, 0x81, 0x81, 0x84, 0x83, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x81, 0x7e, 0x7e, 0x7f, 0x81, 0x7f,
+  0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x81, 0x82, 0x82, 0x80, 0x7f, 0x80,
+  0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7d, 0x7e, 0x7e, 0x7f, 0x80,
+  0x80, 0x80, 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81, 0x80, 0x80, 0x81, 0x7f, 0x80,
+  0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7f,
+  0x7e, 0x7d, 0x7d, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7e, 0x80, 0x7e, 0x7f, 0x7f,
+  0x7e, 0x7f, 0x7e, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f,
+  0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x81, 0x80, 0x7f, 0x80, 0x80, 0x82,
+  0x81, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x81, 0x81, 0x80, 0x81, 0x80, 0x82, 0x7f,
+  0x7f, 0x7e, 0x7e, 0x80, 0x7e, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x81, 0x80,
+  0x81, 0x80, 0x80, 0x81, 0x80, 0x83, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7e, 0x80, 0x7f,
+  0x7f, 0x80, 0x7f, 0x82, 0x80, 0x81, 0x7f, 0x7e, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80,
+  0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x7f, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+  0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x80, 0x80, 0x81, 0x81, 0x7f, 0x7f, 0x7f,
+  0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x81, 0x7f, 0x80, 0x7e, 0x7f, 0x7f,
+  0x7e, 0x80, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7d, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x80,
+  0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x81, 0x81, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x80, 0x7f,
+  0x7f, 0x7f, 0x81, 0x81, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x7f, 0x7f,
+  0x7f, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x81, 0x80, 0x80, 0x7f, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e,
+  0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80, 0x7e, 0x7f, 0x7e
+};
+
+static const Uint8 right[1777]  = {
+  0x7f, 0x7e, 0x7e, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x82, 0x83, 0x83, 0x83,
+  0x82, 0x81, 0x81, 0x80, 0x7f, 0x7e, 0x7c, 0x7b, 0x7a, 0x7a, 0x79, 0x79, 0x79, 0x7a, 0x7a, 0x7b,
+  0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88, 0x89, 0x89, 0x89, 0x88, 0x87, 0x84, 0x82, 0x80, 0x7e,
+  0x7c, 0x7b, 0x7a, 0x7a, 0x79, 0x78, 0x77, 0x75, 0x76, 0x77, 0x78, 0x78, 0x78, 0x7b, 0x81, 0x87,
+  0x8c, 0x8e, 0x90, 0x92, 0x91, 0x8d, 0x87, 0x81, 0x7d, 0x7b, 0x7a, 0x79, 0x79, 0x7a, 0x79, 0x78,
+  0x75, 0x74, 0x75, 0x75, 0x75, 0x76, 0x76, 0x76, 0x76, 0x7b, 0x83, 0x88, 0x8b, 0x8f, 0x95, 0x98,
+  0x95, 0x8d, 0x86, 0x83, 0x80, 0x7e, 0x7c, 0x7c, 0x7e, 0x7e, 0x7c, 0x79, 0x78, 0x76, 0x75, 0x72,
+  0x73, 0x74, 0x72, 0x6f, 0x6d, 0x72, 0x7e, 0x87, 0x8b, 0x90, 0x98, 0x9f, 0x9b, 0x91, 0x85, 0x7f,
+  0x7b, 0x78, 0x79, 0x7f, 0x87, 0x8b, 0x8a, 0x89, 0x89, 0x86, 0x81, 0x79, 0x75, 0x74, 0x73, 0x73,
+  0x6f, 0x6d, 0x6e, 0x6e, 0x6e, 0x6f, 0x72, 0x77, 0x82, 0x8f, 0x95, 0x99, 0x9c, 0x9e, 0x99, 0x8c,
+  0x7f, 0x74, 0x71, 0x70, 0x74, 0x7e, 0x8a, 0x92, 0x91, 0x8f, 0x8f, 0x8d, 0x85, 0x7c, 0x76, 0x75,
+  0x76, 0x75, 0x71, 0x6d, 0x6b, 0x68, 0x64, 0x64, 0x66, 0x6e, 0x83, 0x8f, 0x93, 0x9b, 0xa3, 0xa4,
+  0x97, 0x86, 0x76, 0x6f, 0x6d, 0x6e, 0x78, 0x87, 0x94, 0x98, 0x96, 0x94, 0x91, 0x89, 0x7e, 0x74,
+  0x6f, 0x70, 0x74, 0x72, 0x6e, 0x6b, 0x67, 0x62, 0x60, 0x60, 0x69, 0x84, 0x91, 0x95, 0xa1, 0xae,
+  0xb0, 0x9b, 0x84, 0x74, 0x6a, 0x65, 0x67, 0x78, 0x8b, 0x98, 0x9f, 0x9e, 0x9a, 0x90, 0x86, 0x7c,
+  0x71, 0x6a, 0x6c, 0x73, 0x74, 0x6d, 0x69, 0x65, 0x5e, 0x5c, 0x60, 0x6f, 0x8b, 0x95, 0x9b, 0xac,
+  0xb3, 0xa5, 0x89, 0x7a, 0x6b, 0x5c, 0x5f, 0x70, 0x88, 0x97, 0xa5, 0xac, 0xa1, 0x95, 0x8e, 0x86,
+  0x76, 0x6a, 0x6b, 0x72, 0x72, 0x6c, 0x67, 0x5e, 0x55, 0x52, 0x56, 0x78, 0x9c, 0x91, 0x9c, 0xbc,
+  0xb8, 0x98, 0x83, 0x7f, 0x5e, 0x4c, 0x6c, 0x83, 0x8a, 0x9a, 0xb7, 0xae, 0x8a, 0x8f, 0x93, 0x79,
+  0x69, 0x76, 0x76, 0x69, 0x70, 0x70, 0x5b, 0x50, 0x51, 0x57, 0x52, 0x77, 0xb2, 0x90, 0x95, 0xc8,
+  0xb1, 0x8d, 0x89, 0x8a, 0x55, 0x4e, 0x87, 0x7f, 0x82, 0xb3, 0xb9, 0x8f, 0x8c, 0x9d, 0x79, 0x71,
+  0x80, 0x6a, 0x61, 0x7b, 0x70, 0x51, 0x63, 0x62, 0x3e, 0x50, 0x61, 0x9a, 0xad, 0x7e, 0xba, 0xb5,
+  0x94, 0x9f, 0x93, 0x75, 0x4b, 0x7b, 0x79, 0x6c, 0xab, 0xaf, 0x9f, 0x93, 0x8e, 0x7a, 0x7f, 0x89,
+  0x6a, 0x6e, 0x71, 0x66, 0x5e, 0x63, 0x5c, 0x53, 0x53, 0x50, 0x5a, 0xb8, 0xbd, 0x6d, 0xc3, 0xb2,
+  0x8a, 0xa7, 0xa1, 0x70, 0x4c, 0x88, 0x63, 0x7d, 0xb1, 0xa1, 0xa6, 0x8e, 0x6a, 0x7c, 0x95, 0x8b,
+  0x84, 0x72, 0x5c, 0x5c, 0x67, 0x64, 0x61, 0x56, 0x65, 0x52, 0x44, 0x80, 0xda, 0x8a, 0x88, 0xc9,
+  0x89, 0x96, 0xb1, 0x92, 0x4a, 0x6f, 0x6d, 0x78, 0xa5, 0xa7, 0xa0, 0x98, 0x66, 0x6e, 0xa6, 0x9d,
+  0x95, 0x70, 0x52, 0x57, 0x73, 0x69, 0x72, 0x5a, 0x55, 0x52, 0x50, 0x3d, 0xb8, 0xdb, 0x5d, 0xa9,
+  0xab, 0x82, 0xad, 0xc3, 0x65, 0x4c, 0x6c, 0x6d, 0x98, 0xac, 0x9f, 0x97, 0x74, 0x5a, 0xa0, 0xb1,
+  0x9e, 0x7e, 0x52, 0x54, 0x74, 0x71, 0x6a, 0x6a, 0x5a, 0x53, 0x4b, 0x46, 0x5e, 0xe5, 0xaa, 0x62,
+  0xab, 0x8f, 0x97, 0xcb, 0xa5, 0x4b, 0x4f, 0x67, 0x88, 0xa6, 0xa4, 0x98, 0x84, 0x61, 0x80, 0xb7,
+  0xb4, 0x98, 0x64, 0x4e, 0x64, 0x77, 0x72, 0x72, 0x55, 0x54, 0x4e, 0x52, 0x3c, 0x96, 0xf0, 0x69,
+  0x7f, 0xa2, 0x80, 0xc1, 0xc8, 0x75, 0x46, 0x4d, 0x74, 0xa4, 0x9e, 0x95, 0x8a, 0x6a, 0x73, 0xa6,
+  0xb7, 0xb4, 0x81, 0x60, 0x5e, 0x71, 0x7c, 0x74, 0x6b, 0x54, 0x54, 0x48, 0x4f, 0x44, 0xc3, 0xcb,
+  0x5b, 0x9b, 0x86, 0x99, 0xd4, 0xa3, 0x71, 0x3e, 0x4b, 0x91, 0x99, 0x9d, 0x95, 0x70, 0x72, 0x85,
+  0xb0, 0xbd, 0xa5, 0x7e, 0x67, 0x67, 0x78, 0x77, 0x6e, 0x63, 0x53, 0x5b, 0x39, 0x50, 0x48, 0xb5,
+  0xc2, 0x6a, 0xa5, 0x77, 0xa8, 0xbd, 0x98, 0x89, 0x3a, 0x60, 0x83, 0x85, 0xa9, 0x87, 0x87, 0x74,
+  0x77, 0xac, 0xa9, 0xb9, 0x8a, 0x71, 0x6b, 0x6d, 0x81, 0x6d, 0x66, 0x51, 0x60, 0x3c, 0x50, 0x4a,
+  0x91, 0xbf, 0x83, 0xae, 0x7a, 0xa4, 0xa1, 0x97, 0x92, 0x4b, 0x73, 0x68, 0x86, 0x8e, 0x8c, 0x95,
+  0x79, 0x83, 0x86, 0xa2, 0xab, 0xa6, 0x8d, 0x79, 0x6a, 0x75, 0x68, 0x74, 0x56, 0x5c, 0x4e, 0x4c,
+  0x49, 0x5d, 0xb1, 0x88, 0xb9, 0x8d, 0xa4, 0x90, 0x94, 0x8b, 0x66, 0x72, 0x69, 0x83, 0x7c, 0x91,
+  0x82, 0x89, 0x79, 0x87, 0x8a, 0xa1, 0x9f, 0xa5, 0x95, 0x8d, 0x7a, 0x6f, 0x6f, 0x61, 0x62, 0x58,
+  0x5f, 0x52, 0x52, 0x4f, 0x80, 0x90, 0xa1, 0xa6, 0xa3, 0x9c, 0x90, 0x86, 0x74, 0x6d, 0x6c, 0x7a,
+  0x83, 0x8a, 0x8c, 0x88, 0x7f, 0x80, 0x82, 0x8f, 0x99, 0x9e, 0xa3, 0x9a, 0x93, 0x84, 0x73, 0x68,
+  0x5d, 0x5e, 0x5d, 0x5f, 0x5e, 0x5d, 0x52, 0x6a, 0x7d, 0x8d, 0x9f, 0xa6, 0xac, 0xa0, 0x95, 0x7d,
+  0x6e, 0x64, 0x6a, 0x76, 0x81, 0x8e, 0x98, 0x94, 0x8e, 0x84, 0x84, 0x84, 0x86, 0x91, 0x98, 0x9d,
+  0x9a, 0x8c, 0x7b, 0x67, 0x5c, 0x58, 0x58, 0x5e, 0x5e, 0x64, 0x60, 0x67, 0x75, 0x7f, 0x8e, 0x99,
+  0xa2, 0xa5, 0xa2, 0x99, 0x87, 0x74, 0x6a, 0x67, 0x6e, 0x7b, 0x87, 0x96, 0x97, 0x97, 0x94, 0x8e,
+  0x8c, 0x8a, 0x8b, 0x8a, 0x8a, 0x88, 0x84, 0x7b, 0x72, 0x66, 0x5e, 0x58, 0x57, 0x5a, 0x60, 0x64,
+  0x6c, 0x78, 0x81, 0x8c, 0x96, 0x9d, 0x9f, 0xa1, 0x99, 0x8f, 0x80, 0x76, 0x70, 0x6c, 0x70, 0x76,
+  0x81, 0x8a, 0x93, 0x97, 0x98, 0x94, 0x91, 0x8c, 0x8a, 0x87, 0x81, 0x7c, 0x74, 0x71, 0x6b, 0x68,
+  0x65, 0x62, 0x60, 0x61, 0x63, 0x67, 0x6c, 0x77, 0x82, 0x8a, 0x96, 0x9c, 0xa4, 0xa5, 0xa0, 0x95,
+  0x86, 0x7b, 0x71, 0x6e, 0x6e, 0x73, 0x79, 0x82, 0x8b, 0x94, 0x99, 0x98, 0x95, 0x8e, 0x88, 0x81,
+  0x7b, 0x77, 0x73, 0x6f, 0x6c, 0x6a, 0x68, 0x67, 0x66, 0x69, 0x69, 0x6e, 0x70, 0x77, 0x81, 0x88,
+  0x91, 0x97, 0x9f, 0xa1, 0xa2, 0x9b, 0x92, 0x82, 0x77, 0x6c, 0x6a, 0x6b, 0x71, 0x79, 0x83, 0x8d,
+  0x93, 0x97, 0x96, 0x95, 0x8f, 0x8b, 0x84, 0x7d, 0x76, 0x71, 0x6a, 0x68, 0x67, 0x68, 0x6b, 0x6d,
+  0x71, 0x73, 0x76, 0x79, 0x7e, 0x83, 0x8a, 0x8f, 0x94, 0x97, 0x97, 0x95, 0x8f, 0x87, 0x7f, 0x79,
+  0x76, 0x76, 0x78, 0x7a, 0x7e, 0x81, 0x86, 0x8a, 0x8c, 0x8e, 0x8d, 0x8a, 0x86, 0x80, 0x7c, 0x78,
+  0x74, 0x71, 0x70, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x82, 0x81, 0x80,
+  0x7e, 0x7f, 0x81, 0x84, 0x88, 0x8b, 0x8d, 0x8d, 0x8b, 0x87, 0x83, 0x7d, 0x7a, 0x77, 0x78, 0x7a,
+  0x7e, 0x81, 0x83, 0x84, 0x84, 0x84, 0x82, 0x80, 0x7f, 0x7d, 0x7b, 0x7a, 0x78, 0x78, 0x77, 0x78,
+  0x78, 0x79, 0x7c, 0x7e, 0x81, 0x83, 0x83, 0x84, 0x83, 0x82, 0x81, 0x80, 0x80, 0x7f, 0x7f, 0x80,
+  0x80, 0x81, 0x82, 0x83, 0x84, 0x84, 0x84, 0x83, 0x83, 0x81, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80,
+  0x7f, 0x7e, 0x7d, 0x7c, 0x7c, 0x7c, 0x7d, 0x7d, 0x7f, 0x80, 0x80, 0x81, 0x80, 0x7f, 0x7e, 0x7d,
+  0x7d, 0x7d, 0x7e, 0x80, 0x80, 0x81, 0x82, 0x82, 0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x81, 0x80,
+  0x81, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x80, 0x80, 0x7e, 0x7d, 0x7d, 0x7e, 0x7e, 0x7f,
+  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x80, 0x80, 0x80, 0x81, 0x81,
+  0x81, 0x81, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f,
+  0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x82, 0x82, 0x82, 0x81, 0x80,
+  0x7f, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f,
+  0x80, 0x80, 0x81, 0x81, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f,
+  0x80, 0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x82, 0x82, 0x82, 0x82,
+  0x81, 0x81, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80,
+  0x80, 0x81, 0x80, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7e,
+  0x7e, 0x7d, 0x7e, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x82, 0x82, 0x81, 0x81, 0x80, 0x7f, 0x7f, 0x7f,
+  0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x80, 0x80,
+  0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x80,
+  0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+  0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x7f, 0x80,
+  0x80, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x7f, 0x87, 0x83, 0x7d, 0x81, 0x80, 0x7e, 0x81, 0x7b,
+  0x7d, 0x84, 0x7f, 0x81, 0x83, 0x82, 0x7f, 0x80, 0x7c, 0x7b, 0x7d, 0x80, 0x80, 0x80, 0x80, 0x80,
+  0x80, 0x7e, 0x7f, 0x7e, 0x7f, 0x80, 0x80, 0x81, 0x82, 0x82, 0x82, 0x82, 0x80, 0x80, 0x7f, 0x7f,
+  0x7e, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x80, 0x82, 0x80, 0x7f, 0x80, 0x81, 0x80, 0x81, 0x7f,
+  0x83, 0x85, 0x7f, 0x80, 0x84, 0x83, 0x7d, 0x7c, 0x7d, 0x80, 0x7d, 0x7d, 0x7e, 0x7e, 0x7d, 0x83,
+  0x81, 0x7d, 0x7d, 0x81, 0x7f, 0x7c, 0x7c, 0x7c, 0x7d, 0x7c, 0x83, 0x80, 0x84, 0x84, 0x82, 0x7d,
+  0x7f, 0x7d, 0x7c, 0x7e, 0x7e, 0x7f, 0x81, 0x84, 0x82, 0x81, 0x7e, 0x7f, 0x7f, 0x7f, 0x7e, 0x80,
+  0x81, 0x80, 0x7f, 0x80, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7e, 0x80, 0x80, 0x80, 0x80, 0x81, 0x81,
+  0x7f, 0x7f, 0x7f, 0x7f, 0x81, 0x80, 0x82, 0x81, 0x83, 0x81, 0x82, 0x80, 0x80, 0x7f, 0x7f, 0x80,
+  0x7d, 0x80, 0x7e, 0x81, 0x7f, 0x81, 0x7f, 0x80, 0x7f, 0x7f, 0x7e, 0x7d, 0x81, 0x80, 0x82, 0x7f,
+  0x81, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7e, 0x80, 0x7f, 0x81, 0x7f, 0x81, 0x81, 0x81, 0x81, 0x81,
+  0x82, 0x81, 0x81, 0x80, 0x81, 0x7f, 0x80, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7e,
+  0x7f, 0x7e, 0x7f, 0x7e, 0x7e, 0x7e, 0x7e, 0x7f, 0x7e, 0x80, 0x7f, 0x82, 0x80, 0x81, 0x81, 0x80,
+  0x81, 0x80, 0x81, 0x80, 0x81, 0x80, 0x81, 0x80, 0x80, 0x7e, 0x7f, 0x7e, 0x7d, 0x7e, 0x7e, 0x7f,
+  0x7f, 0x7f, 0x7e, 0x7d, 0x80, 0x7e, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x81, 0x7e, 0x81, 0x81, 0x83,
+  0x80, 0x81, 0x80, 0x80, 0x81, 0x7f, 0x80, 0x80, 0x80, 0x81, 0x7f, 0x80, 0x7f, 0x80, 0x7d, 0x80,
+  0x7e, 0x7d, 0x80, 0x80, 0x83, 0x7f, 0x83, 0x7e, 0x83, 0x7f, 0x80, 0x7f, 0x7e, 0x81, 0x7f, 0x7f,
+  0x80, 0x80, 0x81, 0x7e, 0x7f, 0x7f, 0x80, 0x81, 0x80, 0x83, 0x7f, 0x82, 0x7f, 0x82, 0x7f, 0x80,
+  0x80, 0x7e, 0x7f, 0x7d, 0x7e, 0x7d, 0x7e, 0x7e, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x81,
+  0x82, 0x80, 0x82, 0x80, 0x82, 0x80, 0x7f, 0x7e, 0x7f, 0x7e, 0x7f, 0x80, 0x7e, 0x80, 0x80, 0x81,
+  0x7f, 0x7f, 0x7e, 0x80, 0x7d, 0x7e, 0x7e, 0x7f, 0x80, 0x7f, 0x80, 0x7e, 0x81, 0x7e, 0x81, 0x7f,
+  0x80, 0x7f, 0x80, 0x81, 0x7f, 0x80, 0x7e, 0x81, 0x7e, 0x80, 0x7d, 0x80, 0x80, 0x80, 0x81, 0x80,
+  0x82, 0x7e, 0x83, 0x7d, 0x80, 0x7c, 0x7d, 0x7e, 0x7c, 0x7e, 0x7d, 0x7e, 0x7f, 0x7e, 0x7e, 0x80,
+  0x7e, 0x81, 0x7e, 0x81, 0x7f, 0x81, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, 0x83, 0x80, 0x81, 0x80,
+  0x80, 0x80, 0x80, 0x7f, 0x80, 0x7e, 0x7f, 0x7f, 0x81, 0x7f, 0x80, 0x80, 0x7f, 0x7e, 0x80, 0x80,
+  0x81, 0x82, 0x81, 0x82, 0x81, 0x81, 0x81, 0x82, 0x80, 0x80, 0x7e, 0x82, 0x80, 0x84, 0x81, 0x80,
+  0x7f, 0x81, 0x80, 0x7f, 0x80, 0x7d, 0x80, 0x7d, 0x81, 0x7f, 0x81, 0x80, 0x81, 0x81, 0x80, 0x80,
+  0x7e, 0x80, 0x7f, 0x81, 0x7f, 0x81, 0x81, 0x81, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
+  0x81, 0x80, 0x80, 0x7e, 0x81, 0x7f, 0x7f, 0x7e, 0x7e, 0x7f, 0x7f, 0x80, 0x7f, 0x7f, 0x7e, 0x81,
+  0x7e, 0x7f, 0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x7f, 0x81, 0x7f, 0x80, 0x7f, 0x80, 0x80, 0x7f, 0x80,
+  0x80, 0x80, 0x7f, 0x7f, 0x7f, 0x80, 0x7f, 0x7e, 0x7d, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+  0x7f, 0x7e, 0x7f, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x80, 0x7f, 0x7f, 0x80, 0x80, 0x80, 0x80, 0x81,
+  0x80
+};
+

BIN
libs/SDL3/examples/audio/05-planar-data/thumbnail.png


+ 47 - 1
libs/SDL3/examples/demo/01-snake/snake.c

@@ -21,6 +21,8 @@
 #define THREE_BITS  0x7U /* ~CHAR_MAX >> (CHAR_BIT - SNAKE_CELL_MAX_BITS) */
 #define SHIFT(x, y) (((x) + ((y) * SNAKE_GAME_WIDTH)) * SNAKE_CELL_MAX_BITS)
 
+static SDL_Joystick *joystick = NULL;
+
 typedef enum
 {
     SNAKE_CELL_NOTHING = 0U,
@@ -186,6 +188,8 @@ void snake_step(SnakeContext *ctx)
     case SNAKE_DIR_DOWN:
         ++ctx->head_ypos;
         break;
+    default:
+        break;
     }
     wrap_around_(&ctx->head_xpos, SNAKE_GAME_WIDTH);
     wrap_around_(&ctx->head_ypos, SNAKE_GAME_HEIGHT);
@@ -238,6 +242,26 @@ static SDL_AppResult handle_key_event_(SnakeContext *ctx, SDL_Scancode key_code)
     return SDL_APP_CONTINUE;
 }
 
+static SDL_AppResult handle_hat_event_(SnakeContext *ctx, Uint8 hat) {
+    switch (hat) {
+    case SDL_HAT_RIGHT:
+        snake_redir(ctx, SNAKE_DIR_RIGHT);
+        break;
+    case SDL_HAT_UP:
+        snake_redir(ctx, SNAKE_DIR_UP);
+        break;
+    case SDL_HAT_LEFT:
+        snake_redir(ctx, SNAKE_DIR_LEFT);
+        break;
+    case SDL_HAT_DOWN:
+        snake_redir(ctx, SNAKE_DIR_DOWN);
+        break;
+    default:
+        break;
+    }
+    return SDL_APP_CONTINUE;
+}
+
 SDL_AppResult SDL_AppIterate(void *appstate)
 {
     AppState *as = (AppState *)appstate;
@@ -305,7 +329,8 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
         }
     }
 
-    if (!SDL_Init(SDL_INIT_VIDEO)) {
+    if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK)) {
+        SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
         return SDL_APP_FAILURE;
     }
 
@@ -333,14 +358,35 @@ SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
     switch (event->type) {
     case SDL_EVENT_QUIT:
         return SDL_APP_SUCCESS;
+    case SDL_EVENT_JOYSTICK_ADDED:
+        if (joystick == NULL) {
+            joystick = SDL_OpenJoystick(event->jdevice.which);
+            if (!joystick) {
+                SDL_Log("Failed to open joystick ID %u: %s", (unsigned int) event->jdevice.which, SDL_GetError());
+            }
+        }
+        break;
+    case SDL_EVENT_JOYSTICK_REMOVED:
+        if (joystick && (SDL_GetJoystickID(joystick) == event->jdevice.which)) {
+            SDL_CloseJoystick(joystick);
+            joystick = NULL;
+        }
+        break;
+    case SDL_EVENT_JOYSTICK_HAT_MOTION:
+        return handle_hat_event_(ctx, event->jhat.value);
     case SDL_EVENT_KEY_DOWN:
         return handle_key_event_(ctx, event->key.scancode);
+    default:
+        break;
     }
     return SDL_APP_CONTINUE;
 }
 
 void SDL_AppQuit(void *appstate, SDL_AppResult result)
 {
+    if (joystick) {
+        SDL_CloseJoystick(joystick);
+    }
     if (appstate != NULL) {
         AppState *as = (AppState *)appstate;
         SDL_DestroyRenderer(as->renderer);

+ 11 - 12
libs/SDL3/examples/demo/04-bytepusher/bytepusher.c

@@ -27,7 +27,6 @@
 
 typedef struct {
     Uint8 ram[RAM_SIZE + 8];
-    Uint8 screenbuf[SCREEN_W * SCREEN_H];
     Uint64 last_tick;
     Uint64 tick_acc;
     SDL_Window* window;
@@ -187,7 +186,7 @@ SDL_AppResult SDL_AppInit(void** appstate, int argc, char* argv[]) {
     }
 
     if (!(vm->screen = SDL_CreateSurfaceFrom(
-        SCREEN_W, SCREEN_H, SDL_PIXELFORMAT_INDEX8, vm->screenbuf, SCREEN_W
+        SCREEN_W, SCREEN_H, SDL_PIXELFORMAT_INDEX8, vm->ram, SCREEN_W
     ))) {
         return SDL_APP_FAILURE;
     }
@@ -296,18 +295,18 @@ SDL_AppResult SDL_AppIterate(void* appstate) {
         SDL_UnlockTexture(vm->screentex);
 
         SDL_RenderTexture(vm->renderer, vm->screentex, NULL, NULL);
-    }
 
-    if (vm->display_help) {
-        print(vm, 4, 4, "Drop a BytePusher file in this");
-        print(vm, 8, 12, "window to load and run it!");
-        print(vm, 4, 28, "Press ENTER to switch between");
-        print(vm, 8, 36, "positional and symbolic input.");
-    }
+        if (vm->display_help) {
+            print(vm, 4, 4, "Drop a BytePusher file in this");
+            print(vm, 8, 12, "window to load and run it!");
+            print(vm, 4, 28, "Press ENTER to switch between");
+            print(vm, 8, 36, "positional and symbolic input.");
+        }
 
-    if (vm->status_ticks > 0) {
-        vm->status_ticks -= 1;
-        print(vm, 4, SCREEN_H - 12, vm->status);
+        if (vm->status_ticks > 0) {
+            vm->status_ticks -= 1;
+            print(vm, 4, SCREEN_H - 12, vm->status);
+        }
     }
 
     SDL_SetRenderTarget(vm->renderer, NULL);

+ 1 - 1
libs/SDL3/examples/input/01-joystick-polling/joystick-polling.c

@@ -41,7 +41,7 @@ SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
         return SDL_APP_FAILURE;
     }
 
-    if (!SDL_CreateWindowAndRenderer("examples/input/joystick-polling", 640, 480, 0, &window, &renderer)) {
+    if (!SDL_CreateWindowAndRenderer("examples/input/joystick-polling", 640, 480, SDL_WINDOW_RESIZABLE, &window, &renderer)) {
         SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
         return SDL_APP_FAILURE;
     }

+ 3 - 0
libs/SDL3/examples/renderer/19-affine-textures/README.txt

@@ -0,0 +1,3 @@
+This example creates an SDL window and renderer, and uses
+SDL_RenderTextureAffine to draw a 3D cube using only 2D rendering operations.
+

+ 145 - 0
libs/SDL3/examples/renderer/19-affine-textures/affine-textures.c

@@ -0,0 +1,145 @@
+/* affine-textures.c ... */
+
+/*
+* This example creates an SDL window and renderer, and then draws a cube
+* using affine-transformed textures every frame.
+*
+* This code is public domain. Feel free to use it for any purpose!
+*/
+
+#define SDL_MAIN_USE_CALLBACKS 1  /* use the callbacks instead of main() */
+#include <SDL3/SDL.h>
+#include <SDL3/SDL_main.h>
+
+/* We will use this renderer to draw into this window every frame. */
+static SDL_Window *window = NULL;
+static SDL_Renderer *renderer = NULL;
+static SDL_Texture *texture = NULL;
+static int texture_width = 0;
+static int texture_height = 0;
+
+#define WINDOW_WIDTH 640
+#define WINDOW_HEIGHT 480
+
+/* This function runs once at startup. */
+SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
+{
+    SDL_Surface *surface = NULL;
+    char *bmp_path = NULL;
+
+    SDL_SetAppMetadata("Example Renderer Affine Textures", "1.0", "com.example.renderer-affine-textures");
+
+    if (!SDL_Init(SDL_INIT_VIDEO)) {
+        SDL_Log("Couldn't initialize SDL: %s", SDL_GetError());
+        return SDL_APP_FAILURE;
+    }
+
+    if (!SDL_CreateWindowAndRenderer("examples/renderer/affine-textures", WINDOW_WIDTH, WINDOW_HEIGHT, 0, &window, &renderer)) {
+        SDL_Log("Couldn't create window/renderer: %s", SDL_GetError());
+        return SDL_APP_FAILURE;
+    }
+
+    /* Textures are pixel data that we upload to the video hardware for fast drawing. Lots of 2D
+       engines refer to these as "sprites." We'll do a static texture (upload once, draw many
+       times) with data from a bitmap file. */
+
+    /* SDL_Surface is pixel data the CPU can access. SDL_Texture is pixel data the GPU can access.
+       Load a .bmp into a surface, move it to a texture from there. */
+    SDL_asprintf(&bmp_path, "%ssample.bmp", SDL_GetBasePath());  /* allocate a string of the full file path */
+    surface = SDL_LoadBMP(bmp_path);
+    if (!surface) {
+        SDL_Log("Couldn't load bitmap: %s", SDL_GetError());
+        return SDL_APP_FAILURE;
+    }
+
+    SDL_free(bmp_path);  /* done with this, the file is loaded. */
+
+    texture_width = surface->w;
+    texture_height = surface->h;
+
+    texture = SDL_CreateTextureFromSurface(renderer, surface);
+    if (!texture) {
+        SDL_Log("Couldn't create static texture: %s", SDL_GetError());
+        return SDL_APP_FAILURE;
+    }
+
+    SDL_DestroySurface(surface);  /* done with this, the texture has a copy of the pixels now. */
+
+    return SDL_APP_CONTINUE;  /* carry on with the program! */
+}
+
+/* This function runs when a new event (mouse input, keypresses, etc) occurs. */
+SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
+{
+    if (event->type == SDL_EVENT_QUIT) {
+        return SDL_APP_SUCCESS;  /* end the program, reporting success to the OS. */
+    }
+    return SDL_APP_CONTINUE;  /* carry on with the program! */
+}
+
+/* This function runs once per frame, and is the heart of the program. */
+SDL_AppResult SDL_AppIterate(void *appstate)
+{
+    const float x0 = 0.5f * WINDOW_WIDTH;
+    const float y0 = 0.5f * WINDOW_HEIGHT;
+    const float px = SDL_min(WINDOW_WIDTH, WINDOW_HEIGHT) / SDL_sqrtf(3.0f);
+
+    const Uint64 now = SDL_GetTicks();
+    const float rad = (((float) ((int) (now % 2000))) / 2000.0f) * SDL_PI_F * 2;
+    const float cos = SDL_cosf(rad);
+    const float sin = SDL_sinf(rad);
+    const float k[3] = { 3.0f / SDL_sqrtf(50.0f), 4.0f / SDL_sqrtf(50.0f), 5.0f / SDL_sqrtf(50.0f)};
+    float mat[9] = { 
+         cos      + (1.0f-cos)*k[0]*k[0], -sin*k[2] + (1.0f-cos)*k[0]*k[1],  sin*k[1] + (1.0f-cos)*k[0]*k[2], 
+         sin*k[2] + (1.0f-cos)*k[0]*k[1],  cos      + (1.0f-cos)*k[1]*k[1], -sin*k[0] + (1.0f-cos)*k[1]*k[2], 
+        -sin*k[1] + (1.0f-cos)*k[0]*k[2],  sin*k[0] + (1.0f-cos)*k[1]*k[2],  cos      + (1.0f-cos)*k[2]*k[2],
+    };
+
+    float corners[16];
+    int i;
+
+    for (i = 0; i < 8; i++) {
+        const float x = (i & 1) ? -0.5f : 0.5f;
+        const float y = (i & 2) ? -0.5f : 0.5f;
+        const float z = (i & 4) ? -0.5f : 0.5f;
+        corners[0 + 2*i] = mat[0]*x + mat[1]*y + mat[2]*z;
+        corners[1 + 2*i] = mat[3]*x + mat[4]*y + mat[5]*z;
+    }
+
+    SDL_SetRenderDrawColor(renderer, 0x42, 0x87, 0xf5, SDL_ALPHA_OPAQUE);  // light blue background.
+    SDL_RenderClear(renderer);
+
+    for (i = 1; i < 7; i++) {
+        const int dir = 3 & ((i & 4) ? ~i : i);
+        const int odd = (i & 1) ^ ((i & 2) >> 1) ^ ((i & 4) >> 2);
+        if (0 < (odd ? 1.0f : -1.0f) * mat[5 + dir]) continue;
+        int origin_index = (1 << ((dir - 1) % 3));
+        int right_index = (1 << ((dir + odd) % 3)) | origin_index;
+        int down_index = (1 << ((dir + (odd^1)) % 3)) | origin_index;
+        if (!odd) {
+            origin_index ^= 7;
+            right_index ^= 7;
+            down_index ^= 7;
+        }
+        SDL_FPoint origin, right, down;
+        origin.x = x0 + px*corners[0 + 2*origin_index];
+        origin.y = y0 + px*corners[1 + 2*origin_index];
+        right.x  = x0 + px*corners[0 + 2*right_index];
+        right.y  = y0 + px*corners[1 + 2*right_index];
+        down.x   = x0 + px*corners[0 + 2*down_index];
+        down.y   = y0 + px*corners[1 + 2*down_index];
+        SDL_RenderTextureAffine(renderer, texture, NULL, &origin, &right, &down);
+    }
+
+    SDL_RenderPresent(renderer);
+
+    return SDL_APP_CONTINUE;
+}
+
+/* This function runs once at shutdown. */
+void SDL_AppQuit(void *appstate, SDL_AppResult result)
+{
+    SDL_DestroyTexture(texture);
+    /* SDL will clean up the window/renderer for us. */
+}
+

BIN
libs/SDL3/examples/renderer/19-affine-textures/onmouseover.webp


BIN
libs/SDL3/examples/renderer/19-affine-textures/thumbnail.png


+ 1 - 1
libs/SDL3/include/SDL3/SDL.h

@@ -20,7 +20,7 @@
 */
 
 /**
- * Main include header for the SDL library, version 3.2.10
+ * Main include header for the SDL library, version 3.3.0
  *
  * It is almost always best to include just this one header instead of
  * picking out individual headers included here. There are exceptions to

+ 1 - 1
libs/SDL3/include/SDL3/SDL_assert.h

@@ -132,7 +132,7 @@ extern "C" {
     #define SDL_TriggerBreakpoint() __debugbreak()
 #elif defined(_MSC_VER) && defined(_M_IX86)
     #define SDL_TriggerBreakpoint() { _asm { int 0x03 }  }
-#elif defined(ANDROID)
+#elif defined(ANDROID) || defined(__SYMBIAN32__)
     #include <assert.h>
     #define SDL_TriggerBreakpoint() assert(0)
 #elif SDL_HAS_BUILTIN(__builtin_debugtrap)

+ 219 - 9
libs/SDL3/include/SDL3/SDL_audio.h

@@ -1021,7 +1021,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_UnbindAudioStream(SDL_AudioStream *stream);
 /**
  * Query an audio stream for its currently-bound device.
  *
- * This reports the audio device that an audio stream is currently bound to.
+ * This reports the logical audio device that an audio stream is currently
+ * bound to.
  *
  * If not bound, or invalid, this returns zero, which is not a valid device
  * ID.
@@ -1149,14 +1150,14 @@ extern SDL_DECLSPEC float SDLCALL SDL_GetAudioStreamFrequencyRatio(SDL_AudioStre
  *
  * The frequency ratio is used to adjust the rate at which input data is
  * consumed. Changing this effectively modifies the speed and pitch of the
- * audio. A value greater than 1.0 will play the audio faster, and at a higher
- * pitch. A value less than 1.0 will play the audio slower, and at a lower
- * pitch.
+ * audio. A value greater than 1.0f will play the audio faster, and at a
+ * higher pitch. A value less than 1.0f will play the audio slower, and at a
+ * lower pitch. 1.0f means play at normal speed.
  *
  * This is applied during SDL_GetAudioStreamData, and can be continuously
  * changed to create various effects.
  *
- * \param stream the stream the frequency ratio is being changed.
+ * \param stream the stream on which the frequency ratio is being changed.
  * \param ratio the frequency ratio. 1.0 is normal speed. Must be between 0.01
  *              and 100.
  * \returns true on success or false on failure; call SDL_GetError() for more
@@ -1332,7 +1333,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetAudioStreamInputChannelMap(SDL_AudioStre
  * Channel maps are optional; most things do not need them, instead passing
  * data in the [order that SDL expects](CategoryAudio#channel-layouts).
  *
- * The output channel map reorders data that leaving a stream via
+ * The output channel map reorders data that is leaving a stream via
  * SDL_GetAudioStreamData.
  *
  * Each item in the array represents an input channel, and its value is the
@@ -1414,6 +1415,136 @@ extern SDL_DECLSPEC bool SDLCALL SDL_SetAudioStreamOutputChannelMap(SDL_AudioStr
  */
 extern SDL_DECLSPEC bool SDLCALL SDL_PutAudioStreamData(SDL_AudioStream *stream, const void *buf, int len);
 
+/**
+ * A callback that fires for completed SDL_PutAudioStreamDataNoCopy() data.
+ *
+ * When using SDL_PutAudioStreamDataNoCopy() to provide data to an
+ * SDL_AudioStream, it's not safe to dispose of the data until the stream has
+ * completely consumed it. Often times it's difficult to know exactly when
+ * this has happened.
+ *
+ * This callback fires once when the stream no longer needs the buffer,
+ * allowing the app to easily free or reuse it.
+ *
+ * \param userdata an opaque pointer provided by the app for their personal
+ *                 use.
+ * \param buf the pointer provided to SDL_PutAudioStreamDataNoCopy().
+ * \param buflen the size of buffer, in bytes, provided to
+ *               SDL_PutAudioStreamDataNoCopy().
+ *
+ * \threadsafety This callbacks may run from any thread, so if you need to
+ *               protect shared data, you should use SDL_LockAudioStream to
+ *               serialize access; this lock will be held before your callback
+ *               is called, so your callback does not need to manage the lock
+ *               explicitly.
+ *
+ * \since This datatype is available since SDL 3.4.0.
+ *
+ * \sa SDL_SetAudioStreamGetCallback
+ * \sa SDL_SetAudioStreamPutCallback
+ */
+typedef void (SDLCALL *SDL_AudioStreamDataCompleteCallback)(void *userdata, const void *buf, int buflen);
+
+/**
+ * Add external data to an audio stream without copying it.
+ *
+ * Unlike SDL_PutAudioStreamData(), this function does not make a copy of the
+ * provided data, instead storing the provided pointer. This means that the
+ * put operation does not need to allocate and copy the data, but the original
+ * data must remain available until the stream is done with it, either by
+ * being read from the stream in its entirety, or a call to
+ * SDL_ClearAudioStream() or SDL_DestroyAudioStream().
+ *
+ * The data must match the format/channels/samplerate specified in the latest
+ * call to SDL_SetAudioStreamFormat, or the format specified when creating the
+ * stream if it hasn't been changed.
+ *
+ * An optional callback may be provided, which is called when the stream no
+ * longer needs the data. Once this callback fires, the stream will not access
+ * the data again. This callback will fire for any reason the data is no
+ * longer needed, including clearing or destroying the stream.
+ *
+ * Note that there is still an allocation to store tracking information, so
+ * this function is more efficient for larger blocks of data. If you're
+ * planning to put a few samples at a time, it will be more efficient to use
+ * SDL_PutAudioStreamData(), which allocates and buffers in blocks.
+ *
+ * \param stream the stream the audio data is being added to.
+ * \param buf a pointer to the audio data to add.
+ * \param len the number of bytes to add to the stream.
+ * \param callback the callback function to call when the data is no longer
+ *                 needed by the stream. May be NULL.
+ * \param userdata an opaque pointer provided to the callback for its own
+ *                 personal use.
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ *          information.
+ *
+ * \threadsafety It is safe to call this function from any thread, but if the
+ *               stream has a callback set, the caller might need to manage
+ *               extra locking.
+ *
+ * \since This function is available since SDL 3.4.0.
+ *
+ * \sa SDL_ClearAudioStream
+ * \sa SDL_FlushAudioStream
+ * \sa SDL_GetAudioStreamData
+ * \sa SDL_GetAudioStreamQueued
+ */
+extern SDL_DECLSPEC bool SDLCALL SDL_PutAudioStreamDataNoCopy(SDL_AudioStream *stream, const void *buf, int len, SDL_AudioStreamDataCompleteCallback callback, void *userdata);
+
+/**
+ * Add data to the stream with each channel in a separate array.
+ *
+ * This data must match the format/channels/samplerate specified in the latest
+ * call to SDL_SetAudioStreamFormat, or the format specified when creating the
+ * stream if it hasn't been changed.
+ *
+ * The data will be interleaved and queued. Note that SDL_AudioStream only
+ * operates on interleaved data, so this is simply a convenience function for
+ * easily queueing data from sources that provide separate arrays. There is no
+ * equivalent function to retrieve planar data.
+ *
+ * The arrays in `channel_buffers` are ordered as they are to be interleaved;
+ * the first array will be the first sample in the interleaved data. Any
+ * individual array may be NULL; in this case, silence will be interleaved for
+ * that channel.
+ *
+ * `num_channels` specifies how many arrays are in `channel_buffers`. This can
+ * be used as a safety to prevent overflow, in case the stream format has
+ * changed elsewhere. If more channels are specified than the current input
+ * spec, they are ignored. If less channels are specified, the missing arrays
+ * are treated as if they are NULL (silence is written to those channels). If
+ * the count is -1, SDL will assume the array count matches the current input
+ * spec.
+ *
+ * Note that `num_samples` is the number of _samples per array_. This can also
+ * be thought of as the number of _sample frames_ to be queued. A value of 1
+ * with stereo arrays will queue two samples to the stream. This is different
+ * than SDL_PutAudioStreamData, which wants the size of a single array in
+ * bytes.
+ *
+ * \param stream the stream the audio data is being added to.
+ * \param channel_buffers a pointer to an array of arrays, one array per
+ *                        channel.
+ * \param num_channels the number of arrays in `channel_buffers` or -1.
+ * \param num_samples the number of _samples_ per array to write to the
+ *                    stream.
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ *          information.
+ *
+ * \threadsafety It is safe to call this function from any thread, but if the
+ *               stream has a callback set, the caller might need to manage
+ *               extra locking.
+ *
+ * \since This function is available since SDL 3.4.0.
+ *
+ * \sa SDL_ClearAudioStream
+ * \sa SDL_FlushAudioStream
+ * \sa SDL_GetAudioStreamData
+ * \sa SDL_GetAudioStreamQueued
+ */
+extern SDL_DECLSPEC bool SDLCALL SDL_PutAudioStreamPlanarData(SDL_AudioStream *stream, const void * const *channel_buffers, int num_channels, int num_samples);
+
 /**
  * Get converted/resampled data from the stream.
  *
@@ -1583,8 +1714,8 @@ extern SDL_DECLSPEC bool SDLCALL SDL_PauseAudioStreamDevice(SDL_AudioStream *str
  * previously been paused. Once unpaused, any bound audio streams will begin
  * to progress again, and audio can be generated.
  *
- * Remember, SDL_OpenAudioDeviceStream opens device in a paused state, so this
- * function call is required for audio playback to begin on such device.
+ * SDL_OpenAudioDeviceStream opens audio devices in a paused state, so this
+ * function call is required for audio playback to begin on such devices.
  *
  * \param stream the audio stream associated with the audio device to resume.
  * \returns true on success or false on failure; call SDL_GetError() for more
@@ -1841,7 +1972,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroyAudioStream(SDL_AudioStream *stream)
  * Also unlike other functions, the audio device begins paused. This is to map
  * more closely to SDL2-style behavior, since there is no extra step here to
  * bind a stream to begin audio flowing. The audio device should be resumed
- * with `SDL_ResumeAudioStreamDevice(stream);`
+ * with SDL_ResumeAudioStreamDevice().
  *
  * This function works with both playback and recording devices.
  *
@@ -1887,6 +2018,85 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroyAudioStream(SDL_AudioStream *stream)
  */
 extern SDL_DECLSPEC SDL_AudioStream * SDLCALL SDL_OpenAudioDeviceStream(SDL_AudioDeviceID devid, const SDL_AudioSpec *spec, SDL_AudioStreamCallback callback, void *userdata);
 
+/**
+ * A callback that fires around an audio device's processing work.
+ *
+ * This callback fires when a logical audio device is about to start accessing
+ * its bound audio streams, and fires again when it has finished accessing
+ * them. It covers the range of one "iteration" of the audio device.
+ *
+ * It can be useful to use this callback to update state that must apply to
+ * all bound audio streams atomically: to make sure state changes don't happen
+ * while half of the streams are already processed for the latest audio
+ * buffer.
+ *
+ * This callback should run as quickly as possible and not block for any
+ * significant time, as this callback delays submission of data to the audio
+ * device, which can cause audio playback problems. This callback delays all
+ * audio processing across a single physical audio device: all its logical
+ * devices and all bound audio streams. Use it carefully.
+ *
+ * \param userdata a pointer provided by the app through
+ *                 SDL_SetAudioPostmixCallback, for its own use.
+ * \param devid the audio device this callback is running for.
+ * \param start true if this is the start of the iteration, false if the end.
+ *
+ * \threadsafety This will run from a background thread owned by SDL. The
+ *               application is responsible for locking resources the callback
+ *               touches that need to be protected.
+ *
+ * \since This datatype is available since SDL 3.4.0.
+ *
+ * \sa SDL_SetAudioIterationCallbacks
+ */
+typedef void (SDLCALL *SDL_AudioIterationCallback)(void *userdata, SDL_AudioDeviceID devid, bool start);
+
+/**
+ * Set callbacks that fire around a new iteration of audio device processing.
+ *
+ * Two callbacks are provided here: one that runs when a device is about to
+ * process its bound audio streams, and another that runs when the device has
+ * finished processing them.
+ *
+ * These callbacks can run at any time, and from any thread; if you need to
+ * serialize access to your app's data, you should provide and use a mutex or
+ * other synchronization device.
+ *
+ * Generally these callbacks are used to apply state that applies to multiple
+ * bound audio streams, with a guarantee that the audio device's thread isn't
+ * halfway through processing them. Generally a finer-grained lock through
+ * SDL_LockAudioStream() is more appropriate.
+ *
+ * The callbacks are extremely time-sensitive; the callback should do the
+ * least amount of work possible and return as quickly as it can. The longer
+ * the callback runs, the higher the risk of audio dropouts or other problems.
+ *
+ * This function will block until the audio device is in between iterations,
+ * so any existing callback that might be running will finish before this
+ * function sets the new callback and returns.
+ *
+ * Physical devices do not accept these callbacks, only logical devices
+ * created through SDL_OpenAudioDevice() can be.
+ *
+ * Setting a NULL callback function disables any previously-set callback.
+ * Either callback may be NULL, and the same callback is permitted to be used
+ * for both.
+ *
+ * \param devid the ID of an opened audio device.
+ * \param start a callback function to be called at the start of an iteration.
+ *              Can be NULL.
+ * \param end a callback function to be called at the end of an iteration. Can
+ *            be NULL.
+ * \param userdata app-controlled pointer passed to callback. Can be NULL.
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ *          information.
+ *
+ * \threadsafety It is safe to call this function from any thread.
+ *
+ * \since This function is available since SDL 3.4.0.
+ */
+extern SDL_DECLSPEC bool SDLCALL SDL_SetAudioIterationCallbacks(SDL_AudioDeviceID devid, SDL_AudioIterationCallback start, SDL_AudioIterationCallback end, void *userdata);
+
 /**
  * A callback that fires when data is about to be fed to an audio device.
  *

+ 70 - 3
libs/SDL3/include/SDL3/SDL_begin_code.h

@@ -261,9 +261,9 @@
  *
  * On compilers without restrict support, this is defined to nothing.
  *
- * \since This macro is available since SDL 3.2.0.
+ * \since This macro is available since SDL 3.4.0.
  */
-#define SDL_RESTRICT __restrict__
+#define SDL_RESTRICT __restrict
 
 /**
  * Check if the compiler supports a given builtin functionality.
@@ -281,9 +281,61 @@
  */
 #define SDL_HAS_BUILTIN(x) __has_builtin(x)
 
+/**
+ * A macro to specify data alignment.
+ *
+ * This informs the compiler that a given datatype or variable must be aligned
+ * to a specific byte count.
+ *
+ * For example:
+ *
+ * ```c
+ * // make sure this is struct is aligned to 16 bytes for SIMD access.
+ * typedef struct {
+ *    float x, y, z, w;
+ * } SDL_ALIGNED(16) MySIMDAlignedData;
+ *
+ * // make sure this one field in a struct is aligned to 16 bytes for SIMD access.
+ * typedef struct {
+ *    SomeStuff stuff;
+ *    float position[4] SDL_ALIGNED(16);
+ *    SomeOtherStuff other_stuff;
+ * } MyStruct;
+ *
+ * // make sure this variable is aligned to 32 bytes.
+ * int SDL_ALIGNED(32) myval = 0;
+ * ```
+ *
+ * Alignment is only guaranteed for things the compiler places: local
+ * variables on the stack and global/static variables. To dynamically allocate
+ * something that respects this alignment, use SDL_aligned_alloc() or some
+ * other mechanism.
+ *
+ * On compilers without alignment support, this macro is defined to an invalid
+ * symbol, to make it clear that the current compiler is likely to generate
+ * incorrect code when it sees this macro.
+ *
+ * \param x the byte count to align to, so the data's address will be a
+ *          multiple of this value.
+ *
+ * \since This macro is available since SDL 3.4.0.
+ */
+#define SDL_ALIGNED(x) __attribute__((aligned(x)))
+
 /* end of wiki documentation section. */
 #endif
 
+/* `restrict` is from C99, but __restrict works with both Visual Studio and GCC. */
+#ifndef SDL_RESTRICT
+#  if defined(restrict) || ((defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)))
+#    define SDL_RESTRICT restrict
+#  elif defined(_MSC_VER) || defined(__GNUC__) || defined(__clang__)
+#    define SDL_RESTRICT __restrict
+#  else
+#    define SDL_RESTRICT
+#  endif
+#endif
+
 #ifndef SDL_HAS_BUILTIN
 #ifdef __has_builtin
 #define SDL_HAS_BUILTIN(x) __has_builtin(x)
@@ -389,7 +441,7 @@
 #endif /* SDL_FORCE_INLINE not defined */
 
 #ifndef SDL_NORETURN
-#ifdef __GNUC__
+#if defined(__GNUC__)
 #define SDL_NORETURN __attribute__((noreturn))
 #elif defined(_MSC_VER)
 #define SDL_NORETURN __declspec(noreturn)
@@ -484,3 +536,18 @@
 #define SDL_ALLOC_SIZE2(p1, p2)
 #endif
 #endif /* SDL_ALLOC_SIZE2 not defined */
+
+#ifndef SDL_ALIGNED
+#if defined(__clang__) || defined(__GNUC__)
+#define SDL_ALIGNED(x) __attribute__((aligned(x)))
+#elif defined(_MSC_VER)
+#define SDL_ALIGNED(x) __declspec(align(x))
+#elif defined(__cplusplus) && (__cplusplus >= 201103L)
+#define SDL_ALIGNED(x) alignas(x)
+#elif defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)
+#define SDL_ALIGNED(x) _Alignas(x)
+#else
+#define SDL_ALIGNED(x) PLEASE_DEFINE_SDL_ALIGNED
+#endif
+#endif /* SDL_ALIGNED not defined */
+

+ 37 - 2
libs/SDL3/include/SDL3/SDL_events.h

@@ -135,7 +135,8 @@ typedef enum SDL_EventType
     /* 0x201 was SDL_SYSWMEVENT, reserve the number for sdl2-compat */
     SDL_EVENT_WINDOW_SHOWN = 0x202,     /**< Window has been shown */
     SDL_EVENT_WINDOW_HIDDEN,            /**< Window has been hidden */
-    SDL_EVENT_WINDOW_EXPOSED,           /**< Window has been exposed and should be redrawn, and can be redrawn directly from event watchers for this event */
+    SDL_EVENT_WINDOW_EXPOSED,           /**< Window has been exposed and should be redrawn, and can be redrawn directly from event watchers for this event.
+                                             data1 is 1 for live-resize expose events, 0 otherwise. */
     SDL_EVENT_WINDOW_MOVED,             /**< Window has been moved to data1, data2 */
     SDL_EVENT_WINDOW_RESIZED,           /**< Window has been resized to data1xdata2 */
     SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED,/**< The pixel size of the window has changed to data1xdata2 */
@@ -492,6 +493,8 @@ typedef struct SDL_MouseWheelEvent
     SDL_MouseWheelDirection direction; /**< Set to one of the SDL_MOUSEWHEEL_* defines. When FLIPPED the values in X and Y will be opposite. Multiply by -1 to change them back */
     float mouse_x;      /**< X coordinate, relative to window */
     float mouse_y;      /**< Y coordinate, relative to window */
+    Sint32 integer_x;   /**< The amount scrolled horizontally, accumulated to whole scroll "ticks" (added in 3.2.12) */
+    Sint32 integer_y;   /**< The amount scrolled vertically, accumulated to whole scroll "ticks" (added in 3.2.12) */
 } SDL_MouseWheelEvent;
 
 /**
@@ -779,7 +782,7 @@ typedef struct SDL_TouchFingerEvent
 } SDL_TouchFingerEvent;
 
 /**
- * Pressure-sensitive pen proximity event structure (event.pmotion.*)
+ * Pressure-sensitive pen proximity event structure (event.pproximity.*)
  *
  * When a pen becomes visible to the system (it is close enough to a tablet,
  * etc), SDL will send an SDL_EVENT_PEN_PROXIMITY_IN event with the new pen's
@@ -1565,6 +1568,38 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_RegisterEvents(int numevents);
  */
 extern SDL_DECLSPEC SDL_Window * SDLCALL SDL_GetWindowFromEvent(const SDL_Event *event);
 
+/**
+ * Generate a human-readable description of an event.
+ *
+ * This will fill `buf` with a null-terminated string that might look
+ * something like this:
+ *
+ * ```
+ * SDL_EVENT_MOUSE_MOTION (timestamp=1140256324 windowid=2 which=0 state=0 x=492.99 y=139.09 xrel=52 yrel=6)
+ * ```
+ *
+ * The exact format of the string is not guaranteed; it is intended for
+ * logging purposes, to be read by a human, and not parsed by a computer.
+ *
+ * The returned value follows the same rules as SDL_snprintf(): `buf` will
+ * always be NULL-terminated (unless `buflen` is zero), and will be truncated
+ * if `buflen` is too small. The return code is the number of bytes needed for
+ * the complete string, not counting the NULL-terminator, whether the string
+ * was truncated or not. Unlike SDL_snprintf(), though, this function never
+ * returns -1.
+ *
+ * \param event an event to describe. May be NULL.
+ * \param buf the buffer to fill with the description string. May be NULL.
+ * \param buflen the maximum bytes that can be written to `buf`.
+ * \returns number of bytes needed for the full string, not counting the
+ *          null-terminator byte.
+ *
+ * \threadsafety It is safe to call this function from any thread.
+ *
+ * \since This function is available since SDL 3.4.0.
+ */
+extern SDL_DECLSPEC int SDLCALL SDL_GetEventDescription(const SDL_Event *event, char *buf, int buflen);
+
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 }

+ 2 - 2
libs/SDL3/include/SDL3/SDL_filesystem.h

@@ -444,10 +444,10 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetPathInfo(const char *path, SDL_PathInfo
  * Enumerate a directory tree, filtered by pattern, and return a list.
  *
  * Files are filtered out if they don't match the string in `pattern`, which
- * may contain wildcard characters '\*' (match everything) and '?' (match one
+ * may contain wildcard characters `*` (match everything) and `?` (match one
  * character). If pattern is NULL, no filtering is done and all results are
  * returned. Subdirectories are permitted, and are specified with a path
- * separator of '/'. Wildcard characters '\*' and '?' never match a path
+ * separator of `/`. Wildcard characters `*` and `?` never match a path
  * separator.
  *
  * `flags` may be set to SDL_GLOB_CASEINSENSITIVE to make the pattern matching

+ 8 - 4
libs/SDL3/include/SDL3/SDL_gamepad.h

@@ -118,6 +118,7 @@ typedef enum SDL_GamepadType
     SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT,
     SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT,
     SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR,
+    SDL_GAMEPAD_TYPE_GAMECUBE,
     SDL_GAMEPAD_TYPE_COUNT
 } SDL_GamepadType;
 
@@ -127,8 +128,9 @@ typedef enum SDL_GamepadType
  * For controllers that use a diamond pattern for the face buttons, the
  * south/east/west/north buttons below correspond to the locations in the
  * diamond pattern. For Xbox controllers, this would be A/B/X/Y, for Nintendo
- * Switch controllers, this would be B/A/Y/X, for PlayStation controllers this
- * would be Cross/Circle/Square/Triangle.
+ * Switch controllers, this would be B/A/Y/X, for GameCube controllers this
+ * would be A/X/B/Y, for PlayStation controllers this would be
+ * Cross/Circle/Square/Triangle.
  *
  * For controllers that don't use a diamond pattern for the face buttons, the
  * south/east/west/north buttons indicate the buttons labeled A, B, C, D, or
@@ -1156,10 +1158,12 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GamepadHasAxis(SDL_Gamepad *gamepad, SDL_Ga
  * return a negative value. Note that this differs from the value reported by
  * the lower-level SDL_GetJoystickAxis(), which normally uses the full range.
  *
+ * Note that for invalid gamepads or axes, this will return 0. Zero is also a
+ * valid value in normal operation; usually it means a centered axis.
+ *
  * \param gamepad a gamepad.
  * \param axis an axis index (one of the SDL_GamepadAxis values).
- * \returns axis state (including 0) on success or 0 (also) on failure; call
- *          SDL_GetError() for more information.
+ * \returns axis state.
  *
  * \since This function is available since SDL 3.2.0.
  *

+ 285 - 48
libs/SDL3/include/SDL3/SDL_gpu.h

@@ -206,14 +206,20 @@
  * underlying graphics API. While it's possible that we have done something
  * inefficiently, it's very unlikely especially if you are relatively
  * inexperienced with GPU rendering. Please see the performance tips above and
- * make sure you are following them. Additionally, tools like RenderDoc can be
- * very helpful for diagnosing incorrect behavior and performance issues.
+ * make sure you are following them. Additionally, tools like
+ * [RenderDoc](https://renderdoc.org/)
+ * can be very helpful for diagnosing incorrect behavior and performance
+ * issues.
  *
  * ## System Requirements
  *
- * **Vulkan:** Supported on Windows, Linux, Nintendo Switch, and certain
- * Android devices. Requires Vulkan 1.0 with the following extensions and
- * device features:
+ * ### Vulkan
+ *
+ * SDL driver name: "vulkan" (for use in SDL_CreateGPUDevice() and
+ * SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING)
+ *
+ * Supported on Windows, Linux, Nintendo Switch, and certain Android devices.
+ * Requires Vulkan 1.0 with the following extensions and device features:
  *
  * - `VK_KHR_swapchain`
  * - `VK_KHR_maintenance1`
@@ -222,13 +228,21 @@
  * - `depthClamp`
  * - `shaderClipDistance`
  * - `drawIndirectFirstInstance`
+ * - `sampleRateShading`
+ *
+ * ### D3D12
+ *
+ * SDL driver name: "direct3d12"
+ *
+ * Supported on Windows 10 or newer, Xbox One (GDK), and Xbox Series X|S
+ * (GDK). Requires a GPU that supports DirectX 12 Feature Level 11_1.
  *
- * **D3D12:** Supported on Windows 10 or newer, Xbox One (GDK), and Xbox
- * Series X|S (GDK). Requires a GPU that supports DirectX 12 Feature Level
- * 11_1.
+ * ### Metal
  *
- * **Metal:** Supported on macOS 10.14+ and iOS/tvOS 13.0+. Hardware
- * requirements vary by operating system:
+ * SDL driver name: "metal"
+ *
+ * Supported on macOS 10.14+ and iOS/tvOS 13.0+. Hardware requirements vary by
+ * operating system:
  *
  * - macOS requires an Apple Silicon or
  *   [Intel Mac2 family](https://developer.apple.com/documentation/metal/mtlfeatureset/mtlfeatureset_macos_gpufamily2_v1?language=objc)
@@ -236,6 +250,26 @@
  * - iOS/tvOS requires an A9 GPU or newer
  * - iOS Simulator and tvOS Simulator are unsupported
  *
+ * ## Coordinate System
+ *
+ * The GPU API uses a left-handed coordinate system, following the convention
+ * of D3D12 and Metal. Specifically:
+ *
+ * - **Normalized Device Coordinates:** The lower-left corner has an x,y
+ *   coordinate of `(-1.0, -1.0)`. The upper-right corner is `(1.0, 1.0)`. Z
+ *   values range from `[0.0, 1.0]` where 0 is the near plane.
+ * - **Viewport Coordinates:** The top-left corner has an x,y coordinate of
+ *   `(0, 0)` and extends to the bottom-right corner at `(viewportWidth,
+ *   viewportHeight)`. +Y is down.
+ * - **Texture Coordinates:** The top-left corner has an x,y coordinate of
+ *   `(0, 0)` and extends to the bottom-right corner at `(1.0, 1.0)`. +Y is
+ *   down.
+ *
+ * If the backend driver differs from this convention (e.g. Vulkan, which has
+ * an NDC that assumes +Y is down), SDL will automatically convert the
+ * coordinate system behind the scenes, so you don't need to perform any
+ * coordinate flipping logic in your shaders.
+ *
  * ## Uniform Data
  *
  * Uniforms are for passing data to shaders. The uniform data will be constant
@@ -301,6 +335,39 @@
  * unreferenced data in a bound resource without cycling, but overwriting a
  * section of data that has already been referenced will produce unexpected
  * results.
+ *
+ * ## Debugging
+ *
+ * At some point of your GPU journey, you will probably encounter issues that
+ * are not traceable with regular debugger - for example, your code compiles
+ * but you get an empty screen, or your shader fails in runtime.
+ *
+ * For debugging such cases, there are tools that allow visually inspecting
+ * the whole GPU frame, every drawcall, every bound resource, memory buffers,
+ * etc. They are the following, per platform:
+ *
+ * * For Windows/Linux, use
+ *   [RenderDoc](https://renderdoc.org/)
+ * * For MacOS (Metal), use Xcode built-in debugger (Open XCode, go to Debug >
+ *   Debug Executable..., select your application, set "GPU Frame Capture" to
+ *   "Metal" in scheme "Options" window, run your app, and click the small
+ *   Metal icon on the bottom to capture a frame)
+ *
+ * Aside from that, you may want to enable additional debug layers to receive
+ * more detailed error messages, based on your GPU backend:
+ *
+ * * For D3D12, the debug layer is an optional feature that can be installed
+ *   via "Windows Settings -> System -> Optional features" and adding the
+ *   "Graphics Tools" optional feature.
+ * * For Vulkan, you will need to install Vulkan SDK on Windows, and on Linux,
+ *   you usually have some sort of `vulkan-validation-layers` system package
+ *   that should be installed.
+ * * For Metal, it should be enough just to run the application from XCode to
+ *   receive detailed errors or warnings in the output.
+ *
+ * Don't hesitate to use tools as RenderDoc when encountering runtime issues
+ * or unexpected output on screen, quick GPU frame inspection can usually help
+ * you fix the majority of such problems.
  */
 
 #ifndef SDL_gpu_h_
@@ -1310,6 +1377,17 @@ typedef struct SDL_GPUViewport
  * A structure specifying parameters related to transferring data to or from a
  * texture.
  *
+ * If either of `pixels_per_row` or `rows_per_layer` is zero, then width and
+ * height of passed SDL_GPUTextureRegion to SDL_UploadToGPUTexture or
+ * SDL_DownloadFromGPUTexture are used as default values respectively and data
+ * is considered to be tightly packed.
+ *
+ * **WARNING**: Direct3D 12 requires texture data row pitch to be 256 byte
+ * aligned, and offsets to be aligned to 512 bytes. If they are not, SDL will
+ * make a temporary copy of the data that is properly aligned, but this adds
+ * overhead to the transfer process. Apps can avoid this by aligning their
+ * data appropriately, or using a different GPU backend than Direct3D 12.
+ *
  * \since This struct is available since SDL 3.2.0.
  *
  * \sa SDL_UploadToGPUTexture
@@ -1391,7 +1469,7 @@ typedef struct SDL_GPUTextureRegion
  */
 typedef struct SDL_GPUBlitRegion
 {
-    SDL_GPUTexture *texture;  /**< The texture. */
+    SDL_GPUTexture *texture;      /**< The texture. */
     Uint32 mip_level;             /**< The mip level index of the region. */
     Uint32 layer_or_depth_plane;  /**< The layer index or depth plane of the region. This value is treated as a layer index on 2D array and cube textures, and as a depth plane on 3D textures. */
     Uint32 x;                     /**< The left offset of the region. */
@@ -1520,8 +1598,8 @@ typedef struct SDL_GPUSamplerCreateInfo
     SDL_GPUCompareOp compare_op;               /**< The comparison operator to apply to fetched data before filtering. */
     float min_lod;                             /**< Clamps the minimum of the computed LOD value. */
     float max_lod;                             /**< Clamps the maximum of the computed LOD value. */
-    bool enable_anisotropy;                /**< true to enable anisotropic filtering. */
-    bool enable_compare;                   /**< true to enable comparison against a reference value during lookups. */
+    bool enable_anisotropy;                    /**< true to enable anisotropic filtering. */
+    bool enable_compare;                       /**< true to enable comparison against a reference value during lookups. */
     Uint8 padding1;
     Uint8 padding2;
 
@@ -1613,6 +1691,9 @@ typedef struct SDL_GPUStencilOpState
  * \since This struct is available since SDL 3.2.0.
  *
  * \sa SDL_GPUColorTargetDescription
+ * \sa SDL_GPUBlendFactor
+ * \sa SDL_GPUBlendOp
+ * \sa SDL_GPUColorComponentFlags
  */
 typedef struct SDL_GPUColorTargetBlendState
 {
@@ -1623,8 +1704,8 @@ typedef struct SDL_GPUColorTargetBlendState
     SDL_GPUBlendFactor dst_alpha_blendfactor;     /**< The value to be multiplied by the destination alpha. */
     SDL_GPUBlendOp alpha_blend_op;                /**< The blend operation for the alpha component. */
     SDL_GPUColorComponentFlags color_write_mask;  /**< A bitmask specifying which of the RGBA components are enabled for writing. Writes to all channels if enable_color_write_mask is false. */
-    bool enable_blend;                        /**< Whether blending is enabled for the color target. */
-    bool enable_color_write_mask;             /**< Whether the color write mask is enabled. */
+    bool enable_blend;                            /**< Whether blending is enabled for the color target. */
+    bool enable_color_write_mask;                 /**< Whether the color write mask is enabled. */
     Uint8 padding1;
     Uint8 padding2;
 } SDL_GPUColorTargetBlendState;
@@ -1636,6 +1717,8 @@ typedef struct SDL_GPUColorTargetBlendState
  * \since This struct is available since SDL 3.2.0.
  *
  * \sa SDL_CreateGPUShader
+ * \sa SDL_GPUShaderFormat
+ * \sa SDL_GPUShaderStage
  */
 typedef struct SDL_GPUShaderCreateInfo
 {
@@ -1741,8 +1824,8 @@ typedef struct SDL_GPURasterizerState
     float depth_bias_constant_factor;  /**< A scalar factor controlling the depth value added to each fragment. */
     float depth_bias_clamp;            /**< The maximum depth bias of a fragment. */
     float depth_bias_slope_factor;     /**< A scalar factor applied to a fragment's slope in depth calculations. */
-    bool enable_depth_bias;        /**< true to bias fragment depth values. */
-    bool enable_depth_clip;        /**< true to enable depth clip, false to enable depth clamp. */
+    bool enable_depth_bias;            /**< true to bias fragment depth values. */
+    bool enable_depth_clip;            /**< true to enable depth clip, false to enable depth clamp. */
     Uint8 padding1;
     Uint8 padding2;
 } SDL_GPURasterizerState;
@@ -1759,8 +1842,8 @@ typedef struct SDL_GPUMultisampleState
 {
     SDL_GPUSampleCount sample_count;  /**< The number of samples to be used in rasterization. */
     Uint32 sample_mask;               /**< Reserved for future use. Must be set to 0. */
-    bool enable_mask;             /**< Reserved for future use. Must be set to false. */
-    Uint8 padding1;
+    bool enable_mask;                 /**< Reserved for future use. Must be set to false. */
+    bool enable_alpha_to_coverage;    /**< true enables the alpha-to-coverage feature. */
     Uint8 padding2;
     Uint8 padding3;
 } SDL_GPUMultisampleState;
@@ -1780,9 +1863,9 @@ typedef struct SDL_GPUDepthStencilState
     SDL_GPUStencilOpState front_stencil_state;  /**< The stencil op state for front-facing triangles. */
     Uint8 compare_mask;                         /**< Selects the bits of the stencil values participating in the stencil test. */
     Uint8 write_mask;                           /**< Selects the bits of the stencil values updated by the stencil test. */
-    bool enable_depth_test;                 /**< true enables the depth test. */
-    bool enable_depth_write;                /**< true enables depth writes. Depth writes are always disabled when enable_depth_test is false. */
-    bool enable_stencil_test;               /**< true enables the stencil test. */
+    bool enable_depth_test;                     /**< true enables the depth test. */
+    bool enable_depth_write;                    /**< true enables depth writes. Depth writes are always disabled when enable_depth_test is false. */
+    bool enable_stencil_test;                   /**< true enables the stencil test. */
     Uint8 padding1;
     Uint8 padding2;
     Uint8 padding3;
@@ -1817,7 +1900,7 @@ typedef struct SDL_GPUGraphicsPipelineTargetInfo
     const SDL_GPUColorTargetDescription *color_target_descriptions;  /**< A pointer to an array of color target descriptions. */
     Uint32 num_color_targets;                                        /**< The number of color target descriptions in the above array. */
     SDL_GPUTextureFormat depth_stencil_format;                       /**< The pixel format of the depth-stencil target. Ignored if has_depth_stencil_target is false. */
-    bool has_depth_stencil_target;                               /**< true specifies that the pipeline uses a depth-stencil target. */
+    bool has_depth_stencil_target;                                   /**< true specifies that the pipeline uses a depth-stencil target. */
     Uint8 padding1;
     Uint8 padding2;
     Uint8 padding3;
@@ -1924,8 +2007,8 @@ typedef struct SDL_GPUColorTargetInfo
     SDL_GPUTexture *resolve_texture; /**< The texture that will receive the results of a multisample resolve operation. Ignored if a RESOLVE* store_op is not used. */
     Uint32 resolve_mip_level;        /**< The mip level of the resolve texture to use for the resolve operation. Ignored if a RESOLVE* store_op is not used. */
     Uint32 resolve_layer;            /**< The layer index of the resolve texture to use for the resolve operation. Ignored if a RESOLVE* store_op is not used. */
-    bool cycle;                  /**< true cycles the texture if the texture is bound and load_op is not LOAD */
-    bool cycle_resolve_texture;  /**< true cycles the resolve texture if the resolve texture is bound. Ignored if a RESOLVE* store_op is not used. */
+    bool cycle;                      /**< true cycles the texture if the texture is bound and load_op is not LOAD */
+    bool cycle_resolve_texture;      /**< true cycles the resolve texture if the resolve texture is bound. Ignored if a RESOLVE* store_op is not used. */
     Uint8 padding1;
     Uint8 padding2;
 } SDL_GPUColorTargetInfo;
@@ -1982,7 +2065,7 @@ typedef struct SDL_GPUDepthStencilTargetInfo
     SDL_GPUStoreOp store_op;               /**< What is done with the depth results of the render pass. */
     SDL_GPULoadOp stencil_load_op;         /**< What is done with the stencil contents at the beginning of the render pass. */
     SDL_GPUStoreOp stencil_store_op;       /**< What is done with the stencil results of the render pass. */
-    bool cycle;                        /**< true cycles the texture if the texture is bound and any load ops are not LOAD */
+    bool cycle;                            /**< true cycles the texture if the texture is bound and any load ops are not LOAD */
     Uint8 clear_stencil;                   /**< The value to clear the stencil component to at the beginning of the render pass. Ignored if SDL_GPU_LOADOP_CLEAR is not used. */
     Uint8 padding1;
     Uint8 padding2;
@@ -2002,7 +2085,7 @@ typedef struct SDL_GPUBlitInfo {
     SDL_FColor clear_color;         /**< The color to clear the destination region to before the blit. Ignored if load_op is not SDL_GPU_LOADOP_CLEAR. */
     SDL_FlipMode flip_mode;         /**< The flip mode for the source region. */
     SDL_GPUFilter filter;           /**< The filter mode used when blitting. */
-    bool cycle;                 /**< true cycles the destination texture if it is already bound. */
+    bool cycle;                     /**< true cycles the destination texture if it is already bound. */
     Uint8 padding1;
     Uint8 padding2;
     Uint8 padding3;
@@ -2111,6 +2194,13 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GPUSupportsProperties(
 /**
  * Creates a GPU context.
  *
+ * The GPU driver name can be one of the following:
+ *
+ * - "vulkan": [Vulkan](CategoryGPU#vulkan)
+ * - "direct3d12": [D3D12](CategoryGPU#d3d12)
+ * - "metal": [Metal](CategoryGPU#metal)
+ * - NULL: let SDL pick the optimal driver
+ *
  * \param format_flags a bitflag indicating which shader formats the app is
  *                     able to provide.
  * \param debug_mode enable debug mode properties and validations.
@@ -2121,6 +2211,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GPUSupportsProperties(
  *
  * \since This function is available since SDL 3.2.0.
  *
+ * \sa SDL_CreateGPUDeviceWithProperties
  * \sa SDL_GetGPUShaderFormats
  * \sa SDL_GetGPUDeviceDriver
  * \sa SDL_DestroyGPUDevice
@@ -2140,6 +2231,8 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice(
  *   properties and validations, defaults to true.
  * - `SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN`: enable to prefer
  *   energy efficiency over maximum GPU performance, defaults to false.
+ * - `SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN`: enable to automatically log
+ *   useful debug information on device creation, defaults to true.
  * - `SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING`: the name of the GPU driver to
  *   use, if a specific one is desired.
  *
@@ -2163,6 +2256,25 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice(
  * - `SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING`: the prefix to
  *   use for all vertex semantics, default is "TEXCOORD".
  *
+ * With the Vulkan renderer:
+ *
+ * - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SHADERCLIPDISTANCE_BOOLEAN`: Enable
+ *   device feature shaderClipDistance. If disabled, clip distances are not
+ *   supported in shader code: gl_ClipDistance[] built-ins of GLSL,
+ *   SV_ClipDistance0/1 semantics of HLSL and [[clip_distance]] attribute of
+ *   Metal. Defaults to true.
+ * - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DEPTHCLAMP_BOOLEAN`: Enable device
+ *   feature depthClamp. If disabled, there is no depth clamp support and
+ *   enable_depth_clip in SDL_GPURasterizerState must always be set to true.
+ *   Defaults to true.
+ * - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DRAWINDIRECTFIRST_BOOLEAN`: Enable
+ *   device feature drawIndirectFirstInstance. If disabled, the argument
+ *   first_instance of SDL_GPUIndirectDrawCommand must be set to zero.
+ *   Defaults to true.
+ * - `SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SAMPLERANISOTROPY_BOOLEAN`: Enable
+ *   device feature samplerAnisotropy. If disabled, enable_anisotropy of
+ *   SDL_GPUSamplerCreateInfo must be set to false. Defaults to true.
+ *
  * \param props the properties to use.
  * \returns a GPU context on success or NULL on failure; call SDL_GetError()
  *          for more information.
@@ -2177,16 +2289,21 @@ extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDevice(
 extern SDL_DECLSPEC SDL_GPUDevice * SDLCALL SDL_CreateGPUDeviceWithProperties(
     SDL_PropertiesID props);
 
-#define SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN          "SDL.gpu.device.create.debugmode"
-#define SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN     "SDL.gpu.device.create.preferlowpower"
-#define SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING                "SDL.gpu.device.create.name"
-#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN    "SDL.gpu.device.create.shaders.private"
-#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN      "SDL.gpu.device.create.shaders.spirv"
-#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN       "SDL.gpu.device.create.shaders.dxbc"
-#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN       "SDL.gpu.device.create.shaders.dxil"
-#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN        "SDL.gpu.device.create.shaders.msl"
-#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN   "SDL.gpu.device.create.shaders.metallib"
-#define SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING "SDL.gpu.device.create.d3d12.semantic"
+#define SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN                 "SDL.gpu.device.create.debugmode"
+#define SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN            "SDL.gpu.device.create.preferlowpower"
+#define SDL_PROP_GPU_DEVICE_CREATE_VERBOSE_BOOLEAN                   "SDL.gpu.device.create.verbose"
+#define SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING                       "SDL.gpu.device.create.name"
+#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOLEAN           "SDL.gpu.device.create.shaders.private"
+#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOLEAN             "SDL.gpu.device.create.shaders.spirv"
+#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOLEAN              "SDL.gpu.device.create.shaders.dxbc"
+#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOLEAN              "SDL.gpu.device.create.shaders.dxil"
+#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOLEAN               "SDL.gpu.device.create.shaders.msl"
+#define SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOLEAN          "SDL.gpu.device.create.shaders.metallib"
+#define SDL_PROP_GPU_DEVICE_CREATE_D3D12_SEMANTIC_NAME_STRING        "SDL.gpu.device.create.d3d12.semantic"
+#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SHADERCLIPDISTANCE_BOOLEAN "SDL.gpu.device.create.vulkan.shaderclipdistance"
+#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DEPTHCLAMP_BOOLEAN         "SDL.gpu.device.create.vulkan.depthclamp"
+#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_DRAWINDIRECTFIRST_BOOLEAN  "SDL.gpu.device.create.vulkan.drawindirectfirstinstance"
+#define SDL_PROP_GPU_DEVICE_CREATE_VULKAN_SAMPLERANISOTROPY_BOOLEAN  "SDL.gpu.device.create.vulkan.sampleranisotropy"
 
 /**
  * Destroys a GPU context previously returned by SDL_CreateGPUDevice.
@@ -2250,6 +2367,116 @@ extern SDL_DECLSPEC const char * SDLCALL SDL_GetGPUDeviceDriver(SDL_GPUDevice *d
  */
 extern SDL_DECLSPEC SDL_GPUShaderFormat SDLCALL SDL_GetGPUShaderFormats(SDL_GPUDevice *device);
 
+/**
+ * Get the properties associated with a GPU device.
+ *
+ * All properties are optional and may differ between GPU backends and SDL
+ * versions.
+ *
+ * The following properties are provided by SDL:
+ *
+ * `SDL_PROP_GPU_DEVICE_NAME_STRING`: Contains the name of the underlying
+ * device as reported by the system driver. This string has no standardized
+ * format, is highly inconsistent between hardware devices and drivers, and is
+ * able to change at any time. Do not attempt to parse this string as it is
+ * bound to fail at some point in the future when system drivers are updated,
+ * new hardware devices are introduced, or when SDL adds new GPU backends or
+ * modifies existing ones.
+ *
+ * Strings that have been found in the wild include:
+ *
+ * - GTX 970
+ * - GeForce GTX 970
+ * - NVIDIA GeForce GTX 970
+ * - Microsoft Direct3D12 (NVIDIA GeForce GTX 970)
+ * - NVIDIA Graphics Device
+ * - GeForce GPU
+ * - P106-100
+ * - AMD 15D8:C9
+ * - AMD Custom GPU 0405
+ * - AMD Radeon (TM) Graphics
+ * - ASUS Radeon RX 470 Series
+ * - Intel(R) Arc(tm) A380 Graphics (DG2)
+ * - Virtio-GPU Venus (NVIDIA TITAN V)
+ * - SwiftShader Device (LLVM 16.0.0)
+ * - llvmpipe (LLVM 15.0.4, 256 bits)
+ * - Microsoft Basic Render Driver
+ * - unknown device
+ *
+ * The above list shows that the same device can have different formats, the
+ * vendor name may or may not appear in the string, the included vendor name
+ * may not be the vendor of the chipset on the device, some manufacturers
+ * include pseudo-legal marks while others don't, some devices may not use a
+ * marketing name in the string, the device string may be wrapped by the name
+ * of a translation interface, the device may be emulated in software, or the
+ * string may contain generic text that does not identify the device at all.
+ *
+ * `SDL_PROP_GPU_DEVICE_DRIVER_NAME_STRING`: Contains the self-reported name
+ * of the underlying system driver.
+ *
+ * Strings that have been found in the wild include:
+ *
+ * - Intel Corporation
+ * - Intel open-source Mesa driver
+ * - Qualcomm Technologies Inc. Adreno Vulkan Driver
+ * - MoltenVK
+ * - Mali-G715
+ * - venus
+ *
+ * `SDL_PROP_GPU_DEVICE_DRIVER_VERSION_STRING`: Contains the self-reported
+ * version of the underlying system driver. This is a relatively short version
+ * string in an unspecified format. If SDL_PROP_GPU_DEVICE_DRIVER_INFO_STRING
+ * is available then that property should be preferred over this one as it may
+ * contain additional information that is useful for identifying the exact
+ * driver version used.
+ *
+ * Strings that have been found in the wild include:
+ *
+ * - 53.0.0
+ * - 0.405.2463
+ * - 32.0.15.6614
+ *
+ * `SDL_PROP_GPU_DEVICE_DRIVER_INFO_STRING`: Contains the detailed version
+ * information of the underlying system driver as reported by the driver. This
+ * is an arbitrary string with no standardized format and it may contain
+ * newlines. This property should be preferred over
+ * SDL_PROP_GPU_DEVICE_DRIVER_VERSION_STRING if it is available as it usually
+ * contains the same information but in a format that is easier to read.
+ *
+ * Strings that have been found in the wild include:
+ *
+ * - 101.6559
+ * - 1.2.11
+ * - Mesa 21.2.2 (LLVM 12.0.1)
+ * - Mesa 22.2.0-devel (git-f226222 2022-04-14 impish-oibaf-ppa)
+ * - v1.r53p0-00eac0.824c4f31403fb1fbf8ee1042422c2129
+ *
+ * This string has also been observed to be a multiline string (which has a
+ * trailing newline):
+ *
+ * ```
+ * Driver Build: 85da404, I46ff5fc46f, 1606794520
+ * Date: 11/30/20
+ * Compiler Version: EV031.31.04.01
+ * Driver Branch: promo490_3_Google
+ * ```
+ *
+ * \param device a GPU context to query.
+ * \returns a valid property ID on success or 0 on failure; call
+ *          SDL_GetError() for more information.
+ *
+ * \threadsafety It is safe to call this function from any thread.
+ *
+ * \since This function is available since SDL 3.4.0.
+ */
+extern SDL_DECLSPEC SDL_PropertiesID SDLCALL SDL_GetGPUDeviceProperties(SDL_GPUDevice *device);
+
+#define SDL_PROP_GPU_DEVICE_NAME_STRING               "SDL.gpu.device.name"
+#define SDL_PROP_GPU_DEVICE_DRIVER_NAME_STRING        "SDL.gpu.device.driver_name"
+#define SDL_PROP_GPU_DEVICE_DRIVER_VERSION_STRING     "SDL.gpu.device.driver_version"
+#define SDL_PROP_GPU_DEVICE_DRIVER_INFO_STRING        "SDL.gpu.device.driver_info"
+
+
 /* State Creation */
 
 /**
@@ -2467,9 +2694,9 @@ extern SDL_DECLSPEC SDL_GPUShader * SDLCALL SDL_CreateGPUShader(
  * - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT`: (Direct3D 12 only)
  *   if the texture usage is SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET, clear
  *   the texture to a depth of this value. Defaults to zero.
- * - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_UINT8`: (Direct3D 12
+ * - `SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_NUMBER`: (Direct3D 12
  *   only) if the texture usage is SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET,
- *   clear the texture to a stencil of this value. Defaults to zero.
+ *   clear the texture to a stencil of this Uint8 value. Defaults to zero.
  * - `SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING`: a name that can be displayed
  *   in debugging tools.
  *
@@ -2495,13 +2722,13 @@ extern SDL_DECLSPEC SDL_GPUTexture * SDLCALL SDL_CreateGPUTexture(
     SDL_GPUDevice *device,
     const SDL_GPUTextureCreateInfo *createinfo);
 
-#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_R_FLOAT       "SDL.gpu.texture.create.d3d12.clear.r"
-#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_G_FLOAT       "SDL.gpu.texture.create.d3d12.clear.g"
-#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_B_FLOAT       "SDL.gpu.texture.create.d3d12.clear.b"
-#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_A_FLOAT       "SDL.gpu.texture.create.d3d12.clear.a"
-#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT   "SDL.gpu.texture.create.d3d12.clear.depth"
-#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_UINT8 "SDL.gpu.texture.create.d3d12.clear.stencil"
-#define SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING               "SDL.gpu.texture.create.name"
+#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_R_FLOAT         "SDL.gpu.texture.create.d3d12.clear.r"
+#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_G_FLOAT         "SDL.gpu.texture.create.d3d12.clear.g"
+#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_B_FLOAT         "SDL.gpu.texture.create.d3d12.clear.b"
+#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_A_FLOAT         "SDL.gpu.texture.create.d3d12.clear.a"
+#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_DEPTH_FLOAT     "SDL.gpu.texture.create.d3d12.clear.depth"
+#define SDL_PROP_GPU_TEXTURE_CREATE_D3D12_CLEAR_STENCIL_NUMBER  "SDL.gpu.texture.create.d3d12.clear.stencil"
+#define SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING                 "SDL.gpu.texture.create.name"
 
 /**
  * Creates a buffer object to be used in graphics or compute workflows.
@@ -2822,6 +3049,9 @@ extern SDL_DECLSPEC SDL_GPUCommandBuffer * SDLCALL SDL_AcquireGPUCommandBuffer(
  * terms this means you must ensure that vec3 and vec4 fields are 16-byte
  * aligned.
  *
+ * For detailed information about accessing uniform data from a shader, please
+ * refer to SDL_CreateGPUShader.
+ *
  * \param command_buffer a command buffer.
  * \param slot_index the vertex uniform slot to push data to.
  * \param data client data to write.
@@ -3775,7 +4005,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_ReleaseWindowFromGPUDevice(
  * supported via SDL_WindowSupportsGPUPresentMode /
  * SDL_WindowSupportsGPUSwapchainComposition prior to calling this function.
  *
- * SDL_GPU_PRESENTMODE_VSYNC and SDL_GPU_SWAPCHAINCOMPOSITION_SDR are always
+ * SDL_GPU_PRESENTMODE_VSYNC with SDL_GPU_SWAPCHAINCOMPOSITION_SDR is always
  * supported.
  *
  * \param device a GPU context.
@@ -3849,7 +4079,9 @@ extern SDL_DECLSPEC SDL_GPUTextureFormat SDLCALL SDL_GetGPUSwapchainTextureForma
  * buffer used to acquire it.
  *
  * This function will fill the swapchain texture handle with NULL if too many
- * frames are in flight. This is not an error.
+ * frames are in flight. This is not an error. This NULL pointer should not be
+ * passed back into SDL. Instead, it should be considered as an indication to
+ * wait until the swapchain is available.
  *
  * If you use this function, it is possible to create a situation where many
  * command buffers are allocated while the rendering context waits for the GPU
@@ -4211,3 +4443,8 @@ extern SDL_DECLSPEC void SDLCALL SDL_GDKResumeGPU(SDL_GPUDevice *device);
 #include <SDL3/SDL_close_code.h>
 
 #endif /* SDL_gpu_h_ */
+
+
+
+
+

+ 46 - 26
libs/SDL3/include/SDL3/SDL_haptic.h

@@ -70,7 +70,7 @@
  * {
  *    SDL_Haptic *haptic;
  *    SDL_HapticEffect effect;
- *    int effect_id;
+ *    SDL_HapticEffectID effect_id;
  *
  *    // Open the device
  *    haptic = SDL_OpenHapticFromJoystick(joystick);
@@ -149,6 +149,19 @@ extern "C" {
  */
 typedef struct SDL_Haptic SDL_Haptic;
 
+/*
+ * Misc defines.
+ */
+
+/**
+ * Used to play a device an infinite number of times.
+ *
+ * \since This macro is available since SDL 3.2.0.
+ *
+ * \sa SDL_RunHapticEffect
+ */
+#define SDL_HAPTIC_INFINITY   4294967295U
+
 
 /**
  *  \name Haptic features
@@ -162,6 +175,11 @@ typedef struct SDL_Haptic SDL_Haptic;
  */
 /* @{ */
 
+/**
+ * Type of haptic effect.
+ */
+typedef Uint16 SDL_HapticEffectType;
+
 /**
  * Constant effect supported.
  *
@@ -383,6 +401,11 @@ typedef struct SDL_Haptic SDL_Haptic;
  */
 /* @{ */
 
+/**
+ * Type of coordinates used for haptic direction.
+ */
+typedef Uint8 SDL_HapticDirectionType;
+
 /**
  * Uses polar coordinates for the direction.
  *
@@ -426,18 +449,15 @@ typedef struct SDL_Haptic SDL_Haptic;
 
 /* @} *//* Haptic features */
 
-/*
- * Misc defines.
- */
 
 /**
- * Used to play a device an infinite number of times.
+ * ID for haptic effects.
  *
- * \since This macro is available since SDL 3.2.0.
+ * This is -1 if the ID is invalid.
  *
- * \sa SDL_RunHapticEffect
+ * \sa SDL_CreateHapticEffect
  */
-#define SDL_HAPTIC_INFINITY   4294967295U
+typedef int SDL_HapticEffectID;
 
 
 /**
@@ -545,8 +565,8 @@ typedef struct SDL_Haptic SDL_Haptic;
  */
 typedef struct SDL_HapticDirection
 {
-    Uint8 type;         /**< The type of encoding. */
-    Sint32 dir[3];      /**< The encoded direction. */
+    SDL_HapticDirectionType type;  /**< The type of encoding. */
+    Sint32 dir[3];                 /**< The encoded direction. */
 } SDL_HapticDirection;
 
 
@@ -566,7 +586,7 @@ typedef struct SDL_HapticDirection
 typedef struct SDL_HapticConstant
 {
     /* Header */
-    Uint16 type;            /**< SDL_HAPTIC_CONSTANT */
+    SDL_HapticEffectType type;      /**< SDL_HAPTIC_CONSTANT */
     SDL_HapticDirection direction;  /**< Direction of the effect. */
 
     /* Replay */
@@ -652,9 +672,9 @@ typedef struct SDL_HapticConstant
 typedef struct SDL_HapticPeriodic
 {
     /* Header */
-    Uint16 type;        /**< SDL_HAPTIC_SINE, SDL_HAPTIC_SQUARE
-                             SDL_HAPTIC_TRIANGLE, SDL_HAPTIC_SAWTOOTHUP or
-                             SDL_HAPTIC_SAWTOOTHDOWN */
+    SDL_HapticEffectType type;      /**< SDL_HAPTIC_SINE, SDL_HAPTIC_SQUARE
+                                         SDL_HAPTIC_TRIANGLE, SDL_HAPTIC_SAWTOOTHUP or
+                                         SDL_HAPTIC_SAWTOOTHDOWN */
     SDL_HapticDirection direction;  /**< Direction of the effect. */
 
     /* Replay */
@@ -708,8 +728,8 @@ typedef struct SDL_HapticPeriodic
 typedef struct SDL_HapticCondition
 {
     /* Header */
-    Uint16 type;            /**< SDL_HAPTIC_SPRING, SDL_HAPTIC_DAMPER,
-                                 SDL_HAPTIC_INERTIA or SDL_HAPTIC_FRICTION */
+    SDL_HapticEffectType type;      /**< SDL_HAPTIC_SPRING, SDL_HAPTIC_DAMPER,
+                                         SDL_HAPTIC_INERTIA or SDL_HAPTIC_FRICTION */
     SDL_HapticDirection direction;  /**< Direction of the effect. */
 
     /* Replay */
@@ -747,7 +767,7 @@ typedef struct SDL_HapticCondition
 typedef struct SDL_HapticRamp
 {
     /* Header */
-    Uint16 type;            /**< SDL_HAPTIC_RAMP */
+    SDL_HapticEffectType type;      /**< SDL_HAPTIC_RAMP */
     SDL_HapticDirection direction;  /**< Direction of the effect. */
 
     /* Replay */
@@ -786,7 +806,7 @@ typedef struct SDL_HapticRamp
 typedef struct SDL_HapticLeftRight
 {
     /* Header */
-    Uint16 type;            /**< SDL_HAPTIC_LEFTRIGHT */
+    SDL_HapticEffectType type;  /**< SDL_HAPTIC_LEFTRIGHT */
 
     /* Replay */
     Uint32 length;          /**< Duration of the effect in milliseconds. */
@@ -816,7 +836,7 @@ typedef struct SDL_HapticLeftRight
 typedef struct SDL_HapticCustom
 {
     /* Header */
-    Uint16 type;            /**< SDL_HAPTIC_CUSTOM */
+    SDL_HapticEffectType type;      /**< SDL_HAPTIC_CUSTOM */
     SDL_HapticDirection direction;  /**< Direction of the effect. */
 
     /* Replay */
@@ -915,7 +935,7 @@ typedef struct SDL_HapticCustom
 typedef union SDL_HapticEffect
 {
     /* Common for all force feedback effects */
-    Uint16 type;                    /**< Effect type. */
+    SDL_HapticEffectType type;      /**< Effect type. */
     SDL_HapticConstant constant;    /**< Constant effect. */
     SDL_HapticPeriodic periodic;    /**< Periodic effect. */
     SDL_HapticCondition condition;  /**< Condition effect. */
@@ -1193,7 +1213,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_HapticEffectSupported(SDL_Haptic *haptic, c
  * \sa SDL_RunHapticEffect
  * \sa SDL_UpdateHapticEffect
  */
-extern SDL_DECLSPEC int SDLCALL SDL_CreateHapticEffect(SDL_Haptic *haptic, const SDL_HapticEffect *effect);
+extern SDL_DECLSPEC SDL_HapticEffectID SDLCALL SDL_CreateHapticEffect(SDL_Haptic *haptic, const SDL_HapticEffect *effect);
 
 /**
  * Update the properties of an effect.
@@ -1215,7 +1235,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_CreateHapticEffect(SDL_Haptic *haptic, const
  * \sa SDL_CreateHapticEffect
  * \sa SDL_RunHapticEffect
  */
-extern SDL_DECLSPEC bool SDLCALL SDL_UpdateHapticEffect(SDL_Haptic *haptic, int effect, const SDL_HapticEffect *data);
+extern SDL_DECLSPEC bool SDLCALL SDL_UpdateHapticEffect(SDL_Haptic *haptic, SDL_HapticEffectID effect, const SDL_HapticEffect *data);
 
 /**
  * Run the haptic effect on its associated haptic device.
@@ -1239,7 +1259,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_UpdateHapticEffect(SDL_Haptic *haptic, int
  * \sa SDL_StopHapticEffect
  * \sa SDL_StopHapticEffects
  */
-extern SDL_DECLSPEC bool SDLCALL SDL_RunHapticEffect(SDL_Haptic *haptic, int effect, Uint32 iterations);
+extern SDL_DECLSPEC bool SDLCALL SDL_RunHapticEffect(SDL_Haptic *haptic, SDL_HapticEffectID effect, Uint32 iterations);
 
 /**
  * Stop the haptic effect on its associated haptic device.
@@ -1254,7 +1274,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RunHapticEffect(SDL_Haptic *haptic, int eff
  * \sa SDL_RunHapticEffect
  * \sa SDL_StopHapticEffects
  */
-extern SDL_DECLSPEC bool SDLCALL SDL_StopHapticEffect(SDL_Haptic *haptic, int effect);
+extern SDL_DECLSPEC bool SDLCALL SDL_StopHapticEffect(SDL_Haptic *haptic, SDL_HapticEffectID effect);
 
 /**
  * Destroy a haptic effect on the device.
@@ -1269,7 +1289,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_StopHapticEffect(SDL_Haptic *haptic, int ef
  *
  * \sa SDL_CreateHapticEffect
  */
-extern SDL_DECLSPEC void SDLCALL SDL_DestroyHapticEffect(SDL_Haptic *haptic, int effect);
+extern SDL_DECLSPEC void SDLCALL SDL_DestroyHapticEffect(SDL_Haptic *haptic, SDL_HapticEffectID effect);
 
 /**
  * Get the status of the current effect on the specified haptic device.
@@ -1285,7 +1305,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_DestroyHapticEffect(SDL_Haptic *haptic, int
  *
  * \sa SDL_GetHapticFeatures
  */
-extern SDL_DECLSPEC bool SDLCALL SDL_GetHapticEffectStatus(SDL_Haptic *haptic, int effect);
+extern SDL_DECLSPEC bool SDLCALL SDL_GetHapticEffectStatus(SDL_Haptic *haptic, SDL_HapticEffectID effect);
 
 /**
  * Set the global gain of the specified haptic device.

+ 97 - 7
libs/SDL3/include/SDL3/SDL_hints.h

@@ -711,8 +711,6 @@ extern "C" {
  *
  * This hint only applies to the emscripten platform.
  *
- * The default value is "#canvas"
- *
  * This hint should be set before creating a window.
  *
  * \since This hint is available since SDL 3.2.0.
@@ -726,7 +724,7 @@ extern "C" {
  *
  * The variable can be one of:
  *
- * - "#window": the javascript window object (default)
+ * - "#window": the javascript window object
  * - "#document": the javascript document object
  * - "#screen": the javascript window.screen object
  * - "#canvas": the WebGL canvas element
@@ -1074,8 +1072,8 @@ extern "C" {
  *
  * By default, SDL will try all available GPU backends in a reasonable order
  * until it finds one that can work, but this hint allows the app or user to
- * force a specific target, such as "direct3d11" if, say, your hardware
- * supports D3D12 but want to try using D3D11 instead.
+ * force a specific target, such as "direct3d12" if, say, your hardware
+ * supports Vulkan but you want to try using D3D12 instead.
  *
  * This hint should be set before any GPU functions are called.
  *
@@ -1723,6 +1721,43 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_HIDAPI_STEAM_HORI "SDL_JOYSTICK_HIDAPI_STEAM_HORI"
 
+/**
+ * A variable controlling whether the HIDAPI driver for some Logitech wheels
+ * should be used.
+ *
+ * This variable can be set to the following values:
+ *
+ * - "0": HIDAPI driver is not used
+ * - "1": HIDAPI driver is used
+ *
+ * The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_LG4FF "SDL_JOYSTICK_HIDAPI_LG4FF"
+
+/**
+ * A variable controlling whether the HIDAPI driver for 8BitDo controllers
+ * should be used.
+ *
+ * This variable can be set to the following values:
+ *
+ * "0" - HIDAPI driver is not used. "1" - HIDAPI driver is used.
+ *
+ * The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_8BITDO "SDL_JOYSTICK_HIDAPI_8BITDO"
+
+/**
+ * A variable controlling whether the HIDAPI driver for Flydigi controllers
+ * should be used.
+ *
+ * This variable can be set to the following values:
+ *
+ * "0" - HIDAPI driver is not used. "1" - HIDAPI driver is used.
+ *
+ * The default is the value of SDL_HINT_JOYSTICK_HIDAPI
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_FLYDIGI "SDL_JOYSTICK_HIDAPI_FLYDIGI"
+
 /**
  * A variable controlling whether the HIDAPI driver for Nintendo Switch
  * controllers should be used.
@@ -1926,6 +1961,41 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED "SDL_JOYSTICK_HIDAPI_XBOX_ONE_HOME_LED"
 
+/**
+ * A variable controlling whether the new HIDAPI driver for wired Xbox One
+ * (GIP) controllers should be used.
+ *
+ * The variable can be set to the following values:
+ *
+ * - "0": HIDAPI driver is not used.
+ * - "1": HIDAPI driver is used.
+ *
+ * The default is the value of SDL_HINT_JOYSTICK_HIDAPI_XBOX_ONE.
+ *
+ * This hint should be set before initializing joysticks and gamepads.
+ *
+ * \since This hint is available since SDL 3.4.0.
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_GIP "SDL_JOYSTICK_HIDAPI_GIP"
+
+/**
+ * A variable controlling whether the new HIDAPI driver for wired Xbox One
+ * (GIP) controllers should reset the controller if it can't get the metadata
+ * from the controller.
+ *
+ * The variable can be set to the following values:
+ *
+ * - "0": Assume this is a generic controller.
+ * - "1": Reset the controller to get metadata.
+ *
+ * By default the controller is not reset.
+ *
+ * This hint should be set before initializing joysticks and gamepads.
+ *
+ * \since This hint is available since SDL 3.4.0.
+ */
+#define SDL_HINT_JOYSTICK_HIDAPI_GIP_RESET_FOR_METADATA "SDL_JOYSTICK_HIDAPI_GIP_RESET_FOR_METADATA"
+
 /**
  * A variable controlling whether IOKit should be used for controller
  * handling.
@@ -2026,8 +2096,8 @@ extern "C" {
  *
  * The variable can be set to the following values:
  *
- * - "0": RAWINPUT drivers are not used.
- * - "1": RAWINPUT drivers are used. (default)
+ * - "0": RAWINPUT drivers are not used. (default)
+ * - "1": RAWINPUT drivers are used.
  *
  * This hint should be set before SDL is initialized.
  *
@@ -3407,6 +3477,26 @@ extern "C" {
  */
 #define SDL_HINT_VIDEO_MAC_FULLSCREEN_MENU_VISIBILITY "SDL_VIDEO_MAC_FULLSCREEN_MENU_VISIBILITY"
 
+/**
+ * A variable controlling whether SDL will attempt to automatically set the
+ * destination display to a mode most closely matching that of the previous
+ * display if an exclusive fullscreen window is moved onto it.
+ *
+ * The variable can be set to the following values:
+ *
+ * - "0": SDL will not attempt to automatically set a matching mode on the
+ *   destination display. If an exclusive fullscreen window is moved to a new
+ *   display, the window will become fullscreen desktop.
+ * - "1": SDL will attempt to automatically set a mode on the destination
+ *   display that most closely matches the mode of the display that the
+ *   exclusive fullscreen window was previously on. (default)
+ *
+ * This hint can be set anytime.
+ *
+ * \since This hint is available since SDL 3.4.0.
+ */
+#define SDL_HINT_VIDEO_MATCH_EXCLUSIVE_MODE_ON_MOVE "SDL_VIDEO_MATCH_EXCLUSIVE_MODE_ON_MOVE"
+
 /**
  * A variable controlling whether fullscreen windows are minimized when they
  * lose focus.

+ 2 - 2
libs/SDL3/include/SDL3/SDL_init.h

@@ -79,7 +79,7 @@ typedef Uint32 SDL_InitFlags;
 
 #define SDL_INIT_AUDIO      0x00000010u /**< `SDL_INIT_AUDIO` implies `SDL_INIT_EVENTS` */
 #define SDL_INIT_VIDEO      0x00000020u /**< `SDL_INIT_VIDEO` implies `SDL_INIT_EVENTS`, should be initialized on the main thread */
-#define SDL_INIT_JOYSTICK   0x00000200u /**< `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS`, should be initialized on the same thread as SDL_INIT_VIDEO on Windows if you don't set SDL_HINT_JOYSTICK_THREAD */
+#define SDL_INIT_JOYSTICK   0x00000200u /**< `SDL_INIT_JOYSTICK` implies `SDL_INIT_EVENTS` */
 #define SDL_INIT_HAPTIC     0x00001000u
 #define SDL_INIT_GAMEPAD    0x00002000u /**< `SDL_INIT_GAMEPAD` implies `SDL_INIT_JOYSTICK` */
 #define SDL_INIT_EVENTS     0x00004000u
@@ -101,7 +101,7 @@ typedef Uint32 SDL_InitFlags;
  * to run.
  *
  * See
- * [Main callbacks in SDL3](https://wiki.libsdl.org/SDL3/README/main-functions#main-callbacks-in-sdl3)
+ * [Main callbacks in SDL3](https://wiki.libsdl.org/SDL3/README-main-functions#main-callbacks-in-sdl3)
  * for complete details.
  *
  * \since This enum is available since SDL 3.2.0.

+ 12 - 12
libs/SDL3/include/SDL3/SDL_iostream.h

@@ -823,7 +823,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadS8(SDL_IOStream *src, Sint8 *value);
  *
  * \param src the stream from which to read data.
  * \param value a pointer filled in with the data read.
- * \returns true on successful write or false on failure; call SDL_GetError()
+ * \returns true on successful read or false on failure; call SDL_GetError()
  *          for more information.
  *
  * \threadsafety This function is not thread safe.
@@ -846,7 +846,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadU16LE(SDL_IOStream *src, Uint16 *value)
  *
  * \param src the stream from which to read data.
  * \param value a pointer filled in with the data read.
- * \returns true on successful write or false on failure; call SDL_GetError()
+ * \returns true on successful read or false on failure; call SDL_GetError()
  *          for more information.
  *
  * \threadsafety This function is not thread safe.
@@ -869,7 +869,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadS16LE(SDL_IOStream *src, Sint16 *value)
  *
  * \param src the stream from which to read data.
  * \param value a pointer filled in with the data read.
- * \returns true on successful write or false on failure; call SDL_GetError()
+ * \returns true on successful read or false on failure; call SDL_GetError()
  *          for more information.
  *
  * \threadsafety This function is not thread safe.
@@ -892,7 +892,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadU16BE(SDL_IOStream *src, Uint16 *value)
  *
  * \param src the stream from which to read data.
  * \param value a pointer filled in with the data read.
- * \returns true on successful write or false on failure; call SDL_GetError()
+ * \returns true on successful read or false on failure; call SDL_GetError()
  *          for more information.
  *
  * \threadsafety This function is not thread safe.
@@ -915,7 +915,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadS16BE(SDL_IOStream *src, Sint16 *value)
  *
  * \param src the stream from which to read data.
  * \param value a pointer filled in with the data read.
- * \returns true on successful write or false on failure; call SDL_GetError()
+ * \returns true on successful read or false on failure; call SDL_GetError()
  *          for more information.
  *
  * \threadsafety This function is not thread safe.
@@ -938,7 +938,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadU32LE(SDL_IOStream *src, Uint32 *value)
  *
  * \param src the stream from which to read data.
  * \param value a pointer filled in with the data read.
- * \returns true on successful write or false on failure; call SDL_GetError()
+ * \returns true on successful read or false on failure; call SDL_GetError()
  *          for more information.
  *
  * \threadsafety This function is not thread safe.
@@ -961,7 +961,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadS32LE(SDL_IOStream *src, Sint32 *value)
  *
  * \param src the stream from which to read data.
  * \param value a pointer filled in with the data read.
- * \returns true on successful write or false on failure; call SDL_GetError()
+ * \returns true on successful read or false on failure; call SDL_GetError()
  *          for more information.
  *
  * \threadsafety This function is not thread safe.
@@ -984,7 +984,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadU32BE(SDL_IOStream *src, Uint32 *value)
  *
  * \param src the stream from which to read data.
  * \param value a pointer filled in with the data read.
- * \returns true on successful write or false on failure; call SDL_GetError()
+ * \returns true on successful read or false on failure; call SDL_GetError()
  *          for more information.
  *
  * \threadsafety This function is not thread safe.
@@ -1007,7 +1007,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadS32BE(SDL_IOStream *src, Sint32 *value)
  *
  * \param src the stream from which to read data.
  * \param value a pointer filled in with the data read.
- * \returns true on successful write or false on failure; call SDL_GetError()
+ * \returns true on successful read or false on failure; call SDL_GetError()
  *          for more information.
  *
  * \threadsafety This function is not thread safe.
@@ -1030,7 +1030,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadU64LE(SDL_IOStream *src, Uint64 *value)
  *
  * \param src the stream from which to read data.
  * \param value a pointer filled in with the data read.
- * \returns true on successful write or false on failure; call SDL_GetError()
+ * \returns true on successful read or false on failure; call SDL_GetError()
  *          for more information.
  *
  * \threadsafety This function is not thread safe.
@@ -1053,7 +1053,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadS64LE(SDL_IOStream *src, Sint64 *value)
  *
  * \param src the stream from which to read data.
  * \param value a pointer filled in with the data read.
- * \returns true on successful write or false on failure; call SDL_GetError()
+ * \returns true on successful read or false on failure; call SDL_GetError()
  *          for more information.
  *
  * \threadsafety This function is not thread safe.
@@ -1076,7 +1076,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_ReadU64BE(SDL_IOStream *src, Uint64 *value)
  *
  * \param src the stream from which to read data.
  * \param value a pointer filled in with the data read.
- * \returns true on successful write or false on failure; call SDL_GetError()
+ * \returns true on successful read or false on failure; call SDL_GetError()
  *          for more information.
  *
  * \threadsafety This function is not thread safe.

+ 4 - 0
libs/SDL3/include/SDL3/SDL_joystick.h

@@ -107,6 +107,10 @@ typedef Uint32 SDL_JoystickID;
  * This is by no means a complete list of everything that can be plugged into
  * a computer.
  *
+ * You may refer to
+ * [XInput Controller Types](https://learn.microsoft.com/en-us/windows/win32/xinput/xinput-and-controller-subtypes)
+ * table for a general understanding of each joystick type.
+ *
  * \since This enum is available since SDL 3.2.0.
  */
 typedef enum SDL_JoystickType

+ 3 - 0
libs/SDL3/include/SDL3/SDL_log.h

@@ -206,6 +206,9 @@ extern SDL_DECLSPEC void SDLCALL SDL_ResetLogPriorities(void);
  * SDL_LOG_PRIORITY_WARN and higher have a prefix showing their priority, e.g.
  * "WARNING: ".
  *
+ * This function makes a copy of its string argument, **prefix**, so it is not
+ * necessary to keep the value of **prefix** alive after the call returns.
+ *
  * \param priority the SDL_LogPriority to modify.
  * \param prefix the prefix to use for that log priority, or NULL to use no
  *               prefix.

+ 10 - 10
libs/SDL3/include/SDL3/SDL_main.h

@@ -47,7 +47,7 @@
  *
  * For more information, see:
  *
- * https://wiki.libsdl.org/SDL3/README/main-functions
+ * https://wiki.libsdl.org/SDL3/README-main-functions
  */
 
 #ifndef SDL_main_h_
@@ -68,7 +68,7 @@
  * proper entry point for the platform, and all the other magic details
  * needed, like manually calling SDL_SetMainReady.
  *
- * Please see [README/main-functions](README/main-functions), (or
+ * Please see [README-main-functions](README-main-functions), (or
  * docs/README-main-functions.md in the source tree) for a more detailed
  * explanation.
  *
@@ -85,7 +85,7 @@
  * SDL_AppQuit. The app should not provide a `main` function in this case, and
  * doing so will likely cause the build to fail.
  *
- * Please see [README/main-functions](README/main-functions), (or
+ * Please see [README-main-functions](README-main-functions), (or
  * docs/README-main-functions.md in the source tree) for a more detailed
  * explanation.
  *
@@ -347,10 +347,10 @@ extern SDLMAIN_DECLSPEC SDL_AppResult SDLCALL SDL_AppInit(void **appstate, int a
  * Apps implement this function when using SDL_MAIN_USE_CALLBACKS. If using a
  * standard "main" function, you should not supply this.
  *
- * This function is called repeatedly by SDL after SDL_AppInit returns 0. The
- * function should operate as a single iteration the program's primary loop;
- * it should update whatever state it needs and draw a new frame of video,
- * usually.
+ * This function is called repeatedly by SDL after SDL_AppInit returns
+ * SDL_APP_CONTINUE. The function should operate as a single iteration the
+ * program's primary loop; it should update whatever state it needs and draw a
+ * new frame of video, usually.
  *
  * On some platforms, this function will be called at the refresh rate of the
  * display (which might change during the life of your app!). There are no
@@ -512,7 +512,7 @@ typedef int (SDLCALL *SDL_main_func)(int argc, char *argv[]);
  * SDL_MAIN_USE_CALLBACKS.
  *
  * Program startup is a surprisingly complex topic. Please see
- * [README/main-functions](README/main-functions), (or
+ * [README-main-functions](README-main-functions), (or
  * docs/README-main-functions.md in the source tree) for a more detailed
  * explanation.
  *
@@ -618,8 +618,8 @@ extern SDL_DECLSPEC int SDLCALL SDL_EnterAppMainCallbacks(int argc, char *argv[]
  * \param name the window class name, in UTF-8 encoding. If NULL, SDL
  *             currently uses "SDL_app" but this isn't guaranteed.
  * \param style the value to use in WNDCLASSEX::style. If `name` is NULL, SDL
- *              currently uses `(CS_BYTEALIGNCLIENT | CS_OWNDC)` regardless of
- *              what is specified here.
+ *              currently uses `(CS_BYTEALIGNCLIENT \| CS_OWNDC)` regardless
+ *              of what is specified here.
  * \param hInst the HINSTANCE to use in WNDCLASSEX::hInstance. If zero, SDL
  *              will use `GetModuleHandle(NULL)` instead.
  * \returns true on success or false on failure; call SDL_GetError() for more

+ 67 - 9
libs/SDL3/include/SDL3/SDL_mouse.h

@@ -160,6 +160,44 @@ typedef Uint32 SDL_MouseButtonFlags;
 #define SDL_BUTTON_X1MASK   SDL_BUTTON_MASK(SDL_BUTTON_X1)
 #define SDL_BUTTON_X2MASK   SDL_BUTTON_MASK(SDL_BUTTON_X2)
 
+/**
+ * A callback used to transform mouse motion delta from raw values.
+ *
+ * This is called during SDL's handling of platform mouse events to scale the
+ * values of the resulting motion delta.
+ *
+ * \param userdata what was passed as `userdata` to
+ *                 SDL_SetRelativeMouseTransform().
+ * \param timestamp the associated time at which this mouse motion event was
+ *                  received.
+ * \param window the associated window to which this mouse motion event was
+ *               addressed.
+ * \param mouseID the associated mouse from which this mouse motion event was
+ *                emitted.
+ * \param x pointer to a variable that will be treated as the resulting x-axis
+ *          motion.
+ * \param y pointer to a variable that will be treated as the resulting y-axis
+ *          motion.
+ *
+ * \threadsafety This callback is called by SDL's internal mouse input
+ *               processing procedure, which may be a thread separate from the
+ *               main event loop that is run at realtime priority. Stalling
+ *               this thread with too much work in the callback can therefore
+ *               potentially freeze the entire system. Care should be taken
+ *               with proper synchronization practices when adding other side
+ *               effects beyond mutation of the x and y values.
+ *
+ * \since This datatype is available since SDL 3.4.0.
+ *
+ * \sa SDL_SetRelativeMouseTransform
+ */
+typedef void (SDLCALL *SDL_MouseMotionTransformCallback)(
+    void *userdata, 
+    Uint64 timestamp, 
+    SDL_Window *window, 
+    SDL_MouseID mouseID, 
+    float *x, float *y
+);
 
 /* Function prototypes */
 
@@ -380,6 +418,24 @@ extern SDL_DECLSPEC void SDLCALL SDL_WarpMouseInWindow(SDL_Window *window,
  */
 extern SDL_DECLSPEC bool SDLCALL SDL_WarpMouseGlobal(float x, float y);
 
+/**
+ * Set a user-defined function by which to transform relative mouse inputs.
+ *
+ * This overrides the relative system scale and relative speed scale hints.
+ * Should be called prior to enabling relative mouse mode, fails otherwise.
+ *
+ * \param callback a callback used to transform relative mouse motion, or NULL
+ *                 for default behavior.
+ * \param userdata a pointer that will be passed to `callback`.
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ *          information.
+ *
+ * \threadsafety This function should only be called on the main thread.
+ *
+ * \since This function is available since SDL 3.4.0.
+ */
+extern SDL_DECLSPEC bool SDLCALL SDL_SetRelativeMouseTransform(SDL_MouseMotionTransformCallback callback, void *userdata);
+
 /**
  * Set relative mouse mode for a window.
  *
@@ -522,15 +578,16 @@ extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_CreateCursor(const Uint8 *data,
 /**
  * Create a color cursor.
  *
- * If this function is passed a surface with alternate representations, the
- * surface will be interpreted as the content to be used for 100% display
- * scale, and the alternate representations will be used for high DPI
- * situations. For example, if the original surface is 32x32, then on a 2x
- * macOS display or 200% display scale on Windows, a 64x64 version of the
- * image will be used, if available. If a matching version of the image isn't
- * available, the closest larger size image will be downscaled to the
- * appropriate size and be used instead, if available. Otherwise, the closest
- * smaller image will be upscaled and be used instead.
+ * If this function is passed a surface with alternate representations added
+ * with SDL_AddSurfaceAlternateImage(), the surface will be interpreted as the
+ * content to be used for 100% display scale, and the alternate
+ * representations will be used for high DPI situations. For example, if the
+ * original surface is 32x32, then on a 2x macOS display or 200% display scale
+ * on Windows, a 64x64 version of the image will be used, if available. If a
+ * matching version of the image isn't available, the closest larger size
+ * image will be downscaled to the appropriate size and be used instead, if
+ * available. Otherwise, the closest smaller image will be upscaled and be
+ * used instead.
  *
  * \param surface an SDL_Surface structure representing the cursor image.
  * \param hot_x the x position of the cursor hot spot.
@@ -542,6 +599,7 @@ extern SDL_DECLSPEC SDL_Cursor * SDLCALL SDL_CreateCursor(const Uint8 *data,
  *
  * \since This function is available since SDL 3.2.0.
  *
+ * \sa SDL_AddSurfaceAlternateImage
  * \sa SDL_CreateCursor
  * \sa SDL_CreateSystemCursor
  * \sa SDL_DestroyCursor

+ 1 - 1
libs/SDL3/include/SDL3/SDL_mutex.h

@@ -942,7 +942,7 @@ typedef enum SDL_InitStatus
  * Here is an example of using this:
  *
  * ```c
- *    static SDL_AtomicInitState init;
+ *    static SDL_InitState init;
  *
  *    bool InitSystem(void)
  *    {

+ 5 - 5
libs/SDL3/include/SDL3/SDL_pixels.h

@@ -517,7 +517,7 @@ typedef enum SDL_PackedLayout
  *   ABGR32, define a platform-independent encoding into bytes in the order
  *   specified. For example, in RGB24 data, each pixel is encoded in 3 bytes
  *   (red, green, blue) in that order, and in ABGR32 data, each pixel is
- *   encoded in 4 bytes alpha, blue, green, red) in that order. Use these
+ *   encoded in 4 bytes (alpha, blue, green, red) in that order. Use these
  *   names if the property of a format that is important to you is the order
  *   of the bytes in memory or on disk.
  * - Names with a bit count per component, such as ARGB8888 and XRGB1555, are
@@ -1379,7 +1379,7 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_MapRGBA(const SDL_PixelFormatDetails *for
  * (e.g., a completely white pixel in 16-bit RGB565 format would return [0xff,
  * 0xff, 0xff] not [0xf8, 0xfc, 0xf8]).
  *
- * \param pixel a pixel value.
+ * \param pixelvalue a pixel value.
  * \param format a pointer to SDL_PixelFormatDetails describing the pixel
  *               format.
  * \param palette an optional palette for indexed formats, may be NULL.
@@ -1397,7 +1397,7 @@ extern SDL_DECLSPEC Uint32 SDLCALL SDL_MapRGBA(const SDL_PixelFormatDetails *for
  * \sa SDL_MapRGB
  * \sa SDL_MapRGBA
  */
-extern SDL_DECLSPEC void SDLCALL SDL_GetRGB(Uint32 pixel, const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 *r, Uint8 *g, Uint8 *b);
+extern SDL_DECLSPEC void SDLCALL SDL_GetRGB(Uint32 pixelvalue, const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 *r, Uint8 *g, Uint8 *b);
 
 /**
  * Get RGBA values from a pixel in the specified format.
@@ -1410,7 +1410,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_GetRGB(Uint32 pixel, const SDL_PixelFormatD
  * If the surface has no alpha component, the alpha will be returned as 0xff
  * (100% opaque).
  *
- * \param pixel a pixel value.
+ * \param pixelvalue a pixel value.
  * \param format a pointer to SDL_PixelFormatDetails describing the pixel
  *               format.
  * \param palette an optional palette for indexed formats, may be NULL.
@@ -1429,7 +1429,7 @@ extern SDL_DECLSPEC void SDLCALL SDL_GetRGB(Uint32 pixel, const SDL_PixelFormatD
  * \sa SDL_MapRGB
  * \sa SDL_MapRGBA
  */
-extern SDL_DECLSPEC void SDLCALL SDL_GetRGBA(Uint32 pixel, const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a);
+extern SDL_DECLSPEC void SDLCALL SDL_GetRGBA(Uint32 pixelvalue, const SDL_PixelFormatDetails *format, const SDL_Palette *palette, Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a);
 
 
 /* Ends C function definitions when using C++ */

+ 12 - 1
libs/SDL3/include/SDL3/SDL_platform_defines.h

@@ -317,7 +317,7 @@
 #define SDL_PLATFORM_CYGWIN 1
 #endif
 
-#if defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)
+#if (defined(_WIN32) || defined(SDL_PLATFORM_CYGWIN)) && !defined(__NGAGE__)
 
 /**
  * A preprocessor macro that is only defined if compiling for Windows.
@@ -473,4 +473,15 @@
 #define SDL_PLATFORM_3DS 1
 #endif
 
+#ifdef __NGAGE__
+
+/**
+ * A preprocessor macro that is only defined if compiling for the Nokia
+ * N-Gage.
+ *
+ * \since This macro is available since SDL 3.4.0.
+ */
+#define SDL_PLATFORM_NGAGE 1
+#endif
+
 #endif /* SDL_platform_defines_h_ */

+ 11 - 0
libs/SDL3/include/SDL3/SDL_process.h

@@ -166,6 +166,9 @@ typedef enum SDL_ProcessIO
  * - `SDL_PROP_PROCESS_CREATE_ENVIRONMENT_POINTER`: an SDL_Environment
  *   pointer. If this property is set, it will be the entire environment for
  *   the process, otherwise the current environment is used.
+ * - `SDL_PROP_PROCESS_CREATE_WORKING_DIRECTORY_STRING`: a UTF-8 encoded
+ *   string representing the working directory for the process, defaults to
+ *   the current working directory.
  * - `SDL_PROP_PROCESS_CREATE_STDIN_NUMBER`: an SDL_ProcessIO value describing
  *   where standard input for the process comes from, defaults to
  *   `SDL_PROCESS_STDIO_NULL`.
@@ -192,6 +195,12 @@ typedef enum SDL_ProcessIO
  *   run in the background. In this case the default input and output is
  *   `SDL_PROCESS_STDIO_NULL` and the exitcode of the process is not
  *   available, and will always be 0.
+ * - `SDL_PROP_PROCESS_CREATE_CMDLINE_STRING`: a string containing the program
+ *   to run and any parameters. This string is passed directly to
+ *   `CreateProcess` on Windows, and does nothing on other platforms. This
+ *   property is only important if you want to start programs that does
+ *   non-standard command-line processing, and in most cases using
+ *   `SDL_PROP_PROCESS_CREATE_ARGS_POINTER` is sufficient.
  *
  * On POSIX platforms, wait() and waitpid(-1, ...) should not be called, and
  * SIGCHLD should not be ignored or handled because those would prevent SDL
@@ -219,6 +228,7 @@ extern SDL_DECLSPEC SDL_Process * SDLCALL SDL_CreateProcessWithProperties(SDL_Pr
 
 #define SDL_PROP_PROCESS_CREATE_ARGS_POINTER                "SDL.process.create.args"
 #define SDL_PROP_PROCESS_CREATE_ENVIRONMENT_POINTER         "SDL.process.create.environment"
+#define SDL_PROP_PROCESS_CREATE_WORKING_DIRECTORY_STRING    "SDL.process.create.working_directory"
 #define SDL_PROP_PROCESS_CREATE_STDIN_NUMBER                "SDL.process.create.stdin_option"
 #define SDL_PROP_PROCESS_CREATE_STDIN_POINTER               "SDL.process.create.stdin_source"
 #define SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER               "SDL.process.create.stdout_option"
@@ -227,6 +237,7 @@ extern SDL_DECLSPEC SDL_Process * SDLCALL SDL_CreateProcessWithProperties(SDL_Pr
 #define SDL_PROP_PROCESS_CREATE_STDERR_POINTER              "SDL.process.create.stderr_source"
 #define SDL_PROP_PROCESS_CREATE_STDERR_TO_STDOUT_BOOLEAN    "SDL.process.create.stderr_to_stdout"
 #define SDL_PROP_PROCESS_CREATE_BACKGROUND_BOOLEAN          "SDL.process.create.background"
+#define SDL_PROP_PROCESS_CREATE_CMDLINE_STRING              "SDL.process.create.cmdline"
 
 /**
  * Get the properties associated with a process.

+ 1 - 1
libs/SDL3/include/SDL3/SDL_rect.h

@@ -324,7 +324,7 @@ SDL_FORCE_INLINE bool SDL_PointInRectFloat(const SDL_FPoint *p, const SDL_FRect
 }
 
 /**
- * Determine whether a floating point rectangle can contain any point.
+ * Determine whether a floating point rectangle takes no space.
  *
  * A rectangle is considered "empty" for this function if `r` is NULL, or if
  * `r`'s width and/or height are < 0.0f.

+ 293 - 4
libs/SDL3/include/SDL3/SDL_render.h

@@ -59,6 +59,7 @@
 #include <SDL3/SDL_rect.h>
 #include <SDL3/SDL_surface.h>
 #include <SDL3/SDL_video.h>
+#include <SDL3/SDL_gpu.h>
 
 #include <SDL3/SDL_begin_code.h>
 /* Set up for C function definitions, even when using C++ */
@@ -97,6 +98,21 @@ typedef enum SDL_TextureAccess
     SDL_TEXTUREACCESS_TARGET     /**< Texture can be used as a render target */
 } SDL_TextureAccess;
 
+/**
+ * The addressing mode for a texture when used in SDL_RenderGeometry().
+ *
+ * This affects how texture coordinates are interpreted outside of [0, 1]
+ *
+ * \since This enum is available since SDL 3.4.0.
+ */
+typedef enum SDL_TextureAddressMode
+{
+    SDL_TEXTURE_ADDRESS_INVALID = -1,
+    SDL_TEXTURE_ADDRESS_AUTO,   /**< Wrapping is enabled if texture coordinates are outside [0, 1], this is the default */
+    SDL_TEXTURE_ADDRESS_CLAMP,  /**< Texture coordinates are clamped to the [0, 1] range */
+    SDL_TEXTURE_ADDRESS_WRAP,   /**< The texture is repeated (tiled) */
+} SDL_TextureAddressMode;
+
 /**
  * How the logical size is mapped to the output.
  *
@@ -267,6 +283,15 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRenderer(SDL_Window *window
  *   present synchronized with the refresh rate. This property can take any
  *   value that is supported by SDL_SetRenderVSync() for the renderer.
  *
+ * With the SDL GPU renderer:
+ *
+ * - `SDL_PROP_RENDERER_CREATE_GPU_SHADERS_SPIRV_BOOLEAN`: the app is able to
+ *   provide SPIR-V shaders to SDL_GPURenderState, optional.
+ * - `SDL_PROP_RENDERER_CREATE_GPU_SHADERS_DXIL_BOOLEAN`: the app is able to
+ *   provide DXIL shaders to SDL_GPURenderState, optional.
+ * - `SDL_PROP_RENDERER_CREATE_GPU_SHADERS_MSL_BOOLEAN`: the app is able to
+ *   provide MSL shaders to SDL_GPURenderState, optional.
+ *
  * With the vulkan renderer:
  *
  * - `SDL_PROP_RENDERER_CREATE_VULKAN_INSTANCE_POINTER`: the VkInstance to use
@@ -303,6 +328,9 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRendererWithProperties(SDL_
 #define SDL_PROP_RENDERER_CREATE_SURFACE_POINTER                            "SDL.renderer.create.surface"
 #define SDL_PROP_RENDERER_CREATE_OUTPUT_COLORSPACE_NUMBER                   "SDL.renderer.create.output_colorspace"
 #define SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER                       "SDL.renderer.create.present_vsync"
+#define SDL_PROP_RENDERER_CREATE_GPU_SHADERS_SPIRV_BOOLEAN                  "SDL.renderer.create.gpu.shaders_spirv"
+#define SDL_PROP_RENDERER_CREATE_GPU_SHADERS_DXIL_BOOLEAN                   "SDL.renderer.create.gpu.shaders_dxil"
+#define SDL_PROP_RENDERER_CREATE_GPU_SHADERS_MSL_BOOLEAN                    "SDL.renderer.create.gpu.shaders_msl"
 #define SDL_PROP_RENDERER_CREATE_VULKAN_INSTANCE_POINTER                    "SDL.renderer.create.vulkan.instance"
 #define SDL_PROP_RENDERER_CREATE_VULKAN_SURFACE_NUMBER                      "SDL.renderer.create.vulkan.surface"
 #define SDL_PROP_RENDERER_CREATE_VULKAN_PHYSICAL_DEVICE_POINTER             "SDL.renderer.create.vulkan.physical_device"
@@ -310,6 +338,37 @@ extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateRendererWithProperties(SDL_
 #define SDL_PROP_RENDERER_CREATE_VULKAN_GRAPHICS_QUEUE_FAMILY_INDEX_NUMBER  "SDL.renderer.create.vulkan.graphics_queue_family_index"
 #define SDL_PROP_RENDERER_CREATE_VULKAN_PRESENT_QUEUE_FAMILY_INDEX_NUMBER   "SDL.renderer.create.vulkan.present_queue_family_index"
 
+/**
+ * Create a 2D GPU rendering context for a window, with support for the
+ * specified shader format.
+ *
+ * This is a convenience function to create a SDL GPU backed renderer,
+ * intended to be used with SDL_GPURenderState. The resulting renderer will
+ * support shaders in one of the specified shader formats.
+ *
+ * If no available GPU driver supports any of the specified shader formats,
+ * this function will fail.
+ *
+ * \param window the window where rendering is displayed.
+ * \param format_flags a bitflag indicating which shader formats the app is
+ *                     able to provide.
+ * \param device a pointer filled with the associated GPU device, or NULL on
+ *               error.
+ * \returns a valid rendering context or NULL if there was an error; call
+ *          SDL_GetError() for more information.
+ *
+ * \threadsafety This function should only be called on the main thread.
+ *
+ * \since This function is available since SDL 3.4.0.
+ *
+ * \sa SDL_CreateRendererWithProperties
+ * \sa SDL_GetGPUShaderFormats
+ * \sa SDL_CreateGPUShader
+ * \sa SDL_CreateGPURenderState
+ * \sa SDL_SetRenderGPUState
+ */
+extern SDL_DECLSPEC SDL_Renderer * SDLCALL SDL_CreateGPURenderer(SDL_Window *window, SDL_GPUShaderFormat format_flags, SDL_GPUDevice **device);
+
 /**
  * Create a 2D software rendering context for a surface.
  *
@@ -1607,8 +1666,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderViewport(SDL_Renderer *renderer, S
  * Return whether an explicit rectangle was set as the viewport.
  *
  * This is useful if you're saving and restoring the viewport and want to know
- * whether you should restore a specific rectangle or NULL. Note that the
- * viewport is always reset when changing rendering targets.
+ * whether you should restore a specific rectangle or NULL.
  *
  * Each render target has its own viewport. This function checks the viewport
  * for the current render target.
@@ -2235,6 +2293,43 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderTextureTiled(SDL_Renderer *renderer,
  */
 extern SDL_DECLSPEC bool SDLCALL SDL_RenderTexture9Grid(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, float left_width, float right_width, float top_height, float bottom_height, float scale, const SDL_FRect *dstrect);
 
+/**
+ * Perform a scaled copy using the 9-grid algorithm to the current rendering
+ * target at subpixel precision.
+ *
+ * The pixels in the texture are split into a 3x3 grid, using the different
+ * corner sizes for each corner, and the sides and center making up the
+ * remaining pixels. The corners are then scaled using `scale` and fit into
+ * the corners of the destination rectangle. The sides and center are then
+ * tiled into place to cover the remaining destination rectangle.
+ *
+ * \param renderer the renderer which should copy parts of a texture.
+ * \param texture the source texture.
+ * \param srcrect the SDL_Rect structure representing the rectangle to be used
+ *                for the 9-grid, or NULL to use the entire texture.
+ * \param left_width the width, in pixels, of the left corners in `srcrect`.
+ * \param right_width the width, in pixels, of the right corners in `srcrect`.
+ * \param top_height the height, in pixels, of the top corners in `srcrect`.
+ * \param bottom_height the height, in pixels, of the bottom corners in
+ *                      `srcrect`.
+ * \param scale the scale used to transform the corner of `srcrect` into the
+ *              corner of `dstrect`, or 0.0f for an unscaled copy.
+ * \param dstrect a pointer to the destination rectangle, or NULL for the
+ *                entire rendering target.
+ * \param tileScale the scale used to transform the borders and center of
+ *                  `srcrect` into the borders and middle of `dstrect`, or
+ *                  1.0f for an unscaled copy.
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ *          information.
+ *
+ * \threadsafety This function should only be called on the main thread.
+ *
+ * \since This function is available since SDL 3.4.0.
+ *
+ * \sa SDL_RenderTexture
+ */
+extern SDL_DECLSPEC bool SDLCALL SDL_RenderTexture9GridTiled(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_FRect *srcrect, float left_width, float right_width, float top_height, float bottom_height, float scale, const SDL_FRect *dstrect, float tileScale);
+
 /**
  * Render a list of triangles, optionally using a texture and indices into the
  * vertex array Color and alpha modulation is done per vertex
@@ -2256,6 +2351,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderTexture9Grid(SDL_Renderer *renderer,
  * \since This function is available since SDL 3.2.0.
  *
  * \sa SDL_RenderGeometryRaw
+ * \sa SDL_SetRenderTextureAddressMode
  */
 extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometry(SDL_Renderer *renderer,
                                                SDL_Texture *texture,
@@ -2288,6 +2384,7 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometry(SDL_Renderer *renderer,
  * \since This function is available since SDL 3.2.0.
  *
  * \sa SDL_RenderGeometry
+ * \sa SDL_SetRenderTextureAddressMode
  */
 extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometryRaw(SDL_Renderer *renderer,
                                                SDL_Texture *texture,
@@ -2297,6 +2394,44 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderGeometryRaw(SDL_Renderer *renderer,
                                                int num_vertices,
                                                const void *indices, int num_indices, int size_indices);
 
+/**
+ * Set the texture addressing mode used in SDL_RenderGeometry().
+ *
+ * \param renderer the rendering context.
+ * \param u_mode the SDL_TextureAddressMode to use for horizontal texture
+ *               coordinates in SDL_RenderGeometry().
+ * \param v_mode the SDL_TextureAddressMode to use for vertical texture
+ *               coordinates in SDL_RenderGeometry().
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ *          information.
+ *
+ * \since This function is available since SDL 3.4.0.
+ *
+ * \sa SDL_RenderGeometry
+ * \sa SDL_RenderGeometryRaw
+ * \sa SDL_GetRenderTextureAddressMode
+ */
+extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderTextureAddressMode(SDL_Renderer *renderer, SDL_TextureAddressMode u_mode, SDL_TextureAddressMode v_mode);
+
+/**
+ * Get the texture addressing mode used in SDL_RenderGeometry().
+ *
+ * \param renderer the rendering context.
+ * \param u_mode a pointer filled in with the SDL_TextureAddressMode to use
+ *               for horizontal texture coordinates in SDL_RenderGeometry(),
+ *               may be NULL.
+ * \param v_mode a pointer filled in with the SDL_TextureAddressMode to use
+ *               for vertical texture coordinates in SDL_RenderGeometry(), may
+ *               be NULL.
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ *          information.
+ *
+ * \since This function is available since SDL 3.4.0.
+ *
+ * \sa SDL_SetRenderTextureAddressMode
+ */
+extern SDL_DECLSPEC bool SDLCALL SDL_GetRenderTextureAddressMode(SDL_Renderer *renderer, SDL_TextureAddressMode *u_mode, SDL_TextureAddressMode *v_mode);
+
 /**
  * Read pixels from the current rendering target.
  *
@@ -2348,8 +2483,7 @@ extern SDL_DECLSPEC SDL_Surface * SDLCALL SDL_RenderReadPixels(SDL_Renderer *ren
  * should not be done; you are only required to change back the rendering
  * target to default via `SDL_SetRenderTarget(renderer, NULL)` afterwards, as
  * textures by themselves do not have a concept of backbuffers. Calling
- * SDL_RenderPresent while rendering to a texture will still update the screen
- * with any current drawing that has been done _to the window itself_.
+ * SDL_RenderPresent while rendering to a texture will fail.
  *
  * \param renderer the rendering context.
  * \returns true on success or false on failure; call SDL_GetError() for more
@@ -2637,6 +2771,161 @@ extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugText(SDL_Renderer *renderer, flo
  */
 extern SDL_DECLSPEC bool SDLCALL SDL_RenderDebugTextFormat(SDL_Renderer *renderer, float x, float y, SDL_PRINTF_FORMAT_STRING const char *fmt, ...) SDL_PRINTF_VARARG_FUNC(4);
 
+/**
+ * Set default scale mode for new textures for given renderer.
+ *
+ * When a renderer is created, scale_mode defaults to SDL_SCALEMODE_LINEAR.
+ *
+ * \param renderer the renderer to update.
+ * \param scale_mode the scale mode to change to for new textures.
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ *          information.
+ *
+ * \threadsafety This function should only be called on the main thread.
+ *
+ * \since This function is available since SDL 3.4.0.
+ *
+ * \sa SDL_GetDefaultTextureScaleMode
+ */
+extern SDL_DECLSPEC bool SDLCALL SDL_SetDefaultTextureScaleMode(SDL_Renderer *renderer, SDL_ScaleMode scale_mode);
+
+/**
+ * Get default texture scale mode of the given renderer.
+ *
+ * \param renderer the renderer to get data from.
+ * \param scale_mode a SDL_ScaleMode filled with current default scale mode.
+ *                   See SDL_SetDefaultTextureScaleMode() for the meaning of
+ *                   the value.
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ *          information.
+ *
+ * \threadsafety This function should only be called on the main thread.
+ *
+ * \since This function is available since SDL 3.4.0.
+ *
+ * \sa SDL_SetDefaultTextureScaleMode
+ */
+extern SDL_DECLSPEC bool SDLCALL SDL_GetDefaultTextureScaleMode(SDL_Renderer *renderer, SDL_ScaleMode *scale_mode);
+
+/**
+ * GPU render state description.
+ *
+ * This structure should be initialized using SDL_INIT_INTERFACE().
+ *
+ * \since This struct is available since SDL 3.4.0.
+ *
+ * \sa SDL_CreateGPURenderState
+ */
+typedef struct SDL_GPURenderStateDesc
+{
+    Uint32 version;                 /**< the version of this interface */
+
+    SDL_GPUShader *fragment_shader; /**< The fragment shader to use when this render state is active */
+
+    Sint32 num_sampler_bindings;    /**< The number of additional fragment samplers to bind when this render state is active */
+    const SDL_GPUTextureSamplerBinding *sampler_bindings;   /**< Additional fragment samplers to bind when this render state is active */
+
+    Sint32 num_storage_textures;    /**< The number of storage textures to bind when this render state is active */
+    SDL_GPUTexture *const *storage_textures;    /**< Storage textures to bind when this render state is active */
+
+    Sint32 num_storage_buffers;    /**< The number of storage buffers to bind when this render state is active */
+    SDL_GPUBuffer *const *storage_buffers;      /**< Storage buffers to bind when this render state is active */
+} SDL_GPURenderStateDesc;
+
+/* Check the size of SDL_GPURenderStateDesc
+ *
+ * If this assert fails, either the compiler is padding to an unexpected size,
+ * or the interface has been updated and this should be updated to match and
+ * the code using this interface should be updated to handle the old version.
+ */
+SDL_COMPILE_TIME_ASSERT(SDL_GPURenderStateDesc_SIZE,
+    (sizeof(void *) == 4 && sizeof(SDL_GPURenderStateDesc) == 32) ||
+    (sizeof(void *) == 8 && sizeof(SDL_GPURenderStateDesc) == 64));
+
+/**
+ * A custom GPU render state.
+ *
+ * \since This struct is available since SDL 3.4.0.
+ *
+ * \sa SDL_CreateGPURenderState
+ * \sa SDL_SetGPURenderStateFragmentUniforms
+ * \sa SDL_SetRenderGPUState
+ * \sa SDL_DestroyGPURenderState
+ */
+typedef struct SDL_GPURenderState SDL_GPURenderState;
+
+/**
+ * Create custom GPU render state.
+ *
+ * \param renderer the renderer to use.
+ * \param desc GPU render state description, initialized using
+ *             SDL_INIT_INTERFACE().
+ * \returns a custom GPU render state or NULL on failure; call SDL_GetError()
+ *          for more information.
+ *
+ * \threadsafety This function should be called on the thread that created the
+ *               renderer.
+ *
+ * \since This function is available since SDL 3.4.0.
+ *
+ * \sa SDL_SetGPURenderStateFragmentUniforms
+ * \sa SDL_SetRenderGPUState
+ * \sa SDL_DestroyGPURenderState
+ */
+extern SDL_DECLSPEC SDL_GPURenderState * SDLCALL SDL_CreateGPURenderState(SDL_Renderer *renderer, SDL_GPURenderStateDesc *desc);
+
+/**
+ * Set fragment shader uniform variables in a custom GPU render state.
+ *
+ * The data is copied and will be pushed using
+ * SDL_PushGPUFragmentUniformData() during draw call execution.
+ *
+ * \param state the state to modify.
+ * \param slot_index the fragment uniform slot to push data to.
+ * \param data client data to write.
+ * \param length the length of the data to write.
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ *          information.
+ *
+ * \threadsafety This function should be called on the thread that created the
+ *               renderer.
+ *
+ * \since This function is available since SDL 3.4.0.
+ */
+extern SDL_DECLSPEC bool SDLCALL SDL_SetGPURenderStateFragmentUniforms(SDL_GPURenderState *state, Uint32 slot_index, const void *data, Uint32 length);
+
+/**
+ * Set custom GPU render state.
+ *
+ * This function sets custom GPU render state for subsequent draw calls. This
+ * allows using custom shaders with the GPU renderer.
+ *
+ * \param renderer the renderer to use.
+ * \param state the state to to use, or NULL to clear custom GPU render state.
+ * \returns true on success or false on failure; call SDL_GetError() for more
+ *          information.
+ *
+ * \threadsafety This function should be called on the thread that created the
+ *               renderer.
+ *
+ * \since This function is available since SDL 3.4.0.
+ */
+extern SDL_DECLSPEC bool SDLCALL SDL_SetRenderGPUState(SDL_Renderer *renderer, SDL_GPURenderState *state);
+
+/**
+ * Destroy custom GPU render state.
+ *
+ * \param state the state to destroy.
+ *
+ * \threadsafety This function should be called on the thread that created the
+ *               renderer.
+ *
+ * \since This function is available since SDL 3.4.0.
+ *
+ * \sa SDL_CreateGPURenderState
+ */
+extern SDL_DECLSPEC void SDLCALL SDL_DestroyGPURenderState(SDL_GPURenderState *state);
+
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 }

+ 7 - 3
libs/SDL3/include/SDL3/SDL_stdinc.h

@@ -2119,7 +2119,7 @@ extern SDL_DECLSPEC int SDLCALL SDL_abs(int x);
  *
  * \param x the first value to compare.
  * \param y the second value to compare.
- * \returns the lesser of `x` and `y`.
+ * \returns the greater of `x` and `y`.
  *
  * \threadsafety It is safe to call this macro from any thread.
  *
@@ -4656,7 +4656,7 @@ extern SDL_DECLSPEC float SDLCALL SDL_atanf(float x);
  *
  * Domain: `-INF <= x <= INF`, `-INF <= y <= INF`
  *
- * Range: `-Pi/2 <= y <= Pi/2`
+ * Range: `-Pi <= y <= Pi`
  *
  * This function operates on double-precision floating point values, use
  * SDL_atan2f for single-precision floats.
@@ -4692,7 +4692,7 @@ extern SDL_DECLSPEC double SDLCALL SDL_atan2(double y, double x);
  *
  * Domain: `-INF <= x <= INF`, `-INF <= y <= INF`
  *
- * Range: `-Pi/2 <= y <= Pi/2`
+ * Range: `-Pi <= y <= Pi`
  *
  * This function operates on single-precision floating point values, use
  * SDL_atan2 for double-precision floats.
@@ -5974,8 +5974,12 @@ size_t wcslcpy(wchar_t *dst, const wchar_t *src, size_t size);
 size_t wcslcat(wchar_t *dst, const wchar_t *src, size_t size);
 #endif
 
+#ifndef _WIN32
 /* strdup is not ANSI but POSIX, and its prototype might be hidden... */
+/* not for windows: might conflict with string.h where strdup may have
+ * dllimport attribute: https://github.com/libsdl-org/SDL/issues/12948 */
 char *strdup(const char *str);
+#endif
 
 /* Starting LLVM 16, the analyser errors out if these functions do not have
    their prototype defined (clang-diagnostic-implicit-function-declaration) */

+ 4 - 0
libs/SDL3/include/SDL3/SDL_storage.h

@@ -334,6 +334,10 @@ typedef struct SDL_Storage SDL_Storage;
 /**
  * Opens up a read-only container for the application's filesystem.
  *
+ * By default, SDL_OpenTitleStorage uses the generic storage implementation.
+ * When the path override is not provided, the generic implementation will use
+ * the output of SDL_GetBasePath as the base path.
+ *
  * \param override a path to override the backend's default title root.
  * \param props a property list that may contain backend-specific information.
  * \returns a title storage container on success or NULL on failure; call

+ 8 - 8
libs/SDL3/include/SDL3/SDL_surface.h

@@ -32,7 +32,8 @@
  * There is also a simple .bmp loader, SDL_LoadBMP(). SDL itself does not
  * provide loaders for various other file formats, but there are several
  * excellent external libraries that do, including its own satellite library,
- * SDL_image:
+ * [SDL_image](https://wiki.libsdl.org/SDL3_image)
+ * :
  *
  * https://github.com/libsdl-org/SDL_image
  */
@@ -83,8 +84,9 @@ typedef Uint32 SDL_SurfaceFlags;
 typedef enum SDL_ScaleMode
 {
     SDL_SCALEMODE_INVALID = -1,
-    SDL_SCALEMODE_NEAREST, /**< nearest pixel sampling */
-    SDL_SCALEMODE_LINEAR   /**< linear filtering */
+    SDL_SCALEMODE_NEAREST,  /**< nearest pixel sampling */
+    SDL_SCALEMODE_LINEAR,   /**< linear filtering */
+    SDL_SCALEMODE_PIXELART  /**< nearest pixel sampling with improved scaling for pixel art */
 } SDL_ScaleMode;
 
 /**
@@ -1135,9 +1137,6 @@ extern SDL_DECLSPEC bool SDLCALL SDL_FillSurfaceRects(SDL_Surface *dst, const SD
  * If either `srcrect` or `dstrect` are NULL, the entire surface (`src` or
  * `dst`) is copied while ensuring clipping to `dst->clip_rect`.
  *
- * The final blit rectangles are saved in `srcrect` and `dstrect` after all
- * clipping is performed.
- *
  * The blit function should not be called on a locked surface.
  *
  * The blit semantics for surfaces with and without blending and colorkey are
@@ -1282,10 +1281,11 @@ extern SDL_DECLSPEC bool SDLCALL SDL_BlitSurfaceUncheckedScaled(SDL_Surface *src
  *
  * \param src the SDL_Surface structure to be copied from.
  * \param srcrect the SDL_Rect structure representing the rectangle to be
- *                copied, may not be NULL.
+ *                copied, or NULL to copy the entire surface.
  * \param dst the SDL_Surface structure that is the blit target.
  * \param dstrect the SDL_Rect structure representing the target rectangle in
- *                the destination surface, may not be NULL.
+ *                the destination surface, or NULL to fill the entire
+ *                destination surface.
  * \param scaleMode the SDL_ScaleMode to be used.
  * \returns true on success or false on failure; call SDL_GetError() for more
  *          information.

+ 2 - 2
libs/SDL3/include/SDL3/SDL_system.h

@@ -247,14 +247,14 @@ typedef void (SDLCALL *SDL_iOSAnimationCallback)(void *userdata);
  *
  * For more information see:
  *
- * https://wiki.libsdl.org/SDL3/README/ios
+ * https://wiki.libsdl.org/SDL3/README-ios
  *
  * Note that if you use the "main callbacks" instead of a standard C `main`
  * function, you don't have to use this API, as SDL will manage this for you.
  *
  * Details on main callbacks are here:
  *
- * https://wiki.libsdl.org/SDL3/README/main-functions
+ * https://wiki.libsdl.org/SDL3/README-main-functions
  *
  * \param window the window for which the animation callback should be set.
  * \param interval the number of frames after which **callback** will be

Some files were not shown because too many files changed in this diff