Ver Fonte

Merge pull request #1480 from Azaezel/alpha1/sdlUpdate

update sdl to 2.32.6
Brian Roberts há 4 meses atrás
pai
commit
fc73890ca8
100 ficheiros alterados com 6092 adições e 758 exclusões
  1. 90 0
      Engine/lib/sdl/.clang-format
  2. 79 0
      Engine/lib/sdl/.editorconfig
  3. 190 0
      Engine/lib/sdl/.gitignore
  4. 31 0
      Engine/lib/sdl/.wikiheaders-options
  5. 1 0
      Engine/lib/sdl/Android.mk
  6. 258 139
      Engine/lib/sdl/CMakeLists.txt
  7. 1 1
      Engine/lib/sdl/LICENSE.txt
  8. 1 1
      Engine/lib/sdl/Makefile.in
  9. 8 6
      Engine/lib/sdl/Makefile.os2
  10. 9 6
      Engine/lib/sdl/Makefile.w32
  11. 0 119
      Engine/lib/sdl/SDL2.spec
  12. 0 1
      Engine/lib/sdl/VERSION.txt
  13. 7 0
      Engine/lib/sdl/VisualC-GDK/clean.sh
  14. BIN
      Engine/lib/sdl/VisualC-GDK/logos/Logo100x100.png
  15. BIN
      Engine/lib/sdl/VisualC-GDK/logos/Logo150x150.png
  16. BIN
      Engine/lib/sdl/VisualC-GDK/logos/Logo44x44.png
  17. BIN
      Engine/lib/sdl/VisualC-GDK/logos/Logo480x480.png
  18. BIN
      Engine/lib/sdl/VisualC-GDK/logos/SplashScreenImage.png
  19. 19 0
      Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_Colors.hlsl
  20. 43 0
      Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_NV12_BT601.hlsl
  21. 43 0
      Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_NV12_BT709.hlsl
  22. 43 0
      Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_NV12_JPEG.hlsl
  23. 43 0
      Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_NV21_BT601.hlsl
  24. 43 0
      Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_NV21_BT709.hlsl
  25. 43 0
      Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_NV21_JPEG.hlsl
  26. 24 0
      Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_Textures.hlsl
  27. 46 0
      Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_YUV_BT601.hlsl
  28. 46 0
      Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_YUV_BT709.hlsl
  29. 46 0
      Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_YUV_JPEG.hlsl
  30. 95 0
      Engine/lib/sdl/VisualC-GDK/shaders/D3D12_VertexShader.hlsl
  31. 35 0
      Engine/lib/sdl/VisualC-GDK/shaders/buildshaders.bat
  32. 9 0
      Engine/lib/sdl/VisualC-GDK/tests/testgamecontroller/PackageLayout.xml
  33. 34 0
      Engine/lib/sdl/VisualC-GDK/tests/testgamecontroller/wingdk/MicrosoftGame.config
  34. 29 0
      Engine/lib/sdl/VisualC-GDK/tests/testgamecontroller/xboxone/MicrosoftGame.config
  35. 29 0
      Engine/lib/sdl/VisualC-GDK/tests/testgamecontroller/xboxseries/MicrosoftGame.config
  36. 10 0
      Engine/lib/sdl/VisualC-GDK/tests/testgdk/PackageLayout.xml
  37. 503 0
      Engine/lib/sdl/VisualC-GDK/tests/testgdk/src/testgdk.cpp
  38. 34 0
      Engine/lib/sdl/VisualC-GDK/tests/testgdk/wingdk/MicrosoftGame.config
  39. 29 0
      Engine/lib/sdl/VisualC-GDK/tests/testgdk/xboxone/MicrosoftGame.config
  40. 29 0
      Engine/lib/sdl/VisualC-GDK/tests/testgdk/xboxseries/MicrosoftGame.config
  41. 9 0
      Engine/lib/sdl/VisualC-GDK/tests/testsprite2/PackageLayout.xml
  42. 34 0
      Engine/lib/sdl/VisualC-GDK/tests/testsprite2/wingdk/MicrosoftGame.config
  43. 29 0
      Engine/lib/sdl/VisualC-GDK/tests/testsprite2/xboxone/MicrosoftGame.config
  44. 29 0
      Engine/lib/sdl/VisualC-GDK/tests/testsprite2/xboxseries/MicrosoftGame.config
  45. 5 3
      Engine/lib/sdl/VisualC/pkg-support/cmake/sdl2-config.cmake
  46. 19 0
      Engine/lib/sdl/WhatsNew.txt
  47. 5 5
      Engine/lib/sdl/Xcode-iOS/Demos/src/accelerometer.c
  48. 5 5
      Engine/lib/sdl/Xcode-iOS/Demos/src/fireworks.c
  49. 2 2
      Engine/lib/sdl/Xcode-iOS/Demos/src/happy.c
  50. 3 3
      Engine/lib/sdl/Xcode-iOS/Demos/src/keyboard.c
  51. 2 2
      Engine/lib/sdl/Xcode-iOS/Demos/src/rectangles.c
  52. 2 2
      Engine/lib/sdl/Xcode-iOS/Demos/src/touch.c
  53. 2 2
      Engine/lib/sdl/Xcode/SDL/Info-Framework.plist
  54. 220 68
      Engine/lib/sdl/Xcode/SDL/SDL.xcodeproj/project.pbxproj
  55. 1 1
      Engine/lib/sdl/Xcode/SDL/pkg-support/SDL.info
  56. 12 5
      Engine/lib/sdl/Xcode/SDL/pkg-support/resources/CMake/sdl2-config.cmake
  57. 1 1
      Engine/lib/sdl/Xcode/SDL/pkg-support/resources/License.txt
  58. 685 43
      Engine/lib/sdl/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj
  59. 88 75
      Engine/lib/sdl/acinclude/libtool.m4
  60. 1 1
      Engine/lib/sdl/acinclude/ltoptions.m4
  61. 1 0
      Engine/lib/sdl/android-project-ant/AndroidManifest.xml
  62. 17 0
      Engine/lib/sdl/android-project-ant/ant.properties
  63. 17 0
      Engine/lib/sdl/android-project-ant/build.properties
  64. 93 0
      Engine/lib/sdl/android-project-ant/build.xml
  65. 11 0
      Engine/lib/sdl/android-project-ant/default.properties
  66. 1 0
      Engine/lib/sdl/android-project-ant/jni/Android.mk
  67. 10 0
      Engine/lib/sdl/android-project-ant/jni/Application.mk
  68. 18 0
      Engine/lib/sdl/android-project-ant/jni/src/Android.mk
  69. 12 0
      Engine/lib/sdl/android-project-ant/jni/src/Android_static.mk
  70. 20 0
      Engine/lib/sdl/android-project-ant/proguard-project.txt
  71. 14 0
      Engine/lib/sdl/android-project-ant/project.properties
  72. BIN
      Engine/lib/sdl/android-project-ant/res/drawable-hdpi/ic_launcher.png
  73. BIN
      Engine/lib/sdl/android-project-ant/res/drawable-mdpi/ic_launcher.png
  74. BIN
      Engine/lib/sdl/android-project-ant/res/drawable-xhdpi/ic_launcher.png
  75. BIN
      Engine/lib/sdl/android-project-ant/res/drawable-xxhdpi/ic_launcher.png
  76. 13 0
      Engine/lib/sdl/android-project-ant/res/layout/main.xml
  77. 4 0
      Engine/lib/sdl/android-project-ant/res/values/strings.xml
  78. 1 0
      Engine/lib/sdl/android-project-ant/src
  79. 81 0
      Engine/lib/sdl/android-project/app/proguard-rules.pro
  80. 1 1
      Engine/lib/sdl/android-project/app/src/main/AndroidManifest.xml
  81. 16 1
      Engine/lib/sdl/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java
  82. 9 5
      Engine/lib/sdl/android-project/app/src/main/java/org/libsdl/app/SDL.java
  83. 12 9
      Engine/lib/sdl/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
  84. 9 7
      Engine/lib/sdl/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java
  85. 2 3
      Engine/lib/sdl/android-project/app/src/main/res/values/styles.xml
  86. 2 1
      Engine/lib/sdl/build-scripts/androidbuild.sh
  87. 1470 0
      Engine/lib/sdl/build-scripts/build-release.py
  88. 18 0
      Engine/lib/sdl/build-scripts/cmake-toolchain-mingw64-i686.cmake
  89. 18 0
      Engine/lib/sdl/build-scripts/cmake-toolchain-mingw64-x86_64.cmake
  90. 14 6
      Engine/lib/sdl/build-scripts/config.guess
  91. 563 173
      Engine/lib/sdl/build-scripts/config.sub
  92. 43 0
      Engine/lib/sdl/build-scripts/create-release.py
  93. 2 2
      Engine/lib/sdl/build-scripts/gen_audio_channel_conversion.c
  94. 2 2
      Engine/lib/sdl/build-scripts/gen_audio_resampler_filter.c
  95. 70 52
      Engine/lib/sdl/build-scripts/ltmain.sh
  96. 108 0
      Engine/lib/sdl/build-scripts/release-info.json
  97. 303 0
      Engine/lib/sdl/build-scripts/setup-gdk-desktop.py
  98. 2 2
      Engine/lib/sdl/build-scripts/showrev.sh
  99. 10 2
      Engine/lib/sdl/build-scripts/update-copyright.sh
  100. 1 1
      Engine/lib/sdl/build-scripts/updaterev.sh

+ 90 - 0
Engine/lib/sdl/.clang-format

@@ -0,0 +1,90 @@
+---
+AlignConsecutiveMacros: Consecutive
+AlignConsecutiveAssignments: None
+AlignConsecutiveBitFields: None
+AlignConsecutiveDeclarations: None
+AlignEscapedNewlines: Right
+AlignOperands: Align
+AlignTrailingComments: true
+
+AllowAllArgumentsOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortEnumsOnASingleLine: true
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: Never
+AllowShortLoopsOnASingleLine: false
+
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: MultiLine
+
+# Custom brace breaking
+BreakBeforeBraces: Custom
+BraceWrapping:
+  AfterCaseLabel: true
+  AfterClass: true
+  AfterControlStatement: Never
+  AfterEnum: true
+  AfterFunction: true
+  AfterNamespace: true
+  AfterObjCDeclaration: true
+  AfterStruct: true
+  AfterUnion: true
+  AfterExternBlock: false
+  BeforeElse: false
+  BeforeWhile: false
+  IndentBraces: false
+  SplitEmptyFunction: true
+  SplitEmptyRecord: true
+
+# Make the closing brace of container literals go to a new line
+Cpp11BracedListStyle: false
+
+# Never format includes
+IncludeBlocks: Preserve
+# clang-format version 4.0 through 12.0:
+#SortIncludes: false
+# clang-format version 13.0+:
+#SortIncludes: Never
+
+# No length limit, in case it breaks macros, you can
+# disable it with /* clang-format off/on */ comments
+ColumnLimit: 0
+
+IndentWidth: 4
+ContinuationIndentWidth: 4
+IndentCaseLabels: false
+IndentCaseBlocks: false
+IndentGotoLabels: true
+IndentPPDirectives: None
+IndentExternBlock: NoIndent
+
+PointerAlignment: Right
+SpaceAfterCStyleCast: false
+SpacesInCStyleCastParentheses: false
+SpacesInConditionalStatement: false
+SpacesInContainerLiterals: true
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCaseColon: false
+SpaceBeforeParens: ControlStatements
+SpaceAroundPointerQualifiers: Default
+SpaceInEmptyBlock: false
+SpaceInEmptyParentheses: false
+
+UseCRLF: false
+UseTab: Never
+
+ForEachMacros:
+  [
+    "spa_list_for_each",
+    "spa_list_for_each_safe",
+    "wl_list_for_each",
+    "wl_array_for_each",
+    "udev_list_entry_foreach",
+  ]
+
+---
+

+ 79 - 0
Engine/lib/sdl/.editorconfig

@@ -0,0 +1,79 @@
+# For format see editorconfig.org
+# Copyright 2022 Collabora Ltd.
+# SPDX-License-Identifier: Zlib
+
+root = true
+
+[*.{c,cg,cpp,gradle,h,java,m,metal,pl,py,S,sh,txt}]
+indent_size = 4
+indent_style = space
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.{html,js,json,m4,yml,yaml,vcxproj,vcxproj.filters}]
+indent_size = 2
+indent_style = space
+
+[*.xml]
+indent_size = 4
+indent_style = space
+
+[{CMakeLists.txt,sdl2-config*.cmake.in,cmake/*.cmake}]
+indent_size = 2
+indent_style = space
+
+[{cmake_uninstall.cmake.in,test/CMakeLists.txt}]
+indent_size = 4
+indent_style = space
+
+[configure.ac]
+# Inconsistently 2-, 4- or occasionally 3-space indented, but mostly 4,
+# so let's use 4 for new code
+indent_size = 4
+indent_style = space
+
+[{Makefile.*,*.mk,*.sln,*.pbxproj,*.plist}]
+indent_size = 8
+indent_style = tab
+tab_width = 8
+
+[Makefile.os2]
+indent_size = 4
+indent_style = space
+
+[test/Makefile.os2]
+indent_size = 2
+indent_style = space
+
+[{src/core/os2/geniconv/makefile,src/core/os2/geniconv/os2cp.c}]
+indent_size = 2
+indent_style = space
+
+[src/joystick/controller_type.*]
+indent_style = tab
+
+[src/joystick/hidapi/steam/*.h]
+indent_style = tab
+
+[src/libm/*.c]
+indent_style = tab
+
+[src/test/SDL_test_{crc32,md5,random}.c]
+indent_size = 2
+indent_style = space
+
+[src/video/yuv2rgb/*.{c,h}]
+indent_style = tab
+
+[wayland-protocols/*.xml]
+indent_size = 2
+indent_style = space
+
+[*.{markdown,md}]
+indent_size = 4
+indent_style = space
+# Markdown syntax treats tabs as 4 spaces
+tab_width = 4
+
+[{*.bat,*.rc}]
+end_of_line = crlf

+ 190 - 0
Engine/lib/sdl/.gitignore

@@ -0,0 +1,190 @@
+aclocal.m4
+autom4te*
+config.cache
+config.log
+config.status
+libtool
+Makefile
+Makefile.rules
+sdl2-config
+sdl2-config.cmake
+sdl2-config-version.cmake
+sdl2.pc
+SDL2.spec
+build
+gen
+Build
+buildbot
+/REVISION.txt
+dist
+
+*.so
+*.so.*
+*.dll
+*.exe
+*.o
+*.obj
+*.res
+*.lib
+*.a
+*.la
+*.dSYM
+*,e1f
+*,ff8
+*.lnk
+*.err
+*.exp
+*.map
+*.orig
+*~
+*.swp
+*.tmp
+*.rej
+
+# for CMake
+CMakeFiles/
+CMakeCache.txt
+cmake_install.cmake
+cmake_uninstall.cmake
+SDL2ConfigVersion.cmake
+.ninja_*
+*.ninja
+
+# for CLion
+.idea
+cmake-build-*
+
+# for Xcode
+*.mode1*
+*.perspective*
+*.pbxuser
+(^|/)build($|/)
+.DS_Store
+xcuserdata
+*.xcworkspace
+
+# for QtCreator
+CMakeLists.txt.user
+build*/
+*.pro.user*
+
+# for Visual C++
+.vs
+Debug
+Release
+*.user
+*.ncb
+*.suo
+*.sdf
+VisualC/tests/controllermap/axis.bmp
+VisualC/tests/controllermap/button.bmp
+VisualC/tests/controllermap/controllermap.bmp
+VisualC/tests/controllermap/controllermap_back.bmp
+VisualC/tests/loopwave/sample.wav
+VisualC/tests/testautomation/CompareSurfaces0001_Reference.bmp
+VisualC/tests/testautomation/CompareSurfaces0001_TestOutput.bmp
+VisualC/tests/testgamecontroller/axis.bmp
+VisualC/tests/testgamecontroller/button.bmp
+VisualC/tests/testgamecontroller/controllermap.bmp
+VisualC/tests/testgamecontroller/controllermap_back.bmp
+VisualC/tests/testoverlay2/moose.dat
+VisualC/tests/testrendertarget/icon.bmp
+VisualC/tests/testrendertarget/sample.bmp
+VisualC/tests/testscale/icon.bmp
+VisualC/tests/testscale/sample.bmp
+VisualC/tests/testsprite2/icon.bmp
+VisualC/tests/testyuv/testyuv.bmp
+VisualC/visualtest/icon.bmp
+VisualC/visualtest/testquit.actions
+VisualC/visualtest/testquit.config
+VisualC/visualtest/testquit.exe
+VisualC/visualtest/testquit.parameters
+VisualC/visualtest/testsprite2.exe
+VisualC/visualtest/testsprite2_sample.actions
+VisualC/visualtest/testsprite2_sample.config
+VisualC/visualtest/testsprite2_sample.parameters
+VisualC-GDK/**/Layout
+VisualC-GDK/shaders/*.h
+
+# for Android
+android-project/local.properties
+android-project/.gradle/
+
+test/checkkeys
+test/checkkeysthreads
+test/controllermap
+test/loopwave
+test/loopwavequeue
+test/testatomic
+test/testaudiocapture
+test/testaudiohotplug
+test/testaudioinfo
+test/testautomation
+test/testbounds
+test/testcustomcursor
+test/testdisplayinfo
+test/testdraw2
+test/testdrawchessboard
+test/testdropfile
+test/testerror
+test/testevdev
+test/testfile
+test/testfilesystem
+test/testgamecontroller
+test/testgeometry
+test/testgesture
+test/testgl2
+test/testgles
+test/testgles2
+test/testhaptic
+test/testhittesting
+test/testhotplug
+test/testiconv
+test/testime
+test/testintersections
+test/testjoystick
+test/testkeys
+test/testloadso
+test/testlocale
+test/testlock
+test/testmessage
+test/testmouse
+test/testmultiaudio
+test/testnative
+test/testoverlay2
+test/testplatform
+test/testpower
+test/testqsort
+test/testrelative
+test/testrendercopyex
+test/testrendertarget
+test/testresample
+test/testrumble
+test/testscale
+test/testsem
+test/testsensor
+test/testshader
+test/testshape
+test/testsprite2
+test/testspriteminimal
+test/teststreaming
+test/testsurround
+test/testthread
+test/testtimer
+test/testurl
+test/testver
+test/testviewport
+test/testvulkan
+test/testwm2
+test/testyuv
+test/torturethread
+
+builddir/
+!build-scripts/
+debian/*.debhelper.log
+debian/*.substvars
+debian/*.tar.gz
+debian/.debhelper/
+debian/files
+debian/libsdl*/
+debian/tmp/

+ 31 - 0
Engine/lib/sdl/.wikiheaders-options

@@ -0,0 +1,31 @@
+projectfullname = Simple Directmedia Layer
+projectshortname = SDL
+incsubdir = include
+wikisubdir = SDL2
+readmesubdir = docs
+apiprefixregex = (SDL_|SDLK_|KMOD_|AUDIO_|[US]int\d+)
+mainincludefname = SDL.h
+versionfname = include/SDL_version.h
+versionmajorregex = \A\#define\s+SDL_MAJOR_VERSION\s+(\d+)\Z
+versionminorregex = \A\#define\s+SDL_MINOR_VERSION\s+(\d+)\Z
+versionpatchregex = \A\#define\s+SDL_PATCHLEVEL\s+(\d+)\Z
+selectheaderregex = \ASDL.*?\.h\Z
+projecturl = https://libsdl.org/
+wikiurl = https://wiki.libsdl.org/SDL2
+bugreporturl = https://github.com/libsdl-org/sdlwiki/issues/new
+warn_about_missing = 0
+#wikipreamble = (This is the legacy documentation for SDL2, the previous stable version; [SDL3](https://wiki.libsdl.org/SDL3/) is the current stable version.)
+wikiheaderfiletext = Defined in [%fname%](https://github.com/libsdl-org/SDL/blob/SDL2/include/%fname%)
+manpageheaderfiletext = Defined in %fname%
+
+# All SDL_config_*.h headers are uncategorized, in case something slips in from them.
+# All SDL_test_* headers become uncategorized, everything else just converts like SDL_audio.h -> Audio
+# A handful of others we fix up in the header itself with /* WIKI CATEGORY: x */ comments.
+headercategoryeval = s/\ASDL_config_.*?\.h\Z//; s/\ASDL_test_.*?\.h\Z//; s/\ASDL_?(.*?)\.h\Z/$1/; ucfirst();
+
+quickrefenabled = 0  # !!! FIXME: maybe later, but there are probably documentation gaps to fix first.
+quickrefcategoryorder = Init,Hints,Error,Version,Properties,Log,Video,Events,Keyboard,Mouse,Touch,Gesture,GameController,Joystick,Haptic,Audio,Timer,Render,LoadSO,Thread,Mutex,Atomic,Filesystem,RWOPS,Pixels,Surface,Blendmode,Rect,Clipboard,Messagebox,Vulkan,Metal,Platform,Power,Sensor,Bits,Endian,Assert,CPUInfo,Locale,System,Misc,GUID,Main,Stdinc
+quickreftitle = SDL2 API Quick Reference
+quickrefurl = https://libsdl.org/
+quickrefdesc = The latest version of this document can be found at https://wiki.libsdl.org/SDL2/QuickReference
+quickrefmacroregex = \A(SDL_Atomic...Ref|SDL_assert.*?|SDL_arraysize|SDL_Swap[BL]E\d\d|SDL_[a-z]+_cast|SDL_Load...)\Z

+ 1 - 0
Engine/lib/sdl/Android.mk

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

+ 258 - 139
Engine/lib/sdl/CMakeLists.txt

@@ -5,8 +5,8 @@ endif()
 # MSVC runtime library flags are selected by an abstraction.
 set(CMAKE_POLICY_DEFAULT_CMP0091 NEW)
 
-cmake_minimum_required(VERSION 3.0.0...3.5)
-project(SDL2 C CXX)
+cmake_minimum_required(VERSION 3.0.0...3.10)
+project(SDL2 C)
 
 if(CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR)
   set(SDL2_SUBPROJECT OFF)
@@ -15,13 +15,15 @@ else()
 endif()
 
 if (HAIKU)
+  enable_language(CXX)
   set(LINKER_LANGUAGE CXX)
 endif()
 
 set(EXTRA_LIBS)
 set(EXTRA_LDFLAGS)
 
-set(CMAKE_DEPENDS)
+set(CMAKE_LIBS)
+set(PKGCONFIG_LDFLAGS)
 set(PKGCONFIG_DEPENDS)
 
 # This is a virtual "library" that just exists to collect up compiler and
@@ -33,8 +35,8 @@ set(PKGCONFIG_DEPENDS)
 add_library(sdl-build-options INTERFACE)
 
 if(WINDOWS_STORE)
-  target_compile_definitions(sdl-build-options INTERFACE "-DSDL_BUILDING_WINRT=1")
-  target_compile_options(sdl-build-options INTERFACE "-ZW")
+  target_compile_definitions(sdl-build-options INTERFACE "-DSDL_BUILDING_WINRT=1" "WINAPI_FAMILY=WINAPI_FAMILY_APP")
+  target_compile_options(sdl-build-options INTERFACE "$<$<COMPILE_LANGUAGE:CXX>:-ZW>" "$<$<COMPILE_LANGUAGE:CXX>:-EHsc>")
 endif()
 
 # CMake 3.0 expands the "if(${A})" in "set(OFF 1);set(A OFF);if(${A})" to "if(1)"
@@ -86,8 +88,8 @@ endif()
 
 # See docs/release_checklist.md
 set(SDL_MAJOR_VERSION 2)
-set(SDL_MINOR_VERSION 28)
-set(SDL_MICRO_VERSION 4)
+set(SDL_MINOR_VERSION 32)
+set(SDL_MICRO_VERSION 6)
 set(SDL_VERSION "${SDL_MAJOR_VERSION}.${SDL_MINOR_VERSION}.${SDL_MICRO_VERSION}")
 
 # Set defaults preventing destination file conflicts
@@ -140,6 +142,7 @@ check_cpu_architecture(x86 SDL_CPU_X86)
 check_cpu_architecture(x64 SDL_CPU_X64)
 check_cpu_architecture(arm32 SDL_CPU_ARM32)
 check_cpu_architecture(arm64 SDL_CPU_ARM64)
+check_cpu_architecture(arm64ec SDL_CPU_ARM64EC)
 check_cpu_architecture(loongarch64 SDL_CPU_LOONGARCH64)
 
 # Check for 64 or 32 bit
@@ -195,7 +198,7 @@ endif()
 #  so we'll just use libusb when it's available. libusb does not support iOS,
 #  so we default to yes on iOS.
 #  TODO: Windows can support libusb, the hid.c file just depends on Unix APIs
-if((WINDOWS AND NOT WINDOWS_STORE) OR IOS OR TVOS OR ANDROID)
+if((WINDOWS AND NOT WINDOWS_STORE) OR IOS OR TVOS OR VISIONOS OR WATCHOS OR ANDROID)
   set(HIDAPI_SKIP_LIBUSB TRUE)
 else()
   set(HIDAPI_SKIP_LIBUSB FALSE)
@@ -238,9 +241,14 @@ if(USE_GCC OR USE_CLANG OR USE_INTELCC OR USE_QCC)
 endif()
 
 # Default option knobs
-if(UNIX OR MINGW OR MSYS OR (USE_CLANG AND NOT WINDOWS) OR VITA OR PSP OR PS2 OR N3DS)
+if(UNIX OR MINGW OR MSYS OR (USE_CLANG AND NOT WINDOWS) OR VITA OR PSP OR PS2 OR N3DS OR SDL_CPU_ARM64EC)
   set(OPT_DEF_LIBC ON)
 endif()
+if(WINDOWS OR MACOS OR IOS OR TVOS OR VISIONOS OR WATCHOS)
+  set(SDL_SYSTEM_ICONV_DEFAULT OFF)
+else()
+  set(SDL_SYSTEM_ICONV_DEFAULT ON)
+endif()
 
 if(NOT ("$ENV{CFLAGS}" STREQUAL ""))
   if(CMAKE_VERSION VERSION_LESS 3.11.0)
@@ -355,6 +363,11 @@ if(VITA OR PSP OR PS2 OR N3DS)
   set(SDL_LOADSO_ENABLED_BY_DEFAULT OFF)
 endif()
 
+set(SDL_X11_XRANDR_DEFAULT ON)
+if(SOLARIS)
+  set(SDL_X11_XRANDR_DEFAULT OFF)
+endif()
+
 # When defined, respect CMake's BUILD_SHARED_LIBS setting:
 set(SDL_STATIC_ENABLED_BY_DEFAULT ON)
 if (NOT DEFINED SDL_SHARED_ENABLED_BY_DEFAULT)
@@ -404,7 +417,7 @@ dep_option(SDL_SSE                 "Use SSE assembly routines" ON "SDL_ASSEMBLY;
 dep_option(SDL_SSE2                "Use SSE2 assembly routines" ON "SDL_ASSEMBLY;SDL_CPU_X86 OR SDL_CPU_X64" OFF)
 dep_option(SDL_SSE3                "Use SSE3 assembly routines" ON "SDL_ASSEMBLY;SDL_CPU_X86 OR SDL_CPU_X64" OFF)
 dep_option(SDL_MMX                 "Use MMX assembly routines" ON "SDL_ASSEMBLY;SDL_CPU_X86 OR SDL_CPU_X64" OFF)
-dep_option(SDL_3DNOW               "Use 3Dnow! MMX assembly routines" ON "SDL_ASSEMBLY;SDL_CPU_X86 OR SDL_CPU_X64" OFF)
+dep_option(SDL_3DNOW               "Use 3Dnow! MMX assembly routines" OFF "SDL_ASSEMBLY;SDL_CPU_X86 OR SDL_CPU_X64" OFF)
 dep_option(SDL_ALTIVEC             "Use Altivec assembly routines" ON "SDL_ASSEMBLY" OFF)
 dep_option(SDL_ARMSIMD             "Use SIMD assembly blitters on ARM" OFF "SDL_ASSEMBLY;SDL_CPU_ARM32" OFF)
 dep_option(SDL_ARMNEON             "Use NEON assembly blitters on ARM" OFF "SDL_ASSEMBLY;SDL_CPU_ARM32" OFF)
@@ -420,7 +433,8 @@ set_option(SDL_DIRECTFB            "Use DirectFB video driver" OFF)
 dep_option(SDL_DIRECTFB_SHARED     "Dynamically load directfb support" ON "SDL_DIRECTFB" OFF)
 set_option(SDL_DUMMYVIDEO          "Use dummy video driver" ON)
 dep_option(SDL_IBUS                "Enable IBus support" ON ${UNIX_SYS} OFF)
-set_option(SDL_SYSTEM_ICONV        "Use iconv() from system-installed libraries" ON)
+set_option(SDL_SYSTEM_ICONV        "Use iconv() from system-installed libraries" ${SDL_SYSTEM_ICONV_DEFAULT})
+set_option(SDL_LIBICONV            "Prefer iconv() from libiconv, if available, over libc version" OFF)
 set_option(SDL_OPENGL              "Include OpenGL support" ON)
 set_option(SDL_OPENGLES            "Include OpenGL ES support" ON)
 set_option(SDL_PTHREADS            "Use POSIX threads for multi-threading" ${SDL_PTHREADS_ENABLED_BY_DEFAULT})
@@ -450,17 +464,19 @@ set_option(SDL_RPATH               "Use an rpath when linking SDL" ${UNIX_SYS})
 set_option(SDL_CLOCK_GETTIME       "Use clock_gettime() instead of gettimeofday()" ${SDL_CLOCK_GETTIME_ENABLED_BY_DEFAULT})
 set_option(SDL_X11                 "Use X11 video driver" ${UNIX_SYS})
 dep_option(SDL_X11_SHARED          "Dynamically load X11 support" ON "SDL_X11" OFF)
-set(SDL_X11_OPTIONS Xcursor Xdbe XInput Xfixes Xrandr Xscrnsaver XShape)
-foreach(_SUB ${SDL_X11_OPTIONS})
-  string(TOUPPER "SDL_X11_${_SUB}" _OPT)
-  dep_option(${_OPT}               "Enable ${_SUB} support" ON "SDL_X11" OFF)
-endforeach()
+dep_option(SDL_X11_XCURSOR         "Enable Xcursor support" ON SDL_X11 OFF)
+dep_option(SDL_X11_XDBE            "Enable Xdbe support" ON SDL_X11 OFF)
+dep_option(SDL_X11_XINPUT          "Enable XInput support" ON SDL_X11 OFF)
+dep_option(SDL_X11_XFIXES          "Enable Xfixes support" ON SDL_X11 OFF)
+dep_option(SDL_X11_XRANDR          "Enable Xrandr support" "${SDL_X11_XRANDR_DEFAULT}" SDL_X11 OFF)
+dep_option(SDL_X11_XSCRNSAVER      "Enable Xscrnsaver support" ON SDL_X11 OFF)
+dep_option(SDL_X11_XSHAPE          "Enable XShape support" ON SDL_X11 OFF)
 set_option(SDL_WAYLAND             "Use Wayland video driver" ${UNIX_SYS})
 dep_option(SDL_WAYLAND_SHARED      "Dynamically load Wayland support" ON "SDL_WAYLAND" OFF)
 dep_option(SDL_WAYLAND_LIBDECOR    "Use client-side window decorations on Wayland" ON "SDL_WAYLAND" OFF)
 dep_option(SDL_WAYLAND_LIBDECOR_SHARED     "Dynamically load libdecor support" ON "SDL_WAYLAND_LIBDECOR;SDL_WAYLAND_SHARED" OFF)
 dep_option(SDL_WAYLAND_QT_TOUCH    "QtWayland server support for Wayland video driver" ON "SDL_WAYLAND" OFF)
-set_option(SDL_RPI                 "Use Raspberry Pi video driver" ${UNIX_SYS})
+set_option(SDL_RPI                 "Use Raspberry Pi 0-3 video driver" ${UNIX_SYS})
 set_option(SDL_COCOA               "Use Cocoa video driver" ${APPLE})
 set_option(SDL_DIRECTX             "Use DirectX for Windows audio/video" ${WINDOWS})
 set_option(SDL_XINPUT              "Use Xinput for Windows" ${WINDOWS})
@@ -585,11 +601,50 @@ if(USE_GCC OR USE_CLANG OR USE_INTELCC OR USE_QCC)
     endif()
   endif()
 
+  check_c_compiler_flag(-Wundef HAVE_GCC_WUNDEF)
+  if(HAVE_GCC_WUNDEF)
+    list(APPEND EXTRA_CFLAGS "-Wundef")
+  endif()
+
   check_c_compiler_flag(-fno-strict-aliasing HAVE_GCC_NO_STRICT_ALIASING)
   if(HAVE_GCC_NO_STRICT_ALIASING)
     list(APPEND EXTRA_CFLAGS "-fno-strict-aliasing")
   endif()
 
+  check_c_compiler_flag(-Wdocumentation HAVE_GCC_WDOCUMENTATION)
+  if(HAVE_GCC_WDOCUMENTATION)
+    if(SDL_WERROR)
+      check_c_compiler_flag(-Werror=documentation HAVE_GCC_WERROR_DOCUMENTATION)
+      if(HAVE_GCC_WERROR_DOCUMENTATION)
+        list(APPEND EXTRA_CFLAGS "-Werror=documentation")
+      endif()
+    endif()
+     list(APPEND EXTRA_CFLAGS "-Wdocumentation")
+  endif()
+
+  check_c_compiler_flag(-Wdocumentation-unknown-command HAVE_GCC_WDOCUMENTATION_UNKNOWN_COMMAND)
+  if(HAVE_GCC_WDOCUMENTATION_UNKNOWN_COMMAND)
+    if(SDL_WERROR)
+      check_c_compiler_flag(-Werror=documentation-unknown-command HAVE_GCC_WERROR_DOCUMENTATION_UNKNOWN_COMMAND)
+      if(HAVE_GCC_WERROR_DOCUMENTATION_UNKNOWN_COMMAND)
+        list(APPEND EXTRA_CFLAGS "-Werror=documentation-unknown-command")
+      endif()
+    endif()
+    list(APPEND EXTRA_CFLAGS "-Wdocumentation-unknown-command")
+  endif()
+
+  check_c_compiler_flag(-fcomment-block-commands=threadsafety HAVE_GCC_COMMENT_BLOCK_COMMANDS)
+  if(HAVE_GCC_COMMENT_BLOCK_COMMANDS)
+    list(APPEND EXTRA_CFLAGS "-fcomment-block-commands=threadsafety")
+    list(APPEND EXTRA_CFLAGS "-fcomment-block-commands=deprecated")
+  else()
+    check_c_compiler_flag(/clang:-fcomment-block-commands=threadsafety HAVE_CLANG_COMMENT_BLOCK_COMMANDS)
+    if(HAVE_CLANG_COMMENT_BLOCK_COMMANDS)
+      list(APPEND EXTRA_CFLAGS "/clang:-fcomment-block-commands=threadsafety")
+      list(APPEND EXTRA_CFLAGS "/clang:-fcomment-block-commands=deprecated")
+    endif()
+  endif()
+
   check_c_compiler_flag(-Wdeclaration-after-statement HAVE_GCC_WDECLARATION_AFTER_STATEMENT)
   if(HAVE_GCC_WDECLARATION_AFTER_STATEMENT)
     if(SDL_WERROR)
@@ -866,7 +921,7 @@ if(SDL_ASSEMBLY)
 
     if(SDL_LSX)
       cmake_push_check_state()
-      list(APPEND CMAKE_REQUIRED_FLAGS "-mlsx")
+      set(CMAKE_REQUIRED_FLAGS "-mlsx")
       check_c_source_compiles("
           #ifndef __loongarch_sx
           #error Assembler CPP flag not enabled
@@ -881,22 +936,6 @@ if(SDL_ASSEMBLY)
       endif()
     endif()
 
-    if(SDL_LASX)
-      cmake_push_check_state()
-      list(APPEND CMAKE_REQUIRED_FLAGS "-mlasx")
-      check_c_source_compiles("
-          #ifndef __loongarch_asx
-          #error Assembler CPP flag not enabled
-          #endif
-          int main(int argc, char **argv) { return 0; }" CPU_SUPPORTS_LASX)
-      check_include_file("lasxintrin.h" HAVE_LASXINTRIN_H)
-      cmake_pop_check_state()
-      if(CPU_SUPPORTS_LASX AND HAVE_LASXINTRIN_H)
-        list(APPEND EXTRA_CFLAGS "-mlasx")
-        set(HAVE_LASX TRUE)
-      endif()
-    endif()
-
     if(SDL_ARMSIMD)
       set(ORIG_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
       set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -x assembler-with-cpp")
@@ -1026,15 +1065,11 @@ if(SDL_LIBC)
         sys/types.h
         wchar.h
     )
-    if(NOT EMSCRIPTEN)
-      list(APPEND headers_to_check libunwind.h)
-    endif()
     foreach(_HEADER ${headers_to_check})
       string(TOUPPER "HAVE_${_HEADER}" _UPPER)
       string(REGEX REPLACE "[./]" "_" _HAVE_H ${_UPPER})
       check_include_file("${_HEADER}" ${_HAVE_H})
     endforeach()
-    check_include_file(linux/input.h HAVE_LINUX_INPUT_H)
 
     set(STDC_HEADER_NAMES "stddef.h;stdarg.h;stdlib.h;string.h;stdio.h;wchar.h;float.h")
     check_include_files("${STDC_HEADER_NAMES}" STDC_HEADERS)
@@ -1066,6 +1101,8 @@ if(SDL_LIBC)
     check_symbol_exists(getauxval "sys/auxv.h" HAVE_GETAUXVAL)
     check_symbol_exists(elf_aux_info "sys/auxv.h" HAVE_ELF_AUX_INFO)
     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_library_exists(m pow "" HAVE_LIBM)
     if(HAVE_LIBM)
@@ -1088,16 +1125,31 @@ if(SDL_LIBC)
     endif()
 
     if(SDL_SYSTEM_ICONV)
-      check_library_exists(iconv iconv_open "" HAVE_LIBICONV)
-      if(HAVE_LIBICONV)
-        list(APPEND EXTRA_LIBS iconv)
+      check_c_source_compiles("
+        #define LIBICONV_PLUG 1 /* in case libiconv header is in include path */
+        #include <stddef.h>
+        #include <iconv.h>
+        int main(int argc, char **argv) {
+            return !iconv_open(NULL,NULL);
+        }" ICONV_IN_LIBC)
+
+      cmake_push_check_state()
+      list(APPEND CMAKE_REQUIRED_LIBRARIES iconv)
+      check_c_source_compiles("
+        #include <stddef.h>
+        #include <iconv.h>
+        int main(int argc, char **argv) {
+            return !iconv_open(NULL,NULL);
+        }" ICONV_IN_LIBICONV)
+      cmake_pop_check_state()
+
+      if(ICONV_IN_LIBC OR ICONV_IN_LIBICONV)
         set(HAVE_ICONV 1)
         set(HAVE_SYSTEM_ICONV TRUE)
-      else()
-        check_library_exists(c iconv_open "" HAVE_BUILTIN_ICONV)
-        if(HAVE_BUILTIN_ICONV)
-          set(HAVE_ICONV 1)
-          set(HAVE_SYSTEM_ICONV TRUE)
+        if(ICONV_IN_LIBICONV AND (SDL_LIBICONV OR (NOT ICONV_IN_LIBC)))
+          set(SDL_USE_LIBICONV 1)
+          set(HAVE_LIBICONV TRUE)
+          list(APPEND EXTRA_LIBS iconv)
         endif()
       endif()
     endif()
@@ -1408,10 +1460,7 @@ elseif(EMSCRIPTEN)
   endif()
 
   CheckPTHREAD()
-
-  if(HAVE_LIBUNWIND_H)
-    list(APPEND EXTRA_TEST_LIBS unwind)
-  endif()
+  CheckLibUnwind()
 
 elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
   if(SDL_AUDIO)
@@ -1479,7 +1528,7 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
         #ifndef EVIOCGNAME
         #error EVIOCGNAME() ioctl not available
         #endif
-        int main(int argc, char** argv) { return 0; }" HAVE_INPUT_EVENTS)
+        int main(int argc, char** argv) { return 0; }" HAVE_LINUX_INPUT_H)
 
     if(LINUX)
       check_c_source_compiles("
@@ -1515,11 +1564,11 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
           }" HAVE_INPUT_WSCONS)
     endif()
 
-    if(HAVE_INPUT_EVENTS)
+    if(HAVE_LINUX_INPUT_H)
       set(SDL_INPUT_LINUXEV 1)
     endif()
 
-    if(SDL_HAPTIC AND HAVE_INPUT_EVENTS)
+    if(SDL_HAPTIC AND HAVE_LINUX_INPUT_H)
       set(SDL_HAPTIC_LINUX 1)
       file(GLOB HAPTIC_SOURCES ${SDL2_SOURCE_DIR}/src/haptic/linux/*.c)
       list(APPEND SOURCE_FILES ${HAPTIC_SOURCES})
@@ -1582,15 +1631,8 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
         endif()
       endif()
 
-      if(HAVE_LIBUNWIND_H)
-        # We've already found the header, so link the lib if present.
-        # NB: This .pc file is not present on FreeBSD where the implicitly
-        # linked base system libgcc_s includes all libunwind ABI.
-        pkg_search_module(UNWIND libunwind)
-        pkg_search_module(UNWIND_GENERIC libunwind-generic)
-        list(APPEND EXTRA_TEST_LIBS ${UNWIND_LIBRARIES} ${UNWIND_GENERIC_LIBRARIES})
-      endif()
     endif()
+    CheckLibUnwind()
 
     if(HAVE_DBUS_DBUS_H)
       list(APPEND SOURCE_FILES "${SDL2_SOURCE_DIR}/src/core/linux/SDL_dbus.c")
@@ -1612,7 +1654,7 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
       list(APPEND SOURCE_FILES "${SDL2_SOURCE_DIR}/src/core/linux/SDL_udev.c")
     endif()
 
-    if(HAVE_INPUT_EVENTS)
+    if(HAVE_LINUX_INPUT_H)
       list(APPEND SOURCE_FILES "${SDL2_SOURCE_DIR}/src/core/linux/SDL_evdev.c")
       list(APPEND SOURCE_FILES "${SDL2_SOURCE_DIR}/src/core/linux/SDL_evdev_kbd.c")
     endif()
@@ -1621,6 +1663,11 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
       list(APPEND SOURCE_FILES "${SDL2_SOURCE_DIR}/src/core/freebsd/SDL_evdev_kbd_freebsd.c")
     endif()
 
+    if(HAVE_INPUT_WSCONS)
+      list(APPEND SOURCE_FILES "${SDL2_SOURCE_DIR}/src/core/openbsd/SDL_wscons_kbd.c")
+      list(APPEND SOURCE_FILES "${SDL2_SOURCE_DIR}/src/core/openbsd/SDL_wscons_mouse.c")
+    endif()
+
     # Always compiled for Linux, unconditionally:
     list(APPEND SOURCE_FILES "${SDL2_SOURCE_DIR}/src/core/linux/SDL_evdev_capabilities.c")
     list(APPEND SOURCE_FILES "${SDL2_SOURCE_DIR}/src/core/linux/SDL_threadprio.c")
@@ -1637,7 +1684,7 @@ elseif(UNIX AND NOT APPLE AND NOT RISCOS AND NOT HAIKU)
     if(FREEBSD OR NETBSD OR OPENBSD OR BSDI)
       CheckUSBHID()
     endif()
-    if(LINUX AND HAVE_LINUX_INPUT_H AND NOT ANDROID)
+    if((LINUX OR FREEBSD) AND HAVE_LINUX_INPUT_H AND NOT ANDROID)
       set(SDL_JOYSTICK_LINUX 1)
       file(GLOB JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/linux/*.c ${SDL2_SOURCE_DIR}/src/joystick/steam/*.c)
       list(APPEND SOURCE_FILES ${JOYSTICK_SOURCES})
@@ -1736,18 +1783,11 @@ elseif(WINDOWS)
   list(APPEND SOURCE_FILES ${CORE_SOURCES})
 
   if(WINDOWS_STORE)
+    enable_language(CXX)
     file(GLOB WINRT_SOURCE_FILES ${SDL2_SOURCE_DIR}/src/core/winrt/*.c ${SDL2_SOURCE_DIR}/src/core/winrt/*.cpp)
     list(APPEND SOURCE_FILES ${WINRT_SOURCE_FILES})
   endif()
 
-  if(MSVC AND NOT SDL_LIBC)
-    # Prevent codegen that would use the VC runtime libraries.
-    set_property(DIRECTORY . APPEND PROPERTY COMPILE_OPTIONS "/GS-;/Gs1048576")
-    if(NOT ARCH_64 AND NOT CMAKE_GENERATOR_PLATFORM STREQUAL "ARM")
-      set_property(DIRECTORY . APPEND PROPERTY COMPILE_OPTIONS "/arch:SSE")
-    endif()
-  endif()
-
   if(SDL_MISC)
     if(WINDOWS_STORE)
       file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/winrt/*.cpp)
@@ -1773,13 +1813,11 @@ elseif(WINDOWS)
     check_include_file(d3d9.h HAVE_D3D_H)
     check_include_file(d3d11_1.h HAVE_D3D11_H)
     check_c_source_compiles("
-      #include <winsdkver.h>
-      #include <sdkddkver.h>
       #include <d3d12.h>
+      #include <d3d12sdklayers.h>
       ID3D12Device1 *device;
-      #if WDK_NTDDI_VERSION > 0x0A000008
-      int main(int argc, char **argv) { return 0; }
-      #endif" HAVE_D3D12_H)
+      int main(int argc, char **argv) {return 0; }
+      " HAVE_D3D12_H)
     check_include_file(ddraw.h HAVE_DDRAW_H)
     check_include_file(dsound.h HAVE_DSOUND_H)
     check_include_file(dinput.h HAVE_DINPUT_H)
@@ -1791,8 +1829,10 @@ elseif(WINDOWS)
       set(HAVE_DIRECTX TRUE)
       if(NOT MINGW AND NOT USE_WINSDK_DIRECTX)
       # TODO: change $ENV{DXSDL_DIR} to get the path from the include checks
-        target_link_directories(sdl-build-options INTERFACE "$$ENV{DXSDK_DIR}\\lib\\${PROCESSOR_ARCH}")
-        target_include_directories(sdl-build-options INTERFACE "$ENV{DXSDK_DIR}\\Include")
+        file(TO_CMAKE_PATH "$ENV{DXSDK_DIR}\\lib\\${PROCESSOR_ARCH}" SDL2_TMP_DXSDK_LIB_DIR)
+        target_link_directories(sdl-build-options INTERFACE "${SDL2_TMP_DXSDK_LIB_DIR}")
+        file(TO_CMAKE_PATH "$ENV{DXSDK_DIR}\\Include" SDL2_TMP_DXSDK_INCLUDE_DIR)
+        target_include_directories(sdl-build-options INTERFACE "${SDL2_TMP_DXSDK_INCLUDE_DIR}")
       endif()
     endif()
     set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS})
@@ -1804,16 +1844,6 @@ elseif(WINDOWS)
       #include <windows.h>
       #include <xinput.h>
       int main(int argc, char **argv) { return 0; }" HAVE_XINPUT_H)
-    check_c_source_compiles("
-      #include <windows.h>
-      #include <xinput.h>
-      XINPUT_GAMEPAD_EX x1;
-      int main(int argc, char **argv) { return 0; }" HAVE_XINPUT_GAMEPAD_EX)
-    check_c_source_compiles("
-      #include <windows.h>
-      #include <xinput.h>
-      XINPUT_STATE_EX s1;
-      int main(int argc, char **argv) { return 0; }" HAVE_XINPUT_STATE_EX)
     check_c_source_compiles("
       #define COBJMACROS
       #include <windows.gaming.input.h>
@@ -2037,6 +2067,7 @@ elseif(WINDOWS)
     endif()
   endif()
 
+  enable_language(RC)
   file(GLOB VERSION_SOURCES ${SDL2_SOURCE_DIR}/src/main/windows/*.rc)
   file(GLOB SDLMAIN_SOURCES ${SDL2_SOURCE_DIR}/src/main/windows/*.c)
   if(MINGW OR CYGWIN)
@@ -2054,7 +2085,7 @@ elseif(APPLE)
   # !!! FIXME: we need Carbon for some very old API calls in
   # !!! FIXME:  src/video/cocoa/SDL_cocoakeyboard.c, but we should figure out
   # !!! FIXME:  how to dump those.
-  if(DARWIN OR MACOSX)
+  if(MACOS)
     set(SDL_FRAMEWORK_COCOA 1)
     set(SDL_FRAMEWORK_CARBON 1)
   endif()
@@ -2068,12 +2099,12 @@ elseif(APPLE)
     set(HAVE_SDL_FILE TRUE)
   endif()
 
-  if(IOS OR TVOS)
+  if(IOS OR TVOS OR VISIONOS OR WATCHOS)
     file(GLOB SDLMAIN_SOURCES ${SDL2_SOURCE_DIR}/src/main/uikit/*.c)
   endif()
 
   if(SDL_MISC)
-    if(IOS OR TVOS)
+    if(IOS OR TVOS OR VISIONOS OR WATCHOS)
       file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/ios/*.m)
     else()
       file(GLOB MISC_SOURCES ${SDL2_SOURCE_DIR}/src/misc/macosx/*.m)
@@ -2098,10 +2129,10 @@ elseif(APPLE)
 
   if(SDL_JOYSTICK)
     file(GLOB MFI_JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/iphoneos/*.m)
-    if(IOS OR TVOS)
+    if(IOS OR TVOS OR VISIONOS OR WATCHOS)
       file(GLOB JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/steam/*.c)
       set(SDL_JOYSTICK_MFI 1)
-      if(IOS)
+      if(IOS OR VISIONOS OR WATCHOS)
         set(SDL_FRAMEWORK_COREMOTION 1)
       endif()
       set(SDL_FRAMEWORK_GAMECONTROLLER 1)
@@ -2142,7 +2173,7 @@ elseif(APPLE)
   endif()
 
   if(SDL_HAPTIC)
-    if (IOS OR TVOS)
+    if(IOS OR TVOS OR VISIONOS OR WATCHOS)
       file(GLOB HAPTIC_SOURCES ${SDL2_SOURCE_DIR}/src/haptic/dummy/*.c)
       set(SDL_HAPTIC_DUMMY 1)
     else()
@@ -2156,7 +2187,7 @@ elseif(APPLE)
   endif()
 
   if(SDL_POWER)
-    if (IOS OR TVOS)
+    if(IOS OR TVOS OR VISIONOS OR WATCHOS)
       file(GLOB POWER_SOURCES ${SDL2_SOURCE_DIR}/src/power/uikit/*.m)
       set(SDL_POWER_UIKIT 1)
     else()
@@ -2189,7 +2220,7 @@ elseif(APPLE)
   endif()
 
   if(SDL_SENSOR)
-    if(IOS)
+    if(IOS OR VISIONOS OR WATCHOS)
       set(SDL_SENSOR_COREMOTION 1)
       set(HAVE_SDL_SENSORS TRUE)
       file(GLOB SENSOR_SOURCES ${SDL2_SOURCE_DIR}/src/sensor/coremotion/*.m)
@@ -2199,7 +2230,7 @@ elseif(APPLE)
 
   # iOS hack needed - http://code.google.com/p/ios-cmake/ ?
   if(SDL_VIDEO)
-    if (IOS OR TVOS)
+    if(IOS OR TVOS OR VISIONOS OR WATCHOS)
       set(SDL_VIDEO_DRIVER_UIKIT 1)
       set(SDL_FRAMEWORK_COREGRAPHICS 1)
       set(SDL_FRAMEWORK_QUARTZCORE 1)
@@ -2220,7 +2251,7 @@ elseif(APPLE)
     endif()
 
     if(SDL_OPENGLES)
-      if(IOS OR TVOS)
+      if(IOS OR TVOS OR VISIONOS OR WATCHOS)
         set(SDL_FRAMEWORK_OPENGLES 1)
         set(SDL_VIDEO_OPENGL_ES 1)
         set(SDL_VIDEO_RENDER_OGL_ES 1)
@@ -2263,73 +2294,96 @@ elseif(APPLE)
     endif()
   endif()
 
+  # Minimum version for $<LINK_LIBRARY:feature,library-list>
+  cmake_minimum_required(VERSION 3.24)
+
   # Actually load the frameworks at the end so we don't duplicate include.
   if(SDL_FRAMEWORK_COREVIDEO)
-    list(APPEND EXTRA_LDFLAGS "-Wl,-framework,CoreVideo")
+    list(APPEND PKGCONFIG_LDFLAGS "-Wl,-framework,CoreVideo")
+    list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:FRAMEWORK,CoreVideo>")
   endif()
   if(SDL_FRAMEWORK_COCOA)
-    list(APPEND EXTRA_LDFLAGS "-Wl,-framework,Cocoa")
+    list(APPEND PKGCONFIG_LDFLAGS "-Wl,-framework,Cocoa")
+    list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:FRAMEWORK,Cocoa>")
   endif()
   if(SDL_FRAMEWORK_IOKIT)
-    list(APPEND EXTRA_LDFLAGS "-Wl,-framework,IOKit")
+    list(APPEND PKGCONFIG_LDFLAGS "-Wl,-framework,IOKit")
+    list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:FRAMEWORK,IOKit>")
   endif()
   if(SDL_FRAMEWORK_FF)
-    list(APPEND EXTRA_LDFLAGS "-Wl,-framework,ForceFeedback")
+    list(APPEND PKGCONFIG_LDFLAGS "-Wl,-framework,ForceFeedback")
+    list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:FRAMEWORK,ForceFeedback>")
   endif()
   if(SDL_FRAMEWORK_CARBON)
-    list(APPEND EXTRA_LDFLAGS "-Wl,-framework,Carbon")
+    list(APPEND PKGCONFIG_LDFLAGS "-Wl,-framework,Carbon")
+    list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:FRAMEWORK,Carbon>")
   endif()
   if(SDL_FRAMEWORK_COREAUDIO)
-    list(APPEND EXTRA_LDFLAGS "-Wl,-framework,CoreAudio")
+    list(APPEND PKGCONFIG_LDFLAGS "-Wl,-framework,CoreAudio")
+    list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:FRAMEWORK,CoreAudio>")
   endif()
   if(SDL_FRAMEWORK_AUDIOTOOLBOX)
-    list(APPEND EXTRA_LDFLAGS "-Wl,-framework,AudioToolbox")
+    list(APPEND PKGCONFIG_LDFLAGS "-Wl,-framework,AudioToolbox")
+    list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:FRAMEWORK,AudioToolbox>")
   endif()
   if(SDL_FRAMEWORK_AVFOUNDATION)
-    list(APPEND EXTRA_LDFLAGS "-Wl,-framework,AVFoundation")
+    list(APPEND PKGCONFIG_LDFLAGS "-Wl,-framework,AVFoundation")
+    list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:FRAMEWORK,AVFoundation>")
   endif()
   if(SDL_FRAMEWORK_COREBLUETOOTH)
-    list(APPEND EXTRA_LDFLAGS "-Wl,-framework,CoreBluetooth")
+    list(APPEND PKGCONFIG_LDFLAGS "-Wl,-framework,CoreBluetooth")
+    list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:FRAMEWORK,CoreBluetooth>")
   endif()
   if(SDL_FRAMEWORK_COREGRAPHICS)
-    list(APPEND EXTRA_LDFLAGS "-Wl,-framework,CoreGraphics")
+    list(APPEND PKGCONFIG_LDFLAGS "-Wl,-framework,CoreGraphics")
+    list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:FRAMEWORK,CoreGraphics>")
   endif()
   if(SDL_FRAMEWORK_COREMOTION)
-    list(APPEND EXTRA_LDFLAGS "-Wl,-framework,CoreMotion")
+    list(APPEND PKGCONFIG_LDFLAGS "-Wl,-framework,CoreMotion")
+    list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:FRAMEWORK,Coremotion>")
   endif()
   if(SDL_FRAMEWORK_FOUNDATION)
-    list(APPEND EXTRA_LDFLAGS "-Wl,-framework,Foundation")
+    list(APPEND PKGCONFIG_LDFLAGS "-Wl,-framework,Foundation")
+    list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:FRAMEWORK,Foundation>")
   endif()
   if(SDL_FRAMEWORK_GAMECONTROLLER)
     find_library(GAMECONTROLLER GameController)
     if(GAMECONTROLLER)
-      list(APPEND EXTRA_LDFLAGS "-Wl,-weak_framework,GameController")
+      list(APPEND PKGCONFIG_LDFLAGS "-Wl,-weak_framework,GameController")
+      list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:WEAK_FRAMEWORK,GameController>")
     endif()
   endif()
   if(SDL_FRAMEWORK_METAL)
-    if(IOS OR TVOS)
-      list(APPEND EXTRA_LDFLAGS "-Wl,-framework,Metal")
+    if(IOS OR TVOS OR VISIONOS OR WATCHOS)
+      list(APPEND PKGCONFIG_LDFLAGS "-Wl,-framework,Metal")
+      list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:FRAMEWORK,Metal>")
     else()
-      list(APPEND EXTRA_LDFLAGS "-Wl,-weak_framework,Metal")
+      list(APPEND PKGCONFIG_LDFLAGS "-Wl,-weak_framework,Metal")
+      list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:WEAK_FRAMEWORK,Metal>")
     endif()
   endif()
   if(SDL_FRAMEWORK_OPENGLES)
-    list(APPEND EXTRA_LDFLAGS "-Wl,-framework,OpenGLES")
+    list(APPEND PKGCONFIG_LDFLAGS "-Wl,-framework,OpenGLES")
+    list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:FRAMEWORK,OpenGLES>")
   endif()
   if(SDL_FRAMEWORK_QUARTZCORE)
-    if(IOS OR TVOS)
-      list(APPEND EXTRA_LDFLAGS "-Wl,-framework,QuartzCore")
+    if(IOS OR TVOS OR VISIONOS OR WATCHOS)
+      list(APPEND PKGCONFIG_LDFLAGS "-Wl,-framework,QuartzCore")
+      list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:FRAMEWORK,QuartzCore>")
     else()
-      list(APPEND EXTRA_LDFLAGS "-Wl,-weak_framework,QuartzCore")
+      list(APPEND PKGCONFIG_LDFLAGS "-Wl,-weak_framework,QuartzCore")
+      list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:WEAK_FRAMEWORK,QuartzCore>")
     endif()
   endif()
   if(SDL_FRAMEWORK_UIKIT)
-    list(APPEND EXTRA_LDFLAGS "-Wl,-framework,UIKit")
+    list(APPEND PKGCONFIG_LDFLAGS "-Wl,-framework,UIKit")
+    list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:FRAMEWORK,UIKit>")
   endif()
   if(SDL_FRAMEWORK_COREHAPTICS)
     find_library(COREHAPTICS CoreHaptics)
     if(COREHAPTICS)
-      list(APPEND EXTRA_LDFLAGS "-Wl,-weak_framework,CoreHaptics")
+      list(APPEND PKGCONFIG_LDFLAGS "-Wl,-weak_framework,CoreHaptics")
+      list(APPEND CMAKE_LIBS "$<LINK_LIBRARY:WEAK_FRAMEWORK,CoreHaptics>")
     endif()
   endif()
 
@@ -2489,7 +2543,7 @@ elseif(VITA)
       ${SDL2_SOURCE_DIR}/src/thread/vita/SDL_sysmutex.c
       ${SDL2_SOURCE_DIR}/src/thread/vita/SDL_syssem.c
       ${SDL2_SOURCE_DIR}/src/thread/vita/SDL_systhread.c
-      ${SDL2_SOURCE_DIR}/src/thread/vita/SDL_syscond.c
+      ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_syscond.c
       ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_systls.c)
     set(HAVE_SDL_THREADS TRUE)
   endif()
@@ -2641,10 +2695,18 @@ elseif(PSP)
   endif()
   if(SDL_THREADS)
     set(SDL_THREAD_PSP 1)
-    file(GLOB PSP_THREAD_SOURCES ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_systls.c ${SDL2_SOURCE_DIR}/src/thread/psp/*.c)
+    file(GLOB PSP_THREAD_SOURCES
+      ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_systls.c
+      ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_syscond.c
+      ${SDL2_SOURCE_DIR}/src/thread/psp/*.c)
     list(APPEND SOURCE_FILES ${PSP_THREAD_SOURCES})
     set(HAVE_SDL_THREADS TRUE)
   endif()
+  if(SDL_LOCALE)
+    file(GLOB PSP_LOCALE_SOURCES ${SDL2_SOURCE_DIR}/src/locale/psp/*.c)
+    list(APPEND SOURCE_FILES ${PSP_LOCALE_SOURCES})
+    set(HAVE_SDL_LOCALE TRUE)
+  endif()
   if(SDL_TIMERS)
     set(SDL_TIMER_PSP 1)
     file(GLOB PSP_TIMER_SOURCES ${SDL2_SOURCE_DIR}/src/timer/psp/*.c)
@@ -2677,7 +2739,6 @@ elseif(PSP)
   endif()
 
 elseif(PS2)
-  list(APPEND EXTRA_CFLAGS "-DPS2" "-D__PS2__" "-I$ENV{PS2SDK}/ports/include" "-I$ENV{PS2DEV}/gsKit/include")
 
   file(GLOB PS2_MAIN_SOURCES ${SDL2_SOURCE_DIR}/src/main/ps2/*.c)
   set(SDLMAIN_SOURCES ${SDLMAIN_SOURCES} ${PS2_MAIN_SOURCES})
@@ -2702,7 +2763,11 @@ elseif(PS2)
   endif()
   if(SDL_THREADS)
     set(SDL_THREAD_PS2 1)
-    file(GLOB PS2_THREAD_SOURCES ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_systls.c ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_sysmutex.c ${SDL2_SOURCE_DIR}/src/thread/ps2/*.c)
+    file(GLOB PS2_THREAD_SOURCES
+      ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_systls.c
+      ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_sysmutex.c
+      ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_syscond.c
+      ${SDL2_SOURCE_DIR}/src/thread/ps2/*.c)
     list(APPEND SOURCE_FILES ${PS2_THREAD_SOURCES})
     set(HAVE_SDL_THREADS TRUE)
   endif()
@@ -2833,7 +2898,9 @@ elseif(N3DS)
   if(SDL_THREADS)
     set(SDL_THREAD_N3DS 1)
     file(GLOB N3DS_THREAD_SOURCES ${SDL2_SOURCE_DIR}/src/thread/n3ds/*.c)
-    list(APPEND SOURCE_FILES ${N3DS_THREAD_SOURCES} ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_systls.c)
+    list(APPEND SOURCE_FILES ${N3DS_THREAD_SOURCES}
+      ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_systls.c
+      ${SDL2_SOURCE_DIR}/src/thread/generic/SDL_syscond.c)
     set(HAVE_SDL_THREADS TRUE)
   endif()
 
@@ -3021,10 +3088,14 @@ endif()
 listtostr(EXTRA_CFLAGS _EXTRA_CFLAGS)
 set(EXTRA_CFLAGS ${_EXTRA_CFLAGS})
 
+if(USE_GCC OR USE_CLANG)
+  string(REGEX REPLACE "(^| )-I" "\\1 -isystem" EXTRA_CFLAGS "${EXTRA_CFLAGS}")
+endif()
+
 # Compat helpers for the configuration files
 
-if(EXISTS "${PROJECT_SOURCE_DIR}/VERSION.txt")
-  file(READ "${PROJECT_SOURCE_DIR}/VERSION.txt" SDL_SOURCE_VERSION)
+if(EXISTS "${PROJECT_SOURCE_DIR}/REVISION.txt")
+  file(READ "${PROJECT_SOURCE_DIR}/REVISION.txt" SDL_SOURCE_VERSION)
   string(STRIP "${SDL_SOURCE_VERSION}" SDL_SOURCE_VERSION)
 endif()
 
@@ -3083,9 +3154,17 @@ else()
   set(sdl_static_libname "SDL2")
 endif()
 
-set(prefix ${CMAKE_INSTALL_PREFIX})
+# CMAKE_PREFIX_PATH and CMAKE_INSTALL_FULL_BINDIR can be a non-absolute path
+# when a master-project does e.g. `set(CMAKE_INSTALL_PREFIX "libs/SDL2" CACHE PATH "prefix" FORCE)`.
+if(NOT IS_ABSOLUTE "${CMAKE_INSTALL_PREFIX}")
+  set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_PREFIX}")
+endif()
+if(NOT IS_ABSOLUTE "${CMAKE_INSTALL_FULL_BINDIR}")
+  set(CMAKE_INSTALL_FULL_BINDIR "${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_FULL_BINDIR}")
+endif()
 file(RELATIVE_PATH bin_prefix_relpath "${CMAKE_INSTALL_FULL_BINDIR}" "${CMAKE_INSTALL_PREFIX}")
 
+set(prefix ${CMAKE_INSTALL_PREFIX})
 set(exec_prefix "\${prefix}")
 set(libdir "\${exec_prefix}/${CMAKE_INSTALL_LIBDIR}")
 set(bindir "\${exec_prefix}/${CMAKE_INSTALL_BINDIR}")
@@ -3110,7 +3189,7 @@ endif()
 
 # Clean up the different lists
 listtostr(EXTRA_LIBS _EXTRA_LIBS "-l")
-set(SDL_STATIC_LIBS ${SDL_LIBS} ${EXTRA_LDFLAGS} ${_EXTRA_LIBS})
+set(SDL_STATIC_LIBS ${EXTRA_LDFLAGS} ${_EXTRA_LIBS} ${PKGCONFIG_LDFLAGS})
 list(REMOVE_DUPLICATES SDL_STATIC_LIBS)
 listtostr(SDL_STATIC_LIBS _SDL_STATIC_LIBS)
 set(SDL_STATIC_LIBS ${_SDL_STATIC_LIBS})
@@ -3144,9 +3223,11 @@ macro(check_add_debug_flag FLAG SUFFIX)
         set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${FLAG}")
     endif()
 
-    check_cxx_compiler_flag(${FLAG} HAS_CXX_${SUFFIX})
-    if (HAS_CXX_${SUFFIX})
-        set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAG}")
+    if(CMAKE_CXX_COMPILER)
+      check_cxx_compiler_flag(${FLAG} HAS_CXX_${SUFFIX})
+      if (HAS_CXX_${SUFFIX})
+          set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAG}")
+      endif()
     endif()
 endmacro()
 
@@ -3165,18 +3246,20 @@ macro(asan_check_add_debug_flag2 ASAN_FLAG)
 
     set (STORED_REQLIBS ${CMAKE_REQUIRED_LIBRARIES})
     set (CMAKE_REQUIRED_LIBRARIES "${FLAG};asan")
-    check_c_compiler_flag (${FLAG} HAS_C_FLAG_${ASAN_FLAG})
-    check_cxx_compiler_flag (${FLAG} HAS_CXX_FLAG_${ASAN_FLAG})
-    set (CMAKE_REQUIRED_LIBRARIES ${STORED_REQLIBS})
 
+    check_c_compiler_flag (${FLAG} HAS_C_FLAG_${ASAN_FLAG})
     if (HAS_C_FLAG_${ASAN_FLAG})
         set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${FLAG}")
     endif()
 
-    if (HAS_CXX_${ASAN_FLAG})
-        set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAG}")
+    if(CMAKE_CXX_COMPILER)
+      check_cxx_compiler_flag (${FLAG} HAS_CXX_FLAG_${ASAN_FLAG})
+      if (HAS_CXX_${ASAN_FLAG})
+          set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAG}")
+      endif()
     endif()
 
+    set (CMAKE_REQUIRED_LIBRARIES ${STORED_REQLIBS})
     if(HAS_C_${ASAN_FLAG} OR HAS_CXX_${ASAN_FLAG})
       set(HAVE_ASAN ON)
     endif()
@@ -3329,6 +3412,12 @@ if(ANDROID)
 endif()
 
 if(APPLE)
+  cmake_push_check_state(RESET)
+  check_c_compiler_flag(-fobjc-arc COMPILER_SUPPORTS_FOBJC_ARC)
+  cmake_pop_check_state()
+  if(NOT COMPILER_SUPPORTS_FOBJC_ARC)
+    message(FATAL_ERROR "Compiler does not support -fobjc-arc: this is required on Apple platforms")
+  endif()
   target_compile_options(sdl-build-options INTERFACE "-fobjc-arc")
 endif()
 
@@ -3394,7 +3483,7 @@ if(SDL_SHARED)
     set_property(TARGET SDL2 APPEND_STRING PROPERTY STATIC_LIBRARY_FLAGS " /NODEFAULTLIB")
   endif()
   # FIXME: if CMAKE_VERSION >= 3.13, use target_link_options for EXTRA_LDFLAGS
-  target_link_libraries(SDL2 PRIVATE ${EXTRA_LIBS} ${EXTRA_LDFLAGS} ${EXTRA_LDFLAGS_BUILD} ${CMAKE_DEPENDS})
+  target_link_libraries(SDL2 PRIVATE ${EXTRA_LIBS} ${EXTRA_LDFLAGS} ${EXTRA_LDFLAGS_BUILD} ${CMAKE_LIBS})
   target_include_directories(SDL2 PUBLIC
       "$<BUILD_INTERFACE:${SDL2_BINARY_DIR}/include>"
       "$<BUILD_INTERFACE:${SDL2_BINARY_DIR}/include/SDL2>"
@@ -3430,7 +3519,7 @@ if(SDL_STATIC)
   target_compile_definitions(SDL2-static PRIVATE SDL_STATIC_LIB)
   # TODO: Win32 platforms keep the same suffix .lib for import and static
   # libraries - do we need to consider this?
-  target_link_libraries(SDL2-static PRIVATE ${EXTRA_LIBS} ${EXTRA_LDFLAGS} ${CMAKE_DEPENDS})
+  target_link_libraries(SDL2-static PRIVATE ${EXTRA_LIBS} ${EXTRA_LDFLAGS} ${CMAKE_LIBS})
   target_include_directories(SDL2-static PUBLIC
       "$<BUILD_INTERFACE:${SDL2_BINARY_DIR}/include>"
       "$<BUILD_INTERFACE:${SDL2_BINARY_DIR}/include/SDL2>"
@@ -3470,10 +3559,28 @@ if(SDL_TEST)
       "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
       "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/SDL2>")
   target_link_libraries(SDL2_test PRIVATE ${EXTRA_TEST_LIBS})
+  target_include_directories(SDL2_test PRIVATE ${EXTRA_TEST_INCLUDES})
   set_property(TARGET SDL2_test APPEND PROPERTY COMPATIBLE_INTERFACE_STRING "SDL_VERSION")
   set_property(TARGET SDL2_test PROPERTY INTERFACE_SDL_VERSION "SDL2")
 endif()
 
+if(MSVC AND NOT SDL_LIBC)
+  set(targets )
+  if(TARGET SDL2)
+    list(APPEND targets SDL2)
+  endif()
+  if(TARGET SDL2-static)
+    list(APPEND targets SDL2-static)
+  endif()
+  if(TARGET SDL2_test)
+    list(APPEND targets SDL2_test)
+  endif()
+  set_property(TARGET ${targets} APPEND PROPERTY COMPILE_OPTIONS "/GS-;/Gs1048576")
+  if(NOT ARCH_64 AND NOT CMAKE_GENERATOR_PLATFORM STREQUAL "ARM")
+    set_property(TARGET ${targets} APPEND PROPERTY COMPILE_OPTIONS "/arch:SSE")
+  endif()
+endif()
+
 ##### Installation targets #####
 if(NOT SDL2_DISABLE_INSTALL)
   if(SDL_SHARED)
@@ -3481,6 +3588,9 @@ if(NOT SDL2_DISABLE_INSTALL)
       LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
       ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
       RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
+    if(MSVC)
+      SDL_install_pdb(SDL2 "${CMAKE_INSTALL_BINDIR}")
+    endif()
   endif()
 
   if(NOT WINDOWS_STORE AND NOT SDL2_DISABLE_SDL2MAIN)
@@ -3488,6 +3598,9 @@ if(NOT SDL2_DISABLE_INSTALL)
       LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
       ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
       RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
+    if(MSVC)
+      SDL_install_pdb(SDL2main "${CMAKE_INSTALL_LIBDIR}")
+    endif()
   endif()
 
   if(SDL_STATIC)
@@ -3495,6 +3608,9 @@ if(NOT SDL2_DISABLE_INSTALL)
       LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
       ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
       RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
+    if(MSVC)
+      SDL_install_pdb(SDL2-static "${CMAKE_INSTALL_LIBDIR}")
+    endif()
   endif()
 
   if(SDL_TEST)
@@ -3502,6 +3618,9 @@ if(NOT SDL2_DISABLE_INSTALL)
       LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
       ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
       RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
+    if(MSVC)
+      SDL_install_pdb(SDL2_test "${CMAKE_INSTALL_LIBDIR}")
+    endif()
   endif()
 
   ##### Export files #####

+ 1 - 1
Engine/lib/sdl/LICENSE.txt

@@ -1,4 +1,4 @@
-Copyright (C) 1997-2023 Sam Lantinga <[email protected]>
+Copyright (C) 1997-2025 Sam Lantinga <[email protected]>
   
 This software is provided 'as-is', without any express or implied
 warranty.  In no event will the authors be held liable for any damages

+ 1 - 1
Engine/lib/sdl/Makefile.in

@@ -52,7 +52,7 @@ WAYLAND_SCANNER_CODE_MODE = @WAYLAND_SCANNER_CODE_MODE@
 
 INSTALL_SDL2_CONFIG = @INSTALL_SDL2_CONFIG@
 
-SRC_DIST = *.md *.txt acinclude Android.mk autogen.sh android-project build-scripts cmake cmake_uninstall.cmake.in configure configure.ac docs include Makefile.* mingw sdl2-config.cmake.in sdl2-config-version.cmake.in sdl2-config.in sdl2.m4 sdl2.pc.in SDL2.spec.in SDL2Config.cmake.in src test VisualC VisualC-WinRT Xcode Xcode-iOS wayland-protocols
+SRC_DIST = *.md *.txt acinclude Android.mk autogen.sh android-project build-scripts cmake cmake_uninstall.cmake.in configure configure.ac docs include Makefile.* mingw sdl2-config.cmake.in sdl2-config-version.cmake.in sdl2-config.in sdl2.m4 sdl2.pc.in SDL2.spec.in SDL2Config.cmake.in src test VisualC VisualC-GDK VisualC-WinRT Xcode Xcode-iOS wayland-protocols
 GEN_DIST = SDL2.spec
 
 ifneq ($V,1)

+ 8 - 6
Engine/lib/sdl/Makefile.os2

@@ -1,4 +1,4 @@
-# Open Watcom makefile to build SDL2.dll for OS/2
+# Open Watcom makefile to build SDL2.dll for OS/2:
 # wmake -f Makefile.os2
 #
 # If you have GNU libiconv installed (iconv2.dll), you
@@ -14,8 +14,8 @@
 
 LIBNAME = SDL2
 MAJOR_VERSION = 2
-MINOR_VERSION = 28
-MICRO_VERSION = 4
+MINOR_VERSION = 32
+MICRO_VERSION = 6
 VERSION = $(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION)
 DESCRIPTION = Simple DirectMedia Layer 2
 
@@ -56,7 +56,7 @@ CFLAGS_DLL+= -bd
 # iconv:
 LIBICONV_LIB=iconv2.lib
 !ifeq LIBICONV 1
-CFLAGS_DLL+= -DHAVE_ICONV=1 -DHAVE_ICONV_H=1
+CFLAGS_DLL+= -DHAVE_ICONV=1 -DHAVE_ICONV_H=1 -DSDL_USE_LIBICONV
 LIBS+= $(ICONVLIB)
 !else
 LIBS+= libuls.lib libconv.lib
@@ -81,7 +81,7 @@ SRCS+= SDL_events.c SDL_quit.c SDL_keyboard.c SDL_mouse.c SDL_windowevents.c &
        SDL_clipboardevents.c SDL_dropevents.c SDL_displayevents.c SDL_gesture.c &
        SDL_sensor.c SDL_touch.c
 SRCS+= SDL_haptic.c SDL_hidapi.c SDL_gamecontroller.c SDL_joystick.c controller_type.c
-SRCS+= SDL_render.c yuv_rgb.c SDL_yuv.c SDL_yuv_sw.c SDL_blendfillrect.c &
+SRCS+= SDL_render.c yuv_rgb_sse.c yuv_rgb_std.c SDL_yuv.c SDL_yuv_sw.c SDL_blendfillrect.c &
        SDL_blendline.c SDL_blendpoint.c SDL_drawline.c SDL_drawpoint.c &
        SDL_render_sw.c SDL_rotate.c SDL_triangle.c
 SRCS+= SDL_blit.c SDL_blit_0.c SDL_blit_1.c SDL_blit_A.c SDL_blit_auto.c &
@@ -94,7 +94,7 @@ SRCS+= SDL_systimer.c
 SRCS+= SDL_sysloadso.c
 SRCS+= SDL_sysfilesystem.c
 SRCS+= SDL_os2joystick.c SDL_syshaptic.c SDL_sysjoystick.c SDL_virtualjoystick.c
-SRCS+= SDL_hidapijoystick.c SDL_hidapi_rumble.c SDL_hidapi_combined.c SDL_hidapi_gamecube.c SDL_hidapi_luna.c SDL_hidapi_ps3.c SDL_hidapi_ps4.c SDL_hidapi_ps5.c SDL_hidapi_shield.c SDL_hidapi_stadia.c SDL_hidapi_switch.c SDL_hidapi_wii.c SDL_hidapi_xbox360.c SDL_hidapi_xbox360w.c SDL_hidapi_xboxone.c SDL_hidapi_steam.c
+SRCS+= SDL_hidapijoystick.c SDL_hidapi_rumble.c SDL_hidapi_combined.c SDL_hidapi_gamecube.c SDL_hidapi_luna.c SDL_hidapi_ps3.c SDL_hidapi_ps4.c SDL_hidapi_ps5.c SDL_hidapi_shield.c SDL_hidapi_stadia.c SDL_hidapi_switch.c SDL_hidapi_wii.c SDL_hidapi_xbox360.c SDL_hidapi_xbox360w.c SDL_hidapi_xboxone.c SDL_hidapi_steam.c SDL_hidapi_steamdeck.c SDL_steam_virtual_gamepad.c
 SRCS+= SDL_dummyaudio.c SDL_diskaudio.c
 SRCS+= SDL_nullvideo.c SDL_nullframebuffer.c SDL_nullevents.c
 SRCS+= SDL_dummysensor.c
@@ -152,6 +152,8 @@ SDL_blendpoint.obj: SDL_blendpoint.c
     wcc386 $(CFLAGS_DLL) -wcd=200 -fo=$^@ $<
 SDL_RLEaccel.obj: SDL_RLEaccel.c
     wcc386 $(CFLAGS_DLL) -wcd=201 -fo=$^@ $<
+yuv_rgb_sse.obj: yuv_rgb_sse.c
+    wcc386 $(CFLAGS_DLL) -wcd=202 -fo=$^@ $<
 !ifeq HIDAPI 1
 # c99 mode needed because of structs with flexible array members in libusb.h
 SDL_hidapi.obj: SDL_hidapi.c

+ 9 - 6
Engine/lib/sdl/Makefile.w32

@@ -1,12 +1,12 @@
-# Open Watcom makefile to build SDL2.dll for Win32
+# Open Watcom makefile to build SDL2.dll for Win32:
 # wmake -f Makefile.w32
 #
 # To error out upon warnings: wmake -f Makefile.w32 ENABLE_WERROR=1
 
 LIBNAME = SDL2
 MAJOR_VERSION = 2
-MINOR_VERSION = 28
-MICRO_VERSION = 4
+MINOR_VERSION = 32
+MICRO_VERSION = 6
 VERSION = $(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION)
 
 LIBHOME = .
@@ -60,7 +60,7 @@ SRCS+= SDL_events.c SDL_quit.c SDL_keyboard.c SDL_mouse.c SDL_windowevents.c &
        SDL_clipboardevents.c SDL_dropevents.c SDL_displayevents.c SDL_gesture.c &
        SDL_sensor.c SDL_touch.c
 SRCS+= SDL_haptic.c SDL_hidapi.c SDL_gamecontroller.c SDL_joystick.c controller_type.c
-SRCS+= SDL_render.c yuv_rgb.c SDL_yuv.c SDL_yuv_sw.c SDL_blendfillrect.c &
+SRCS+= SDL_render.c yuv_rgb_sse.c yuv_rgb_std.c SDL_yuv.c SDL_yuv_sw.c SDL_blendfillrect.c &
        SDL_blendline.c SDL_blendpoint.c SDL_drawline.c SDL_drawpoint.c &
        SDL_render_sw.c SDL_rotate.c SDL_triangle.c
 SRCS+= SDL_blit.c SDL_blit_0.c SDL_blit_1.c SDL_blit_A.c SDL_blit_auto.c &
@@ -73,7 +73,7 @@ SRCS+= SDL_systimer.c
 SRCS+= SDL_sysloadso.c
 SRCS+= SDL_sysfilesystem.c
 SRCS+= SDL_syshaptic.c SDL_sysjoystick.c SDL_virtualjoystick.c
-SRCS+= SDL_hidapijoystick.c SDL_hidapi_rumble.c SDL_hidapi_combined.c SDL_hidapi_gamecube.c SDL_hidapi_luna.c SDL_hidapi_ps3.c SDL_hidapi_ps4.c SDL_hidapi_ps5.c SDL_hidapi_shield.c SDL_hidapi_stadia.c SDL_hidapi_switch.c SDL_hidapi_wii.c SDL_hidapi_xbox360.c SDL_hidapi_xbox360w.c SDL_hidapi_xboxone.c SDL_hidapi_steam.c
+SRCS+= SDL_hidapijoystick.c SDL_hidapi_rumble.c SDL_hidapi_combined.c SDL_hidapi_gamecube.c SDL_hidapi_luna.c SDL_hidapi_ps3.c SDL_hidapi_ps4.c SDL_hidapi_ps5.c SDL_hidapi_shield.c SDL_hidapi_stadia.c SDL_hidapi_switch.c SDL_hidapi_wii.c SDL_hidapi_xbox360.c SDL_hidapi_xbox360w.c SDL_hidapi_xboxone.c SDL_hidapi_steam.c SDL_hidapi_steamdeck.c
 SRCS+= SDL_dummyaudio.c SDL_diskaudio.c
 SRCS+= SDL_nullvideo.c SDL_nullframebuffer.c SDL_nullevents.c
 SRCS+= SDL_dummysensor.c
@@ -93,7 +93,7 @@ SRCS+= SDL_render_gl.c SDL_shaders_gl.c
 SRCS+= SDL_render_gles2.c SDL_shaders_gles2.c
 SRCS+= SDL_windowssensor.c
 SRCS+= SDL_syscond_cv.c
-SRCS+= SDL_windowsclipboard.c SDL_windowsevents.c SDL_windowsframebuffer.c SDL_windowskeyboard.c SDL_windowsmessagebox.c SDL_windowsmodes.c SDL_windowsmouse.c SDL_windowsopengl.c SDL_windowsopengles.c SDL_windowsshape.c SDL_windowsvideo.c SDL_windowsvulkan.c SDL_windowswindow.c
+SRCS+= SDL_windowsclipboard.c SDL_windowsevents.c SDL_windowsframebuffer.c SDL_windowskeyboard.c SDL_windowsmessagebox.c SDL_windowsmodes.c SDL_windowsmouse.c SDL_windowsopengl.c SDL_windowsopengles.c SDL_windowsshape.c SDL_windowsvideo.c SDL_windowsvulkan.c SDL_windowswindow.c SDL_steam_virtual_gamepad.c
 
 SRCS+= SDL_dynapi.c
 
@@ -147,6 +147,9 @@ SDL_RLEaccel.obj: SDL_RLEaccel.c
 SDL_malloc.obj: SDL_malloc.c
     wcc386 $(CFLAGS_DLL) -wcd=201 -fo=$^@ $<
 
+yuv_rgb_sse.obj: yuv_rgb_sse.c
+    wcc386 $(CFLAGS_DLL) -wcd=202 -fo=$^@ $<
+
 # SDL2libm
 MSRCS= e_atan2.c e_exp.c e_fmod.c e_log10.c e_log.c e_pow.c e_rem_pio2.c e_sqrt.c &
        k_cos.c k_rem_pio2.c k_sin.c k_tan.c &

+ 0 - 119
Engine/lib/sdl/SDL2.spec

@@ -1,119 +0,0 @@
-Summary: Simple DirectMedia Layer
-Name: SDL2
-Version: 2.28.4
-Release: 2
-Source: http://www.libsdl.org/release/%{name}-%{version}.tar.gz
-URL: http://www.libsdl.org/
-License: zlib
-Group: System Environment/Libraries
-BuildRoot: %{_tmppath}/%{name}-%{version}-buildroot
-Prefix: %{_prefix}
-%ifos linux
-Provides: libSDL2-2.0.so.0
-%endif
-
-%define __defattr %defattr(-,root,root)
-%define __soext so
-
-%description
-This is the Simple DirectMedia Layer, a generic API that provides low
-level access to audio, keyboard, mouse, and display framebuffer across
-multiple platforms.
-
-%package devel
-Summary: Libraries, includes and more to develop SDL applications.
-Group: Development/Libraries
-Requires: %{name} = %{version}
-
-%description devel
-This is the Simple DirectMedia Layer, a generic API that provides low
-level access to audio, keyboard, mouse, and display framebuffer across
-multiple platforms.
-
-This is the libraries, include files and other resources you can use
-to develop SDL applications.
-
-
-%prep
-%setup -q 
-
-%build
-%ifos linux
-CFLAGS="$RPM_OPT_FLAGS" ./configure --prefix=%{prefix} --disable-video-directfb
-%else
-%configure
-%endif
-make
-
-%install
-rm -rf $RPM_BUILD_ROOT
-%ifos linux
-make install prefix=$RPM_BUILD_ROOT%{prefix} \
-             bindir=$RPM_BUILD_ROOT%{_bindir} \
-             libdir=$RPM_BUILD_ROOT%{_libdir} \
-             includedir=$RPM_BUILD_ROOT%{_includedir} \
-             datadir=$RPM_BUILD_ROOT%{_datadir} \
-             mandir=$RPM_BUILD_ROOT%{_mandir}
-%else
-%makeinstall
-%endif
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-%files
-%{__defattr}
-%doc README*.txt LICENSE.txt CREDITS.txt BUGS.txt
-%{_libdir}/lib*.%{__soext}.*
-
-%files devel
-%{__defattr}
-%doc docs/README*.md
-%{_bindir}/*-config
-%{_libdir}/lib*.a
-%{_libdir}/lib*.la
-%{_libdir}/lib*.%{__soext}
-%{_includedir}/*/*.h
-%{_libdir}/cmake/*
-%{_libdir}/pkgconfig/SDL2/*
-%{_datadir}/aclocal/*
-
-%changelog
-* Thu Jun 04 2015 Ryan C. Gordon <[email protected]>
-- Fixed README paths.
-
-* Sun Dec 07 2014 Simone Contini <[email protected]>
-- Fixed changelog date issue and docs filenames
-
-* Sun Jan 22 2012 Sam Lantinga <[email protected]>
-- Updated for SDL 2.0
-
-* Tue May 16 2006 Sam Lantinga <[email protected]>
-- Removed support for Darwin, due to build problems on ps2linux
-
-* Sat Jan 03 2004 Anders Bjorklund <[email protected]>
-- Added support for Darwin, updated spec file
-
-* Wed Jan 19 2000 Sam Lantinga <[email protected]>
-- Re-integrated spec file into SDL distribution
-- 'name' and 'version' come from configure 
-- Some of the documentation is devel specific
-- Removed SMP support from %build - it doesn't work with libtool anyway
-
-* Tue Jan 18 2000 Hakan Tandogan <[email protected]>
-- Hacked Mandrake sdl spec to build 1.1
-
-* Sun Dec 19 1999 John Buswell <[email protected]>
-- Build Release
-
-* Sat Dec 18 1999 John Buswell <[email protected]>
-- Add symlink for libSDL-1.0.so.0 required by sdlbomber
-- Added docs
-
-* Thu Dec 09 1999 Lenny Cartier <[email protected]>
-- v 1.0.0
-
-* Mon Nov  1 1999 Chmouel Boudjnah <[email protected]>
-- First spec file for Mandrake distribution.
-
-# end of file

+ 0 - 1
Engine/lib/sdl/VERSION.txt

@@ -1 +0,0 @@
-release-2.28.4-0-gcc016b004

+ 7 - 0
Engine/lib/sdl/VisualC-GDK/clean.sh

@@ -0,0 +1,7 @@
+#!/bin/sh
+find . -type f \( -name '*.user' -o -name '*.sdf' -o -name '*.ncb' -o -name '*.suo' \) -print -delete
+find . -type f \( -name '*.bmp' -o -name '*.wav' -o -name '*.dat' \) -print -delete
+find . -depth -type d \( -name Gaming.Desktop.x64 \) -exec rm -rv {} \;
+find . -depth -type d \( -name Gaming.Xbox.Scarlett.x64 \) -exec rm -rv {} \;
+find . -depth -type d \( -name Gaming.Xbox.XboxOne.x64 \) -exec rm -rv {} \;
+rm shaders/*.h

BIN
Engine/lib/sdl/VisualC-GDK/logos/Logo100x100.png


BIN
Engine/lib/sdl/VisualC-GDK/logos/Logo150x150.png


BIN
Engine/lib/sdl/VisualC-GDK/logos/Logo44x44.png


BIN
Engine/lib/sdl/VisualC-GDK/logos/Logo480x480.png


BIN
Engine/lib/sdl/VisualC-GDK/logos/SplashScreenImage.png


+ 19 - 0
Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_Colors.hlsl

@@ -0,0 +1,19 @@
+struct PixelShaderInput
+{
+    float4 pos : SV_POSITION;
+    float2 tex : TEXCOORD0;
+    float4 color : COLOR0;
+};
+
+#define ColorRS \
+    "RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \
+    "DENY_DOMAIN_SHADER_ROOT_ACCESS |" \
+    "DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
+    "DENY_HULL_SHADER_ROOT_ACCESS )," \
+    "RootConstants(num32BitConstants=32, b0)"
+
+[RootSignature(ColorRS)]
+float4 main(PixelShaderInput input) : SV_TARGET0
+{
+    return input.color;
+}

+ 43 - 0
Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_NV12_BT601.hlsl

@@ -0,0 +1,43 @@
+Texture2D theTextureY : register(t0);
+Texture2D theTextureUV : register(t1);
+SamplerState theSampler : register(s0);
+
+struct PixelShaderInput
+{
+    float4 pos : SV_POSITION;
+    float2 tex : TEXCOORD0;
+    float4 color : COLOR0;
+};
+
+#define NVRS \
+    "RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \
+    "            DENY_DOMAIN_SHADER_ROOT_ACCESS |" \
+    "            DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
+    "            DENY_HULL_SHADER_ROOT_ACCESS )," \
+    "RootConstants(num32BitConstants=32, b0),"\
+    "DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL )"
+
+[RootSignature(NVRS)]
+float4 main(PixelShaderInput input) : SV_TARGET
+{
+    const float3 offset = {-0.0627451017, -0.501960814, -0.501960814};
+    const float3 Rcoeff = {1.1644,  0.0000,  1.5960};
+    const float3 Gcoeff = {1.1644, -0.3918, -0.8130};
+    const float3 Bcoeff = {1.1644,  2.0172,  0.0000};
+
+    float4 Output;
+
+    float3 yuv;
+    yuv.x = theTextureY.Sample(theSampler, input.tex).r;
+    yuv.yz = theTextureUV.Sample(theSampler, input.tex).rg;
+
+    yuv += offset;
+    Output.r = dot(yuv, Rcoeff);
+    Output.g = dot(yuv, Gcoeff);
+    Output.b = dot(yuv, Bcoeff);
+    Output.a = 1.0f;
+
+    return Output * input.color;
+}

+ 43 - 0
Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_NV12_BT709.hlsl

@@ -0,0 +1,43 @@
+Texture2D theTextureY : register(t0);
+Texture2D theTextureUV : register(t1);
+SamplerState theSampler : register(s0);
+
+struct PixelShaderInput
+{
+    float4 pos : SV_POSITION;
+    float2 tex : TEXCOORD0;
+    float4 color : COLOR0;
+};
+
+#define NVRS \
+    "RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \
+    "            DENY_DOMAIN_SHADER_ROOT_ACCESS |" \
+    "            DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
+    "            DENY_HULL_SHADER_ROOT_ACCESS )," \
+    "RootConstants(num32BitConstants=32, b0),"\
+    "DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL )"
+
+[RootSignature(NVRS)]
+float4 main(PixelShaderInput input) : SV_TARGET
+{
+    const float3 offset = {-0.0627451017, -0.501960814, -0.501960814};
+    const float3 Rcoeff = {1.1644,  0.0000,  1.7927};
+    const float3 Gcoeff = {1.1644, -0.2132, -0.5329};
+    const float3 Bcoeff = {1.1644,  2.1124,  0.0000};
+
+    float4 Output;
+
+    float3 yuv;
+    yuv.x = theTextureY.Sample(theSampler, input.tex).r;
+    yuv.yz = theTextureUV.Sample(theSampler, input.tex).rg;
+
+    yuv += offset;
+    Output.r = dot(yuv, Rcoeff);
+    Output.g = dot(yuv, Gcoeff);
+    Output.b = dot(yuv, Bcoeff);
+    Output.a = 1.0f;
+
+    return Output * input.color;
+}

+ 43 - 0
Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_NV12_JPEG.hlsl

@@ -0,0 +1,43 @@
+Texture2D theTextureY : register(t0);
+Texture2D theTextureUV : register(t1);
+SamplerState theSampler : register(s0);
+
+struct PixelShaderInput
+{
+    float4 pos : SV_POSITION;
+    float2 tex : TEXCOORD0;
+    float4 color : COLOR0;
+};
+
+#define NVRS \
+    "RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \
+    "            DENY_DOMAIN_SHADER_ROOT_ACCESS |" \
+    "            DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
+    "            DENY_HULL_SHADER_ROOT_ACCESS )," \
+    "RootConstants(num32BitConstants=32, b0),"\
+    "DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL )"
+
+[RootSignature(NVRS)]
+float4 main(PixelShaderInput input) : SV_TARGET
+{
+    const float3 offset = {0.0, -0.501960814, -0.501960814};
+    const float3 Rcoeff = {1.0000,  0.0000,  1.4020};
+    const float3 Gcoeff = {1.0000, -0.3441, -0.7141};
+    const float3 Bcoeff = {1.0000,  1.7720,  0.0000};
+
+    float4 Output;
+
+    float3 yuv;
+    yuv.x = theTextureY.Sample(theSampler, input.tex).r;
+    yuv.yz = theTextureUV.Sample(theSampler, input.tex).rg;
+
+    yuv += offset;
+    Output.r = dot(yuv, Rcoeff);
+    Output.g = dot(yuv, Gcoeff);
+    Output.b = dot(yuv, Bcoeff);
+    Output.a = 1.0f;
+
+    return Output * input.color;
+}

+ 43 - 0
Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_NV21_BT601.hlsl

@@ -0,0 +1,43 @@
+Texture2D theTextureY : register(t0);
+Texture2D theTextureUV : register(t1);
+SamplerState theSampler : register(s0);
+
+struct PixelShaderInput
+{
+    float4 pos : SV_POSITION;
+    float2 tex : TEXCOORD0;
+    float4 color : COLOR0;
+};
+
+#define NVRS \
+    "RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \
+    "            DENY_DOMAIN_SHADER_ROOT_ACCESS |" \
+    "            DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
+    "            DENY_HULL_SHADER_ROOT_ACCESS )," \
+    "RootConstants(num32BitConstants=32, b0),"\
+    "DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL )"
+
+[RootSignature(NVRS)]
+float4 main(PixelShaderInput input) : SV_TARGET
+{
+    const float3 offset = {-0.0627451017, -0.501960814, -0.501960814};
+    const float3 Rcoeff = {1.1644,  0.0000,  1.5960};
+    const float3 Gcoeff = {1.1644, -0.3918, -0.8130};
+    const float3 Bcoeff = {1.1644,  2.0172,  0.0000};
+
+    float4 Output;
+
+    float3 yuv;
+    yuv.x = theTextureY.Sample(theSampler, input.tex).r;
+    yuv.yz = theTextureUV.Sample(theSampler, input.tex).gr;
+
+    yuv += offset;
+    Output.r = dot(yuv, Rcoeff);
+    Output.g = dot(yuv, Gcoeff);
+    Output.b = dot(yuv, Bcoeff);
+    Output.a = 1.0f;
+
+    return Output * input.color;
+}

+ 43 - 0
Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_NV21_BT709.hlsl

@@ -0,0 +1,43 @@
+Texture2D theTextureY : register(t0);
+Texture2D theTextureUV : register(t1);
+SamplerState theSampler : register(s0);
+
+struct PixelShaderInput
+{
+    float4 pos : SV_POSITION;
+    float2 tex : TEXCOORD0;
+    float4 color : COLOR0;
+};
+
+#define NVRS \
+    "RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \
+    "            DENY_DOMAIN_SHADER_ROOT_ACCESS |" \
+    "            DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
+    "            DENY_HULL_SHADER_ROOT_ACCESS )," \
+    "RootConstants(num32BitConstants=32, b0),"\
+    "DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL )"
+
+[RootSignature(NVRS)]
+float4 main(PixelShaderInput input) : SV_TARGET
+{
+    const float3 offset = {-0.0627451017, -0.501960814, -0.501960814};
+    const float3 Rcoeff = {1.1644,  0.0000,  1.7927};
+    const float3 Gcoeff = {1.1644, -0.2132, -0.5329};
+    const float3 Bcoeff = {1.1644,  2.1124,  0.0000};
+
+    float4 Output;
+
+    float3 yuv;
+    yuv.x = theTextureY.Sample(theSampler, input.tex).r;
+    yuv.yz = theTextureUV.Sample(theSampler, input.tex).gr;
+
+    yuv += offset;
+    Output.r = dot(yuv, Rcoeff);
+    Output.g = dot(yuv, Gcoeff);
+    Output.b = dot(yuv, Bcoeff);
+    Output.a = 1.0f;
+
+    return Output * input.color;
+}

+ 43 - 0
Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_NV21_JPEG.hlsl

@@ -0,0 +1,43 @@
+Texture2D theTextureY : register(t0);
+Texture2D theTextureUV : register(t1);
+SamplerState theSampler : register(s0);
+
+struct PixelShaderInput
+{
+    float4 pos : SV_POSITION;
+    float2 tex : TEXCOORD0;
+    float4 color : COLOR0;
+};
+
+#define NVRS \
+    "RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \
+    "            DENY_DOMAIN_SHADER_ROOT_ACCESS |" \
+    "            DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
+    "            DENY_HULL_SHADER_ROOT_ACCESS )," \
+    "RootConstants(num32BitConstants=32, b0),"\
+    "DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL )"
+
+[RootSignature(NVRS)]
+float4 main(PixelShaderInput input) : SV_TARGET
+{
+    const float3 offset = {0.0, -0.501960814, -0.501960814};
+    const float3 Rcoeff = {1.0000,  0.0000,  1.4020};
+    const float3 Gcoeff = {1.0000, -0.3441, -0.7141};
+    const float3 Bcoeff = {1.0000,  1.7720,  0.0000};
+
+    float4 Output;
+
+    float3 yuv;
+    yuv.x = theTextureY.Sample(theSampler, input.tex).r;
+    yuv.yz = theTextureUV.Sample(theSampler, input.tex).gr;
+
+    yuv += offset;
+    Output.r = dot(yuv, Rcoeff);
+    Output.g = dot(yuv, Gcoeff);
+    Output.b = dot(yuv, Bcoeff);
+    Output.a = 1.0f;
+
+    return Output * input.color;
+}

+ 24 - 0
Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_Textures.hlsl

@@ -0,0 +1,24 @@
+Texture2D theTexture : register(t0);
+SamplerState theSampler : register(s0);
+
+struct PixelShaderInput
+{
+    float4 pos : SV_POSITION;
+    float2 tex : TEXCOORD0;
+    float4 color : COLOR0;
+};
+
+#define TextureRS \
+    "RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \
+    "            DENY_DOMAIN_SHADER_ROOT_ACCESS |" \
+    "            DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
+    "            DENY_HULL_SHADER_ROOT_ACCESS )," \
+    "RootConstants(num32BitConstants=32, b0),"\
+    "DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL )"
+
+[RootSignature(TextureRS)]
+float4 main(PixelShaderInput input) : SV_TARGET
+{
+    return theTexture.Sample(theSampler, input.tex) * input.color;
+}

+ 46 - 0
Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_YUV_BT601.hlsl

@@ -0,0 +1,46 @@
+Texture2D theTextureY : register(t0);
+Texture2D theTextureU : register(t1);
+Texture2D theTextureV : register(t2);
+SamplerState theSampler : register(s0);
+
+struct PixelShaderInput
+{
+    float4 pos : SV_POSITION;
+    float2 tex : TEXCOORD0;
+    float4 color : COLOR0;
+};
+
+#define YUVRS \
+    "RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \
+    "            DENY_DOMAIN_SHADER_ROOT_ACCESS |" \
+    "            DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
+    "            DENY_HULL_SHADER_ROOT_ACCESS )," \
+    "RootConstants(num32BitConstants=32, b0),"\
+    "DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( SRV(t2), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL )"
+
+[RootSignature(YUVRS)]
+float4 main(PixelShaderInput input) : SV_TARGET
+{
+    const float3 offset = {-0.0627451017, -0.501960814, -0.501960814};
+    const float3 Rcoeff = {1.1644,  0.0000,  1.5960};
+    const float3 Gcoeff = {1.1644, -0.3918, -0.8130};
+    const float3 Bcoeff = {1.1644,  2.0172,  0.0000};
+
+    float4 Output;
+
+    float3 yuv;
+    yuv.x = theTextureY.Sample(theSampler, input.tex).r;
+    yuv.y = theTextureU.Sample(theSampler, input.tex).r;
+    yuv.z = theTextureV.Sample(theSampler, input.tex).r;
+
+    yuv += offset;
+    Output.r = dot(yuv, Rcoeff);
+    Output.g = dot(yuv, Gcoeff);
+    Output.b = dot(yuv, Bcoeff);
+    Output.a = 1.0f;
+
+    return Output * input.color;
+}

+ 46 - 0
Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_YUV_BT709.hlsl

@@ -0,0 +1,46 @@
+Texture2D theTextureY : register(t0);
+Texture2D theTextureU : register(t1);
+Texture2D theTextureV : register(t2);
+SamplerState theSampler : register(s0);
+
+struct PixelShaderInput
+{
+    float4 pos : SV_POSITION;
+    float2 tex : TEXCOORD0;
+    float4 color : COLOR0;
+};
+
+#define YUVRS \
+    "RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \
+    "            DENY_DOMAIN_SHADER_ROOT_ACCESS |" \
+    "            DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
+    "            DENY_HULL_SHADER_ROOT_ACCESS )," \
+    "RootConstants(num32BitConstants=32, b0),"\
+    "DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( SRV(t2), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL )"
+
+[RootSignature(YUVRS)]
+float4 main(PixelShaderInput input) : SV_TARGET
+{
+    const float3 offset = {-0.0627451017, -0.501960814, -0.501960814};
+    const float3 Rcoeff = {1.1644,  0.0000,  1.7927};
+    const float3 Gcoeff = {1.1644, -0.2132, -0.5329};
+    const float3 Bcoeff = {1.1644,  2.1124,  0.0000};
+
+    float4 Output;
+
+    float3 yuv;
+    yuv.x = theTextureY.Sample(theSampler, input.tex).r;
+    yuv.y = theTextureU.Sample(theSampler, input.tex).r;
+    yuv.z = theTextureV.Sample(theSampler, input.tex).r;
+
+    yuv += offset;
+    Output.r = dot(yuv, Rcoeff);
+    Output.g = dot(yuv, Gcoeff);
+    Output.b = dot(yuv, Bcoeff);
+    Output.a = 1.0f;
+
+    return Output * input.color;
+}

+ 46 - 0
Engine/lib/sdl/VisualC-GDK/shaders/D3D12_PixelShader_YUV_JPEG.hlsl

@@ -0,0 +1,46 @@
+Texture2D theTextureY : register(t0);
+Texture2D theTextureU : register(t1);
+Texture2D theTextureV : register(t2);
+SamplerState theSampler : register(s0);
+
+struct PixelShaderInput
+{
+    float4 pos : SV_POSITION;
+    float2 tex : TEXCOORD0;
+    float4 color : COLOR0;
+};
+
+#define YUVRS \
+    "RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \
+    "            DENY_DOMAIN_SHADER_ROOT_ACCESS |" \
+    "            DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
+    "            DENY_HULL_SHADER_ROOT_ACCESS )," \
+    "RootConstants(num32BitConstants=32, b0),"\
+    "DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( SRV(t2), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL )"
+
+[RootSignature(YUVRS)]
+float4 main(PixelShaderInput input) : SV_TARGET
+{
+    const float3 offset = {0.0, -0.501960814, -0.501960814};
+    const float3 Rcoeff = {1.0000,  0.0000,  1.4020};
+    const float3 Gcoeff = {1.0000, -0.3441, -0.7141};
+    const float3 Bcoeff = {1.0000,  1.7720,  0.0000};
+
+    float4 Output;
+
+    float3 yuv;
+    yuv.x = theTextureY.Sample(theSampler, input.tex).r;
+    yuv.y = theTextureU.Sample(theSampler, input.tex).r;
+    yuv.z = theTextureV.Sample(theSampler, input.tex).r;
+
+    yuv += offset;
+    Output.r = dot(yuv, Rcoeff);
+    Output.g = dot(yuv, Gcoeff);
+    Output.b = dot(yuv, Bcoeff);
+    Output.a = 1.0f;
+
+    return Output * input.color;
+}

+ 95 - 0
Engine/lib/sdl/VisualC-GDK/shaders/D3D12_VertexShader.hlsl

@@ -0,0 +1,95 @@
+#pragma pack_matrix( row_major )
+
+struct VertexShaderConstants
+{
+    matrix model;
+    matrix projectionAndView;
+};
+ConstantBuffer<VertexShaderConstants> Constants : register(b0);
+
+struct VertexShaderInput
+{
+    float3 pos : POSITION;
+    float2 tex : TEXCOORD0;
+    float4 color : COLOR0;
+};
+
+struct VertexShaderOutput
+{
+    float4 pos : SV_POSITION;
+    float2 tex : TEXCOORD0;
+    float4 color : COLOR0;
+};
+
+#define ColorRS \
+    "RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \
+    "DENY_DOMAIN_SHADER_ROOT_ACCESS |" \
+    "DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
+    "DENY_HULL_SHADER_ROOT_ACCESS )," \
+    "RootConstants(num32BitConstants=32, b0)"
+
+#define TextureRS \
+    "RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \
+    "            DENY_DOMAIN_SHADER_ROOT_ACCESS |" \
+    "            DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
+    "            DENY_HULL_SHADER_ROOT_ACCESS )," \
+    "RootConstants(num32BitConstants=32, b0),"\
+    "DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL )"
+
+#define YUVRS \
+    "RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \
+    "            DENY_DOMAIN_SHADER_ROOT_ACCESS |" \
+    "            DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
+    "            DENY_HULL_SHADER_ROOT_ACCESS )," \
+    "RootConstants(num32BitConstants=32, b0),"\
+    "DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( SRV(t2), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL )"
+
+#define NVRS \
+    "RootFlags ( ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT |" \
+    "            DENY_DOMAIN_SHADER_ROOT_ACCESS |" \
+    "            DENY_GEOMETRY_SHADER_ROOT_ACCESS |" \
+    "            DENY_HULL_SHADER_ROOT_ACCESS )," \
+    "RootConstants(num32BitConstants=32, b0),"\
+    "DescriptorTable ( SRV(t0), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( SRV(t1), visibility = SHADER_VISIBILITY_PIXEL ),"\
+    "DescriptorTable ( Sampler(s0), visibility = SHADER_VISIBILITY_PIXEL )"
+
+[RootSignature(ColorRS)]
+VertexShaderOutput mainColor(VertexShaderInput input)
+{
+    VertexShaderOutput output;
+    float4 pos = float4(input.pos, 1.0f);
+
+    // Transform the vertex position into projected space.
+    pos = mul(pos, Constants.model);
+    pos = mul(pos, Constants.projectionAndView);
+    output.pos = pos;
+
+    // Pass through texture coordinates and color values without transformation
+    output.tex = input.tex;
+    output.color = input.color;
+
+    return output;
+}
+
+[RootSignature(TextureRS)]
+VertexShaderOutput mainTexture(VertexShaderInput input)
+{
+    return mainColor(input);
+}
+
+[RootSignature(YUVRS)]
+VertexShaderOutput mainYUV(VertexShaderInput input)
+{
+    return mainColor(input);
+}
+
+[RootSignature(NVRS)]
+VertexShaderOutput mainNV(VertexShaderInput input)
+{
+    return mainColor(input);
+}

+ 35 - 0
Engine/lib/sdl/VisualC-GDK/shaders/buildshaders.bat

@@ -0,0 +1,35 @@
+if %2.==one. goto setxboxone
+rem Xbox Series compile
+set XBOXDXC="%GameDKLatest%\GXDK\bin\Scarlett\DXC.exe"
+set SUFFIX=_Series.h
+goto startbuild
+
+:setxboxone
+set XBOXDXC="%GameDKLatest%\GXDK\bin\XboxOne\DXC.exe"
+set SUFFIX=_One.h
+
+:startbuild
+echo Building with %XBOXDXC%
+cd "%1\shaders"
+rem Root Signatures
+%XBOXDXC% -E ColorRS -T rootsig_1_1 -rootsig-define ColorRS -Fh D3D12_RootSig_Color%SUFFIX% -Vn D3D12_RootSig_Color D3D12_VertexShader.hlsl
+%XBOXDXC% -E TextureRS -T rootsig_1_1 -rootsig-define TextureRS -Fh D3D12_RootSig_Texture%SUFFIX% -Vn D3D12_RootSig_Texture D3D12_VertexShader.hlsl
+%XBOXDXC% -E YUVRS -T rootsig_1_1 -rootsig-define YUVRS -Fh D3D12_RootSig_YUV%SUFFIX% -Vn D3D12_RootSig_YUV D3D12_VertexShader.hlsl
+%XBOXDXC% -E NVRS -T rootsig_1_1 -rootsig-define NVRS -Fh D3D12_RootSig_NV%SUFFIX% -Vn D3D12_RootSig_NV D3D12_VertexShader.hlsl
+rem Vertex Shaders
+%XBOXDXC% -E mainColor -T vs_6_0 -Fh D3D12_VertexShader_Color%SUFFIX% -Vn D3D12_VertexShader_Color D3D12_VertexShader.hlsl
+%XBOXDXC% -E mainTexture -T vs_6_0 -Fh D3D12_VertexShader_Texture%SUFFIX% -Vn D3D12_VertexShader_Texture D3D12_VertexShader.hlsl
+%XBOXDXC% -E mainNV -T vs_6_0 -Fh D3D12_VertexShader_NV%SUFFIX% -Vn D3D12_VertexShader_NV D3D12_VertexShader.hlsl
+%XBOXDXC% -E mainYUV -T vs_6_0 -Fh D3D12_VertexShader_YUV%SUFFIX% -Vn D3D12_VertexShader_YUV D3D12_VertexShader.hlsl
+rem Pixel Shaders
+%XBOXDXC% -E main -T ps_6_0 -Fh D3D12_PixelShader_Colors%SUFFIX% -Vn D3D12_PixelShader_Colors D3D12_PixelShader_Colors.hlsl
+%XBOXDXC% -E main -T ps_6_0 -Fh D3D12_PixelShader_NV12_BT601%SUFFIX% -Vn D3D12_PixelShader_NV12_BT601 D3D12_PixelShader_NV12_BT601.hlsl
+%XBOXDXC% -E main -T ps_6_0 -Fh D3D12_PixelShader_NV12_BT709%SUFFIX% -Vn D3D12_PixelShader_NV12_BT709 D3D12_PixelShader_NV12_BT709.hlsl
+%XBOXDXC% -E main -T ps_6_0 -Fh D3D12_PixelShader_NV12_JPEG%SUFFIX% -Vn D3D12_PixelShader_NV12_JPEG D3D12_PixelShader_NV12_JPEG.hlsl
+%XBOXDXC% -E main -T ps_6_0 -Fh D3D12_PixelShader_NV21_BT601%SUFFIX% -Vn D3D12_PixelShader_NV21_BT601 D3D12_PixelShader_NV21_BT601.hlsl
+%XBOXDXC% -E main -T ps_6_0 -Fh D3D12_PixelShader_NV21_BT709%SUFFIX% -Vn D3D12_PixelShader_NV21_BT709 D3D12_PixelShader_NV21_BT709.hlsl
+%XBOXDXC% -E main -T ps_6_0 -Fh D3D12_PixelShader_NV21_JPEG%SUFFIX% -Vn D3D12_PixelShader_NV21_JPEG D3D12_PixelShader_NV21_JPEG.hlsl
+%XBOXDXC% -E main -T ps_6_0 -Fh D3D12_PixelShader_Textures%SUFFIX% -Vn D3D12_PixelShader_Textures D3D12_PixelShader_Textures.hlsl
+%XBOXDXC% -E main -T ps_6_0 -Fh D3D12_PixelShader_YUV_BT601%SUFFIX% -Vn D3D12_PixelShader_YUV_BT601 D3D12_PixelShader_YUV_BT601.hlsl
+%XBOXDXC% -E main -T ps_6_0 -Fh D3D12_PixelShader_YUV_BT709%SUFFIX% -Vn D3D12_PixelShader_YUV_BT709 D3D12_PixelShader_YUV_BT709.hlsl
+%XBOXDXC% -E main -T ps_6_0 -Fh D3D12_PixelShader_YUV_JPEG%SUFFIX% -Vn D3D12_PixelShader_YUV_JPEG D3D12_PixelShader_YUV_JPEG.hlsl

+ 9 - 0
Engine/lib/sdl/VisualC-GDK/tests/testgamecontroller/PackageLayout.xml

@@ -0,0 +1,9 @@
+<Package>
+  <Chunk Id="1000" Marker="Launch">
+    <FileGroup DestinationPath="." SourcePath="." Include="testgamecontroller.exe" />
+    <FileGroup DestinationPath="." SourcePath="." Include="MicrosoftGame.config" />
+    <FileGroup DestinationPath="." SourcePath="." Include="*.bmp" />
+    <FileGroup DestinationPath="." SourcePath="." Include="*.png" />
+    <FileGroup DestinationPath="." SourcePath="." Include="*.dll" />
+  </Chunk>
+</Package>

+ 34 - 0
Engine/lib/sdl/VisualC-GDK/tests/testgamecontroller/wingdk/MicrosoftGame.config

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Game configVersion="1">
+
+	<!-- Set these to the correct identifiers from Partner Center -->
+	<Identity Name="SDL"
+		Version="1.0.0.0"
+		Publisher="CN=Publisher"/>
+
+	<ExecutableList>
+		<Executable Name="testgamecontroller.exe"
+					TargetDeviceFamily="PC"
+					Id="Game" />
+	</ExecutableList>
+
+	<DesktopRegistration>
+		<DependencyList>
+			<KnownDependency Name="VC14"/>
+		</DependencyList>
+	</DesktopRegistration>
+
+	<!-- Set these to the correct values from Partner Center -->
+	<MSAAppId>PleaseChangeMe</MSAAppId>
+	<TitleId>FFFFFFFF</TitleId>
+
+	<ShellVisuals DefaultDisplayName="testgamecontroller"
+					PublisherDisplayName="SDL"
+					Square480x480Logo="Logo480x480.png"
+					Square150x150Logo="Logo150x150.png"
+					Square44x44Logo="Logo44x44.png"
+					Description="testgamecontroller"
+					ForegroundText="light"
+					BackgroundColor="#000000"
+					StoreLogo="Logo100x100.png"/>
+</Game>

+ 29 - 0
Engine/lib/sdl/VisualC-GDK/tests/testgamecontroller/xboxone/MicrosoftGame.config

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Game configVersion="1">
+
+	<!-- Set these to the correct identifiers from Partner Center -->
+	<Identity Name="SDL"
+		Version="1.0.0.0"
+		Publisher="CN=Publisher"/>
+
+	<ExecutableList>
+		<Executable Name="testgamecontroller.exe"
+					TargetDeviceFamily="XboxOne"
+					Id="Game" />
+	</ExecutableList>
+
+	<!-- Set these to the correct values from Partner Center -->
+	<MSAAppId>PleaseChangeMe</MSAAppId>
+	<TitleId>FFFFFFFF</TitleId>
+
+	<ShellVisuals DefaultDisplayName="testgamecontroller"
+					PublisherDisplayName="SDL"
+					Square480x480Logo="Logo480x480.png"
+					Square150x150Logo="Logo150x150.png"
+					Square44x44Logo="Logo44x44.png"
+					SplashScreenImage="SplashScreenImage.png"
+					Description="testgamecontroller"
+					ForegroundText="light"
+					BackgroundColor="#000000"
+					StoreLogo="Logo100x100.png"/>
+</Game>

+ 29 - 0
Engine/lib/sdl/VisualC-GDK/tests/testgamecontroller/xboxseries/MicrosoftGame.config

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Game configVersion="1">
+
+	<!-- Set these to the correct identifiers from Partner Center -->
+	<Identity Name="SDL"
+		Version="1.0.0.0"
+		Publisher="CN=Publisher"/>
+
+	<ExecutableList>
+		<Executable Name="testgamecontroller.exe"
+					TargetDeviceFamily="Scarlett"
+					Id="Game" />
+	</ExecutableList>
+
+	<!-- Set these to the correct values from Partner Center -->
+	<MSAAppId>PleaseChangeMe</MSAAppId>
+	<TitleId>FFFFFFFF</TitleId>
+
+	<ShellVisuals DefaultDisplayName="testgamecontroller"
+					PublisherDisplayName="SDL"
+					Square480x480Logo="Logo480x480.png"
+					Square150x150Logo="Logo150x150.png"
+					Square44x44Logo="Logo44x44.png"
+					SplashScreenImage="SplashScreenImage.png"
+					Description="testgamecontroller"
+					ForegroundText="light"
+					BackgroundColor="#000000"
+					StoreLogo="Logo100x100.png"/>
+</Game>

+ 10 - 0
Engine/lib/sdl/VisualC-GDK/tests/testgdk/PackageLayout.xml

@@ -0,0 +1,10 @@
+<Package>
+  <Chunk Id="1000" Marker="Launch">
+    <FileGroup DestinationPath="." SourcePath="." Include="testgdk.exe" />
+    <FileGroup DestinationPath="." SourcePath="." Include="MicrosoftGame.config" />
+    <FileGroup DestinationPath="." SourcePath="." Include="*.bmp" />
+    <FileGroup DestinationPath="." SourcePath="." Include="*.wav" />
+    <FileGroup DestinationPath="." SourcePath="." Include="*.png" />
+    <FileGroup DestinationPath="." SourcePath="." Include="*.dll" />
+  </Chunk>
+</Package>

+ 503 - 0
Engine/lib/sdl/VisualC-GDK/tests/testgdk/src/testgdk.cpp

@@ -0,0 +1,503 @@
+/*
+  Copyright (C) 1997-2025 Sam Lantinga <[email protected]>
+
+  This software is provided 'as-is', without any express or implied
+  warranty.  In no event will the authors be held liable for any damages
+  arising from the use of this software.
+
+  Permission is granted to anyone to use this software for any purpose,
+  including commercial applications, and to alter it and redistribute it
+  freely.
+*/
+/* testgdk:  Basic tests of using task queue/xbl (with simple drawing) in GDK.
+ * NOTE: As of June 2022 GDK, login will only work if MicrosoftGame.config is
+ * configured properly. See README-gdk.md.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "SDL_test.h"
+#include "SDL_test_common.h"
+#include "../src/core/windows/SDL_windows.h"
+
+extern "C" {
+#include "../test/testutils.h"
+}
+
+#include <XGameRuntime.h>
+
+#define NUM_SPRITES    100
+#define MAX_SPEED     1
+
+static SDLTest_CommonState *state;
+static int num_sprites;
+static SDL_Texture **sprites;
+static SDL_bool cycle_color;
+static SDL_bool cycle_alpha;
+static int cycle_direction = 1;
+static int current_alpha = 0;
+static int current_color = 0;
+static int sprite_w, sprite_h;
+static SDL_BlendMode blendMode = SDL_BLENDMODE_BLEND;
+
+int done;
+
+static struct
+{
+    SDL_AudioSpec spec;
+    Uint8 *sound;    /* Pointer to wave data */
+    Uint32 soundlen; /* Length of wave data */
+    int soundpos;    /* Current play position */
+} wave;
+
+static SDL_AudioDeviceID device;
+
+static void
+close_audio()
+{
+    if (device != 0) {
+        SDL_CloseAudioDevice(device);
+        device = 0;
+    }
+}
+
+/* Call this instead of exit(), so we can clean up SDL: atexit() is evil. */
+static void
+quit(int rc)
+{
+    SDL_free(sprites);
+    close_audio();
+    SDL_FreeWAV(wave.sound);
+    SDLTest_CommonQuit(state);
+    /* If rc is 0, just let main return normally rather than calling exit.
+     * This allows testing of platforms where SDL_main is required and does meaningful cleanup.
+     */
+    if (rc != 0) {
+        exit(rc);
+    }
+}
+
+static void
+open_audio()
+{
+    /* Initialize fillerup() variables */
+    device = SDL_OpenAudioDevice(NULL, SDL_FALSE, &wave.spec, NULL, 0);
+    if (!device) {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't open audio: %s\n", SDL_GetError());
+        SDL_FreeWAV(wave.sound);
+        quit(2);
+    }
+
+    /* Let the audio run */
+    SDL_PauseAudioDevice(device, SDL_FALSE);
+}
+
+static void
+reopen_audio()
+{
+    close_audio();
+    open_audio();
+}
+
+void SDLCALL
+fillerup(void *unused, Uint8 *stream, int len)
+{
+    Uint8 *waveptr;
+    int waveleft;
+
+    /* Set up the pointers */
+    waveptr = wave.sound + wave.soundpos;
+    waveleft = wave.soundlen - wave.soundpos;
+
+    /* Go! */
+    while (waveleft <= len) {
+        SDL_memcpy(stream, waveptr, waveleft);
+        stream += waveleft;
+        len -= waveleft;
+        waveptr = wave.sound;
+        waveleft = wave.soundlen;
+        wave.soundpos = 0;
+    }
+    SDL_memcpy(stream, waveptr, len);
+    wave.soundpos += len;
+}
+
+void
+UserLoggedIn(XUserHandle user)
+{
+    HRESULT hr;
+    char gamertag[128];
+    hr = XUserGetGamertag(user, XUserGamertagComponent::UniqueModern, sizeof(gamertag), gamertag, NULL);
+
+    if (SUCCEEDED(hr)) {
+        SDL_Log("User logged in: %s", gamertag);
+    } else {
+        SDL_Log("[GDK] UserLoggedIn -- XUserGetGamertag failed: 0x%08x.", hr);
+    }
+
+    XUserCloseHandle(user);
+}
+
+void
+AddUserUICallback(XAsyncBlock *asyncBlock)
+{
+    HRESULT hr;
+    XUserHandle user = NULL;
+
+    hr = XUserAddResult(asyncBlock, &user);
+    if (SUCCEEDED(hr)) {
+        uint64_t userId;
+
+        hr = XUserGetId(user, &userId);
+        if (FAILED(hr)) {
+            /* If unable to get the user ID, it means the account is banned, etc. */
+            SDL_Log("[GDK] AddUserSilentCallback -- XUserGetId failed: 0x%08x.", hr);
+            XUserCloseHandle(user);
+
+            /* Per the docs, likely should call XUserResolveIssueWithUiAsync here. */
+        } else {
+            UserLoggedIn(user);
+        }
+    } else {
+        SDL_Log("[GDK] AddUserUICallback -- XUserAddAsync failed: 0x%08x.", hr);
+    }
+
+    delete asyncBlock;
+}
+
+void
+AddUserUI()
+{
+    HRESULT hr;
+    XAsyncBlock *asyncBlock = new XAsyncBlock;
+
+    asyncBlock->context = NULL;
+    asyncBlock->queue = NULL; /* A null queue will use the global process task queue */
+    asyncBlock->callback = &AddUserUICallback;
+
+    hr = XUserAddAsync(XUserAddOptions::None, asyncBlock);
+
+    if (FAILED(hr)) {
+        delete asyncBlock;
+        SDL_Log("[GDK] AddUserSilent -- failed: 0x%08x", hr);
+    }
+}
+
+void
+AddUserSilentCallback(XAsyncBlock *asyncBlock)
+{
+    HRESULT hr;
+    XUserHandle user = NULL;
+
+    hr = XUserAddResult(asyncBlock, &user);
+    if (SUCCEEDED(hr)) {
+        uint64_t userId;
+
+        hr = XUserGetId(user, &userId);
+        if (FAILED(hr)) {
+            /* If unable to get the user ID, it means the account is banned, etc. */
+            SDL_Log("[GDK] AddUserSilentCallback -- XUserGetId failed: 0x%08x. Trying with UI.", hr);
+            XUserCloseHandle(user);
+            AddUserUI();
+        } else {
+            UserLoggedIn(user);
+        }
+    } else {
+        SDL_Log("[GDK] AddUserSilentCallback -- XUserAddAsync failed: 0x%08x. Trying with UI.", hr);
+        AddUserUI();
+    }
+
+    delete asyncBlock;
+}
+
+void
+AddUserSilent()
+{
+    HRESULT hr;
+    XAsyncBlock *asyncBlock = new XAsyncBlock;
+
+    asyncBlock->context = NULL;
+    asyncBlock->queue = NULL; /* A null queue will use the global process task queue */
+    asyncBlock->callback = &AddUserSilentCallback;
+
+    hr = XUserAddAsync(XUserAddOptions::AddDefaultUserSilently, asyncBlock);
+
+    if (FAILED(hr)) {
+        delete asyncBlock;
+        SDL_Log("[GDK] AddUserSilent -- failed: 0x%08x", hr);
+    }
+}
+
+int
+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, SDL_TRUE, &sprite_w, &sprite_h);
+        if (!sprites[i]) {
+            return -1;
+        }
+        if (SDL_SetTextureBlendMode(sprites[i], blendMode) < 0) {
+            SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't set blend mode: %s\n", SDL_GetError());
+            SDL_DestroyTexture(sprites[i]);
+            return -1;
+        }
+    }
+
+    /* We're ready to roll. :) */
+    return 0;
+}
+
+void
+DrawSprites(SDL_Renderer * renderer, SDL_Texture * sprite)
+{
+    SDL_Rect viewport, temp;
+
+    /* Query the sizes */
+    SDL_RenderGetViewport(renderer, &viewport);
+
+    /* Cycle the color and alpha, if desired */
+    if (cycle_color) {
+        current_color += cycle_direction;
+        if (current_color < 0) {
+            current_color = 0;
+            cycle_direction = -cycle_direction;
+        }
+        if (current_color > 255) {
+            current_color = 255;
+            cycle_direction = -cycle_direction;
+        }
+        SDL_SetTextureColorMod(sprite, 255, (Uint8) current_color,
+                               (Uint8) current_color);
+    }
+    if (cycle_alpha) {
+        current_alpha += cycle_direction;
+        if (current_alpha < 0) {
+            current_alpha = 0;
+            cycle_direction = -cycle_direction;
+        }
+        if (current_alpha > 255) {
+            current_alpha = 255;
+            cycle_direction = -cycle_direction;
+        }
+        SDL_SetTextureAlphaMod(sprite, (Uint8) current_alpha);
+    }
+
+    /* Draw a gray background */
+    SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF);
+    SDL_RenderClear(renderer);
+
+    /* Test points */
+    SDL_SetRenderDrawColor(renderer, 0xFF, 0x00, 0x00, 0xFF);
+    SDL_RenderDrawPoint(renderer, 0, 0);
+    SDL_RenderDrawPoint(renderer, viewport.w-1, 0);
+    SDL_RenderDrawPoint(renderer, 0, viewport.h-1);
+    SDL_RenderDrawPoint(renderer, viewport.w-1, viewport.h-1);
+
+    /* Test horizontal and vertical lines */
+    SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0xFF);
+    SDL_RenderDrawLine(renderer, 1, 0, viewport.w-2, 0);
+    SDL_RenderDrawLine(renderer, 1, viewport.h-1, viewport.w-2, viewport.h-1);
+    SDL_RenderDrawLine(renderer, 0, 1, 0, viewport.h-2);
+    SDL_RenderDrawLine(renderer, viewport.w-1, 1, viewport.w-1, viewport.h-2);
+
+    /* Test fill and copy */
+    SDL_SetRenderDrawColor(renderer, 0xFF, 0xFF, 0xFF, 0xFF);
+    temp.x = 1;
+    temp.y = 1;
+    temp.w = sprite_w;
+    temp.h = sprite_h;
+    SDL_RenderFillRect(renderer, &temp);
+    SDL_RenderCopy(renderer, sprite, NULL, &temp);
+    temp.x = viewport.w-sprite_w-1;
+    temp.y = 1;
+    temp.w = sprite_w;
+    temp.h = sprite_h;
+    SDL_RenderFillRect(renderer, &temp);
+    SDL_RenderCopy(renderer, sprite, NULL, &temp);
+    temp.x = 1;
+    temp.y = viewport.h-sprite_h-1;
+    temp.w = sprite_w;
+    temp.h = sprite_h;
+    SDL_RenderFillRect(renderer, &temp);
+    SDL_RenderCopy(renderer, sprite, NULL, &temp);
+    temp.x = viewport.w-sprite_w-1;
+    temp.y = viewport.h-sprite_h-1;
+    temp.w = sprite_w;
+    temp.h = sprite_h;
+    SDL_RenderFillRect(renderer, &temp);
+    SDL_RenderCopy(renderer, sprite, NULL, &temp);
+
+    /* Test diagonal lines */
+    SDL_SetRenderDrawColor(renderer, 0x00, 0xFF, 0x00, 0xFF);
+    SDL_RenderDrawLine(renderer, sprite_w, sprite_h,
+                       viewport.w-sprite_w-2, viewport.h-sprite_h-2);
+    SDL_RenderDrawLine(renderer, viewport.w-sprite_w-2, sprite_h,
+                       sprite_w, viewport.h-sprite_h-2);
+
+    /* Update the screen! */
+    SDL_RenderPresent(renderer);
+}
+
+void
+loop()
+{
+    int i;
+    SDL_Event event;
+
+    /* Check for events */
+    while (SDL_PollEvent(&event)) {
+        if (event.type == SDL_KEYDOWN && !event.key.repeat) {
+            SDL_Log("Initial SDL_KEYDOWN: %s", SDL_GetScancodeName(event.key.keysym.scancode));
+        }
+#if defined(__XBOXONE__) || defined(__XBOXSERIES__)
+        /* On Xbox, ignore the keydown event because the features aren't supported */
+        if (event.type != SDL_KEYDOWN) {
+            SDLTest_CommonEvent(state, &event, &done);
+        }
+#else
+        SDLTest_CommonEvent(state, &event, &done);
+#endif
+    }
+    for (i = 0; i < state->num_windows; ++i) {
+        if (state->windows[i] == NULL) {
+            continue;
+        }
+        DrawSprites(state->renderers[i], sprites[i]);
+    }
+}
+
+int
+main(int argc, char *argv[])
+{
+    int i;
+    const char *icon = "icon.bmp";
+    char *soundname = NULL;
+
+    /* Initialize parameters */
+    num_sprites = NUM_SPRITES;
+
+    /* Initialize test framework */
+    state = SDLTest_CommonCreateState(argv, SDL_INIT_VIDEO | SDL_INIT_AUDIO);
+    if (!state) {
+        return 1;
+    }
+
+    for (i = 1; i < argc;) {
+        int consumed;
+
+        consumed = SDLTest_CommonArg(state, i);
+        if (consumed == 0) {
+            consumed = -1;
+            if (SDL_strcasecmp(argv[i], "--blend") == 0) {
+                if (argv[i + 1]) {
+                    if (SDL_strcasecmp(argv[i + 1], "none") == 0) {
+                        blendMode = SDL_BLENDMODE_NONE;
+                        consumed = 2;
+                    } else if (SDL_strcasecmp(argv[i + 1], "blend") == 0) {
+                        blendMode = SDL_BLENDMODE_BLEND;
+                        consumed = 2;
+                    } else if (SDL_strcasecmp(argv[i + 1], "add") == 0) {
+                        blendMode = SDL_BLENDMODE_ADD;
+                        consumed = 2;
+                    } else if (SDL_strcasecmp(argv[i + 1], "mod") == 0) {
+                        blendMode = SDL_BLENDMODE_MOD;
+                        consumed = 2;
+                    } else if (SDL_strcasecmp(argv[i + 1], "sub") == 0) {
+                        blendMode = SDL_ComposeCustomBlendMode(SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_SUBTRACT, SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_SUBTRACT);
+                        consumed = 2;
+                    }
+                }
+            } else if (SDL_strcasecmp(argv[i], "--cyclecolor") == 0) {
+                cycle_color = SDL_TRUE;
+                consumed = 1;
+            } else if (SDL_strcasecmp(argv[i], "--cyclealpha") == 0) {
+                cycle_alpha = SDL_TRUE;
+                consumed = 1;
+            } else if (SDL_isdigit(*argv[i])) {
+                num_sprites = SDL_atoi(argv[i]);
+                consumed = 1;
+            } else if (argv[i][0] != '-') {
+                icon = argv[i];
+                consumed = 1;
+            }
+        }
+        if (consumed < 0) {
+            static const char *options[] = {
+                "[--blend none|blend|add|mod]",
+                "[--cyclecolor]",
+                "[--cyclealpha]",
+                "[num_sprites]",
+                "[icon.bmp]",
+                NULL };
+            SDLTest_CommonLogUsage(state, argv[0], options);
+            quit(1);
+        }
+        i += consumed;
+    }
+    if (!SDLTest_CommonInit(state)) {
+        quit(2);
+    }
+
+    /* Create the windows, initialize the renderers, and load the textures */
+    sprites =
+        (SDL_Texture **) SDL_malloc(state->num_windows * sizeof(*sprites));
+    if (!sprites) {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Out of memory!\n");
+        quit(2);
+    }
+    for (i = 0; i < state->num_windows; ++i) {
+        SDL_Renderer *renderer = state->renderers[i];
+        SDL_SetRenderDrawColor(renderer, 0xA0, 0xA0, 0xA0, 0xFF);
+        SDL_RenderClear(renderer);
+    }
+    if (LoadSprite(icon) < 0) {
+        quit(2);
+    }
+
+    soundname = GetResourceFilename(argc > 1 ? argv[1] : NULL, "sample.wav");
+
+    if (!soundname) {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "%s\n", SDL_GetError());
+        quit(1);
+    }
+
+    /* Load the wave file into memory */
+    if (SDL_LoadWAV(soundname, &wave.spec, &wave.sound, &wave.soundlen) == NULL) {
+        SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", soundname, SDL_GetError());
+        quit(1);
+    }
+
+    wave.spec.callback = fillerup;
+
+    /* Show the list of available drivers */
+    SDL_Log("Available audio drivers:");
+    for (i = 0; i < SDL_GetNumAudioDrivers(); ++i) {
+        SDL_Log("%i: %s", i, SDL_GetAudioDriver(i));
+    }
+
+    SDL_Log("Using audio driver: %s\n", SDL_GetCurrentAudioDriver());
+
+    open_audio();
+
+    /* Main render loop */
+    done = 0;
+
+    /* Try to add the default user silently */
+    AddUserSilent();
+
+    while (!done) {
+        loop();
+    }
+
+    quit(0);
+
+    SDL_free(soundname);
+    return 0;
+}
+
+/* vi: set ts=4 sw=4 expandtab: */

+ 34 - 0
Engine/lib/sdl/VisualC-GDK/tests/testgdk/wingdk/MicrosoftGame.config

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Game configVersion="1">
+
+	<!-- Set these to the correct identifiers from Partner Center -->
+	<Identity Name="SDL"
+		Version="1.0.0.0"
+		Publisher="CN=Publisher"/>
+
+	<ExecutableList>
+		<Executable Name="testgdk.exe"
+					TargetDeviceFamily="PC"
+					Id="Game" />
+	</ExecutableList>
+
+	<DesktopRegistration>
+		<DependencyList>
+			<KnownDependency Name="VC14"/>
+		</DependencyList>
+	</DesktopRegistration>
+
+	<!-- Set these to the correct values from Partner Center -->
+	<MSAAppId>PleaseChangeMe</MSAAppId>
+	<TitleId>FFFFFFFF</TitleId>
+
+	<ShellVisuals DefaultDisplayName="testgdk"
+					PublisherDisplayName="SDL"
+					Square480x480Logo="Logo480x480.png"
+					Square150x150Logo="Logo150x150.png"
+					Square44x44Logo="Logo44x44.png"
+					Description="testgdk"
+					ForegroundText="light"
+					BackgroundColor="#000000"
+					StoreLogo="Logo100x100.png"/>
+</Game>

+ 29 - 0
Engine/lib/sdl/VisualC-GDK/tests/testgdk/xboxone/MicrosoftGame.config

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Game configVersion="1">
+
+	<!-- Set these to the correct identifiers from Partner Center -->
+	<Identity Name="SDL"
+		Version="1.0.0.0"
+		Publisher="CN=Publisher"/>
+
+	<ExecutableList>
+		<Executable Name="testgdk.exe"
+					TargetDeviceFamily="XboxOne"
+					Id="Game" />
+	</ExecutableList>
+
+	<!-- Set these to the correct values from Partner Center -->
+	<MSAAppId>PleaseChangeMe</MSAAppId>
+	<TitleId>FFFFFFFF</TitleId>
+
+	<ShellVisuals DefaultDisplayName="testgdk"
+					PublisherDisplayName="SDL"
+					Square480x480Logo="Logo480x480.png"
+					Square150x150Logo="Logo150x150.png"
+					Square44x44Logo="Logo44x44.png"
+					SplashScreenImage="SplashScreenImage.png"
+					Description="testgdk"
+					ForegroundText="light"
+					BackgroundColor="#000000"
+					StoreLogo="Logo100x100.png"/>
+</Game>

+ 29 - 0
Engine/lib/sdl/VisualC-GDK/tests/testgdk/xboxseries/MicrosoftGame.config

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Game configVersion="1">
+
+	<!-- Set these to the correct identifiers from Partner Center -->
+	<Identity Name="SDL"
+		Version="1.0.0.0"
+		Publisher="CN=Publisher"/>
+
+	<ExecutableList>
+		<Executable Name="testgdk.exe"
+					TargetDeviceFamily="Scarlett"
+					Id="Game" />
+	</ExecutableList>
+
+	<!-- Set these to the correct values from Partner Center -->
+	<MSAAppId>PleaseChangeMe</MSAAppId>
+	<TitleId>FFFFFFFF</TitleId>
+
+	<ShellVisuals DefaultDisplayName="testgdk"
+					PublisherDisplayName="SDL"
+					Square480x480Logo="Logo480x480.png"
+					Square150x150Logo="Logo150x150.png"
+					Square44x44Logo="Logo44x44.png"
+					SplashScreenImage="SplashScreenImage.png"
+					Description="testgdk"
+					ForegroundText="light"
+					BackgroundColor="#000000"
+					StoreLogo="Logo100x100.png"/>
+</Game>

+ 9 - 0
Engine/lib/sdl/VisualC-GDK/tests/testsprite2/PackageLayout.xml

@@ -0,0 +1,9 @@
+<Package>
+  <Chunk Id="1000" Marker="Launch">
+    <FileGroup DestinationPath="." SourcePath="." Include="testsprite2.exe" />
+    <FileGroup DestinationPath="." SourcePath="." Include="MicrosoftGame.config" />
+    <FileGroup DestinationPath="." SourcePath="." Include="*.bmp" />
+    <FileGroup DestinationPath="." SourcePath="." Include="*.png" />
+    <FileGroup DestinationPath="." SourcePath="." Include="*.dll" />
+  </Chunk>
+</Package>

+ 34 - 0
Engine/lib/sdl/VisualC-GDK/tests/testsprite2/wingdk/MicrosoftGame.config

@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Game configVersion="1">
+
+	<!-- Set these to the correct identifiers from Partner Center -->
+	<Identity Name="SDL"
+		Version="1.0.0.0"
+		Publisher="CN=Publisher"/>
+
+	<ExecutableList>
+		<Executable Name="testsprite2.exe"
+					TargetDeviceFamily="PC"
+					Id="Game" />
+	</ExecutableList>
+
+	<DesktopRegistration>
+		<DependencyList>
+			<KnownDependency Name="VC14"/>
+		</DependencyList>
+	</DesktopRegistration>
+
+	<!-- Set these to the correct values from Partner Center -->
+	<MSAAppId>PleaseChangeMe</MSAAppId>
+	<TitleId>FFFFFFFF</TitleId>
+
+	<ShellVisuals DefaultDisplayName="testsprite2"
+					PublisherDisplayName="SDL"
+					Square480x480Logo="Logo480x480.png"
+					Square150x150Logo="Logo150x150.png"
+					Square44x44Logo="Logo44x44.png"
+					Description="testsprite2"
+					ForegroundText="light"
+					BackgroundColor="#000000"
+					StoreLogo="Logo100x100.png"/>
+</Game>

+ 29 - 0
Engine/lib/sdl/VisualC-GDK/tests/testsprite2/xboxone/MicrosoftGame.config

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Game configVersion="1">
+
+	<!-- Set these to the correct identifiers from Partner Center -->
+	<Identity Name="SDL"
+		Version="1.0.0.0"
+		Publisher="CN=Publisher"/>
+
+	<ExecutableList>
+		<Executable Name="testsprite2.exe"
+					TargetDeviceFamily="XboxOne"
+					Id="Game" />
+	</ExecutableList>
+
+	<!-- Set these to the correct values from Partner Center -->
+	<MSAAppId>PleaseChangeMe</MSAAppId>
+	<TitleId>FFFFFFFF</TitleId>
+
+	<ShellVisuals DefaultDisplayName="testsprite2"
+					PublisherDisplayName="SDL"
+					Square480x480Logo="Logo480x480.png"
+					Square150x150Logo="Logo150x150.png"
+					Square44x44Logo="Logo44x44.png"
+					SplashScreenImage="SplashScreenImage.png"
+					Description="testsprite2"
+					ForegroundText="light"
+					BackgroundColor="#000000"
+					StoreLogo="Logo100x100.png"/>
+</Game>

+ 29 - 0
Engine/lib/sdl/VisualC-GDK/tests/testsprite2/xboxseries/MicrosoftGame.config

@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Game configVersion="1">
+
+	<!-- Set these to the correct identifiers from Partner Center -->
+	<Identity Name="SDL"
+		Version="1.0.0.0"
+		Publisher="CN=Publisher"/>
+
+	<ExecutableList>
+		<Executable Name="testsprite2.exe"
+					TargetDeviceFamily="Scarlett"
+					Id="Game" />
+	</ExecutableList>
+
+	<!-- Set these to the correct values from Partner Center -->
+	<MSAAppId>PleaseChangeMe</MSAAppId>
+	<TitleId>FFFFFFFF</TitleId>
+
+	<ShellVisuals DefaultDisplayName="testsprite2"
+					PublisherDisplayName="SDL"
+					Square480x480Logo="Logo480x480.png"
+					Square150x150Logo="Logo150x150.png"
+					Square44x44Logo="Logo44x44.png"
+					Description="testsprite2"
+					SplashScreenImage="SplashScreenImage.png"
+					ForegroundText="light"
+					BackgroundColor="#000000"
+					StoreLogo="Logo100x100.png"/>
+</Game>

+ 5 - 3
Engine/lib/sdl/VisualC/pkg-support/cmake/sdl2-config.cmake

@@ -1,7 +1,7 @@
 # SDL2 CMake configuration file:
 # This file is meant to be placed in a cmake subfolder of SDL2-devel-2.x.y-VC
 
-cmake_minimum_required(VERSION 3.0...3.5)
+cmake_minimum_required(VERSION 3.0...3.28)
 
 include(FeatureSummary)
 set_package_properties(SDL2 PROPERTIES
@@ -79,6 +79,8 @@ endif()
 unset(_sdl2_library)
 unset(_sdl2_dll_library)
 
+set(SDL2_SDL2-static_FOUND FALSE)
+
 set(_sdl2main_library "${SDL2_LIBDIR}/SDL2main.lib")
 if(EXISTS "${_sdl2main_library}")
     if(NOT TARGET SDL2::SDL2main)
@@ -92,7 +94,7 @@ if(EXISTS "${_sdl2main_library}")
     endif()
     set(SDL2_SDL2main_FOUND TRUE)
 else()
-    set(SDL2_SDL2_FOUND FALSE)
+    set(SDL2_SDL2main_FOUND FALSE)
 endif()
 unset(_sdl2main_library)
 
@@ -110,7 +112,7 @@ if(EXISTS "${_sdl2test_library}")
     endif()
     set(SDL2_SDL2test_FOUND TRUE)
 else()
-    set(SDL2_SDL2_FOUND FALSE)
+    set(SDL2_SDL2test_FOUND FALSE)
 endif()
 unset(_sdl2test_library)
 

+ 19 - 0
Engine/lib/sdl/WhatsNew.txt

@@ -1,9 +1,28 @@
 
 This is a list of major changes in SDL's version history.
 
+---------------------------------------------------------------------------
+2.30.0:
+---------------------------------------------------------------------------
+
+General:
+* Added support for 2 bits-per-pixel indexed surface formats
+* Added the function SDL_GameControllerGetSteamHandle() to get the Steam API handle for a controller, if available
+* Added the event SDL_CONTROLLERSTEAMHANDLEUPDATED which is sent when the Steam API handle for a controller changes. This could also change the name, VID, and PID of the controller.
+* Added the environment variable SDL_LOGGING to control default log output
+
+macOS:
+* Added the hint SDL_HINT_JOYSTICK_IOKIT to control whether the IOKit controller driver should be used
+* Added the hint SDL_HINT_JOYSTICK_MFI to control whether the GCController controller driver should be used
+* Added the hint SDL_HINT_RENDER_METAL_PREFER_LOW_POWER_DEVICE to choose whether high or low power GPU should be used for rendering, in the case where there are multiple GPUs available
+
+Xbox:
+* Added the function SDL_GDKGetDefaultUser()
+
 ---------------------------------------------------------------------------
 2.28.2:
 ---------------------------------------------------------------------------
+
 General:
 * Added the hint SDL_HINT_JOYSTICK_WGI to control whether to use Windows.Gaming.Input for controllers
 

+ 5 - 5
Engine/lib/sdl/Xcode-iOS/Demos/src/accelerometer.c

@@ -118,7 +118,7 @@ initializeTextures(SDL_Renderer *renderer)
 
     /* load the ship */
     bmp_surface = SDL_LoadBMP("ship.bmp");
-    if (bmp_surface == NULL) {
+    if (!bmp_surface) {
         fatalError("could not ship.bmp");
     }
     /* set blue to transparent on the ship */
@@ -127,7 +127,7 @@ initializeTextures(SDL_Renderer *renderer)
 
     /* create ship texture from surface */
     ship = SDL_CreateTextureFromSurface(renderer, bmp_surface);
-    if (ship == NULL) {
+    if (!ship) {
         fatalError("could not create ship texture");
     }
     SDL_SetTextureBlendMode(ship, SDL_BLENDMODE_BLEND);
@@ -140,12 +140,12 @@ initializeTextures(SDL_Renderer *renderer)
 
     /* load the space background */
     bmp_surface = SDL_LoadBMP("space.bmp");
-    if (bmp_surface == NULL) {
+    if (!bmp_surface) {
         fatalError("could not load space.bmp");
     }
     /* create space texture from surface */
     space = SDL_CreateTextureFromSurface(renderer, bmp_surface);
-    if (space == NULL) {
+    if (!space) {
         fatalError("could not create space texture");
     }
     SDL_FreeSurface(bmp_surface);
@@ -179,7 +179,7 @@ main(int argc, char *argv[])
     printf("There are %d joysticks available\n", SDL_NumJoysticks());
     printf("Default joystick (index 0) is %s\n", SDL_JoystickName(0));
     accelerometer = SDL_JoystickOpen(0);
-    if (accelerometer == NULL) {
+    if (!accelerometer) {
         fatalError("Could not open joystick (accelerometer)");
     }
     printf("joystick number of axis = %d\n",

+ 5 - 5
Engine/lib/sdl/Xcode-iOS/Demos/src/fireworks.c

@@ -52,9 +52,9 @@ void spawnTrailFromEmitter(struct particle *emitter);
 void spawnEmitterParticle(GLfloat x, GLfloat y);
 void explodeEmitter(struct particle *emitter);
 void initializeParticles(void);
-void initializeTexture();
+void initializeTexture(void);
 int nextPowerOfTwo(int x);
-void drawParticles();
+void drawParticles(void);
 void stepParticles(double deltaTime);
 
 /*  helper function (used in texture loading)
@@ -159,7 +159,7 @@ stepParticles(double deltaTime)
     This draws all the particles shown on screen
 */
 void
-drawParticles()
+drawParticles(void)
 {
 
     /* draw the background */
@@ -324,7 +324,7 @@ initializeParticles(void)
     loads the particle texture
  */
 void
-initializeTexture()
+initializeTexture(void)
 {
 
     int bpp;                    /* texture bits per pixel */
@@ -334,7 +334,7 @@ initializeTexture()
                                            to format passed into OpenGL */
 
     bmp_surface = SDL_LoadBMP("stroke.bmp");
-    if (bmp_surface == NULL) {
+    if (!bmp_surface) {
         fatalError("could not load stroke.bmp");
     }
 

+ 2 - 2
Engine/lib/sdl/Xcode-iOS/Demos/src/happy.c

@@ -108,7 +108,7 @@ initializeTexture(SDL_Renderer *renderer)
     SDL_Surface *bmp_surface;
     /* load the bmp */
     bmp_surface = SDL_LoadBMP("icon.bmp");
-    if (bmp_surface == NULL) {
+    if (!bmp_surface) {
         fatalError("could not load bmp");
     }
     /* set white to transparent on the happyface */
@@ -117,7 +117,7 @@ initializeTexture(SDL_Renderer *renderer)
 
     /* convert RGBA surface to texture */
     texture = SDL_CreateTextureFromSurface(renderer, bmp_surface);
-    if (texture == NULL) {
+    if (!texture) {
         fatalError("could not create texture");
     }
     SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);

+ 3 - 3
Engine/lib/sdl/Xcode-iOS/Demos/src/keyboard.c

@@ -165,7 +165,7 @@ loadFont(void)
 {
     SDL_Surface *surface = SDL_LoadBMP("kromasky_16x16.bmp");
 
-    if (surface == NULL) {
+    if (!surface) {
         printf("Error loading bitmap: %s\n", SDL_GetError());
         return 0;
     } else {
@@ -183,7 +183,7 @@ loadFont(void)
         SDL_BlitSurface(surface, NULL, converted, NULL);
         /* create our texture */
         texture = SDL_CreateTextureFromSurface(renderer, converted);
-        if (texture == NULL) {
+        if (!texture) {
             printf("texture creation failed: %s\n", SDL_GetError());
         } else {
             /* set blend mode for our texture */
@@ -196,7 +196,7 @@ loadFont(void)
 }
 
 void
-draw()
+draw(void)
 {
     SDL_SetRenderDrawColor(renderer, bg_color.r, bg_color.g, bg_color.b, bg_color.a);
     SDL_RenderClear(renderer);

+ 2 - 2
Engine/lib/sdl/Xcode-iOS/Demos/src/rectangles.c

@@ -58,11 +58,11 @@ main(int argc, char *argv[])
 
     /* create window and renderer */
     window = SDL_CreateWindow(NULL, 0, 0, 320, 480, SDL_WINDOW_ALLOW_HIGHDPI);
-    if (window == NULL) {
+    if (!window) {
         fatalError("Could not initialize Window");
     }
     renderer = SDL_CreateRenderer(window, -1, 0);
-    if (renderer == NULL) {
+    if (!renderer) {
         fatalError("Could not create renderer");
     }
 

+ 2 - 2
Engine/lib/sdl/Xcode-iOS/Demos/src/touch.c

@@ -57,13 +57,13 @@ initializeTexture(SDL_Renderer *renderer)
 {
     SDL_Surface *bmp_surface;
     bmp_surface = SDL_LoadBMP("stroke.bmp");
-    if (bmp_surface == NULL) {
+    if (!bmp_surface) {
         fatalError("could not load stroke.bmp");
     }
     brush =
         SDL_CreateTextureFromSurface(renderer, bmp_surface);
     SDL_FreeSurface(bmp_surface);
-    if (brush == NULL) {
+    if (!brush) {
         fatalError("could not create brush texture");
     }
     /* additive blending -- laying strokes on top of eachother makes them brighter */

+ 2 - 2
Engine/lib/sdl/Xcode/SDL/Info-Framework.plist

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

Diff do ficheiro suprimidas por serem muito extensas
+ 220 - 68
Engine/lib/sdl/Xcode/SDL/SDL.xcodeproj/project.pbxproj


+ 1 - 1
Engine/lib/sdl/Xcode/SDL/pkg-support/SDL.info

@@ -1,4 +1,4 @@
-Title SDL 2.28.4
+Title SDL 2.32.6
 Version 1
 Description SDL Library for Mac OS X (http://www.libsdl.org)
 DefaultLocation /Library/Frameworks

+ 12 - 5
Engine/lib/sdl/Xcode/SDL/pkg-support/resources/CMake/sdl2-config.cmake

@@ -31,8 +31,15 @@ endmacro()
 
 set(SDL2_FOUND TRUE)
 
-string(REGEX REPLACE "SDL2\\.framework.*" "SDL2.framework" SDL2_FRAMEWORK_PATH "${CMAKE_CURRENT_LIST_DIR}")
-string(REGEX REPLACE "SDL2\\.framework.*" "" SDL2_FRAMEWORK_PARENT_PATH "${CMAKE_CURRENT_LIST_DIR}")
+# Compute the installation prefix relative to this file.
+set(SDL2_FRAMEWORK_PATH "${CMAKE_CURRENT_LIST_DIR}")                                # > /SDL2.framework/Resources/CMake/
+get_filename_component(SDL2_FRAMEWORK_PATH "${SDL2_FRAMEWORK_PATH}" REALPATH)       # > /SDL2.framework/Versions/Current/Resources/CMake
+get_filename_component(SDL2_FRAMEWORK_PATH "${SDL2_FRAMEWORK_PATH}" REALPATH)       # > /SDL2.framework/Versions/A/Resources/CMake/
+get_filename_component(SDL2_FRAMEWORK_PATH "${SDL2_FRAMEWORK_PATH}" PATH)           # > /SDL2.framework/Versions/A/Resources/
+get_filename_component(SDL2_FRAMEWORK_PATH "${SDL2_FRAMEWORK_PATH}" PATH)           # > /SDL2.framework/Versions/A/
+get_filename_component(SDL2_FRAMEWORK_PATH "${SDL2_FRAMEWORK_PATH}" PATH)           # > /SDL2.framework/Versions/
+get_filename_component(SDL2_FRAMEWORK_PATH "${SDL2_FRAMEWORK_PATH}" PATH)           # > /SDL2.framework/
+get_filename_component(SDL2_FRAMEWORK_PARENT_PATH "${SDL2_FRAMEWORK_PATH}" PATH)    # > /
 
 # For compatibility with autotools sdl2-config.cmake, provide SDL2_* variables.
 
@@ -49,12 +56,12 @@ set(SDL2_LIBRARIES "SDL2::SDL2")
 # This is done for compatibility with CMake generated SDL2-target.cmake files.
 
 if(NOT TARGET SDL2::SDL2)
-    add_library(SDL2::SDL2 INTERFACE IMPORTED)
+    add_library(SDL2::SDL2 SHARED IMPORTED)
     set_target_properties(SDL2::SDL2
         PROPERTIES
-            INTERFACE_COMPILE_OPTIONS "SHELL:-F \"${SDL2_FRAMEWORK_PARENT_PATH}\""
+            FRAMEWORK "TRUE"
+            IMPORTED_LOCATION "${SDL2_FRAMEWORK_PATH}/Versions/A/SDL2"
             INTERFACE_INCLUDE_DIRECTORIES "${SDL2_INCLUDE_DIRS}"
-            INTERFACE_LINK_OPTIONS "SHELL:-F \"${SDL2_FRAMEWORK_PARENT_PATH}\";SHELL:-framework SDL2"
             COMPATIBLE_INTERFACE_BOOL "SDL2_SHARED"
             INTERFACE_SDL2_SHARED "ON"
             COMPATIBLE_INTERFACE_STRING "SDL_VERSION"

+ 1 - 1
Engine/lib/sdl/Xcode/SDL/pkg-support/resources/License.txt

@@ -1,6 +1,6 @@
 
 Simple DirectMedia Layer
-Copyright (C) 1997-2023 Sam Lantinga <[email protected]>
+Copyright (C) 1997-2025 Sam Lantinga <[email protected]>
   
 This software is provided 'as-is', without any express or implied
 warranty.  In no event will the authors be held liable for any damages

Diff do ficheiro suprimidas por serem muito extensas
+ 685 - 43
Engine/lib/sdl/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj


+ 88 - 75
Engine/lib/sdl/acinclude/libtool.m4

@@ -219,8 +219,8 @@ esac
 ofile=libtool
 can_build_shared=yes
 
-# All known linkers require a '.a' archive for static linking (except MSVC,
-# which needs '.lib').
+# All known linkers require a '.a' archive for static linking (except MSVC and
+# ICC, which need '.lib').
 libext=a
 
 with_gnu_ld=$lt_cv_prog_gnu_ld
@@ -1023,6 +1023,21 @@ m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
 	rm -f conftest.*
       fi])
 
+    # Feature test to disable chained fixups since it is not
+    # compatible with '-undefined dynamic_lookup'
+    AC_CACHE_CHECK([for -no_fixup_chains linker flag],
+      [lt_cv_support_no_fixup_chains],
+      [ save_LDFLAGS=$LDFLAGS
+        LDFLAGS="$LDFLAGS -Wl,-no_fixup_chains"
+        AC_LINK_IFELSE(
+          [AC_LANG_PROGRAM([],[])],
+          lt_cv_support_no_fixup_chains=yes,
+          lt_cv_support_no_fixup_chains=no
+        )
+        LDFLAGS=$save_LDFLAGS
+      ]
+    )
+
     AC_CACHE_CHECK([for -exported_symbols_list linker flag],
       [lt_cv_ld_exported_symbols_list],
       [lt_cv_ld_exported_symbols_list=no
@@ -1047,7 +1062,7 @@ _LT_EOF
       echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
       $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
       cat > conftest.c << _LT_EOF
-int main() { return 0;}
+int main(void) { return 0;}
 _LT_EOF
       echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
       $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
@@ -1072,7 +1087,12 @@ _LT_EOF
         10.[[012]],*|,*powerpc*-darwin[[5-8]]*)
           _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
         *)
-          _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
+          if test yes = "$lt_cv_support_no_fixup_chains"; then
+            _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup $wl-no_fixup_chains'
+          else
+            _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup'
+          fi
+        ;;
       esac
     ;;
   esac
@@ -1365,7 +1385,7 @@ mips64*-*linux*)
   ;;
 
 x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
-s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*|x86_64-gnu*)
   # Find out what ABI is being produced by ac_compile, and set linker
   # options accordingly.  Note that the listed cases only cover the
   # situations where additional linker options are needed (such as when
@@ -1380,7 +1400,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
 	  x86_64-*kfreebsd*-gnu)
 	    LD="${LD-ld} -m elf_i386_fbsd"
 	    ;;
-	  x86_64-*linux*)
+	  x86_64-*linux*|x86_64-gnu*)
 	    case `/usr/bin/file conftest.o` in
 	      *x86-64*)
 		LD="${LD-ld} -m elf32_x86_64"
@@ -1409,7 +1429,7 @@ s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
 	  x86_64-*kfreebsd*-gnu)
 	    LD="${LD-ld} -m elf_x86_64_fbsd"
 	    ;;
-	  x86_64-*linux*)
+	  x86_64-*linux*|x86_64-gnu*)
 	    LD="${LD-ld} -m elf_x86_64"
 	    ;;
 	  powerpcle-*linux*|powerpc64le-*linux*)
@@ -1540,15 +1560,8 @@ old_postinstall_cmds='chmod 644 $oldlib'
 old_postuninstall_cmds=
 
 if test -n "$RANLIB"; then
-  case $host_os in
-  bitrig* | openbsd*)
-    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
-    ;;
-  *)
-    old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
-    ;;
-  esac
   old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+  old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
 fi
 
 case $host_os in
@@ -1687,7 +1700,7 @@ AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
     lt_cv_sys_max_cmd_len=-1;
     ;;
 
-  cygwin* | mingw* | cegcc*)
+  cygwin* | mingw* | windows* | cegcc*)
     # On Win9x/ME, this test blows up -- it succeeds, but takes
     # about 5 minutes as the teststring grows exponentially.
     # Worse, since 9x/ME are not pre-emptively multitasking,
@@ -1869,11 +1882,11 @@ else
 /* When -fvisibility=hidden is used, assume the code has been annotated
    correspondingly for the symbols needed.  */
 #if defined __GNUC__ && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
-int fnord () __attribute__((visibility("default")));
+int fnord (void) __attribute__((visibility("default")));
 #endif
 
-int fnord () { return 42; }
-int main ()
+int fnord (void) { return 42; }
+int main (void)
 {
   void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
   int status = $lt_dlunknown;
@@ -1930,7 +1943,7 @@ else
     lt_cv_dlopen_self=yes
     ;;
 
-  mingw* | pw32* | cegcc*)
+  mingw* | windows* | pw32* | cegcc*)
     lt_cv_dlopen=LoadLibrary
     lt_cv_dlopen_libs=
     ;;
@@ -2298,7 +2311,7 @@ if test yes = "$GCC"; then
     *) lt_awk_arg='/^libraries:/' ;;
   esac
   case $host_os in
-    mingw* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;;
+    mingw* | windows* | cegcc*) lt_sed_strip_eq='s|=\([[A-Za-z]]:\)|\1|g' ;;
     *) lt_sed_strip_eq='s|=/|/|g' ;;
   esac
   lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
@@ -2356,7 +2369,7 @@ BEGIN {RS = " "; FS = "/|\n";} {
   # AWK program above erroneously prepends '/' to C:/dos/paths
   # for these hosts.
   case $host_os in
-    mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+    mingw* | windows* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
       $SED 's|/\([[A-Za-z]]:\)|\1|g'` ;;
   esac
   sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
@@ -2525,7 +2538,7 @@ bsdi[[45]]*)
   # libtool to hard-code these into programs
   ;;
 
-cygwin* | mingw* | pw32* | cegcc*)
+cygwin* | mingw* | windows* | pw32* | cegcc*)
   version_type=windows
   shrext_cmds=.dll
   need_version=no
@@ -2554,14 +2567,14 @@ cygwin* | mingw* | pw32* | cegcc*)
     cygwin*)
       # Cygwin DLLs use 'cyg' prefix rather than 'lib'
       #soname_spec='`echo $libname | sed -e 's/^lib/cyg/'``echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
-      soname_spec='`echo $libname | sed -e 's/^lib//'`$shared_ext' # SDL customization
+      soname_spec='`echo $libname | sed -e 's/^lib//'`$shared_ext' # SDL customization.
 m4_if([$1], [],[
       sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
       ;;
-    mingw* | cegcc*)
+    mingw* | windows* | cegcc*)
       # MinGW DLLs use traditional 'lib' prefix
       #soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
-      soname_spec='`echo $libname | $SED -e 's/^lib//'`$shared_ext' # SDL customization
+      soname_spec='`echo $libname | $SED -e 's/^lib//'`$shared_ext' # SDL customization.
       ;;
     pw32*)
       # pw32 DLLs use 'pw' prefix rather than 'lib'
@@ -2571,14 +2584,14 @@ m4_if([$1], [],[
     dynamic_linker='Win32 ld.exe'
     ;;
 
-  *,cl*)
-    # Native MSVC
+  *,cl* | *,icl*)
+    # Native MSVC or ICC
     libname_spec='$name'
     soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
     library_names_spec='$libname.dll.lib'
 
     case $build_os in
-    mingw*)
+    mingw* | windows*)
       sys_lib_search_path_spec=
       lt_save_ifs=$IFS
       IFS=';'
@@ -2628,7 +2641,7 @@ m4_if([$1], [],[
     ;;
 
   *)
-    # Assume MSVC wrapper
+    # Assume MSVC and ICC wrapper
     library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib'
     dynamic_linker='Win32 ld.exe'
     ;;
@@ -3267,7 +3280,7 @@ if test yes = "$GCC"; then
   # Check if gcc -print-prog-name=ld gives a path.
   AC_MSG_CHECKING([for ld used by $CC])
   case $host in
-  *-*-mingw*)
+  *-*-mingw* | *-*-windows*)
     # gcc leaves a trailing carriage return, which upsets mingw
     ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
   *)
@@ -3376,7 +3389,7 @@ case $reload_flag in
 esac
 reload_cmds='$LD$reload_flag -o $output$reload_objs'
 case $host_os in
-  cygwin* | mingw* | pw32* | cegcc*)
+  cygwin* | mingw* | windows* | pw32* | cegcc*)
     if test yes != "$GCC"; then
       reload_cmds=false
     fi
@@ -3473,10 +3486,10 @@ cygwin*)
   # func_win32_libid is a shell function defined in ltmain.sh
   lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
   lt_cv_file_magic_cmd='func_win32_libid'
-  lt_cv_deplibs_check_method=pass_all # SDL customization
+  lt_cv_deplibs_check_method=pass_all # SDL customization.
   ;;
 
-mingw* | pw32*)
+mingw* | windows* | pw32*)
   # Base MSYS/MinGW do not provide the 'file' command needed by
   # func_win32_libid shell function, so use a weaker test based on 'objdump',
   # unless we find 'file', for example because we are cross-compiling.
@@ -3485,10 +3498,10 @@ mingw* | pw32*)
     lt_cv_file_magic_cmd='func_win32_libid'
   else
     # Keep this pattern in sync with the one in func_win32_libid.
-    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+    lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64|pe-aarch64)'
     lt_cv_file_magic_cmd='$OBJDUMP -f'
   fi
-  lt_cv_deplibs_check_method=pass_all # SDL customization
+  lt_cv_deplibs_check_method=pass_all # SDL customization.
   ;;
 
 cegcc*)
@@ -3641,7 +3654,7 @@ file_magic_glob=
 want_nocaseglob=no
 if test "$build" = "$host"; then
   case $host_os in
-  mingw* | pw32*)
+  mingw* | windows* | pw32*)
     if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
       want_nocaseglob=yes
     else
@@ -3693,7 +3706,7 @@ else
 	# Tru64's nm complains that /dev/null is an invalid object file
 	# MSYS converts /dev/null to NUL, MinGW nm treats NUL as empty
 	case $build_os in
-	mingw*) lt_bad_file=conftest.nm/nofile ;;
+	mingw* | windows*) lt_bad_file=conftest.nm/nofile ;;
 	*) lt_bad_file=/dev/null ;;
 	esac
 	case `"$tmp_nm" -B $lt_bad_file 2>&1 | sed '1q'` in
@@ -3784,7 +3797,7 @@ lt_cv_sharedlib_from_linklib_cmd,
 [lt_cv_sharedlib_from_linklib_cmd='unknown'
 
 case $host_os in
-cygwin* | mingw* | pw32* | cegcc*)
+cygwin* | mingw* | windows* | pw32* | cegcc*)
   # two different shell functions defined in ltmain.sh;
   # decide which one to use based on capabilities of $DLLTOOL
   case `$DLLTOOL --help 2>&1` in
@@ -3929,7 +3942,7 @@ case $host_os in
 aix*)
   symcode='[[BCDT]]'
   ;;
-cygwin* | mingw* | pw32* | cegcc*)
+cygwin* | mingw* | windows* | pw32* | cegcc*)
   symcode='[[ABCDGISTW]]'
   ;;
 hpux*)
@@ -4008,7 +4021,7 @@ $lt_c_name_lib_hook\
 # Handle CRLF in mingw tool chain
 opt_cr=
 case $build_os in
-mingw*)
+mingw* | windows*)
   opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
   ;;
 esac
@@ -4023,7 +4036,7 @@ for ac_symprfx in "" "_"; do
   if test "$lt_cv_nm_interface" = "MS dumpbin"; then
     # Fake it for dumpbin and say T for any non-static function,
     # D for any global variable and I for any imported variable.
-    # Also find C++ and __fastcall symbols from MSVC++,
+    # Also find C++ and __fastcall symbols from MSVC++ or ICC,
     # which start with @ or ?.
     lt_cv_sys_global_symbol_pipe="$AWK ['"\
 "     {last_section=section; section=\$ 3};"\
@@ -4059,7 +4072,7 @@ void nm_test_func(void){}
 #ifdef __cplusplus
 }
 #endif
-int main(){nm_test_var='a';nm_test_func();return(0);}
+int main(void){nm_test_var='a';nm_test_func();return(0);}
 _LT_EOF
 
   if AC_TRY_EVAL(ac_compile); then
@@ -4235,7 +4248,7 @@ m4_if([$1], [CXX], [
     beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
       # PIC is the default for these OSes.
       ;;
-    mingw* | cygwin* | os2* | pw32* | cegcc*)
+    mingw* | windows* | cygwin* | os2* | pw32* | cegcc*)
       # This hack is so that the source file can tell whether it is being
       # built for inclusion in a dll (and should export symbols for example).
       # Although the cygwin gcc ignores -fPIC, still need this for old-style
@@ -4311,7 +4324,7 @@ m4_if([$1], [CXX], [
 	  ;;
 	esac
 	;;
-      mingw* | cygwin* | os2* | pw32* | cegcc*)
+      mingw* | windows* | cygwin* | os2* | pw32* | cegcc*)
 	# This hack is so that the source file can tell whether it is being
 	# built for inclusion in a dll (and should export symbols for example).
 	m4_if([$1], [GCJ], [],
@@ -4559,7 +4572,7 @@ m4_if([$1], [CXX], [
       # PIC is the default for these OSes.
       ;;
 
-    mingw* | cygwin* | pw32* | os2* | cegcc*)
+    mingw* | windows* | cygwin* | pw32* | os2* | cegcc*)
       # This hack is so that the source file can tell whether it is being
       # built for inclusion in a dll (and should export symbols for example).
       # Although the cygwin gcc ignores -fPIC, still need this for old-style
@@ -4663,7 +4676,7 @@ m4_if([$1], [CXX], [
       esac
       ;;
 
-    mingw* | cygwin* | pw32* | os2* | cegcc*)
+    mingw* | windows* | cygwin* | pw32* | os2* | cegcc*)
       # This hack is so that the source file can tell whether it is being
       # built for inclusion in a dll (and should export symbols for example).
       m4_if([$1], [GCJ], [],
@@ -4938,9 +4951,9 @@ m4_if([$1], [CXX], [
   pw32*)
     _LT_TAGVAR(export_symbols_cmds, $1)=$ltdll_cmds
     ;;
-  cygwin* | mingw* | cegcc*)
+  cygwin* | mingw* | windows* | cegcc*)
     case $cc_basename in
-    cl*)
+    cl* | icl*)
       _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
       ;;
     *)
@@ -4996,16 +5009,16 @@ dnl Note also adjust exclude_expsyms for C++ above.
   extract_expsyms_cmds=
 
   case $host_os in
-  cygwin* | mingw* | pw32* | cegcc*)
-    # FIXME: the MSVC++ port hasn't been tested in a loooong time
+  cygwin* | mingw* | windows* | pw32* | cegcc*)
+    # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time
     # When not using gcc, we currently assume that we are using
-    # Microsoft Visual C++.
+    # Microsoft Visual C++ or Intel C++ Compiler.
     if test yes != "$GCC"; then
       with_gnu_ld=no
     fi
     ;;
   interix*)
-    # we just hope/assume this is gcc and not c89 (= MSVC++)
+    # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC)
     with_gnu_ld=yes
     ;;
   openbsd* | bitrig*)
@@ -5111,7 +5124,7 @@ _LT_EOF
       fi
       ;;
 
-    cygwin* | mingw* | pw32* | cegcc*)
+    cygwin* | mingw* | windows* | pw32* | cegcc*)
       # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
       # as there is no search path for DLLs.
       _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
@@ -5568,14 +5581,14 @@ _LT_EOF
       _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
       ;;
 
-    cygwin* | mingw* | pw32* | cegcc*)
+    cygwin* | mingw* | windows* | pw32* | cegcc*)
       # When not using gcc, we currently assume that we are using
-      # Microsoft Visual C++.
+      # Microsoft Visual C++ or Intel C++ Compiler.
       # hardcode_libdir_flag_spec is actually meaningless, as there is
       # no search path for DLLs.
       case $cc_basename in
-      cl*)
-	# Native MSVC
+      cl* | icl*)
+	# Native MSVC or ICC
 	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
 	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
 	_LT_TAGVAR(always_export_symbols, $1)=yes
@@ -5585,14 +5598,14 @@ _LT_EOF
 	# Tell ltmain to make .dll files, not .so files.
 	shrext_cmds=.dll
 	# FIXME: Setting linknames here is a bad hack.
-	_LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
+	_LT_TAGVAR(archive_cmds, $1)='$CC -Fe $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~linknames='
 	_LT_TAGVAR(archive_expsym_cmds, $1)='if _LT_DLL_DEF_P([$export_symbols]); then
             cp "$export_symbols" "$output_objdir/$soname.def";
             echo "$tool_output_objdir$soname.def" > "$output_objdir/$soname.exp";
           else
             $SED -e '\''s/^/-link -EXPORT:/'\'' < $export_symbols > $output_objdir/$soname.exp;
           fi~
-          $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+          $CC -Fe $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
           linknames='
 	# The linker will not automatically build a static lib if we build a DLL.
 	# _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
@@ -5616,7 +5629,7 @@ _LT_EOF
           fi'
 	;;
       *)
-	# Assume MSVC wrapper
+	# Assume MSVC and ICC wrapper
 	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
 	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
 	# Tell ltmain to make .lib files, not .a files.
@@ -6225,7 +6238,7 @@ _LT_TAGVAR(objext, $1)=$objext
 lt_simple_compile_test_code="int some_variable = 0;"
 
 # Code to be used in simple link tests
-lt_simple_link_test_code='int main(){return(0);}'
+lt_simple_link_test_code='int main(void){return(0);}'
 
 _LT_TAG_COMPILER
 # Save the default compiler, since it gets overwritten when the other
@@ -6435,7 +6448,7 @@ if test yes != "$_lt_caught_CXX_error"; then
       # Commands to make compiler produce verbose output that lists
       # what "hidden" libraries, object files and flags are used when
       # linking a shared library.
-      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "[[-]]L"'
 
     else
       GXX=no
@@ -6644,10 +6657,10 @@ if test yes != "$_lt_caught_CXX_error"; then
         esac
         ;;
 
-      cygwin* | mingw* | pw32* | cegcc*)
+      cygwin* | mingw* | windows* | pw32* | cegcc*)
 	case $GXX,$cc_basename in
-	,cl* | no,cl*)
-	  # Native MSVC
+	,cl* | no,cl* | ,icl* | no,icl*)
+	  # Native MSVC or ICC
 	  # hardcode_libdir_flag_spec is actually meaningless, as there is
 	  # no search path for DLLs.
 	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
@@ -6811,7 +6824,7 @@ if test yes != "$_lt_caught_CXX_error"; then
             # explicitly linking system object files so we need to strip them
             # from the output so that they don't get included in the library
             # dependencies.
-            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "[[-]]L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
             ;;
           *)
             if test yes = "$GXX"; then
@@ -6876,7 +6889,7 @@ if test yes != "$_lt_caught_CXX_error"; then
 	    # explicitly linking system object files so we need to strip them
 	    # from the output so that they don't get included in the library
 	    # dependencies.
-	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "[[-]]L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
 	    ;;
           *)
 	    if test yes = "$GXX"; then
@@ -7215,7 +7228,7 @@ if test yes != "$_lt_caught_CXX_error"; then
 	      # Commands to make compiler produce verbose output that lists
 	      # what "hidden" libraries, object files and flags are used when
 	      # linking a shared library.
-	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "[[-]]L"'
 
 	    else
 	      # FIXME: insert proper C++ library support
@@ -7299,7 +7312,7 @@ if test yes != "$_lt_caught_CXX_error"; then
 	        # Commands to make compiler produce verbose output that lists
 	        # what "hidden" libraries, object files and flags are used when
 	        # linking a shared library.
-	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "[[-]]L"'
 	      else
 	        # g++ 2.7 appears to require '-G' NOT '-shared' on this
 	        # platform.
@@ -7310,7 +7323,7 @@ if test yes != "$_lt_caught_CXX_error"; then
 	        # Commands to make compiler produce verbose output that lists
 	        # what "hidden" libraries, object files and flags are used when
 	        # linking a shared library.
-	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "[[-]]L"'
 	      fi
 
 	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir'
@@ -8331,7 +8344,7 @@ AC_CACHE_VAL(lt_cv_to_host_file_cmd,
 [case $host in
   *-*-mingw* )
     case $build in
-      *-*-mingw* ) # actually msys
+      *-*-mingw* | *-*-windows* ) # actually msys
         lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
         ;;
       *-*-cygwin* )
@@ -8344,7 +8357,7 @@ AC_CACHE_VAL(lt_cv_to_host_file_cmd,
     ;;
   *-*-cygwin* )
     case $build in
-      *-*-mingw* ) # actually msys
+      *-*-mingw* | *-*-windows* ) # actually msys
         lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
         ;;
       *-*-cygwin* )
@@ -8370,9 +8383,9 @@ AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
 [#assume ordinary cross tools, or native build.
 lt_cv_to_tool_file_cmd=func_convert_file_noop
 case $host in
-  *-*-mingw* )
+  *-*-mingw* | *-*-windows* )
     case $build in
-      *-*-mingw* ) # actually msys
+      *-*-mingw* | *-*-windows* ) # actually msys
         lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
         ;;
     esac

+ 1 - 1
Engine/lib/sdl/acinclude/ltoptions.m4

@@ -128,7 +128,7 @@ LT_OPTION_DEFINE([LT_INIT], [win32-dll],
 [enable_win32_dll=yes
 
 case $host in
-*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+*-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-cegcc*)
   AC_CHECK_TOOL(AS, as, false)
   AC_CHECK_TOOL(DLLTOOL, dlltool, false)
   AC_CHECK_TOOL(OBJDUMP, objdump, false)

+ 1 - 0
Engine/lib/sdl/android-project-ant/AndroidManifest.xml

@@ -0,0 +1 @@
+../android-project/app/src/main/AndroidManifest.xml

+ 17 - 0
Engine/lib/sdl/android-project-ant/ant.properties

@@ -0,0 +1,17 @@
+# This file is used to override default values used by the Ant build system.
+#
+# This file must be checked into Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+#  'source.dir' for the location of your java source folder and
+#  'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+#  'key.store' for the location of your keystore and
+#  'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+

+ 17 - 0
Engine/lib/sdl/android-project-ant/build.properties

@@ -0,0 +1,17 @@
+# This file is used to override default values used by the Ant build system.
+# 
+# This file must be checked in Version Control Systems, as it is
+# integral to the build system of your project.
+
+# This file is only used by the Ant script.
+
+# You can use this to override default values such as
+#  'source.dir' for the location of your java source folder and
+#  'out.dir' for the location of your output folder.
+
+# You can also use it define how the release builds are signed by declaring
+# the following properties:
+#  'key.store' for the location of your keystore and
+#  'key.alias' for the name of the key to use.
+# The password will be asked during the build when you use the 'release' target.
+

+ 93 - 0
Engine/lib/sdl/android-project-ant/build.xml

@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- This should be changed to the name of your project -->
+<project name="SDLActivity" default="help">
+
+    <!-- The local.properties file is created and updated by the 'android' tool.
+         It contains the path to the SDK. It should *NOT* be checked into
+         Version Control Systems. -->
+    <property file="local.properties" />
+
+    <!-- The ant.properties file can be created by you. It is only edited by the
+         'android' tool to add properties to it.
+         This is the place to change some Ant specific build properties.
+         Here are some properties you may want to change/update:
+
+         source.dir
+             The name of the source directory. Default is 'src'.
+         out.dir
+             The name of the output directory. Default is 'bin'.
+
+         For other overridable properties, look at the beginning of the rules
+         files in the SDK, at tools/ant/build.xml
+
+         Properties related to the SDK location or the project target should
+         be updated using the 'android' tool with the 'update' action.
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems.
+
+         -->
+    <property file="ant.properties" />
+
+    <!-- if sdk.dir was not set from one of the property file, then
+         get it from the ANDROID_HOME env var.
+         This must be done before we load project.properties since
+         the proguard config can use sdk.dir -->
+    <property environment="env" />
+    <condition property="sdk.dir" value="${env.ANDROID_HOME}">
+        <isset property="env.ANDROID_HOME" />
+    </condition>
+
+    <!-- The project.properties file is created and updated by the 'android'
+         tool, as well as ADT.
+
+         This contains project specific properties such as project target, and library
+         dependencies. Lower level build properties are stored in ant.properties
+         (or in .classpath for Eclipse projects).
+
+         This file is an integral part of the build system for your
+         application and should be checked into Version Control Systems. -->
+    <loadproperties srcFile="project.properties" />
+
+    <!-- quick check on sdk.dir -->
+    <fail
+            message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
+            unless="sdk.dir"
+    />
+
+    <!--
+        Import per project custom build rules if present at the root of the project.
+        This is the place to put custom intermediary targets such as:
+            -pre-build
+            -pre-compile
+            -post-compile (This is typically used for code obfuscation.
+                           Compiled code location: ${out.classes.absolute.dir}
+                           If this is not done in place, override ${out.dex.input.absolute.dir})
+            -post-package
+            -post-build
+            -pre-clean
+    -->
+    <import file="custom_rules.xml" optional="true" />
+
+    <!-- Import the actual build file.
+
+         To customize existing targets, there are two options:
+         - Customize only one target:
+             - copy/paste the target into this file, *before* the
+               <import> task.
+             - customize it to your needs.
+         - Customize the whole content of build.xml
+             - copy/paste the content of the rules files (minus the top node)
+               into this file, replacing the <import> task.
+             - customize to your needs.
+
+         ***********************
+         ****** IMPORTANT ******
+         ***********************
+         In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
+         in order to avoid having your file be overridden by tools such as "android update project"
+    -->
+    <!-- version-tag: 1 -->
+    <import file="${sdk.dir}/tools/ant/build.xml" />
+
+</project>

+ 11 - 0
Engine/lib/sdl/android-project-ant/default.properties

@@ -0,0 +1,11 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+# 
+# This file must be checked in Version Control Systems.
+# 
+# To customize properties used by the Ant build system use,
+# "build.properties", and override values to adapt the script to your
+# project structure.
+
+# Project target.
+target=android-16

+ 1 - 0
Engine/lib/sdl/android-project-ant/jni/Android.mk

@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)

+ 10 - 0
Engine/lib/sdl/android-project-ant/jni/Application.mk

@@ -0,0 +1,10 @@
+
+# Uncomment this if you're using STL in your project
+# See CPLUSPLUS-SUPPORT.html in the NDK documentation for more information
+# APP_STL := stlport_static 
+
+APP_ABI := armeabi armeabi-v7a x86
+
+# Min SDK level
+APP_PLATFORM=android-10
+

+ 18 - 0
Engine/lib/sdl/android-project-ant/jni/src/Android.mk

@@ -0,0 +1,18 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := main
+
+SDL_PATH := ../SDL
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include
+
+# Add your application source files here...
+LOCAL_SRC_FILES := YourSourceHere.c
+
+LOCAL_SHARED_LIBRARIES := SDL2
+
+LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -llog
+
+include $(BUILD_SHARED_LIBRARY)

+ 12 - 0
Engine/lib/sdl/android-project-ant/jni/src/Android_static.mk

@@ -0,0 +1,12 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := main
+
+LOCAL_SRC_FILES := YourSourceHere.c
+
+LOCAL_STATIC_LIBRARIES := SDL2_static
+
+include $(BUILD_SHARED_LIBRARY)
+$(call import-module,SDL)LOCAL_PATH := $(call my-dir)

+ 20 - 0
Engine/lib/sdl/android-project-ant/proguard-project.txt

@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}

+ 14 - 0
Engine/lib/sdl/android-project-ant/project.properties

@@ -0,0 +1,14 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-16

BIN
Engine/lib/sdl/android-project-ant/res/drawable-hdpi/ic_launcher.png


BIN
Engine/lib/sdl/android-project-ant/res/drawable-mdpi/ic_launcher.png


BIN
Engine/lib/sdl/android-project-ant/res/drawable-xhdpi/ic_launcher.png


BIN
Engine/lib/sdl/android-project-ant/res/drawable-xxhdpi/ic_launcher.png


+ 13 - 0
Engine/lib/sdl/android-project-ant/res/layout/main.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:layout_width="fill_parent"
+    android:layout_height="fill_parent"
+    >
+<TextView  
+    android:layout_width="fill_parent" 
+    android:layout_height="wrap_content" 
+    android:text="Hello World, SDLActivity"
+    />
+</LinearLayout>
+

+ 4 - 0
Engine/lib/sdl/android-project-ant/res/values/strings.xml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">SDL App</string>
+</resources>

+ 1 - 0
Engine/lib/sdl/android-project-ant/src

@@ -0,0 +1 @@
+../android-project/app/src/main/java

+ 81 - 0
Engine/lib/sdl/android-project/app/proguard-rules.pro

@@ -15,3 +15,84 @@
 #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
 #   public *;
 #}
+
+-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLInputConnection {
+    void nativeCommitText(java.lang.String, int);
+    void nativeGenerateScancodeForUnichar(char);
+}
+
+-keep,includedescriptorclasses class org.libsdl.app.SDLActivity {
+    # for some reason these aren't compatible with allowoptimization modifier
+    boolean supportsRelativeMouse();
+    void setWindowStyle(boolean);
+}
+
+-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLActivity {
+    java.lang.String nativeGetHint(java.lang.String); # Java-side doesn't use this, so it gets minified, but C-side still tries to register it
+    boolean onNativeSoftReturnKey();
+    void onNativeKeyboardFocusLost();
+    boolean isScreenKeyboardShown();
+    android.util.DisplayMetrics getDisplayDPI();
+    java.lang.String clipboardGetText();
+    boolean clipboardHasText();
+    void clipboardSetText(java.lang.String);
+    int createCustomCursor(int[], int, int, int, int);
+    void destroyCustomCursor(int);
+    android.content.Context getContext();
+    boolean getManifestEnvironmentVariables();
+    android.view.Surface getNativeSurface();
+    void initTouch();
+    boolean isAndroidTV();
+    boolean isChromebook();
+    boolean isDeXMode();
+    boolean isTablet();
+    void manualBackButton();
+    int messageboxShowMessageBox(int, java.lang.String, java.lang.String, int[], int[], java.lang.String[], int[]);
+    void minimizeWindow();
+    int openURL(java.lang.String);
+    void requestPermission(java.lang.String, int);
+    int showToast(java.lang.String, int, int, int, int);
+    boolean sendMessage(int, int);
+    boolean setActivityTitle(java.lang.String);
+    boolean setCustomCursor(int);
+    void setOrientation(int, int, boolean, java.lang.String);
+    boolean setRelativeMouseEnabled(boolean);
+    boolean setSystemCursor(int);
+    boolean shouldMinimizeOnFocusLoss();
+    boolean showTextInput(int, int, int, int);
+}
+
+-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.HIDDeviceManager {
+    boolean initialize(boolean, boolean);
+    boolean openDevice(int);
+    int sendOutputReport(int, byte[]);
+    int sendFeatureReport(int, byte[]);
+    boolean getFeatureReport(int, byte[]);
+    void closeDevice(int);
+}
+
+-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLAudioManager {
+    int[] getAudioOutputDevices();
+    int[] getAudioInputDevices();
+    int[] audioOpen(int, int, int, int, int);
+    void audioWriteFloatBuffer(float[]);
+    void audioWriteShortBuffer(short[]);
+    void audioWriteByteBuffer(byte[]);
+    void audioClose();
+    int[] captureOpen(int, int, int, int, int);
+    int captureReadFloatBuffer(float[], boolean);
+    int captureReadShortBuffer(short[], boolean);
+    int captureReadByteBuffer(byte[], boolean);
+    void captureClose();
+    void audioSetThreadPriority(boolean, int);
+    native int nativeSetupJNI();
+    native void removeAudioDevice(boolean, int);
+    native void addAudioDevice(boolean, int);
+}
+
+-keep,includedescriptorclasses,allowoptimization class org.libsdl.app.SDLControllerManager {
+    void pollInputDevices();
+    void pollHapticDevices();
+    void hapticRun(int, float, int);
+    void hapticStop(int);
+}

+ 1 - 1
Engine/lib/sdl/android-project/app/src/main/AndroidManifest.xml

@@ -62,7 +62,7 @@
     <application android:label="@string/app_name"
         android:icon="@mipmap/ic_launcher"
         android:allowBackup="true"
-        android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
+        android:theme="@style/AppTheme"
         android:hardwareAccelerated="true" >
 
         <!-- Example of setting SDL hints from AndroidManifest.xml:

+ 16 - 1
Engine/lib/sdl/android-project/app/src/main/java/org/libsdl/app/HIDDeviceManager.java

@@ -273,9 +273,11 @@ public class HIDDeviceManager {
         final int XB1_IFACE_SUBCLASS = 71;
         final int XB1_IFACE_PROTOCOL = 208;
         final int[] SUPPORTED_VENDORS = {
+            0x03f0, // HP
             0x044f, // Thrustmaster
             0x045e, // Microsoft
             0x0738, // Mad Catz
+            0x0b05, // ASUS
             0x0e6f, // PDP
             0x0f0d, // Hori
             0x10f5, // Turtle Beach
@@ -284,6 +286,7 @@ public class HIDDeviceManager {
             0x24c6, // PowerA
             0x2dc8, // 8BitDo
             0x2e24, // Hyperkin
+            0x3537, // GameSir
         };
 
         if (usbInterface.getId() == 0 &&
@@ -357,6 +360,12 @@ public class HIDDeviceManager {
     private void initializeBluetooth() {
         Log.d(TAG, "Initializing Bluetooth");
 
+        if (Build.VERSION.SDK_INT >= 31 /* Android 12  */ &&
+            mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH_CONNECT, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
+            Log.d(TAG, "Couldn't initialize Bluetooth, missing android.permission.BLUETOOTH_CONNECT");
+            return;
+        }
+
         if (Build.VERSION.SDK_INT <= 30 /* Android 11.0 (R) */ &&
             mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
             Log.d(TAG, "Couldn't initialize Bluetooth, missing android.permission.BLUETOOTH");
@@ -582,7 +591,13 @@ public class HIDDeviceManager {
                 } else {
                     flags = 0;
                 }
-                mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(HIDDeviceManager.ACTION_USB_PERMISSION), flags));
+                if (Build.VERSION.SDK_INT >= 33 /* Android 14.0 (U) */) {
+                   Intent intent = new Intent(HIDDeviceManager.ACTION_USB_PERMISSION);
+                   intent.setPackage(mContext.getPackageName());
+                   mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, intent, flags));
+               } else {
+                   mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(HIDDeviceManager.ACTION_USB_PERMISSION), flags));
+               }
             } catch (Exception e) {
                 Log.v(TAG, "Couldn't request permission for USB device " + usbDevice);
                 HIDDeviceOpenResult(deviceID, false);

+ 9 - 5
Engine/lib/sdl/android-project/app/src/main/java/org/libsdl/app/SDL.java

@@ -38,6 +38,10 @@ public class SDL {
     }
 
     public static void loadLibrary(String libraryName) throws UnsatisfiedLinkError, SecurityException, NullPointerException {
+        loadLibrary(libraryName, mContext);
+    }
+
+    public static void loadLibrary(String libraryName, Context context) throws UnsatisfiedLinkError, SecurityException, NullPointerException {
 
         if (libraryName == null) {
             throw new NullPointerException("No library name provided.");
@@ -53,10 +57,10 @@ public class SDL {
             // To use ReLinker, just add it as a dependency.  For more information, see 
             // https://github.com/KeepSafe/ReLinker for ReLinker's repository.
             //
-            Class<?> relinkClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker");
-            Class<?> relinkListenerClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker$LoadListener");
-            Class<?> contextClass = mContext.getClassLoader().loadClass("android.content.Context");
-            Class<?> stringClass = mContext.getClassLoader().loadClass("java.lang.String");
+            Class<?> relinkClass = context.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker");
+            Class<?> relinkListenerClass = context.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker$LoadListener");
+            Class<?> contextClass = context.getClassLoader().loadClass("android.content.Context");
+            Class<?> stringClass = context.getClassLoader().loadClass("java.lang.String");
 
             // Get a 'force' instance of the ReLinker, so we can ensure libraries are reinstalled if 
             // they've changed during updates.
@@ -66,7 +70,7 @@ public class SDL {
 
             // Actually load the library!
             Method loadMethod = relinkInstanceClass.getDeclaredMethod("loadLibrary", contextClass, stringClass, stringClass, relinkListenerClass);
-            loadMethod.invoke(relinkInstance, mContext, libraryName, null, null);
+            loadMethod.invoke(relinkInstance, context, libraryName, null, null);
         }
         catch (final Throwable e) {
             // Fall back

+ 12 - 9
Engine/lib/sdl/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java

@@ -60,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 = 2;
-    private static final int SDL_MINOR_VERSION = 28;
-    private static final int SDL_MICRO_VERSION = 4;
+    private static final int SDL_MINOR_VERSION = 32;
+    private static final int SDL_MICRO_VERSION = 6;
 /*
     // Display InputType.SOURCE/CLASS of events and devices
     //
@@ -89,7 +89,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
                 | InputDevice.SOURCE_CLASS_POSITION
                 | InputDevice.SOURCE_CLASS_TRACKBALL);
 
-        if (s2 != 0) cls += "Some_Unkown";
+        if (s2 != 0) cls += "Some_Unknown";
 
         s2 = s_copy & InputDevice.SOURCE_ANY; // keep source only, no class;
 
@@ -163,7 +163,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         if (s == FLAG_TAINTED) src += " FLAG_TAINTED";
         s2 &= ~FLAG_TAINTED;
 
-        if (s2 != 0) src += " Some_Unkown";
+        if (s2 != 0) src += " Some_Unknown";
 
         Log.v(TAG, prefix + "int=" + s_copy + " CLASS={" + cls + " } source(s):" + src);
     }
@@ -281,7 +281,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
     // Load the .so
     public void loadLibraries() {
        for (String lib : getLibraries()) {
-          SDL.loadLibrary(lib);
+          SDL.loadLibrary(lib, this);
        }
     }
 
@@ -790,6 +790,9 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
                                 window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
                                 SDLActivity.mFullscreenModeActive = false;
                             }
+                            if (Build.VERSION.SDK_INT >= 28 /* Android 9 (Pie) */) {
+                                window.getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+                            }
                         }
                     } else {
                         Log.e(TAG, "error handling message, getContext() returned no Activity");
@@ -995,8 +998,8 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         /* No valid hint, nothing is explicitly allowed */
         if (!is_portrait_allowed && !is_landscape_allowed) {
             if (resizable) {
-                /* All orientations are allowed */
-                req = ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
+                /* All orientations are allowed, respecting user orientation lock setting */
+                req = ActivityInfo.SCREEN_ORIENTATION_FULL_USER;
             } else {
                 /* Fixed window and nothing specified. Get orientation from w/h of created window */
                 req = (w > h ? ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE : ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
@@ -1005,8 +1008,8 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
             /* At least one orientation is allowed */
             if (resizable) {
                 if (is_portrait_allowed && is_landscape_allowed) {
-                    /* hint allows both landscape and portrait, promote to full sensor */
-                    req = ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR;
+                    /* hint allows both landscape and portrait, promote to full user */
+                    req = ActivityInfo.SCREEN_ORIENTATION_FULL_USER;
                 } else {
                     /* Use the only one allowed "orientation" */
                     req = (is_landscape_allowed ? orientation_landscape : orientation_portrait);

+ 9 - 7
Engine/lib/sdl/android-project/app/src/main/java/org/libsdl/app/SDLControllerManager.java

@@ -546,13 +546,15 @@ class SDLHapticHandler {
             if (haptic == null) {
                 InputDevice device = InputDevice.getDevice(deviceIds[i]);
                 Vibrator vib = device.getVibrator();
-                if (vib.hasVibrator()) {
-                    haptic = new SDLHaptic();
-                    haptic.device_id = deviceIds[i];
-                    haptic.name = device.getName();
-                    haptic.vib = vib;
-                    mHaptics.add(haptic);
-                    SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
+                if (vib != null) {
+                    if (vib.hasVibrator()) {
+                        haptic = new SDLHaptic();
+                        haptic.device_id = deviceIds[i];
+                        haptic.name = device.getName();
+                        haptic.vib = vib;
+                        mHaptics.add(haptic);
+                        SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
+                    }
                 }
             }
         }

+ 2 - 3
Engine/lib/sdl/android-project/app/src/main/res/values/styles.xml

@@ -1,8 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
 <resources>
-
     <!-- Base application theme. -->
-    <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
+    <style name="AppTheme" parent="android:Theme.NoTitleBar.Fullscreen">
         <!-- Customize your theme here. -->
     </style>
-
 </resources>

+ 2 - 1
Engine/lib/sdl/build-scripts/androidbuild.sh

@@ -80,7 +80,8 @@ do
     cd $folder
 done
 
-ACTIVITY="${folder}Activity"
+# Uppercase the first char in the activity class name because it's Java
+ACTIVITY="$(echo $folder | awk '{$1=toupper(substr($1,0,1))substr($1,2)}1')Activity"
 sed -i -e "s|\"SDLActivity\"|\"$ACTIVITY\"|g" $BUILDPATH/app/src/main/AndroidManifest.xml
 
 # Fill in a default Activity

+ 1470 - 0
Engine/lib/sdl/build-scripts/build-release.py

@@ -0,0 +1,1470 @@
+#!/usr/bin/env python3
+
+"""
+This script is shared between SDL2, SDL3, and all satellite libraries.
+Don't specialize this script for doing project-specific modifications.
+Rather, modify release-info.json.
+"""
+
+import argparse
+import collections
+import dataclasses
+from collections.abc import Callable
+import contextlib
+import datetime
+import fnmatch
+import glob
+import io
+import json
+import logging
+import multiprocessing
+import os
+from pathlib import Path
+import platform
+import re
+import shlex
+import shutil
+import subprocess
+import sys
+import tarfile
+import tempfile
+import textwrap
+import typing
+import zipfile
+
+
+logger = logging.getLogger(__name__)
+GIT_HASH_FILENAME = ".git-hash"
+REVISION_TXT = "REVISION.txt"
+
+
+def safe_isotime_to_datetime(str_isotime: str) -> datetime.datetime:
+    try:
+        return datetime.datetime.fromisoformat(str_isotime)
+    except ValueError:
+        pass
+    logger.warning("Invalid iso time: %s", str_isotime)
+    if str_isotime[-6:-5] in ("+", "-"):
+        # Commits can have isotime with invalid timezone offset (e.g. "2021-07-04T20:01:40+32:00")
+        modified_str_isotime = str_isotime[:-6] + "+00:00"
+        try:
+            return datetime.datetime.fromisoformat(modified_str_isotime)
+        except ValueError:
+            pass
+    raise ValueError(f"Invalid isotime: {str_isotime}")
+
+
+def arc_join(*parts: list[str]) -> str:
+    assert all(p[:1] != "/" and p[-1:] != "/" for p in parts), f"None of {parts} may start or end with '/'"
+    return "/".join(p for p in parts if p)
+
+
[email protected](frozen=True)
+class VsArchPlatformConfig:
+    arch: str
+    configuration: str
+    platform: str
+
+    def extra_context(self):
+        return {
+            "ARCH": self.arch,
+            "CONFIGURATION": self.configuration,
+            "PLATFORM": self.platform,
+        }
+
+
[email protected]
+def chdir(path):
+    original_cwd = os.getcwd()
+    try:
+        os.chdir(path)
+        yield
+    finally:
+        os.chdir(original_cwd)
+
+
+class Executer:
+    def __init__(self, root: Path, dry: bool=False):
+        self.root = root
+        self.dry = dry
+
+    def run(self, cmd, cwd=None, env=None):
+        logger.info("Executing args=%r", cmd)
+        sys.stdout.flush()
+        if not self.dry:
+            subprocess.check_call(cmd, cwd=cwd or self.root, env=env, text=True)
+
+    def check_output(self, cmd, cwd=None, dry_out=None, env=None, text=True):
+        logger.info("Executing args=%r", cmd)
+        sys.stdout.flush()
+        if self.dry:
+            return dry_out
+        return subprocess.check_output(cmd, cwd=cwd or self.root, env=env, text=text)
+
+
+class SectionPrinter:
+    @contextlib.contextmanager
+    def group(self, title: str):
+        print(f"{title}:")
+        yield
+
+
+class GitHubSectionPrinter(SectionPrinter):
+    def __init__(self):
+        super().__init__()
+        self.in_group = False
+
+    @contextlib.contextmanager
+    def group(self, title: str):
+        print(f"::group::{title}")
+        assert not self.in_group, "Can enter a group only once"
+        self.in_group = True
+        yield
+        self.in_group = False
+        print("::endgroup::")
+
+
+class VisualStudio:
+    def __init__(self, executer: Executer, year: typing.Optional[str]=None):
+        self.executer = executer
+        self.vsdevcmd = self.find_vsdevcmd(year)
+        self.msbuild = self.find_msbuild()
+
+    @property
+    def dry(self) -> bool:
+        return self.executer.dry
+
+    VS_YEAR_TO_VERSION = {
+        "2022": 17,
+        "2019": 16,
+        "2017": 15,
+        "2015": 14,
+        "2013": 12,
+    }
+
+    def find_vsdevcmd(self, year: typing.Optional[str]=None) -> typing.Optional[Path]:
+        vswhere_spec = ["-latest"]
+        if year is not None:
+            try:
+                version = self.VS_YEAR_TO_VERSION[year]
+            except KeyError:
+                logger.error("Invalid Visual Studio year")
+                return None
+            vswhere_spec.extend(["-version", f"[{version},{version+1})"])
+        vswhere_cmd = ["vswhere"] + vswhere_spec + ["-property", "installationPath"]
+        vs_install_path = Path(self.executer.check_output(vswhere_cmd, dry_out="/tmp").strip())
+        logger.info("VS install_path = %s", vs_install_path)
+        assert vs_install_path.is_dir(), "VS installation path does not exist"
+        vsdevcmd_path = vs_install_path / "Common7/Tools/vsdevcmd.bat"
+        logger.info("vsdevcmd path = %s", vsdevcmd_path)
+        if self.dry:
+            vsdevcmd_path.parent.mkdir(parents=True, exist_ok=True)
+            vsdevcmd_path.touch(exist_ok=True)
+        assert vsdevcmd_path.is_file(), "vsdevcmd.bat batch file does not exist"
+        return vsdevcmd_path
+
+    def find_msbuild(self) -> typing.Optional[Path]:
+        vswhere_cmd = ["vswhere", "-latest", "-requires", "Microsoft.Component.MSBuild", "-find", r"MSBuild\**\Bin\MSBuild.exe"]
+        msbuild_path = Path(self.executer.check_output(vswhere_cmd, dry_out="/tmp/MSBuild.exe").strip())
+        logger.info("MSBuild path = %s", msbuild_path)
+        if self.dry:
+            msbuild_path.parent.mkdir(parents=True, exist_ok=True)
+            msbuild_path.touch(exist_ok=True)
+        assert msbuild_path.is_file(), "MSBuild.exe does not exist"
+        return msbuild_path
+
+    def build(self, arch_platform: VsArchPlatformConfig, projects: list[Path]):
+        assert projects, "Need at least one project to build"
+
+        vsdev_cmd_str = f"\"{self.vsdevcmd}\" -arch={arch_platform.arch}"
+        msbuild_cmd_str = " && ".join([f"\"{self.msbuild}\" \"{project}\" /m /p:BuildInParallel=true /p:Platform={arch_platform.platform} /p:Configuration={arch_platform.configuration}" for project in projects])
+        bat_contents = f"{vsdev_cmd_str} && {msbuild_cmd_str}\n"
+        bat_path = Path(tempfile.gettempdir()) / "cmd.bat"
+        with bat_path.open("w") as f:
+            f.write(bat_contents)
+
+        logger.info("Running cmd.exe script (%s): %s", bat_path, bat_contents)
+        cmd = ["cmd.exe", "/D", "/E:ON", "/V:OFF", "/S", "/C", f"CALL {str(bat_path)}"]
+        self.executer.run(cmd)
+
+
+class Archiver:
+    def __init__(self, zip_path: typing.Optional[Path]=None, tgz_path: typing.Optional[Path]=None, txz_path: typing.Optional[Path]=None):
+        self._zip_files = []
+        self._tar_files = []
+        self._added_files = set()
+        if zip_path:
+            self._zip_files.append(zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED))
+        if tgz_path:
+            self._tar_files.append(tarfile.open(tgz_path, "w:gz"))
+        if txz_path:
+            self._tar_files.append(tarfile.open(txz_path, "w:xz"))
+
+    @property
+    def added_files(self) -> set[str]:
+        return self._added_files
+
+    def add_file_data(self, arcpath: str, data: bytes, mode: int, time: datetime.datetime):
+        for zf in self._zip_files:
+            file_data_time = (time.year, time.month, time.day, time.hour, time.minute, time.second)
+            zip_info = zipfile.ZipInfo(filename=arcpath, date_time=file_data_time)
+            zip_info.external_attr = mode << 16
+            zip_info.compress_type = zipfile.ZIP_DEFLATED
+            zf.writestr(zip_info, data=data)
+        for tf in self._tar_files:
+            tar_info = tarfile.TarInfo(arcpath)
+            tar_info.type = tarfile.REGTYPE
+            tar_info.mode = mode
+            tar_info.size = len(data)
+            tar_info.mtime = int(time.timestamp())
+            tf.addfile(tar_info, fileobj=io.BytesIO(data))
+
+        self._added_files.add(arcpath)
+
+    def add_symlink(self, arcpath: str, target: str, time: datetime.datetime, files_for_zip):
+        logger.debug("Adding symlink (target=%r) -> %s", target, arcpath)
+        for zf in self._zip_files:
+            file_data_time = (time.year, time.month, time.day, time.hour, time.minute, time.second)
+            for f in files_for_zip:
+                zip_info = zipfile.ZipInfo(filename=f["arcpath"], date_time=file_data_time)
+                zip_info.external_attr = f["mode"] << 16
+                zip_info.compress_type = zipfile.ZIP_DEFLATED
+                zf.writestr(zip_info, data=f["data"])
+        for tf in self._tar_files:
+            tar_info = tarfile.TarInfo(arcpath)
+            tar_info.type = tarfile.SYMTYPE
+            tar_info.mode = 0o777
+            tar_info.mtime = int(time.timestamp())
+            tar_info.linkname = target
+            tf.addfile(tar_info)
+
+        self._added_files.update(f["arcpath"] for f in files_for_zip)
+
+    def add_git_hash(self, arcdir: str, commit: str, time: datetime.datetime):
+        arcpath = arc_join(arcdir, GIT_HASH_FILENAME)
+        data = f"{commit}\n".encode()
+        self.add_file_data(arcpath=arcpath, data=data, mode=0o100644, time=time)
+
+    def add_file_path(self, arcpath: str, path: Path):
+        assert path.is_file(), f"{path} should be a file"
+        logger.debug("Adding %s -> %s", path, arcpath)
+        for zf in self._zip_files:
+            zf.write(path, arcname=arcpath)
+        for tf in self._tar_files:
+            tf.add(path, arcname=arcpath)
+
+    def add_file_directory(self, arcdirpath: str, dirpath: Path):
+        assert dirpath.is_dir()
+        if arcdirpath and arcdirpath[-1:] != "/":
+            arcdirpath += "/"
+        for f in dirpath.iterdir():
+            if f.is_file():
+                arcpath = f"{arcdirpath}{f.name}"
+                logger.debug("Adding %s to %s", f, arcpath)
+                self.add_file_path(arcpath=arcpath, path=f)
+
+    def close(self):
+        # Archiver is intentionally made invalid after this function
+        del self._zip_files
+        self._zip_files = None
+        del self._tar_files
+        self._tar_files = None
+
+    def __enter__(self):
+        return self
+
+    def __exit__(self, type, value, traceback):
+        self.close()
+
+
+class NodeInArchive:
+    def __init__(self, arcpath: str, path: typing.Optional[Path]=None, data: typing.Optional[bytes]=None, mode: typing.Optional[int]=None, symtarget: typing.Optional[str]=None, time: typing.Optional[datetime.datetime]=None, directory: bool=False):
+        self.arcpath = arcpath
+        self.path = path
+        self.data = data
+        self.mode = mode
+        self.symtarget = symtarget
+        self.time = time
+        self.directory = directory
+
+    @classmethod
+    def from_fs(cls, arcpath: str, path: Path, mode: int=0o100644, time: typing.Optional[datetime.datetime]=None) -> "NodeInArchive":
+        if time is None:
+            time = datetime.datetime.fromtimestamp(os.stat(path).st_mtime)
+        return cls(arcpath=arcpath, path=path, mode=mode)
+
+    @classmethod
+    def from_data(cls, arcpath: str, data: bytes, time: datetime.datetime) -> "NodeInArchive":
+        return cls(arcpath=arcpath, data=data, time=time, mode=0o100644)
+
+    @classmethod
+    def from_text(cls, arcpath: str, text: str, time: datetime.datetime) -> "NodeInArchive":
+        return cls.from_data(arcpath=arcpath, data=text.encode(), time=time)
+
+    @classmethod
+    def from_symlink(cls, arcpath: str, symtarget: str) -> "NodeInArchive":
+        return cls(arcpath=arcpath, symtarget=symtarget)
+
+    @classmethod
+    def from_directory(cls, arcpath: str) -> "NodeInArchive":
+        return cls(arcpath=arcpath, directory=True)
+
+    def __repr__(self) -> str:
+        return f"<{type(self).__name__}:arcpath={self.arcpath},path='{str(self.path)}',len(data)={len(self.data) if self.data else 'n/a'},directory={self.directory},symtarget={self.symtarget}>"
+
+
+def configure_file(path: Path, context: dict[str, str]) -> bytes:
+    text = path.read_text()
+    return configure_text(text, context=context).encode()
+
+
+def configure_text(text: str, context: dict[str, str]) -> str:
+    original_text = text
+    for txt, repl in context.items():
+        text = text.replace(f"@<@{txt}@>@", repl)
+    success = all(thing not in text for thing in ("@<@", "@>@"))
+    if not success:
+        raise ValueError(f"Failed to configure {repr(original_text)}")
+    return text
+
+
+def configure_text_list(text_list: list[str], context: dict[str, str]) -> list[str]:
+    return [configure_text(text=e, context=context) for e in text_list]
+
+
+class ArchiveFileTree:
+    def __init__(self):
+        self._tree: dict[str, NodeInArchive] = {}
+
+    def add_file(self, file: NodeInArchive):
+        self._tree[file.arcpath] = file
+
+    def get_latest_mod_time(self) -> datetime.datetime:
+        return max(item.time for item in self._tree.values() if item.time)
+
+    def add_to_archiver(self, archive_base: str, archiver: Archiver):
+        remaining_symlinks = set()
+        added_files = dict()
+
+        def calculate_symlink_target(s: NodeInArchive) -> str:
+            dest_dir = os.path.dirname(s.arcpath)
+            if dest_dir:
+                dest_dir += "/"
+            target = dest_dir + s.symtarget
+            while True:
+                new_target, n = re.subn(r"([^/]+/+[.]{2}/)", "", target)
+                target = new_target
+                if not n:
+                    break
+            return target
+
+        # Add files in first pass
+        for arcpath, node in self._tree.items():
+            assert node is not None, f"{arcpath} -> node"
+            if node.data is not None:
+                archiver.add_file_data(arcpath=arc_join(archive_base, arcpath), data=node.data, time=node.time, mode=node.mode)
+                assert node.arcpath is not None, f"{node=}"
+                added_files[node.arcpath] = node
+            elif node.path is not None:
+                archiver.add_file_path(arcpath=arc_join(archive_base, arcpath), path=node.path)
+                assert node.arcpath is not None, f"{node=}"
+                added_files[node.arcpath] = node
+            elif node.symtarget is not None:
+                remaining_symlinks.add(node)
+            elif node.directory:
+                pass
+            else:
+                raise ValueError(f"Invalid Archive Node: {repr(node)}")
+
+        assert None not in added_files
+
+        # Resolve symlinks in second pass: zipfile does not support symlinks, so add files to zip archive
+        while True:
+            if not remaining_symlinks:
+                break
+            symlinks_this_time = set()
+            extra_added_files = {}
+            for symlink in remaining_symlinks:
+                symlink_files_for_zip = {}
+                symlink_target_path = calculate_symlink_target(symlink)
+                if symlink_target_path in added_files:
+                    symlink_files_for_zip[symlink.arcpath] = added_files[symlink_target_path]
+                else:
+                    symlink_target_path_slash = symlink_target_path + "/"
+                    for added_file in added_files:
+                        if added_file.startswith(symlink_target_path_slash):
+                            path_in_symlink = symlink.arcpath + "/" + added_file.removeprefix(symlink_target_path_slash)
+                            symlink_files_for_zip[path_in_symlink] = added_files[added_file]
+                if symlink_files_for_zip:
+                    symlinks_this_time.add(symlink)
+                    extra_added_files.update(symlink_files_for_zip)
+                    files_for_zip = [{"arcpath": f"{archive_base}/{sym_path}", "data": sym_info.data, "mode": sym_info.mode} for sym_path, sym_info in symlink_files_for_zip.items()]
+                    archiver.add_symlink(arcpath=f"{archive_base}/{symlink.arcpath}", target=symlink.symtarget, time=symlink.time, files_for_zip=files_for_zip)
+            # if not symlinks_this_time:
+            #     logger.info("files added: %r", set(path for path in added_files.keys()))
+            assert symlinks_this_time, f"No targets found for symlinks: {remaining_symlinks}"
+            remaining_symlinks.difference_update(symlinks_this_time)
+            added_files.update(extra_added_files)
+
+    def add_directory_tree(self, arc_dir: str, path: Path, time: datetime.datetime):
+        assert path.is_dir()
+        for files_dir, _, filenames in os.walk(path):
+            files_dir_path = Path(files_dir)
+            rel_files_path = files_dir_path.relative_to(path)
+            for filename in filenames:
+                self.add_file(NodeInArchive.from_fs(arcpath=arc_join(arc_dir, str(rel_files_path), filename), path=files_dir_path / filename, time=time))
+
+    def _add_files_recursively(self, arc_dir: str, paths: list[Path], time: datetime.datetime):
+        logger.debug(f"_add_files_recursively({arc_dir=} {paths=})")
+        for path in paths:
+            arcpath = arc_join(arc_dir, path.name)
+            if path.is_file():
+                logger.debug("Adding %s as %s", path, arcpath)
+                self.add_file(NodeInArchive.from_fs(arcpath=arcpath, path=path, time=time))
+            elif path.is_dir():
+                self._add_files_recursively(arc_dir=arc_join(arc_dir, path.name), paths=list(path.iterdir()), time=time)
+            else:
+                raise ValueError(f"Unsupported file type to add recursively: {path}")
+
+    def add_file_mapping(self, arc_dir: str, file_mapping: dict[str, list[str]], file_mapping_root: Path, context: dict[str, str], time: datetime.datetime):
+        for meta_rel_destdir, meta_file_globs in file_mapping.items():
+            rel_destdir = configure_text(meta_rel_destdir, context=context)
+            assert "@" not in rel_destdir, f"archive destination should not contain an @ after configuration ({repr(meta_rel_destdir)}->{repr(rel_destdir)})"
+            for meta_file_glob in meta_file_globs:
+                file_glob = configure_text(meta_file_glob, context=context)
+                assert "@" not in rel_destdir, f"archive glob should not contain an @ after configuration ({repr(meta_file_glob)}->{repr(file_glob)})"
+                if ":" in file_glob:
+                    original_path, new_filename = file_glob.rsplit(":", 1)
+                    assert ":" not in original_path, f"Too many ':' in {repr(file_glob)}"
+                    assert "/" not in new_filename, f"New filename cannot contain a '/' in {repr(file_glob)}"
+                    path = file_mapping_root / original_path
+                    arcpath = arc_join(arc_dir, rel_destdir, new_filename)
+                    if path.suffix == ".in":
+                        data = configure_file(path, context=context)
+                        logger.debug("Adding processed %s -> %s", path, arcpath)
+                        self.add_file(NodeInArchive.from_data(arcpath=arcpath, data=data, time=time))
+                    else:
+                        logger.debug("Adding %s -> %s", path, arcpath)
+                        self.add_file(NodeInArchive.from_fs(arcpath=arcpath, path=path, time=time))
+                else:
+                    relative_file_paths = glob.glob(file_glob, root_dir=file_mapping_root)
+                    assert relative_file_paths, f"Glob '{file_glob}' does not match any file"
+                    self._add_files_recursively(arc_dir=arc_join(arc_dir, rel_destdir), paths=[file_mapping_root / p for p in relative_file_paths], time=time)
+
+
+class SourceCollector:
+    # TreeItem = collections.namedtuple("TreeItem", ("path", "mode", "data", "symtarget", "directory", "time"))
+    def __init__(self, root: Path, commit: str, filter: typing.Optional[Callable[[str], bool]], executer: Executer):
+        self.root = root
+        self.commit = commit
+        self.filter = filter
+        self.executer = executer
+
+    def get_archive_file_tree(self) -> ArchiveFileTree:
+        git_archive_args = ["git", "archive", "--format=tar.gz", self.commit, "-o", "/dev/stdout"]
+        logger.info("Executing args=%r", git_archive_args)
+        contents_tgz = subprocess.check_output(git_archive_args, cwd=self.root, text=False)
+        tar_archive = tarfile.open(fileobj=io.BytesIO(contents_tgz), mode="r:gz")
+        filenames = tuple(m.name for m in tar_archive if (m.isfile() or m.issym()))
+
+        file_times = self._get_file_times(paths=filenames)
+        git_contents = ArchiveFileTree()
+        for ti in tar_archive:
+            if self.filter and not self.filter(ti.name):
+                continue
+            data = None
+            symtarget = None
+            directory = False
+            file_time = None
+            if ti.isfile():
+                contents_file = tar_archive.extractfile(ti.name)
+                data = contents_file.read()
+                file_time = file_times[ti.name]
+            elif ti.issym():
+                symtarget = ti.linkname
+                file_time = file_times[ti.name]
+            elif ti.isdir():
+                directory = True
+            else:
+                raise ValueError(f"{ti.name}: unknown type")
+            node = NodeInArchive(arcpath=ti.name, data=data, mode=ti.mode, symtarget=symtarget, time=file_time, directory=directory)
+            git_contents.add_file(node)
+        return git_contents
+
+    def _get_file_times(self, paths: tuple[str, ...]) -> dict[str, datetime.datetime]:
+        dry_out = textwrap.dedent("""\
+            time=2024-03-14T15:40:25-07:00
+
+            M\tCMakeLists.txt
+        """)
+        git_log_out = self.executer.check_output(["git", "log", "--name-status", '--pretty=time=%cI', self.commit], dry_out=dry_out, cwd=self.root).splitlines(keepends=False)
+        current_time = None
+        set_paths = set(paths)
+        path_times: dict[str, datetime.datetime] = {}
+        for line in git_log_out:
+            if not line:
+                continue
+            if line.startswith("time="):
+                current_time = safe_isotime_to_datetime(line.removeprefix("time="))
+                continue
+            mod_type, file_paths = line.split(maxsplit=1)
+            assert current_time is not None
+            for file_path in file_paths.split("\t"):
+                if file_path in set_paths and file_path not in path_times:
+                    path_times[file_path] = current_time
+
+        # FIXME: find out why some files are not shown in "git log"
+        # assert set(path_times.keys()) == set_paths
+        if set(path_times.keys()) != set_paths:
+            found_times = set(path_times.keys())
+            paths_without_times = set_paths.difference(found_times)
+            logger.warning("No times found for these paths: %s", paths_without_times)
+            max_time = max(time for time in path_times.values())
+            for path in paths_without_times:
+                path_times[path] = max_time
+
+        return path_times
+
+
+class Releaser:
+    def __init__(self, release_info: dict, commit: str, revision: str, root: Path, dist_path: Path, section_printer: SectionPrinter, executer: Executer, cmake_generator: str, deps_path: Path, overwrite: bool, github: bool, fast: bool):
+        self.release_info = release_info
+        self.project = release_info["name"]
+        self.version = self.extract_sdl_version(root=root, release_info=release_info)
+        self.root = root
+        self.commit = commit
+        self.revision = revision
+        self.dist_path = dist_path
+        self.section_printer = section_printer
+        self.executer = executer
+        self.cmake_generator = cmake_generator
+        self.cpu_count = multiprocessing.cpu_count()
+        self.deps_path = deps_path
+        self.overwrite = overwrite
+        self.github = github
+        self.fast = fast
+        self.arc_time = datetime.datetime.now()
+
+        self.artifacts: dict[str, Path] = {}
+
+    def get_context(self, extra_context: typing.Optional[dict[str, str]]=None) -> dict[str, str]:
+        ctx = {
+            "PROJECT_NAME": self.project,
+            "PROJECT_VERSION": self.version,
+            "PROJECT_COMMIT": self.commit,
+            "PROJECT_REVISION": self.revision,
+            "PROJECT_ROOT": str(self.root),
+        }
+        if extra_context:
+            ctx.update(extra_context)
+        return ctx
+
+    @property
+    def dry(self) -> bool:
+        return self.executer.dry
+
+    def prepare(self):
+        logger.debug("Creating dist folder")
+        self.dist_path.mkdir(parents=True, exist_ok=True)
+
+    @classmethod
+    def _path_filter(cls, path: str) -> bool:
+        if ".gitmodules" in path:
+            return True
+        if path.startswith(".git"):
+            return False
+        return True
+
+    @classmethod
+    def _external_repo_path_filter(cls, path: str) -> bool:
+        if not cls._path_filter(path):
+            return False
+        if path.startswith("test/") or path.startswith("tests/"):
+            return False
+        return True
+
+    def create_source_archives(self) -> None:
+        source_collector = SourceCollector(root=self.root, commit=self.commit, executer=self.executer, filter=self._path_filter)
+        print(f"Collecting sources of {self.project}...")
+        archive_tree = source_collector.get_archive_file_tree()
+        latest_mod_time = archive_tree.get_latest_mod_time()
+        archive_tree.add_file(NodeInArchive.from_text(arcpath=REVISION_TXT, text=f"{self.revision}\n", time=latest_mod_time))
+        archive_tree.add_file(NodeInArchive.from_text(arcpath=f"{GIT_HASH_FILENAME}", text=f"{self.commit}\n", time=latest_mod_time))
+        archive_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["source"].get("files", {}), file_mapping_root=self.root, context=self.get_context(), time=latest_mod_time)
+
+        archive_base = f"{self.project}-{self.version}"
+        zip_path = self.dist_path / f"{archive_base}.zip"
+        tgz_path = self.dist_path / f"{archive_base}.tar.gz"
+        txz_path = self.dist_path / f"{archive_base}.tar.xz"
+
+        logger.info("Creating zip/tgz/txz source archives ...")
+        if self.dry:
+            zip_path.touch()
+            tgz_path.touch()
+            txz_path.touch()
+        else:
+            with Archiver(zip_path=zip_path, tgz_path=tgz_path, txz_path=txz_path) as archiver:
+                print(f"Adding source files of {self.project}...")
+                archive_tree.add_to_archiver(archive_base=archive_base, archiver=archiver)
+
+                for extra_repo in self.release_info["source"].get("extra-repos", []):
+                    extra_repo_root = self.root / extra_repo
+                    assert (extra_repo_root / ".git").exists(), f"{extra_repo_root} must be a git repo"
+                    extra_repo_commit = self.executer.check_output(["git", "rev-parse", "HEAD"], dry_out=f"gitsha-extra-repo-{extra_repo}", cwd=extra_repo_root).strip()
+                    extra_repo_source_collector = SourceCollector(root=extra_repo_root, commit=extra_repo_commit, executer=self.executer, filter=self._external_repo_path_filter)
+                    print(f"Collecting sources of {extra_repo} ...")
+                    extra_repo_archive_tree = extra_repo_source_collector.get_archive_file_tree()
+                    print(f"Adding source files of {extra_repo} ...")
+                    extra_repo_archive_tree.add_to_archiver(archive_base=f"{archive_base}/{extra_repo}", archiver=archiver)
+
+            for file in self.release_info["source"]["checks"]:
+                assert f"{archive_base}/{file}" in archiver.added_files, f"'{archive_base}/{file}' must exist"
+
+        logger.info("... done")
+
+        self.artifacts["src-zip"] = zip_path
+        self.artifacts["src-tar-gz"] = tgz_path
+        self.artifacts["src-tar-xz"] = txz_path
+
+        if not self.dry:
+            with tgz_path.open("r+b") as f:
+                # Zero the embedded timestamp in the gzip'ed tarball
+                f.seek(4, 0)
+                f.write(b"\x00\x00\x00\x00")
+
+    def create_dmg(self, configuration: str="Release") -> None:
+        dmg_in = self.root / self.release_info["dmg"]["path"]
+        xcode_project = self.root / self.release_info["dmg"]["project"]
+        assert xcode_project.is_dir(), f"{xcode_project} must be a directory"
+        assert (xcode_project / "project.pbxproj").is_file, f"{xcode_project} must contain project.pbxproj"
+        if not self.fast:
+            dmg_in.unlink(missing_ok=True)
+        build_xcconfig = self.release_info["dmg"].get("build-xcconfig")
+        if build_xcconfig:
+            shutil.copy(self.root / build_xcconfig, xcode_project.parent / "build.xcconfig")
+
+        xcode_scheme = self.release_info["dmg"].get("scheme")
+        xcode_target = self.release_info["dmg"].get("target")
+        assert xcode_scheme or xcode_target, "dmg needs scheme or target"
+        assert not (xcode_scheme and xcode_target), "dmg cannot have both scheme and target set"
+        if xcode_scheme:
+            scheme_or_target = "-scheme"
+            target_like = xcode_scheme
+        else:
+            scheme_or_target = "-target"
+            target_like = xcode_target
+        self.executer.run(["xcodebuild", "ONLY_ACTIVE_ARCH=NO", "-project", xcode_project, scheme_or_target, target_like, "-configuration", configuration])
+        if self.dry:
+            dmg_in.parent.mkdir(parents=True, exist_ok=True)
+            dmg_in.touch()
+
+        assert dmg_in.is_file(), f"{self.project}.dmg was not created by xcodebuild"
+
+        dmg_out = self.dist_path / f"{self.project}-{self.version}.dmg"
+        shutil.copy(dmg_in, dmg_out)
+        self.artifacts["dmg"] = dmg_out
+
+    @property
+    def git_hash_data(self) -> bytes:
+        return f"{self.commit}\n".encode()
+
+    def create_mingw_archives(self) -> None:
+        build_type = "Release"
+        build_parent_dir = self.root / "build-mingw"
+        ARCH_TO_GNU_ARCH = {
+            # "arm64": "aarch64",
+            "x86": "i686",
+            "x64": "x86_64",
+        }
+        ARCH_TO_TRIPLET = {
+            # "arm64": "aarch64-w64-mingw32",
+            "x86": "i686-w64-mingw32",
+            "x64": "x86_64-w64-mingw32",
+        }
+
+        new_env = dict(os.environ)
+
+        cmake_prefix_paths = []
+        mingw_deps_path = self.deps_path / "mingw-deps"
+
+        if "dependencies" in self.release_info["mingw"]:
+            shutil.rmtree(mingw_deps_path, ignore_errors=True)
+            mingw_deps_path.mkdir()
+
+            for triplet in ARCH_TO_TRIPLET.values():
+                (mingw_deps_path / triplet).mkdir()
+
+            def extract_filter(member: tarfile.TarInfo, path: str, /):
+                if member.name.startswith("SDL"):
+                    member.name = "/".join(Path(member.name).parts[1:])
+                return member
+            for dep in self.release_info.get("dependencies", {}):
+                extract_path = mingw_deps_path / f"extract-{dep}"
+                extract_path.mkdir()
+                with chdir(extract_path):
+                    tar_path = self.deps_path / glob.glob(self.release_info["mingw"]["dependencies"][dep]["artifact"], root_dir=self.deps_path)[0]
+                    logger.info("Extracting %s to %s", tar_path, mingw_deps_path)
+                    assert tar_path.suffix in (".gz", ".xz")
+                    with tarfile.open(tar_path, mode=f"r:{tar_path.suffix.strip('.')}") as tarf:
+                        tarf.extractall(filter=extract_filter)
+                    for arch, triplet in ARCH_TO_TRIPLET.items():
+                        install_cmd = self.release_info["mingw"]["dependencies"][dep]["install-command"]
+                        extra_configure_data = {
+                            "ARCH": ARCH_TO_GNU_ARCH[arch],
+                            "TRIPLET": triplet,
+                            "PREFIX": str(mingw_deps_path / triplet),
+                        }
+                        install_cmd = configure_text(install_cmd, context=self.get_context(extra_configure_data))
+                        self.executer.run(shlex.split(install_cmd), cwd=str(extract_path))
+
+            dep_binpath = mingw_deps_path / triplet / "bin"
+            assert dep_binpath.is_dir(), f"{dep_binpath} for PATH should exist"
+            dep_pkgconfig = mingw_deps_path / triplet / "lib/pkgconfig"
+            assert dep_pkgconfig.is_dir(), f"{dep_pkgconfig} for PKG_CONFIG_PATH should exist"
+
+            new_env["PATH"] = os.pathsep.join([str(dep_binpath), new_env["PATH"]])
+            new_env["PKG_CONFIG_PATH"] = str(dep_pkgconfig)
+            cmake_prefix_paths.append(mingw_deps_path)
+
+        new_env["CFLAGS"] = f"-O2 -ffile-prefix-map={self.root}=/src/{self.project}"
+        new_env["CXXFLAGS"] = f"-O2 -ffile-prefix-map={self.root}=/src/{self.project}"
+
+        assert any(system in self.release_info["mingw"] for system in ("autotools", "cmake"))
+        assert not all(system in self.release_info["mingw"] for system in ("autotools", "cmake"))
+
+        mingw_archs = set()
+        arc_root = f"{self.project}-{self.version}"
+        archive_file_tree = ArchiveFileTree()
+
+        if "autotools" in self.release_info["mingw"]:
+            for arch in self.release_info["mingw"]["autotools"]["archs"]:
+                triplet = ARCH_TO_TRIPLET[arch]
+                new_env["CC"] = f"{triplet}-gcc"
+                new_env["CXX"] = f"{triplet}-g++"
+                new_env["RC"] = f"{triplet}-windres"
+
+                assert arch not in mingw_archs
+                mingw_archs.add(arch)
+
+                build_path = build_parent_dir / f"build-{triplet}"
+                install_path = build_parent_dir / f"install-{triplet}"
+                shutil.rmtree(install_path, ignore_errors=True)
+                build_path.mkdir(parents=True, exist_ok=True)
+                context = self.get_context({
+                    "ARCH": arch,
+                    "DEP_PREFIX": str(mingw_deps_path / triplet),
+                })
+                extra_args = configure_text_list(text_list=self.release_info["mingw"]["autotools"]["args"], context=context)
+
+                with self.section_printer.group(f"Configuring MinGW {triplet} (autotools)"):
+                    assert "@" not in " ".join(extra_args), f"@ should not be present in extra arguments ({extra_args})"
+                    self.executer.run([
+                        self.root / "configure",
+                        f"--prefix={install_path}",
+                        f"--includedir=${{prefix}}/include",
+                        f"--libdir=${{prefix}}/lib",
+                        f"--bindir=${{prefix}}/bin",
+                        f"--exec-prefix=${{prefix}}/bin",
+                        f"--host={triplet}",
+                        f"--build=x86_64-none-linux-gnu",
+                        "CFLAGS=-O2",
+                        "CXXFLAGS=-O2",
+                        "LDFLAGS=-Wl,-s",
+                    ] + extra_args, cwd=build_path, env=new_env)
+                with self.section_printer.group(f"Build MinGW {triplet} (autotools)"):
+                    self.executer.run(["make", "V=1", f"-j{self.cpu_count}"], cwd=build_path, env=new_env)
+                with self.section_printer.group(f"Install MinGW {triplet} (autotools)"):
+                    self.executer.run(["make", "install"], cwd=build_path, env=new_env)
+                archive_file_tree.add_directory_tree(arc_dir=arc_join(arc_root, triplet), path=install_path, time=self.arc_time)
+
+                print("Recording arch-dependent extra files for MinGW development archive ...")
+                extra_context = {
+                    "TRIPLET": ARCH_TO_TRIPLET[arch],
+                }
+                archive_file_tree.add_file_mapping(arc_dir=arc_root, file_mapping=self.release_info["mingw"]["autotools"].get("files", {}), file_mapping_root=self.root, context=self.get_context(extra_context=extra_context), time=self.arc_time)
+
+        if "cmake" in self.release_info["mingw"]:
+            assert self.release_info["mingw"]["cmake"]["shared-static"] in ("args", "both")
+            for arch in self.release_info["mingw"]["cmake"]["archs"]:
+                triplet = ARCH_TO_TRIPLET[arch]
+                new_env["CC"] = f"{triplet}-gcc"
+                new_env["CXX"] = f"{triplet}-g++"
+                new_env["RC"] = f"{triplet}-windres"
+
+                assert arch not in mingw_archs
+                mingw_archs.add(arch)
+
+                context = self.get_context({
+                    "ARCH": arch,
+                    "DEP_PREFIX": str(mingw_deps_path / triplet),
+                })
+                extra_args = configure_text_list(text_list=self.release_info["mingw"]["cmake"]["args"], context=context)
+
+                build_path = build_parent_dir / f"build-{triplet}"
+                install_path = build_parent_dir / f"install-{triplet}"
+                shutil.rmtree(install_path, ignore_errors=True)
+                build_path.mkdir(parents=True, exist_ok=True)
+                if self.release_info["mingw"]["cmake"]["shared-static"] == "args":
+                    args_for_shared_static = ([], )
+                elif self.release_info["mingw"]["cmake"]["shared-static"] == "both":
+                    args_for_shared_static = (["-DBUILD_SHARED_LIBS=ON"], ["-DBUILD_SHARED_LIBS=OFF"])
+                for arg_for_shared_static in args_for_shared_static:
+                    with self.section_printer.group(f"Configuring MinGW {triplet} (CMake)"):
+                        assert "@" not in " ".join(extra_args), f"@ should not be present in extra arguments ({extra_args})"
+                        self.executer.run([
+                            f"cmake",
+                            f"-S", str(self.root), "-B", str(build_path),
+                            f"-DCMAKE_BUILD_TYPE={build_type}",
+                            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_PREFIX_PATH={mingw_deps_path / triplet}",
+                            f"-DCMAKE_INSTALL_PREFIX={install_path}",
+                            f"-DCMAKE_INSTALL_INCLUDEDIR=include",
+                            f"-DCMAKE_INSTALL_LIBDIR=lib",
+                            f"-DCMAKE_INSTALL_BINDIR=bin",
+                            f"-DCMAKE_INSTALL_DATAROOTDIR=share",
+                            f"-DCMAKE_TOOLCHAIN_FILE={self.root}/build-scripts/cmake-toolchain-mingw64-{ARCH_TO_GNU_ARCH[arch]}.cmake",
+                            f"-G{self.cmake_generator}",
+                        ] + extra_args + ([] if self.fast else ["--fresh"]) + arg_for_shared_static, cwd=build_path, env=new_env)
+                    with self.section_printer.group(f"Build MinGW {triplet} (CMake)"):
+                        self.executer.run(["cmake", "--build", str(build_path), "--verbose", "--config", build_type], cwd=build_path, env=new_env)
+                    with self.section_printer.group(f"Install MinGW {triplet} (CMake)"):
+                        self.executer.run(["cmake", "--install", str(build_path)], cwd=build_path, env=new_env)
+                archive_file_tree.add_directory_tree(arc_dir=arc_join(arc_root, triplet), path=install_path, time=self.arc_time)
+
+                print("Recording arch-dependent extra files for MinGW development archive ...")
+                extra_context = {
+                    "TRIPLET": ARCH_TO_TRIPLET[arch],
+                }
+                archive_file_tree.add_file_mapping(arc_dir=arc_root, file_mapping=self.release_info["mingw"]["cmake"].get("files", {}), file_mapping_root=self.root, context=self.get_context(extra_context=extra_context), time=self.arc_time)
+                print("... done")
+
+        print("Recording extra files for MinGW development archive ...")
+        archive_file_tree.add_file_mapping(arc_dir=arc_root, file_mapping=self.release_info["mingw"].get("files", {}), file_mapping_root=self.root, context=self.get_context(), time=self.arc_time)
+        print("... done")
+
+        print("Creating zip/tgz/txz development archives ...")
+        zip_path = self.dist_path / f"{self.project}-devel-{self.version}-mingw.zip"
+        tgz_path = self.dist_path / f"{self.project}-devel-{self.version}-mingw.tar.gz"
+        txz_path = self.dist_path / f"{self.project}-devel-{self.version}-mingw.tar.xz"
+
+        with Archiver(zip_path=zip_path, tgz_path=tgz_path, txz_path=txz_path) as archiver:
+            archive_file_tree.add_to_archiver(archive_base="", archiver=archiver)
+            archiver.add_git_hash(arcdir=arc_root, commit=self.commit, time=self.arc_time)
+        print("... done")
+
+        self.artifacts["mingw-devel-zip"] = zip_path
+        self.artifacts["mingw-devel-tar-gz"] = tgz_path
+        self.artifacts["mingw-devel-tar-xz"] = txz_path
+
+    def _detect_android_api(self, android_home: str) -> typing.Optional[int]:
+        platform_dirs = list(Path(p) for p in glob.glob(f"{android_home}/platforms/android-*"))
+        re_platform = re.compile("android-([0-9]+)")
+        platform_versions = []
+        for platform_dir in platform_dirs:
+            logger.debug("Found Android Platform SDK: %s", platform_dir)
+            if m:= re_platform.match(platform_dir.name):
+                platform_versions.append(int(m.group(1)))
+        platform_versions.sort()
+        logger.info("Available platform versions: %s", platform_versions)
+        platform_versions = list(filter(lambda v: v >= self._android_api_minimum, platform_versions))
+        logger.info("Valid platform versions (>=%d): %s", self._android_api_minimum, platform_versions)
+        if not platform_versions:
+            return None
+        android_api = platform_versions[0]
+        logger.info("Selected API version %d", android_api)
+        return android_api
+
+    def _get_prefab_json_text(self) -> str:
+        return textwrap.dedent(f"""\
+            {{
+                "schema_version": 2,
+                "name": "{self.project}",
+                "version": "{self.version}",
+                "dependencies": []
+            }}
+        """)
+
+    def _get_prefab_module_json_text(self, library_name: typing.Optional[str], export_libraries: list[str]) -> str:
+        for lib in export_libraries:
+            assert isinstance(lib, str), f"{lib} must be a string"
+        module_json_dict = {
+            "export_libraries": export_libraries,
+        }
+        if library_name:
+            module_json_dict["library_name"] = f"lib{library_name}"
+        return json.dumps(module_json_dict, indent=4)
+
+    @property
+    def _android_api_minimum(self):
+        return self.release_info["android"]["api-minimum"]
+
+    @property
+    def _android_api_target(self):
+        return self.release_info["android"]["api-target"]
+
+    @property
+    def _android_ndk_minimum(self):
+        return self.release_info["android"]["ndk-minimum"]
+
+    def _get_prefab_abi_json_text(self, abi: str, cpp: bool, shared: bool) -> str:
+        abi_json_dict = {
+            "abi": abi,
+            "api": self._android_api_minimum,
+            "ndk": self._android_ndk_minimum,
+            "stl": "c++_shared" if cpp else "none",
+            "static": not shared,
+        }
+        return json.dumps(abi_json_dict, indent=4)
+
+    def _get_android_manifest_text(self) -> str:
+        return textwrap.dedent(f"""\
+            <manifest
+                xmlns:android="http://schemas.android.com/apk/res/android"
+                package="org.libsdl.android.{self.project}" android:versionCode="1"
+                android:versionName="1.0">
+                <uses-sdk android:minSdkVersion="{self._android_api_minimum}"
+                          android:targetSdkVersion="{self._android_api_target}" />
+            </manifest>
+        """)
+
+    def create_android_archives(self, android_api: int, android_home: Path, android_ndk_home: Path) -> None:
+        cmake_toolchain_file = Path(android_ndk_home) / "build/cmake/android.toolchain.cmake"
+        if not cmake_toolchain_file.exists():
+            logger.error("CMake toolchain file does not exist (%s)", cmake_toolchain_file)
+            raise SystemExit(1)
+        aar_path =  self.dist_path / f"{self.project}-{self.version}.aar"
+        android_abis = self.release_info["android"]["abis"]
+        java_jars_added = False
+        module_data_added = False
+        android_deps_path = self.deps_path / "android-deps"
+        shutil.rmtree(android_deps_path, ignore_errors=True)
+
+        for dep, depinfo in self.release_info["android"].get("dependencies", {}).items():
+            android_aar = self.deps_path / glob.glob(depinfo["artifact"], root_dir=self.deps_path)[0]
+            with self.section_printer.group(f"Extracting Android dependency {dep} ({android_aar.name})"):
+                self.executer.run([sys.executable, str(android_aar), "-o", str(android_deps_path)])
+
+        for module_name, module_info in self.release_info["android"]["modules"].items():
+            assert "type" in module_info and module_info["type"] in ("interface", "library"), f"module {module_name} must have a valid type"
+
+        archive_file_tree = ArchiveFileTree()
+
+        for android_abi in android_abis:
+            with self.section_printer.group(f"Building for Android {android_api} {android_abi}"):
+                build_dir = self.root / "build-android" / f"{android_abi}-build"
+                install_dir = self.root / "install-android" / f"{android_abi}-install"
+                shutil.rmtree(install_dir, ignore_errors=True)
+                assert not install_dir.is_dir(), f"{install_dir} should not exist prior to build"
+                build_type = "Release"
+                cmake_args = [
+                    "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}"''',
+                    f"-DCMAKE_TOOLCHAIN_FILE={cmake_toolchain_file}",
+                    f"-DCMAKE_PREFIX_PATH={str(android_deps_path)}",
+                    f"-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=BOTH",
+                    f"-DANDROID_HOME={android_home}",
+                    f"-DANDROID_PLATFORM={android_api}",
+                    f"-DANDROID_ABI={android_abi}",
+                    "-DCMAKE_POSITION_INDEPENDENT_CODE=ON",
+                    f"-DCMAKE_INSTALL_PREFIX={install_dir}",
+                    "-DCMAKE_INSTALL_INCLUDEDIR=include ",
+                    "-DCMAKE_INSTALL_LIBDIR=lib",
+                    "-DCMAKE_INSTALL_DATAROOTDIR=share",
+                    f"-DCMAKE_BUILD_TYPE={build_type}",
+                    f"-G{self.cmake_generator}",
+                ] + self.release_info["android"]["cmake"]["args"] + ([] if self.fast else ["--fresh"])
+                build_args = [
+                    "cmake",
+                    "--build", str(build_dir),
+                    "--verbose",
+                    "--config", build_type,
+                ]
+                install_args = [
+                    "cmake",
+                    "--install", str(build_dir),
+                    "--config", build_type,
+                ]
+                self.executer.run(cmake_args)
+                self.executer.run(build_args)
+                self.executer.run(install_args)
+
+                for module_name, module_info in self.release_info["android"]["modules"].items():
+                    arcdir_prefab_module = f"prefab/modules/{module_name}"
+                    if module_info["type"] == "library":
+                        library = install_dir / module_info["library"]
+                        assert library.suffix in (".so", ".a")
+                        assert library.is_file(), f"CMake should have built library '{library}' for module {module_name}"
+                        arcdir_prefab_libs = f"{arcdir_prefab_module}/libs/android.{android_abi}"
+                        archive_file_tree.add_file(NodeInArchive.from_fs(arcpath=f"{arcdir_prefab_libs}/{library.name}", path=library, time=self.arc_time))
+                        archive_file_tree.add_file(NodeInArchive.from_text(arcpath=f"{arcdir_prefab_libs}/abi.json", text=self._get_prefab_abi_json_text(abi=android_abi, cpp=False, shared=library.suffix == ".so"), time=self.arc_time))
+
+                    if not module_data_added:
+                        library_name = None
+                        if module_info["type"] == "library":
+                            library_name = Path(module_info["library"]).stem.removeprefix("lib")
+                        export_libraries = module_info.get("export-libraries", [])
+                        archive_file_tree.add_file(NodeInArchive.from_text(arcpath=arc_join(arcdir_prefab_module, "module.json"), text=self._get_prefab_module_json_text(library_name=library_name, export_libraries=export_libraries), time=self.arc_time))
+                        arcdir_prefab_include = f"prefab/modules/{module_name}/include"
+                        if "includes" in module_info:
+                            archive_file_tree.add_file_mapping(arc_dir=arcdir_prefab_include, file_mapping=module_info["includes"], file_mapping_root=install_dir, context=self.get_context(), time=self.arc_time)
+                        else:
+                            archive_file_tree.add_file(NodeInArchive.from_text(arcpath=arc_join(arcdir_prefab_include, ".keep"), text="\n", time=self.arc_time))
+                module_data_added = True
+
+                if not java_jars_added:
+                    java_jars_added = True
+                    if "jars" in self.release_info["android"]:
+                        classes_jar_path = install_dir / configure_text(text=self.release_info["android"]["jars"]["classes"], context=self.get_context())
+                        sources_jar_path = install_dir / configure_text(text=self.release_info["android"]["jars"]["sources"], context=self.get_context())
+                        doc_jar_path = install_dir / configure_text(text=self.release_info["android"]["jars"]["doc"], context=self.get_context())
+                        assert classes_jar_path.is_file(), f"CMake should have compiled the java sources and archived them into a JAR ({classes_jar_path})"
+                        assert sources_jar_path.is_file(), f"CMake should have archived the java sources into a JAR ({sources_jar_path})"
+                        assert doc_jar_path.is_file(), f"CMake should have archived javadoc into a JAR ({doc_jar_path})"
+
+                        archive_file_tree.add_file(NodeInArchive.from_fs(arcpath="classes.jar", path=classes_jar_path, time=self.arc_time))
+                        archive_file_tree.add_file(NodeInArchive.from_fs(arcpath="classes-sources.jar", path=sources_jar_path, time=self.arc_time))
+                        archive_file_tree.add_file(NodeInArchive.from_fs(arcpath="classes-doc.jar", path=doc_jar_path, time=self.arc_time))
+
+        assert ("jars" in self.release_info["android"] and java_jars_added) or "jars" not in self.release_info["android"], "Must have archived java JAR archives"
+
+        archive_file_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["android"].get("files", {}), file_mapping_root=self.root, context=self.get_context(), time=self.arc_time)
+
+        archive_file_tree.add_file(NodeInArchive.from_text(arcpath="prefab/prefab.json", text=self._get_prefab_json_text(), time=self.arc_time))
+        archive_file_tree.add_file(NodeInArchive.from_text(arcpath="AndroidManifest.xml", text=self._get_android_manifest_text(), time=self.arc_time))
+
+        with Archiver(zip_path=aar_path) as archiver:
+            archive_file_tree.add_to_archiver(archive_base="", archiver=archiver)
+            archiver.add_git_hash(arcdir="", commit=self.commit, time=self.arc_time)
+        self.artifacts[f"android-aar"] = aar_path
+
+    def download_dependencies(self):
+        shutil.rmtree(self.deps_path, ignore_errors=True)
+        self.deps_path.mkdir(parents=True)
+
+        if self.github:
+            with open(os.environ["GITHUB_OUTPUT"], "a") as f:
+                f.write(f"dep-path={self.deps_path.absolute()}\n")
+
+        for dep, depinfo in self.release_info.get("dependencies", {}).items():
+            startswith = depinfo["startswith"]
+            dep_repo = depinfo["repo"]
+            # FIXME: dropped "--exclude-pre-releases"
+            dep_string_data = self.executer.check_output(["gh", "-R", dep_repo, "release", "list", "--exclude-drafts", "--json", "name,createdAt,tagName", "--jq", f'[.[]|select(.name|startswith("{startswith}"))]|max_by(.createdAt)']).strip()
+            dep_data = json.loads(dep_string_data)
+            dep_tag = dep_data["tagName"]
+            dep_version = dep_data["name"]
+            logger.info("Download dependency %s version %s (tag=%s) ", dep, dep_version, dep_tag)
+            self.executer.run(["gh", "-R", dep_repo, "release", "download", dep_tag], cwd=self.deps_path)
+            if self.github:
+                with open(os.environ["GITHUB_OUTPUT"], "a") as f:
+                    f.write(f"dep-{dep.lower()}-version={dep_version}\n")
+
+    def verify_dependencies(self):
+        for dep, depinfo in self.release_info.get("dependencies", {}).items():
+            if "mingw" in self.release_info:
+                mingw_matches = glob.glob(self.release_info["mingw"]["dependencies"][dep]["artifact"], root_dir=self.deps_path)
+                assert len(mingw_matches) == 1, f"Exactly one archive matches mingw {dep} dependency: {mingw_matches}"
+            if "dmg" in self.release_info:
+                dmg_matches = glob.glob(self.release_info["dmg"]["dependencies"][dep]["artifact"], root_dir=self.deps_path)
+                assert len(dmg_matches) == 1, f"Exactly one archive matches dmg {dep} dependency: {dmg_matches}"
+            if "msvc" in self.release_info:
+                msvc_matches = glob.glob(self.release_info["msvc"]["dependencies"][dep]["artifact"], root_dir=self.deps_path)
+                assert len(msvc_matches) == 1, f"Exactly one archive matches msvc {dep} dependency: {msvc_matches}"
+            if "android" in self.release_info:
+                android_matches = glob.glob(self.release_info["android"]["dependencies"][dep]["artifact"], root_dir=self.deps_path)
+                assert len(android_matches) == 1, f"Exactly one archive matches msvc {dep} dependency: {msvc_matches}"
+
+    @staticmethod
+    def _arch_to_vs_platform(arch: str, configuration: str="Release") -> VsArchPlatformConfig:
+        ARCH_TO_VS_PLATFORM = {
+            "x86": VsArchPlatformConfig(arch="x86", platform="Win32", configuration=configuration),
+            "x64": VsArchPlatformConfig(arch="x64", platform="x64", configuration=configuration),
+            "arm64": VsArchPlatformConfig(arch="arm64", platform="ARM64", configuration=configuration),
+        }
+        return ARCH_TO_VS_PLATFORM[arch]
+
+    def build_msvc(self):
+        with self.section_printer.group("Find Visual Studio"):
+            vs = VisualStudio(executer=self.executer)
+        for arch in self.release_info["msvc"].get("msbuild", {}).get("archs", []):
+            self._build_msvc_msbuild(arch_platform=self._arch_to_vs_platform(arch=arch), vs=vs)
+        if "cmake" in self.release_info["msvc"]:
+            deps_path = self.root / "msvc-deps"
+            shutil.rmtree(deps_path, ignore_errors=True)
+            dep_roots = []
+            for dep, depinfo in self.release_info["msvc"].get("dependencies", {}).items():
+                dep_extract_path = deps_path / f"extract-{dep}"
+                msvc_zip = self.deps_path / glob.glob(depinfo["artifact"], root_dir=self.deps_path)[0]
+                with zipfile.ZipFile(msvc_zip, "r") as zf:
+                    zf.extractall(dep_extract_path)
+                contents_msvc_zip = glob.glob(str(dep_extract_path / "*"))
+                assert len(contents_msvc_zip) == 1, f"There must be exactly one root item in the root directory of {dep}"
+                dep_roots.append(contents_msvc_zip[0])
+
+            for arch in self.release_info["msvc"].get("cmake", {}).get("archs", []):
+                self._build_msvc_cmake(arch_platform=self._arch_to_vs_platform(arch=arch), dep_roots=dep_roots)
+        with self.section_printer.group("Create SDL VC development zip"):
+            self._build_msvc_devel()
+
+    def _build_msvc_msbuild(self, arch_platform: VsArchPlatformConfig, vs: VisualStudio):
+        platform_context = self.get_context(arch_platform.extra_context())
+        for dep, depinfo in self.release_info["msvc"].get("dependencies", {}).items():
+            msvc_zip = self.deps_path / glob.glob(depinfo["artifact"], root_dir=self.deps_path)[0]
+
+            src_globs = [configure_text(instr["src"], context=platform_context) for instr in depinfo["copy"]]
+            with zipfile.ZipFile(msvc_zip, "r") as zf:
+                for member in zf.namelist():
+                    member_path = "/".join(Path(member).parts[1:])
+                    for src_i, src_glob in enumerate(src_globs):
+                        if fnmatch.fnmatch(member_path, src_glob):
+                            dst = (self.root / configure_text(depinfo["copy"][src_i]["dst"], context=platform_context)).resolve() / Path(member_path).name
+                            zip_data = zf.read(member)
+                            if dst.exists():
+                                identical = False
+                                if dst.is_file():
+                                    orig_bytes = dst.read_bytes()
+                                    if orig_bytes == zip_data:
+                                        identical = True
+                                if not identical:
+                                    logger.warning("Extracting dependency %s, will cause %s to be overwritten", dep, dst)
+                                    if not self.overwrite:
+                                        raise RuntimeError("Run with --overwrite to allow overwriting")
+                            logger.debug("Extracting %s -> %s", member, dst)
+
+                            dst.parent.mkdir(exist_ok=True, parents=True)
+                            dst.write_bytes(zip_data)
+
+        prebuilt_paths = set(self.root / full_prebuilt_path for prebuilt_path in self.release_info["msvc"]["msbuild"].get("prebuilt", []) for full_prebuilt_path in glob.glob(configure_text(prebuilt_path, context=platform_context), root_dir=self.root))
+        msbuild_paths = set(self.root / configure_text(f, context=platform_context) for file_mapping in (self.release_info["msvc"]["msbuild"]["files-lib"], self.release_info["msvc"]["msbuild"]["files-devel"]) for files_list in file_mapping.values() for f in files_list)
+        assert prebuilt_paths.issubset(msbuild_paths), f"msvc.msbuild.prebuilt must be a subset of (msvc.msbuild.files-lib, msvc.msbuild.files-devel)"
+        built_paths = msbuild_paths.difference(prebuilt_paths)
+        logger.info("MSbuild builds these files, to be included in the package: %s", built_paths)
+        if not self.fast:
+            for b in built_paths:
+                b.unlink(missing_ok=True)
+
+        rel_projects: list[str] = self.release_info["msvc"]["msbuild"]["projects"]
+        projects = list(self.root / p for p in rel_projects)
+
+        directory_build_props_src_relpath = self.release_info["msvc"]["msbuild"].get("directory-build-props")
+        for project in projects:
+            dir_b_props = project.parent / "Directory.Build.props"
+            dir_b_props.unlink(missing_ok = True)
+            if directory_build_props_src_relpath:
+                src = self.root / directory_build_props_src_relpath
+                logger.debug("Copying %s -> %s", src, dir_b_props)
+                shutil.copy(src=src, dst=dir_b_props)
+
+        with self.section_printer.group(f"Build {arch_platform.arch} VS binary"):
+            vs.build(arch_platform=arch_platform, projects=projects)
+
+        if self.dry:
+            for b in built_paths:
+                b.parent.mkdir(parents=True, exist_ok=True)
+                b.touch()
+
+        for b in built_paths:
+            assert b.is_file(), f"{b} has not been created"
+            b.parent.mkdir(parents=True, exist_ok=True)
+            b.touch()
+
+        zip_path = self.dist_path / f"{self.project}-{self.version}-win32-{arch_platform.arch}.zip"
+        zip_path.unlink(missing_ok=True)
+
+        logger.info("Collecting files...")
+        archive_file_tree = ArchiveFileTree()
+        archive_file_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["msvc"]["msbuild"]["files-lib"], file_mapping_root=self.root, context=platform_context, time=self.arc_time)
+        archive_file_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["msvc"]["files-lib"], file_mapping_root=self.root, context=platform_context, time=self.arc_time)
+
+        logger.info("Writing to %s", zip_path)
+        with Archiver(zip_path=zip_path) as archiver:
+            arc_root = f""
+            archive_file_tree.add_to_archiver(archive_base=arc_root, archiver=archiver)
+            archiver.add_git_hash(arcdir=arc_root, commit=self.commit, time=self.arc_time)
+        self.artifacts[f"VC-{arch_platform.arch}"] = zip_path
+
+        for p in built_paths:
+            assert p.is_file(), f"{p} should exist"
+
+    def _arch_platform_to_build_path(self, arch_platform: VsArchPlatformConfig) -> Path:
+        return self.root / f"build-vs-{arch_platform.arch}"
+
+    def _arch_platform_to_install_path(self, arch_platform: VsArchPlatformConfig) -> Path:
+        return self._arch_platform_to_build_path(arch_platform) / "prefix"
+
+    def _build_msvc_cmake(self, arch_platform: VsArchPlatformConfig, dep_roots: list[Path]):
+        build_path = self._arch_platform_to_build_path(arch_platform)
+        install_path = self._arch_platform_to_install_path(arch_platform)
+        platform_context = self.get_context(extra_context=arch_platform.extra_context())
+
+        build_type = "Release"
+
+        built_paths = set(install_path / configure_text(f, context=platform_context) for file_mapping in (self.release_info["msvc"]["cmake"]["files-lib"], self.release_info["msvc"]["cmake"]["files-devel"]) for files_list in file_mapping.values() for f in files_list)
+        logger.info("CMake builds these files, to be included in the package: %s", built_paths)
+        if not self.fast:
+            for b in built_paths:
+                b.unlink(missing_ok=True)
+
+        shutil.rmtree(install_path, ignore_errors=True)
+        build_path.mkdir(parents=True, exist_ok=True)
+        with self.section_printer.group(f"Configure VC CMake project for {arch_platform.arch}"):
+            self.executer.run([
+                "cmake", "-S", str(self.root), "-B", str(build_path),
+                "-A", arch_platform.platform,
+                "-DCMAKE_INSTALL_BINDIR=bin",
+                "-DCMAKE_INSTALL_DATAROOTDIR=share",
+                "-DCMAKE_INSTALL_INCLUDEDIR=include",
+                "-DCMAKE_INSTALL_LIBDIR=lib",
+                f"-DCMAKE_BUILD_TYPE={build_type}",
+                f"-DCMAKE_INSTALL_PREFIX={install_path}",
+                # MSVC debug information format flags are selected by an abstraction
+                "-DCMAKE_POLICY_DEFAULT_CMP0141=NEW",
+                # MSVC debug information format
+                "-DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=ProgramDatabase",
+                # Linker flags for executables
+                "-DCMAKE_EXE_LINKER_FLAGS=-INCREMENTAL:NO -DEBUG -OPT:REF -OPT:ICF",
+                # Linker flag for shared libraries
+                "-DCMAKE_SHARED_LINKER_FLAGS=-INCREMENTAL:NO -DEBUG -OPT:REF -OPT:ICF",
+                # MSVC runtime library flags are selected by an abstraction
+                "-DCMAKE_POLICY_DEFAULT_CMP0091=NEW",
+                # Use statically linked runtime (-MT) (ideally, should be "MultiThreaded$<$<CONFIG:Debug>:Debug>")
+                "-DCMAKE_MSVC_RUNTIME_LIBRARY=MultiThreaded",
+                f"-DCMAKE_PREFIX_PATH={';'.join(str(s) for s in dep_roots)}",
+            ] + self.release_info["msvc"]["cmake"]["args"] + ([] if self.fast else ["--fresh"]))
+
+        with self.section_printer.group(f"Build VC CMake project for {arch_platform.arch}"):
+            self.executer.run(["cmake", "--build", str(build_path), "--verbose", "--config", build_type])
+        with self.section_printer.group(f"Install VC CMake project for {arch_platform.arch}"):
+            self.executer.run(["cmake", "--install", str(build_path), "--config", build_type])
+
+        if self.dry:
+            for b in built_paths:
+                b.parent.mkdir(parents=True, exist_ok=True)
+                b.touch()
+
+        zip_path = self.dist_path / f"{self.project}-{self.version}-win32-{arch_platform.arch}.zip"
+        zip_path.unlink(missing_ok=True)
+
+        logger.info("Collecting files...")
+        archive_file_tree = ArchiveFileTree()
+        archive_file_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["msvc"]["cmake"]["files-lib"], file_mapping_root=install_path, context=platform_context, time=self.arc_time)
+        archive_file_tree.add_file_mapping(arc_dir="", file_mapping=self.release_info["msvc"]["files-lib"], file_mapping_root=self.root, context=self.get_context(), time=self.arc_time)
+
+        logger.info("Creating %s", zip_path)
+        with Archiver(zip_path=zip_path) as archiver:
+            arc_root = f""
+            archive_file_tree.add_to_archiver(archive_base=arc_root, archiver=archiver)
+            archiver.add_git_hash(arcdir=arc_root, commit=self.commit, time=self.arc_time)
+
+        for p in built_paths:
+            assert p.is_file(), f"{p} should exist"
+
+    def _build_msvc_devel(self) -> None:
+        zip_path = self.dist_path / f"{self.project}-devel-{self.version}-VC.zip"
+        arc_root = f"{self.project}-{self.version}"
+
+        def copy_files_devel(ctx):
+            archive_file_tree.add_file_mapping(arc_dir=arc_root, file_mapping=self.release_info["msvc"]["files-devel"], file_mapping_root=self.root, context=ctx, time=self.arc_time)
+
+
+        logger.info("Collecting files...")
+        archive_file_tree = ArchiveFileTree()
+        if "msbuild" in self.release_info["msvc"]:
+            for arch in self.release_info["msvc"]["msbuild"]["archs"]:
+                arch_platform = self._arch_to_vs_platform(arch=arch)
+                platform_context = self.get_context(arch_platform.extra_context())
+                archive_file_tree.add_file_mapping(arc_dir=arc_root, file_mapping=self.release_info["msvc"]["msbuild"]["files-devel"], file_mapping_root=self.root, context=platform_context, time=self.arc_time)
+                copy_files_devel(ctx=platform_context)
+        if "cmake" in self.release_info["msvc"]:
+            for arch in self.release_info["msvc"]["cmake"]["archs"]:
+                arch_platform = self._arch_to_vs_platform(arch=arch)
+                platform_context = self.get_context(arch_platform.extra_context())
+                archive_file_tree.add_file_mapping(arc_dir=arc_root, file_mapping=self.release_info["msvc"]["cmake"]["files-devel"], file_mapping_root=self._arch_platform_to_install_path(arch_platform), context=platform_context, time=self.arc_time)
+                copy_files_devel(ctx=platform_context)
+
+        with Archiver(zip_path=zip_path) as archiver:
+            archive_file_tree.add_to_archiver(archive_base="", archiver=archiver)
+            archiver.add_git_hash(arcdir=arc_root, commit=self.commit, time=self.arc_time)
+        self.artifacts["VC-devel"] = zip_path
+
+    @classmethod
+    def extract_sdl_version(cls, root: Path, release_info: dict) -> str:
+        with open(root / release_info["version"]["file"], "r") as f:
+            text = f.read()
+        major = next(re.finditer(release_info["version"]["re_major"], text, flags=re.M)).group(1)
+        minor = next(re.finditer(release_info["version"]["re_minor"], text, flags=re.M)).group(1)
+        micro = next(re.finditer(release_info["version"]["re_micro"], text, flags=re.M)).group(1)
+        return f"{major}.{minor}.{micro}"
+
+
+def main(argv=None) -> int:
+    if sys.version_info < (3, 11):
+        logger.error("This script needs at least python 3.11")
+        return 1
+
+    parser = argparse.ArgumentParser(allow_abbrev=False, description="Create SDL release artifacts")
+    parser.add_argument("--root", metavar="DIR", type=Path, default=Path(__file__).absolute().parents[1], help="Root of project")
+    parser.add_argument("--release-info", metavar="JSON", dest="path_release_info", type=Path, default=Path(__file__).absolute().parent / "release-info.json", help="Path of release-info.json")
+    parser.add_argument("--dependency-folder", metavar="FOLDER", dest="deps_path", type=Path, default="deps", help="Directory containing pre-built archives of dependencies (will be removed when downloading archives)")
+    parser.add_argument("--out", "-o", metavar="DIR", dest="dist_path", type=Path, default="dist", help="Output directory")
+    parser.add_argument("--github", action="store_true", help="Script is running on a GitHub runner")
+    parser.add_argument("--commit", default="HEAD", help="Git commit/tag of which a release should be created")
+    parser.add_argument("--actions", choices=["download", "source", "android", "mingw", "msvc", "dmg"], required=True, nargs="+", dest="actions", help="What to do?")
+    parser.set_defaults(loglevel=logging.INFO)
+    parser.add_argument('--vs-year', dest="vs_year", help="Visual Studio year")
+    parser.add_argument('--android-api', type=int, dest="android_api", help="Android API version")
+    parser.add_argument('--android-home', dest="android_home", default=os.environ.get("ANDROID_HOME"), help="Android Home folder")
+    parser.add_argument('--android-ndk-home', dest="android_ndk_home", default=os.environ.get("ANDROID_NDK_HOME"), help="Android NDK Home folder")
+    parser.add_argument('--cmake-generator', dest="cmake_generator", default="Ninja", help="CMake Generator")
+    parser.add_argument('--debug', action='store_const', const=logging.DEBUG, dest="loglevel", help="Print script debug information")
+    parser.add_argument('--dry-run', action='store_true', dest="dry", help="Don't execute anything")
+    parser.add_argument('--force', action='store_true', dest="force", help="Ignore a non-clean git tree")
+    parser.add_argument('--overwrite', action='store_true', dest="overwrite", help="Allow potentially overwriting other projects")
+    parser.add_argument('--fast', action='store_true', dest="fast", help="Don't do a rebuild")
+
+    args = parser.parse_args(argv)
+    logging.basicConfig(level=args.loglevel, format='[%(levelname)s] %(message)s')
+    args.deps_path = args.deps_path.absolute()
+    args.dist_path = args.dist_path.absolute()
+    args.root = args.root.absolute()
+    args.dist_path = args.dist_path.absolute()
+    if args.dry:
+        args.dist_path = args.dist_path / "dry"
+
+    if args.github:
+        section_printer: SectionPrinter = GitHubSectionPrinter()
+    else:
+        section_printer = SectionPrinter()
+
+    if args.github and "GITHUB_OUTPUT" not in os.environ:
+        os.environ["GITHUB_OUTPUT"] = "/tmp/github_output.txt"
+
+    executer = Executer(root=args.root, dry=args.dry)
+
+    root_git_hash_path = args.root / GIT_HASH_FILENAME
+    root_is_maybe_archive = root_git_hash_path.is_file()
+    if root_is_maybe_archive:
+        logger.warning("%s detected: Building from archive", GIT_HASH_FILENAME)
+        archive_commit = root_git_hash_path.read_text().strip()
+        if args.commit != archive_commit:
+            logger.warning("Commit argument is %s, but archive commit is %s. Using %s.", args.commit, archive_commit, archive_commit)
+        args.commit = archive_commit
+        revision = (args.root / REVISION_TXT).read_text().strip()
+    else:
+        args.commit = executer.check_output(["git", "rev-parse", args.commit], dry_out="e5812a9fd2cda317b503325a702ba3c1c37861d9").strip()
+        revision = executer.check_output(["git", "describe", "--always", "--tags", "--long", args.commit], dry_out="preview-3.1.3-96-g9512f2144").strip()
+        logger.info("Using commit %s", args.commit)
+
+    try:
+        with args.path_release_info.open() as f:
+            release_info = json.load(f)
+    except FileNotFoundError:
+        logger.error(f"Could not find {args.path_release_info}")
+
+    releaser = Releaser(
+        release_info=release_info,
+        commit=args.commit,
+        revision=revision,
+        root=args.root,
+        dist_path=args.dist_path,
+        executer=executer,
+        section_printer=section_printer,
+        cmake_generator=args.cmake_generator,
+        deps_path=args.deps_path,
+        overwrite=args.overwrite,
+        github=args.github,
+        fast=args.fast,
+    )
+
+    if root_is_maybe_archive:
+        logger.warning("Building from archive. Skipping clean git tree check.")
+    else:
+        porcelain_status = executer.check_output(["git", "status", "--ignored", "--porcelain"], dry_out="\n").strip()
+        if porcelain_status:
+            print(porcelain_status)
+            logger.warning("The tree is dirty! Do not publish any generated artifacts!")
+            if not args.force:
+                raise Exception("The git repo contains modified and/or non-committed files. Run with --force to ignore.")
+
+    if args.fast:
+        logger.warning("Doing fast build! Do not publish generated artifacts!")
+
+    with section_printer.group("Arguments"):
+        print(f"project          = {releaser.project}")
+        print(f"version          = {releaser.version}")
+        print(f"revision         = {revision}")
+        print(f"commit           = {args.commit}")
+        print(f"out              = {args.dist_path}")
+        print(f"actions          = {args.actions}")
+        print(f"dry              = {args.dry}")
+        print(f"force            = {args.force}")
+        print(f"overwrite        = {args.overwrite}")
+        print(f"cmake_generator  = {args.cmake_generator}")
+
+    releaser.prepare()
+
+    if "download" in args.actions:
+        releaser.download_dependencies()
+
+    if set(args.actions).intersection({"msvc", "mingw", "android"}):
+        print("Verifying presence of dependencies (run 'download' action to download) ...")
+        releaser.verify_dependencies()
+        print("... done")
+
+    if "source" in args.actions:
+        if root_is_maybe_archive:
+            raise Exception("Cannot build source archive from source archive")
+        with section_printer.group("Create source archives"):
+            releaser.create_source_archives()
+
+    if "dmg" in args.actions:
+        if platform.system() != "Darwin" and not args.dry:
+            parser.error("framework artifact(s) can only be built on Darwin")
+
+        releaser.create_dmg()
+
+    if "msvc" in args.actions:
+        if platform.system() != "Windows" and not args.dry:
+            parser.error("msvc artifact(s) can only be built on Windows")
+        releaser.build_msvc()
+
+    if "mingw" in args.actions:
+        releaser.create_mingw_archives()
+
+    if "android" in args.actions:
+        if args.android_home is None or not Path(args.android_home).is_dir():
+            parser.error("Invalid $ANDROID_HOME or --android-home: must be a directory containing the Android SDK")
+        if args.android_ndk_home is None or not Path(args.android_ndk_home).is_dir():
+            parser.error("Invalid $ANDROID_NDK_HOME or --android_ndk_home: must be a directory containing the Android NDK")
+        if args.android_api is None:
+            with section_printer.group("Detect Android APIS"):
+                args.android_api = releaser._detect_android_api(android_home=args.android_home)
+        if args.android_api is None or not (Path(args.android_home) / f"platforms/android-{args.android_api}").is_dir():
+            parser.error("Invalid --android-api, and/or could not be detected")
+        with section_printer.group("Android arguments"):
+            print(f"android_home     = {args.android_home}")
+            print(f"android_ndk_home = {args.android_ndk_home}")
+            print(f"android_api      = {args.android_api}")
+        releaser.create_android_archives(
+            android_api=args.android_api,
+            android_home=args.android_home,
+            android_ndk_home=args.android_ndk_home,
+        )
+    with section_printer.group("Summary"):
+        print(f"artifacts = {releaser.artifacts}")
+
+    if args.github:
+        with open(os.environ["GITHUB_OUTPUT"], "a") as f:
+            f.write(f"project={releaser.project}\n")
+            f.write(f"version={releaser.version}\n")
+            for k, v in releaser.artifacts.items():
+                f.write(f"{k}={v.name}\n")
+    return 0
+
+
+if __name__ == "__main__":
+    raise SystemExit(main())

+ 18 - 0
Engine/lib/sdl/build-scripts/cmake-toolchain-mingw64-i686.cmake

@@ -0,0 +1,18 @@
+set(CMAKE_SYSTEM_NAME Windows)
+set(CMAKE_SYSTEM_PROCESSOR x86)
+
+find_program(CMAKE_C_COMPILER NAMES i686-w64-mingw32-gcc)
+find_program(CMAKE_CXX_COMPILER NAMES i686-w64-mingw32-g++)
+find_program(CMAKE_RC_COMPILER NAMES i686-w64-mingw32-windres windres)
+
+if(NOT CMAKE_C_COMPILER)
+	message(FATAL_ERROR "Failed to find CMAKE_C_COMPILER.")
+endif()
+
+if(NOT CMAKE_CXX_COMPILER)
+	message(FATAL_ERROR "Failed to find CMAKE_CXX_COMPILER.")
+endif()
+
+if(NOT CMAKE_RC_COMPILER)
+        message(FATAL_ERROR "Failed to find CMAKE_RC_COMPILER.")
+endif()

+ 18 - 0
Engine/lib/sdl/build-scripts/cmake-toolchain-mingw64-x86_64.cmake

@@ -0,0 +1,18 @@
+set(CMAKE_SYSTEM_NAME Windows)
+set(CMAKE_SYSTEM_PROCESSOR x86_64)
+
+find_program(CMAKE_C_COMPILER NAMES x86_64-w64-mingw32-gcc)
+find_program(CMAKE_CXX_COMPILER NAMES x86_64-w64-mingw32-g++)
+find_program(CMAKE_RC_COMPILER NAMES x86_64-w64-mingw32-windres windres)
+
+if(NOT CMAKE_C_COMPILER)
+	message(FATAL_ERROR "Failed to find CMAKE_C_COMPILER.")
+endif()
+
+if(NOT CMAKE_CXX_COMPILER)
+	message(FATAL_ERROR "Failed to find CMAKE_CXX_COMPILER.")
+endif()
+
+if(NOT CMAKE_RC_COMPILER)
+        message(FATAL_ERROR "Failed to find CMAKE_RC_COMPILER.")
+endif()

+ 14 - 6
Engine/lib/sdl/build-scripts/config.guess

@@ -1,10 +1,10 @@
 #! /bin/sh
 # Attempt to guess a canonical system name.
-#   Copyright 1992-2023 Free Software Foundation, Inc.
+#   Copyright 1992-2024 Free Software Foundation, Inc.
 
 # shellcheck disable=SC2006,SC2268 # see below for rationale
 
-timestamp='2023-08-22'
+timestamp='2024-07-27'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -60,7 +60,7 @@ version="\
 GNU config.guess ($timestamp)
 
 Originally written by Per Bothner.
-Copyright 1992-2023 Free Software Foundation, Inc.
+Copyright 1992-2024 Free Software Foundation, Inc.
 
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -123,7 +123,7 @@ set_cc_for_build() {
     dummy=$tmp/dummy
     case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
 	,,)    echo "int x;" > "$dummy.c"
-	       for driver in cc gcc c89 c99 ; do
+	       for driver in cc gcc c17 c99 c89 ; do
 		   if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
 		       CC_FOR_BUILD=$driver
 		       break
@@ -165,6 +165,8 @@ Linux|GNU|GNU/*)
 	LIBC=dietlibc
 	#elif defined(__GLIBC__)
 	LIBC=gnu
+	#elif defined(__LLVM_LIBC__)
+	LIBC=llvm
 	#else
 	#include <stdarg.h>
 	/* First heuristic to detect musl libc.  */
@@ -632,7 +634,8 @@ EOF
 		sed 's/^		//' << EOF > "$dummy.c"
 		#include <sys/systemcfg.h>
 
-		main()
+		int
+		main ()
 			{
 			if (!__power_pc())
 				exit(1);
@@ -716,7 +719,8 @@ EOF
 		#include <stdlib.h>
 		#include <unistd.h>
 
-		int main ()
+		int
+		main ()
 		{
 		#if defined(_SC_KERNEL_BITS)
 		    long bits = sysconf(_SC_KERNEL_BITS);
@@ -1593,6 +1597,9 @@ EOF
     *:Unleashed:*:*)
 	GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
 	;;
+    *:Ironclad:*:*)
+	GUESS=$UNAME_MACHINE-unknown-ironclad
+	;;
 esac
 
 # Do we have a guess based on uname results?
@@ -1616,6 +1623,7 @@ cat > "$dummy.c" <<EOF
 #endif
 #endif
 #endif
+int
 main ()
 {
 #if defined (sony)

Diff do ficheiro suprimidas por serem muito extensas
+ 563 - 173
Engine/lib/sdl/build-scripts/config.sub


+ 43 - 0
Engine/lib/sdl/build-scripts/create-release.py

@@ -0,0 +1,43 @@
+#!/usr/bin/env python3
+
+import argparse
+from pathlib import Path
+import json
+import logging
+import re
+import subprocess
+
+ROOT = Path(__file__).resolve().parents[1]
+
+
+def determine_remote() -> str:
+    text = (ROOT / "build-scripts/release-info.json").read_text()
+    release_info = json.loads(text)
+    if "remote" in release_info:
+        return release_info["remote"]
+    project_with_version = release_info["name"]
+    project, _ = re.subn("([^a-zA-Z_])", "", project_with_version)
+    return f"libsdl-org/{project}"
+
+
+def main():
+    default_remote = determine_remote()
+
+    current_commit = subprocess.check_output(["git", "rev-parse", "HEAD"], cwd=ROOT, text=True).strip()
+
+    parser = argparse.ArgumentParser(allow_abbrev=False)
+    parser.add_argument("--ref", required=True, help=f"Name of branch or tag containing release.yml")
+    parser.add_argument("--remote", "-R", default=default_remote, help=f"Remote repo (default={default_remote})")
+    parser.add_argument("--commit", default=current_commit, help=f"Commit (default={current_commit})")
+    args = parser.parse_args()
+
+
+    print(f"Running release.yml workflow:")
+    print(f"  commit = {args.commit}")
+    print(f"  remote = {args.remote}")
+
+    subprocess.check_call(["gh", "-R", args.remote, "workflow", "run", "release.yml", "--ref", args.ref, "-f", f"commit={args.commit}"], cwd=ROOT)
+
+
+if __name__ == "__main__":
+    raise SystemExit(main())

+ 2 - 2
Engine/lib/sdl/build-scripts/gen_audio_channel_conversion.c

@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2023 Sam Lantinga <[email protected]>
+  Copyright (C) 1997-2025 Sam Lantinga <[email protected]>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -395,7 +395,7 @@ int main(void)
     printf(
         "/*\n"
         "  Simple DirectMedia Layer\n"
-        "  Copyright (C) 1997-2023 Sam Lantinga <[email protected]>\n"
+        "  Copyright (C) 1997-2025 Sam Lantinga <[email protected]>\n"
         "\n"
         "  This software is provided 'as-is', without any express or implied\n"
         "  warranty.  In no event will the authors be held liable for any damages\n"

+ 2 - 2
Engine/lib/sdl/build-scripts/gen_audio_resampler_filter.c

@@ -1,6 +1,6 @@
 /*
   Simple DirectMedia Layer
-  Copyright (C) 1997-2023 Sam Lantinga <[email protected]>
+  Copyright (C) 1997-2025 Sam Lantinga <[email protected]>
 
   This software is provided 'as-is', without any express or implied
   warranty.  In no event will the authors be held liable for any damages
@@ -113,7 +113,7 @@ int main(void)
     printf(
         "/*\n"
         "  Simple DirectMedia Layer\n"
-        "  Copyright (C) 1997-2023 Sam Lantinga <[email protected]>\n"
+        "  Copyright (C) 1997-2025 Sam Lantinga <[email protected]>\n"
         "\n"
         "  This software is provided 'as-is', without any express or implied\n"
         "  warranty.  In no event will the authors be held liable for any damages\n"

+ 70 - 52
Engine/lib/sdl/build-scripts/ltmain.sh

@@ -2415,10 +2415,10 @@ libtool_validate_options ()
     # preserve --debug
     test : = "$debug_cmd" || func_append preserve_args " --debug"
 
-    case $host in
+    case $host_os in
       # Solaris2 added to fix http://debbugs.gnu.org/cgi/bugreport.cgi?bug=16452
       # see also: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=59788
-      *cygwin* | *mingw* | *pw32* | *cegcc* | *solaris2* | *os2*)
+      cygwin* | mingw* | windows* | pw32* | cegcc* | solaris2* | os2*)
         # don't eliminate duplications in $postdeps and $predeps
         opt_duplicate_compiler_generated_deps=:
         ;;
@@ -2750,7 +2750,7 @@ EOF
 
 # func_convert_core_file_wine_to_w32 ARG
 # Helper function used by file name conversion functions when $build is *nix,
-# and $host is mingw, cygwin, or some other w32 environment. Relies on a
+# and $host is mingw, windows, cygwin, or some other w32 environment. Relies on a
 # correctly configured wine environment available, with the winepath program
 # in $build's $PATH.
 #
@@ -2782,9 +2782,10 @@ func_convert_core_file_wine_to_w32 ()
 
 # func_convert_core_path_wine_to_w32 ARG
 # Helper function used by path conversion functions when $build is *nix, and
-# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
-# configured wine environment available, with the winepath program in $build's
-# $PATH. Assumes ARG has no leading or trailing path separator characters.
+# $host is mingw, windows, cygwin, or some other w32 environment. Relies on a
+# correctly configured wine environment available, with the winepath program
+# in $build's $PATH. Assumes ARG has no leading or trailing path separator
+# characters.
 #
 # ARG is path to be converted from $build format to win32.
 # Result is available in $func_convert_core_path_wine_to_w32_result.
@@ -3439,7 +3440,7 @@ func_mode_compile ()
 
     # On Cygwin there's no "real" PIC flag so we must build both object types
     case $host_os in
-    cygwin* | mingw* | pw32* | os2* | cegcc*)
+    cygwin* | mingw* | windows* | pw32* | os2* | cegcc*)
       pic_mode=default
       ;;
     esac
@@ -4316,7 +4317,7 @@ func_mode_install ()
 	      'exit $?'
 	  tstripme=$stripme
 	  case $host_os in
-	  cygwin* | mingw* | pw32* | cegcc*)
+	  cygwin* | mingw* | windows* | pw32* | cegcc*)
 	    case $realname in
 	    *.dll.a)
 	      tstripme=
@@ -4429,7 +4430,7 @@ func_mode_install ()
 
 	# Do a test to see if this is really a libtool program.
 	case $host in
-	*cygwin* | *mingw*)
+	*cygwin* | *mingw* | *windows*)
 	    if func_ltwrapper_executable_p "$file"; then
 	      func_ltwrapper_scriptname "$file"
 	      wrapper=$func_ltwrapper_scriptname_result
@@ -4657,7 +4658,7 @@ extern \"C\" {
 	      $RM $export_symbols
 	      eval "$SED -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
 	      case $host in
-	      *cygwin* | *mingw* | *cegcc* )
+	      *cygwin* | *mingw* | *windows* | *cegcc* )
                 eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
                 eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
 	        ;;
@@ -4669,7 +4670,7 @@ extern \"C\" {
 	      eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
 	      eval '$MV "$nlist"T "$nlist"'
 	      case $host in
-	        *cygwin* | *mingw* | *cegcc* )
+	        *cygwin* | *mingw* | *windows* | *cegcc* )
 	          eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
 	          eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
 	          ;;
@@ -4683,7 +4684,7 @@ extern \"C\" {
 	  func_basename "$dlprefile"
 	  name=$func_basename_result
           case $host in
-	    *cygwin* | *mingw* | *cegcc* )
+	    *cygwin* | *mingw* | *windows* | *cegcc* )
 	      # if an import library, we need to obtain dlname
 	      if func_win32_import_lib_p "$dlprefile"; then
 	        func_tr_sh "$dlprefile"
@@ -4858,7 +4859,7 @@ static const void *lt_preloaded_setup() {
 	# Transform the symbol file into the correct name.
 	symfileobj=$output_objdir/${my_outputname}S.$objext
 	case $host in
-	*cygwin* | *mingw* | *cegcc* )
+	*cygwin* | *mingw* | *windows* | *cegcc* )
 	  if test -f "$output_objdir/$my_outputname.def"; then
 	    compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
 	    finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
@@ -4934,7 +4935,7 @@ func_win32_libid ()
   *ar\ archive*) # could be an import, or static
     # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
     if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
-       $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+       $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64|pe-aarch64)' >/dev/null; then
       case $nm_interface in
       "MS dumpbin")
 	if func_cygming_ms_implib_p "$1" ||
@@ -5201,7 +5202,7 @@ func_extract_archives ()
 #
 # Emit a libtool wrapper script on stdout.
 # Don't directly open a file because we may want to
-# incorporate the script contents within a cygwin/mingw
+# incorporate the script contents within a cygwin/mingw/windows
 # wrapper executable.  Must ONLY be called from within
 # func_mode_link because it depends on a number of variables
 # set therein.
@@ -5209,7 +5210,7 @@ func_extract_archives ()
 # ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
 # variable will take.  If 'yes', then the emitted script
 # will assume that the directory where it is stored is
-# the $objdir directory.  This is a cygwin/mingw-specific
+# the $objdir directory.  This is a cygwin/mingw/windows-specific
 # behavior.
 func_emit_wrapper ()
 {
@@ -5333,7 +5334,7 @@ func_exec_program_core ()
 "
   case $host in
   # Backslashes separate directories on plain windows
-  *-*-mingw | *-*-os2* | *-cegcc*)
+  *-*-mingw* | *-*-windows* | *-*-os2* | *-cegcc*)
     $ECHO "\
       if test -n \"\$lt_option_debug\"; then
         \$ECHO \"$outputname:$output:\$LINENO: newargv[0]: \$progdir\\\\\$program\" 1>&2
@@ -5401,7 +5402,7 @@ func_exec_program ()
     file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
   done
 
-  # Usually 'no', except on cygwin/mingw when embedded into
+  # Usually 'no', except on cygwin/mingw/windows when embedded into
   # the cwrapper.
   WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
   if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
@@ -5533,7 +5534,7 @@ EOF
 #endif
 #include <stdio.h>
 #include <stdlib.h>
-#ifdef _MSC_VER
+#if defined _WIN32 && !defined __GNUC__
 # include <direct.h>
 # include <process.h>
 # include <io.h>
@@ -5558,7 +5559,7 @@ EOF
 /* declarations of non-ANSI functions */
 #if defined __MINGW32__
 # ifdef __STRICT_ANSI__
-int _putenv (const char *);
+_CRTIMP int __cdecl _putenv (const char *);
 # endif
 #elif defined __CYGWIN__
 # ifdef __STRICT_ANSI__
@@ -5756,7 +5757,7 @@ main (int argc, char *argv[])
 	{
 EOF
 	    case $host in
-	      *mingw* | *cygwin* )
+	      *mingw* | *windows* | *cygwin* )
 		# make stdout use "unix" line endings
 		echo "          setmode(1,_O_BINARY);"
 		;;
@@ -5859,7 +5860,7 @@ EOF
 EOF
 
 	    case $host_os in
-	      mingw*)
+	      mingw* | windows*)
 	    cat <<"EOF"
   {
     char* p;
@@ -5901,7 +5902,7 @@ EOF
 EOF
 
 	    case $host_os in
-	      mingw*)
+	      mingw* | windows*)
 		cat <<"EOF"
   /* execv doesn't actually work on mingw as expected on unix */
   newargz = prepare_spawn (newargz);
@@ -6320,7 +6321,7 @@ lt_update_lib_path (const char *name, const char *value)
 
 EOF
 	    case $host_os in
-	      mingw*)
+	      mingw* | windows*)
 		cat <<"EOF"
 
 /* Prepares an argument vector before calling spawn().
@@ -6495,12 +6496,12 @@ func_mode_link ()
     $debug_cmd
 
     case $host in
-    *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+    *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-cegcc*)
       # It is impossible to link a dll without this setting, and
       # we shouldn't force the makefile maintainer to figure out
       # what system we are compiling for in order to pass an extra
       # flag for every libtool invocation.
-      # SDL customization: SDL code doesn't have any undefined symbols
+      # SDL customization: SDL code doesn't have any undefined symbols.
       allow_undefined=no
 
       # FIXME: Unfortunately, there are problems with the above when trying
@@ -6508,7 +6509,7 @@ func_mode_link ()
       # even a static library is built.  For now, we need to specify
       # -no-undefined on the libtool link line when we can be certain
       # that all symbols are satisfied, otherwise we get a static library.
-      # SDL customization: SDL code doesn't have any undefined symbols
+      # SDL customization: SDL code doesn't have any undefined symbols.
       # allow_undefined=yes
       ;;
     *)
@@ -7003,7 +7004,7 @@ func_mode_link ()
 	  ;;
 	esac
 	case $host in
-	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	*-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-cegcc*)
 	  testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
 	  case :$dllsearchpath: in
 	  *":$dir:"*) ;;
@@ -7023,7 +7024,7 @@ func_mode_link ()
       -l*)
 	if test X-lc = "X$arg" || test X-lm = "X$arg"; then
 	  case $host in
-	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	  *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
 	    # These systems don't actually have a C or math library (as such)
 	    continue
 	    ;;
@@ -7095,7 +7096,7 @@ func_mode_link ()
 	continue
 	;;
       -mt|-mthreads|-kthread|-Kthread|-pthreads|--thread-safe \
-      |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+      |-threads|-fopenmp|-fopenmp=*|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
 	func_append compiler_flags " $arg"
 	func_append compile_command " $arg"
 	func_append finalize_command " $arg"
@@ -7118,7 +7119,7 @@ func_mode_link ()
 
       -no-install)
 	case $host in
-	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+	*-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
 	  # The PATH hackery in wrapper scripts is required on Windows
 	  # and Darwin in order for the loader to find any dlls it needs.
 	  func_warning "'-no-install' is ignored for $host"
@@ -7303,13 +7304,29 @@ func_mode_link ()
       # -O*, -g*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
       # -specs=*             GCC specs files
       # -stdlib=*            select c++ std lib with clang
+      # -fdiagnostics-color* simply affects output
+      # -frecord-gcc-switches used to verify flags were respected
       # -fsanitize=*         Clang/GCC memory and address sanitizer
+      # -fno-sanitize*       Clang/GCC memory and address sanitizer
+      # -shared-libsan       Link with shared sanitizer runtimes (Clang)
+      # -static-libsan       Link with static sanitizer runtimes (Clang)
+      # -no-canonical-prefixes Do not expand any symbolic links
       # -fuse-ld=*           Linker select flags for GCC
+      # -static-*            direct GCC to link specific libraries statically
+      # -fcilkplus           Cilk Plus language extension features for C/C++
+      # -rtlib=*             select c runtime lib with clang
+      # --unwindlib=*        select unwinder library with clang
+      # -f{file|debug|macro|profile}-prefix-map=* needed for lto linking
       # -Wa,*                Pass flags directly to the assembler
+      # -Werror, -Werror=*   Report (specified) warnings as errors
       -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
       -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
-      -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \
-      -specs=*|-fsanitize=*|-fuse-ld=*|-Wa,*)
+      -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-no-canonical-prefixes| \
+      -stdlib=*|-rtlib=*|--unwindlib=*| \
+      -specs=*|-fsanitize=*|-fno-sanitize*|-shared-libsan|-static-libsan| \
+      -ffile-prefix-map=*|-fdebug-prefix-map=*|-fmacro-prefix-map=*|-fprofile-prefix-map=*| \
+      -fdiagnostics-color*|-frecord-gcc-switches| \
+      -fuse-ld=*|-static-*|-fcilkplus|-Wa,*|-Werror|-Werror=*)
         func_quote_for_eval "$arg"
 	arg=$func_quote_for_eval_result
         func_append compile_command " $arg"
@@ -7639,7 +7656,7 @@ func_mode_link ()
 	found=false
 	case $deplib in
 	-mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
-        |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+        |-threads|-fopenmp|-fopenmp=*|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
 	  if test prog,link = "$linkmode,$pass"; then
 	    compile_deplibs="$deplib $compile_deplibs"
 	    finalize_deplibs="$deplib $finalize_deplibs"
@@ -8022,7 +8039,7 @@ func_mode_link ()
 	  fi
 	  case $host in
 	    # special handling for platforms with PE-DLLs.
-	    *cygwin* | *mingw* | *cegcc* )
+	    *cygwin* | *mingw* | *windows* | *cegcc* )
 	      # Linker will automatically link against shared library if both
 	      # static and shared are present.  Therefore, ensure we extract
 	      # symbols from the import library if a shared library is present
@@ -8165,8 +8182,8 @@ func_mode_link ()
 	fi
 	if test -n "$library_names" &&
 	   { test no = "$use_static_libs" || test -z "$old_library"; }; then
-	  case $host in
-	  *cygwin* | *mingw* | *cegcc* | *os2*)
+	  case $host_os in
+	  cygwin* | mingw* | windows* | cegcc* | os2*)
 	      # No point in relinking DLLs because paths are not encoded
 	      func_append notinst_deplibs " $lib"
 	      need_relink=no
@@ -8235,8 +8252,8 @@ func_mode_link ()
 	      soname=$dlname
 	    elif test -n "$soname_spec"; then
 	      # bleh windows
-	      case $host in
-	      *cygwin* | mingw* | *cegcc*)  # | *os2* # SDL customization: removed OS/2 versioning support.
+	      case $host_os in
+	      cygwin* | mingw* | windows* | cegcc*) # | os2* # SDL customization: removed OS/2 versioning support.
 	        func_arith $current - $age
 		major=$func_arith_result
 		versuffix=-$major
@@ -8378,7 +8395,7 @@ func_mode_link ()
 	       test no = "$hardcode_direct_absolute"; then
 	      add=$libdir/$linklib
 	    elif test yes = "$hardcode_minus_L"; then
-	      add_dir=-L$libdir
+	      add_dir=-L$lt_sysroot$libdir
 	      add=-l$name
 	    elif test yes = "$hardcode_shlibpath_var"; then
 	      case :$finalize_shlibpath: in
@@ -8395,7 +8412,7 @@ func_mode_link ()
 	      fi
 	    else
 	      # We cannot seem to hardcode it, guess we'll fake it.
-	      add_dir=-L$libdir
+	      add_dir=-L$lt_sysroot$libdir
 	      # Try looking first in the location we're being installed to.
 	      if test -n "$inst_prefix_dir"; then
 		case $libdir in
@@ -8666,7 +8683,7 @@ func_mode_link ()
       test CXX = "$tagname" && {
         case $host_os in
         linux*)
-          case `$CC -V 2>&1 | sed 5q` in
+          case `$CC -V 2>&1 | $SED 5q` in
           *Sun\ C*) # Sun C++ 5.9
             func_suncc_cstd_abi
 
@@ -8839,13 +8856,13 @@ func_mode_link ()
 	  #
 	  case $version_type in
 	  # correct linux to gnu/linux during the next big refactor
-	  darwin|freebsd-elf|linux|midnightbsd-elf|osf|windows|none)
+	  darwin|freebsd-elf|linux|midnightbsd-elf|osf|qnx|windows|none)
 	    func_arith $number_major + $number_minor
 	    current=$func_arith_result
 	    age=$number_minor
 	    revision=$number_revision
 	    ;;
-	  freebsd-aout|qnx|sunos)
+	  freebsd-aout|sco|sunos)
 	    current=$number_major
 	    revision=$number_minor
 	    age=0
@@ -8992,8 +9009,9 @@ func_mode_link ()
 	  ;;
 
 	qnx)
-	  major=.$current
-	  versuffix=.$current
+	  func_arith $current - $age
+	  major=.$func_arith_result
+	  versuffix=$major.$age.$revision
 	  ;;
 
 	sco)
@@ -9146,7 +9164,7 @@ func_mode_link ()
       if test yes = "$build_libtool_libs"; then
 	if test -n "$rpath"; then
 	  case $host in
-	  *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+	  *-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
 	    # these systems don't actually have a c library (as such)!
 	    ;;
 	  *-*-rhapsody* | *-*-darwin1.[012])
@@ -9660,7 +9678,7 @@ EOF
 
 	orig_export_symbols=
 	case $host_os in
-	cygwin* | mingw* | cegcc*)
+	cygwin* | mingw* | windows* | cegcc*)
 	  if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
 	    # exporting using user supplied symfile
 	    func_dll_def_p "$export_symbols" || {
@@ -10330,7 +10348,7 @@ EOF
 	  esac
 	fi
 	case $host in
-	*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+	*-*-cygwin* | *-*-mingw* | *-*-windows* | *-*-pw32* | *-*-os2* | *-cegcc*)
 	  testbindir=`$ECHO "$libdir" | $SED -e 's*/lib$*/bin*'`
 	  case :$dllsearchpath: in
 	  *":$libdir:"*) ;;
@@ -10408,7 +10426,7 @@ EOF
         # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
         wrappers_required=false
         ;;
-      *cygwin* | *mingw* )
+      *cygwin* | *mingw* | *windows* )
         test yes = "$build_libtool_libs" || wrappers_required=false
         ;;
       *)
@@ -10561,7 +10579,7 @@ EOF
 	  *) exeext= ;;
 	esac
 	case $host in
-	  *cygwin* | *mingw* )
+	  *cygwin* | *mingw* | windows* )
 	    func_dirname_and_basename "$output" "" "."
 	    output_name=$func_basename_result
 	    output_path=$func_dirname_result
@@ -10893,7 +10911,7 @@ EOF
 	  # tests/bindir.at for full details.
 	  tdlname=$dlname
 	  case $host,$output,$installed,$module,$dlname in
-	    *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+	    *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *windows*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
 	      # If a -bindir argument was supplied, place the dll there.
 	      if test -n "$bindir"; then
 		func_relative_path "$install_libdir" "$bindir"

+ 108 - 0
Engine/lib/sdl/build-scripts/release-info.json

@@ -0,0 +1,108 @@
+{
+  "name": "SDL2",
+  "remote": "libsdl-org/SDL",
+  "version": {
+    "file": "include/SDL_version.h",
+    "re_major": "^#define SDL_MAJOR_VERSION\\s+([0-9]+)$",
+    "re_minor": "^#define SDL_MINOR_VERSION\\s+([0-9]+)$",
+    "re_micro": "^#define SDL_PATCHLEVEL\\s+([0-9]+)$"
+  },
+  "source": {
+    "checks": [
+      "src/SDL.c",
+      "include/SDL.h",
+      "test/testsprite2.c",
+      "android-project/app/src/main/java/org/libsdl/app/SDLActivity.java"
+    ]
+  },
+  "dmg": {
+    "project": "Xcode/SDL/SDL.xcodeproj",
+    "path": "Xcode/SDL/build/SDL2.dmg",
+    "target": "Standard DMG"
+  },
+  "mingw": {
+    "autotools": {
+      "archs": ["x86", "x64"],
+      "args": [
+      ],
+      "files": {
+        "@<@TRIPLET@>@/include/SDL2": [
+          "include/SDL_config*.h"
+        ]
+      }
+    },
+    "files": {
+      "": [
+        "mingw/pkg-support/INSTALL.txt",
+        "mingw/pkg-support/Makefile",
+        "BUGS.txt",
+        "CREDITS.txt",
+        "README-SDL.txt",
+        "WhatsNew.txt",
+        "LICENSE.txt",
+        "README.md"
+      ],
+      "cmake": [
+        "mingw/pkg-support/cmake/sdl2-config.cmake",
+        "mingw/pkg-support/cmake/sdl2-config-version.cmake"
+      ],
+      "docs": [
+        "docs/*"
+      ],
+      "test": [
+        "test/*"
+      ]
+    }
+  },
+  "msvc": {
+    "msbuild": {
+      "archs": [
+        "x86",
+        "x64"
+      ],
+      "projects": [
+        "VisualC/SDL/SDL.vcxproj",
+        "VisualC/SDLmain/SDLmain.vcxproj",
+        "VisualC/SDLtest/SDLtest.vcxproj"
+      ],
+      "files-lib": {
+        "": [
+          "VisualC/SDL/@<@PLATFORM@>@/@<@CONFIGURATION@>@/SDL2.dll"
+        ]
+      },
+      "files-devel": {
+        "lib/@<@ARCH@>@": [
+          "VisualC/SDL/@<@PLATFORM@>@/@<@CONFIGURATION@>@/SDL2.dll",
+          "VisualC/SDL/@<@PLATFORM@>@/@<@CONFIGURATION@>@/SDL2.lib",
+          "VisualC/SDL/@<@PLATFORM@>@/@<@CONFIGURATION@>@/SDL2.pdb",
+          "VisualC/SDLmain/@<@PLATFORM@>@/@<@CONFIGURATION@>@/SDL2main.lib",
+          "VisualC/SDLtest/@<@PLATFORM@>@/@<@CONFIGURATION@>@/SDL2test.lib"
+        ]
+      }
+    },
+    "files-lib": {
+      "": [
+        "README-SDL.txt"
+      ]
+    },
+    "files-devel": {
+      "": [
+        "README-SDL.txt",
+        "BUGS.txt",
+        "LICENSE.txt",
+        "README.md",
+        "WhatsNew.txt"
+      ],
+      "cmake": [
+        "VisualC/pkg-support/cmake/sdl2-config.cmake",
+        "VisualC/pkg-support/cmake/sdl2-config-version.cmake"
+      ],
+      "docs": [
+        "docs/*"
+      ],
+      "include": [
+        "include/*.h"
+      ]
+    }
+  }
+}

+ 303 - 0
Engine/lib/sdl/build-scripts/setup-gdk-desktop.py

@@ -0,0 +1,303 @@
+#!/usr/bin/env python
+
+import argparse
+import functools
+import logging
+import os
+from pathlib import Path
+import re
+import shutil
+import subprocess
+import tempfile
+import textwrap
+import urllib.request
+import zipfile
+
+# Update both variables when updating the GDK
+GIT_REF = "June_2024_Update_1"
+GDK_EDITION = "240601"  # YYMMUU
+
+logger = logging.getLogger(__name__)
+
+class GdDesktopConfigurator:
+    def __init__(self, gdk_path, arch, vs_folder, vs_version=None, vs_toolset=None, temp_folder=None, git_ref=None, gdk_edition=None):
+        self.git_ref = git_ref or GIT_REF
+        self.gdk_edition = gdk_edition or GDK_EDITION
+        self.gdk_path = gdk_path
+        self.temp_folder = temp_folder or Path(tempfile.gettempdir())
+        self.dl_archive_path = Path(self.temp_folder) / f"{ self.git_ref }.zip"
+        self.gdk_extract_path = Path(self.temp_folder) / f"GDK-{ self.git_ref }"
+        self.arch = arch
+        self.vs_folder = vs_folder
+        self._vs_version = vs_version
+        self._vs_toolset = vs_toolset
+
+    def download_archive(self) -> None:
+        gdk_url = f"https://github.com/microsoft/GDK/archive/refs/tags/{ GIT_REF }.zip"
+        logger.info("Downloading %s to %s", gdk_url, self.dl_archive_path)
+        urllib.request.urlretrieve(gdk_url, self.dl_archive_path)
+        assert self.dl_archive_path.is_file()
+
+    def extract_zip_archive(self) -> None:
+        extract_path = self.gdk_extract_path.parent
+        assert self.dl_archive_path.is_file()
+        logger.info("Extracting %s to %s", self.dl_archive_path, extract_path)
+        with zipfile.ZipFile(self.dl_archive_path) as zf:
+            zf.extractall(extract_path)
+        assert self.gdk_extract_path.is_dir(), f"{self.gdk_extract_path} must exist"
+
+    def extract_development_kit(self) -> None:
+        extract_dks_cmd = self.gdk_extract_path / "SetupScripts/ExtractXboxOneDKs.cmd"
+        assert extract_dks_cmd.is_file()
+        logger.info("Extracting GDK Development Kit: running %s", extract_dks_cmd)
+        cmd = ["cmd.exe", "/C", str(extract_dks_cmd), str(self.gdk_extract_path), str(self.gdk_path)]
+        logger.debug("Running %r", cmd)
+        subprocess.check_call(cmd)
+
+    def detect_vs_version(self) -> str:
+        vs_regex = re.compile("VS([0-9]{4})")
+        supported_vs_versions = []
+        for p in self.gaming_grdk_build_path.iterdir():
+            if not p.is_dir():
+                continue
+            if m := vs_regex.match(p.name):
+                supported_vs_versions.append(m.group(1))
+        logger.info(f"Supported Visual Studio versions: {supported_vs_versions}")
+        vs_versions = set(self.vs_folder.parts).intersection(set(supported_vs_versions))
+        if not vs_versions:
+            raise RuntimeError("Visual Studio version is incompatible")
+        if len(vs_versions) > 1:
+            raise RuntimeError(f"Too many compatible VS versions found ({vs_versions})")
+        vs_version = vs_versions.pop()
+        logger.info(f"Used Visual Studio version: {vs_version}")
+        return vs_version
+
+    def detect_vs_toolset(self) -> str:
+        toolset_paths = []
+        for ts_path in self.gdk_toolset_parent_path.iterdir():
+            if not ts_path.is_dir():
+                continue
+            ms_props = ts_path / "Microsoft.Cpp.props"
+            if not ms_props.is_file():
+                continue
+            toolset_paths.append(ts_path.name)
+        logger.info("Detected Visual Studio toolsets: %s", toolset_paths)
+        assert toolset_paths, "Have we detected at least one toolset?"
+
+        def toolset_number(toolset: str) -> int:
+            if m:= re.match("[^0-9]*([0-9]+).*", toolset):
+                return int(m.group(1))
+            return -9
+
+        return max(toolset_paths, key=toolset_number)
+
+    @property
+    def vs_version(self) -> str:
+        if self._vs_version is None:
+            self._vs_version = self.detect_vs_version()
+        return self._vs_version
+
+    @property
+    def vs_toolset(self) -> str:
+        if self._vs_toolset is None:
+            self._vs_toolset = self.detect_vs_toolset()
+        return self._vs_toolset
+
+    @staticmethod
+    def copy_files_and_merge_into(srcdir: Path, dstdir: Path) -> None:
+        logger.info(f"Copy {srcdir} to {dstdir}")
+        for root, _, files in os.walk(srcdir):
+            dest_root = dstdir / Path(root).relative_to(srcdir)
+            if not dest_root.is_dir():
+                dest_root.mkdir()
+            for file in files:
+                srcfile = Path(root) / file
+                dstfile = dest_root / file
+                shutil.copy(srcfile, dstfile)
+
+    def copy_msbuild(self) -> None:
+        vc_toolset_parent_path = self.vs_folder / "MSBuild/Microsoft/VC"
+        if 1:
+            logger.info(f"Detected compatible Visual Studio version: {self.vs_version}")
+            srcdir = vc_toolset_parent_path
+            dstdir = self.gdk_toolset_parent_path
+            assert srcdir.is_dir(), "Source directory must exist"
+            assert dstdir.is_dir(), "Destination directory must exist"
+
+            self.copy_files_and_merge_into(srcdir=srcdir, dstdir=dstdir)
+
+    @property
+    def game_dk_path(self) -> Path:
+        return self.gdk_path / "Microsoft GDK"
+
+    @property
+    def game_dk_latest_path(self) -> Path:
+        return self.game_dk_path / self.gdk_edition
+
+    @property
+    def windows_sdk_path(self) -> Path:
+        return self.gdk_path / "Windows Kits/10"
+
+    @property
+    def gaming_grdk_build_path(self) -> Path:
+        return self.game_dk_latest_path / "GRDK"
+
+    @property
+    def gdk_toolset_parent_path(self) -> Path:
+        return self.gaming_grdk_build_path / f"VS{self.vs_version}/flatDeployment/MSBuild/Microsoft/VC"
+
+    @property
+    def env(self) -> dict[str, str]:
+        game_dk = self.game_dk_path
+        game_dk_latest = self.game_dk_latest_path
+        windows_sdk_dir = self.windows_sdk_path
+        gaming_grdk_build = self.gaming_grdk_build_path
+
+        return {
+            "GRDKEDITION": f"{self.gdk_edition}",
+            "GameDK": f"{game_dk}\\",
+            "GameDKLatest": f"{ game_dk_latest }\\",
+            "WindowsSdkDir": f"{ windows_sdk_dir }\\",
+            "GamingGRDKBuild": f"{ gaming_grdk_build }\\",
+            "VSInstallDir": f"{ self.vs_folder }\\",
+        }
+
+    def create_user_props(self, path: Path) -> None:
+        vc_targets_path = self.gaming_grdk_build_path / f"VS{ self.vs_version }/flatDeployment/MSBuild/Microsoft/VC/{ self.vs_toolset }"
+        vc_targets_path16 = self.gaming_grdk_build_path / f"VS2019/flatDeployment/MSBuild/Microsoft/VC/{ self.vs_toolset }"
+        vc_targets_path17 = self.gaming_grdk_build_path / f"VS2022/flatDeployment/MSBuild/Microsoft/VC/{ self.vs_toolset }"
+        additional_include_directories = ";".join(str(p) for p in self.gdk_include_paths)
+        additional_library_directories = ";".join(str(p) for p in self.gdk_library_paths)
+        durango_xdk_install_path = self.gdk_path / "Microsoft GDK"
+        with path.open("w") as f:
+            f.write(textwrap.dedent(f"""\
+                <?xml version="1.0" encoding="utf-8"?>
+                <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+                  <PropertyGroup>
+                    <VCTargetsPath>{ vc_targets_path }\\</VCTargetsPath>
+                    <VCTargetsPath16>{ vc_targets_path16 }\\</VCTargetsPath16>
+                    <VCTargetsPath17>{ vc_targets_path17 }\\</VCTargetsPath17>
+                    <BWOI_GDK_Path>{ self.gaming_grdk_build_path }\\</BWOI_GDK_Path>
+                    <Platform Condition="'$(Platform)' == ''">Gaming.Desktop.x64</Platform>
+                    <Configuration Condition="'$(Configuration)' == ''">Debug</Configuration>
+                    <XdkEditionTarget>{ self.gdk_edition }</XdkEditionTarget>
+                    <DurangoXdkInstallPath>{ durango_xdk_install_path }</DurangoXdkInstallPath>
+
+                    <DefaultXdkEditionRootVS2019>$(DurangoXdkInstallPath)\\{self.gdk_edition}\\GRDK\\VS2019\\flatDeployment\\MSBuild\\Microsoft\\VC\\{self.vs_toolset}\\Platforms\\$(Platform)\\</DefaultXdkEditionRootVS2019>
+                    <XdkEditionRootVS2019>$(DurangoXdkInstallPath)\\{self.gdk_edition}\\GRDK\\VS2019\\flatDeployment\\MSBuild\\Microsoft\\VC\\{self.vs_toolset}\\Platforms\\$(Platform)\\</XdkEditionRootVS2019>
+                    <DefaultXdkEditionRootVS2022>$(DurangoXdkInstallPath)\\{self.gdk_edition}\\GRDK\\VS2022\\flatDeployment\\MSBuild\\Microsoft\\VC\\{self.vs_toolset}\\Platforms\\$(Platform)\\</DefaultXdkEditionRootVS2022>
+                    <XdkEditionRootVS2022>$(DurangoXdkInstallPath)\\{self.gdk_edition}\\GRDK\\VS2022\\flatDeployment\\MSBuild\\Microsoft\\VC\\{self.vs_toolset}\\Platforms\\$(Platform)\\</XdkEditionRootVS2022>
+
+                    <Deterministic>true</Deterministic>
+                    <DisableInstalledVCTargetsUse>true</DisableInstalledVCTargetsUse>
+                    <ClearDevCommandPromptEnvVars>true</ClearDevCommandPromptEnvVars>
+                  </PropertyGroup>
+                  <ItemDefinitionGroup Condition="'$(Platform)' == 'Gaming.Desktop.x64'">
+                    <ClCompile>
+                      <AdditionalIncludeDirectories>{ additional_include_directories };%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+                    </ClCompile>
+                    <Link>
+                      <AdditionalLibraryDirectories>{ additional_library_directories };%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
+                    </Link>
+                  </ItemDefinitionGroup>
+                </Project>
+            """))
+
+    @property
+    def gdk_include_paths(self) -> list[Path]:
+        return [
+            self.gaming_grdk_build_path / "gamekit/include",
+        ]
+
+    @property
+    def gdk_library_paths(self) -> list[Path]:
+        return [
+            self.gaming_grdk_build_path / f"gamekit/lib/{self.arch}",
+        ]
+
+    @property
+    def gdk_binary_path(self) -> list[Path]:
+        return [
+            self.gaming_grdk_build_path / "bin",
+            self.game_dk_path / "bin",
+        ]
+
+    @property
+    def build_env(self) -> dict[str, str]:
+        gdk_include = ";".join(str(p) for p in self.gdk_include_paths)
+        gdk_lib = ";".join(str(p) for p in self.gdk_library_paths)
+        gdk_path = ";".join(str(p) for p in self.gdk_binary_path)
+        return {
+            "GDK_INCLUDE": gdk_include,
+            "GDK_LIB": gdk_lib,
+            "GDK_PATH": gdk_path,
+        }
+
+    def print_env(self) -> None:
+        for k, v in self.env.items():
+            print(f"set \"{k}={v}\"")
+        print()
+        for k, v in self.build_env.items():
+            print(f"set \"{k}={v}\"")
+        print()
+        print(f"set \"PATH=%GDK_PATH%;%PATH%\"")
+        print(f"set \"LIB=%GDK_LIB%;%LIB%\"")
+        print(f"set \"INCLUDE=%GDK_INCLUDE%;%INCLUDE%\"")
+
+
+def main():
+    logging.basicConfig(level=logging.INFO)
+    parser = argparse.ArgumentParser(allow_abbrev=False)
+    parser.add_argument("--arch", choices=["amd64"], default="amd64", help="Architecture")
+    parser.add_argument("--download", action="store_true", help="Download GDK")
+    parser.add_argument("--extract", action="store_true", help="Extract downloaded GDK")
+    parser.add_argument("--copy-msbuild", action="store_true", help="Copy MSBuild files")
+    parser.add_argument("--temp-folder", help="Temporary folder where to download and extract GDK")
+    parser.add_argument("--gdk-path", required=True, type=Path, help="Folder where to store the GDK")
+    parser.add_argument("--ref-edition", type=str, help="Git ref and GDK edition separated by comma")
+    parser.add_argument("--vs-folder", required=True, type=Path, help="Installation folder of Visual Studio")
+    parser.add_argument("--vs-version", required=False, type=int, help="Visual Studio version")
+    parser.add_argument("--vs-toolset", required=False, help="Visual Studio toolset (e.g. v150)")
+    parser.add_argument("--props-folder", required=False, type=Path, default=Path(), help="Visual Studio toolset (e.g. v150)")
+    parser.add_argument("--no-user-props", required=False, dest="user_props", action="store_false", help="Don't ")
+    args = parser.parse_args()
+
+    logging.basicConfig(level=logging.INFO)
+
+    git_ref = None
+    gdk_edition = None
+    if args.ref_edition is not None:
+        git_ref, gdk_edition = args.ref_edition.split(",", 1)
+        try:
+            int(gdk_edition)
+        except ValueError:
+            parser.error("Edition should be an integer (YYMMUU) (Y=year M=month U=update)")
+
+    configurator = GdDesktopConfigurator(
+        arch=args.arch,
+        git_ref=git_ref,
+        gdk_edition=gdk_edition,
+        vs_folder=args.vs_folder,
+        vs_version=args.vs_version,
+        vs_toolset=args.vs_toolset,
+        gdk_path=args.gdk_path,
+        temp_folder=args.temp_folder,
+    )
+
+    if args.download:
+        configurator.download_archive()
+
+    if args.extract:
+        configurator.extract_zip_archive()
+
+        configurator.extract_development_kit()
+
+    if args.copy_msbuild:
+        configurator.copy_msbuild()
+
+    if args.user_props:
+        configurator.print_env()
+        configurator.create_user_props(args.props_folder / "Directory.Build.props")
+
+if __name__ == "__main__":
+    raise SystemExit(main())

+ 2 - 2
Engine/lib/sdl/build-scripts/showrev.sh

@@ -5,8 +5,8 @@
 SDL_ROOT=$(dirname $0)/..
 cd $SDL_ROOT
 
-if [ -e ./VERSION.txt ]; then
-    cat ./VERSION.txt
+if [ -e ./REVISION.txt ]; then
+    cat ./REVISION.txt
     exit 0
 fi
 

+ 10 - 2
Engine/lib/sdl/build-scripts/update-copyright.sh

@@ -1,7 +1,15 @@
 #!/bin/sh
 
-find . -type f -exec grep -Il "Copyright" {} \; \
+if [ "$SED" = "" ]; then
+    if type gsed >/dev/null; then
+        SED=gsed
+    else
+        SED=sed
+    fi
+fi
+
+find . -type f \
 | grep -v \.git                                 \
 | while read file; do                           \
-    LC_ALL=C sed -b -i "s/\(.*Copyright.*\)[0-9]\{4\}\( *Sam Lantinga\)/\1`date +%Y`\2/" "$file"; \
+    LC_ALL=C $SED -b -i "s/\(.*Copyright.*\)[0-9]\{4\}\( *Sam Lantinga\)/\1`date +%Y`\2/" "$file"; \
 done

+ 1 - 1
Engine/lib/sdl/build-scripts/updaterev.sh

@@ -29,7 +29,7 @@ done
 rev=`sh showrev.sh 2>/dev/null`
 if [ "$rev" != "" ]; then
     if [ -n "$dist" ]; then
-        echo "$rev" > "$outdir/VERSION.txt"
+        echo "$rev" > "$outdir/REVISION.txt"
     fi
     echo "/* Generated by updaterev.sh, do not edit */" >"$header.new"
     if [ -n "$vendor" ]; then

Alguns ficheiros não foram mostrados porque muitos ficheiros mudaram neste diff