Bladeren bron

Update to SDL 1.0.11-0b98870c7f72.

woollybah 5 jaren geleden
bovenliggende
commit
4701a2a9f2
100 gewijzigde bestanden met toevoegingen van 5725 en 1642 verwijderingen
  1. 6 1
      sdl.mod/SDL/Android.mk
  2. 334 54
      sdl.mod/SDL/CMakeLists.txt
  3. 1 0
      sdl.mod/SDL/Makefile.in
  4. 4 1
      sdl.mod/SDL/Makefile.os2
  5. 2 1
      sdl.mod/SDL/SDL2.spec.in
  6. 1 4
      sdl.mod/SDL/VisualC/SDL/SDL.vcxproj
  7. 1 2
      sdl.mod/SDL/VisualC/SDL/SDL.vcxproj.filters
  8. 0 2
      sdl.mod/SDL/VisualC/SDLmain/SDLmain.vcxproj
  9. 0 2
      sdl.mod/SDL/VisualC/SDLtest/SDLtest.vcxproj
  10. 28 0
      sdl.mod/SDL/WhatsNew.txt
  11. 134 48
      sdl.mod/SDL/Xcode-iOS/Demos/Demos.xcodeproj/project.pbxproj
  12. 8 12
      sdl.mod/SDL/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj
  13. 1 1
      sdl.mod/SDL/Xcode-iOS/Test/Info.plist
  14. 297 181
      sdl.mod/SDL/Xcode-iOS/Test/TestiPhoneOS.xcodeproj/project.pbxproj
  15. 2 2
      sdl.mod/SDL/Xcode/SDL/Info-Framework.plist
  16. 9 11
      sdl.mod/SDL/Xcode/SDL/SDL.xcodeproj/project.pbxproj
  17. 8 0
      sdl.mod/SDL/android-project/app/build.gradle
  18. 20 0
      sdl.mod/SDL/android-project/app/jni/CMakeLists.txt
  19. 13 0
      sdl.mod/SDL/android-project/app/jni/src/CMakeLists.txt
  20. 70 8
      sdl.mod/SDL/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java
  21. 1 1
      sdl.mod/SDL/build-scripts/winrtbuild.ps1
  22. 38 0
      sdl.mod/SDL/cmake/sdlchecks.cmake
  23. 271 55
      sdl.mod/SDL/configure
  24. 220 49
      sdl.mod/SDL/configure.ac
  25. 12 0
      sdl.mod/SDL/debian/changelog
  26. 19 0
      sdl.mod/SDL/docs/README-android.md
  27. 53 1
      sdl.mod/SDL/docs/README-cmake.md
  28. 5 2
      sdl.mod/SDL/docs/README-winrt.md
  29. 1 0
      sdl.mod/SDL/include/SDL.h
  30. 18 0
      sdl.mod/SDL/include/SDL_atomic.h
  31. 46 13
      sdl.mod/SDL/include/SDL_audio.h
  32. 14 1
      sdl.mod/SDL/include/SDL_config.h.cmake
  33. 12 5
      sdl.mod/SDL/include/SDL_config.h.in
  34. 4 0
      sdl.mod/SDL/include/SDL_config_iphoneos.h
  35. 28 11
      sdl.mod/SDL/include/SDL_config_macosx.h
  36. 2 3
      sdl.mod/SDL/include/SDL_config_windows.h
  37. 0 1
      sdl.mod/SDL/include/SDL_config_winrt.h
  38. 72 4
      sdl.mod/SDL/include/SDL_cpuinfo.h
  39. 3 0
      sdl.mod/SDL/include/SDL_egl.h
  40. 5 2
      sdl.mod/SDL/include/SDL_endian.h
  41. 5 1
      sdl.mod/SDL/include/SDL_events.h
  42. 93 11
      sdl.mod/SDL/include/SDL_hints.h
  43. 2 2
      sdl.mod/SDL/include/SDL_keycode.h
  44. 2 2
      sdl.mod/SDL/include/SDL_log.h
  45. 5 3
      sdl.mod/SDL/include/SDL_messagebox.h
  46. 91 0
      sdl.mod/SDL/include/SDL_metal.h
  47. 3 0
      sdl.mod/SDL/include/SDL_opengl_glext.h
  48. 10 10
      sdl.mod/SDL/include/SDL_pixels.h
  49. 21 0
      sdl.mod/SDL/include/SDL_render.h
  50. 49 12
      sdl.mod/SDL/include/SDL_rwops.h
  51. 4 1
      sdl.mod/SDL/include/SDL_stdinc.h
  52. 3 0
      sdl.mod/SDL/include/SDL_syswm.h
  53. 1 1
      sdl.mod/SDL/include/SDL_version.h
  54. 0 1
      sdl.mod/SDL/include/SDL_video.h
  55. 3 3
      sdl.mod/SDL/include/SDL_vulkan.h
  56. 3 0
      sdl.mod/SDL/include/begin_code.h
  57. 36 0
      sdl.mod/SDL/src/SDL.c
  58. 12 29
      sdl.mod/SDL/src/SDL_assert.c
  59. 0 10
      sdl.mod/SDL/src/SDL_error.c
  60. 2 2
      sdl.mod/SDL/src/SDL_log.c
  61. 4 0
      sdl.mod/SDL/src/atomic/SDL_atomic.c
  62. 12 14
      sdl.mod/SDL/src/audio/SDL_audio.c
  63. 16 6
      sdl.mod/SDL/src/audio/SDL_audiocvt.c
  64. 21 22
      sdl.mod/SDL/src/audio/SDL_audiotypecvt.c
  65. 0 1
      sdl.mod/SDL/src/audio/SDL_sysaudio.h
  66. 2024 565
      sdl.mod/SDL/src/audio/SDL_wave.c
  67. 103 31
      sdl.mod/SDL/src/audio/SDL_wave.h
  68. 21 13
      sdl.mod/SDL/src/audio/alsa/SDL_alsa_audio.c
  69. 34 4
      sdl.mod/SDL/src/audio/coreaudio/SDL_coreaudio.m
  70. 47 126
      sdl.mod/SDL/src/audio/netbsd/SDL_netbsdaudio.c
  71. 40 14
      sdl.mod/SDL/src/audio/openslES/SDL_openslES.c
  72. 4 4
      sdl.mod/SDL/src/audio/qsa/SDL_qsa_audio.c
  73. 3 19
      sdl.mod/SDL/src/audio/wasapi/SDL_wasapi.c
  74. 1 1
      sdl.mod/SDL/src/audio/winmm/SDL_winmm.c
  75. 78 20
      sdl.mod/SDL/src/core/android/SDL_android.c
  76. 6 0
      sdl.mod/SDL/src/core/android/SDL_android.h
  77. 20 8
      sdl.mod/SDL/src/core/linux/SDL_dbus.c
  78. 57 22
      sdl.mod/SDL/src/core/linux/SDL_evdev.c
  79. 0 1
      sdl.mod/SDL/src/core/linux/SDL_evdev_kbd.c
  80. 13 9
      sdl.mod/SDL/src/core/linux/SDL_threadprio.c
  81. 7 0
      sdl.mod/SDL/src/core/linux/SDL_udev.c
  82. 65 4
      sdl.mod/SDL/src/cpuinfo/SDL_cpuinfo.c
  83. 0 88
      sdl.mod/SDL/src/cpuinfo/SDL_simd.h
  84. 42 13
      sdl.mod/SDL/src/dynapi/SDL_dynapi.c
  85. 14 0
      sdl.mod/SDL/src/dynapi/SDL_dynapi_overrides.h
  86. 15 1
      sdl.mod/SDL/src/dynapi/SDL_dynapi_procs.h
  87. 3 3
      sdl.mod/SDL/src/dynapi/gendynapi.pl
  88. 9 9
      sdl.mod/SDL/src/events/SDL_events.c
  89. 45 36
      sdl.mod/SDL/src/events/SDL_gesture.c
  90. 2 2
      sdl.mod/SDL/src/events/SDL_keyboard.c
  91. 43 24
      sdl.mod/SDL/src/events/SDL_mouse.c
  92. 1 0
      sdl.mod/SDL/src/events/SDL_mouse_c.h
  93. 36 8
      sdl.mod/SDL/src/events/SDL_touch.c
  94. 2 2
      sdl.mod/SDL/src/events/SDL_touch_c.h
  95. 61 3
      sdl.mod/SDL/src/file/SDL_rwops.c
  96. 21 0
      sdl.mod/SDL/src/filesystem/cocoa/SDL_sysfilesystem.m
  97. 1 1
      sdl.mod/SDL/src/filesystem/unix/SDL_sysfilesystem.c
  98. 1 1
      sdl.mod/SDL/src/hidapi/AUTHORS.txt
  99. 1 1
      sdl.mod/SDL/src/hidapi/README.txt
  100. 744 0
      sdl.mod/SDL/src/hidapi/SDL_hidapi.c

+ 6 - 1
sdl.mod/SDL/Android.mk

@@ -64,7 +64,12 @@ LOCAL_CFLAGS += \
 	-Wmissing-variable-declarations \
 	-Wfloat-conversion \
 	-Wshorten-64-to-32 \
-	-Wunreachable-code-return
+	-Wunreachable-code-return \
+	-Wshift-sign-overflow \
+	-Wunused-macros \
+	-Wstrict-prototypes \
+	-Wkeyword-macro \
+
 
 # Warnings we haven't fixed (yet)
 LOCAL_CFLAGS += -Wno-unused-parameter -Wno-sign-compare

+ 334 - 54
sdl.mod/SDL/CMakeLists.txt

@@ -42,9 +42,9 @@ include(${SDL2_SOURCE_DIR}/cmake/sdlchecks.cmake)
 # set SDL_BINARY_AGE and SDL_INTERFACE_AGE to 0.
 set(SDL_MAJOR_VERSION 2)
 set(SDL_MINOR_VERSION 0)
-set(SDL_MICRO_VERSION 9)
+set(SDL_MICRO_VERSION 11)
 set(SDL_INTERFACE_AGE 0)
-set(SDL_BINARY_AGE 9)
+set(SDL_BINARY_AGE 11)
 set(SDL_VERSION "${SDL_MAJOR_VERSION}.${SDL_MINOR_VERSION}.${SDL_MICRO_VERSION}")
 # the following should match the versions in Xcode project file:
 set(DYLIB_CURRENT_VERSION 10.0.0)
@@ -118,6 +118,8 @@ elseif(APPLE)
     set(DARWIN TRUE)
   elseif(CMAKE_SYSTEM_NAME MATCHES ".*MacOS.*")
     set(MACOSX TRUE)
+  elseif(CMAKE_SYSTEM_NAME MATCHES ".*tvOS.*")
+    set(TVOS TRUE)
   endif()
   # TODO: iOS?
 elseif(CMAKE_SYSTEM_NAME MATCHES "BeOS.*")
@@ -155,6 +157,27 @@ if(UNIX OR MINGW OR MSYS)
   set(OPT_DEF_LIBC ON)
 endif()
 
+# The hidraw support doesn't catch Xbox, PS4 and Nintendo controllers,
+#  so we'll just use libusb when it's available. libusb does not support iOS,
+#  so we default to yes on iOS.
+#  TODO: Windows can support libusb, the hid.c file just depends on Unix APIs
+if(WINDOWS OR IOS OR TVOS OR ANDROID)
+  set(HIDAPI_SKIP_LIBUSB TRUE)
+else()
+  set(HIDAPI_SKIP_LIBUSB FALSE)
+endif()
+if (HIDAPI_SKIP_LIBUSB)
+  set(OPT_DEF_HIDAPI ON)
+endif()
+
+# On the other hand, *BSD specifically uses libusb only, so we make a special
+#  case just for them.
+if(FREEBSD OR NETBSD OR OPENBSD OR BSDI)
+  set(HIDAPI_ONLY_LIBUSB TRUE)
+else()
+  set(HIDAPI_ONLY_LIBUSB FALSE)
+endif()
+
 # Compiler info
 if(CMAKE_COMPILER_IS_GNUCC)
   set(USE_GCC TRUE)
@@ -264,8 +287,23 @@ if(EMSCRIPTEN)
   set(SDL_DLOPEN_ENABLED_BY_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)
+  # ...unless decided already (as for EMSCRIPTEN)
+
+  set(SDL_SHARED_ENABLED_BY_DEFAULT OFF)
+
+  if (NOT DEFINED BUILD_SHARED_LIBS)
+    # No preference? Build both, just like the AC/AM configure
+    set(SDL_SHARED_ENABLED_BY_DEFAULT ON)
+
+  elseif (BUILD_SHARED_LIBS)
+    # In this case, we assume the user wants a shared lib and don't build
+    # the static one
     set(SDL_SHARED_ENABLED_BY_DEFAULT ON)
+    set(SDL_STATIC_ENABLED_BY_DEFAULT OFF)
+  endif()
 endif()
 
 set(SDL_SUBSYSTEMS
@@ -291,6 +329,8 @@ set_option(SSE                 "Use SSE assembly routines" ${OPT_DEF_ASM})
 set_option(SSE2                "Use SSE2 assembly routines" ${OPT_DEF_SSEMATH})
 set_option(SSE3                "Use SSE3 assembly routines" ${OPT_DEF_SSEMATH})
 set_option(ALTIVEC             "Use Altivec assembly routines" ${OPT_DEF_ASM})
+set_option(ARMSIMD             "use SIMD assembly blitters on ARM" ON)
+set_option(ARMNEON             "use NEON assembly blitters on ARM" ON)
 set_option(DISKAUDIO           "Support the disk writer audio driver" ON)
 set_option(DUMMYAUDIO          "Support the dummy audio driver" ON)
 set_option(VIDEO_DIRECTFB      "Use DirectFB video driver" OFF)
@@ -337,17 +377,19 @@ set_option(VIDEO_COCOA         "Use Cocoa video driver" ${APPLE})
 set_option(DIRECTX             "Use DirectX for Windows audio/video" ${WINDOWS})
 set_option(WASAPI              "Use the Windows WASAPI audio driver" ${WINDOWS})
 set_option(RENDER_D3D          "Enable the Direct3D render driver" ${WINDOWS})
+set_option(RENDER_METAL        "Enable the Metal render driver" ${APPLE})
 set_option(VIDEO_VIVANTE       "Use Vivante EGL video driver" ${UNIX_SYS})
 dep_option(VIDEO_VULKAN        "Enable Vulkan support" ON "ANDROID OR APPLE OR LINUX OR WINDOWS" OFF)
+set_option(VIDEO_METAL         "Enable Metal support" ${APPLE})
 set_option(VIDEO_KMSDRM        "Use KMS DRM video driver" ${UNIX_SYS})
 dep_option(KMSDRM_SHARED       "Dynamically load KMS DRM support" ON "VIDEO_KMSDRM" OFF)
+set_option(VIDEO_OFFSCREEN     "Use offscreen video driver" OFF)
 option_string(BACKGROUNDING_SIGNAL "number to use for magic backgrounding signal or 'OFF'" "OFF")
 option_string(FOREGROUNDING_SIGNAL "number to use for magic foregrounding signal or 'OFF'" "OFF")
+set_option(HIDAPI              "Use HIDAPI for low level joystick drivers" ${OPT_DEF_HIDAPI})
 
-# TODO: We should (should we?) respect cmake's ${BUILD_SHARED_LIBS} flag here
-# The options below are for compatibility to configure's default behaviour.
 set(SDL_SHARED ${SDL_SHARED_ENABLED_BY_DEFAULT} CACHE BOOL "Build a shared version of the library")
-set(SDL_STATIC ON CACHE BOOL "Build a static version of the library")
+set(SDL_STATIC ${SDL_STATIC_ENABLED_BY_DEFAULT} CACHE BOOL "Build a static version of the library")
 
 dep_option(SDL_STATIC_PIC      "Static version of the library should be built with Position Independent Code" OFF "SDL_STATIC" OFF)
 set_option(SDL_TEST            "Build the test directory" OFF)
@@ -405,6 +447,11 @@ if(USE_GCC OR USE_CLANG)
     endif()
   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(-Wdeclaration-after-statement HAVE_GCC_WDECLARATION_AFTER_STATEMENT)
   if(HAVE_GCC_WDECLARATION_AFTER_STATEMENT)
     check_c_compiler_flag(-Werror=declaration-after-statement HAVE_GCC_WERROR_DECLARATION_AFTER_STATEMENT)
@@ -626,6 +673,61 @@ if(ASSEMBLY)
         endif()
       endif()
     endif()
+
+    if(ARMSIMD)
+      set(ORIG_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
+      set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -x assembler-with-cpp")
+      check_c_source_compiles("
+        .text
+        .arch armv6
+        .object_arch armv4
+        .arm
+        .altmacro
+        #ifndef __ARM_EABI__
+        #error EABI is required (to be sure that calling conventions are compatible)
+        #endif
+        pld [r0]
+        uqadd8 r0, r0, r0
+      " ARMSIMD_FOUND)
+      set(CMAKE_REQUIRED_FLAGS "${ORIG_CMAKE_REQUIRED_FLAGS}")
+
+      if(ARMSIMD_FOUND)
+        set(HAVE_ARMSIMD TRUE)
+        set(SDL_ARM_SIMD_BLITTERS 1)
+        file(GLOB ARMSIMD_SOURCES ${SDL2_SOURCE_DIR}/src/video/arm/pixman-arm-simd*.S)
+        set(SOURCE_FILES ${SOURCE_FILES} ${ARMSIMD_SOURCES})
+        set(WARN_ABOUT_ARM_SIMD_ASM_MIT TRUE)
+      endif()
+    endif()
+
+    if(ARMNEON)
+      set(ORIG_CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS}")
+      set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -x assembler-with-cpp")
+      check_c_source_compiles("
+        .text
+        .fpu neon
+        .arch armv7a
+        .object_arch armv4
+        .eabi_attribute 10, 0
+        .arm
+        .altmacro
+        #ifndef __ARM_EABI__
+        #error EABI is required (to be sure that calling conventions are compatible)
+        #endif
+        pld [r0]
+        vmovn.u16 d0, q0
+      " ARMNEON_FOUND)
+      set(CMAKE_REQUIRED_FLAGS "${ORIG_CMAKE_REQUIRED_FLAGS}")
+
+      if(ARMNEON_FOUND)
+        set(HAVE_ARMNEON TRUE)
+        set(SDL_ARM_NEON_BLITTERS 1)
+        file(GLOB ARMNEON_SOURCES ${SDL2_SOURCE_DIR}/src/video/arm/pixman-arm-neon*.S)
+        set(SOURCE_FILES ${SOURCE_FILES} ${ARMNEON_SOURCES})
+        set(WARN_ABOUT_ARM_NEON_ASM_MIT TRUE)
+      endif()
+    endif()
+
   elseif(MSVC_VERSION GREATER 1500)
     # TODO: SDL_cpuinfo.h needs to support the user's configuration wish
     # for MSVC - right now it is always activated
@@ -808,8 +910,16 @@ if(SDL_VIDEO)
     set(HAVE_VIDEO_DUMMY TRUE)
     set(HAVE_SDL_VIDEO TRUE)
   endif()
+  if(VIDEO_OFFSCREEN)
+    set(SDL_VIDEO_DRIVER_OFFSCREEN 1)
+    file(GLOB VIDEO_OFFSCREEN_SOURCES ${SDL2_SOURCE_DIR}/src/video/offscreen/*.c)
+    set(SOURCE_FILES ${SOURCE_FILES} ${VIDEO_OFFSCREEN_SOURCES})
+    set(HAVE_VIDEO_OFFSCREEN TRUE)
+    set(HAVE_SDL_VIDEO TRUE)
+  endif()
 endif()
 
+# Platform-specific options and settings
 if(ANDROID)
   file(GLOB ANDROID_CORE_SOURCES ${SDL2_SOURCE_DIR}/src/core/android/*.c)
   set(SOURCE_FILES ${SOURCE_FILES} ${ANDROID_CORE_SOURCES})
@@ -845,6 +955,7 @@ if(ANDROID)
     set(HAVE_SDL_HAPTIC TRUE)
   endif()
   if(SDL_JOYSTICK)
+    CheckHIDAPI()
     set(SDL_JOYSTICK_ANDROID 1)
     file(GLOB ANDROID_JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/android/*.c ${SDL2_SOURCE_DIR}/src/joystick/steam/*.c)
     set(SOURCE_FILES ${SOURCE_FILES} ${ANDROID_JOYSTICK_SOURCES})
@@ -881,16 +992,24 @@ if(ANDROID)
     set(HAVE_SDL_VIDEO TRUE)
 
     # Core stuff
-    find_library(ANDROID_DL_LIBRARY dl)
+    # find_library(ANDROID_DL_LIBRARY dl)
+    # FIXME failing dlopen https://github.com/android-ndk/ndk/issues/929
+    find_library(ANDROID_DL_LIBRARY NAMES libdl.so dl)
     find_library(ANDROID_LOG_LIBRARY log)
     find_library(ANDROID_LIBRARY_LIBRARY android)
     list(APPEND EXTRA_LIBS ${ANDROID_DL_LIBRARY} ${ANDROID_LOG_LIBRARY} ${ANDROID_LIBRARY_LIBRARY})
     add_definitions(-DGL_GLEXT_PROTOTYPES)
 
+    if (HAVE_HIDAPI)
+        list(APPEND EXTRA_LIBS hidapi)
+    endif()
+
     #enable gles
     if(VIDEO_OPENGLES)
       set(SDL_VIDEO_OPENGL_EGL 1)
       set(HAVE_VIDEO_OPENGLES TRUE)
+      set(SDL_VIDEO_OPENGL_ES 1)
+      set(SDL_VIDEO_RENDER_OGL_ES 1)
       set(SDL_VIDEO_OPENGL_ES2 1)
       set(SDL_VIDEO_RENDER_OGL_ES2 1)
 
@@ -914,14 +1033,9 @@ if(ANDROID)
     endif()
   endif()
 
-  file(GLOB ANDROID_HIDAPI_SOURCES ${SDL2_SOURCE_DIR}/src/hidapi/android/*.cpp)
-
   CheckPTHREAD()
 
-endif()
-
-# Platform-specific options and settings
-if(EMSCRIPTEN)
+elseif(EMSCRIPTEN)
   # Hide noisy warnings that intend to aid mostly during initial stages of porting a new
   # project. Uncomment at will for verbose cross-compiling -I/../ path info.
   add_definitions(-Wno-warn-absolute-paths)
@@ -973,6 +1087,7 @@ if(EMSCRIPTEN)
       set(SDL_VIDEO_RENDER_OGL_ES2 1)
     endif()
   endif()
+
 elseif(UNIX AND NOT APPLE AND NOT ANDROID)
   if(SDL_AUDIO)
     if(SYSV5 OR SOLARIS OR HPUX)
@@ -1072,6 +1187,7 @@ elseif(UNIX AND NOT APPLE AND NOT ANDROID)
         set(HAVE_IBUS_IBUS_H TRUE)
         include_directories(${IBUS_INCLUDE_DIRS})
         list(APPEND EXTRA_LIBS ${IBUS_LIBRARIES})
+        add_definitions(-DSDL_USE_IME)
       endif()
       if(HAVE_LIBUNWIND_H)
         # We've already found the header, so REQUIRE the lib to be present
@@ -1095,7 +1211,10 @@ elseif(UNIX AND NOT APPLE AND NOT ANDROID)
   endif()
 
   if(SDL_JOYSTICK)
-    CheckUSBHID()   # seems to be BSD specific - limit the test to BSD only?
+    if(FREEBSD OR NETBSD OR OPENBSD OR BSDI)
+      CheckUSBHID()
+    endif()
+    CheckHIDAPI()
     if(LINUX 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)
@@ -1232,10 +1351,9 @@ elseif(WINDOWS)
     set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS})
   endif()
 
-  # headers needed elsewhere ...
+  # headers needed elsewhere
   check_include_file(mmdeviceapi.h HAVE_MMDEVICEAPI_H)
   check_include_file(audioclient.h HAVE_AUDIOCLIENT_H)
-  check_include_file(endpointvolume.h HAVE_ENDPOINTVOLUME_H)
 
   if(SDL_AUDIO)
     set(SDL_AUDIO_DRIVER_WINMM 1)
@@ -1301,7 +1419,7 @@ elseif(WINDOWS)
   endif()
 
   # Libraries for Win32 native and MinGW
-  list(APPEND EXTRA_LIBS user32 gdi32 winmm imm32 ole32 oleaut32 version uuid advapi32 shell32)
+  list(APPEND EXTRA_LIBS user32 gdi32 winmm imm32 ole32 oleaut32 version uuid advapi32 setupapi shell32)
 
   # TODO: in configure.ac the check for timers is set on
   # cygwin | mingw32* - does this include mingw32CE?
@@ -1339,6 +1457,11 @@ elseif(WINDOWS)
   endif()
 
   if(SDL_JOYSTICK)
+    CheckHIDAPI()
+    # TODO: Remove this hid.c block when SDL_hidapi.c is supported on Windows!
+    if(HAVE_HIDAPI)
+      set(SOURCE_FILES ${SOURCE_FILES} ${SDL2_SOURCE_DIR}/src/hidapi/windows/hid.c)
+    endif()
     file(GLOB JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/windows/*.c)
     set(SOURCE_FILES ${SOURCE_FILES} ${JOYSTICK_SOURCES})
     if(HAVE_DINPUT_H)
@@ -1384,6 +1507,7 @@ elseif(WINDOWS)
     set(SDL_CFLAGS "${SDL_CFLAGS} -Dmain=SDL_main")
     list(APPEND SDL_LIBS "-lmingw32" "-lSDL2main" "-mwindows")
   endif()
+
 elseif(APPLE)
   # TODO: rework this all for proper MacOS X, iOS and Darwin support
 
@@ -1391,10 +1515,11 @@ 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(NOT IOS)
+  if(DARWIN OR MACOSX)
     set(SDL_FRAMEWORK_COCOA 1)
     set(SDL_FRAMEWORK_CARBON 1)
   endif()
+  set(SDL_FRAMEWORK_FOUNDATION 1)
 
   # Requires the darwin file implementation
   if(SDL_FILE)
@@ -1418,48 +1543,63 @@ elseif(APPLE)
     set(HAVE_SDL_AUDIO TRUE)
     set(SDL_FRAMEWORK_COREAUDIO 1)
     set(SDL_FRAMEWORK_AUDIOTOOLBOX 1)
+    set(SDL_FRAMEWORK_AVFOUNDATION 1)
   endif()
 
   if(SDL_JOYSTICK)
-    set(SDL_JOYSTICK_IOKIT 1)
-    if (IOS)
+    CheckHIDAPI()
+    if(HAVE_HIDAPI)
+      if(IOS OR TVOS)
+        set(SOURCE_FILES ${SOURCE_FILES} ${SDL2_SOURCE_DIR}/src/hidapi/ios/hid.m)
+        set(SDL_FRAMEWORK_COREBLUETOOTH 1)
+      endif()
+    endif()
+    if(IOS OR TVOS)
       file(GLOB JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/iphoneos/*.m ${SDL2_SOURCE_DIR}/src/joystick/steam/*.c)
+      set(SDL_JOYSTICK_MFI 1)
+      if(IOS)
+        set(SDL_FRAMEWORK_COREMOTION 1)
+      endif()
+      set(SDL_FRAMEWORK_GAMECONTROLLER 1)
+      set(HAVE_SDL_SENSORS 1)
     else()
       file(GLOB JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/darwin/*.c)
+      set(SDL_JOYSTICK_IOKIT 1)
+      set(SDL_FRAMEWORK_IOKIT 1)
+      set(SDL_FRAMEWORK_FF 1)
     endif()
     set(SOURCE_FILES ${SOURCE_FILES} ${JOYSTICK_SOURCES})
     set(HAVE_SDL_JOYSTICK TRUE)
-    set(SDL_FRAMEWORK_IOKIT 1)
-    set(SDL_FRAMEWORK_FF 1)
   endif()
 
   if(SDL_HAPTIC)
-    set(SDL_HAPTIC_IOKIT 1)
-    if (IOS)
+    if (IOS OR TVOS)
       file(GLOB HAPTIC_SOURCES ${SDL2_SOURCE_DIR}/src/haptic/dummy/*.c)
       set(SDL_HAPTIC_DUMMY 1)
     else()
       file(GLOB HAPTIC_SOURCES ${SDL2_SOURCE_DIR}/src/haptic/darwin/*.c)
+      set(SDL_HAPTIC_IOKIT 1)
+      set(SDL_FRAMEWORK_IOKIT 1)
+      set(SDL_FRAMEWORK_FF 1)
     endif()
     set(SOURCE_FILES ${SOURCE_FILES} ${HAPTIC_SOURCES})
     set(HAVE_SDL_HAPTIC TRUE)
-    set(SDL_FRAMEWORK_IOKIT 1)
-    set(SDL_FRAMEWORK_FF 1)
     if(NOT SDL_JOYSTICK)
       message(FATAL_ERROR "SDL_HAPTIC requires SDL_JOYSTICK to be enabled")
     endif()
   endif()
 
   if(SDL_POWER)
-    set(SDL_POWER_MACOSX 1)
-    if (IOS)
+    if (IOS OR TVOS)
       file(GLOB POWER_SOURCES ${SDL2_SOURCE_DIR}/src/power/uikit/*.m)
+      set(SDL_POWER_UIKIT 1)
     else()
       file(GLOB POWER_SOURCES ${SDL2_SOURCE_DIR}/src/power/macosx/*.c)
+      set(SDL_POWER_MACOSX 1)
+      set(SDL_FRAMEWORK_IOKIT 1)
     endif()
     set(SOURCE_FILES ${SOURCE_FILES} ${POWER_SOURCES})
     set(HAVE_SDL_POWER TRUE)
-    set(SDL_FRAMEWORK_IOKIT 1)
   endif()
 
   if(SDL_TIMERS)
@@ -1478,6 +1618,89 @@ elseif(APPLE)
     set(HAVE_SDL_FILESYSTEM TRUE)
   endif()
 
+  if(SDL_SENSOR)
+    if(IOS)
+      set(SDL_SENSOR_COREMOTION 1)
+      set(HAVE_SDL_SENSORS TRUE)
+      file(GLOB SENSOR_SOURCES ${SDL2_SOURCE_DIR}/src/sensor/coremotion/*.m)
+      set(SOURCE_FILES ${SOURCE_FILES} ${SENSOR_SOURCES})
+    endif()
+  endif()
+
+  # iOS hack needed - http://code.google.com/p/ios-cmake/ ?
+  if(SDL_VIDEO)
+    if (IOS OR TVOS)
+      set(SDL_VIDEO_DRIVER_UIKIT 1)
+      set(SDL_FRAMEWORK_COREGRAPHICS 1)
+      set(SDL_FRAMEWORK_QUARTZCORE 1)
+      set(SDL_FRAMEWORK_UIKIT 1)
+      set(SDL_IPHONE_KEYBOARD 1)
+      set(SDL_IPHONE_LAUNCHSCREEN 1)
+      file(GLOB UIKITVIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/uikit/*.m)
+      set(SOURCE_FILES ${SOURCE_FILES} ${UIKITVIDEO_SOURCES})
+    else()
+      CheckCOCOA()
+      if(VIDEO_OPENGL)
+        set(SDL_VIDEO_OPENGL 1)
+        set(SDL_VIDEO_OPENGL_CGL 1)
+        set(SDL_VIDEO_RENDER_OGL 1)
+        set(HAVE_VIDEO_OPENGL TRUE)
+      endif()
+    endif()
+
+    if(VIDEO_OPENGLES)
+      if(IOS OR TVOS)
+        set(SDL_FRAMEWORK_OPENGLES 1)
+        set(SDL_VIDEO_OPENGL_ES 1)
+        set(SDL_VIDEO_RENDER_OGL_ES 1)
+      else()
+        set(SDL_VIDEO_OPENGL_EGL 1)
+      endif()
+      set(SDL_VIDEO_OPENGL_ES2 1)
+      set(SDL_VIDEO_RENDER_OGL_ES2 1)
+      set(HAVE_VIDEO_OPENGLES TRUE)
+    endif()
+
+    if(VIDEO_VULKAN OR VIDEO_METAL OR RENDER_METAL)
+      set(ORIG_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS})
+      set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -x objective-c")
+      check_c_source_compiles("
+        #include <AvailabilityMacros.h>
+        #import <Metal/Metal.h>
+        #import <QuartzCore/CAMetalLayer.h>
+
+        #if TARGET_OS_SIMULATOR || (!TARGET_CPU_X86_64 && !TARGET_CPU_ARM64)
+        #error Metal doesn't work on this configuration
+        #endif
+        int main()
+        {
+            return 0;
+        }
+        " HAVE_FRAMEWORK_METAL)
+      set(CMAKE_REQUIRED_FLAGS ${ORIG_CMAKE_REQUIRED_FLAGS})
+      if(HAVE_FRAMEWORK_METAL)
+        set(SDL_FRAMEWORK_METAL 1)
+        set(SDL_FRAMEWORK_QUARTZCORE 1)
+      else()
+        set(VIDEO_VULKAN 0)
+        set(VIDEO_METAL 0)
+        set(RENDER_METAL 0)
+      endif()
+    endif()
+
+    if(VIDEO_METAL)
+      set(SDL_VIDEO_METAL 1)
+      set(HAVE_VIDEO_METAL TRUE)
+    endif()
+
+    if(RENDER_METAL)
+      file(GLOB RENDER_METAL_SOURCES ${SDL2_SOURCE_DIR}/src/render/metal/*.m)
+      set(SOURCE_FILES ${SOURCE_FILES} ${RENDER_METAL_SOURCES})
+      set(SDL_VIDEO_RENDER_METAL 1)
+      set(HAVE_RENDER_METAL TRUE)
+    endif()
+  endif()
+
   # Actually load the frameworks at the end so we don't duplicate include.
   if(SDL_FRAMEWORK_COREVIDEO)
     find_library(COREVIDEO CoreVideo)
@@ -1507,32 +1730,57 @@ elseif(APPLE)
     find_library(AUDIOTOOLBOX AudioToolbox)
     list(APPEND EXTRA_LIBS ${AUDIOTOOLBOX})
   endif()
-
-  # iOS hack needed - http://code.google.com/p/ios-cmake/ ?
-  if(SDL_VIDEO)
-    if (IOS)
-      set(SDL_VIDEO_DRIVER_UIKIT 1)
-      file(GLOB UIKITVIDEO_SOURCES ${SDL2_SOURCE_DIR}/src/video/uikit/*.m)
-      set(SOURCE_FILES ${SOURCE_FILES} ${UIKITVIDEO_SOURCES})
+  if(SDL_FRAMEWORK_AVFOUNDATION)
+    find_library(AVFOUNDATION AVFoundation)
+    list(APPEND EXTRA_LIBS ${AVFOUNDATION})
+  endif()
+  if(SDL_FRAMEWORK_COREBLUETOOTH)
+    find_library(COREBLUETOOTH CoreBluetooth)
+    list(APPEND EXTRA_LIBS ${COREBLUETOOTH})
+  endif()
+  if(SDL_FRAMEWORK_COREGRAPHICS)
+    find_library(COREGRAPHICS CoreGraphics)
+    list(APPEND EXTRA_LIBS ${COREGRAPHICS})
+  endif()
+  if(SDL_FRAMEWORK_COREMOTION)
+    find_library(COREMOTION CoreMotion)
+    list(APPEND EXTRA_LIBS ${COREMOTION})
+  endif()
+  if(SDL_FRAMEWORK_FOUNDATION)
+    find_library(FOUNDATION Foundation)
+    list(APPEND EXTRA_LIBS ${FOUNDATION})
+  endif()
+  if(SDL_FRAMEWORK_GAMECONTROLLER)
+    find_library(GAMECONTROLLER GameController)
+    list(APPEND EXTRA_LIBS ${GAMECONTROLLER})
+  endif()
+  if(SDL_FRAMEWORK_METAL)
+    if(IOS OR TVOS)
+      find_library(METAL Metal)
+      list(APPEND EXTRA_LIBS ${METAL})
     else()
-      CheckCOCOA()
-      if(VIDEO_OPENGL)
-        set(SDL_VIDEO_OPENGL 1)
-        set(SDL_VIDEO_OPENGL_CGL 1)
-        set(SDL_VIDEO_RENDER_OGL 1)
-        set(HAVE_VIDEO_OPENGL TRUE)
-      endif()
-
-      if(VIDEO_OPENGLES)
-        set(SDL_VIDEO_OPENGL_EGL 1)
-        set(SDL_VIDEO_OPENGL_ES2 1)
-        set(SDL_VIDEO_RENDER_OGL_ES2 1)
-        set(HAVE_VIDEO_OPENGLES TRUE)
-      endif()
+      list(APPEND EXTRA_LDFLAGS "-Wl,-weak_framework,Metal")
+    endif()
+  endif()
+  if(SDL_FRAMEWORK_OPENGLES)
+    find_library(OPENGLES OpenGLES)
+    list(APPEND EXTRA_LIBS ${OPENGLES})
+  endif()
+  if(SDL_FRAMEWORK_QUARTZCORE)
+    if(IOS OR TVOS)
+      find_library(QUARTZCORE QuartzCore)
+      list(APPEND EXTRA_LIBS ${QUARTZCORE})
+    else()
+      list(APPEND EXTRA_LDFLAGS "-Wl,-weak_framework,QuartzCore")
     endif()
   endif()
+  if(SDL_FRAMEWORK_UIKIT)
+    find_library(UIKIT UIKit)
+    list(APPEND EXTRA_LIBS ${UIKIT})
+  endif()
 
   CheckPTHREAD()
+
 elseif(HAIKU)
   if(SDL_VIDEO)
     set(SDL_VIDEO_DRIVER_HAIKU 1)
@@ -1736,6 +1984,24 @@ if(UNIX)
   message(STATUS "")
 endif()
 
+if(WARN_ABOUT_ARM_SIMD_ASM_MIT)
+  message(STATUS "")
+  message(STATUS "SDL is being built with ARM SIMD optimizations, which")
+  message(STATUS "uses code licensed under the MIT license. If this is a")
+  message(STATUS "problem, please disable that code by rerunning CMake with:")
+  message(STATUS "")
+  message(STATUS "    -DARMSIMD=OFF")
+endif()
+
+if(WARN_ABOUT_ARM_NEON_ASM_MIT)
+  message(STATUS "")
+  message(STATUS "SDL is being built with ARM NEON optimizations, which")
+  message(STATUS "uses code licensed under the MIT license. If this is a")
+  message(STATUS "problem, please disable that code by rerunning CMake with:")
+  message(STATUS "")
+  message(STATUS "    -DARMNEON=OFF")
+endif()
+
 # Ensure that the extra cflags are used at compile time
 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${EXTRA_CFLAGS}")
 
@@ -1747,6 +2013,10 @@ if (NOT ANDROID)
   set_target_properties(SDL2main PROPERTIES DEBUG_POSTFIX ${SDL_CMAKE_DEBUG_POSTFIX})
 endif()
 
+if (ANDROID AND HAVE_HIDAPI)
+  set(_INSTALL_LIBS ${_INSTALL_LIBS} "hidapi")
+endif()
+
 if(SDL_SHARED)
   add_library(SDL2 SHARED ${SOURCE_FILES} ${VERSION_SOURCES})
   if(APPLE)
@@ -1776,17 +2046,26 @@ if(SDL_SHARED)
   if (NOT ANDROID)
     set_target_properties(SDL2 PROPERTIES DEBUG_POSTFIX ${SDL_CMAKE_DEBUG_POSTFIX})
   endif()
+  if(IOS OR TVOS)
+    set_property(TARGET SDL2 APPEND_STRING PROPERTY COMPILE_FLAGS "-fobjc-arc")
+    target_compile_definitions(SDL2 PRIVATE IOS_DYLIB=1)
+  endif()
 endif()
 
 if(ANDROID)
-  add_library(hidapi SHARED ${ANDROID_HIDAPI_SOURCES})
+  if(HAVE_HIDAPI)
+    add_library(hidapi SHARED ${SDL2_SOURCE_DIR}/src/hidapi/android/hid.cpp)
+  endif()
+
   if(MSVC AND NOT LIBC)
     # Don't try to link with the default set of libraries.
     set_target_properties(hidapi PROPERTIES LINK_FLAGS_RELEASE "/NODEFAULTLIB")
     set_target_properties(hidapi PROPERTIES LINK_FLAGS_DEBUG "/NODEFAULTLIB")
     set_target_properties(hidapi PROPERTIES STATIC_LIBRARY_FLAGS "/NODEFAULTLIB")
   endif()
-  target_link_libraries(hidapi log)
+  if(HAVE_HIDAPI)
+    target_link_libraries(hidapi log)
+  endif()
 endif()
 
 if(SDL_STATIC)
@@ -1813,6 +2092,9 @@ if(SDL_STATIC)
   if (NOT ANDROID)
     set_target_properties(SDL2-static PROPERTIES DEBUG_POSTFIX ${SDL_CMAKE_DEBUG_POSTFIX})
   endif()
+  if(IOS OR TVOS)
+    set_property(TARGET SDL2-static APPEND_STRING PROPERTY COMPILE_FLAGS "-fobjc-arc")
+  endif()
 endif()
 
 ##### Tests #####
@@ -1831,9 +2113,7 @@ install(TARGETS ${_INSTALL_LIBS} EXPORT SDL2Targets
   RUNTIME DESTINATION bin)
 
 ##### Export files #####
-if (APPLE)
-  set(PKG_PREFIX "SDL2.framework/Resources")
-elseif (WINDOWS)
+if (WINDOWS)
   set(PKG_PREFIX "cmake")
 else ()
   set(PKG_PREFIX "lib/cmake/SDL2")

+ 1 - 0
sdl.mod/SDL/Makefile.in

@@ -84,6 +84,7 @@ HDRS = \
 	SDL_log.h \
 	SDL_main.h \
 	SDL_messagebox.h \
+	SDL_metal.h \
 	SDL_mouse.h \
 	SDL_mutex.h \
 	SDL_name.h \

+ 4 - 1
sdl.mod/SDL/Makefile.os2

@@ -2,7 +2,7 @@
 # wmake -f Makefile.os2
 
 LIBNAME = SDL2
-VERSION = 2.0.9
+VERSION = 2.0.11
 DESCRIPTION = Simple DirectMedia Layer 2
 
 LIBHOME = .
@@ -89,6 +89,9 @@ SDL_cpuinfo.obj: SDL_cpuinfo.c
 SDL_rwops.obj: SDL_rwops.c
     wcc386 $(CFLAGS) -wcd=136 -fo=$^@ $<
 
+SDL_wave.obj: SDL_wave.c
+    wcc386 $(CFLAGS) -wcd=124 -fo=$^@ $<
+
 SDL_blendfillrect.obj: SDL_blendfillrect.c
     wcc386 $(CFLAGS) -wcd=200 -fo=$^@ $<
 

+ 2 - 1
sdl.mod/SDL/SDL2.spec.in

@@ -74,7 +74,8 @@ rm -rf $RPM_BUILD_ROOT
 %{_libdir}/lib*.la
 %{_libdir}/lib*.%{__soext}
 %{_includedir}/*/*.h
-%{_libdir}/pkgconfig/*
+%{_libdir}/cmake/*
+%{_libdir}/pkgconfig/SDL2/*
 %{_datadir}/aclocal/*
 
 %changelog

+ 1 - 4
sdl.mod/SDL/VisualC/SDL/SDL.vcxproj

@@ -130,7 +130,6 @@
       <PreprocessorDefinitions>_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
       <BufferSecurityCheck>false</BufferSecurityCheck>
-      <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>OldStyle</DebugInformationFormat>
       <OmitDefaultLibName>true</OmitDefaultLibName>
@@ -196,7 +195,6 @@
       <PreprocessorDefinitions>NDEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
       <BufferSecurityCheck>false</BufferSecurityCheck>
-      <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
       <OmitDefaultLibName>true</OmitDefaultLibName>
@@ -320,7 +318,7 @@
     <ClInclude Include="..\..\src\haptic\windows\SDL_dinputhaptic_c.h" />
     <ClInclude Include="..\..\src\haptic\windows\SDL_windowshaptic_c.h" />
     <ClInclude Include="..\..\src\haptic\windows\SDL_xinputhaptic_c.h" />
-    <ClInclude Include="..\..\src\joystick\hidapi\controller_type.h" />
+    <ClInclude Include="..\..\src\joystick\controller_type.h" />
     <ClInclude Include="..\..\src\joystick\hidapi\SDL_hidapijoystick_c.h" />
     <ClInclude Include="..\..\src\joystick\SDL_joystick_c.h" />
     <ClInclude Include="..\..\src\joystick\SDL_sysjoystick.h" />
@@ -421,7 +419,6 @@
     <ClCompile Include="..\..\src\haptic\windows\SDL_xinputhaptic.c" />
     <ClCompile Include="..\..\src\hidapi\windows\hid.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapijoystick.c" />
-    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_gamecube.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_ps4.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />

+ 1 - 2
sdl.mod/SDL/VisualC/SDL/SDL.vcxproj.filters

@@ -259,7 +259,7 @@
     <ClInclude Include="..\..\src\haptic\windows\SDL_dinputhaptic_c.h" />
     <ClInclude Include="..\..\src\haptic\windows\SDL_windowshaptic_c.h" />
     <ClInclude Include="..\..\src\haptic\windows\SDL_xinputhaptic_c.h" />
-    <ClInclude Include="..\..\src\joystick\hidapi\controller_type.h" />
+    <ClInclude Include="..\..\src\joystick\controller_type.h" />
     <ClInclude Include="..\..\src\joystick\hidapi\SDL_hidapijoystick_c.h" />
     <ClInclude Include="..\..\src\joystick\SDL_joystick_c.h" />
     <ClInclude Include="..\..\src\joystick\SDL_sysjoystick.h" />
@@ -360,7 +360,6 @@
     <ClCompile Include="..\..\src\haptic\windows\SDL_windowshaptic.c" />
     <ClCompile Include="..\..\src\haptic\windows\SDL_xinputhaptic.c" />
     <ClCompile Include="..\..\src\hidapi\windows\hid.c" />
-    <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_gamecube.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_ps4.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_switch.c" />
     <ClCompile Include="..\..\src\joystick\hidapi\SDL_hidapi_xbox360.c" />

+ 0 - 2
sdl.mod/SDL/VisualC/SDLmain/SDLmain.vcxproj

@@ -108,7 +108,6 @@
       <StringPooling>true</StringPooling>
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
       <BufferSecurityCheck>false</BufferSecurityCheck>
-      <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>OldStyle</DebugInformationFormat>
       <OmitDefaultLibName>true</OmitDefaultLibName>
@@ -143,7 +142,6 @@
       <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
       <BufferSecurityCheck>false</BufferSecurityCheck>
-      <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>OldStyle</DebugInformationFormat>
       <OmitDefaultLibName>true</OmitDefaultLibName>

+ 0 - 2
sdl.mod/SDL/VisualC/SDLtest/SDLtest.vcxproj

@@ -108,7 +108,6 @@
       <StringPooling>true</StringPooling>
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
       <BufferSecurityCheck>false</BufferSecurityCheck>
-      <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>OldStyle</DebugInformationFormat>
       <OmitDefaultLibName>true</OmitDefaultLibName>
@@ -143,7 +142,6 @@
       <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
       <BufferSecurityCheck>false</BufferSecurityCheck>
-      <EnableEnhancedInstructionSet>StreamingSIMDExtensions</EnableEnhancedInstructionSet>
       <WarningLevel>Level3</WarningLevel>
       <DebugInformationFormat>OldStyle</DebugInformationFormat>
       <OmitDefaultLibName>true</OmitDefaultLibName>

+ 28 - 0
sdl.mod/SDL/WhatsNew.txt

@@ -1,17 +1,45 @@
 
 This is a list of major changes in SDL's version history.
 
+---------------------------------------------------------------------------
+2.0.11/12:
+---------------------------------------------------------------------------
+
+General:
+* Added SDL_LockTextureToSurface(), similar to SDL_LockTexture() but the locked area is exposed as a SDL surface.
+
 ---------------------------------------------------------------------------
 2.0.10:
 ---------------------------------------------------------------------------
+
+General:
+* The SDL_RW* macros have been turned into functions that are available only in 2.0.10 and onward
+* Added SDL_SIMDGetAlignment(), SDL_SIMDAlloc(), and SDL_SIMDFree(), to allocate memory aligned for SIMD operations for the current CPU
+* Added SDL_RenderDrawPointF(), SDL_RenderDrawPointsF(), SDL_RenderDrawLineF(), SDL_RenderDrawLinesF(), SDL_RenderDrawRectF(), SDL_RenderDrawRectsF(), SDL_RenderFillRectF(), SDL_RenderFillRectsF(), SDL_RenderCopyF(), SDL_RenderCopyExF(), to allow floating point precision in the SDL rendering API.
+* Added SDL_GetTouchDeviceType() to get the type of a touch device, which can be a touch screen or a trackpad in relative or absolute coordinate mode.
+* The SDL rendering API now uses batched rendering by default, for improved performance
+* Added SDL_RenderFlush() to force batched render commands to execute, if you're going to mix SDL rendering with native rendering
+* Added the hint SDL_HINT_RENDER_BATCHING to control whether batching should be used for the rendering API. This defaults to "1" if you don't specify what rendering driver to use when creating the renderer.
+* Added the hint SDL_HINT_EVENT_LOGGING to enable logging of SDL events for debugging purposes
+* Added the hint SDL_HINT_GAMECONTROLLERCONFIG_FILE to specify a file that will be loaded at joystick initialization with game controller bindings
 * Added the hint SDL_HINT_MOUSE_TOUCH_EVENTS to control whether SDL will synthesize touch events from mouse events
+* Improved handling of malformed WAVE and BMP files, fixing potential security exploits
+
+Linux:
+* Removed the Mir video driver in favor of Wayland
+
+iOS / tvOS:
+* Added support for Xbox and PS4 wireless controllers in iOS 13 and tvOS 13
+* Added support for text input using Bluetooth keyboards
 
 Android:
+* Added low latency audio using OpenSL ES
 * Removed SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH (replaced by SDL_HINT_MOUSE_TOUCH_EVENTS and SDL_HINT_TOUCH_MOUSE_EVENTS)
   SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH=1, should be replaced by setting both previous hints to 0.
   SDL_HINT_ANDROID_SEPARATE_MOUSE_AND_TOUCH=0, should be replaced by setting both previous hints to 1.
 * Added the hint SDL_HINT_ANDROID_BLOCK_ON_PAUSE to set whether the event loop will block itself when the app is paused.
 
+
 ---------------------------------------------------------------------------
 2.0.9:
 ---------------------------------------------------------------------------

+ 134 - 48
sdl.mod/SDL/Xcode-iOS/Demos/Demos.xcodeproj/project.pbxproj

@@ -10,6 +10,13 @@
 		1D3623EC0D0F72F000981E51 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D3623EB0D0F72F000981E51 /* CoreGraphics.framework */; };
 		1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; };
 		1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; };
+		F3F7590022AC5EC7001D97F2 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3F758FF22AC5EC7001D97F2 /* Metal.framework */; };
+		F3F7590122AC5F00001D97F2 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3F758FF22AC5EC7001D97F2 /* Metal.framework */; };
+		F3F7590222AC5F3D001D97F2 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3F758FF22AC5EC7001D97F2 /* Metal.framework */; };
+		F3F7590322AC5F71001D97F2 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3F758FF22AC5EC7001D97F2 /* Metal.framework */; };
+		F3F7590422AC5F8D001D97F2 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3F758FF22AC5EC7001D97F2 /* Metal.framework */; };
+		F3F7590522AC5FB3001D97F2 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3F758FF22AC5EC7001D97F2 /* Metal.framework */; };
+		F3F7590622AC5FD1001D97F2 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F3F758FF22AC5EC7001D97F2 /* Metal.framework */; };
 		FA30DEB01BBF5A8F009C397F /* common.c in Sources */ = {isa = PBXBuildFile; fileRef = FD77A0060E26BC0500F39101 /* common.c */; };
 		FA30DEB11BBF5A93009C397F /* happy.c in Sources */ = {isa = PBXBuildFile; fileRef = FD77A0080E26BC0500F39101 /* happy.c */; };
 		FA30DEB31BBF5AD7009C397F /* icon.bmp in Resources */ = {isa = PBXBuildFile; fileRef = FDB651CC0E43D19800F688B5 /* icon.bmp */; };
@@ -40,7 +47,6 @@
 		FA8B4BA91967073D00F8EB7C /* CoreMotion.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA8B4BA21967070A00F8EB7C /* CoreMotion.framework */; };
 		FABA34D41D8B5E5600915323 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FABA34D31D8B5E5600915323 /* AVFoundation.framework */; };
 		FABA34D61D8B5E5A00915323 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FABA34D31D8B5E5600915323 /* AVFoundation.framework */; };
-		FABA34D81D8B5E7700915323 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FABA34D71D8B5E7700915323 /* AVFoundation.framework */; };
 		FABA34D91D8B5E7B00915323 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FABA34D31D8B5E5600915323 /* AVFoundation.framework */; };
 		FABA34DA1D8B5E7F00915323 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FABA34D31D8B5E5600915323 /* AVFoundation.framework */; };
 		FABA34DB1D8B5E8500915323 /* AVFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FABA34D31D8B5E5600915323 /* AVFoundation.framework */; };
@@ -197,6 +203,34 @@
 			remoteGlobalIDString = FD6526620DE8FCCB002AD96B;
 			remoteInfo = libSDL;
 		};
+		F3F758F722AC5E8F001D97F2 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = FD1B48920E313154007AB34E /* SDL.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = 52ED1E5C222889500061FCE0;
+			remoteInfo = "libSDL-iOS-dylib";
+		};
+		F3F758F922AC5E8F001D97F2 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = FD1B48920E313154007AB34E /* SDL.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = F3E3C7572241389A007D243C;
+			remoteInfo = "libSDL-tvOS-dylib";
+		};
+		F3F758FB22AC5E8F001D97F2 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = FD1B48920E313154007AB34E /* SDL.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = F3E3C65222406928007D243C;
+			remoteInfo = "libSDLmain-iOS";
+		};
+		F3F758FD22AC5E8F001D97F2 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = FD1B48920E313154007AB34E /* SDL.xcodeproj */;
+			proxyType = 2;
+			remoteGlobalIDString = F3E3C75F224138AE007D243C;
+			remoteInfo = "libSDLmain-tvOS";
+		};
 		FA30DEAB1BBF59D9009C397F /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = FD1B48920E313154007AB34E /* SDL.xcodeproj */;
@@ -226,6 +260,7 @@
 		1D6058910D05DD3D006BFB54 /* Rectangles.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Rectangles.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
 		8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		F3F758FF22AC5EC7001D97F2 /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
 		FA30DE961BBF59D9009C397F /* Happy-TV.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Happy-TV.app"; sourceTree = BUILT_PRODUCTS_DIR; };
 		FA86C0361D9765BA009CB637 /* iOS Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = "iOS Launch Screen.storyboard"; sourceTree = "<group>"; };
 		FA8B4BA21967070A00F8EB7C /* CoreMotion.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMotion.framework; path = System/Library/Frameworks/CoreMotion.framework; sourceTree = SDKROOT; };
@@ -271,17 +306,18 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				FABA34D41D8B5E5600915323 /* AVFoundation.framework in Frameworks */,
 				FD1B48DD0E313255007AB34E /* libSDL2.a in Frameworks */,
-				FAE0E96A1BAF96A00098DFA4 /* GameController.framework in Frameworks */,
-				FA8B4BA31967070A00F8EB7C /* CoreMotion.framework in Frameworks */,
-				FDF0D7AB0E12D53800247964 /* CoreAudio.framework in Frameworks */,
 				FDF0D7AC0E12D53800247964 /* AudioToolbox.framework in Frameworks */,
-				1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */,
-				1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */,
+				FABA34D41D8B5E5600915323 /* AVFoundation.framework in Frameworks */,
+				FDF0D7AB0E12D53800247964 /* CoreAudio.framework in Frameworks */,
 				1D3623EC0D0F72F000981E51 /* CoreGraphics.framework in Frameworks */,
+				FA8B4BA31967070A00F8EB7C /* CoreMotion.framework in Frameworks */,
+				1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */,
+				FAE0E96A1BAF96A00098DFA4 /* GameController.framework in Frameworks */,
+				F3F7590022AC5EC7001D97F2 /* Metal.framework in Frameworks */,
 				FDB96ED40DEFC9C700FAF19F /* OpenGLES.framework in Frameworks */,
 				FDB96EE00DEFC9DC00FAF19F /* QuartzCore.framework in Frameworks */,
+				1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -289,16 +325,15 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				FABA34D81D8B5E7700915323 /* AVFoundation.framework in Frameworks */,
 				FA30DEB71BBF5BB8009C397F /* libSDL2.a in Frameworks */,
-				FA30DEC81BBF5C14009C397F /* GameController.framework in Frameworks */,
 				FA30DEC91BBF5C14009C397F /* AudioToolbox.framework in Frameworks */,
+				FA30DECF1BBF5C14009C397F /* CoreAudio.framework in Frameworks */,
+				FA30DECC1BBF5C14009C397F /* CoreGraphics.framework in Frameworks */,
+				FA30DECE1BBF5C14009C397F /* Foundation.framework in Frameworks */,
+				FA30DEC81BBF5C14009C397F /* GameController.framework in Frameworks */,
 				FA30DECA1BBF5C14009C397F /* QuartzCore.framework in Frameworks */,
 				FA30DECB1BBF5C14009C397F /* OpenGLES.framework in Frameworks */,
-				FA30DECC1BBF5C14009C397F /* CoreGraphics.framework in Frameworks */,
 				FA30DECD1BBF5C14009C397F /* UIKit.framework in Frameworks */,
-				FA30DECE1BBF5C14009C397F /* Foundation.framework in Frameworks */,
-				FA30DECF1BBF5C14009C397F /* CoreAudio.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -306,17 +341,18 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				FABA34D61D8B5E5A00915323 /* AVFoundation.framework in Frameworks */,
 				FD1B49980E313261007AB34E /* libSDL2.a in Frameworks */,
-				FAE0E96C1BAF96A90098DFA4 /* GameController.framework in Frameworks */,
-				FA8B4BA41967071300F8EB7C /* CoreMotion.framework in Frameworks */,
-				FDF0D7A90E12D53500247964 /* CoreAudio.framework in Frameworks */,
 				FDF0D7AA0E12D53500247964 /* AudioToolbox.framework in Frameworks */,
-				FD15FD690E086911003BDF25 /* Foundation.framework in Frameworks */,
-				FD15FD6A0E086911003BDF25 /* UIKit.framework in Frameworks */,
+				FABA34D61D8B5E5A00915323 /* AVFoundation.framework in Frameworks */,
+				FDF0D7A90E12D53500247964 /* CoreAudio.framework in Frameworks */,
 				FD15FD6B0E086911003BDF25 /* CoreGraphics.framework in Frameworks */,
+				FA8B4BA41967071300F8EB7C /* CoreMotion.framework in Frameworks */,
+				FD15FD690E086911003BDF25 /* Foundation.framework in Frameworks */,
+				FAE0E96C1BAF96A90098DFA4 /* GameController.framework in Frameworks */,
+				F3F7590122AC5F00001D97F2 /* Metal.framework in Frameworks */,
 				FD15FD6C0E086911003BDF25 /* OpenGLES.framework in Frameworks */,
 				FD15FD6D0E086911003BDF25 /* QuartzCore.framework in Frameworks */,
+				FD15FD6A0E086911003BDF25 /* UIKit.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -324,17 +360,18 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				FABA34D91D8B5E7B00915323 /* AVFoundation.framework in Frameworks */,
 				FD1B499C0E313269007AB34E /* libSDL2.a in Frameworks */,
-				FAE0E96D1BAF96AF0098DFA4 /* GameController.framework in Frameworks */,
-				FA8B4BA51967071A00F8EB7C /* CoreMotion.framework in Frameworks */,
-				FDF0D7A70E12D53200247964 /* CoreAudio.framework in Frameworks */,
 				FDF0D7A80E12D53200247964 /* AudioToolbox.framework in Frameworks */,
+				FABA34D91D8B5E7B00915323 /* AVFoundation.framework in Frameworks */,
+				FDF0D7A70E12D53200247964 /* CoreAudio.framework in Frameworks */,
+				FD5F9CEA0E0E0741008E885B /* CoreGraphics.framework in Frameworks */,
+				FA8B4BA51967071A00F8EB7C /* CoreMotion.framework in Frameworks */,
+				FD5F9CE80E0E0741008E885B /* Foundation.framework in Frameworks */,
+				FAE0E96D1BAF96AF0098DFA4 /* GameController.framework in Frameworks */,
+				F3F7590222AC5F3D001D97F2 /* Metal.framework in Frameworks */,
 				FD5F9CEB0E0E0741008E885B /* OpenGLES.framework in Frameworks */,
 				FD5F9CEC0E0E0741008E885B /* QuartzCore.framework in Frameworks */,
-				FD5F9CE80E0E0741008E885B /* Foundation.framework in Frameworks */,
 				FD5F9CE90E0E0741008E885B /* UIKit.framework in Frameworks */,
-				FD5F9CEA0E0E0741008E885B /* CoreGraphics.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -342,17 +379,18 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				FABA34DD1D8B5E8D00915323 /* AVFoundation.framework in Frameworks */,
 				FDB652000E43D1F300F688B5 /* libSDL2.a in Frameworks */,
-				FAE0E9711BAF96BB0098DFA4 /* GameController.framework in Frameworks */,
+				FDB652080E43D1F300F688B5 /* AudioToolbox.framework in Frameworks */,
+				FABA34DD1D8B5E8D00915323 /* AVFoundation.framework in Frameworks */,
+				FDB652070E43D1F300F688B5 /* CoreAudio.framework in Frameworks */,
+				FDB652040E43D1F300F688B5 /* CoreGraphics.framework in Frameworks */,
 				FA8B4BA91967073D00F8EB7C /* CoreMotion.framework in Frameworks */,
 				FDB652020E43D1F300F688B5 /* Foundation.framework in Frameworks */,
-				FDB652030E43D1F300F688B5 /* UIKit.framework in Frameworks */,
-				FDB652040E43D1F300F688B5 /* CoreGraphics.framework in Frameworks */,
+				FAE0E9711BAF96BB0098DFA4 /* GameController.framework in Frameworks */,
+				F3F7590622AC5FD1001D97F2 /* Metal.framework in Frameworks */,
 				FDB652050E43D1F300F688B5 /* OpenGLES.framework in Frameworks */,
 				FDB652060E43D1F300F688B5 /* QuartzCore.framework in Frameworks */,
-				FDB652070E43D1F300F688B5 /* CoreAudio.framework in Frameworks */,
-				FDB652080E43D1F300F688B5 /* AudioToolbox.framework in Frameworks */,
+				FDB652030E43D1F300F688B5 /* UIKit.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -360,17 +398,18 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				FABA34DA1D8B5E7F00915323 /* AVFoundation.framework in Frameworks */,
 				FD1B499E0E31326C007AB34E /* libSDL2.a in Frameworks */,
-				FAE0E96E1BAF96B10098DFA4 /* GameController.framework in Frameworks */,
-				FA8B4BA61967072100F8EB7C /* CoreMotion.framework in Frameworks */,
-				FDF0D7950E12D52900247964 /* CoreAudio.framework in Frameworks */,
 				FDF0D7960E12D52900247964 /* AudioToolbox.framework in Frameworks */,
-				FDC202E60E107B1200ABAC90 /* Foundation.framework in Frameworks */,
-				FDC202E70E107B1200ABAC90 /* UIKit.framework in Frameworks */,
+				FABA34DA1D8B5E7F00915323 /* AVFoundation.framework in Frameworks */,
+				FDF0D7950E12D52900247964 /* CoreAudio.framework in Frameworks */,
 				FDC202E80E107B1200ABAC90 /* CoreGraphics.framework in Frameworks */,
+				FA8B4BA61967072100F8EB7C /* CoreMotion.framework in Frameworks */,
+				FDC202E60E107B1200ABAC90 /* Foundation.framework in Frameworks */,
+				FAE0E96E1BAF96B10098DFA4 /* GameController.framework in Frameworks */,
+				F3F7590322AC5F71001D97F2 /* Metal.framework in Frameworks */,
 				FDC202E90E107B1200ABAC90 /* OpenGLES.framework in Frameworks */,
 				FDC202EA0E107B1200ABAC90 /* QuartzCore.framework in Frameworks */,
+				FDC202E70E107B1200ABAC90 /* UIKit.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -378,17 +417,18 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				FABA34DC1D8B5E8900915323 /* AVFoundation.framework in Frameworks */,
 				FD1B49A20E313273007AB34E /* libSDL2.a in Frameworks */,
-				FAE0E9701BAF96B80098DFA4 /* GameController.framework in Frameworks */,
+				FDC52EDA0E2843D6008D768C /* AudioToolbox.framework in Frameworks */,
+				FABA34DC1D8B5E8900915323 /* AVFoundation.framework in Frameworks */,
+				FDC52ED90E2843D6008D768C /* CoreAudio.framework in Frameworks */,
+				FDC52ED60E2843D6008D768C /* CoreGraphics.framework in Frameworks */,
 				FA8B4BA81967073400F8EB7C /* CoreMotion.framework in Frameworks */,
 				FDC52ED40E2843D6008D768C /* Foundation.framework in Frameworks */,
-				FDC52ED50E2843D6008D768C /* UIKit.framework in Frameworks */,
-				FDC52ED60E2843D6008D768C /* CoreGraphics.framework in Frameworks */,
+				FAE0E9701BAF96B80098DFA4 /* GameController.framework in Frameworks */,
+				F3F7590522AC5FB3001D97F2 /* Metal.framework in Frameworks */,
 				FDC52ED70E2843D6008D768C /* OpenGLES.framework in Frameworks */,
 				FDC52ED80E2843D6008D768C /* QuartzCore.framework in Frameworks */,
-				FDC52ED90E2843D6008D768C /* CoreAudio.framework in Frameworks */,
-				FDC52EDA0E2843D6008D768C /* AudioToolbox.framework in Frameworks */,
+				FDC52ED50E2843D6008D768C /* UIKit.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -396,17 +436,18 @@
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				FABA34DB1D8B5E8500915323 /* AVFoundation.framework in Frameworks */,
 				FD1B49A00E313270007AB34E /* libSDL2.a in Frameworks */,
-				FAE0E96F1BAF96B50098DFA4 /* GameController.framework in Frameworks */,
+				FDF0D7230E12D31800247964 /* AudioToolbox.framework in Frameworks */,
+				FABA34DB1D8B5E8500915323 /* AVFoundation.framework in Frameworks */,
+				FDF0D71E0E12D2AB00247964 /* CoreAudio.framework in Frameworks */,
+				FDF0D69E0E12D05400247964 /* CoreGraphics.framework in Frameworks */,
 				FA8B4BA71967072800F8EB7C /* CoreMotion.framework in Frameworks */,
 				FDF0D69C0E12D05400247964 /* Foundation.framework in Frameworks */,
-				FDF0D69D0E12D05400247964 /* UIKit.framework in Frameworks */,
-				FDF0D69E0E12D05400247964 /* CoreGraphics.framework in Frameworks */,
+				FAE0E96F1BAF96B50098DFA4 /* GameController.framework in Frameworks */,
+				F3F7590422AC5F8D001D97F2 /* Metal.framework in Frameworks */,
 				FDF0D69F0E12D05400247964 /* OpenGLES.framework in Frameworks */,
 				FDF0D6A00E12D05400247964 /* QuartzCore.framework in Frameworks */,
-				FDF0D71E0E12D2AB00247964 /* CoreAudio.framework in Frameworks */,
-				FDF0D7230E12D31800247964 /* AudioToolbox.framework in Frameworks */,
+				FDF0D69D0E12D05400247964 /* UIKit.framework in Frameworks */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -455,6 +496,7 @@
 		29B97323FDCFA39411CA2CEA /* Frameworks */ = {
 			isa = PBXGroup;
 			children = (
+				F3F758FF22AC5EC7001D97F2 /* Metal.framework */,
 				FABA34D71D8B5E7700915323 /* AVFoundation.framework */,
 				FABA34D31D8B5E5600915323 /* AVFoundation.framework */,
 				FAE0E9691BAF96A00098DFA4 /* GameController.framework */,
@@ -474,7 +516,11 @@
 			isa = PBXGroup;
 			children = (
 				FD1B489E0E313154007AB34E /* libSDL2.a */,
+				F3F758F822AC5E8F001D97F2 /* libSDL2.dylib */,
 				FA30DEAC1BBF59D9009C397F /* libSDL2.a */,
+				F3F758FA22AC5E8F001D97F2 /* libSDL2.dylib */,
+				F3F758FC22AC5E8F001D97F2 /* libSDLmain.a */,
+				F3F758FE22AC5E8F001D97F2 /* libSDLmain.a */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -725,6 +771,34 @@
 /* End PBXProject section */
 
 /* Begin PBXReferenceProxy section */
+		F3F758F822AC5E8F001D97F2 /* libSDL2.dylib */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libSDL2.dylib;
+			remoteRef = F3F758F722AC5E8F001D97F2 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		F3F758FA22AC5E8F001D97F2 /* libSDL2.dylib */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libSDL2.dylib;
+			remoteRef = F3F758F922AC5E8F001D97F2 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		F3F758FC22AC5E8F001D97F2 /* libSDLmain.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libSDLmain.a;
+			remoteRef = F3F758FB22AC5E8F001D97F2 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
+		F3F758FE22AC5E8F001D97F2 /* libSDLmain.a */ = {
+			isa = PBXReferenceProxy;
+			fileType = archive.ar;
+			path = libSDLmain.a;
+			remoteRef = F3F758FD22AC5E8F001D97F2 /* PBXContainerItemProxy */;
+			sourceTree = BUILT_PRODUCTS_DIR;
+		};
 		FA30DEAC1BBF59D9009C397F /* libSDL2.a */ = {
 			isa = PBXReferenceProxy;
 			fileType = archive.ar;
@@ -957,6 +1031,7 @@
 		1D6058940D05DD3E006BFB54 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				DEVELOPMENT_TEAM = "";
 				INFOPLIST_FILE = Info.plist;
 				PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.Rectangles;
 				PRODUCT_NAME = Rectangles;
@@ -966,6 +1041,7 @@
 		1D6058950D05DD3E006BFB54 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				DEVELOPMENT_TEAM = "";
 				INFOPLIST_FILE = Info.plist;
 				PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.Rectangles;
 				PRODUCT_NAME = Rectangles;
@@ -1089,6 +1165,7 @@
 		FD15FCB50E086866003BDF25 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				DEVELOPMENT_TEAM = "";
 				GCC_DYNAMIC_NO_PIC = NO;
 				INFOPLIST_FILE = Info.plist;
 				PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.Happy;
@@ -1100,6 +1177,7 @@
 		FD15FCB60E086866003BDF25 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				DEVELOPMENT_TEAM = "";
 				INFOPLIST_FILE = Info.plist;
 				PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.Happy;
 				PRODUCT_NAME = Happy;
@@ -1110,6 +1188,7 @@
 		FD5F9BE70E0DEBEB008E885B /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				DEVELOPMENT_TEAM = "";
 				INFOPLIST_FILE = Info.plist;
 				PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.Accel;
 				PRODUCT_NAME = Accel;
@@ -1120,6 +1199,7 @@
 		FD5F9BE80E0DEBEB008E885B /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				DEVELOPMENT_TEAM = "";
 				INFOPLIST_FILE = Info.plist;
 				PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.Accel;
 				PRODUCT_NAME = Accel;
@@ -1130,6 +1210,7 @@
 		FDB6520A0E43D1F300F688B5 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				DEVELOPMENT_TEAM = "";
 				INFOPLIST_FILE = Info.plist;
 				PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.Keyboard;
 				PRODUCT_NAME = Keyboard;
@@ -1140,6 +1221,7 @@
 		FDB6520B0E43D1F300F688B5 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				DEVELOPMENT_TEAM = "";
 				INFOPLIST_FILE = Info.plist;
 				PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.Keyboard;
 				PRODUCT_NAME = Keyboard;
@@ -1150,6 +1232,7 @@
 		FDC202EC0E107B1200ABAC90 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				DEVELOPMENT_TEAM = "";
 				INFOPLIST_FILE = Info.plist;
 				PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.Touch;
 				PRODUCT_NAME = Touch;
@@ -1160,6 +1243,7 @@
 		FDC202ED0E107B1200ABAC90 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				DEVELOPMENT_TEAM = "";
 				INFOPLIST_FILE = Info.plist;
 				PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.Touch;
 				PRODUCT_NAME = Touch;
@@ -1194,6 +1278,7 @@
 		FDF0D6A20E12D05400247964 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				DEVELOPMENT_TEAM = "";
 				INFOPLIST_FILE = Info.plist;
 				PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.Mixer;
 				PRODUCT_NAME = Mixer;
@@ -1204,6 +1289,7 @@
 		FDF0D6A30E12D05400247964 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				DEVELOPMENT_TEAM = "";
 				INFOPLIST_FILE = Info.plist;
 				PRODUCT_BUNDLE_IDENTIFIER = com.yourcompany.Mixer;
 				PRODUCT_NAME = Mixer;

+ 8 - 12
sdl.mod/SDL/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj

@@ -468,9 +468,6 @@
 		F3BDD79B20F51CB8004ECBF3 /* SDL_hidapijoystick_c.h in Headers */ = {isa = PBXBuildFile; fileRef = F3BDD79020F51CB8004ECBF3 /* SDL_hidapijoystick_c.h */; };
 		F3BDD79C20F51CB8004ECBF3 /* SDL_hidapijoystick.c in Sources */ = {isa = PBXBuildFile; fileRef = F3BDD79120F51CB8004ECBF3 /* SDL_hidapijoystick.c */; };
 		F3BDD79D20F51CB8004ECBF3 /* SDL_hidapijoystick.c in Sources */ = {isa = PBXBuildFile; fileRef = F3BDD79120F51CB8004ECBF3 /* SDL_hidapijoystick.c */; };
-		F3E3C55D223DEC6C007D243C /* SDL_hidapi_gamecube.c in Sources */ = {isa = PBXBuildFile; fileRef = F3E3C55C223DEC6C007D243C /* SDL_hidapi_gamecube.c */; };
-		F3E3C55E223DEC6C007D243C /* SDL_hidapi_gamecube.c in Sources */ = {isa = PBXBuildFile; fileRef = F3E3C55C223DEC6C007D243C /* SDL_hidapi_gamecube.c */; };
-		F3E3C55F224065AE007D243C /* SDL_hidapi_gamecube.c in Sources */ = {isa = PBXBuildFile; fileRef = F3E3C55C223DEC6C007D243C /* SDL_hidapi_gamecube.c */; };
 		F3E3C658224069CE007D243C /* SDL_uikit_main.c in Sources */ = {isa = PBXBuildFile; fileRef = F3E3C657224069CE007D243C /* SDL_uikit_main.c */; };
 		F3E3C65B2241389A007D243C /* SDL_blit.h in Headers */ = {isa = PBXBuildFile; fileRef = FDA683010DF2374E00F98A1A /* SDL_blit.h */; };
 		F3E3C65C2241389A007D243C /* SDL_uikitmetalview.h in Headers */ = {isa = PBXBuildFile; fileRef = 4D7517191EE1D32200820EEA /* SDL_uikitmetalview.h */; };
@@ -657,7 +654,6 @@
 		F3E3C7122241389A007D243C /* SDL_uikitevents.m in Sources */ = {isa = PBXBuildFile; fileRef = FD689F0D0E26E5D900F90B21 /* SDL_uikitevents.m */; };
 		F3E3C7132241389A007D243C /* yuv_rgb.c in Sources */ = {isa = PBXBuildFile; fileRef = AA13B3561FB8B46300D9FEE6 /* yuv_rgb.c */; };
 		F3E3C7142241389A007D243C /* SDL_uikitopengles.m in Sources */ = {isa = PBXBuildFile; fileRef = FD689F0F0E26E5D900F90B21 /* SDL_uikitopengles.m */; };
-		F3E3C7152241389A007D243C /* SDL_hidapi_gamecube.c in Sources */ = {isa = PBXBuildFile; fileRef = F3E3C55C223DEC6C007D243C /* SDL_hidapi_gamecube.c */; };
 		F3E3C7162241389A007D243C /* SDL_uikitvideo.m in Sources */ = {isa = PBXBuildFile; fileRef = FD689F110E26E5D900F90B21 /* SDL_uikitvideo.m */; };
 		F3E3C7172241389A007D243C /* SDL_uikitview.m in Sources */ = {isa = PBXBuildFile; fileRef = FD689F130E26E5D900F90B21 /* SDL_uikitview.m */; };
 		F3E3C7182241389A007D243C /* SDL_displayevents.c in Sources */ = {isa = PBXBuildFile; fileRef = A7C19D28212E552B00DF2152 /* SDL_displayevents.c */; };
@@ -721,6 +717,7 @@
 		F3E3C75B224138AE007D243C /* SDL_uikit_main.c in Sources */ = {isa = PBXBuildFile; fileRef = F3E3C657224069CE007D243C /* SDL_uikit_main.c */; };
 		FA1DC2721C62BE65008F99A0 /* SDL_uikitclipboard.h in Headers */ = {isa = PBXBuildFile; fileRef = FA1DC2701C62BE65008F99A0 /* SDL_uikitclipboard.h */; };
 		FA1DC2731C62BE65008F99A0 /* SDL_uikitclipboard.m in Sources */ = {isa = PBXBuildFile; fileRef = FA1DC2711C62BE65008F99A0 /* SDL_uikitclipboard.m */; };
+		FA24348D21D4201400B8918A /* SDL_metal.h in Headers */ = {isa = PBXBuildFile; fileRef = FA24348C21D4201400B8918A /* SDL_metal.h */; };
 		FAB5981D1BB5C31500BE72C5 /* SDL_atomic.c in Sources */ = {isa = PBXBuildFile; fileRef = 04FFAB8912E23B8D00BA343D /* SDL_atomic.c */; };
 		FAB5981E1BB5C31500BE72C5 /* SDL_spinlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 04FFAB8A12E23B8D00BA343D /* SDL_spinlock.c */; };
 		FAB5981F1BB5C31500BE72C5 /* SDL_coreaudio.m in Sources */ = {isa = PBXBuildFile; fileRef = 56EA86F913E9EC2B002E47EB /* SDL_coreaudio.m */; };
@@ -1062,13 +1059,14 @@
 		F3BDD78E20F51CB8004ECBF3 /* SDL_hidapi_ps4.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_ps4.c; sourceTree = "<group>"; };
 		F3BDD79020F51CB8004ECBF3 /* SDL_hidapijoystick_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_hidapijoystick_c.h; sourceTree = "<group>"; };
 		F3BDD79120F51CB8004ECBF3 /* SDL_hidapijoystick.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapijoystick.c; sourceTree = "<group>"; };
-		F3E3C55C223DEC6C007D243C /* SDL_hidapi_gamecube.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_gamecube.c; sourceTree = "<group>"; };
 		F3E3C65222406928007D243C /* libSDLmain.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSDLmain.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		F3E3C657224069CE007D243C /* SDL_uikit_main.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_uikit_main.c; sourceTree = "<group>"; };
 		F3E3C7572241389A007D243C /* libSDL2.dylib */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSDL2.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
 		F3E3C75F224138AE007D243C /* libSDLmain.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSDLmain.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		FA1DC2701C62BE65008F99A0 /* SDL_uikitclipboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_uikitclipboard.h; sourceTree = "<group>"; };
 		FA1DC2711C62BE65008F99A0 /* SDL_uikitclipboard.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_uikitclipboard.m; sourceTree = "<group>"; };
+		FA20874D2307894C0029758C /* SDL_shaders_metal_tvos.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDL_shaders_metal_tvos.h; sourceTree = "<group>"; };
+		FA24348C21D4201400B8918A /* SDL_metal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_metal.h; sourceTree = "<group>"; };
 		FAB598141BB5C1B100BE72C5 /* libSDL2.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSDL2.a; sourceTree = BUILT_PRODUCTS_DIR; };
 		FAD4F7011BA3C4E8008346CE /* SDL_sysjoystick_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_sysjoystick_c.h; sourceTree = "<group>"; };
 		FD0BBFEF0E3933DD00D833B1 /* SDL_uikitview.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_uikitview.h; sourceTree = "<group>"; };
@@ -1410,6 +1408,7 @@
 			children = (
 				AADC5A621FDA10C800960936 /* SDL_render_metal.m */,
 				AADC5A611FDA10C800960936 /* SDL_shaders_metal_ios.h */,
+				FA20874D2307894C0029758C /* SDL_shaders_metal_tvos.h */,
 			);
 			path = metal;
 			sourceTree = "<group>";
@@ -1463,7 +1462,6 @@
 		F3BDD78A20F51C8D004ECBF3 /* hidapi */ = {
 			isa = PBXGroup;
 			children = (
-				F3E3C55C223DEC6C007D243C /* SDL_hidapi_gamecube.c */,
 				F3BDD78E20F51CB8004ECBF3 /* SDL_hidapi_ps4.c */,
 				F3BDD78C20F51CB8004ECBF3 /* SDL_hidapi_switch.c */,
 				F3BDD78B20F51CB8004ECBF3 /* SDL_hidapi_xbox360.c */,
@@ -1582,15 +1580,14 @@
 			children = (
 				AA7558651595D55500BBD41B /* begin_code.h */,
 				AA7558661595D55500BBD41B /* close_code.h */,
-				AA7558971595D55500BBD41B /* SDL.h */,
 				AA7558671595D55500BBD41B /* SDL_assert.h */,
 				AA7558681595D55500BBD41B /* SDL_atomic.h */,
 				AA7558691595D55500BBD41B /* SDL_audio.h */,
 				AADA5B8E16CCAB7C00107CF7 /* SDL_bits.h */,
 				AA75586A1595D55500BBD41B /* SDL_blendmode.h */,
 				AA75586B1595D55500BBD41B /* SDL_clipboard.h */,
-				AA75586D1595D55500BBD41B /* SDL_config.h */,
 				AA75586C1595D55500BBD41B /* SDL_config_iphoneos.h */,
+				AA75586D1595D55500BBD41B /* SDL_config.h */,
 				AA75586E1595D55500BBD41B /* SDL_copying.h */,
 				AA75586F1595D55500BBD41B /* SDL_cpuinfo.h */,
 				AA7558701595D55500BBD41B /* SDL_endian.h */,
@@ -1608,6 +1605,7 @@
 				AA75587B1595D55500BBD41B /* SDL_log.h */,
 				AA75587C1595D55500BBD41B /* SDL_main.h */,
 				AA9FF9501637C6E5000DF050 /* SDL_messagebox.h */,
+				FA24348C21D4201400B8918A /* SDL_metal.h */,
 				AA75587D1595D55500BBD41B /* SDL_mouse.h */,
 				AA75587E1595D55500BBD41B /* SDL_mutex.h */,
 				AA75587F1595D55500BBD41B /* SDL_name.h */,
@@ -1636,6 +1634,7 @@
 				AA7558951595D55500BBD41B /* SDL_version.h */,
 				AA7558961595D55500BBD41B /* SDL_video.h */,
 				4D7516FE1EE1C5B400820EEA /* SDL_vulkan.h */,
+				AA7558971595D55500BBD41B /* SDL.h */,
 			);
 			name = "Public Headers";
 			path = ../../include;
@@ -2189,6 +2188,7 @@
 				AA75589D1595D55500BBD41B /* SDL_blendmode.h in Headers */,
 				F30D9C9E212CD0990047DF2E /* SDL_sensor_c.h in Headers */,
 				AA75589E1595D55500BBD41B /* SDL_clipboard.h in Headers */,
+				FA24348D21D4201400B8918A /* SDL_metal.h in Headers */,
 				AA75589F1595D55500BBD41B /* SDL_config_iphoneos.h in Headers */,
 				AA7558A01595D55500BBD41B /* SDL_config.h in Headers */,
 				AA7558A11595D55500BBD41B /* SDL_copying.h in Headers */,
@@ -2518,7 +2518,6 @@
 				52ED1E24222889500061FCE0 /* SDL_uikitevents.m in Sources */,
 				52ED1E25222889500061FCE0 /* yuv_rgb.c in Sources */,
 				52ED1E26222889500061FCE0 /* SDL_uikitopengles.m in Sources */,
-				F3E3C55F224065AE007D243C /* SDL_hidapi_gamecube.c in Sources */,
 				52ED1E27222889500061FCE0 /* SDL_uikitvideo.m in Sources */,
 				52ED1E28222889500061FCE0 /* SDL_uikitview.m in Sources */,
 				52ED1E29222889500061FCE0 /* SDL_displayevents.c in Sources */,
@@ -2647,7 +2646,6 @@
 				F3E3C7122241389A007D243C /* SDL_uikitevents.m in Sources */,
 				F3E3C7132241389A007D243C /* yuv_rgb.c in Sources */,
 				F3E3C7142241389A007D243C /* SDL_uikitopengles.m in Sources */,
-				F3E3C7152241389A007D243C /* SDL_hidapi_gamecube.c in Sources */,
 				F3E3C7162241389A007D243C /* SDL_uikitvideo.m in Sources */,
 				F3E3C7172241389A007D243C /* SDL_uikitview.m in Sources */,
 				F3E3C7182241389A007D243C /* SDL_displayevents.c in Sources */,
@@ -2824,7 +2822,6 @@
 				FAB598BD1BB5C31600BE72C5 /* SDL_hints.c in Sources */,
 				FAB598BE1BB5C31600BE72C5 /* SDL_log.c in Sources */,
 				FAB598BF1BB5C31600BE72C5 /* SDL.c in Sources */,
-				F3E3C55E223DEC6C007D243C /* SDL_hidapi_gamecube.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -2895,7 +2892,6 @@
 				FD689F1D0E26E5D900F90B21 /* SDL_uikitevents.m in Sources */,
 				AA13B35A1FB8B46400D9FEE6 /* yuv_rgb.c in Sources */,
 				FD689F1F0E26E5D900F90B21 /* SDL_uikitopengles.m in Sources */,
-				F3E3C55D223DEC6C007D243C /* SDL_hidapi_gamecube.c in Sources */,
 				FD689F210E26E5D900F90B21 /* SDL_uikitvideo.m in Sources */,
 				FD689F230E26E5D900F90B21 /* SDL_uikitview.m in Sources */,
 				A7C19D2A212E552C00DF2152 /* SDL_displayevents.c in Sources */,

+ 1 - 1
sdl.mod/SDL/Xcode-iOS/Test/Info.plist

@@ -11,7 +11,7 @@
 	<key>CFBundleIconFile</key>
 	<string></string>
 	<key>CFBundleIdentifier</key>
-	<string>com.yourcompany.${PRODUCT_NAME:identifier}</string>
+	<string>com.yourcompany.${PRODUCT_NAME}</string>
 	<key>CFBundleInfoDictionaryVersion</key>
 	<string>6.0</string>
 	<key>CFBundleName</key>

File diff suppressed because it is too large
+ 297 - 181
sdl.mod/SDL/Xcode-iOS/Test/TestiPhoneOS.xcodeproj/project.pbxproj


+ 2 - 2
sdl.mod/SDL/Xcode/SDL/Info-Framework.plist

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

+ 9 - 11
sdl.mod/SDL/Xcode/SDL/SDL.xcodeproj/project.pbxproj

@@ -919,9 +919,7 @@
 		F3950CD8212BC88D00F51292 /* SDL_sensor.h in Headers */ = {isa = PBXBuildFile; fileRef = F3950CD7212BC88D00F51292 /* SDL_sensor.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		F3950CD9212BC88D00F51292 /* SDL_sensor.h in Headers */ = {isa = PBXBuildFile; fileRef = F3950CD7212BC88D00F51292 /* SDL_sensor.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		F3950CDA212BC88D00F51292 /* SDL_sensor.h in Headers */ = {isa = PBXBuildFile; fileRef = F3950CD7212BC88D00F51292 /* SDL_sensor.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		F3E3C559223DEBC7007D243C /* SDL_hidapi_gamecube.c in Sources */ = {isa = PBXBuildFile; fileRef = F3E3C558223DEBC7007D243C /* SDL_hidapi_gamecube.c */; };
-		F3E3C55A223DEBC7007D243C /* SDL_hidapi_gamecube.c in Sources */ = {isa = PBXBuildFile; fileRef = F3E3C558223DEBC7007D243C /* SDL_hidapi_gamecube.c */; };
-		F3E3C55B223DEBC7007D243C /* SDL_hidapi_gamecube.c in Sources */ = {isa = PBXBuildFile; fileRef = F3E3C558223DEBC7007D243C /* SDL_hidapi_gamecube.c */; };
+		FA24348B21D41FFB00B8918A /* SDL_metal.h in Headers */ = {isa = PBXBuildFile; fileRef = FA24348A21D41FFB00B8918A /* SDL_metal.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		FA73671D19A540EF004122E4 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA73671C19A540EF004122E4 /* CoreVideo.framework */; };
 		FA73671E19A54140004122E4 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA73671C19A540EF004122E4 /* CoreVideo.framework */; };
 		FA73671F19A54144004122E4 /* CoreVideo.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA73671C19A540EF004122E4 /* CoreVideo.framework */; };
@@ -1252,12 +1250,13 @@
 		F30D9CCB212EB4810047DF2E /* SDL_displayevents_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_displayevents_c.h; sourceTree = "<group>"; };
 		F30D9CCC212EB4810047DF2E /* SDL_displayevents.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_displayevents.c; sourceTree = "<group>"; };
 		F3950CD7212BC88D00F51292 /* SDL_sensor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_sensor.h; sourceTree = "<group>"; };
-		F3E3C558223DEBC7007D243C /* SDL_hidapi_gamecube.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_hidapi_gamecube.c; sourceTree = "<group>"; };
 		F59C710300D5CB5801000001 /* ReadMe.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = ReadMe.txt; sourceTree = "<group>"; };
 		F59C710600D5CB5801000001 /* SDL.info */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; path = SDL.info; sourceTree = "<group>"; };
 		F5A2EF3900C6A39A01000001 /* BUGS.txt */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text; name = BUGS.txt; path = ../../BUGS.txt; sourceTree = SOURCE_ROOT; };
+		FA24348A21D41FFB00B8918A /* SDL_metal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_metal.h; sourceTree = "<group>"; };
 		FA73671C19A540EF004122E4 /* CoreVideo.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreVideo.framework; path = System/Library/Frameworks/CoreVideo.framework; sourceTree = SDKROOT; };
 		FABA34C61D8B5DB100915323 /* SDL_coreaudio.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_coreaudio.m; sourceTree = "<group>"; };
+		FAF136422308312A00F414DE /* SDL_shaders_metal.metal */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.metal; path = SDL_shaders_metal.metal; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -1346,6 +1345,7 @@
 				AA7557DD1595D4D800BBD41B /* SDL_log.h */,
 				AA7557DE1595D4D800BBD41B /* SDL_main.h */,
 				AA9FF9591637CBF9000DF050 /* SDL_messagebox.h */,
+				FA24348A21D41FFB00B8918A /* SDL_metal.h */,
 				AA7557DF1595D4D800BBD41B /* SDL_mouse.h */,
 				AA7557E01595D4D800BBD41B /* SDL_mutex.h */,
 				AA7557E11595D4D800BBD41B /* SDL_name.h */,
@@ -1932,7 +1932,6 @@
 		A704170C20F09AA600A82227 /* hidapi */ = {
 			isa = PBXGroup;
 			children = (
-				F3E3C558223DEBC7007D243C /* SDL_hidapi_gamecube.c */,
 				A704171120F09AC900A82227 /* SDL_hidapi_ps4.c */,
 				A704170F20F09AC800A82227 /* SDL_hidapi_switch.c */,
 				A704171320F09AC900A82227 /* SDL_hidapi_xbox360.c */,
@@ -1965,6 +1964,7 @@
 			children = (
 				AADC5A421FDA035D00960936 /* SDL_render_metal.m */,
 				AADC5A411FDA035D00960936 /* SDL_shaders_metal_osx.h */,
+				FAF136422308312A00F414DE /* SDL_shaders_metal.metal */,
 			);
 			path = metal;
 			sourceTree = "<group>";
@@ -2043,6 +2043,7 @@
 				AA75581E1595D4D800BBD41B /* SDL_joystick.h in Headers */,
 				AA7558201595D4D800BBD41B /* SDL_keyboard.h in Headers */,
 				F3950CD8212BC88D00F51292 /* SDL_sensor.h in Headers */,
+				FA24348B21D41FFB00B8918A /* SDL_metal.h in Headers */,
 				AA7558221595D4D800BBD41B /* SDL_keycode.h in Headers */,
 				F30D9C84212BC94F0047DF2E /* SDL_sensor_c.h in Headers */,
 				AA7558241595D4D800BBD41B /* SDL_loadso.h in Headers */,
@@ -2671,7 +2672,7 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
-			shellScript = "# Sign framework\nif [ \"$SDL_CODESIGN_IDENTITY\" != \"\" ]; then\n    codesign --force --deep --sign \"$SDL_CODESIGN_IDENTITY\" $TARGET_BUILD_DIR/SDL2.framework/Versions/A\nfi\n\n# clean up the framework, remove headers, extra files\nmkdir -p build/dmg-tmp\nxcrun CpMac -r $TARGET_BUILD_DIR/SDL2.framework build/dmg-tmp/\n\ncp pkg-support/resources/License.txt build/dmg-tmp\ncp pkg-support/resources/ReadMe.txt build/dmg-tmp\n\n# remove the .DS_Store files if any (we may want to provide one in the future for fancy .dmgs)\nfind build/dmg-tmp -name .DS_Store -exec rm -f \"{}\" \\;\n\n# for fancy .dmg\nmkdir -p build/dmg-tmp/.logo\ncp pkg-support/resources/SDL_DS_Store build/dmg-tmp/.DS_Store\ncp pkg-support/sdl_logo.pdf build/dmg-tmp/.logo\n\n# create the dmg\nhdiutil create -ov -fs HFS+ -volname SDL2 -srcfolder build/dmg-tmp build/SDL2.dmg\n\n# clean up\nrm -rf build/dmg-tmp";
+			shellScript = "# Sign framework\nif [ \"$SDL_CODESIGN_IDENTITY\" != \"\" ]; then\n    codesign --force --deep --sign \"$SDL_CODESIGN_IDENTITY\" $TARGET_BUILD_DIR/SDL2.framework/Versions/A || exit $?\nfi\n\n# clean up the framework, remove headers, extra files\nmkdir -p build/dmg-tmp\ncp -a $TARGET_BUILD_DIR/SDL2.framework build/dmg-tmp/\n\ncp pkg-support/resources/License.txt build/dmg-tmp\ncp pkg-support/resources/ReadMe.txt build/dmg-tmp\n\n# remove the .DS_Store files if any (we may want to provide one in the future for fancy .dmgs)\nfind build/dmg-tmp -name .DS_Store -exec rm -f \"{}\" \\;\n\n# for fancy .dmg\nmkdir -p build/dmg-tmp/.logo\ncp pkg-support/resources/SDL_DS_Store build/dmg-tmp/.DS_Store\ncp pkg-support/sdl_logo.pdf build/dmg-tmp/.logo\n\n# create the dmg\nhdiutil create -ov -fs HFS+ -volname SDL2 -srcfolder build/dmg-tmp build/SDL2.dmg\n\n# clean up\nrm -rf build/dmg-tmp\n";
 		};
 /* End PBXShellScriptBuildPhase section */
 
@@ -2707,7 +2708,6 @@
 				04BD005B12E6671800899322 /* SDL_syshaptic.c in Sources */,
 				04BD005F12E6671800899322 /* SDL_haptic.c in Sources */,
 				4D1664551EDD60AD003DE88E /* SDL_cocoavulkan.m in Sources */,
-				F3E3C559223DEBC7007D243C /* SDL_hidapi_gamecube.c in Sources */,
 				04BD006612E6671800899322 /* SDL_sysjoystick.c in Sources */,
 				04BD007012E6671800899322 /* SDL_joystick.c in Sources */,
 				04BD008812E6671800899322 /* SDL_sysloadso.c in Sources */,
@@ -2846,7 +2846,6 @@
 				04BD026D12E6671800899322 /* SDL_quit.c in Sources */,
 				04BD026F12E6671800899322 /* SDL_touch.c in Sources */,
 				04BD027112E6671800899322 /* SDL_windowevents.c in Sources */,
-				F3E3C55A223DEBC7007D243C /* SDL_hidapi_gamecube.c in Sources */,
 				04BD027412E6671800899322 /* SDL_rwopsbundlesupport.m in Sources */,
 				04BD027512E6671800899322 /* SDL_rwops.c in Sources */,
 				04BD027612E6671800899322 /* SDL_syshaptic.c in Sources */,
@@ -2985,7 +2984,6 @@
 				DB31401017554B71006C0E22 /* SDL_quit.c in Sources */,
 				DB31401117554B71006C0E22 /* SDL_touch.c in Sources */,
 				DB31401217554B71006C0E22 /* SDL_windowevents.c in Sources */,
-				F3E3C55B223DEBC7007D243C /* SDL_hidapi_gamecube.c in Sources */,
 				DB31401317554B71006C0E22 /* SDL_rwopsbundlesupport.m in Sources */,
 				DB31401417554B71006C0E22 /* SDL_rwops.c in Sources */,
 				DB31401517554B71006C0E22 /* SDL_syshaptic.c in Sources */,
@@ -3160,7 +3158,7 @@
 				CLANG_LINK_OBJC_RUNTIME = NO;
 				COMBINE_HIDPI_IMAGES = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1.0.0;
-				DYLIB_CURRENT_VERSION = 10.0.0;
+				DYLIB_CURRENT_VERSION = 12.0.0;
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(PROJECT_DIR)",
@@ -3259,7 +3257,7 @@
 				CLANG_LINK_OBJC_RUNTIME = NO;
 				COMBINE_HIDPI_IMAGES = YES;
 				DYLIB_COMPATIBILITY_VERSION = 1.0.0;
-				DYLIB_CURRENT_VERSION = 10.0.0;
+				DYLIB_CURRENT_VERSION = 12.0.0;
 				FRAMEWORK_SEARCH_PATHS = (
 					"$(inherited)",
 					"$(PROJECT_DIR)",

+ 8 - 0
sdl.mod/SDL/android-project/app/build.gradle

@@ -22,6 +22,11 @@ android {
                 arguments "APP_PLATFORM=android-16"
                 abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
             }
+            // cmake {
+            //     arguments "-DANDROID_APP_PLATFORM=android-16", "-DANDROID_STL=c++_static"
+            //     // abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
+            //     abiFilters 'arm64-v8a'
+            // }
         }
     }
     buildTypes {
@@ -38,6 +43,9 @@ android {
             ndkBuild {
                 path 'jni/Android.mk'
             }
+            // cmake {
+            //     path 'jni/CMakeLists.txt'
+            // }
         }
        
     }

+ 20 - 0
sdl.mod/SDL/android-project/app/jni/CMakeLists.txt

@@ -0,0 +1,20 @@
+cmake_minimum_required(VERSION 3.6)
+
+project(GAME)
+
+# armeabi-v7a requires cpufeatures library
+# include(AndroidNdkModules)
+# android_ndk_import_module_cpufeatures()
+
+
+# SDL sources are in a subfolder named "SDL"
+add_subdirectory(SDL)
+
+# Compilation of companion libraries
+#add_subdirectory(SDL_image)
+#add_subdirectory(SDL_mixer)
+#add_subdirectory(SDL_ttf)
+
+# Your game and its CMakeLists.txt are in a subfolder named "src"
+add_subdirectory(src)
+

+ 13 - 0
sdl.mod/SDL/android-project/app/jni/src/CMakeLists.txt

@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 3.6)
+
+project(MY_APP)
+
+find_library(SDL2 SDL2)
+
+add_library(main SHARED)
+
+target_sources(main PRIVATE YourSourceHere.c)
+
+target_link_libraries(main SDL2)
+
+

+ 70 - 8
sdl.mod/SDL/android-project/app/src/main/java/org/libsdl/app/SDLActivity.java

@@ -846,6 +846,45 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
         }
     }
 
+    /**
+     * This method is called by SDL using JNI.
+     */
+    public static void minimizeWindow() {
+
+        if (mSingleton == null) {
+            return;
+        }
+
+        Intent startMain = new Intent(Intent.ACTION_MAIN);
+        startMain.addCategory(Intent.CATEGORY_HOME);
+        startMain.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        mSingleton.startActivity(startMain);
+    }
+
+    /**
+     * This method is called by SDL using JNI.
+     */
+    public static boolean shouldMinimizeOnFocusLoss() {
+/*
+        if (Build.VERSION.SDK_INT >= 24) {
+            if (mSingleton == null) {
+                return true;
+            }
+
+            if (mSingleton.isInMultiWindowMode()) {
+                return false;
+            }
+
+            if (mSingleton.isInPictureInPictureMode()) {
+                return false;
+            }
+        }
+
+        return true;
+*/
+        return false;
+    }
+
     /**
      * This method is called by SDL using JNI.
      */
@@ -1700,6 +1739,8 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
         SDLActivity.nativeSetScreenResolution(width, height, nDeviceWidth, nDeviceHeight, sdlFormat, mDisplay.getRefreshRate());
         SDLActivity.onNativeResize();
 
+        // Prevent a screen distortion glitch,
+        // for instance when the device is in Landscape and a Portrait App is resumed.
         boolean skip = false;
         int requestedOrientation = SDLActivity.mSingleton.getRequestedOrientation();
 
@@ -1729,6 +1770,16 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
            }
         }
 
+        // Don't skip in MultiWindow.
+        if (skip) {
+            if (Build.VERSION.SDK_INT >= 24) {
+                if (SDLActivity.mSingleton.isInMultiWindowMode()) {
+                    Log.v("SDL", "Don't skip in Multi-Window");
+                    skip = false;
+                }
+            }
+        }
+
         if (skip) {
            Log.v("SDL", "Skip .. Surface is not ready.");
            mIsSurfaceReady = false;
@@ -1748,6 +1799,10 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
     // Key events
     @Override
     public boolean onKey(View  v, int keyCode, KeyEvent event) {
+
+        int deviceId = event.getDeviceId();
+        int source = event.getSource();
+
         // Dispatch the different events depending on where they come from
         // Some SOURCE_JOYSTICK, SOURCE_DPAD or SOURCE_GAMEPAD are also SOURCE_KEYBOARD
         // So, we try to process them as JOYSTICK/DPAD/GAMEPAD events first, if that fails we try them as KEYBOARD
@@ -1755,20 +1810,27 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
         // Furthermore, it's possible a game controller has SOURCE_KEYBOARD and
         // SOURCE_JOYSTICK, while its key events arrive from the keyboard source
         // So, retrieve the device itself and check all of its sources
-        if (SDLControllerManager.isDeviceSDLJoystick(event.getDeviceId())) {
+        if (SDLControllerManager.isDeviceSDLJoystick(deviceId)) {
             // Note that we process events with specific key codes here
             if (event.getAction() == KeyEvent.ACTION_DOWN) {
-                if (SDLControllerManager.onNativePadDown(event.getDeviceId(), keyCode) == 0) {
+                if (SDLControllerManager.onNativePadDown(deviceId, keyCode) == 0) {
                     return true;
                 }
             } else if (event.getAction() == KeyEvent.ACTION_UP) {
-                if (SDLControllerManager.onNativePadUp(event.getDeviceId(), keyCode) == 0) {
+                if (SDLControllerManager.onNativePadUp(deviceId, keyCode) == 0) {
                     return true;
                 }
             }
         }
 
-        if ((event.getSource() & InputDevice.SOURCE_KEYBOARD) != 0) {
+        if (source == InputDevice.SOURCE_UNKNOWN) {
+            InputDevice device = InputDevice.getDevice(deviceId);
+            if (device != null) {
+                source = device.getSources();
+            }
+        }
+
+        if ((source & InputDevice.SOURCE_KEYBOARD) != 0) {
             if (event.getAction() == KeyEvent.ACTION_DOWN) {
                 //Log.v("SDL", "key down: " + keyCode);
                 if (SDLActivity.isTextInputEvent(event)) {
@@ -1784,7 +1846,7 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
             }
         }
 
-        if ((event.getSource() & InputDevice.SOURCE_MOUSE) != 0) {
+        if ((source & InputDevice.SOURCE_MOUSE) != 0) {
             // on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses
             // they are ignored here because sending them as mouse input to SDL is messy
             if ((keyCode == KeyEvent.KEYCODE_BACK) || (keyCode == KeyEvent.KEYCODE_FORWARD)) {
@@ -1932,8 +1994,8 @@ class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
                     newOrientation = SDLActivity.SDL_ORIENTATION_LANDSCAPE_FLIPPED;
                     break;
                 case Surface.ROTATION_180:
-                    x = -event.values[1];
-                    y = -event.values[0];
+                    x = -event.values[0];
+                    y = -event.values[1];
                     newOrientation = SDLActivity.SDL_ORIENTATION_PORTRAIT_FLIPPED;
                     break;
                 default:
@@ -2058,7 +2120,7 @@ class DummyEdit extends View implements View.OnKeyListener {
     public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
         ic = new SDLInputConnection(this, true);
 
-        outAttrs.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD;
+        outAttrs.inputType = InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
         outAttrs.imeOptions = EditorInfo.IME_FLAG_NO_EXTRACT_UI
                 | EditorInfo.IME_FLAG_NO_FULLSCREEN /* API 11 */;
 

+ 1 - 1
sdl.mod/SDL/build-scripts/winrtbuild.ps1

@@ -39,7 +39,7 @@
 #
 
 # Base version of SDL, used for packaging purposes
-$SDLVersion = "2.0.9"
+$SDLVersion = "2.0.11"
 
 # Gets the .bat file that sets up an MSBuild environment, given one of
 # Visual Studio's, "PlatformToolset"s.

+ 38 - 0
sdl.mod/SDL/cmake/sdlchecks.cmake

@@ -1065,6 +1065,44 @@ macro(CheckUSBHID)
   endif()
 endmacro()
 
+# Check for HIDAPI joystick drivers. This is currently a Unix thing, not Windows or macOS!
+macro(CheckHIDAPI)
+  if(HIDAPI)
+    if(HIDAPI_SKIP_LIBUSB)
+      set(HAVE_HIDAPI TRUE)
+    else()
+      set(HAVE_HIDAPI FALSE)
+      pkg_check_modules(LIBUSB libusb)
+      if (LIBUSB_FOUND)
+        check_include_file(libusb.h HAVE_LIBUSB_H ${LIBUSB_CFLAGS})
+        if (HAVE_LIBUSB_H)
+          set(HAVE_HIDAPI TRUE)
+        endif()
+      endif()
+    endif()
+
+    if(HAVE_HIDAPI)
+      set(SDL_JOYSTICK_HIDAPI 1)
+      set(HAVE_SDL_JOYSTICK TRUE)
+      file(GLOB HIDAPI_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/hidapi/*.c)
+      set(SOURCE_FILES ${SOURCE_FILES} ${HIDAPI_SOURCES})
+      set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${LIBUSB_CFLAGS} -I${SDL2_SOURCE_DIR}/src/hidapi/hidapi")
+      if(NOT HIDAPI_SKIP_LIBUSB)
+        if(HIDAPI_ONLY_LIBUSB)
+          set(SOURCE_FILES ${SOURCE_FILES} ${SDL2_SOURCE_DIR}/src/hidapi/libusb/hid.c)
+          list(APPEND EXTRA_LIBS ${LIBUSB_LIBS})
+        else()
+          set(SOURCE_FILES ${SOURCE_FILES} ${SDL2_SOURCE_DIR}/src/hidapi/SDL_hidapi.c)
+          # libusb is loaded dynamically, so don't add it to EXTRA_LIBS
+          FindLibraryAndSONAME("usb-1.0")
+          set(SDL_LIBUSB_DYNAMIC "\"${USB_LIB_SONAME}\"")
+        endif()
+      endif()
+    endif()
+  endif()
+endmacro()
+
+
 # Requires:
 # - n/a
 macro(CheckRPI)

+ 271 - 55
sdl.mod/SDL/configure

@@ -852,6 +852,8 @@ enable_diskaudio
 enable_dummyaudio
 enable_libsamplerate
 enable_libsamplerate_shared
+enable_arm_simd
+enable_arm_neon
 enable_video_wayland
 enable_video_wayland_qt_touch
 enable_wayland_shared
@@ -869,6 +871,7 @@ enable_video_x11_xshape
 enable_video_x11_vm
 enable_video_vivante
 enable_video_cocoa
+enable_video_metal
 enable_render_metal
 enable_video_directfb
 enable_directfb_shared
@@ -1621,12 +1624,14 @@ Optional Features:
                           [[default=yes]]
   --enable-libsamplerate-shared
                           dynamically load libsamplerate [[default=yes]]
+  --enable-arm-simd       use SIMD assembly blitters on ARM [[default=yes]]
+  --enable-arm-neon       use NEON assembly blitters on ARM [[default=yes]]
   --enable-video-wayland  use Wayland video driver [[default=yes]]
   --enable-video-wayland-qt-touch
                           QtWayland server support for Wayland video driver
                           [[default=yes]]
   --enable-wayland-shared dynamically load Wayland support [[default=maybe]]
-  --enable-video-rpi      use Raspberry Pi video driver [[default=no]]
+  --enable-video-rpi      use Raspberry Pi video driver [[default=yes]]
   --enable-video-x11      use X11 video driver [[default=yes]]
   --enable-x11-shared     dynamically load X11 support [[default=maybe]]
   --enable-video-x11-xcursor
@@ -1647,6 +1652,7 @@ Optional Features:
   --enable-video-x11-vm   use X11 VM extension for fullscreen [[default=yes]]
   --enable-video-vivante  use Vivante EGL video driver [[default=yes]]
   --enable-video-cocoa    use Cocoa video driver [[default=yes]]
+  --enable-video-metal    include Metal support [[default=yes]]
   --enable-render-metal   enable the Metal render driver [[default=yes]]
   --enable-video-directfb use DirectFB video driver [[default=no]]
   --enable-directfb-shared
@@ -2811,9 +2817,9 @@ orig_CFLAGS="$CFLAGS"
 #
 SDL_MAJOR_VERSION=2
 SDL_MINOR_VERSION=0
-SDL_MICRO_VERSION=9
+SDL_MICRO_VERSION=11
 SDL_INTERFACE_AGE=0
-SDL_BINARY_AGE=9
+SDL_BINARY_AGE=11
 SDL_VERSION=$SDL_MAJOR_VERSION.$SDL_MINOR_VERSION.$SDL_MICRO_VERSION
 
 
@@ -19356,6 +19362,106 @@ _ACEOF
     fi
 }
 
+CheckARM()
+{
+    # Check whether --enable-arm-simd was given.
+if test "${enable_arm_simd+set}" = set; then :
+  enableval=$enable_arm_simd; enable_arm_simd=$enableval
+else
+  enable_arm_simd=yes
+fi
+
+    if test x$enable_video = xyes -a x$enable_assembly = xyes -a x$enable_arm_simd = xyes; then
+        save_CFLAGS="$CFLAGS"
+        have_arm_simd=no
+        CFLAGS="-x assembler-with-cpp $CFLAGS"
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ARM SIMD" >&5
+$as_echo_n "checking for ARM SIMD... " >&6; }
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+        .text
+        .arch armv6
+        .object_arch armv4
+        .arm
+        .altmacro
+        #ifndef __ARM_EABI__
+        #error EABI is required (to be sure that calling conventions are compatible)
+        #endif
+        pld [r0]
+        uqadd8 r0, r0, r0
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  have_arm_simd=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_arm_simd" >&5
+$as_echo "$have_arm_simd" >&6; }
+
+        CFLAGS="$save_CFLAGS"
+
+        if test x$have_arm_simd = xyes; then
+            $as_echo "#define SDL_ARM_SIMD_BLITTERS 1" >>confdefs.h
+
+            SOURCES="$SOURCES $srcdir/src/video/arm/pixman-arm-simd*.S"
+            WARN_ABOUT_ARM_SIMD_ASM_MIT="yes"
+        fi
+    fi
+}
+
+CheckNEON()
+{
+    # Check whether --enable-arm-neon was given.
+if test "${enable_arm_neon+set}" = set; then :
+  enableval=$enable_arm_neon; enable_arm_neon=$enableval
+else
+  enable_arm_neon=yes
+fi
+
+    if test x$enable_video = xyes -a x$enable_assembly = xyes -a x$enable_arm_neon = xyes; then
+        save_CFLAGS="$CFLAGS"
+        have_arm_neon=no
+        CFLAGS="-x assembler-with-cpp $CFLAGS"
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ARM NEON" >&5
+$as_echo_n "checking for ARM NEON... " >&6; }
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+        .text
+        .fpu neon
+        .arch armv7a
+        .object_arch armv4
+        .eabi_attribute 10, 0
+        .arm
+        .altmacro
+        #ifndef __ARM_EABI__
+        #error EABI is required (to be sure that calling conventions are compatible)
+        #endif
+        pld [r0]
+        vmovn.u16 d0, q0
+
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  have_arm_neon=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_arm_neon" >&5
+$as_echo "$have_arm_neon" >&6; }
+
+        CFLAGS="$save_CFLAGS"
+
+        if test x$have_arm_neon = xyes; then
+            $as_echo "#define SDL_ARM_NEON_BLITTERS 1" >>confdefs.h
+
+            SOURCES="$SOURCES $srcdir/src/video/arm/pixman-arm-neon*.S"
+            WARN_ABOUT_ARM_NEON_ASM_MIT="yes"
+        fi
+    fi
+}
+
 CheckVisibilityHidden()
 {
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GCC -fvisibility=hidden option" >&5
@@ -19396,6 +19502,43 @@ $as_echo "$have_gcc_fvisibility" >&6; }
     fi
 }
 
+CheckNoStrictAliasing()
+{
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GCC -fno-strict-aliasing option" >&5
+$as_echo_n "checking for GCC -fno-strict-aliasing option... " >&6; }
+    have_gcc_no_strict_aliasing=no
+
+    save_CFLAGS="$CFLAGS"
+    CFLAGS="$save_CFLAGS -fno-strict-aliasing"
+    cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+    int x = 0;
+
+int
+main ()
+{
+
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+    have_gcc_no_strict_aliasing=yes
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $have_gcc_no_strict_aliasing" >&5
+$as_echo "$have_gcc_no_strict_aliasing" >&6; }
+    CFLAGS="$save_CFLAGS"
+
+    if test x$have_gcc_no_strict_aliasing = xyes; then
+        EXTRA_CFLAGS="$EXTRA_CFLAGS -fno-strict-aliasing"
+    fi
+}
+
 CheckStackBoundary()
 {
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GCC -mpreferred-stack-boundary option" >&5
@@ -19697,7 +19840,7 @@ CheckRPI()
 if test "${enable_video_rpi+set}" = set; then :
   enableval=$enable_video_rpi;
 else
-  enable_video_rpi=no
+  enable_video_rpi=yes
 fi
 
     if test x$enable_video = xyes -a x$enable_video_rpi = xyes; then
@@ -19847,10 +19990,10 @@ fi
                 # This isn't necessary for X11, but fixes GLX detection
                 if test "x$x_includes" = xNONE && \
                    test "x$x_libraries" = xNONE && \
-                   test -d /usr/X11R6/include && \
-                   test -d /usr/X11R6/lib; then
-                    x_includes="/usr/X11R6/include"
-                    x_libraries="/usr/X11R6/lib"
+                   test -d /opt/X11/include && \
+                   test -d /opt/X11/lib; then
+                    x_includes="/opt/X11/include"
+                    x_libraries="/opt/X11/lib"
                 fi
                 ;;
         esac
@@ -20548,15 +20691,16 @@ fi
 
             case "$host" in
                 *-*-darwin*)
-                    x11_lib='/usr/X11R6/lib/libX11.6.dylib'
-                    x11ext_lib='/usr/X11R6/lib/libXext.6.dylib'
-                    xcursor_lib='/usr/X11R6/lib/libXcursor.1.dylib'
-                    xinerama_lib='/usr/X11R6/lib/libXinerama.1.dylib'
-                    xinput_lib='/usr/X11R6/lib/libXi.6.dylib'
-                    xrandr_lib='/usr/X11R6/lib/libXrandr.2.dylib'
-                    xrender_lib='/usr/X11R6/lib/libXrender.1.dylib'
-                    xss_lib='/usr/X11R6/lib/libXss.1.dylib'
-                    xvidmode_lib='/usr/X11R6/lib/libXxf86vm.1.dylib'
+                    # Apple now puts this in /opt/X11
+                    x11_lib='/opt/X11/lib/libX11.6.dylib'
+                    x11ext_lib='/opt/X11/lib/libXext.6.dylib'
+                    xcursor_lib='/opt/X11/lib/libXcursor.1.dylib'
+                    xinerama_lib='/opt/X11/lib/libXinerama.1.dylib'
+                    xinput_lib='/opt/X11/lib/libXi.6.dylib'
+                    xrandr_lib='/opt/X11/lib/libXrandr.2.dylib'
+                    xrender_lib='/opt/X11/lib/libXrender.1.dylib'
+                    xss_lib='/opt/X11/lib/libXss.1.dylib'
+                    xvidmode_lib='/opt/X11/lib/libXxf86vm.1.dylib'
                     ;;
                 *-*-openbsd*)
                     x11_lib='libX11.so'
@@ -21493,6 +21637,13 @@ $as_echo "#define SDL_VIDEO_DRIVER_COCOA 1" >>confdefs.h
 
 CheckMETAL()
 {
+    # Check whether --enable-video-metal was given.
+if test "${enable_video_metal+set}" = set; then :
+  enableval=$enable_video_metal;
+else
+  enable_video_metal=yes
+fi
+
     # Check whether --enable-render-metal was given.
 if test "${enable_render_metal+set}" = set; then :
   enableval=$enable_render_metal;
@@ -21500,7 +21651,7 @@ else
   enable_render_metal=yes
 fi
 
-    if test x$enable_render = xyes -a x$enable_render_metal = xyes; then
+    if test x$enable_video = xyes -a x$enable_video_metal = xyes; then
         save_CFLAGS="$CFLAGS"
                 CFLAGS="$CFLAGS -x objective-c"
         { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Metal framework" >&5
@@ -21537,11 +21688,17 @@ rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 $as_echo "$have_metal" >&6; }
         if test x$have_metal = xyes; then
 
+$as_echo "#define SDL_VIDEO_METAL 1" >>confdefs.h
+
+            if test x$enable_render = xyes -a x$enable_render_metal = xyes; then
+
 $as_echo "#define SDL_VIDEO_RENDER_METAL 1" >>confdefs.h
 
-            SOURCES="$SOURCES $srcdir/src/render/metal/*.m"
+                SOURCES="$SOURCES $srcdir/src/render/metal/*.m"
+            fi
             SUMMARY_video="${SUMMARY_video} metal"
         else
+            enable_video_metal=no
             enable_render_metal=no
         fi
     fi
@@ -22679,7 +22836,7 @@ fi
 
 $as_echo "#define SDL_USE_IME 1" >>confdefs.h
 
-            SOURCES="$SOURCES $srcdir/src/core/linux/SDL_ime.c"
+        SOURCES="$SOURCES $srcdir/src/core/linux/SDL_ime.c"
     fi
 }
 
@@ -23571,14 +23728,6 @@ fi
 
     fi
 
-    ac_fn_c_check_header_mongrel "$LINENO" "endpointvolume.h" "ac_cv_header_endpointvolume_h" "$ac_includes_default"
-if test "x$ac_cv_header_endpointvolume_h" = xyes; then :
-  $as_echo "#define HAVE_ENDPOINTVOLUME_H 1" >>confdefs.h
-
-fi
-
-
-
     # Check whether --enable-wasapi was given.
 if test "${enable_wasapi+set}" = set; then :
   enableval=$enable_wasapi;
@@ -24068,8 +24217,17 @@ CheckHIDAPI()
 {
     # The hidraw support doesn't catch Xbox, PS4 and Nintendo controllers,
     # so we'll just use libusb when it's available.
-    #
-    # Except that libusb requires root permissions to open devices, so that's not generally useful, and we'll disable this by default.
+    case "$host" in
+        # libusb does not support iOS
+        arm*-apple-darwin* | *-ios-* )
+            skiplibusb=yes
+            ;;
+        # On the other hand, *BSD specifically uses libusb only
+        *-*-*bsd* )
+            onlylibusb=yes
+            ;;
+    esac
+
     # Check whether --enable-hidapi was given.
 if test "${enable_hidapi+set}" = set; then :
   enableval=$enable_hidapi;
@@ -24078,6 +24236,9 @@ else
 fi
 
     if test x$enable_joystick = xyes -a x$enable_hidapi = xyes; then
+        if test x$skiplibusb = xyes; then
+            hidapi_support=yes
+        else
 
 pkg_failed=no
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBUSB" >&5
@@ -24147,28 +24308,73 @@ else
 $as_echo "yes" >&6; }
 	have_libusb=yes
 fi
-        hidapi_support=no
-        save_CFLAGS="$CFLAGS"
-        CFLAGS="$save_CFLAGS $LIBUSB_CFLAGS"
-        ac_fn_c_check_header_mongrel "$LINENO" "libusb.h" "ac_cv_header_libusb_h" "$ac_includes_default"
+            save_CFLAGS="$CFLAGS"
+            CFLAGS="$save_CFLAGS $LIBUSB_CFLAGS"
+            ac_fn_c_check_header_mongrel "$LINENO" "libusb.h" "ac_cv_header_libusb_h" "$ac_includes_default"
 if test "x$ac_cv_header_libusb_h" = xyes; then :
   have_libusb_h=yes
 fi
 
 
-        CFLAGS="$save_CFLAGS"
+            CFLAGS="$save_CFLAGS"
+            if test x$have_libusb_h = xyes; then
+                hidapi_support=yes
+            elif test x$onlylibusb = xyes; then
+                hidapi_support=no
+            else
+                hidapi_support=yes
+            fi
+        fi
 
-        if test x$have_libusb_h = xyes; then
-            hidapi_support=yes
+        if test x$hidapi_support = xyes; then
 
 $as_echo "#define SDL_JOYSTICK_HIDAPI 1" >>confdefs.h
 
             EXTRA_CFLAGS="$EXTRA_CFLAGS -I$srcdir/src/hidapi/hidapi"
             SOURCES="$SOURCES $srcdir/src/joystick/hidapi/*.c"
-            SOURCES="$SOURCES $srcdir/src/hidapi/libusb/hid.c"
-            EXTRA_CFLAGS="$EXTRA_CFLAGS $LIBUSB_CFLAGS"
-            EXTRA_LDFLAGS="$EXTRA_LDFLAGS $LIBUSB_LIBS"
+
+            if test x$have_libusb_h = xyes; then
+                EXTRA_CFLAGS="$EXTRA_CFLAGS $LIBUSB_CFLAGS"
+                if test x$onlylibusb = xyes; then
+                    SOURCES="$SOURCES $srcdir/src/hidapi/libusb/hid.c"
+                    EXTRA_LDFLAGS="$EXTRA_LDFLAGS $LIBUSB_LIBS"
+                else
+                    if test x$have_loadso != xyes; then
+                        { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: You must have SDL_LoadObject() support for dynamic libusb loading" >&5
+$as_echo "$as_me: WARNING: You must have SDL_LoadObject() support for dynamic libusb loading" >&2;}
+                    fi
+                    SOURCES="$SOURCES $srcdir/src/hidapi/SDL_hidapi.c"
+                    # libusb is loaded dynamically, so don't add it to LDFLAGS
+                    libusb_lib=""
+                    case "$host" in
+                        *-*-darwin* )
+                            libusb_lib="libusb-1.0.0.dylib"
+                            ;;
+                        *-*-cygwin* | *-*-mingw32* )
+                            libusb_lib="libusb-1.0.dll"
+                            ;;
+                    esac
+                    if test x$libusb_lib = x; then
+                        libusb_lib=`find_lib "libusb-1.0.so.*" "" | sed 's/.*\/\(.*\)/\1/; q'`
+                    fi
+
+cat >>confdefs.h <<_ACEOF
+#define SDL_LIBUSB_DYNAMIC "$libusb_lib"
+_ACEOF
+
+                fi
+            else
+                case "$host" in
+                *-*-cygwin* | *-*-mingw32* )
+                    SOURCES="$SOURCES $srcdir/src/hidapi/windows/hid.c"
+                    ;;
+                *-*-darwin* )
+                    SOURCES="$SOURCES $srcdir/src/hidapi/mac/hid.c"
+                    ;;
+                esac
+            fi
         fi
+
         { $as_echo "$as_me:${as_lineno-$LINENO}: checking for hidapi support" >&5
 $as_echo_n "checking for hidapi support... " >&6; }
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hidapi_support" >&5
@@ -24334,6 +24540,7 @@ fi
 
 
 CheckWarnAll
+CheckNoStrictAliasing
 
 CheckEventSignals
 
@@ -24383,6 +24590,8 @@ case "$host" in
         CheckDiskAudio
         CheckDummyAudio
         CheckDLOPEN
+        CheckARM
+        CheckNEON
         CheckOSS
         CheckALSA
         CheckPulseAudio
@@ -24402,6 +24611,7 @@ case "$host" in
         CheckOpenGLESX11
         CheckVulkan
         CheckWayland
+        CheckInputEvents
         CheckLibUDev
         CheckDBus
         CheckIME
@@ -24409,7 +24619,6 @@ case "$host" in
         CheckFcitx
         case $ARCH in
           linux)
-              CheckInputEvents
               CheckInputKD
           ;;
         esac
@@ -24594,6 +24803,7 @@ $as_echo "#define SDL_TIMER_UNIX 1" >>confdefs.h
         CheckWINDOWSGLES
         CheckVulkan
         CheckDIRECTX
+        CheckHIDAPI
 
         # Set up the core platform files
         SOURCES="$SOURCES $srcdir/src/core/windows/*.c"
@@ -24667,13 +24877,7 @@ $as_echo "#define SDL_JOYSTICK_DINPUT 1" >>confdefs.h
 $as_echo "#define SDL_JOYSTICK_WINMM 1" >>confdefs.h
 
             fi
-
-$as_echo "#define SDL_JOYSTICK_HIDAPI 1" >>confdefs.h
-
             SOURCES="$SOURCES $srcdir/src/joystick/windows/*.c"
-            SOURCES="$SOURCES $srcdir/src/joystick/hidapi/*.c"
-            SOURCES="$SOURCES $srcdir/src/hidapi/windows/hid.c"
-            EXTRA_CFLAGS="$EXTRA_CFLAGS -I$srcdir/src/hidapi/hidapi"
             have_joystick=yes
         fi
         if test x$enable_haptic = xyes; then
@@ -24970,7 +25174,7 @@ $as_echo "#define SDL_VIDEO_RENDER_OGL_ES2 1" >>confdefs.h
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,QuartzCore"
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,UIKit"
 
-        if test x$enable_render = xyes -a x$enable_render_metal = xyes; then
+        if test x$enable_video_metal = xyes -o x$enable_video_vulkan = xyes; then
             EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Metal"
         fi
         ;;
@@ -24998,6 +25202,7 @@ $as_echo "#define SDL_VIDEO_RENDER_OGL_ES2 1" >>confdefs.h
         CheckOpenGLX11
         CheckVulkan
         CheckPTHREAD
+        CheckHIDAPI
 
         # Set up files for the audio library
         if test x$enable_audio = xyes; then
@@ -25014,13 +25219,7 @@ $as_echo "#define SDL_AUDIO_DRIVER_COREAUDIO 1" >>confdefs.h
 
 $as_echo "#define SDL_JOYSTICK_IOKIT 1" >>confdefs.h
 
-
-$as_echo "#define SDL_JOYSTICK_HIDAPI 1" >>confdefs.h
-
             SOURCES="$SOURCES $srcdir/src/joystick/darwin/*.c"
-            SOURCES="$SOURCES $srcdir/src/joystick/hidapi/*.c"
-            SOURCES="$SOURCES $srcdir/src/hidapi/mac/hid.c"
-            EXTRA_CFLAGS="$EXTRA_CFLAGS -I$srcdir/src/hidapi/hidapi"
             have_joystick=yes
         fi
         # Set up files for the haptic library
@@ -25069,7 +25268,7 @@ $as_echo "#define SDL_TIMER_UNIX 1" >>confdefs.h
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Carbon"
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,IOKit"
 
-        if test x$enable_render = xyes -a x$enable_render_metal = xyes; then
+        if test x$enable_video_metal = xyes -o x$enable_video_vulkan = xyes; then
             EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-weak_framework,QuartzCore -Wl,-weak_framework,Metal"
         fi
         ;;
@@ -25458,6 +25657,23 @@ if test x$have_fcitx_frontend_h_hdr = xyes; then
 else
     SUMMARY="${SUMMARY}Using fcitx         : NO\n"
 fi
+
+if test x$WARN_ABOUT_ARM_SIMD_ASM_MIT = xyes; then
+    SUMMARY="${SUMMARY}\nSDL is being built with ARM SIMD optimizations, which\n"
+    SUMMARY="${SUMMARY}uses code licensed under the MIT license. If this is a\n"
+    SUMMARY="${SUMMARY}problem, please disable that code by rerunning the\n"
+    SUMMARY="${SUMMARY}configure script with:\n"
+    SUMMARY="${SUMMARY}\n    --disable-arm-simd\n"
+fi
+
+if test x$WARN_ABOUT_ARM_NEON_ASM_MIT = xyes; then
+    SUMMARY="${SUMMARY}\nSDL is being built with ARM NEON optimizations, which\n"
+    SUMMARY="${SUMMARY}uses code licensed under the MIT license. If this is a\n"
+    SUMMARY="${SUMMARY}problem, please disable that code by rerunning the\n"
+    SUMMARY="${SUMMARY}configure script with:\n"
+    SUMMARY="${SUMMARY}\n    --disable-arm-neon\n"
+fi
+
 ac_config_commands="$ac_config_commands summary"
 
 

+ 220 - 49
sdl.mod/SDL/configure.ac

@@ -20,9 +20,9 @@ dnl Set various version strings - taken gratefully from the GTk sources
 #
 SDL_MAJOR_VERSION=2
 SDL_MINOR_VERSION=0
-SDL_MICRO_VERSION=9
+SDL_MICRO_VERSION=11
 SDL_INTERFACE_AGE=0
-SDL_BINARY_AGE=9
+SDL_BINARY_AGE=11
 SDL_VERSION=$SDL_MAJOR_VERSION.$SDL_MINOR_VERSION.$SDL_MICRO_VERSION
 
 AC_SUBST(SDL_MAJOR_VERSION)
@@ -1303,6 +1303,82 @@ AS_HELP_STRING([--enable-libsamplerate-shared], [dynamically load libsamplerate
     fi
 }
 
+dnl Check for ARM instruction support using gas syntax
+CheckARM()
+{
+    AC_ARG_ENABLE(arm-simd,
+AC_HELP_STRING([--enable-arm-simd], [use SIMD assembly blitters on ARM [[default=yes]]]),
+                  enable_arm_simd=$enableval, enable_arm_simd=yes)
+    if test x$enable_video = xyes -a x$enable_assembly = xyes -a x$enable_arm_simd = xyes; then
+        save_CFLAGS="$CFLAGS"
+        have_arm_simd=no
+        CFLAGS="-x assembler-with-cpp $CFLAGS"
+        
+        AC_MSG_CHECKING(for ARM SIMD)
+        AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+        .text
+        .arch armv6
+        .object_arch armv4
+        .arm
+        .altmacro
+        #ifndef __ARM_EABI__
+        #error EABI is required (to be sure that calling conventions are compatible)
+        #endif
+        pld [r0]
+        uqadd8 r0, r0, r0
+        ]])], have_arm_simd=yes)
+        AC_MSG_RESULT($have_arm_simd)
+        
+        CFLAGS="$save_CFLAGS"
+        
+        if test x$have_arm_simd = xyes; then
+            AC_DEFINE(SDL_ARM_SIMD_BLITTERS)
+dnl            SOURCES="$SOURCES $srcdir/src/video/arm/pixman-arm-simd*.c"
+            SOURCES="$SOURCES $srcdir/src/video/arm/pixman-arm-simd*.S"
+            WARN_ABOUT_ARM_SIMD_ASM_MIT="yes"
+        fi
+    fi
+}
+
+dnl Check for ARM NEON instruction support using gas syntax
+CheckNEON()
+{
+    AC_ARG_ENABLE(arm-neon,
+AC_HELP_STRING([--enable-arm-neon], [use NEON assembly blitters on ARM [[default=yes]]]),
+                  enable_arm_neon=$enableval, enable_arm_neon=yes)
+    if test x$enable_video = xyes -a x$enable_assembly = xyes -a x$enable_arm_neon = xyes; then
+        save_CFLAGS="$CFLAGS"
+        have_arm_neon=no
+        CFLAGS="-x assembler-with-cpp $CFLAGS"
+        
+        AC_MSG_CHECKING(for ARM NEON)
+        AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+        .text
+        .fpu neon
+        .arch armv7a
+        .object_arch armv4
+        .eabi_attribute 10, 0
+        .arm
+        .altmacro
+        #ifndef __ARM_EABI__
+        #error EABI is required (to be sure that calling conventions are compatible)
+        #endif
+        pld [r0]
+        vmovn.u16 d0, q0
+        ]])], have_arm_neon=yes)
+        AC_MSG_RESULT($have_arm_neon)
+        
+        CFLAGS="$save_CFLAGS"
+        
+        if test x$have_arm_neon = xyes; then
+            AC_DEFINE(SDL_ARM_NEON_BLITTERS)
+dnl            SOURCES="$SOURCES $srcdir/src/video/arm/pixman-arm-neon*.c"
+            SOURCES="$SOURCES $srcdir/src/video/arm/pixman-arm-neon*.S"
+            WARN_ABOUT_ARM_NEON_ASM_MIT="yes"
+        fi
+    fi
+}
+
 dnl See if GCC's -fvisibility=hidden is supported (gcc4 and later, usually).
 dnl  Details of this flag are here: http://gcc.gnu.org/wiki/Visibility
 CheckVisibilityHidden()
@@ -1329,6 +1405,29 @@ CheckVisibilityHidden()
     fi
 }
 
+dnl See if GCC's -fno-strict-aliasingis supported.
+dnl  Reference: https://bugzilla.libsdl.org/show_bug.cgi?id=4254
+CheckNoStrictAliasing()
+{
+    AC_MSG_CHECKING(for GCC -fno-strict-aliasing option)
+    have_gcc_no_strict_aliasing=no
+
+    save_CFLAGS="$CFLAGS"
+    CFLAGS="$save_CFLAGS -fno-strict-aliasing"
+    AC_TRY_COMPILE([
+    int x = 0;
+    ],[
+    ],[
+    have_gcc_no_strict_aliasing=yes
+    ])
+    AC_MSG_RESULT($have_gcc_no_strict_aliasing)
+    CFLAGS="$save_CFLAGS"
+
+    if test x$have_gcc_no_strict_aliasing = xyes; then
+        EXTRA_CFLAGS="$EXTRA_CFLAGS -fno-strict-aliasing"
+    fi
+}
+
 dnl See if GCC's -mpreferred-stack-boundary is supported.
 dnl  Reference: http://bugzilla.libsdl.org/show_bug.cgi?id=1296
 CheckStackBoundary()
@@ -1527,8 +1626,8 @@ CheckNativeClient()
 CheckRPI()
 {
     AC_ARG_ENABLE(video-rpi,
-AS_HELP_STRING([--enable-video-rpi], [use Raspberry Pi video driver [[default=no]]]),
-                  , enable_video_rpi=no)
+AS_HELP_STRING([--enable-video-rpi], [use Raspberry Pi video driver [[default=yes]]]),
+                  , enable_video_rpi=yes)
     if test x$enable_video = xyes -a x$enable_video_rpi = xyes; then
         PKG_CHECK_MODULES([RPI], [bcm_host brcmegl], video_rpi=yes, video_rpi=no)
 
@@ -1587,10 +1686,10 @@ AS_HELP_STRING([--enable-video-x11], [use X11 video driver [[default=yes]]]),
                 # This isn't necessary for X11, but fixes GLX detection
                 if test "x$x_includes" = xNONE && \
                    test "x$x_libraries" = xNONE && \
-                   test -d /usr/X11R6/include && \
-                   test -d /usr/X11R6/lib; then
-                    x_includes="/usr/X11R6/include"
-                    x_libraries="/usr/X11R6/lib"
+                   test -d /opt/X11/include && \
+                   test -d /opt/X11/lib; then
+                    x_includes="/opt/X11/include"
+                    x_libraries="/opt/X11/lib"
                 fi
                 ;;
         esac
@@ -1603,15 +1702,16 @@ AS_HELP_STRING([--enable-x11-shared], [dynamically load X11 support [[default=ma
 
             case "$host" in
                 *-*-darwin*)
-                    x11_lib='/usr/X11R6/lib/libX11.6.dylib'
-                    x11ext_lib='/usr/X11R6/lib/libXext.6.dylib'
-                    xcursor_lib='/usr/X11R6/lib/libXcursor.1.dylib'
-                    xinerama_lib='/usr/X11R6/lib/libXinerama.1.dylib'
-                    xinput_lib='/usr/X11R6/lib/libXi.6.dylib'
-                    xrandr_lib='/usr/X11R6/lib/libXrandr.2.dylib'
-                    xrender_lib='/usr/X11R6/lib/libXrender.1.dylib'
-                    xss_lib='/usr/X11R6/lib/libXss.1.dylib'
-                    xvidmode_lib='/usr/X11R6/lib/libXxf86vm.1.dylib'
+                    # Apple now puts this in /opt/X11
+                    x11_lib='/opt/X11/lib/libX11.6.dylib'
+                    x11ext_lib='/opt/X11/lib/libXext.6.dylib'
+                    xcursor_lib='/opt/X11/lib/libXcursor.1.dylib'
+                    xinerama_lib='/opt/X11/lib/libXinerama.1.dylib'
+                    xinput_lib='/opt/X11/lib/libXi.6.dylib'
+                    xrandr_lib='/opt/X11/lib/libXrandr.2.dylib'
+                    xrender_lib='/opt/X11/lib/libXrender.1.dylib'
+                    xss_lib='/opt/X11/lib/libXss.1.dylib'
+                    xvidmode_lib='/opt/X11/lib/libXxf86vm.1.dylib'
                     ;;
                 *-*-openbsd*)
                     x11_lib='libX11.so'
@@ -2025,10 +2125,13 @@ AS_HELP_STRING([--enable-video-cocoa], [use Cocoa video driver [[default=yes]]])
 
 CheckMETAL()
 {
+    AC_ARG_ENABLE(video-metal,
+AC_HELP_STRING([--enable-video-metal], [include Metal support [[default=yes]]]),
+              , enable_video_metal=yes)
     AC_ARG_ENABLE(render-metal,
 AS_HELP_STRING([--enable-render-metal], [enable the Metal render driver [[default=yes]]]),
                                 , enable_render_metal=yes)
-    if test x$enable_render = xyes -a x$enable_render_metal = xyes; then
+    if test x$enable_video = xyes -a x$enable_video_metal = xyes; then
         save_CFLAGS="$CFLAGS"
         dnl Work around that we don't have Objective-C support in autoconf
         CFLAGS="$CFLAGS -x objective-c"
@@ -2049,10 +2152,14 @@ AS_HELP_STRING([--enable-render-metal], [enable the Metal render driver [[defaul
         CFLAGS="$save_CFLAGS"
         AC_MSG_RESULT($have_metal)
         if test x$have_metal = xyes; then
-            AC_DEFINE(SDL_VIDEO_RENDER_METAL, 1, [ ])
-            SOURCES="$SOURCES $srcdir/src/render/metal/*.m"
+            AC_DEFINE(SDL_VIDEO_METAL, 1, [ ])
+            if test x$enable_render = xyes -a x$enable_render_metal = xyes; then
+                AC_DEFINE(SDL_VIDEO_RENDER_METAL, 1, [ ])
+                SOURCES="$SOURCES $srcdir/src/render/metal/*.m"
+            fi
             SUMMARY_video="${SUMMARY_video} metal"
         else
+            enable_video_metal=no
             enable_render_metal=no
         fi
     fi
@@ -2261,7 +2368,7 @@ CheckOpenGLESX11()
         if test x$video_opengl_egl = xyes; then
             AC_DEFINE(SDL_VIDEO_OPENGL_EGL, 1, [ ])
         fi
-            
+        
         if test x$enable_video_opengles1 = xyes; then
             AC_MSG_CHECKING(for OpenGL ES v1 headers)
             video_opengles_v1=no
@@ -2572,7 +2679,7 @@ AS_HELP_STRING([--enable-ime], [enable IME support [[default=yes]]]),
                   , enable_ime=yes)
     if test x$enable_ime = xyes; then
         AC_DEFINE(SDL_USE_IME, 1, [ ])
-            SOURCES="$SOURCES $srcdir/src/core/linux/SDL_ime.c"
+        SOURCES="$SOURCES $srcdir/src/core/linux/SDL_ime.c"
     fi
 }
 
@@ -2991,8 +3098,6 @@ XINPUT_STATE_EX s1;
         AC_DEFINE(HAVE_AUDIOCLIENT_H,1,[])
     fi
 
-    AC_CHECK_HEADER(endpointvolume.h,AC_DEFINE(HAVE_ENDPOINTVOLUME_H,1,[]))
-
     AC_ARG_ENABLE(wasapi,
 AS_HELP_STRING([--enable-wasapi], [use the Windows WASAPI audio driver [[default=yes]]]),
                                 , enable_wasapi=yes)
@@ -3044,7 +3149,7 @@ CheckUSBHID()
                     AC_CHECK_HEADER(libusb.h, [USB_CFLAGS="-DHAVE_LIBUSB_H"])
                     AC_CHECK_LIB(usb, hid_init, [USB_LIBS="$USB_LIBS -lusb"])
                 fi
-                    
+                
                 save_CFLAGS="$CFLAGS"
                 CFLAGS="$CFLAGS $USB_CFLAGS"
 
@@ -3174,28 +3279,80 @@ CheckHIDAPI()
 {
     # The hidraw support doesn't catch Xbox, PS4 and Nintendo controllers,
     # so we'll just use libusb when it's available.
-    #
-    # Except that libusb requires root permissions to open devices, so that's not generally useful, and we'll disable this by default.
+    case "$host" in
+        # libusb does not support iOS
+        arm*-apple-darwin* | *-ios-* )
+            skiplibusb=yes
+            ;;
+        # On the other hand, *BSD specifically uses libusb only
+        *-*-*bsd* )
+            onlylibusb=yes
+            ;;
+    esac
+
     AC_ARG_ENABLE(hidapi,
 AS_HELP_STRING([--enable-hidapi], [use HIDAPI for low level joystick drivers [[default=no]]]),
                   , enable_hidapi=no)
     if test x$enable_joystick = xyes -a x$enable_hidapi = xyes; then
-        PKG_CHECK_MODULES([LIBUSB], [libusb-1.0], have_libusb=yes, have_libusb=no)
-        hidapi_support=no
-        save_CFLAGS="$CFLAGS"
-        CFLAGS="$save_CFLAGS $LIBUSB_CFLAGS"
-        AC_CHECK_HEADER(libusb.h, have_libusb_h=yes)
-        CFLAGS="$save_CFLAGS"
-
-        if test x$have_libusb_h = xyes; then
+        if test x$skiplibusb = xyes; then
             hidapi_support=yes
+        else
+            PKG_CHECK_MODULES([LIBUSB], [libusb-1.0], have_libusb=yes, have_libusb=no)
+            save_CFLAGS="$CFLAGS"
+            CFLAGS="$save_CFLAGS $LIBUSB_CFLAGS"
+            AC_CHECK_HEADER(libusb.h, have_libusb_h=yes)
+            CFLAGS="$save_CFLAGS"
+            if test x$have_libusb_h = xyes; then
+                hidapi_support=yes
+            elif test x$onlylibusb = xyes; then
+                hidapi_support=no
+            else
+                hidapi_support=yes
+            fi
+        fi
+
+        if test x$hidapi_support = xyes; then
             AC_DEFINE(SDL_JOYSTICK_HIDAPI, 1, [ ])
             EXTRA_CFLAGS="$EXTRA_CFLAGS -I$srcdir/src/hidapi/hidapi"
             SOURCES="$SOURCES $srcdir/src/joystick/hidapi/*.c"
-            SOURCES="$SOURCES $srcdir/src/hidapi/libusb/hid.c"
-            EXTRA_CFLAGS="$EXTRA_CFLAGS $LIBUSB_CFLAGS"
-            EXTRA_LDFLAGS="$EXTRA_LDFLAGS $LIBUSB_LIBS"
+
+            if test x$have_libusb_h = xyes; then
+                EXTRA_CFLAGS="$EXTRA_CFLAGS $LIBUSB_CFLAGS"
+                if test x$onlylibusb = xyes; then
+                    SOURCES="$SOURCES $srcdir/src/hidapi/libusb/hid.c"
+                    EXTRA_LDFLAGS="$EXTRA_LDFLAGS $LIBUSB_LIBS"
+                else
+                    if test x$have_loadso != xyes; then
+                        AC_MSG_WARN([You must have SDL_LoadObject() support for dynamic libusb loading])
+                    fi
+                    SOURCES="$SOURCES $srcdir/src/hidapi/SDL_hidapi.c"
+                    # libusb is loaded dynamically, so don't add it to LDFLAGS
+                    libusb_lib=""
+                    case "$host" in
+                        *-*-darwin* )
+                            libusb_lib="libusb-1.0.0.dylib"
+                            ;;
+                        *-*-cygwin* | *-*-mingw32* )
+                            libusb_lib="libusb-1.0.dll"
+                            ;;
+                    esac
+                    if test x$libusb_lib = x; then
+                        libusb_lib=[`find_lib "libusb-1.0.so.*" "" | sed 's/.*\/\(.*\)/\1/; q'`]
+                    fi
+                    AC_DEFINE_UNQUOTED(SDL_LIBUSB_DYNAMIC, "$libusb_lib", [ ])
+                fi
+            else
+                case "$host" in
+                *-*-cygwin* | *-*-mingw32* )
+                    SOURCES="$SOURCES $srcdir/src/hidapi/windows/hid.c"
+                    ;;
+                *-*-darwin* )
+                    SOURCES="$SOURCES $srcdir/src/hidapi/mac/hid.c"
+                    ;;
+                esac
+            fi
         fi
+
         AC_MSG_CHECKING(for hidapi support)
         AC_MSG_RESULT($hidapi_support)
     fi
@@ -3263,6 +3420,7 @@ AS_HELP_STRING([--enable-foregrounding-signal], [number to use for magic foregro
 
 dnl Do this on all platforms, before everything else (other things might want to override it).
 CheckWarnAll
+CheckNoStrictAliasing
 
 dnl Do this for every platform, but for some it doesn't mean anything, but better to catch it here anyhow.
 CheckEventSignals
@@ -3314,6 +3472,8 @@ case "$host" in
         CheckDiskAudio
         CheckDummyAudio
         CheckDLOPEN
+        CheckARM
+        CheckNEON
         CheckOSS
         CheckALSA
         CheckPulseAudio
@@ -3333,6 +3493,7 @@ case "$host" in
         CheckOpenGLESX11
         CheckVulkan
         CheckWayland
+        CheckInputEvents
         CheckLibUDev
         CheckDBus
         CheckIME
@@ -3340,7 +3501,6 @@ case "$host" in
         CheckFcitx
         case $ARCH in
           linux)
-              CheckInputEvents
               CheckInputKD
           ;;
         esac
@@ -3497,6 +3657,7 @@ case "$host" in
         CheckWINDOWSGLES
         CheckVulkan
         CheckDIRECTX
+        CheckHIDAPI
 
         # Set up the core platform files
         SOURCES="$SOURCES $srcdir/src/core/windows/*.c"
@@ -3548,11 +3709,7 @@ AS_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
             else
                 AC_DEFINE(SDL_JOYSTICK_WINMM, 1, [ ])
             fi
-            AC_DEFINE(SDL_JOYSTICK_HIDAPI, 1, [ ])
             SOURCES="$SOURCES $srcdir/src/joystick/windows/*.c"
-            SOURCES="$SOURCES $srcdir/src/joystick/hidapi/*.c"
-            SOURCES="$SOURCES $srcdir/src/hidapi/windows/hid.c"
-            EXTRA_CFLAGS="$EXTRA_CFLAGS -I$srcdir/src/hidapi/hidapi"
             have_joystick=yes
         fi
         if test x$enable_haptic = xyes; then
@@ -3751,7 +3908,7 @@ AS_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,QuartzCore"
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,UIKit"
 
-        if test x$enable_render = xyes -a x$enable_render_metal = xyes; then
+        if test x$enable_video_metal = xyes -o x$enable_video_vulkan = xyes; then
             EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Metal"
         fi
         ;;
@@ -3779,6 +3936,7 @@ AS_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
         CheckOpenGLX11
         CheckVulkan
         CheckPTHREAD
+        CheckHIDAPI
 
         # Set up files for the audio library
         if test x$enable_audio = xyes; then
@@ -3791,11 +3949,7 @@ AS_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
         # Set up files for the joystick library
         if test x$enable_joystick = xyes; then
             AC_DEFINE(SDL_JOYSTICK_IOKIT, 1, [ ])
-            AC_DEFINE(SDL_JOYSTICK_HIDAPI, 1, [ ])
             SOURCES="$SOURCES $srcdir/src/joystick/darwin/*.c"
-            SOURCES="$SOURCES $srcdir/src/joystick/hidapi/*.c"
-            SOURCES="$SOURCES $srcdir/src/hidapi/mac/hid.c"
-            EXTRA_CFLAGS="$EXTRA_CFLAGS -I$srcdir/src/hidapi/hidapi"
             have_joystick=yes
         fi
         # Set up files for the haptic library
@@ -3836,7 +3990,7 @@ AS_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,Carbon"
         EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-framework,IOKit"
 
-        if test x$enable_render = xyes -a x$enable_render_metal = xyes; then
+        if test x$enable_video_metal = xyes -o x$enable_video_vulkan = xyes; then
             EXTRA_LDFLAGS="$EXTRA_LDFLAGS -Wl,-weak_framework,QuartzCore -Wl,-weak_framework,Metal"
         fi
         ;;
@@ -4172,6 +4326,23 @@ if test x$have_fcitx_frontend_h_hdr = xyes; then
 else
     SUMMARY="${SUMMARY}Using fcitx         : NO\n"
 fi
+
+if test x$WARN_ABOUT_ARM_SIMD_ASM_MIT = xyes; then
+    SUMMARY="${SUMMARY}\nSDL is being built with ARM SIMD optimizations, which\n"
+    SUMMARY="${SUMMARY}uses code licensed under the MIT license. If this is a\n"
+    SUMMARY="${SUMMARY}problem, please disable that code by rerunning the\n"
+    SUMMARY="${SUMMARY}configure script with:\n"
+    SUMMARY="${SUMMARY}\n    --disable-arm-simd\n"
+fi
+
+if test x$WARN_ABOUT_ARM_NEON_ASM_MIT = xyes; then
+    SUMMARY="${SUMMARY}\nSDL is being built with ARM NEON optimizations, which\n"
+    SUMMARY="${SUMMARY}uses code licensed under the MIT license. If this is a\n"
+    SUMMARY="${SUMMARY}problem, please disable that code by rerunning the\n"
+    SUMMARY="${SUMMARY}configure script with:\n"
+    SUMMARY="${SUMMARY}\n    --disable-arm-neon\n"
+fi
+
 AC_CONFIG_COMMANDS([summary], [echo -en "$SUMMARY"], [SUMMARY="$SUMMARY"])
 
 AC_OUTPUT

+ 12 - 0
sdl.mod/SDL/debian/changelog

@@ -1,3 +1,15 @@
+libsdl2 (2.0.11) UNRELEASED; urgency=low
+
+  * Updated SDL to version 2.0.11 for development builds
+
+ -- Sam Lantinga <[email protected]>  Sun, 22 Sep 2019 10:33:03 -0800
+
+libsdl2 (2.0.10) UNRELEASED; urgency=low
+
+  * Updated SDL to version 2.0.10
+
+ -- Sam Lantinga <[email protected]>  Mon, 17 Jun 2019 08:48:47 -0800
+
 libsdl2 (2.0.9) UNRELEASED; urgency=low
 
   * Updated SDL to version 2.0.9

+ 19 - 0
sdl.mod/SDL/docs/README-android.md

@@ -82,6 +82,23 @@ For more complex projects, follow these instructions:
 
 4b. If you want to build manually, run './gradlew installDebug' in the project directory. This compiles the .java, creates an .apk with the native code embedded, and installs it on any connected Android device
 
+
+If you already have a project that uses CMake, the instructions change somewhat:
+
+1. Do points 1 and 2 from the instruction above.
+2. Edit "<project>/app/build.gradle" to comment out or remove sections containing ndk-build
+   and uncomment the cmake sections. Add arguments to the CMake invocation as needed.
+3. Edit "<project>/app/jni/CMakeLists.txt" to include your project (it defaults to
+   adding the "src" subdirectory). Note that you'll have SDL2, SDL2main and SDL2-static
+   as targets in your project, so you should have "target_link_libraries(yourgame SDL2 SDL2main)"
+   in your CMakeLists.txt file. Also be aware that you should use add_library() instead of
+   add_executable() for the target containing your "main" function.
+
+If you wish to use Android Studio, you can skip the last step.
+
+4. Run './gradlew installDebug' or './gradlew installRelease' in the project directory. It will build and install your .apk on any
+   connected Android device
+
 Here's an explanation of the files in the Android project, so you can customize them:
 
     android-project/app
@@ -90,10 +107,12 @@ Here's an explanation of the files in the Android project, so you can customize
         jni/			- directory holding native code
         jni/Application.mk	- Application JNI settings, including target platform and STL library
         jni/Android.mk		- Android makefile that can call recursively the Android.mk files in all subdirectories
+        jni/CMakeLists.txt	- Top-level CMake project that adds SDL as a subproject
         jni/SDL/		- (symlink to) directory holding the SDL library files
         jni/SDL/Android.mk	- Android makefile for creating the SDL shared library
         jni/src/		- directory holding your C/C++ source
         jni/src/Android.mk	- Android makefile that you should customize to include your source code and any library references
+        jni/src/CMakeLists.txt	- CMake file that you may customize to include your source code and any library references
         src/main/assets/	- directory holding asset files for your application
         src/main/res/		- directory holding resources for your application
         src/main/res/mipmap-*	- directories holding icons for different phone hardware

+ 53 - 1
sdl.mod/SDL/docs/README-cmake.md

@@ -15,7 +15,7 @@ platforms:
 * Linux
 * VS.NET 2010
 * MinGW and Msys
-* OS X with support for XCode
+* macOS, iOS, and tvOS, with support for XCode
 
 
 ================================================================================
@@ -30,3 +30,55 @@ Assuming the source for SDL is located at ~/sdl
     cmake ../sdl
 
 This will build the static and dynamic versions of SDL in the ~/build directory.
+
+
+================================================================================
+Usage, iOS/tvOS
+================================================================================
+
+CMake 3.14+ natively includes support for iOS and tvOS.  SDL binaries may be built
+using Xcode or Make, possibly among other build-systems.
+
+When using a recent version of CMake (3.14+), it should be possible to:
+
+- build SDL for iOS, both static and dynamic
+- build SDL test apps (as iOS/tvOS .app bundles)
+- generate a working SDL_config.h for iOS (using SDL_config.h.cmake as a basis)
+
+To use, set the following CMake variables when running CMake's configuration stage:
+
+- `CMAKE_SYSTEM_NAME=<OS>`   (either `iOS` or `tvOS`)
+- `CMAKE_OSX_SYSROOT=<SDK>`  (examples: `iphoneos`, `iphonesimulator`, `iphoneos12.4`, `/full/path/to/iPhoneOS.sdk`,
+                              `appletvos`, `appletvsimulator`, `appletvos12.4`, `/full/path/to/AppleTVOS.sdk`, etc.)
+- `CMAKE_OSX_ARCHITECTURES=<semicolon-separated list of CPU architectures>` (example: "arm64;armv7s;x86_64")
+
+
+### Examples (for iOS/tvOS):
+
+- for iOS-Simulator, using the latest, installed SDK:
+
+    `cmake ~/sdl -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphonesimulator -DCMAKE_OSX_ARCHITECTURES=x86_64`
+
+- for iOS-Device, using the latest, installed SDK, 64-bit only
+
+    `cmake ~/sdl -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos -DCMAKE_OSX_ARCHITECTURES=arm64`
+
+- for iOS-Device, using the latest, installed SDK, mixed 32/64 bit
+
+    `cmake ~/sdl -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos -DCMAKE_OSX_ARCHITECTURES="arm64;armv7s"`
+
+- for iOS-Device, using a specific SDK revision (iOS 12.4, in this example):
+
+    `cmake ~/sdl -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphoneos12.4 -DCMAKE_OSX_ARCHITECTURES=arm64`
+
+- for iOS-Simulator, using the latest, installed SDK, and building SDL test apps (as .app bundles):
+
+    `cmake ~/sdl -DSDL_TEST=1 -DCMAKE_SYSTEM_NAME=iOS -DCMAKE_OSX_SYSROOT=iphonesimulator -DCMAKE_OSX_ARCHITECTURES=x86_64`
+
+- for tvOS-Simulator, using the latest, installed SDK:
+
+    `cmake ~/sdl -DCMAKE_SYSTEM_NAME=tvOS -DCMAKE_OSX_SYSROOT=appletvsimulator -DCMAKE_OSX_ARCHITECTURES=x86_64`
+
+- for tvOS-Device, using the latest, installed SDK:
+
+    `cmake ~/sdl -DCMAKE_SYSTEM_NAME=tvOS -DCMAKE_OSX_SYSROOT=appletvos -DCMAKE_OSX_ARCHITECTURES=arm64`

+ 5 - 2
sdl.mod/SDL/docs/README-winrt.md

@@ -296,7 +296,7 @@ A few files should be included directly in your app's MSVC project, specifically
    included, mouse-position reporting may fail if and when the cursor is
    hidden, due to possible bugs/design-oddities in Windows itself.*
 
-To include these files:
+To include these files for C/C++ projects:
 
 1. right-click on your project (again, in Visual C++'s Solution Explorer), 
    navigate to "Add", then choose "Existing Item...".
@@ -313,11 +313,14 @@ To include these files:
 7. change the setting for "Consume Windows Runtime Extension" to "Yes (/ZW)".
 8. click the OK button.  This will close the dialog.
 
-
 **NOTE: C++/CX compilation is currently required in at least one file of your 
 app's project.  This is to make sure that Visual C++'s linker builds a 'Windows 
 Metadata' file (.winmd) for your app.  Not doing so can lead to build errors.**
 
+For non-C++ projects, you will need to call SDL_WinRTRunApp from your language's
+main function, and generate SDL2-WinRTResources.res manually by using `rc` via
+the Developer Command Prompt and including it as a <Win32Resource> within the
+first <PropertyGroup> block in your Visual Studio project file.
 
 ### 6. Add app code and assets ###
 

+ 1 - 0
sdl.mod/SDL/include/SDL.h

@@ -47,6 +47,7 @@
 #include "SDL_loadso.h"
 #include "SDL_log.h"
 #include "SDL_messagebox.h"
+#include "SDL_metal.h"
 #include "SDL_mutex.h"
 #include "SDL_power.h"
 #include "SDL_render.h"

+ 18 - 0
sdl.mod/SDL/include/SDL_atomic.h

@@ -162,12 +162,29 @@ extern DECLSPEC void SDLCALL SDL_MemoryBarrierAcquireFunction(void);
 #define SDL_MemoryBarrierRelease()   __asm__ __volatile__ ("dmb ish" : : : "memory")
 #define SDL_MemoryBarrierAcquire()   __asm__ __volatile__ ("dmb ish" : : : "memory")
 #elif defined(__GNUC__) && defined(__arm__)
+#if 0 /* defined(__LINUX__) || defined(__ANDROID__) */
+/* Information from:
+   https://chromium.googlesource.com/chromium/chromium/+/trunk/base/atomicops_internals_arm_gcc.h#19
+
+   The Linux kernel provides a helper function which provides the right code for a memory barrier,
+   hard-coded at address 0xffff0fa0
+*/
+typedef void (*SDL_KernelMemoryBarrierFunc)();
+#define SDL_MemoryBarrierRelease()	((SDL_KernelMemoryBarrierFunc)0xffff0fa0)()
+#define SDL_MemoryBarrierAcquire()	((SDL_KernelMemoryBarrierFunc)0xffff0fa0)()
+#elif 0 /* defined(__QNXNTO__) */
+#include <sys/cpuinline.h>
+
+#define SDL_MemoryBarrierRelease()   __cpu_membarrier()
+#define SDL_MemoryBarrierAcquire()   __cpu_membarrier()
+#else
 #if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__) || defined(__ARM_ARCH_8A__)
 #define SDL_MemoryBarrierRelease()   __asm__ __volatile__ ("dmb ish" : : : "memory")
 #define SDL_MemoryBarrierAcquire()   __asm__ __volatile__ ("dmb ish" : : : "memory")
 #elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_5TE__)
 #ifdef __thumb__
 /* The mcr instruction isn't available in thumb mode, use real functions */
+#define SDL_MEMORY_BARRIER_USES_FUNCTION
 #define SDL_MemoryBarrierRelease()   SDL_MemoryBarrierReleaseFunction()
 #define SDL_MemoryBarrierAcquire()   SDL_MemoryBarrierAcquireFunction()
 #else
@@ -177,6 +194,7 @@ extern DECLSPEC void SDLCALL SDL_MemoryBarrierAcquireFunction(void);
 #else
 #define SDL_MemoryBarrierRelease()   __asm__ __volatile__ ("" : : : "memory")
 #define SDL_MemoryBarrierAcquire()   __asm__ __volatile__ ("" : : : "memory")
+#endif /* __LINUX__ || __ANDROID__ */
 #endif /* __GNUC__ && __arm__ */
 #else
 #if (defined(__SUNPRO_C) && (__SUNPRO_C >= 0x5120))

+ 46 - 13
sdl.mod/SDL/include/SDL_audio.h

@@ -420,23 +420,56 @@ extern DECLSPEC void SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID dev,
 /* @} *//* Pause audio functions */
 
 /**
- *  This function loads a WAVE from the data source, automatically freeing
- *  that source if \c freesrc is non-zero.  For example, to load a WAVE file,
- *  you could do:
+ *  \brief Load the audio data of a WAVE file into memory
+ *
+ *  Loading a WAVE file requires \c src, \c spec, \c audio_buf and \c audio_len
+ *  to be valid pointers. The entire data portion of the file is then loaded
+ *  into memory and decoded if necessary.
+ *
+ *  If \c freesrc is non-zero, the data source gets automatically closed and
+ *  freed before the function returns.
+ *
+ *  Supported are RIFF WAVE files with the formats PCM (8, 16, 24, and 32 bits),
+ *  IEEE Float (32 bits), Microsoft ADPCM and IMA ADPCM (4 bits), and A-law and
+ *  µ-law (8 bits). Other formats are currently unsupported and cause an error.
+ *
+ *  If this function succeeds, the pointer returned by it is equal to \c spec
+ *  and the pointer to the audio data allocated by the function is written to
+ *  \c audio_buf and its length in bytes to \c audio_len. The \ref SDL_AudioSpec
+ *  members \c freq, \c channels, and \c format are set to the values of the
+ *  audio data in the buffer. The \c samples member is set to a sane default and
+ *  all others are set to zero.
+ *
+ *  It's necessary to use SDL_FreeWAV() to free the audio data returned in
+ *  \c audio_buf when it is no longer used.
+ *
+ *  Because of the underspecification of the Waveform format, there are many
+ *  problematic files in the wild that cause issues with strict decoders. To
+ *  provide compatibility with these files, this decoder is lenient in regards
+ *  to the truncation of the file, the fact chunk, and the size of the RIFF
+ *  chunk. The hints SDL_HINT_WAVE_RIFF_CHUNK_SIZE, SDL_HINT_WAVE_TRUNCATION,
+ *  and SDL_HINT_WAVE_FACT_CHUNK can be used to tune the behavior of the
+ *  loading process.
+ *
+ *  Any file that is invalid (due to truncation, corruption, or wrong values in
+ *  the headers), too big, or unsupported causes an error. Additionally, any
+ *  critical I/O error from the data source will terminate the loading process
+ *  with an error. The function returns NULL on error and in all cases (with the
+ *  exception of \c src being NULL), an appropriate error message will be set.
+ *
+ *  It is required that the data source supports seeking.
+ *
+ *  Example:
  *  \code
  *      SDL_LoadWAV_RW(SDL_RWFromFile("sample.wav", "rb"), 1, ...);
  *  \endcode
  *
- *  If this function succeeds, it returns the given SDL_AudioSpec,
- *  filled with the audio data format of the wave data, and sets
- *  \c *audio_buf to a malloc()'d buffer containing the audio data,
- *  and sets \c *audio_len to the length of that audio buffer, in bytes.
- *  You need to free the audio buffer with SDL_FreeWAV() when you are
- *  done with it.
- *
- *  This function returns NULL and sets the SDL error message if the
- *  wave file cannot be opened, uses an unknown data format, or is
- *  corrupt.  Currently raw and MS-ADPCM WAVE files are supported.
+ *  \param src The data source with the WAVE data
+ *  \param freesrc A integer value that makes the function close the data source if non-zero
+ *  \param spec A pointer filled with the audio format of the audio data
+ *  \param audio_buf A pointer filled with the audio data allocated by the function
+ *  \param audio_len A pointer filled with the length of the audio data buffer in bytes
+ *  \return NULL on error, or non-NULL on success.
  */
 extern DECLSPEC SDL_AudioSpec *SDLCALL SDL_LoadWAV_RW(SDL_RWops * src,
                                                       int freesrc,

+ 14 - 1
sdl.mod/SDL/include/SDL_config.h.cmake

@@ -211,7 +211,6 @@
 #cmakedefine HAVE_XINPUT_H @HAVE_XINPUT_H@
 #cmakedefine HAVE_DXGI_H @HAVE_DXGI_H@
 
-#cmakedefine HAVE_ENDPOINTVOLUME_H @HAVE_ENDPOINTVOLUME_H@
 #cmakedefine HAVE_MMDEVICEAPI_H @HAVE_MMDEVICEAPI_H@
 #cmakedefine HAVE_AUDIOCLIENT_H @HAVE_AUDIOCLIENT_H@
 
@@ -286,6 +285,7 @@
 #cmakedefine SDL_JOYSTICK_WINMM @SDL_JOYSTICK_WINMM@
 #cmakedefine SDL_JOYSTICK_USBHID @SDL_JOYSTICK_USBHID@
 #cmakedefine SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H @SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H@
+#cmakedefine SDL_JOYSTICK_HIDAPI @SDL_JOYSTICK_HIDAPI@
 #cmakedefine SDL_JOYSTICK_EMSCRIPTEN @SDL_JOYSTICK_EMSCRIPTEN@
 #cmakedefine SDL_HAPTIC_DUMMY @SDL_HAPTIC_DUMMY@
 #cmakedefine SDL_HAPTIC_LINUX @SDL_HAPTIC_LINUX@
@@ -293,9 +293,11 @@
 #cmakedefine SDL_HAPTIC_DINPUT @SDL_HAPTIC_DINPUT@
 #cmakedefine SDL_HAPTIC_XINPUT @SDL_HAPTIC_XINPUT@
 #cmakedefine SDL_HAPTIC_ANDROID @SDL_HAPTIC_ANDROID@
+#cmakedefine SDL_LIBUSB_DYNAMIC @SDL_LIBUSB_DYNAMIC@
 
 /* Enable various sensor drivers */
 #cmakedefine SDL_SENSOR_ANDROID @SDL_SENSOR_ANDROID@
+#cmakedefine SDL_SENSOR_COREMOTION @SDL_SENSOR_COREMOTION@
 #cmakedefine SDL_SENSOR_DUMMY @SDL_SENSOR_DUMMY@
 
 /* Enable various shared object loading systems */
@@ -321,9 +323,11 @@
 #cmakedefine SDL_VIDEO_DRIVER_ANDROID @SDL_VIDEO_DRIVER_ANDROID@
 #cmakedefine SDL_VIDEO_DRIVER_HAIKU @SDL_VIDEO_DRIVER_HAIKU@
 #cmakedefine SDL_VIDEO_DRIVER_COCOA @SDL_VIDEO_DRIVER_COCOA@
+#cmakedefine SDL_VIDEO_DRIVER_UIKIT @SDL_VIDEO_DRIVER_UIKIT@
 #cmakedefine SDL_VIDEO_DRIVER_DIRECTFB @SDL_VIDEO_DRIVER_DIRECTFB@
 #cmakedefine SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC @SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC@
 #cmakedefine SDL_VIDEO_DRIVER_DUMMY @SDL_VIDEO_DRIVER_DUMMY@
+#cmakedefine SDL_VIDEO_DRIVER_OFFSCREEN @SDL_VIDEO_DRIVER_OFFSCREEN@
 #cmakedefine SDL_VIDEO_DRIVER_WINDOWS @SDL_VIDEO_DRIVER_WINDOWS@
 #cmakedefine SDL_VIDEO_DRIVER_WAYLAND @SDL_VIDEO_DRIVER_WAYLAND@
 #cmakedefine SDL_VIDEO_DRIVER_RPI @SDL_VIDEO_DRIVER_RPI@
@@ -386,11 +390,15 @@
 /* Enable Vulkan support */
 #cmakedefine SDL_VIDEO_VULKAN @SDL_VIDEO_VULKAN@
 
+/* Enable Metal support */
+#cmakedefine SDL_VIDEO_METAL @SDL_VIDEO_METAL@
+
 /* Enable system power support */
 #cmakedefine SDL_POWER_ANDROID @SDL_POWER_ANDROID@
 #cmakedefine SDL_POWER_LINUX @SDL_POWER_LINUX@
 #cmakedefine SDL_POWER_WINDOWS @SDL_POWER_WINDOWS@
 #cmakedefine SDL_POWER_MACOSX @SDL_POWER_MACOSX@
+#cmakedefine SDL_POWER_UIKIT @SDL_POWER_UIKIT@
 #cmakedefine SDL_POWER_HAIKU @SDL_POWER_HAIKU@
 #cmakedefine SDL_POWER_EMSCRIPTEN @SDL_POWER_EMSCRIPTEN@
 #cmakedefine SDL_POWER_HARDWIRED @SDL_POWER_HARDWIRED@
@@ -407,11 +415,16 @@
 /* Enable assembly routines */
 #cmakedefine SDL_ASSEMBLY_ROUTINES @SDL_ASSEMBLY_ROUTINES@
 #cmakedefine SDL_ALTIVEC_BLITTERS @SDL_ALTIVEC_BLITTERS@
+#cmakedefine SDL_ARM_SIMD_BLITTERS @SDL_ARM_SIMD_BLITTERS@
+#cmakedefine SDL_ARM_NEON_BLITTERS @SDL_ARM_NEON_BLITTERS@
 
 /* Enable dynamic libsamplerate support */
 #cmakedefine SDL_LIBSAMPLERATE_DYNAMIC @SDL_LIBSAMPLERATE_DYNAMIC@
 
 /* Platform specific definitions */
+#cmakedefine SDL_IPHONE_KEYBOARD @SDL_IPHONE_KEYBOARD@
+#cmakedefine SDL_IPHONE_LAUNCHSCREEN @SDL_IPHONE_LAUNCHSCREEN@
+
 #if !defined(__WIN32__)
 #  if !defined(_STDINT_H_) && !defined(_STDINT_H) && !defined(HAVE_STDINT_H) && !defined(_HAVE_STDINT_H)
 typedef unsigned int size_t;

+ 12 - 5
sdl.mod/SDL/include/SDL_config.h.in

@@ -33,7 +33,7 @@
 
 /* Make sure that this isn't included by Visual C++ */
 #ifdef _MSC_VER
-#error You should run hg revert SDL_config.h 
+#error You should run hg revert SDL_config.h
 #endif
 
 /* C language features */
@@ -192,9 +192,9 @@
 #undef HAVE__EXIT
 
 #else
-#define HAVE_STDARG_H   1
-#define HAVE_STDDEF_H   1
-#define HAVE_STDINT_H   1
+#define HAVE_STDARG_H 1
+#define HAVE_STDDEF_H 1
+#define HAVE_STDINT_H 1
 #endif /* HAVE_LIBC */
 
 #undef HAVE_ALTIVEC_H
@@ -210,7 +210,6 @@
 #undef HAVE_DSOUND_H
 #undef HAVE_DXGI_H
 #undef HAVE_XINPUT_H
-#undef HAVE_ENDPOINTVOLUME_H
 #undef HAVE_MMDEVICEAPI_H
 #undef HAVE_AUDIOCLIENT_H
 #undef HAVE_XINPUT_GAMEPAD_EX
@@ -383,6 +382,9 @@
 /* Enable Vulkan support */
 #undef SDL_VIDEO_VULKAN
 
+/* Enable Metal support */
+#undef SDL_VIDEO_METAL
+
 /* Enable system power support */
 #undef SDL_POWER_LINUX
 #undef SDL_POWER_WINDOWS
@@ -405,6 +407,8 @@
 /* Enable assembly routines */
 #undef SDL_ASSEMBLY_ROUTINES
 #undef SDL_ALTIVEC_BLITTERS
+#undef SDL_ARM_SIMD_BLITTERS
+#undef SDL_ARM_NEON_BLITTERS
 
 /* Enable ime support */
 #undef SDL_USE_IME
@@ -412,6 +416,9 @@
 /* Enable dynamic udev support */
 #undef SDL_UDEV_DYNAMIC
 
+/* Enable dynamic libusb support */
+#undef SDL_LIBUSB_DYNAMIC
+
 /* Enable dynamic libsamplerate support */
 #undef SDL_LIBSAMPLERATE_DYNAMIC
 

+ 4 - 0
sdl.mod/SDL/include/SDL_config_iphoneos.h

@@ -181,6 +181,10 @@
 #define SDL_VIDEO_VULKAN 1
 #endif
 
+#if SDL_PLATFORM_SUPPORTS_METAL
+#define SDL_VIDEO_METAL 1
+#endif
+
 /* Enable system power support */
 #define SDL_POWER_UIKIT 1
 

+ 28 - 11
sdl.mod/SDL/include/SDL_config_macosx.h

@@ -130,6 +130,8 @@
 #define HAVE_SYSCONF    1
 #define HAVE_SYSCTLBYNAME 1
 
+#define HAVE_GCC_ATOMICS 1
+
 /* Enable various audio drivers */
 #define SDL_AUDIO_DRIVER_COREAUDIO  1
 #define SDL_AUDIO_DRIVER_DISK   1
@@ -157,13 +159,13 @@
 #define SDL_VIDEO_DRIVER_COCOA  1
 #define SDL_VIDEO_DRIVER_DUMMY  1
 #undef SDL_VIDEO_DRIVER_X11
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC "/usr/X11R6/lib/libX11.6.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT "/usr/X11R6/lib/libXext.6.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA "/usr/X11R6/lib/libXinerama.1.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 "/usr/X11R6/lib/libXi.6.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR "/usr/X11R6/lib/libXrandr.2.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS "/usr/X11R6/lib/libXss.1.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE "/usr/X11R6/lib/libXxf86vm.1.dylib"
+#define SDL_VIDEO_DRIVER_X11_DYNAMIC "/opt/X11/lib/libX11.6.dylib"
+#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT "/opt/X11/lib/libXext.6.dylib"
+#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA "/opt/X11/lib/libXinerama.1.dylib"
+#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 "/opt/X11/lib/libXi.6.dylib"
+#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR "/opt/X11/lib/libXrandr.2.dylib"
+#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS "/opt/X11/lib/libXss.1.dylib"
+#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE "/opt/X11/lib/libXxf86vm.1.dylib"
 #define SDL_VIDEO_DRIVER_X11_XDBE 1
 #define SDL_VIDEO_DRIVER_X11_XINERAMA 1
 #define SDL_VIDEO_DRIVER_X11_XRANDR 1
@@ -191,9 +193,15 @@
 #define SDL_VIDEO_RENDER_OGL_ES2 1
 #endif
 
-#ifndef SDL_VIDEO_RENDER_METAL
 /* Metal only supported on 64-bit architectures with 10.11+ */
 #if TARGET_CPU_X86_64 && (MAC_OS_X_VERSION_MAX_ALLOWED >= 101100)
+#define SDL_PLATFORM_SUPPORTS_METAL    1
+#else
+#define SDL_PLATFORM_SUPPORTS_METAL    0
+#endif
+
+#ifndef SDL_VIDEO_RENDER_METAL
+#if SDL_PLATFORM_SUPPORTS_METAL
 #define SDL_VIDEO_RENDER_METAL    1
 #else
 #define SDL_VIDEO_RENDER_METAL    0
@@ -217,13 +225,22 @@
 #define SDL_VIDEO_OPENGL_GLX    1
 #endif
 
-/* Enable Vulkan support */
-/* Metal/MoltenVK/Vulkan only supported on 64-bit architectures with 10.11+ */
-#if TARGET_CPU_X86_64 && (MAC_OS_X_VERSION_MAX_ALLOWED >= 101100)
+/* Enable Vulkan and Metal support */
+#ifndef SDL_VIDEO_VULKAN
+#if SDL_PLATFORM_SUPPORTS_METAL
 #define SDL_VIDEO_VULKAN 1
 #else
 #define SDL_VIDEO_VULKAN 0
 #endif
+#endif
+
+#ifndef SDL_VIDEO_METAL
+#if SDL_PLATFORM_SUPPORTS_METAL
+#define SDL_VIDEO_METAL 1
+#else
+#define SDL_VIDEO_METAL 0
+#endif
+#endif
 
 /* Enable system power support */
 #define SDL_POWER_MACOSX 1

+ 2 - 3
sdl.mod/SDL/include/SDL_config_windows.h

@@ -84,7 +84,6 @@ typedef unsigned int uintptr_t;
 #define HAVE_XINPUT_H 1
 #define HAVE_MMDEVICEAPI_H 1
 #define HAVE_AUDIOCLIENT_H 1
-#define HAVE_ENDPOINTVOLUME_H 1
 
 /* This is disabled by default to avoid C runtime dependencies and manifest requirements */
 #ifdef HAVE_LIBC
@@ -139,7 +138,7 @@ typedef unsigned int uintptr_t;
 #define HAVE_ATAN2  1
 #define HAVE_ATAN2F 1
 #define HAVE_CEILF  1
-#define HAVE__COPYSIGN  1
+#define HAVE__COPYSIGN 1
 #define HAVE_COS    1
 #define HAVE_COSF   1
 #define HAVE_EXP    1
@@ -168,7 +167,7 @@ typedef unsigned int uintptr_t;
 #define HAVE_STRTOLL 1
 #define HAVE_VSSCANF 1
 #define HAVE_SCALBN 1
-#define HAVE_SCALBNF    1
+#define HAVE_SCALBNF 1
 #endif
 /* This function is available with at least the VC++ 2008 C runtime library */
 #if _MSC_VER >= 1400

+ 0 - 1
sdl.mod/SDL/include/SDL_config_winrt.h

@@ -100,7 +100,6 @@ typedef unsigned int uintptr_t;
 
 #define HAVE_MMDEVICEAPI_H 1
 #define HAVE_AUDIOCLIENT_H 1
-#define HAVE_ENDPOINTVOLUME_H 1
 
 #define HAVE_LIBC 1
 #define STDC_HEADERS 1

+ 72 - 4
sdl.mod/SDL/include/SDL_cpuinfo.h

@@ -70,13 +70,13 @@
 #    if defined(_M_ARM)
 #      include <armintr.h>
 #      include <arm_neon.h>
+#      define __ARM_NEON 1 /* Set __ARM_NEON so that it can be used elsewhere, at compile time */
 #    endif
 #    if defined (_M_ARM64)
-#      include <armintr.h>
-#      include <arm_neon.h>
+#      include <arm64intr.h>
+#      include <arm64_neon.h>
+#      define __ARM_NEON 1 /* Set __ARM_NEON so that it can be used elsewhere, at compile time */
 #    endif
-/* Set __ARM_NEON so that it can be used elsewhere, at compile time */
-#    define __ARM_NEON 1
 #  endif
 #endif
 #if defined(__3dNOW__) && !defined(SDL_DISABLE_MM3DNOW_H)
@@ -186,6 +186,11 @@ extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX2(void);
  */
 extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX512F(void);
 
+/**
+ *  This function returns true if the CPU has ARM SIMD (ARMv6) features.
+ */
+extern DECLSPEC SDL_bool SDLCALL SDL_HasARMSIMD(void);
+
 /**
  *  This function returns true if the CPU has NEON (ARM SIMD) features.
  */
@@ -196,6 +201,69 @@ extern DECLSPEC SDL_bool SDLCALL SDL_HasNEON(void);
  */
 extern DECLSPEC int SDLCALL SDL_GetSystemRAM(void);
 
+/**
+ * \brief Report the alignment this system needs for SIMD allocations.
+ *
+ * This will return the minimum number of bytes to which a pointer must be
+ *  aligned to be compatible with SIMD instructions on the current machine.
+ *  For example, if the machine supports SSE only, it will return 16, but if
+ *  it supports AVX-512F, it'll return 64 (etc). This only reports values for
+ *  instruction sets SDL knows about, so if your SDL build doesn't have
+ *  SDL_HasAVX512F(), then it might return 16 for the SSE support it sees and
+ *  not 64 for the AVX-512 instructions that exist but SDL doesn't know about.
+ *  Plan accordingly.
+ */
+extern DECLSPEC size_t SDLCALL SDL_SIMDGetAlignment(void);
+
+/**
+ * \brief Allocate memory in a SIMD-friendly way.
+ *
+ * This will allocate a block of memory that is suitable for use with SIMD
+ *  instructions. Specifically, it will be properly aligned and padded for
+ *  the system's supported vector instructions.
+ *
+ * The memory returned will be padded such that it is safe to read or write
+ *  an incomplete vector at the end of the memory block. This can be useful
+ *  so you don't have to drop back to a scalar fallback at the end of your
+ *  SIMD processing loop to deal with the final elements without overflowing
+ *  the allocated buffer.
+ *
+ * You must free this memory with SDL_FreeSIMD(), not free() or SDL_free()
+ *  or delete[], etc.
+ *
+ * Note that SDL will only deal with SIMD instruction sets it is aware of;
+ *  for example, SDL 2.0.8 knows that SSE wants 16-byte vectors
+ *  (SDL_HasSSE()), and AVX2 wants 32 bytes (SDL_HasAVX2()), but doesn't
+ *  know that AVX-512 wants 64. To be clear: if you can't decide to use an
+ *  instruction set with an SDL_Has*() function, don't use that instruction
+ *  set with memory allocated through here.
+ *
+ * SDL_AllocSIMD(0) will return a non-NULL pointer, assuming the system isn't
+ *  out of memory.
+ *
+ *  \param len The length, in bytes, of the block to allocated. The actual
+ *             allocated block might be larger due to padding, etc.
+ * \return Pointer to newly-allocated block, NULL if out of memory.
+ *
+ * \sa SDL_SIMDAlignment
+ * \sa SDL_SIMDFree
+ */
+extern DECLSPEC void * SDLCALL SDL_SIMDAlloc(const size_t len);
+
+/**
+ * \brief Deallocate memory obtained from SDL_SIMDAlloc
+ *
+ * It is not valid to use this function on a pointer from anything but
+ *  SDL_SIMDAlloc(). It can't be used on pointers from malloc, realloc,
+ *  SDL_malloc, memalign, new[], etc.
+ *
+ * However, SDL_SIMDFree(NULL) is a legal no-op.
+ *
+ * \sa SDL_SIMDAlloc
+ */
+extern DECLSPEC void SDLCALL SDL_SIMDFree(void *ptr);
+
+/* vi: set ts=4 sw=4 expandtab: */
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 }

+ 3 - 0
sdl.mod/SDL/include/SDL_egl.h

@@ -390,6 +390,9 @@ typedef enum {
 #ifndef WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN 1
 #endif
+#ifndef NOMINMAX   /* don't define min() and max(). */
+#define NOMINMAX
+#endif
 #include <windows.h>
 
 #if __WINRT__

+ 5 - 2
sdl.mod/SDL/include/SDL_endian.h

@@ -42,10 +42,13 @@
 #ifdef __linux__
 #include <endian.h>
 #define SDL_BYTEORDER  __BYTE_ORDER
-#else /* __linux__ */
+#elif defined(__OpenBSD__)
+#include <endian.h>
+#define SDL_BYTEORDER  BYTE_ORDER
+#else
 #if defined(__hppa__) || \
     defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \
-    (defined(__MIPS__) && defined(__MISPEB__)) || \
+    (defined(__MIPS__) && defined(__MIPSEB__)) || \
     defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \
     defined(__sparc__)
 #define SDL_BYTEORDER   SDL_BIG_ENDIAN

+ 5 - 1
sdl.mod/SDL/include/SDL_events.h

@@ -442,6 +442,7 @@ typedef struct SDL_TouchFingerEvent
     float dx;           /**< Normalized in the range -1...1 */
     float dy;           /**< Normalized in the range -1...1 */
     float pressure;     /**< Normalized in the range 0...1 */
+    Uint32 windowID;    /**< The window underneath the finger, if any */
 } SDL_TouchFingerEvent;
 
 
@@ -558,7 +559,7 @@ typedef union SDL_Event
 {
     Uint32 type;                    /**< Event type, shared with all events */
     SDL_CommonEvent common;         /**< Common event data */
-    SDL_DisplayEvent display;       /**< Window event data */
+    SDL_DisplayEvent display;       /**< Display event data */
     SDL_WindowEvent window;         /**< Window event data */
     SDL_KeyboardEvent key;          /**< Keyboard event data */
     SDL_TextEditingEvent edit;      /**< Text editing event data */
@@ -594,6 +595,9 @@ typedef union SDL_Event
     Uint8 padding[56];
 } SDL_Event;
 
+/* Make sure we haven't broken binary compatibility */
+SDL_COMPILE_TIME_ASSERT(SDL_Event, sizeof(SDL_Event) == 56);
+
 
 /* Function prototypes */
 

+ 93 - 11
sdl.mod/SDL/include/SDL_hints.h

@@ -197,6 +197,12 @@ extern "C" {
  */
 #define SDL_HINT_VIDEO_X11_XRANDR           "SDL_VIDEO_X11_XRANDR"
 
+/**
+ *  \brief  A variable forcing the visual ID chosen for new X11 windows
+ *
+ */
+#define SDL_HINT_VIDEO_X11_WINDOW_VISUALID      "SDL_VIDEO_X11_WINDOW_VISUALID"
+
 /**
  *  \brief  A variable controlling whether the X11 _NET_WM_PING protocol should be supported.
  *
@@ -482,6 +488,29 @@ extern "C" {
  */
 #define SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT "SDL_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT"
 
+/**
+ *  \brief  If set, game controller face buttons report their values according to their labels instead of their positional layout.
+ * 
+ *  For example, on Nintendo Switch controllers, normally you'd get:
+ *
+ *      (Y)
+ *  (X)     (B)
+ *      (A)
+ *
+ *  but if this hint is set, you'll get:
+ *
+ *      (X)
+ *  (Y)     (A)
+ *      (B)
+ *
+ *  The variable can be set to the following values:
+ *    "0"       - Report the face buttons by position, as though they were on an Xbox controller.
+ *    "1"       - Report the face buttons by label instead of position
+ *
+ *  The default value is "0".  This hint may be set at any time.
+ */
+#define SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS "SDL_GAMECONTROLLER_USE_BUTTON_LABELS"
+
 /**
  *  \brief  A variable that lets you enable joystick (and gamecontroller) events even when your app is in the background.
  *
@@ -565,17 +594,6 @@ extern "C" {
  */
 #define SDL_HINT_JOYSTICK_HIDAPI_XBOX   "SDL_JOYSTICK_HIDAPI_XBOX"
 
-/**
- *  \brief  A variable controlling whether the HIDAPI driver for Nintendo GameCube controllers should be used.
- *
- *  This variable can be set to the following values:
- *    "0"       - HIDAPI driver is not used
- *    "1"       - HIDAPI driver is used
- *
- *  The default is the value of SDL_HINT_JOYSTICK_HIDAPI
- */
-#define SDL_HINT_JOYSTICK_HIDAPI_GAMECUBE "SDL_JOYSTICK_HIDAPI_GAMECUBE"
-
 /**
  *  \brief  A variable that controls whether Steam Controllers should be exposed using the SDL joystick and game controller APIs
  *
@@ -1121,6 +1139,70 @@ extern "C" {
 
 
 
+/**
+ *  \brief  Controls how the size of the RIFF chunk affects the loading of a WAVE file.
+ *
+ *  The size of the RIFF chunk (which includes all the sub-chunks of the WAVE
+ *  file) is not always reliable. In case the size is wrong, it's possible to
+ *  just ignore it and step through the chunks until a fixed limit is reached.
+ *
+ *  Note that files that have trailing data unrelated to the WAVE file or
+ *  corrupt files may slow down the loading process without a reliable boundary.
+ *  By default, SDL stops after 10000 chunks to prevent wasting time. Use the
+ *  environment variable SDL_WAVE_CHUNK_LIMIT to adjust this value.
+ *
+ *  This variable can be set to the following values:
+ *
+ *    "force"        - Always use the RIFF chunk size as a boundary for the chunk search
+ *    "ignorezero"   - Like "force", but a zero size searches up to 4 GiB (default)
+ *    "ignore"       - Ignore the RIFF chunk size and always search up to 4 GiB
+ *    "maximum"      - Search for chunks until the end of file (not recommended)
+ */
+#define SDL_HINT_WAVE_RIFF_CHUNK_SIZE   "SDL_WAVE_RIFF_CHUNK_SIZE"
+
+/**
+ *  \brief  Controls how a truncated WAVE file is handled.
+ *
+ *  A WAVE file is considered truncated if any of the chunks are incomplete or
+ *  the data chunk size is not a multiple of the block size. By default, SDL
+ *  decodes until the first incomplete block, as most applications seem to do.
+ *
+ *  This variable can be set to the following values:
+ *
+ *    "verystrict" - Raise an error if the file is truncated
+ *    "strict"     - Like "verystrict", but the size of the RIFF chunk is ignored
+ *    "dropframe"  - Decode until the first incomplete sample frame
+ *    "dropblock"  - Decode until the first incomplete block (default)
+ */
+#define SDL_HINT_WAVE_TRUNCATION   "SDL_WAVE_TRUNCATION"
+
+/**
+ *  \brief  Controls how the fact chunk affects the loading of a WAVE file.
+ *
+ *  The fact chunk stores information about the number of samples of a WAVE
+ *  file. The Standards Update from Microsoft notes that this value can be used
+ *  to 'determine the length of the data in seconds'. This is especially useful
+ *  for compressed formats (for which this is a mandatory chunk) if they produce
+ *  multiple sample frames per block and truncating the block is not allowed.
+ *  The fact chunk can exactly specify how many sample frames there should be
+ *  in this case.
+ *
+ *  Unfortunately, most application seem to ignore the fact chunk and so SDL
+ *  ignores it by default as well.
+ *
+ *  This variable can be set to the following values:
+ *
+ *    "truncate"    - Use the number of samples to truncate the wave data if
+ *                    the fact chunk is present and valid
+ *    "strict"      - Like "truncate", but raise an error if the fact chunk
+ *                    is invalid, not present for non-PCM formats, or if the
+ *                    data chunk doesn't have that many samples
+ *    "ignorezero"  - Like "truncate", but ignore fact chunk if the number of
+ *                    samples is zero
+ *    "ignore"      - Ignore fact chunk entirely (default)
+ */
+#define SDL_HINT_WAVE_FACT_CHUNK   "SDL_WAVE_FACT_CHUNK"
+
 /**
  *  \brief  An enumeration of hint priorities
  */

+ 2 - 2
sdl.mod/SDL/include/SDL_keycode.h

@@ -47,7 +47,7 @@ typedef Sint32 SDL_Keycode;
 #define SDLK_SCANCODE_MASK (1<<30)
 #define SDL_SCANCODE_TO_KEYCODE(X)  (X | SDLK_SCANCODE_MASK)
 
-enum
+typedef enum
 {
     SDLK_UNKNOWN = 0,
 
@@ -317,7 +317,7 @@ enum
 
     SDLK_AUDIOREWIND = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOREWIND),
     SDLK_AUDIOFASTFORWARD = SDL_SCANCODE_TO_KEYCODE(SDL_SCANCODE_AUDIOFASTFORWARD)
-};
+} SDL_KeyCode;
 
 /**
  * \brief Enumeration of valid key mods (possibly OR'd together).

+ 2 - 2
sdl.mod/SDL/include/SDL_log.h

@@ -61,7 +61,7 @@ extern "C" {
  *  at the VERBOSE level and all other categories are enabled at the
  *  CRITICAL level.
  */
-enum
+typedef enum
 {
     SDL_LOG_CATEGORY_APPLICATION,
     SDL_LOG_CATEGORY_ERROR,
@@ -94,7 +94,7 @@ enum
        };
      */
     SDL_LOG_CATEGORY_CUSTOM
-};
+} SDL_LogCategory;
 
 /**
  *  \brief The predefined log priorities

+ 5 - 3
sdl.mod/SDL/include/SDL_messagebox.h

@@ -36,9 +36,11 @@ extern "C" {
  */
 typedef enum
 {
-    SDL_MESSAGEBOX_ERROR        = 0x00000010,   /**< error dialog */
-    SDL_MESSAGEBOX_WARNING      = 0x00000020,   /**< warning dialog */
-    SDL_MESSAGEBOX_INFORMATION  = 0x00000040    /**< informational dialog */
+    SDL_MESSAGEBOX_ERROR                 = 0x00000010,   /**< error dialog */
+    SDL_MESSAGEBOX_WARNING               = 0x00000020,   /**< warning dialog */
+    SDL_MESSAGEBOX_INFORMATION           = 0x00000040,   /**< informational dialog */
+    SDL_MESSAGEBOX_BUTTONS_LEFT_TO_RIGHT = 0x00000080,   /**< buttons placed left to right */
+    SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT = 0x00000100    /**< buttons placed right to left */
 } SDL_MessageBoxFlags;
 
 /**

+ 91 - 0
sdl.mod/SDL/include/SDL_metal.h

@@ -0,0 +1,91 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2019 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, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+/**
+ *  \file SDL_metal.h
+ *
+ *  Header file for functions to creating Metal layers and views on SDL windows.
+ */
+
+#ifndef SDL_metal_h_
+#define SDL_metal_h_
+
+#include "SDL_video.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ *  \brief A handle to a CAMetalLayer-backed NSView (macOS) or UIView (iOS/tvOS).
+ *
+ *  \note This can be cast directly to an NSView or UIView.
+ */
+typedef void *SDL_MetalView;
+
+/**
+ *  \name Metal support functions
+ */
+/* @{ */
+
+/**
+ *  \brief Create a CAMetalLayer-backed NSView/UIView and attach it to the
+ *        specified window.
+ *
+ *  On macOS, this does *not* associate a MTLDevice with the CAMetalLayer on its
+ *  own. It is up to user code to do that.
+ *
+ *  The returned handle can be casted directly to a NSView or UIView, and the
+ *  CAMetalLayer can be accessed from the view's 'layer' property.
+ *
+ *  \code
+ *  SDL_MetalView metalview = SDL_Metal_CreateView(window);
+ *  UIView *uiview = (__bridge UIView *)metalview;
+ *  CAMetalLayer *metallayer = (CAMetalLayer *)uiview.layer;
+ *  // [...]
+ *  SDL_Metal_DestroyView(metalview);
+ *  \endcode
+ *
+ *  \sa SDL_Metal_DestroyView
+ */
+extern DECLSPEC SDL_MetalView SDLCALL SDL_Metal_CreateView(SDL_Window * window);
+
+/**
+ *  \brief Destroy an existing SDL_MetalView object.
+ *
+ *  This should be called before SDL_DestroyWindow, if SDL_Metal_CreateView was
+ *  called after SDL_CreateWindow.
+ *
+ *  \sa SDL_Metal_CreateView
+ */
+extern DECLSPEC void SDLCALL SDL_Metal_DestroyView(SDL_MetalView view);
+
+/* @} *//* Metal support functions */
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* SDL_metal_h_ */

+ 3 - 0
sdl.mod/SDL/include/SDL_opengl_glext.h

@@ -40,6 +40,9 @@ extern "C" {
 #ifndef WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN 1
 #endif
+#ifndef NOMINMAX   /* don't define min() and max(). */
+#define NOMINMAX
+#endif
 #include <windows.h>
 #endif
 

+ 10 - 10
sdl.mod/SDL/include/SDL_pixels.h

@@ -48,7 +48,7 @@ extern "C" {
 /* @} */
 
 /** Pixel type. */
-enum
+typedef enum
 {
     SDL_PIXELTYPE_UNKNOWN,
     SDL_PIXELTYPE_INDEX1,
@@ -62,18 +62,18 @@ enum
     SDL_PIXELTYPE_ARRAYU32,
     SDL_PIXELTYPE_ARRAYF16,
     SDL_PIXELTYPE_ARRAYF32
-};
+} SDL_PixelType;
 
 /** Bitmap pixel order, high bit -> low bit. */
-enum
+typedef enum
 {
     SDL_BITMAPORDER_NONE,
     SDL_BITMAPORDER_4321,
     SDL_BITMAPORDER_1234
-};
+} SDL_BitmapOrder;
 
 /** Packed component order, high bit -> low bit. */
-enum
+typedef enum
 {
     SDL_PACKEDORDER_NONE,
     SDL_PACKEDORDER_XRGB,
@@ -84,12 +84,12 @@ enum
     SDL_PACKEDORDER_BGRX,
     SDL_PACKEDORDER_ABGR,
     SDL_PACKEDORDER_BGRA
-};
+} SDL_PackedOrder;
 
 /** Array component order, low byte -> high byte. */
 /* !!! FIXME: in 2.1, make these not overlap differently with
    !!! FIXME:  SDL_PACKEDORDER_*, so we can simplify SDL_ISPIXELFORMAT_ALPHA */
-enum
+typedef enum
 {
     SDL_ARRAYORDER_NONE,
     SDL_ARRAYORDER_RGB,
@@ -98,10 +98,10 @@ enum
     SDL_ARRAYORDER_BGR,
     SDL_ARRAYORDER_BGRA,
     SDL_ARRAYORDER_ABGR
-};
+} SDL_ArrayOrder;
 
 /** Packed component layout. */
-enum
+typedef enum
 {
     SDL_PACKEDLAYOUT_NONE,
     SDL_PACKEDLAYOUT_332,
@@ -112,7 +112,7 @@ enum
     SDL_PACKEDLAYOUT_8888,
     SDL_PACKEDLAYOUT_2101010,
     SDL_PACKEDLAYOUT_1010102
-};
+} SDL_PackedLayout;
 
 #define SDL_DEFINE_PIXELFOURCC(A, B, C, D) SDL_FOURCC(A, B, C, D)
 

+ 21 - 0
sdl.mod/SDL/include/SDL_render.h

@@ -430,10 +430,31 @@ extern DECLSPEC int SDLCALL SDL_LockTexture(SDL_Texture * texture,
                                             const SDL_Rect * rect,
                                             void **pixels, int *pitch);
 
+/**
+ *  \brief Lock a portion of the texture for write-only pixel access.
+ *         Expose it as a SDL surface.
+ *
+ *  \param texture   The texture to lock for access, which was created with
+ *                   ::SDL_TEXTUREACCESS_STREAMING.
+ *  \param rect      A pointer to the rectangle to lock for access. If the rect
+ *                   is NULL, the entire texture will be locked.
+ *  \param surface   This is filled in with a SDL surface representing the locked area
+ *                   Surface is freed internally after calling SDL_UnlockTexture or SDL_DestroyTexture.
+ *
+ *  \return 0 on success, or -1 if the texture is not valid or was not created with ::SDL_TEXTUREACCESS_STREAMING.
+ *
+ *  \sa SDL_UnlockTexture()
+ */
+extern DECLSPEC int SDLCALL SDL_LockTextureToSurface(SDL_Texture *texture,
+                                            const SDL_Rect *rect,
+                                            SDL_Surface **surface);
+
 /**
  *  \brief Unlock a texture, uploading the changes to video memory, if needed.
+ *         If SDL_LockTextureToSurface() was called for locking, the SDL surface is freed.
  *
  *  \sa SDL_LockTexture()
+ *  \sa SDL_LockTextureToSurface()
  */
 extern DECLSPEC void SDLCALL SDL_UnlockTexture(SDL_Texture * texture);
 

+ 49 - 12
sdl.mod/SDL/include/SDL_rwops.h

@@ -176,19 +176,48 @@ extern DECLSPEC void SDLCALL SDL_FreeRW(SDL_RWops * area);
 #define RW_SEEK_END 2       /**< Seek relative to the end of data */
 
 /**
- *  \name Read/write macros
+ *  Return the size of the file in this rwops, or -1 if unknown
+ */
+extern DECLSPEC Sint64 SDLCALL SDL_RWsize(SDL_RWops *context);
+
+/**
+ *  Seek to \c offset relative to \c whence, one of stdio's whence values:
+ *  RW_SEEK_SET, RW_SEEK_CUR, RW_SEEK_END
  *
- *  Macros to easily read and write from an SDL_RWops structure.
+ *  \return the final offset in the data stream, or -1 on error.
  */
-/* @{ */
-#define SDL_RWsize(ctx)         (ctx)->size(ctx)
-#define SDL_RWseek(ctx, offset, whence) (ctx)->seek(ctx, offset, whence)
-#define SDL_RWtell(ctx)         (ctx)->seek(ctx, 0, RW_SEEK_CUR)
-#define SDL_RWread(ctx, ptr, size, n)   (ctx)->read(ctx, ptr, size, n)
-#define SDL_RWwrite(ctx, ptr, size, n)  (ctx)->write(ctx, ptr, size, n)
-#define SDL_RWclose(ctx)        (ctx)->close(ctx)
-/* @} *//* Read/write macros */
+extern DECLSPEC Sint64 SDLCALL SDL_RWseek(SDL_RWops *context,
+                                          Sint64 offset, int whence);
+
+/**
+ *  Return the current offset in the data stream, or -1 on error.
+ */
+extern DECLSPEC Sint64 SDLCALL SDL_RWtell(SDL_RWops *context);
 
+/**
+ *  Read up to \c maxnum objects each of size \c size from the data
+ *  stream to the area pointed at by \c ptr.
+ *
+ *  \return the number of objects read, or 0 at error or end of file.
+ */
+extern DECLSPEC size_t SDLCALL SDL_RWread(SDL_RWops *context,
+                                          void *ptr, size_t size, size_t maxnum);
+
+/**
+ *  Write exactly \c num objects each of size \c size from the area
+ *  pointed at by \c ptr to data stream.
+ *
+ *  \return the number of objects written, or 0 at error or end of file.
+ */
+extern DECLSPEC size_t SDLCALL SDL_RWwrite(SDL_RWops *context,
+                                           const void *ptr, size_t size, size_t num);
+
+/**
+ *  Close and free an allocated SDL_RWops structure.
+ *
+ *  \return 0 if successful or -1 on write error when flushing data.
+ */
+extern DECLSPEC int SDLCALL SDL_RWclose(SDL_RWops *context);
 
 /**
  *  Load all the data from an SDL data stream.
@@ -209,9 +238,17 @@ extern DECLSPEC void *SDLCALL SDL_LoadFile_RW(SDL_RWops * src, size_t *datasize,
 /**
  *  Load an entire file.
  *
- *  Convenience macro.
+ *  The data is allocated with a zero byte at the end (null terminated)
+ *
+ *  If \c datasize is not NULL, it is filled with the size of the data read.
+ *
+ *  If \c freesrc is non-zero, the stream will be closed after being read.
+ *
+ *  The data should be freed with SDL_free().
+ *
+ *  \return the data, or NULL if there was an error.
  */
-#define SDL_LoadFile(file, datasize)   SDL_LoadFile_RW(SDL_RWFromFile(file, "rb"), datasize, 1)
+extern DECLSPEC void *SDLCALL SDL_LoadFile(const char *file, size_t *datasize);
 
 /**
  *  \name Read endian functions

+ 4 - 1
sdl.mod/SDL/include/SDL_stdinc.h

@@ -415,11 +415,14 @@ extern DECLSPEC void *SDLCALL SDL_memset(SDL_OUT_BYTECAP(len) void *dst, int c,
 
 #define SDL_zero(x) SDL_memset(&(x), 0, sizeof((x)))
 #define SDL_zerop(x) SDL_memset((x), 0, sizeof(*(x)))
+#define SDL_zeroa(x) SDL_memset((x), 0, sizeof((x)))
 
 /* Note that memset() is a byte assignment and this is a 32-bit assignment, so they're not directly equivalent. */
 SDL_FORCE_INLINE void SDL_memset4(void *dst, Uint32 val, size_t dwords)
 {
-#if defined(__GNUC__) && defined(i386)
+#ifdef __APPLE__
+    memset_pattern4(dst, &val, dwords * 4);
+#elif defined(__GNUC__) && defined(i386)
     int u0, u1, u2;
     __asm__ __volatile__ (
         "cld \n\t"

+ 3 - 0
sdl.mod/SDL/include/SDL_syswm.h

@@ -49,6 +49,9 @@ struct SDL_SysWMinfo;
 #ifndef WIN32_LEAN_AND_MEAN
 #define WIN32_LEAN_AND_MEAN
 #endif
+#ifndef NOMINMAX   /* don't define min() and max(). */
+#define NOMINMAX
+#endif
 #include <windows.h>
 #endif
 

+ 1 - 1
sdl.mod/SDL/include/SDL_version.h

@@ -59,7 +59,7 @@ typedef struct SDL_version
 */
 #define SDL_MAJOR_VERSION   2
 #define SDL_MINOR_VERSION   0
-#define SDL_PATCHLEVEL      9
+#define SDL_PATCHLEVEL      11
 
 /**
  *  \brief Macro to determine SDL version program was compiled against.

+ 0 - 1
sdl.mod/SDL/include/SDL_video.h

@@ -96,7 +96,6 @@ typedef struct SDL_Window SDL_Window;
  */
 typedef enum
 {
-    /* !!! FIXME: change this to name = (1<<x). */
     SDL_WINDOW_FULLSCREEN = 0x00000001,         /**< fullscreen window */
     SDL_WINDOW_OPENGL = 0x00000002,             /**< window usable with OpenGL context */
     SDL_WINDOW_SHOWN = 0x00000004,              /**< window is visible */

+ 3 - 3
sdl.mod/SDL/include/SDL_vulkan.h

@@ -98,8 +98,8 @@ typedef VkSurfaceKHR SDL_vulkanSurface; /* for compatibility with Tizen */
  *        applications to link with libvulkan (and historically MoltenVK was
  *        provided as a static library). If it is not found then, on macOS, SDL
  *        will attempt to load \c vulkan.framework/vulkan, \c libvulkan.1.dylib,
- *        \c MoltenVK.framework/MoltenVK and \c libMoltenVK.dylib in that order.
- *        On iOS SDL will attempt to load \c libMoltenVK.dylib. Applications
+ *        followed by \c libvulkan.dylib, in that order.
+ *        On iOS SDL will attempt to load \c libvulkan.dylib only. Applications
  *        using a dynamic framework or .dylib must ensure it is included in its
  *        application bundle.
  *
@@ -153,7 +153,7 @@ extern DECLSPEC void SDLCALL SDL_Vulkan_UnloadLibrary(void);
  *  is smaller than the number of required extensions, \c SDL_FALSE will be
  *  returned instead of \c SDL_TRUE, to indicate that not all the required
  *  extensions were returned.
- * 
+ *
  *  \note If \c window is not NULL, it will be checked against its creation
  *        flags to ensure that the Vulkan flag is present. This parameter
  *        will be removed in a future major release.

+ 3 - 0
sdl.mod/SDL/include/begin_code.h

@@ -105,6 +105,9 @@
 #ifdef _MSC_VER
 #pragma warning(disable: 4103)
 #endif
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wpragma-pack"
+#endif
 #ifdef __BORLANDC__
 #pragma nopackwarning
 #endif

+ 36 - 0
sdl.mod/SDL/src/SDL.c

@@ -22,6 +22,14 @@
 
 #if defined(__WIN32__)
 #include "core/windows/SDL_windows.h"
+#elif defined(__OS2__)
+#include <stdlib.h> /* For _exit() */
+#elif !defined(__WINRT__)
+#include <unistd.h> /* For _exit(), etc. */
+#endif
+
+#if defined(__EMSCRIPTEN__)
+#include <emscripten.h>
 #endif
 
 /* Initialization code for SDL */
@@ -45,6 +53,34 @@ extern int SDL_HelperWindowDestroy(void);
 #endif
 
 
+/* This is not declared in any header, although it is shared between some
+    parts of SDL, because we don't want anything calling it without an
+    extremely good reason. */
+extern SDL_NORETURN void SDL_ExitProcess(int exitcode);
+SDL_NORETURN void SDL_ExitProcess(const int exitcode)
+{
+#ifdef __WIN32__
+    /* "if you do not know the state of all threads in your process, it is
+       better to call TerminateProcess than ExitProcess"
+       https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658(v=vs.85).aspx */
+    TerminateProcess(GetCurrentProcess(), exitcode);
+    /* MingW doesn't have TerminateProcess marked as noreturn, so add an
+       ExitProcess here that will never be reached but make MingW happy. */
+    ExitProcess(exitcode);
+#elif defined(__EMSCRIPTEN__)
+    emscripten_cancel_main_loop();  /* this should "kill" the app. */
+    emscripten_force_exit(exitcode);  /* this should "kill" the app. */
+    exit(exitcode);
+#elif defined(__HAIKU__)  /* Haiku has _Exit, but it's not marked noreturn. */
+    _exit(exitcode);
+#elif defined(HAVE__EXIT) /* Upper case _Exit() */
+    _Exit(exitcode);
+#else
+    _exit(exitcode);
+#endif
+}
+
+
 /* The initialized subsystems */
 #ifdef SDL_MAIN_NEEDED
 static SDL_bool SDL_MainIsReady = SDL_FALSE;

+ 12 - 29
sdl.mod/SDL/src/SDL_assert.c

@@ -36,12 +36,9 @@
 #ifndef WS_OVERLAPPEDWINDOW
 #define WS_OVERLAPPEDWINDOW 0
 #endif
-#else  /* fprintf, _exit(), etc. */
+#else  /* fprintf, etc. */
 #include <stdio.h>
 #include <stdlib.h>
-#if ! defined(__WINRT__)
-#include <unistd.h>
-#endif
 #endif
 
 #if defined(__EMSCRIPTEN__)
@@ -120,35 +117,21 @@ static void SDL_GenerateAssertionReport(void)
 }
 
 
+/* This is not declared in any header, although it is shared between some
+    parts of SDL, because we don't want anything calling it without an
+    extremely good reason. */
 #if defined(__WATCOMC__)
+extern void SDL_ExitProcess(int exitcode);
 #pragma aux SDL_ExitProcess aborts;
 #endif
-static void SDL_ExitProcess(int exitcode)
-{
-#ifdef __WIN32__
-    /* "if you do not know the state of all threads in your process, it is
-       better to call TerminateProcess than ExitProcess"
-       https://msdn.microsoft.com/en-us/library/windows/desktop/ms682658(v=vs.85).aspx */
-    TerminateProcess(GetCurrentProcess(), exitcode);
-
-#elif defined(__EMSCRIPTEN__)
-    emscripten_cancel_main_loop();  /* this should "kill" the app. */
-    emscripten_force_exit(exitcode);  /* this should "kill" the app. */
-    exit(exitcode);
-#else
-#ifdef HAVE__EXIT /* Upper case _Exit() */
-    _Exit(exitcode);
-#else
-    _exit(exitcode);
-#endif
-#endif
-}
+extern SDL_NORETURN void SDL_ExitProcess(int exitcode);
 
 
 #if defined(__WATCOMC__)
+static void SDL_AbortAssertion (void);
 #pragma aux SDL_AbortAssertion aborts;
 #endif
-static void SDL_AbortAssertion(void)
+static SDL_NORETURN void SDL_AbortAssertion(void)
 {
     SDL_Quit();
     SDL_ExitProcess(42);
@@ -374,10 +357,6 @@ SDL_ReportAssertion(SDL_assert_data *data, const char *func, const char *file,
 
     switch (state)
     {
-        case SDL_ASSERTION_ABORT:
-            SDL_AbortAssertion();
-            return SDL_ASSERTION_IGNORE;  /* shouldn't return, but oh well. */
-
         case SDL_ASSERTION_ALWAYS_IGNORE:
             state = SDL_ASSERTION_IGNORE;
             data->always_ignore = 1;
@@ -387,6 +366,10 @@ SDL_ReportAssertion(SDL_assert_data *data, const char *func, const char *file,
         case SDL_ASSERTION_RETRY:
         case SDL_ASSERTION_BREAK:
             break;  /* macro handles these. */
+
+        case SDL_ASSERTION_ABORT:
+            SDL_AbortAssertion();
+            /*break;  ...shouldn't return, but oh well. */
     }
 
     assertion_running--;

+ 0 - 10
sdl.mod/SDL/src/SDL_error.c

@@ -26,16 +26,6 @@
 #include "SDL_error.h"
 #include "SDL_error_c.h"
 
-
-/* Routine to get the thread-specific error variable */
-#if SDL_THREADS_DISABLED
-/* The default (non-thread-safe) global error variable */
-static SDL_error SDL_global_error;
-#define SDL_GetErrBuf() (&SDL_global_error)
-#else
-extern SDL_error *SDL_GetErrBuf(void);
-#endif /* SDL_THREADS_DISABLED */
-
 #define SDL_ERRBUFIZE   1024
 
 /* Private functions */

+ 2 - 2
sdl.mod/SDL/src/SDL_log.c

@@ -400,8 +400,8 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
         SDL_snprintf(tag, SDL_arraysize(tag), "SDL/%s", GetCategoryPrefix(category));
         __android_log_write(SDL_android_priority[priority], tag, message);
     }
-#elif defined(__APPLE__) && defined(SDL_VIDEO_DRIVER_COCOA)
-    /* Technically we don't need SDL_VIDEO_DRIVER_COCOA, but that's where this function is defined for now.
+#elif defined(__APPLE__) && (defined(SDL_VIDEO_DRIVER_COCOA) || defined(SDL_VIDEO_DRIVER_UIKIT))
+    /* Technically we don't need Cocoa/UIKit, but that's where this function is defined for now.
     */
     extern void SDL_NSLog(const char *text);
     {

+ 4 - 0
sdl.mod/SDL/src/atomic/SDL_atomic.c

@@ -289,6 +289,10 @@ SDL_AtomicGetPtr(void **a)
 #endif
 }
 
+#ifdef SDL_MEMORY_BARRIER_USES_FUNCTION
+#error This file should be built in arm mode so the mcr instruction is available for memory barriers
+#endif
+
 void
 SDL_MemoryBarrierReleaseFunction(void)
 {

+ 12 - 14
sdl.mod/SDL/src/audio/SDL_audio.c

@@ -248,12 +248,6 @@ SDL_AudioPlayDevice_Default(_THIS)
 {                               /* no-op. */
 }
 
-static int
-SDL_AudioGetPendingBytes_Default(_THIS)
-{
-    return 0;
-}
-
 static Uint8 *
 SDL_AudioGetDeviceBuf_Default(_THIS)
 {
@@ -361,7 +355,6 @@ finish_audio_entry_points_init(void)
     FILL_STUB(BeginLoopIteration);
     FILL_STUB(WaitDevice);
     FILL_STUB(PlayDevice);
-    FILL_STUB(GetPendingBytes);
     FILL_STUB(GetDeviceBuf);
     FILL_STUB(CaptureFromDevice);
     FILL_STUB(FlushCapture);
@@ -654,11 +647,9 @@ SDL_GetQueuedAudioSize(SDL_AudioDeviceID devid)
     }
 
     /* Nothing to do unless we're set up for queueing. */
-    if (device->callbackspec.callback == SDL_BufferQueueDrainCallback) {
-        current_audio.impl.LockDevice(device);
-        retval = ((Uint32) SDL_CountDataQueue(device->buffer_queue)) + current_audio.impl.GetPendingBytes(device);
-        current_audio.impl.UnlockDevice(device);
-    } else if (device->callbackspec.callback == SDL_BufferQueueFillCallback) {
+    if (device->callbackspec.callback == SDL_BufferQueueDrainCallback ||
+        device->callbackspec.callback == SDL_BufferQueueFillCallback)
+    {
         current_audio.impl.LockDevice(device);
         retval = (Uint32) SDL_CountDataQueue(device->buffer_queue);
         current_audio.impl.UnlockDevice(device);
@@ -957,7 +948,7 @@ SDL_AudioInit(const char *driver_name)
     }
 
     SDL_zero(current_audio);
-    SDL_zero(open_devices);
+    SDL_zeroa(open_devices);
 
     /* Select the proper audio driver */
     if (driver_name == NULL) {
@@ -1617,7 +1608,7 @@ SDL_AudioQuit(void)
     SDL_DestroyMutex(current_audio.detectionLock);
 
     SDL_zero(current_audio);
-    SDL_zero(open_devices);
+    SDL_zeroa(open_devices);
 
 #ifdef HAVE_LIBSAMPLERATE_H
     UnloadLibSampleRate();
@@ -1678,8 +1669,15 @@ SDL_CalculateAudioSpec(SDL_AudioSpec * spec)
 {
     switch (spec->format) {
     case AUDIO_U8:
+
+    // !!! FIXME: 0x80 isn't perfect for U16, but we can't fit 0x8000 in a
+    // !!! FIXME:  byte for memset() use. This is actually 0.1953 percent off
+    //  from silence. Maybe just don't use U16.
+    case AUDIO_U16LSB:
+    case AUDIO_U16MSB:
         spec->silence = 0x80;
         break;
+
     default:
         spec->silence = 0x00;
         break;

+ 16 - 6
sdl.mod/SDL/src/audio/SDL_audiocvt.c

@@ -718,9 +718,15 @@ SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format
     /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
     float *dst = (float *) (cvt->buf + srclen);
     const int dstlen = (cvt->len * cvt->len_mult) - srclen;
-    const int paddingsamples = (ResamplerPadding(inrate, outrate) * chans);
+    const int requestedpadding = ResamplerPadding(inrate, outrate);
+    int paddingsamples;
     float *padding;
 
+    if (requestedpadding < SDL_MAX_SINT32 / chans) {
+        paddingsamples = requestedpadding * chans;
+    } else {
+        paddingsamples = 0;
+    }
     SDL_assert(format == AUDIO_F32SYS);
 
     /* we keep no streaming state here, so pad with silence on both ends. */
@@ -889,10 +895,14 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
         return SDL_SetError("Invalid source channels");
     } else if (!SDL_SupportedChannelCount(dst_channels)) {
         return SDL_SetError("Invalid destination channels");
-    } else if (src_rate == 0) {
-        return SDL_SetError("Source rate is zero");
-    } else if (dst_rate == 0) {
-        return SDL_SetError("Destination rate is zero");
+    } else if (src_rate <= 0) {
+        return SDL_SetError("Source rate is equal to or less than zero");
+    } else if (dst_rate <= 0) {
+        return SDL_SetError("Destination rate is equal to or less than zero");
+    } else if (src_rate >= SDL_MAX_SINT32 / RESAMPLER_SAMPLES_PER_ZERO_CROSSING) {
+        return SDL_SetError("Source rate is too high");
+    } else if (dst_rate >= SDL_MAX_SINT32 / RESAMPLER_SAMPLES_PER_ZERO_CROSSING) {
+        return SDL_SetError("Destination rate is too high");
     }
 
 #if DEBUG_CONVERT
@@ -905,7 +915,7 @@ SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
     cvt->dst_format = dst_fmt;
     cvt->needed = 0;
     cvt->filter_index = 0;
-    SDL_zero(cvt->filters);
+    SDL_zeroa(cvt->filters);
     cvt->len_mult = 1;
     cvt->len_ratio = 1.0;
     cvt->rate_incr = ((double) dst_rate) / ((double) src_rate);

+ 21 - 22
sdl.mod/SDL/src/audio/SDL_audiotypecvt.c

@@ -25,8 +25,7 @@
 #include "SDL_cpuinfo.h"
 #include "SDL_assert.h"
 
-/* !!! FIXME: disabled until we fix https://bugzilla.libsdl.org/show_bug.cgi?id=4186 */
-#if 0 /*def __ARM_NEON */
+#ifdef __ARM_NEON
 #define HAVE_NEON_INTRINSICS 1
 #endif
 
@@ -483,7 +482,7 @@ SDL_Convert_U16_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
     if ((((size_t) src) & 15) == 0) {
         /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
         const __m128 divby32768 = _mm_set1_ps(DIVBY32768);
-        const __m128 minus1 = _mm_set1_ps(1.0f);
+        const __m128 minus1 = _mm_set1_ps(-1.0f);
         while (i >= 8) {   /* 8 * 16-bit */
             const __m128i ints = _mm_load_si128((__m128i const *) src);  /* get 8 sint16 into an XMM register. */
             /* treat as int32, shift left to clear every other sint16, then back right with zero-extend. Now sint32. */
@@ -526,9 +525,9 @@ SDL_Convert_S32_to_F32_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
     }
 
     SDL_assert(!i || ((((size_t) dst) & 15) == 0));
-    SDL_assert(!i || ((((size_t) src) & 15) == 0));
 
-    {
+    /* Make sure src is aligned too. */
+    if ((((size_t) src) & 15) == 0) {
         /* Aligned! Do SSE blocks as long as we have 16 bytes available. */
         const __m128 divby8388607 = _mm_set1_ps(DIVBY8388607);
         const __m128i *mmsrc = (const __m128i *) src;
@@ -615,7 +614,7 @@ static void SDLCALL
 SDL_Convert_F32_to_U8_SSE2(SDL_AudioCVT *cvt, SDL_AudioFormat format)
 {
     const float *src = (const float *) cvt->buf;
-    Uint8 *dst = (Uint8 *) cvt->buf;
+    Uint8 *dst = cvt->buf;
     int i;
 
     LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U8 (using SSE2)");
@@ -880,10 +879,10 @@ SDL_Convert_S8_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
             const int16x8_t int16hi = vmovl_s8(vget_high_s8(bytes));  /* convert top 8 bytes to 8 int16 */
             const int16x8_t int16lo = vmovl_s8(vget_low_s8(bytes));   /* convert bottom 8 bytes to 8 int16 */
             /* split int16 to two int32, then convert to float, then multiply to normalize, store. */
-            vst1q_f32(dst, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(int16hi))), divby128));
-            vst1q_f32(dst+4, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(int16hi))), divby128));
-            vst1q_f32(dst+8, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(int16lo))), divby128));
-            vst1q_f32(dst+12, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(int16lo))), divby128));
+            vst1q_f32(dst, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(int16lo))), divby128));
+            vst1q_f32(dst+4, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(int16lo))), divby128));
+            vst1q_f32(dst+8, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_low_s16(int16hi))), divby128));
+            vst1q_f32(dst+12, vmulq_f32(vcvtq_f32_s32(vmovl_s16(vget_high_s16(int16hi))), divby128));
             i -= 16; mmsrc -= 16; dst -= 16;
         }
 
@@ -926,16 +925,16 @@ SDL_Convert_U8_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
         /* Aligned! Do NEON blocks as long as we have 16 bytes available. */
         const uint8_t *mmsrc = (const uint8_t *) src;
         const float32x4_t divby128 = vdupq_n_f32(DIVBY128);
-        const float32x4_t one = vdupq_n_f32(1.0f);
+        const float32x4_t negone = vdupq_n_f32(-1.0f);
         while (i >= 16) {   /* 16 * 8-bit */
             const uint8x16_t bytes = vld1q_u8(mmsrc);  /* get 16 uint8 into a NEON register. */
             const uint16x8_t uint16hi = vmovl_u8(vget_high_u8(bytes));  /* convert top 8 bytes to 8 uint16 */
             const uint16x8_t uint16lo = vmovl_u8(vget_low_u8(bytes));   /* convert bottom 8 bytes to 8 uint16 */
             /* split uint16 to two uint32, then convert to float, then multiply to normalize, subtract to adjust for sign, store. */
-            vst1q_f32(dst, vmlsq_f32(vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16hi))), divby128, one));
-            vst1q_f32(dst+4, vmlsq_f32(vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16hi))), divby128, one));
-            vst1q_f32(dst+8, vmlsq_f32(vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16lo))), divby128, one));
-            vst1q_f32(dst+12, vmlsq_f32(vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16lo))), divby128, one));
+            vst1q_f32(dst, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16lo))), divby128));
+            vst1q_f32(dst+4, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16lo))), divby128));
+            vst1q_f32(dst+8, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uint16hi))), divby128));
+            vst1q_f32(dst+12, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uint16hi))), divby128));
             i -= 16; mmsrc -= 16; dst -= 16;
         }
 
@@ -1021,12 +1020,12 @@ SDL_Convert_U16_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
     if ((((size_t) src) & 15) == 0) {
         /* Aligned! Do NEON blocks as long as we have 16 bytes available. */
         const float32x4_t divby32768 = vdupq_n_f32(DIVBY32768);
-        const float32x4_t one = vdupq_n_f32(1.0f);
+        const float32x4_t negone = vdupq_n_f32(-1.0f);
         while (i >= 8) {   /* 8 * 16-bit */
             const uint16x8_t uints = vld1q_u16((uint16_t const *) src);  /* get 8 uint16 into a NEON register. */
             /* split uint16 to two int32, then convert to float, then multiply to normalize, subtract for sign, store. */
-            vst1q_f32(dst, vmlsq_f32(one, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uints))), divby32768));
-            vst1q_f32(dst+4, vmlsq_f32(one, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uints))), divby32768));
+            vst1q_f32(dst, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_low_u16(uints))), divby32768));
+            vst1q_f32(dst+4, vmlaq_f32(negone, vcvtq_f32_u32(vmovl_u16(vget_high_u16(uints))), divby32768));
             i -= 8; src -= 8; dst -= 8;
         }
     }
@@ -1060,9 +1059,9 @@ SDL_Convert_S32_to_F32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
     }
 
     SDL_assert(!i || ((((size_t) dst) & 15) == 0));
-    SDL_assert(!i || ((((size_t) src) & 15) == 0));
 
-    {
+    /* Make sure src is aligned too. */
+    if ((((size_t) src) & 15) == 0) {
         /* Aligned! Do NEON blocks as long as we have 16 bytes available. */
         const float32x4_t divby8388607 = vdupq_n_f32(DIVBY8388607);
         const int32_t *mmsrc = (const int32_t *) src;
@@ -1341,7 +1340,7 @@ SDL_Convert_F32_to_S32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
         if (sample >= 1.0f) {
             *dst = 2147483647;
         } else if (sample <= -1.0f) {
-            *dst = -2147483648;
+            *dst = (-2147483647) - 1;
         } else {
             *dst = ((Sint32)(sample * 8388607.0f)) << 8;
         }
@@ -1369,7 +1368,7 @@ SDL_Convert_F32_to_S32_NEON(SDL_AudioCVT *cvt, SDL_AudioFormat format)
         if (sample >= 1.0f) {
             *dst = 2147483647;
         } else if (sample <= -1.0f) {
-            *dst = -2147483648;
+            *dst = (-2147483647) - 1;
         } else {
             *dst = ((Sint32)(sample * 8388607.0f)) << 8;
         }

+ 0 - 1
sdl.mod/SDL/src/audio/SDL_sysaudio.h

@@ -71,7 +71,6 @@ typedef struct SDL_AudioDriverImpl
     void (*BeginLoopIteration)(_THIS);  /* Called by audio thread at top of loop */
     void (*WaitDevice) (_THIS);
     void (*PlayDevice) (_THIS);
-    int (*GetPendingBytes) (_THIS);
     Uint8 *(*GetDeviceBuf) (_THIS);
     int (*CaptureFromDevice) (_THIS, void *buffer, int buflen);
     void (*FlushCapture) (_THIS);

+ 2024 - 565
sdl.mod/SDL/src/audio/SDL_wave.c

@@ -20,675 +20,2134 @@
 */
 #include "../SDL_internal.h"
 
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#else
+#ifndef SIZE_MAX
+#define SIZE_MAX ((size_t)-1)
+#endif
+#ifndef INT_MAX
+/* Make a lucky guess. */
+#define INT_MAX SDL_MAX_SINT32
+#endif
+#endif
+
 /* Microsoft WAVE file loading routines */
 
-#include "SDL_audio.h"
-#include "SDL_wave.h"
+#include "SDL_log.h"
+#include "SDL_hints.h"
+#include "SDL_audio.h"
+#include "SDL_wave.h"
+
+/* Reads the value stored at the location of the f1 pointer, multiplies it
+ * with the second argument and then stores the result to f1.
+ * Returns 0 on success, or -1 if the multiplication overflows, in which case f1
+ * does not get modified.
+ */
+static int
+SafeMult(size_t *f1, size_t f2)
+{
+    if (*f1 > 0 && SIZE_MAX / *f1 <= f2) {
+        return -1;
+    }
+    *f1 *= f2;
+    return 0;
+}
+
+typedef struct ADPCM_DecoderState
+{
+    Uint32 channels;        /* Number of channels. */
+    size_t blocksize;       /* Size of an ADPCM block in bytes. */
+    size_t blockheadersize; /* Size of an ADPCM block header in bytes. */
+    size_t samplesperblock; /* Number of samples per channel in an ADPCM block. */
+    size_t framesize;       /* Size of a sample frame (16-bit PCM) in bytes. */
+    Sint64 framestotal;     /* Total number of sample frames. */
+    Sint64 framesleft;      /* Number of sample frames still to be decoded. */
+    void *ddata;            /* Decoder data from initialization. */
+    void *cstate;           /* Decoding state for each channel. */
+
+    /* ADPCM data. */
+    struct {
+        Uint8 *data;
+        size_t size;
+        size_t pos;
+    } input;
+
+    /* Current ADPCM block in the ADPCM data above. */
+    struct {
+        Uint8 *data;
+        size_t size;
+        size_t pos;
+    } block;
+
+    /* Decoded 16-bit PCM data. */
+    struct {
+        Sint16 *data;
+        size_t size;
+        size_t pos;
+    } output;
+} ADPCM_DecoderState;
+
+typedef struct MS_ADPCM_CoeffData
+{
+    Uint16 coeffcount;
+    Sint16 *coeff;
+    Sint16 aligndummy; /* Has to be last member. */
+} MS_ADPCM_CoeffData;
+
+typedef struct MS_ADPCM_ChannelState
+{
+    Uint16 delta;
+    Sint16 coeff1;
+    Sint16 coeff2;
+} MS_ADPCM_ChannelState;
+
+#ifdef SDL_WAVE_DEBUG_LOG_FORMAT
+static void
+WaveDebugLogFormat(WaveFile *file)
+{
+    WaveFormat *format = &file->format;
+    const char *fmtstr = "WAVE file: %s, %u Hz, %s, %u bits, %u %s/s";
+    const char *waveformat, *wavechannel, *wavebpsunit = "B";
+    Uint32 wavebps = format->byterate;
+    char channelstr[64];
+
+    SDL_zeroa(channelstr);
+
+    switch (format->encoding) {
+    case PCM_CODE:
+        waveformat = "PCM";
+        break;
+    case IEEE_FLOAT_CODE:
+        waveformat = "IEEE Float";
+        break;
+    case ALAW_CODE:
+        waveformat = "A-law";
+        break;
+    case MULAW_CODE:
+        waveformat = "\xc2\xb5-law";
+        break;
+    case MS_ADPCM_CODE:
+        waveformat = "MS ADPCM";
+        break;
+    case IMA_ADPCM_CODE:
+        waveformat = "IMA ADPCM";
+        break;
+    default:
+        waveformat = "Unknown";
+        break;
+    }
+
+#define SDL_WAVE_DEBUG_CHANNELCFG(STR, CODE) case CODE: wavechannel = STR; break;
+#define SDL_WAVE_DEBUG_CHANNELSTR(STR, CODE) if (format->channelmask & CODE) { \
+    SDL_strlcat(channelstr, channelstr[0] ? "-" STR : STR, sizeof(channelstr));}
+
+    if (format->formattag == EXTENSIBLE_CODE && format->channelmask > 0) {
+        switch (format->channelmask) {
+            SDL_WAVE_DEBUG_CHANNELCFG("1.0 Mono",         0x4)
+            SDL_WAVE_DEBUG_CHANNELCFG("1.1 Mono",         0xc)
+            SDL_WAVE_DEBUG_CHANNELCFG("2.0 Stereo",       0x3)
+            SDL_WAVE_DEBUG_CHANNELCFG("2.1 Stereo",       0xb)
+            SDL_WAVE_DEBUG_CHANNELCFG("3.0 Stereo",       0x7)
+            SDL_WAVE_DEBUG_CHANNELCFG("3.1 Stereo",       0xf)
+            SDL_WAVE_DEBUG_CHANNELCFG("3.0 Surround",     0x103)
+            SDL_WAVE_DEBUG_CHANNELCFG("3.1 Surround",     0x10b)
+            SDL_WAVE_DEBUG_CHANNELCFG("4.0 Quad",         0x33)
+            SDL_WAVE_DEBUG_CHANNELCFG("4.1 Quad",         0x3b)
+            SDL_WAVE_DEBUG_CHANNELCFG("4.0 Surround",     0x107)
+            SDL_WAVE_DEBUG_CHANNELCFG("4.1 Surround",     0x10f)
+            SDL_WAVE_DEBUG_CHANNELCFG("5.0",              0x37)
+            SDL_WAVE_DEBUG_CHANNELCFG("5.1",              0x3f)
+            SDL_WAVE_DEBUG_CHANNELCFG("5.0 Side",         0x607)
+            SDL_WAVE_DEBUG_CHANNELCFG("5.1 Side",         0x60f)
+            SDL_WAVE_DEBUG_CHANNELCFG("6.0",              0x137)
+            SDL_WAVE_DEBUG_CHANNELCFG("6.1",              0x13f)
+            SDL_WAVE_DEBUG_CHANNELCFG("6.0 Side",         0x707)
+            SDL_WAVE_DEBUG_CHANNELCFG("6.1 Side",         0x70f)
+            SDL_WAVE_DEBUG_CHANNELCFG("7.0",              0xf7)
+            SDL_WAVE_DEBUG_CHANNELCFG("7.1",              0xff)
+            SDL_WAVE_DEBUG_CHANNELCFG("7.0 Side",         0x6c7)
+            SDL_WAVE_DEBUG_CHANNELCFG("7.1 Side",         0x6cf)
+            SDL_WAVE_DEBUG_CHANNELCFG("7.0 Surround",     0x637)
+            SDL_WAVE_DEBUG_CHANNELCFG("7.1 Surround",     0x63f)
+            SDL_WAVE_DEBUG_CHANNELCFG("9.0 Surround",     0x5637)
+            SDL_WAVE_DEBUG_CHANNELCFG("9.1 Surround",     0x563f)
+            SDL_WAVE_DEBUG_CHANNELCFG("11.0 Surround",    0x56f7)
+            SDL_WAVE_DEBUG_CHANNELCFG("11.1 Surround",    0x56ff)
+        default:
+            SDL_WAVE_DEBUG_CHANNELSTR("FL",  0x1)
+            SDL_WAVE_DEBUG_CHANNELSTR("FR",  0x2)
+            SDL_WAVE_DEBUG_CHANNELSTR("FC",  0x4)
+            SDL_WAVE_DEBUG_CHANNELSTR("LF",  0x8)
+            SDL_WAVE_DEBUG_CHANNELSTR("BL",  0x10)
+            SDL_WAVE_DEBUG_CHANNELSTR("BR",  0x20)
+            SDL_WAVE_DEBUG_CHANNELSTR("FLC", 0x40)
+            SDL_WAVE_DEBUG_CHANNELSTR("FRC", 0x80)
+            SDL_WAVE_DEBUG_CHANNELSTR("BC",  0x100)
+            SDL_WAVE_DEBUG_CHANNELSTR("SL",  0x200)
+            SDL_WAVE_DEBUG_CHANNELSTR("SR",  0x400)
+            SDL_WAVE_DEBUG_CHANNELSTR("TC",  0x800)
+            SDL_WAVE_DEBUG_CHANNELSTR("TFL", 0x1000)
+            SDL_WAVE_DEBUG_CHANNELSTR("TFC", 0x2000)
+            SDL_WAVE_DEBUG_CHANNELSTR("TFR", 0x4000)
+            SDL_WAVE_DEBUG_CHANNELSTR("TBL", 0x8000)
+            SDL_WAVE_DEBUG_CHANNELSTR("TBC", 0x10000)
+            SDL_WAVE_DEBUG_CHANNELSTR("TBR", 0x20000)
+            break;
+        }
+    } else {
+        switch (format->channels) {
+        default:
+            if (SDL_snprintf(channelstr, sizeof(channelstr), "%u channels", format->channels) >= 0) {
+                wavechannel = channelstr;
+                break;
+            }
+        case 0:
+            wavechannel = "Unknown";
+            break;
+        case 1:
+            wavechannel = "Mono";
+            break;
+        case 2:
+            wavechannel = "Setero";
+            break;
+        }
+    }
+
+#undef SDL_WAVE_DEBUG_CHANNELCFG
+#undef SDL_WAVE_DEBUG_CHANNELSTR
+
+    if (wavebps >= 1024) {
+        wavebpsunit = "KiB";
+        wavebps = wavebps / 1024 + (wavebps & 0x3ff ? 1 : 0);
+    }
+
+    SDL_LogDebug(SDL_LOG_CATEGORY_AUDIO, fmtstr, waveformat, format->frequency, wavechannel, format->bitspersample, wavebps, wavebpsunit);
+}
+#endif
+
+#ifdef SDL_WAVE_DEBUG_DUMP_FORMAT
+static void
+WaveDebugDumpFormat(WaveFile *file, Uint32 rifflen, Uint32 fmtlen, Uint32 datalen)
+{
+    WaveFormat *format = &file->format;
+    const char *fmtstr1 = "WAVE chunk dump:\n"
+        "-------------------------------------------\n"
+        "RIFF                            %11u\n"
+        "-------------------------------------------\n"
+        "    fmt                         %11u\n"
+        "        wFormatTag                   0x%04x\n"
+        "        nChannels               %11u\n"
+        "        nSamplesPerSec          %11u\n"
+        "        nAvgBytesPerSec         %11u\n"
+        "        nBlockAlign             %11u\n";
+    const char *fmtstr2 = "        wBitsPerSample          %11u\n";
+    const char *fmtstr3 = "        cbSize                  %11u\n";
+    const char *fmtstr4a = "        wValidBitsPerSample     %11u\n";
+    const char *fmtstr4b = "        wSamplesPerBlock        %11u\n";
+    const char *fmtstr5 = "        dwChannelMask            0x%08x\n"
+        "        SubFormat\n"
+        "        %08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x\n";
+    const char *fmtstr6 = "-------------------------------------------\n"
+        " fact\n"
+        "  dwSampleLength                %11u\n";
+    const char *fmtstr7 = "-------------------------------------------\n"
+        " data                           %11u\n"
+        "-------------------------------------------\n";
+    char *dumpstr;
+    size_t dumppos = 0;
+    const size_t bufsize = 1024;
+    int res;
+
+    dumpstr = SDL_malloc(bufsize);
+    if (dumpstr == NULL) {
+        return;
+    }
+    dumpstr[0] = 0;
+
+    res = SDL_snprintf(dumpstr, bufsize, fmtstr1, rifflen, fmtlen, format->formattag, format->channels, format->frequency, format->byterate, format->blockalign);
+    dumppos += res > 0 ? res : 0;
+    if (fmtlen >= 16) {
+        res = SDL_snprintf(dumpstr + dumppos, bufsize - dumppos, fmtstr2, format->bitspersample);
+        dumppos += res > 0 ? res : 0;
+    }
+    if (fmtlen >= 18) {
+        res = SDL_snprintf(dumpstr + dumppos, bufsize - dumppos, fmtstr3, format->extsize);
+        dumppos += res > 0 ? res : 0;
+    }
+    if (format->formattag == EXTENSIBLE_CODE && fmtlen >= 40 && format->extsize >= 22) {
+        const Uint8 *g = format->subformat;
+        const Uint32 g1 = g[0] | ((Uint32)g[1] << 8) | ((Uint32)g[2] << 16) | ((Uint32)g[3] << 24);
+        const Uint32 g2 = g[4] | ((Uint32)g[5] << 8);
+        const Uint32 g3 = g[6] | ((Uint32)g[7] << 8);
+
+        switch (format->encoding) {
+        default:
+            res = SDL_snprintf(dumpstr + dumppos, bufsize - dumppos, fmtstr4a, format->validsamplebits);
+            dumppos += res > 0 ? res : 0;
+            break;
+        case MS_ADPCM_CODE:
+        case IMA_ADPCM_CODE:
+            res = SDL_snprintf(dumpstr + dumppos, bufsize - dumppos, fmtstr4b, format->samplesperblock);
+            dumppos += res > 0 ? res : 0;
+            break;
+        }
+        res = SDL_snprintf(dumpstr + dumppos, bufsize - dumppos, fmtstr5, format->channelmask, g1, g2, g3, g[8], g[9], g[10], g[11], g[12], g[13], g[14], g[15]);
+        dumppos += res > 0 ? res : 0;
+    } else {
+        switch (format->encoding) {
+        case MS_ADPCM_CODE:
+        case IMA_ADPCM_CODE:
+            if (fmtlen >= 20 && format->extsize >= 2) {
+                res = SDL_snprintf(dumpstr + dumppos, bufsize - dumppos, fmtstr4b, format->samplesperblock);
+                dumppos += res > 0 ? res : 0;
+            }
+            break;
+        }
+    }
+    if (file->fact.status >= 1) {
+        res = SDL_snprintf(dumpstr + dumppos, bufsize - dumppos, fmtstr6, file->fact.samplelength);
+        dumppos += res > 0 ? res : 0;
+    }
+    res = SDL_snprintf(dumpstr + dumppos, bufsize - dumppos, fmtstr7, datalen);
+    dumppos += res > 0 ? res : 0;
+
+    SDL_LogDebug(SDL_LOG_CATEGORY_AUDIO, "%s", dumpstr);
+
+    free(dumpstr);
+}
+#endif
+
+static Sint64
+WaveAdjustToFactValue(WaveFile *file, Sint64 sampleframes)
+{
+    if (file->fact.status == 2) {
+        if (file->facthint == FactStrict && sampleframes < file->fact.samplelength) {
+            return SDL_SetError("Invalid number of sample frames in WAVE fact chunk (too many)");
+        } else if (sampleframes > file->fact.samplelength) {
+            return file->fact.samplelength;
+        }
+    }
+
+    return sampleframes;
+}
+
+static int
+MS_ADPCM_CalculateSampleFrames(WaveFile *file, size_t datalength)
+{
+    WaveFormat *format = &file->format;
+    const size_t blockheadersize = (size_t)file->format.channels * 7;
+    const size_t availableblocks = datalength / file->format.blockalign;
+    const size_t blockframebitsize = (size_t)file->format.bitspersample * file->format.channels;
+    const size_t trailingdata = datalength % file->format.blockalign;
+
+    if (file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict) {
+        /* The size of the data chunk must be a multiple of the block size. */
+        if (datalength < blockheadersize || trailingdata > 0) {
+            return SDL_SetError("Truncated MS ADPCM block");
+        }
+    }
+
+    /* Calculate number of sample frames that will be decoded. */
+    file->sampleframes = (Sint64)availableblocks * format->samplesperblock;
+    if (trailingdata > 0) {
+        /* The last block is truncated. Check if we can get any samples out of it. */
+        if (file->trunchint == TruncDropFrame) {
+            /* Drop incomplete sample frame. */
+            if (trailingdata >= blockheadersize) {
+                size_t trailingsamples = 2 + (trailingdata - blockheadersize) * 8 / blockframebitsize;
+                if (trailingsamples > format->samplesperblock) {
+                    trailingsamples = format->samplesperblock;
+                }
+                file->sampleframes += trailingsamples;
+            }
+        }
+    }
+
+    file->sampleframes = WaveAdjustToFactValue(file, file->sampleframes);
+    if (file->sampleframes < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+MS_ADPCM_Init(WaveFile *file, size_t datalength)
+{
+    WaveFormat *format = &file->format;
+    WaveChunk *chunk = &file->chunk;
+    const size_t blockheadersize = (size_t)format->channels * 7;
+    const size_t blockdatasize = (size_t)format->blockalign - blockheadersize;
+    const size_t blockframebitsize = (size_t)format->bitspersample * format->channels;
+    const size_t blockdatasamples = (blockdatasize * 8) / blockframebitsize;
+    const Sint16 presetcoeffs[14] = {256, 0, 512, -256, 0, 0, 192, 64, 240, 0, 460, -208, 392, -232};
+    size_t i, coeffcount;
+    MS_ADPCM_CoeffData *coeffdata;
+
+    /* Sanity checks. */
+
+    /* While it's clear how IMA ADPCM handles more than two channels, the nibble
+     * order of MS ADPCM makes it awkward. The Standards Update does not talk
+     * about supporting more than stereo anyway.
+     */
+    if (format->channels > 2) {
+        return SDL_SetError("Invalid number of channels");
+    }
+
+    if (format->bitspersample != 4) {
+        return SDL_SetError("Invalid MS ADPCM bits per sample of %u", (unsigned int)format->bitspersample);
+    }
+
+    /* The block size must be big enough to contain the block header. */
+    if (format->blockalign < blockheadersize) {
+        return SDL_SetError("Invalid MS ADPCM block size (nBlockAlign)");
+    }
+
+    if (format->formattag == EXTENSIBLE_CODE) {
+        /* Does have a GUID (like all format tags), but there's no specification
+         * for how the data is packed into the extensible header. Making
+         * assumptions here could lead to new formats nobody wants to support.
+         */
+        return SDL_SetError("MS ADPCM with the extensible header is not supported");
+    }
+
+    /* There are wSamplesPerBlock, wNumCoef, and at least 7 coefficient pairs in
+     * the extended part of the header.
+     */
+    if (chunk->size < 22) {
+        return SDL_SetError("Could not read MS ADPCM format header");
+    }
+
+    format->samplesperblock = chunk->data[18] | ((Uint16)chunk->data[19] << 8);
+    /* Number of coefficient pairs. A pair has two 16-bit integers. */
+    coeffcount = chunk->data[20] | ((size_t)chunk->data[21] << 8);
+    /* bPredictor, the integer offset into the coefficients array, is only
+     * 8 bits. It can only address the first 256 coefficients. Let's limit
+     * the count number here.
+     */
+    if (coeffcount > 256) {
+        coeffcount = 256;
+    }
+
+    if (chunk->size < 22 + coeffcount * 4) {
+        return SDL_SetError("Could not read custom coefficients in MS ADPCM format header");
+    } else if (format->extsize < 4 + coeffcount * 4) {
+        return SDL_SetError("Invalid MS ADPCM format header (too small)");
+    } else if (coeffcount < 7) {
+        return SDL_SetError("Missing required coefficients in MS ADPCM format header");
+    }
+
+    coeffdata = (MS_ADPCM_CoeffData *)SDL_malloc(sizeof(MS_ADPCM_CoeffData) + coeffcount * 4);
+    file->decoderdata = coeffdata; /* Freed in cleanup. */
+    if (coeffdata == NULL) {
+        return SDL_OutOfMemory();
+    }
+    coeffdata->coeff = &coeffdata->aligndummy;
+    coeffdata->coeffcount = (Uint16)coeffcount;
+
+    /* Copy the 16-bit pairs. */
+    for (i = 0; i < coeffcount * 2; i++) {
+        Sint32 c = chunk->data[22 + i * 2] | ((Sint32)chunk->data[23 + i * 2] << 8);
+        if (c >= 0x8000) {
+            c -= 0x10000;
+        }
+        if (i < 14 && c != presetcoeffs[i]) {
+            return SDL_SetError("Wrong preset coefficients in MS ADPCM format header");
+        }
+        coeffdata->coeff[i] = (Sint16)c;
+    }
+
+    /* Technically, wSamplesPerBlock is required, but we have all the
+     * information in the other fields to calculate it, if it's zero.
+     */
+    if (format->samplesperblock == 0) {
+        /* Let's be nice to the encoders that didn't know how to fill this.
+         * The Standards Update calculates it this way:
+         *
+         *   x = Block size (in bits) minus header size (in bits)
+         *   y = Bit depth multiplied by channel count
+         *   z = Number of samples per channel in block header
+         *   wSamplesPerBlock = x / y + z
+         */
+        format->samplesperblock = (Uint32)blockdatasamples + 2;
+    }
+
+    /* nBlockAlign can be in conflict with wSamplesPerBlock. For example, if
+     * the number of samples doesn't fit into the block. The Standards Update
+     * also describes wSamplesPerBlock with a formula that makes it necessary to
+     * always fill the block with the maximum amount of samples, but this is not
+     * enforced here as there are no compatibility issues.
+     * A truncated block header with just one sample is not supported.
+     */
+    if (format->samplesperblock == 1 || blockdatasamples < format->samplesperblock - 2) {
+        return SDL_SetError("Invalid number of samples per MS ADPCM block (wSamplesPerBlock)");
+    }
+
+    if (MS_ADPCM_CalculateSampleFrames(file, datalength) < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static Sint16
+MS_ADPCM_ProcessNibble(MS_ADPCM_ChannelState *cstate, Sint32 sample1, Sint32 sample2, Uint8 nybble)
+{
+    const Sint32 max_audioval = 32767;
+    const Sint32 min_audioval = -32768;
+    const Uint16 max_deltaval = 65535;
+    const Uint16 adaptive[] = {
+        230, 230, 230, 230, 307, 409, 512, 614,
+        768, 614, 512, 409, 307, 230, 230, 230
+    };
+    Sint32 new_sample;
+    Sint32 errordelta;
+    Uint32 delta = cstate->delta;
+
+    new_sample = (sample1 * cstate->coeff1 + sample2 * cstate->coeff2) / 256;
+    /* The nibble is a signed 4-bit error delta. */
+    errordelta = (Sint32)nybble - (nybble >= 0x08 ? 0x10 : 0);
+    new_sample += (Sint32)delta * errordelta;
+    if (new_sample < min_audioval) {
+        new_sample = min_audioval;
+    } else if (new_sample > max_audioval) {
+        new_sample = max_audioval;
+    }
+    delta = (delta * adaptive[nybble]) / 256;
+    if (delta < 16) {
+        delta = 16;
+    } else if (delta > max_deltaval) {
+        /* This issue is not described in the Standards Update and therefore
+         * undefined. It seems sensible to prevent overflows with a limit.
+         */
+        delta = max_deltaval;
+    }
+
+    cstate->delta = (Uint16)delta;
+    return (Sint16)new_sample;
+}
+
+static int
+MS_ADPCM_DecodeBlockHeader(ADPCM_DecoderState *state)
+{
+    Uint8 coeffindex;
+    const Uint32 channels = state->channels;
+    Sint32 sample;
+    Uint32 c;
+    MS_ADPCM_ChannelState *cstate = (MS_ADPCM_ChannelState *)state->cstate;
+    MS_ADPCM_CoeffData *ddata = (MS_ADPCM_CoeffData *)state->ddata;
+
+    for (c = 0; c < channels; c++) {
+        size_t o = c;
+
+        /* Load the coefficient pair into the channel state. */
+        coeffindex = state->block.data[o];
+        if (coeffindex > ddata->coeffcount) {
+            return SDL_SetError("Invalid MS ADPCM coefficient index in block header");
+        }
+        cstate[c].coeff1 = ddata->coeff[coeffindex * 2];
+        cstate[c].coeff2 = ddata->coeff[coeffindex * 2 + 1];
+
+        /* Initial delta value. */
+        o = channels + c * 2;
+        cstate[c].delta = state->block.data[o] | ((Uint16)state->block.data[o + 1] << 8);
+
+        /* Load the samples from the header. Interestingly, the sample later in
+         * the output stream comes first.
+         */
+        o = channels * 3 + c * 2;
+        sample = state->block.data[o] | ((Sint32)state->block.data[o + 1] << 8);
+        if (sample >= 0x8000) {
+            sample -= 0x10000;
+        }
+        state->output.data[state->output.pos + channels] = (Sint16)sample;
+
+        o = channels * 5 + c * 2;
+        sample = state->block.data[o] | ((Sint32)state->block.data[o + 1] << 8);
+        if (sample >= 0x8000) {
+            sample -= 0x10000;
+        }
+        state->output.data[state->output.pos] = (Sint16)sample;
+
+        state->output.pos++;
+    }
+
+    state->block.pos += state->blockheadersize;
+
+    /* Skip second sample frame that came from the header. */
+    state->output.pos += state->channels;
+
+    /* Header provided two sample frames. */
+    state->framesleft -= 2;
+
+    return 0;
+}
+
+/* Decodes the data of the MS ADPCM block. Decoding will stop if a block is too
+ * short, returning with none or partially decoded data. The partial data
+ * will always contain full sample frames (same sample count for each channel).
+ * Incomplete sample frames are discarded.
+ */
+static int
+MS_ADPCM_DecodeBlockData(ADPCM_DecoderState *state)
+{
+    Uint16 nybble = 0;
+    Sint16 sample1, sample2;
+    const Uint32 channels = state->channels;
+    Uint32 c;
+    MS_ADPCM_ChannelState *cstate = (MS_ADPCM_ChannelState *)state->cstate;
+
+    size_t blockpos = state->block.pos;
+    size_t blocksize = state->block.size;
+
+    size_t outpos = state->output.pos;
+
+    Sint64 blockframesleft = state->samplesperblock - 2;
+    if (blockframesleft > state->framesleft) {
+        blockframesleft = state->framesleft;
+    }
+
+    while (blockframesleft > 0) {
+        for (c = 0; c < channels; c++) {
+            if (nybble & 0x4000) {
+                nybble <<= 4;
+            } else if (blockpos < blocksize) {
+                nybble = state->block.data[blockpos++] | 0x4000;
+            } else {
+                /* Out of input data. Drop the incomplete frame and return. */
+                state->output.pos = outpos - c;
+                return -1;
+            }
+
+            /* Load previous samples which may come from the block header. */
+            sample1 = state->output.data[outpos - channels];
+            sample2 = state->output.data[outpos - channels * 2];
+
+            sample1 = MS_ADPCM_ProcessNibble(cstate + c, sample1, sample2, (nybble >> 4) & 0x0f);
+            state->output.data[outpos++] = sample1;
+        }
+
+        state->framesleft--;
+        blockframesleft--;
+    }
+
+    state->output.pos = outpos;
+
+    return 0;
+}
+
+static int
+MS_ADPCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
+{
+    int result;
+    size_t bytesleft, outputsize;
+    WaveChunk *chunk = &file->chunk;
+    ADPCM_DecoderState state;
+    MS_ADPCM_ChannelState cstate[2];
+
+    SDL_zero(state);
+    SDL_zeroa(cstate);
+
+    if (chunk->size != chunk->length) {
+        /* Could not read everything. Recalculate number of sample frames. */
+        if (MS_ADPCM_CalculateSampleFrames(file, chunk->size) < 0) {
+            return -1;
+        }
+    }
+
+    /* Nothing to decode, nothing to return. */
+    if (file->sampleframes == 0) {
+        *audio_buf = NULL;
+        *audio_len = 0;
+        return 0;
+    }
+
+    state.blocksize = file->format.blockalign;
+    state.channels = file->format.channels;
+    state.blockheadersize = (size_t)state.channels * 7;
+    state.samplesperblock = file->format.samplesperblock;
+    state.framesize = state.channels * sizeof(Sint16);
+    state.ddata = file->decoderdata;
+    state.framestotal = file->sampleframes;
+    state.framesleft = state.framestotal;
+
+    state.input.data = chunk->data;
+    state.input.size = chunk->size;
+    state.input.pos = 0;
+
+    /* The output size in bytes. May get modified if data is truncated. */
+    outputsize = (size_t)state.framestotal;
+    if (SafeMult(&outputsize, state.framesize)) {
+        return SDL_OutOfMemory();
+    } else if (outputsize > SDL_MAX_UINT32 || state.framestotal > SIZE_MAX) {
+        return SDL_SetError("WAVE file too big");
+    }
+
+    state.output.pos = 0;
+    state.output.size = outputsize / sizeof(Sint16);
+    state.output.data = (Sint16 *)SDL_malloc(outputsize);
+    if (state.output.data == NULL) {
+        return SDL_OutOfMemory();
+    }
+
+    state.cstate = cstate;
+
+    /* Decode block by block. A truncated block will stop the decoding. */
+    bytesleft = state.input.size - state.input.pos;
+    while (state.framesleft > 0 && bytesleft >= state.blockheadersize) {
+        state.block.data = state.input.data + state.input.pos;
+        state.block.size = bytesleft < state.blocksize ? bytesleft : state.blocksize;
+        state.block.pos = 0;
+
+        if (state.output.size - state.output.pos < (Uint64)state.framesleft * state.channels) {
+            /* Somehow didn't allocate enough space for the output. */
+            SDL_free(state.output.data);
+            return SDL_SetError("Unexpected overflow in MS ADPCM decoder");
+        }
+
+        /* Initialize decoder with the values from the block header. */
+        result = MS_ADPCM_DecodeBlockHeader(&state);
+        if (result == -1) {
+            SDL_free(state.output.data);
+            return -1;
+        }
+
+        /* Decode the block data. It stores the samples directly in the output. */
+        result = MS_ADPCM_DecodeBlockData(&state);
+        if (result == -1) {
+            /* Unexpected end. Stop decoding and return partial data if necessary. */
+            if (file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict) {
+                SDL_free(state.output.data);
+                return SDL_SetError("Truncated data chunk");
+            } else if (file->trunchint != TruncDropFrame) {
+                state.output.pos -= state.output.pos % (state.samplesperblock * state.channels);
+            }
+            outputsize = state.output.pos * sizeof(Sint16); /* Can't overflow, is always smaller. */
+            break;
+        }
+
+        state.input.pos += state.block.size;
+        bytesleft = state.input.size - state.input.pos;
+    }
+
+    *audio_buf = (Uint8 *)state.output.data;
+    *audio_len = (Uint32)outputsize;
+
+    return 0;
+}
+
+static int
+IMA_ADPCM_CalculateSampleFrames(WaveFile *file, size_t datalength)
+{
+    WaveFormat *format = &file->format;
+    const size_t blockheadersize = (size_t)format->channels * 4;
+    const size_t subblockframesize = (size_t)format->channels * 4;
+    const size_t availableblocks = datalength / format->blockalign;
+    const size_t trailingdata = datalength % format->blockalign;
+
+    if (file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict) {
+        /* The size of the data chunk must be a multiple of the block size. */
+        if (datalength < blockheadersize || trailingdata > 0) {
+            return SDL_SetError("Truncated IMA ADPCM block");
+        }
+    }
+
+    /* Calculate number of sample frames that will be decoded. */
+    file->sampleframes = (Uint64)availableblocks * format->samplesperblock;
+    if (trailingdata > 0) {
+        /* The last block is truncated. Check if we can get any samples out of it. */
+        if (file->trunchint == TruncDropFrame && trailingdata > blockheadersize - 2) {
+            /* The sample frame in the header of the truncated block is present.
+             * Drop incomplete sample frames.
+             */
+            size_t trailingsamples = 1;
+
+            if (trailingdata > blockheadersize) {
+                /* More data following after the header. */
+                const size_t trailingblockdata = trailingdata - blockheadersize;
+                const size_t trailingsubblockdata = trailingblockdata % subblockframesize;
+                trailingsamples += (trailingblockdata / subblockframesize) * 8;
+                /* Due to the interleaved sub-blocks, the last 4 bytes determine
+                 * how many samples of the truncated sub-block are lost.
+                 */
+                if (trailingsubblockdata > subblockframesize - 4) {
+                    trailingsamples += (trailingsubblockdata % 4) * 2;
+                }
+            }
+
+            if (trailingsamples > format->samplesperblock) {
+                trailingsamples = format->samplesperblock;
+            }
+            file->sampleframes += trailingsamples;
+        }
+    }
+
+    file->sampleframes = WaveAdjustToFactValue(file, file->sampleframes);
+    if (file->sampleframes < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+IMA_ADPCM_Init(WaveFile *file, size_t datalength)
+{
+    WaveFormat *format = &file->format;
+    WaveChunk *chunk = &file->chunk;
+    const size_t blockheadersize = (size_t)format->channels * 4;
+    const size_t blockdatasize = (size_t)format->blockalign - blockheadersize;
+    const size_t blockframebitsize = (size_t)format->bitspersample * format->channels;
+    const size_t blockdatasamples = (blockdatasize * 8) / blockframebitsize;
+
+    /* Sanity checks. */
+
+    /* IMA ADPCM can also have 3-bit samples, but it's not supported by SDL at this time. */
+    if (format->bitspersample == 3) {
+        return SDL_SetError("3-bit IMA ADPCM currently not supported");
+    } else if (format->bitspersample != 4) {
+        return SDL_SetError("Invalid IMA ADPCM bits per sample of %u", (unsigned int)format->bitspersample);
+    }
+
+    /* The block size is required to be a multiple of 4 and it must be able to
+     * hold a block header.
+     */
+    if (format->blockalign < blockheadersize || format->blockalign % 4) {
+        return SDL_SetError("Invalid IMA ADPCM block size (nBlockAlign)");
+    }
+
+    if (format->formattag == EXTENSIBLE_CODE) {
+        /* There's no specification for this, but it's basically the same
+         * format because the extensible header has wSampePerBlocks too.
+         */
+    } else  {
+        /* The Standards Update says there 'should' be 2 bytes for wSamplesPerBlock. */
+        if (chunk->size >= 20 && format->extsize >= 2) {
+            format->samplesperblock = chunk->data[18] | ((Uint16)chunk->data[19] << 8);
+        }
+    }
+
+    if (format->samplesperblock == 0) {
+        /* Field zero? No problem. We just assume the encoder packed the block.
+         * The specification calculates it this way:
+         *
+         *   x = Block size (in bits) minus header size (in bits)
+         *   y = Bit depth multiplied by channel count
+         *   z = Number of samples per channel in header
+         *   wSamplesPerBlock = x / y + z
+         */
+        format->samplesperblock = (Uint32)blockdatasamples + 1;
+    }
+
+    /* nBlockAlign can be in conflict with wSamplesPerBlock. For example, if
+     * the number of samples doesn't fit into the block. The Standards Update
+     * also describes wSamplesPerBlock with a formula that makes it necessary
+     * to always fill the block with the maximum amount of samples, but this is
+     * not enforced here as there are no compatibility issues.
+     */
+    if (blockdatasamples < format->samplesperblock - 1) {
+        return SDL_SetError("Invalid number of samples per IMA ADPCM block (wSamplesPerBlock)");
+    }
+
+    if (IMA_ADPCM_CalculateSampleFrames(file, datalength) < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static Sint16
+IMA_ADPCM_ProcessNibble(Sint8 *cindex, Sint16 lastsample, Uint8 nybble)
+{
+    const Sint32 max_audioval = 32767;
+    const Sint32 min_audioval = -32768;
+    const Sint8 index_table_4b[16] = {
+        -1, -1, -1, -1,
+        2, 4, 6, 8,
+        -1, -1, -1, -1,
+        2, 4, 6, 8
+    };
+    const Uint16 step_table[89] = {
+        7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31,
+        34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130,
+        143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408,
+        449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282,
+        1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327,
+        3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630,
+        9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350,
+        22385, 24623, 27086, 29794, 32767
+    };
+    Uint32 step;
+    Sint32 sample, delta;
+    Sint8 index = *cindex;
+
+    /* Clamp index into valid range. */
+    if (index > 88) {
+        index = 88;
+    } else if (index < 0) {
+        index = 0;
+    }
+
+    /* explicit cast to avoid gcc warning about using 'char' as array index */
+    step = step_table[(size_t)index];
+
+    /* Update index value */
+    *cindex = index + index_table_4b[nybble];
+
+    /* This calculation uses shifts and additions because multiplications were
+     * much slower back then. Sadly, this can't just be replaced with an actual
+     * multiplication now as the old algorithm drops some bits. The closest
+     * approximation I could find is something like this:
+     * (nybble & 0x8 ? -1 : 1) * ((nybble & 0x7) * step / 4 + step / 8)
+     */
+    delta = step >> 3;
+    if (nybble & 0x04)
+        delta += step;
+    if (nybble & 0x02)
+        delta += step >> 1;
+    if (nybble & 0x01)
+        delta += step >> 2;
+    if (nybble & 0x08)
+        delta = -delta;
+
+    sample = lastsample + delta;
+
+    /* Clamp output sample */
+    if (sample > max_audioval) {
+        sample = max_audioval;
+    } else if (sample < min_audioval) {
+        sample = min_audioval;
+    }
+
+    return (Sint16)sample;
+}
+
+static int
+IMA_ADPCM_DecodeBlockHeader(ADPCM_DecoderState *state)
+{
+    Sint16 step;
+    Uint32 c;
+    Uint8 *cstate = state->cstate;
+
+    for (c = 0; c < state->channels; c++) {
+        size_t o = state->block.pos + c * 4;
+
+        /* Extract the sample from the header. */
+        Sint32 sample = state->block.data[o] | ((Sint32)state->block.data[o + 1] << 8);
+        if (sample >= 0x8000) {
+            sample -= 0x10000;
+        }
+        state->output.data[state->output.pos++] = (Sint16)sample;
+
+        /* Channel step index. */
+        step = (Sint16)state->block.data[o + 2];
+        cstate[c] = (Sint8)(step > 0x80 ? step - 0x100 : step);
+
+        /* Reserved byte in block header, should be 0. */
+        if (state->block.data[o + 3] != 0) {
+            /* Uh oh, corrupt data?  Buggy code? */ ;
+        }
+    }
+
+    state->block.pos += state->blockheadersize;
+
+    /* Header provided one sample frame. */
+    state->framesleft--;
+
+    return 0;
+}
+
+/* Decodes the data of the IMA ADPCM block. Decoding will stop if a block is too
+ * short, returning with none or partially decoded data. The partial data always
+ * contains full sample frames (same sample count for each channel).
+ * Incomplete sample frames are discarded.
+ */
+static int
+IMA_ADPCM_DecodeBlockData(ADPCM_DecoderState *state)
+{
+    size_t i;
+    int retval = 0;
+    const Uint32 channels = state->channels;
+    const size_t subblockframesize = channels * 4;
+    Uint64 bytesrequired;
+    Uint32 c;
+
+    size_t blockpos = state->block.pos;
+    size_t blocksize = state->block.size;
+    size_t blockleft = blocksize - blockpos;
+
+    size_t outpos = state->output.pos;
+
+    Sint64 blockframesleft = state->samplesperblock - 1;
+    if (blockframesleft > state->framesleft) {
+        blockframesleft = state->framesleft;
+    }
+
+    bytesrequired = (blockframesleft + 7) / 8 * subblockframesize;
+    if (blockleft < bytesrequired) {
+        /* Data truncated. Calculate how many samples we can get out if it. */
+        const size_t guaranteedframes = blockleft / subblockframesize;
+        const size_t remainingbytes = blockleft % subblockframesize;
+        blockframesleft = guaranteedframes;
+        if (remainingbytes > subblockframesize - 4) {
+            blockframesleft += (remainingbytes % 4) * 2;
+        }
+        /* Signal the truncation. */
+        retval = -1;
+    }
+
+    /* Each channel has their nibbles packed into 32-bit blocks. These blocks
+     * are interleaved and make up the data part of the ADPCM block. This loop
+     * decodes the samples as they come from the input data and puts them at
+     * the appropriate places in the output data.
+     */
+    while (blockframesleft > 0) {
+        const size_t subblocksamples = blockframesleft < 8 ? (size_t)blockframesleft : 8;
+
+        for (c = 0; c < channels; c++) {
+            Uint8 nybble = 0;
+            /* Load previous sample which may come from the block header. */
+            Sint16 sample = state->output.data[outpos + c - channels];
+
+            for (i = 0; i < subblocksamples; i++) {
+                if (i & 1) {
+                    nybble >>= 4;
+                } else {
+                    nybble = state->block.data[blockpos++];
+                }
+
+                sample = IMA_ADPCM_ProcessNibble((Sint8 *)state->cstate + c, sample, nybble & 0x0f);
+                state->output.data[outpos + c + i * channels] = sample;
+            }
+        }
+
+        outpos += channels * subblocksamples;
+        state->framesleft -= subblocksamples;
+        blockframesleft -= subblocksamples;
+    }
+
+    state->block.pos = blockpos;
+    state->output.pos = outpos;
+
+    return retval;
+}
+
+static int
+IMA_ADPCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
+{
+    int result;
+    size_t bytesleft, outputsize;
+    WaveChunk *chunk = &file->chunk;
+    ADPCM_DecoderState state;
+    Sint8 *cstate;
+
+    if (chunk->size != chunk->length) {
+        /* Could not read everything. Recalculate number of sample frames. */
+        if (IMA_ADPCM_CalculateSampleFrames(file, chunk->size) < 0) {
+            return -1;
+        }
+    }
+
+    /* Nothing to decode, nothing to return. */
+    if (file->sampleframes == 0) {
+        *audio_buf = NULL;
+        *audio_len = 0;
+        return 0;
+    }
+
+    SDL_zero(state);
+    state.channels = file->format.channels;
+    state.blocksize = file->format.blockalign;
+    state.blockheadersize = (size_t)state.channels * 4;
+    state.samplesperblock = file->format.samplesperblock;
+    state.framesize = state.channels * sizeof(Sint16);
+    state.framestotal = file->sampleframes;
+    state.framesleft = state.framestotal;
+
+    state.input.data = chunk->data;
+    state.input.size = chunk->size;
+    state.input.pos = 0;
+
+    /* The output size in bytes. May get modified if data is truncated. */
+    outputsize = (size_t)state.framestotal;
+    if (SafeMult(&outputsize, state.framesize)) {
+        return SDL_OutOfMemory();
+    } else if (outputsize > SDL_MAX_UINT32 || state.framestotal > SIZE_MAX) {
+        return SDL_SetError("WAVE file too big");
+    }
+
+    state.output.pos = 0;
+    state.output.size = outputsize / sizeof(Sint16);
+    state.output.data = (Sint16 *)SDL_malloc(outputsize);
+    if (state.output.data == NULL) {
+        return SDL_OutOfMemory();
+    }
+
+    cstate = (Sint8 *)SDL_calloc(state.channels, sizeof(Sint8));
+    if (cstate == NULL) {
+        SDL_free(state.output.data);
+        return SDL_OutOfMemory();
+    }
+    state.cstate = cstate;
+
+    /* Decode block by block. A truncated block will stop the decoding. */
+    bytesleft = state.input.size - state.input.pos;
+    while (state.framesleft > 0 && bytesleft >= state.blockheadersize) {
+        state.block.data = state.input.data + state.input.pos;
+        state.block.size = bytesleft < state.blocksize ? bytesleft : state.blocksize;
+        state.block.pos = 0;
+
+        if (state.output.size - state.output.pos < (Uint64)state.framesleft * state.channels) {
+            /* Somehow didn't allocate enough space for the output. */
+            SDL_free(state.output.data);
+            SDL_free(cstate);
+            return SDL_SetError("Unexpected overflow in IMA ADPCM decoder");
+        }
+
+        /* Initialize decoder with the values from the block header. */
+        result = IMA_ADPCM_DecodeBlockHeader(&state);
+        if (result == 0) {
+            /* Decode the block data. It stores the samples directly in the output. */
+            result = IMA_ADPCM_DecodeBlockData(&state);
+        }
+
+        if (result == -1) {
+            /* Unexpected end. Stop decoding and return partial data if necessary. */
+            if (file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict) {
+                SDL_free(state.output.data);
+                SDL_free(cstate);
+                return SDL_SetError("Truncated data chunk");
+            } else if (file->trunchint != TruncDropFrame) {
+                state.output.pos -= state.output.pos % (state.samplesperblock * state.channels);
+            }
+            outputsize = state.output.pos * sizeof(Sint16); /* Can't overflow, is always smaller. */
+            break;
+        }
+
+        state.input.pos += state.block.size;
+        bytesleft = state.input.size - state.input.pos;
+    }
+
+    *audio_buf = (Uint8 *)state.output.data;
+    *audio_len = (Uint32)outputsize;
+
+    SDL_free(cstate);
+
+    return 0;
+}
+
+static int
+LAW_Init(WaveFile *file, size_t datalength)
+{
+    WaveFormat *format = &file->format;
+
+    /* Standards Update requires this to be 8. */
+    if (format->bitspersample != 8) {
+        return SDL_SetError("Invalid companded bits per sample of %u", (unsigned int)format->bitspersample);
+    }
+
+    /* Not going to bother with weird padding. */
+    if (format->blockalign != format->channels) {
+        return SDL_SetError("Unsupported block alignment");
+    }
+
+    if ((file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict)) {
+        if (format->blockalign > 1 && datalength % format->blockalign) {
+            return SDL_SetError("Truncated data chunk in WAVE file");
+        }
+    }
+
+    file->sampleframes = WaveAdjustToFactValue(file, datalength / format->blockalign);
+    if (file->sampleframes < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+LAW_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
+{
+#ifdef SDL_WAVE_LAW_LUT
+    const Sint16 alaw_lut[256] = {
+        -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, -2752,
+        -2624, -3008, -2880, -2240, -2112, -2496, -2368, -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, -22016,
+        -20992, -24064, -23040, -17920, -16896, -19968, -18944, -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, -11008,
+        -10496, -12032, -11520, -8960, -8448, -9984, -9472, -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, -344,
+        -328, -376, -360, -280, -264, -312, -296, -472, -456, -504, -488, -408, -392, -440, -424, -88,
+        -72, -120, -104, -24, -8, -56, -40, -216, -200, -248, -232, -152, -136, -184, -168, -1376,
+        -1312, -1504, -1440, -1120, -1056, -1248, -1184, -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, -688,
+        -656, -752, -720, -560, -528, -624, -592, -944, -912, -1008, -976, -816, -784, -880, -848, 5504,
+        5248, 6016, 5760, 4480, 4224, 4992, 4736, 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, 2752,
+        2624, 3008, 2880, 2240, 2112, 2496, 2368, 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, 22016,
+        20992, 24064, 23040, 17920, 16896, 19968, 18944, 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, 11008,
+        10496, 12032, 11520, 8960, 8448, 9984, 9472, 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, 344,
+        328, 376, 360, 280, 264, 312, 296, 472, 456, 504, 488, 408, 392, 440, 424, 88,
+        72, 120, 104, 24, 8, 56, 40, 216, 200, 248, 232, 152, 136, 184, 168, 1376,
+        1312, 1504, 1440, 1120, 1056, 1248, 1184, 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, 688,
+        656, 752, 720, 560, 528, 624, 592, 944, 912, 1008, 976, 816, 784, 880, 848
+    };
+    const Sint16 mulaw_lut[256] = {
+        -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956, -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764, -15996,
+        -15484, -14972, -14460, -13948, -13436, -12924, -12412, -11900, -11388, -10876, -10364, -9852, -9340, -8828, -8316, -7932,
+        -7676, -7420, -7164, -6908, -6652, -6396, -6140, -5884, -5628, -5372, -5116, -4860, -4604, -4348, -4092, -3900,
+        -3772, -3644, -3516, -3388, -3260, -3132, -3004, -2876, -2748, -2620, -2492, -2364, -2236, -2108, -1980, -1884,
+        -1820, -1756, -1692, -1628, -1564, -1500, -1436, -1372, -1308, -1244, -1180, -1116, -1052, -988, -924, -876,
+        -844, -812, -780, -748, -716, -684, -652, -620, -588, -556, -524, -492, -460, -428, -396, -372,
+        -356, -340, -324, -308, -292, -276, -260, -244, -228, -212, -196, -180, -164, -148, -132, -120,
+        -112, -104, -96, -88, -80, -72, -64, -56, -48, -40, -32, -24, -16, -8, 0, 32124,
+        31100, 30076, 29052, 28028, 27004, 25980, 24956, 23932, 22908, 21884, 20860, 19836, 18812, 17788, 16764, 15996,
+        15484, 14972, 14460, 13948, 13436, 12924, 12412, 11900, 11388, 10876, 10364, 9852, 9340, 8828, 8316, 7932,
+        7676, 7420, 7164, 6908, 6652, 6396, 6140, 5884, 5628, 5372, 5116, 4860, 4604, 4348, 4092, 3900,
+        3772, 3644, 3516, 3388, 3260, 3132, 3004, 2876, 2748, 2620, 2492, 2364, 2236, 2108, 1980, 1884,
+        1820, 1756, 1692, 1628, 1564, 1500, 1436, 1372, 1308, 1244, 1180, 1116, 1052, 988, 924, 876,
+        844, 812, 780, 748, 716, 684, 652, 620, 588, 556, 524, 492, 460, 428, 396, 372,
+        356, 340, 324, 308, 292, 276, 260, 244, 228, 212, 196, 180, 164, 148, 132, 120,
+        112, 104, 96, 88, 80, 72, 64, 56, 48, 40, 32, 24, 16, 8, 0
+    };
+#endif
+
+    WaveFormat *format = &file->format;
+    WaveChunk *chunk = &file->chunk;
+    size_t i, sample_count, expanded_len;
+    Uint8 *src;
+    Sint16 *dst;
+
+    if (chunk->length != chunk->size) {
+        file->sampleframes = WaveAdjustToFactValue(file, chunk->size / format->blockalign);
+        if (file->sampleframes < 0) {
+            return -1;
+        }
+    }
+
+    /* Nothing to decode, nothing to return. */
+    if (file->sampleframes == 0) {
+        *audio_buf = NULL;
+        *audio_len = 0;
+        return 0;
+    }
+
+    sample_count = (size_t)file->sampleframes;
+    if (SafeMult(&sample_count, format->channels)) {
+        return SDL_OutOfMemory();
+    }
+
+    expanded_len = sample_count;
+    if (SafeMult(&expanded_len, sizeof(Sint16))) {
+        return SDL_OutOfMemory();
+    } else if (expanded_len > SDL_MAX_UINT32 || file->sampleframes > SIZE_MAX) {
+        return SDL_SetError("WAVE file too big");
+    }
+
+    /* 1 to avoid allocating zero bytes, to keep static analysis happy. */
+    src = (Uint8 *)SDL_realloc(chunk->data, expanded_len ? expanded_len : 1);
+    if (src == NULL) {
+        return SDL_OutOfMemory();
+    }
+    chunk->data = NULL;
+    chunk->size = 0;
+
+    dst = (Sint16 *)src;
+
+    /* Work backwards, since we're expanding in-place. SDL_AudioSpec.format will
+     * inform the caller about the byte order.
+     */
+    i = sample_count;
+    switch (file->format.encoding) {
+#ifdef SDL_WAVE_LAW_LUT
+    case ALAW_CODE:
+        while (i--) {
+            dst[i] = alaw_lut[src[i]];
+        }
+        break;
+    case MULAW_CODE:
+        while (i--) {
+            dst[i] = mulaw_lut[src[i]];
+        }
+        break;
+#else
+    case ALAW_CODE:
+        while (i--) {
+            Uint8 nibble = src[i];
+            Uint8 exponent = (nibble & 0x7f) ^ 0x55;
+            Sint16 mantissa = exponent & 0xf;
+
+            exponent >>= 4;
+            if (exponent > 0) {
+                mantissa |= 0x10;
+            }
+            mantissa = (mantissa << 4) | 0x8;
+            if (exponent > 1) {
+                mantissa <<= exponent - 1;
+            }
+
+            dst[i] = nibble & 0x80 ? mantissa : -mantissa;
+        }
+        break;
+    case MULAW_CODE:
+        while (i--) {
+            Uint8 nibble = ~src[i];
+            Sint16 mantissa = nibble & 0xf;
+            Uint8 exponent = (nibble >> 4) & 0x7;
+            Sint16 step = 4 << (exponent + 1);
+
+            mantissa = (0x80 << exponent) + step * mantissa + step / 2 - 132;
+
+            dst[i] = nibble & 0x80 ? -mantissa : mantissa;
+        }
+        break;
+#endif
+    default:
+        SDL_free(src);
+        return SDL_SetError("Unknown companded encoding");
+    }
+
+    *audio_buf = src;
+    *audio_len = (Uint32)expanded_len;
+
+    return 0;
+}
+
+static int
+PCM_Init(WaveFile *file, size_t datalength)
+{
+    WaveFormat *format = &file->format;
+
+    if (format->encoding == PCM_CODE) {
+        switch (format->bitspersample) {
+        case 8:
+        case 16:
+        case 24:
+        case 32:
+            /* These are supported. */
+            break;
+        default:
+            return SDL_SetError("%u-bit PCM format not supported", (unsigned int)format->bitspersample);
+        }
+    } else if (format->encoding == IEEE_FLOAT_CODE) {
+        if (format->bitspersample != 32) {
+            return SDL_SetError("%u-bit IEEE floating-point format not supported", (unsigned int)format->bitspersample);
+        }
+    }
+
+    /* It wouldn't be that hard to support more exotic block sizes, but
+     * the most common formats should do for now.
+     */
+    if (format->blockalign * 8 != format->channels * format->bitspersample) {
+        return SDL_SetError("Unsupported block alignment");
+    }
+
+    if ((file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict)) {
+        if (format->blockalign > 1 && datalength % format->blockalign) {
+            return SDL_SetError("Truncated data chunk in WAVE file");
+        }
+    }
+
+    file->sampleframes = WaveAdjustToFactValue(file, datalength / format->blockalign);
+    if (file->sampleframes < 0) {
+        return -1;
+    }
+
+    return 0;
+}
+
+static int
+PCM_ConvertSint24ToSint32(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
+{
+    WaveFormat *format = &file->format;
+    WaveChunk *chunk = &file->chunk;
+    size_t i, expanded_len, sample_count;
+    Uint8 *ptr;
+
+    sample_count = (size_t)file->sampleframes;
+    if (SafeMult(&sample_count, format->channels)) {
+        return SDL_OutOfMemory();
+    }
+
+    expanded_len = sample_count;
+    if (SafeMult(&expanded_len, sizeof(Sint32))) {
+        return SDL_OutOfMemory();
+    } else if (expanded_len > SDL_MAX_UINT32 || file->sampleframes > SIZE_MAX) {
+        return SDL_SetError("WAVE file too big");
+    }
+
+    /* 1 to avoid allocating zero bytes, to keep static analysis happy. */
+    ptr = (Uint8 *)SDL_realloc(chunk->data, expanded_len ? expanded_len : 1);
+    if (ptr == NULL) {
+        return SDL_OutOfMemory();
+    }
+
+    /* This pointer is now invalid. */
+    chunk->data = NULL;
+    chunk->size = 0;
+
+    *audio_buf = ptr;
+    *audio_len = (Uint32)expanded_len;
+
+    /* work from end to start, since we're expanding in-place. */
+    for (i = sample_count; i > 0; i--) {
+        const size_t o = i - 1;
+        uint8_t b[4];
+
+        b[0] = 0;
+        b[1] = ptr[o * 3];
+        b[2] = ptr[o * 3 + 1];
+        b[3] = ptr[o * 3 + 2];
+
+        ptr[o * 4 + 0] = b[0];
+        ptr[o * 4 + 1] = b[1];
+        ptr[o * 4 + 2] = b[2];
+        ptr[o * 4 + 3] = b[3];
+    }
+
+    return 0;
+}
+
+static int
+PCM_Decode(WaveFile *file, Uint8 **audio_buf, Uint32 *audio_len)
+{
+    WaveFormat *format = &file->format;
+    WaveChunk *chunk = &file->chunk;
+    size_t outputsize;
+
+    if (chunk->length != chunk->size) {
+        file->sampleframes = WaveAdjustToFactValue(file, chunk->size / format->blockalign);
+        if (file->sampleframes < 0) {
+            return -1;
+        }
+    }
+
+    /* Nothing to decode, nothing to return. */
+    if (file->sampleframes == 0) {
+        *audio_buf = NULL;
+        *audio_len = 0;
+        return 0;
+    }
+
+    /* 24-bit samples get shifted to 32 bits. */
+    if (format->encoding == PCM_CODE && format->bitspersample == 24) {
+        return PCM_ConvertSint24ToSint32(file, audio_buf, audio_len);
+    }
+
+    outputsize = (size_t)file->sampleframes;
+    if (SafeMult(&outputsize, format->blockalign)) {
+        return SDL_OutOfMemory();
+    } else if (outputsize > SDL_MAX_UINT32 || file->sampleframes > SIZE_MAX) {
+        return SDL_SetError("WAVE file too big");
+    }
+
+    *audio_buf = chunk->data;
+    *audio_len = (Uint32)outputsize;
+
+    /* This pointer is going to be returned to the caller. Prevent free in cleanup. */
+    chunk->data = NULL;
+    chunk->size = 0;
+
+    return 0;
+}
+
+static WaveRiffSizeHint
+WaveGetRiffSizeHint()
+{
+    const char *hint = SDL_GetHint(SDL_HINT_WAVE_RIFF_CHUNK_SIZE);
+
+    if (hint != NULL) {
+        if (SDL_strcmp(hint, "force") == 0) {
+            return RiffSizeForce;
+        } else if (SDL_strcmp(hint, "ignore") == 0) {
+            return RiffSizeIgnore;
+        } else if (SDL_strcmp(hint, "ignorezero") == 0) {
+            return RiffSizeIgnoreZero;
+        } else if (SDL_strcmp(hint, "maximum") == 0) {
+            return RiffSizeMaximum;
+        }
+    }
 
+    return RiffSizeNoHint;
+}
+
+static WaveTruncationHint
+WaveGetTruncationHint()
+{
+    const char *hint = SDL_GetHint(SDL_HINT_WAVE_TRUNCATION);
+
+    if (hint != NULL) {
+        if (SDL_strcmp(hint, "verystrict") == 0) {
+            return TruncVeryStrict;
+        } else if (SDL_strcmp(hint, "strict") == 0) {
+            return TruncStrict;
+        } else if (SDL_strcmp(hint, "dropframe") == 0) {
+            return TruncDropFrame;
+        } else if (SDL_strcmp(hint, "dropblock") == 0) {
+            return TruncDropBlock;
+        }
+    }
 
-static int ReadChunk(SDL_RWops * src, Chunk * chunk);
+    return TruncNoHint;
+}
 
-struct MS_ADPCM_decodestate
+static WaveFactChunkHint
+WaveGetFactChunkHint()
 {
-    Uint8 hPredictor;
-    Uint16 iDelta;
-    Sint16 iSamp1;
-    Sint16 iSamp2;
-};
-static struct MS_ADPCM_decoder
+    const char *hint = SDL_GetHint(SDL_HINT_WAVE_FACT_CHUNK);
+
+    if (hint != NULL) {
+        if (SDL_strcmp(hint, "truncate") == 0) {
+            return FactTruncate;
+        } else if (SDL_strcmp(hint, "strict") == 0) {
+            return FactStrict;
+        } else if (SDL_strcmp(hint, "ignorezero") == 0) {
+            return FactIgnoreZero;
+        } else if (SDL_strcmp(hint, "ignore") == 0) {
+            return FactIgnore;
+        }
+    }
+
+    return FactNoHint;
+}
+
+static void
+WaveFreeChunkData(WaveChunk *chunk)
 {
-    WaveFMT wavefmt;
-    Uint16 wSamplesPerBlock;
-    Uint16 wNumCoef;
-    Sint16 aCoeff[7][2];
-    /* * * */
-    struct MS_ADPCM_decodestate state[2];
-} MS_ADPCM_state;
+    if (chunk->data != NULL) {
+        SDL_free(chunk->data);
+        chunk->data = NULL;
+    }
+    chunk->size = 0;
+}
 
 static int
-InitMS_ADPCM(WaveFMT * format)
-{
-    Uint8 *rogue_feel;
-    int i;
-
-    /* Set the rogue pointer to the MS_ADPCM specific data */
-    MS_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding);
-    MS_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels);
-    MS_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency);
-    MS_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate);
-    MS_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign);
-    MS_ADPCM_state.wavefmt.bitspersample =
-        SDL_SwapLE16(format->bitspersample);
-    rogue_feel = (Uint8 *) format + sizeof(*format);
-    if (sizeof(*format) == 16) {
-        /* const Uint16 extra_info = ((rogue_feel[1] << 8) | rogue_feel[0]); */
-        rogue_feel += sizeof(Uint16);
-    }
-    MS_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1] << 8) | rogue_feel[0]);
-    rogue_feel += sizeof(Uint16);
-    MS_ADPCM_state.wNumCoef = ((rogue_feel[1] << 8) | rogue_feel[0]);
-    rogue_feel += sizeof(Uint16);
-    if (MS_ADPCM_state.wNumCoef != 7) {
-        SDL_SetError("Unknown set of MS_ADPCM coefficients");
-        return (-1);
-    }
-    for (i = 0; i < MS_ADPCM_state.wNumCoef; ++i) {
-        MS_ADPCM_state.aCoeff[i][0] = ((rogue_feel[1] << 8) | rogue_feel[0]);
-        rogue_feel += sizeof(Uint16);
-        MS_ADPCM_state.aCoeff[i][1] = ((rogue_feel[1] << 8) | rogue_feel[0]);
-        rogue_feel += sizeof(Uint16);
-    }
-    return (0);
-}
-
-static Sint32
-MS_ADPCM_nibble(struct MS_ADPCM_decodestate *state,
-                Uint8 nybble, Sint16 * coeff)
-{
-    const Sint32 max_audioval = ((1 << (16 - 1)) - 1);
-    const Sint32 min_audioval = -(1 << (16 - 1));
-    const Sint32 adaptive[] = {
-        230, 230, 230, 230, 307, 409, 512, 614,
-        768, 614, 512, 409, 307, 230, 230, 230
-    };
-    Sint32 new_sample, delta;
+WaveNextChunk(SDL_RWops *src, WaveChunk *chunk)
+{
+    Uint32 chunkheader[2];
+    Sint64 nextposition = chunk->position + chunk->length;
 
-    new_sample = ((state->iSamp1 * coeff[0]) +
-                  (state->iSamp2 * coeff[1])) / 256;
-    if (nybble & 0x08) {
-        new_sample += state->iDelta * (nybble - 0x10);
-    } else {
-        new_sample += state->iDelta * nybble;
+    /* Data is no longer valid after this function returns. */
+    WaveFreeChunkData(chunk);
+
+    /* Error on overflows. */
+    if (SDL_MAX_SINT64 - chunk->length < chunk->position || SDL_MAX_SINT64 - 8 < nextposition) {
+        return -1;
     }
-    if (new_sample < min_audioval) {
-        new_sample = min_audioval;
-    } else if (new_sample > max_audioval) {
-        new_sample = max_audioval;
+
+    /* RIFF chunks have a 2-byte alignment. Skip padding byte. */
+    if (chunk->length & 1) {
+        nextposition++;
     }
-    delta = ((Sint32) state->iDelta * adaptive[nybble]) / 256;
-    if (delta < 16) {
-        delta = 16;
+
+    if (SDL_RWseek(src, nextposition, RW_SEEK_SET) != nextposition) {
+        /* Not sure how we ended up here. Just abort. */
+        return -2;
+    } else if (SDL_RWread(src, chunkheader, 4, 2) != 2) {
+        return -1;
     }
-    state->iDelta = (Uint16) delta;
-    state->iSamp2 = state->iSamp1;
-    state->iSamp1 = (Sint16) new_sample;
-    return (new_sample);
+
+    chunk->fourcc = SDL_SwapLE32(chunkheader[0]);
+    chunk->length = SDL_SwapLE32(chunkheader[1]);
+    chunk->position = nextposition + 8;
+
+    return 0;
 }
 
 static int
-MS_ADPCM_decode(Uint8 ** audio_buf, Uint32 * audio_len)
-{
-    struct MS_ADPCM_decodestate *state[2];
-    Uint8 *freeable, *encoded, *decoded;
-    Sint32 encoded_len, samplesleft;
-    Sint8 nybble;
-    Uint8 stereo;
-    Sint16 *coeff[2];
-    Sint32 new_sample;
+WaveReadPartialChunkData(SDL_RWops *src, WaveChunk *chunk, size_t length)
+{
+    WaveFreeChunkData(chunk);
 
-    /* Allocate the proper sized output buffer */
-    encoded_len = *audio_len;
-    encoded = *audio_buf;
-    freeable = *audio_buf;
-    *audio_len = (encoded_len / MS_ADPCM_state.wavefmt.blockalign) *
-        MS_ADPCM_state.wSamplesPerBlock *
-        MS_ADPCM_state.wavefmt.channels * sizeof(Sint16);
-    *audio_buf = (Uint8 *) SDL_malloc(*audio_len);
-    if (*audio_buf == NULL) {
-        return SDL_OutOfMemory();
+    if (length > chunk->length) {
+        length = chunk->length;
+    }
+
+    if (length > 0) {
+        chunk->data = SDL_malloc(length);
+        if (chunk->data == NULL) {
+            return SDL_OutOfMemory();
+        }
+
+        if (SDL_RWseek(src, chunk->position, RW_SEEK_SET) != chunk->position) {
+            /* Not sure how we ended up here. Just abort. */
+            return -2;
+        }
+
+        chunk->size = SDL_RWread(src, chunk->data, 1, length);
+        if (chunk->size != length) {
+            /* Expected to be handled by the caller. */
+        }
     }
-    decoded = *audio_buf;
-
-    /* Get ready... Go! */
-    stereo = (MS_ADPCM_state.wavefmt.channels == 2);
-    state[0] = &MS_ADPCM_state.state[0];
-    state[1] = &MS_ADPCM_state.state[stereo];
-    while (encoded_len >= MS_ADPCM_state.wavefmt.blockalign) {
-        /* Grab the initial information for this block */
-        state[0]->hPredictor = *encoded++;
-        if (stereo) {
-            state[1]->hPredictor = *encoded++;
-        }
-        state[0]->iDelta = ((encoded[1] << 8) | encoded[0]);
-        encoded += sizeof(Sint16);
-        if (stereo) {
-            state[1]->iDelta = ((encoded[1] << 8) | encoded[0]);
-            encoded += sizeof(Sint16);
-        }
-        state[0]->iSamp1 = ((encoded[1] << 8) | encoded[0]);
-        encoded += sizeof(Sint16);
-        if (stereo) {
-            state[1]->iSamp1 = ((encoded[1] << 8) | encoded[0]);
-            encoded += sizeof(Sint16);
-        }
-        state[0]->iSamp2 = ((encoded[1] << 8) | encoded[0]);
-        encoded += sizeof(Sint16);
-        if (stereo) {
-            state[1]->iSamp2 = ((encoded[1] << 8) | encoded[0]);
-            encoded += sizeof(Sint16);
-        }
-        coeff[0] = MS_ADPCM_state.aCoeff[state[0]->hPredictor];
-        coeff[1] = MS_ADPCM_state.aCoeff[state[1]->hPredictor];
-
-        /* Store the two initial samples we start with */
-        decoded[0] = state[0]->iSamp2 & 0xFF;
-        decoded[1] = state[0]->iSamp2 >> 8;
-        decoded += 2;
-        if (stereo) {
-            decoded[0] = state[1]->iSamp2 & 0xFF;
-            decoded[1] = state[1]->iSamp2 >> 8;
-            decoded += 2;
-        }
-        decoded[0] = state[0]->iSamp1 & 0xFF;
-        decoded[1] = state[0]->iSamp1 >> 8;
-        decoded += 2;
-        if (stereo) {
-            decoded[0] = state[1]->iSamp1 & 0xFF;
-            decoded[1] = state[1]->iSamp1 >> 8;
-            decoded += 2;
-        }
-
-        /* Decode and store the other samples in this block */
-        samplesleft = (MS_ADPCM_state.wSamplesPerBlock - 2) *
-            MS_ADPCM_state.wavefmt.channels;
-        while (samplesleft > 0) {
-            nybble = (*encoded) >> 4;
-            new_sample = MS_ADPCM_nibble(state[0], nybble, coeff[0]);
-            decoded[0] = new_sample & 0xFF;
-            new_sample >>= 8;
-            decoded[1] = new_sample & 0xFF;
-            decoded += 2;
-
-            nybble = (*encoded) & 0x0F;
-            new_sample = MS_ADPCM_nibble(state[1], nybble, coeff[1]);
-            decoded[0] = new_sample & 0xFF;
-            new_sample >>= 8;
-            decoded[1] = new_sample & 0xFF;
-            decoded += 2;
-
-            ++encoded;
-            samplesleft -= 2;
-        }
-        encoded_len -= MS_ADPCM_state.wavefmt.blockalign;
-    }
-    SDL_free(freeable);
-    return (0);
-}
-
-struct IMA_ADPCM_decodestate
+
+    return 0;
+}
+
+static int
+WaveReadChunkData(SDL_RWops *src, WaveChunk *chunk)
 {
-    Sint32 sample;
-    Sint8 index;
+    return WaveReadPartialChunkData(src, chunk, chunk->length);
+}
+
+typedef struct WaveExtensibleGUID {
+    Uint16 encoding;
+    Uint8 guid[16];
+} WaveExtensibleGUID;
+
+/* Some of the GUIDs that are used by WAVEFORMATEXTENSIBLE. */
+#define WAVE_FORMATTAG_GUID(tag) {(tag) & 0xff, (tag) >> 8, 0, 0, 0, 0, 16, 0, 128, 0, 0, 170, 0, 56, 155, 113}
+static WaveExtensibleGUID extensible_guids[] = {
+    {PCM_CODE,        WAVE_FORMATTAG_GUID(PCM_CODE)},
+    {MS_ADPCM_CODE,   WAVE_FORMATTAG_GUID(MS_ADPCM_CODE)},
+    {IEEE_FLOAT_CODE, WAVE_FORMATTAG_GUID(IEEE_FLOAT_CODE)},
+    {ALAW_CODE,       WAVE_FORMATTAG_GUID(ALAW_CODE)},
+    {MULAW_CODE,      WAVE_FORMATTAG_GUID(MULAW_CODE)},
+    {IMA_ADPCM_CODE,  WAVE_FORMATTAG_GUID(IMA_ADPCM_CODE)}
 };
-static struct IMA_ADPCM_decoder
+
+static Uint16
+WaveGetFormatGUIDEncoding(WaveFormat *format)
 {
-    WaveFMT wavefmt;
-    Uint16 wSamplesPerBlock;
-    /* * * */
-    struct IMA_ADPCM_decodestate state[2];
-} IMA_ADPCM_state;
+    size_t i;
+    for (i = 0; i < SDL_arraysize(extensible_guids); i++) {
+        if (SDL_memcmp(format->subformat, extensible_guids[i].guid, 16) == 0) {
+            return extensible_guids[i].encoding;
+        }
+    }
+    return UNKNOWN_CODE;
+}
 
 static int
-InitIMA_ADPCM(WaveFMT * format)
+WaveReadFormat(WaveFile *file)
 {
-    Uint8 *rogue_feel;
+    WaveChunk *chunk = &file->chunk;
+    WaveFormat *format = &file->format;
+    SDL_RWops *fmtsrc;
+    size_t fmtlen = chunk->size;
 
-    /* Set the rogue pointer to the IMA_ADPCM specific data */
-    IMA_ADPCM_state.wavefmt.encoding = SDL_SwapLE16(format->encoding);
-    IMA_ADPCM_state.wavefmt.channels = SDL_SwapLE16(format->channels);
-    IMA_ADPCM_state.wavefmt.frequency = SDL_SwapLE32(format->frequency);
-    IMA_ADPCM_state.wavefmt.byterate = SDL_SwapLE32(format->byterate);
-    IMA_ADPCM_state.wavefmt.blockalign = SDL_SwapLE16(format->blockalign);
-    IMA_ADPCM_state.wavefmt.bitspersample =
-        SDL_SwapLE16(format->bitspersample);
-    rogue_feel = (Uint8 *) format + sizeof(*format);
-    if (sizeof(*format) == 16) {
-        /* const Uint16 extra_info = ((rogue_feel[1] << 8) | rogue_feel[0]); */
-        rogue_feel += sizeof(Uint16);
+    if (fmtlen > SDL_MAX_SINT32) {
+        /* Limit given by SDL_RWFromConstMem. */
+        return SDL_SetError("Data of WAVE fmt chunk too big");
+    }
+    fmtsrc = SDL_RWFromConstMem(chunk->data, (int)chunk->size);
+    if (fmtsrc == NULL) {
+        return SDL_OutOfMemory();
     }
-    IMA_ADPCM_state.wSamplesPerBlock = ((rogue_feel[1] << 8) | rogue_feel[0]);
-    return (0);
-}
 
-static Sint32
-IMA_ADPCM_nibble(struct IMA_ADPCM_decodestate *state, Uint8 nybble)
-{
-    const Sint32 max_audioval = ((1 << (16 - 1)) - 1);
-    const Sint32 min_audioval = -(1 << (16 - 1));
-    const int index_table[16] = {
-        -1, -1, -1, -1,
-        2, 4, 6, 8,
-        -1, -1, -1, -1,
-        2, 4, 6, 8
-    };
-    const Sint32 step_table[89] = {
-        7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31,
-        34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130,
-        143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408,
-        449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282,
-        1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327,
-        3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630,
-        9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350,
-        22385, 24623, 27086, 29794, 32767
-    };
-    Sint32 delta, step;
+    format->formattag = SDL_ReadLE16(fmtsrc);
+    format->encoding = format->formattag;
+    format->channels = SDL_ReadLE16(fmtsrc);
+    format->frequency = SDL_ReadLE32(fmtsrc);
+    format->byterate = SDL_ReadLE32(fmtsrc);
+    format->blockalign = SDL_ReadLE16(fmtsrc);
 
-    /* Compute difference and new sample value */
-    if (state->index > 88) {
-        state->index = 88;
-    } else if (state->index < 0) {
-        state->index = 0;
+    /* This is PCM specific in the first version of the specification. */
+    if (fmtlen >= 16) {
+        format->bitspersample = SDL_ReadLE16(fmtsrc);
+    } else if (format->encoding == PCM_CODE) {
+        SDL_RWclose(fmtsrc);
+        return SDL_SetError("Missing wBitsPerSample field in WAVE fmt chunk");
     }
-    /* explicit cast to avoid gcc warning about using 'char' as array index */
-    step = step_table[(int)state->index];
-    delta = step >> 3;
-    if (nybble & 0x04)
-        delta += step;
-    if (nybble & 0x02)
-        delta += (step >> 1);
-    if (nybble & 0x01)
-        delta += (step >> 2);
-    if (nybble & 0x08)
-        delta = -delta;
-    state->sample += delta;
 
-    /* Update index value */
-    state->index += index_table[nybble];
+    /* The earlier versions also don't have this field. */
+    if (fmtlen >= 18) {
+        format->extsize = SDL_ReadLE16(fmtsrc);
+    }
 
-    /* Clamp output sample */
-    if (state->sample > max_audioval) {
-        state->sample = max_audioval;
-    } else if (state->sample < min_audioval) {
-        state->sample = min_audioval;
+    if (format->formattag == EXTENSIBLE_CODE) {
+        /* note that this ignores channel masks, smaller valid bit counts
+         * inside a larger container, and most subtypes. This is just enough
+         * to get things that didn't really _need_ WAVE_FORMAT_EXTENSIBLE
+         * to be useful working when they use this format flag.
+         */
+
+        /* Extensible header must be at least 22 bytes. */
+        if (fmtlen < 40 || format->extsize < 22) {
+            SDL_RWclose(fmtsrc);
+            return SDL_SetError("Extensible WAVE header too small");
+        }
+
+        format->validsamplebits = SDL_ReadLE16(fmtsrc);
+        format->samplesperblock = format->validsamplebits;
+        format->channelmask = SDL_ReadLE32(fmtsrc);
+        SDL_RWread(fmtsrc, format->subformat, 1, 16);
+        format->encoding = WaveGetFormatGUIDEncoding(format);
     }
-    return (state->sample);
+
+    SDL_RWclose(fmtsrc);
+
+    return 0;
 }
 
-/* Fill the decode buffer with a channel block of data (8 samples) */
-static void
-Fill_IMA_ADPCM_block(Uint8 * decoded, Uint8 * encoded,
-                     int channel, int numchannels,
-                     struct IMA_ADPCM_decodestate *state)
+static int
+WaveCheckFormat(WaveFile *file, size_t datalength)
 {
-    int i;
-    Sint8 nybble;
-    Sint32 new_sample;
+    WaveFormat *format = &file->format;
 
-    decoded += (channel * 2);
-    for (i = 0; i < 4; ++i) {
-        nybble = (*encoded) & 0x0F;
-        new_sample = IMA_ADPCM_nibble(state, nybble);
-        decoded[0] = new_sample & 0xFF;
-        new_sample >>= 8;
-        decoded[1] = new_sample & 0xFF;
-        decoded += 2 * numchannels;
+    /* Check for some obvious issues. */
 
-        nybble = (*encoded) >> 4;
-        new_sample = IMA_ADPCM_nibble(state, nybble);
-        decoded[0] = new_sample & 0xFF;
-        new_sample >>= 8;
-        decoded[1] = new_sample & 0xFF;
-        decoded += 2 * numchannels;
+    if (format->channels == 0) {
+        return SDL_SetError("Invalid number of channels");
+    } else if (format->channels > 255) {
+        /* Limit given by SDL_AudioSpec.channels. */
+        return SDL_SetError("Number of channels exceeds limit of 255");
+    }
 
-        ++encoded;
+    if (format->frequency == 0) {
+        return SDL_SetError("Invalid sample rate");
+    } else if (format->frequency > INT_MAX) {
+        /* Limit given by SDL_AudioSpec.freq. */
+        return SDL_SetError("Sample rate exceeds limit of %d", INT_MAX);
     }
-}
 
-static int
-IMA_ADPCM_decode(Uint8 ** audio_buf, Uint32 * audio_len)
-{
-    struct IMA_ADPCM_decodestate *state;
-    Uint8 *freeable, *encoded, *decoded;
-    Sint32 encoded_len, samplesleft;
-    unsigned int c, channels;
-
-    /* Check to make sure we have enough variables in the state array */
-    channels = IMA_ADPCM_state.wavefmt.channels;
-    if (channels > SDL_arraysize(IMA_ADPCM_state.state)) {
-        SDL_SetError("IMA ADPCM decoder can only handle %u channels",
-                     (unsigned int)SDL_arraysize(IMA_ADPCM_state.state));
-        return (-1);
-    }
-    state = IMA_ADPCM_state.state;
-
-    /* Allocate the proper sized output buffer */
-    encoded_len = *audio_len;
-    encoded = *audio_buf;
-    freeable = *audio_buf;
-    *audio_len = (encoded_len / IMA_ADPCM_state.wavefmt.blockalign) *
-        IMA_ADPCM_state.wSamplesPerBlock *
-        IMA_ADPCM_state.wavefmt.channels * sizeof(Sint16);
-    *audio_buf = (Uint8 *) SDL_malloc(*audio_len);
-    if (*audio_buf == NULL) {
-        return SDL_OutOfMemory();
+    /* Reject invalid fact chunks in strict mode. */
+    if (file->facthint == FactStrict && file->fact.status == -1) {
+        return SDL_SetError("Invalid fact chunk in WAVE file");
     }
-    decoded = *audio_buf;
-
-    /* Get ready... Go! */
-    while (encoded_len >= IMA_ADPCM_state.wavefmt.blockalign) {
-        /* Grab the initial information for this block */
-        for (c = 0; c < channels; ++c) {
-            /* Fill the state information for this block */
-            state[c].sample = ((encoded[1] << 8) | encoded[0]);
-            encoded += 2;
-            if (state[c].sample & 0x8000) {
-                state[c].sample -= 0x10000;
-            }
-            state[c].index = *encoded++;
-            /* Reserved byte in buffer header, should be 0 */
-            if (*encoded++ != 0) {
-                /* Uh oh, corrupt data?  Buggy code? */ ;
-            }
 
-            /* Store the initial sample we start with */
-            decoded[0] = (Uint8) (state[c].sample & 0xFF);
-            decoded[1] = (Uint8) (state[c].sample >> 8);
-            decoded += 2;
+    /* Check for issues common to all encodings. Some unsupported formats set
+     * the bits per sample to zero. These fall through to the 'unsupported
+     * format' error.
+     */
+    switch (format->encoding) {
+    case IEEE_FLOAT_CODE:
+    case ALAW_CODE:
+    case MULAW_CODE:
+    case MS_ADPCM_CODE:
+    case IMA_ADPCM_CODE:
+        /* These formats require a fact chunk. */
+        if (file->facthint == FactStrict && file->fact.status <= 0) {
+            return SDL_SetError("Missing fact chunk in WAVE file");
+        }
+        /* fallthrough */
+    case PCM_CODE:
+        /* All supported formats require a non-zero bit depth. */
+        if (file->chunk.size < 16) {
+            return SDL_SetError("Missing wBitsPerSample field in WAVE fmt chunk");
+        } else if (format->bitspersample == 0) {
+            return SDL_SetError("Invalid bits per sample");
+        }
+
+        /* All supported formats must have a proper block size. */
+        if (format->blockalign == 0) {
+            return SDL_SetError("Invalid block alignment");
         }
 
-        /* Decode and store the other samples in this block */
-        samplesleft = (IMA_ADPCM_state.wSamplesPerBlock - 1) * channels;
-        while (samplesleft > 0) {
-            for (c = 0; c < channels; ++c) {
-                Fill_IMA_ADPCM_block(decoded, encoded,
-                                     c, channels, &state[c]);
-                encoded += 4;
-                samplesleft -= 8;
+        /* If the fact chunk is valid and the appropriate hint is set, the
+         * decoders will use the number of sample frames from the fact chunk.
+         */
+        if (file->fact.status == 1) {
+            WaveFactChunkHint hint = file->facthint;
+            Uint32 samples = file->fact.samplelength;
+            if (hint == FactTruncate || hint == FactStrict || (hint == FactIgnoreZero && samples > 0)) {
+                file->fact.status = 2;
             }
-            decoded += (channels * 8 * 2);
         }
-        encoded_len -= IMA_ADPCM_state.wavefmt.blockalign;
     }
-    SDL_free(freeable);
-    return (0);
-}
 
+    /* Check the format for encoding specific issues and initialize decoders. */
+    switch (format->encoding) {
+    case PCM_CODE:
+    case IEEE_FLOAT_CODE:
+        if (PCM_Init(file, datalength) < 0) {
+            return -1;
+        }
+        break;
+    case ALAW_CODE:
+    case MULAW_CODE:
+        if (LAW_Init(file, datalength) < 0) {
+            return -1;
+        }
+        break;
+    case MS_ADPCM_CODE:
+        if (MS_ADPCM_Init(file, datalength) < 0) {
+            return -1;
+        }
+        break;
+    case IMA_ADPCM_CODE:
+        if (IMA_ADPCM_Init(file, datalength) < 0) {
+            return -1;
+        }
+        break;
+    case MPEG_CODE:
+    case MPEGLAYER3_CODE:
+        return SDL_SetError("MPEG formats not supported");
+    default:
+        if (format->formattag == EXTENSIBLE_CODE) {
+            const char *errstr = "Unknown WAVE format GUID: %08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x";
+            const Uint8 *g = format->subformat;
+            const Uint32 g1 = g[0] | ((Uint32)g[1] << 8) | ((Uint32)g[2] << 16) | ((Uint32)g[3] << 24);
+            const Uint32 g2 = g[4] | ((Uint32)g[5] << 8);
+            const Uint32 g3 = g[6] | ((Uint32)g[7] << 8);
+            return SDL_SetError(errstr, g1, g2, g3, g[8], g[9], g[10], g[11], g[12], g[13], g[14], g[15]);
+        }
+        return SDL_SetError("Unknown WAVE format tag: 0x%04x", (unsigned int)format->encoding);
+    }
+
+    return 0;
+}
 
 static int
-ConvertSint24ToSint32(Uint8 ** audio_buf, Uint32 * audio_len)
-{
-    const double DIVBY8388608 = 0.00000011920928955078125;
-    const Uint32 original_len = *audio_len;
-    const Uint32 samples = original_len / 3;
-    const Uint32 expanded_len = samples * sizeof (Uint32);
-    Uint8 *ptr = (Uint8 *) SDL_realloc(*audio_buf, expanded_len);
-    const Uint8 *src;
-    Uint32 *dst;
-    Uint32 i;
-
-    if (!ptr) {
-        return SDL_OutOfMemory();
+WaveLoad(SDL_RWops *src, WaveFile *file, SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
+{
+    int result;
+    Uint32 chunkcount = 0;
+    Uint32 chunkcountlimit = 10000;
+    char *envchunkcountlimit;
+    Sint64 RIFFstart, RIFFend, lastchunkpos;
+    SDL_bool RIFFlengthknown = SDL_FALSE;
+    WaveFormat *format = &file->format;
+    WaveChunk *chunk = &file->chunk;
+    WaveChunk RIFFchunk;
+    WaveChunk fmtchunk;
+    WaveChunk datachunk;
+
+    SDL_zero(RIFFchunk);
+    SDL_zero(fmtchunk);
+    SDL_zero(datachunk);
+
+    envchunkcountlimit = SDL_getenv("SDL_WAVE_CHUNK_LIMIT");
+    if (envchunkcountlimit != NULL) {
+        unsigned int count;
+        if (SDL_sscanf(envchunkcountlimit, "%u", &count) == 1) {
+            chunkcountlimit = count <= SDL_MAX_UINT32 ? count : SDL_MAX_UINT32;
+        }
     }
 
-    *audio_buf = ptr;
-    *audio_len = expanded_len;
+    RIFFstart = SDL_RWtell(src);
+    if (RIFFstart < 0) {
+        return SDL_SetError("Could not seek in file");
+    }
 
-    /* work from end to start, since we're expanding in-place. */
-    src = (ptr + original_len) - 3;
-    dst = ((Uint32 *) (ptr + expanded_len)) - 1;
-    for (i = 0; i < samples; i++) {
-        /* There's probably a faster way to do all this. */
-        const Sint32 converted = ((Sint32) ( (((Uint32) src[2]) << 24) |
-                                             (((Uint32) src[1]) << 16) |
-                                             (((Uint32) src[0]) << 8) )) >> 8;
-        const double scaled = (((double) converted) * DIVBY8388608);
-        src -= 3;
-        *(dst--) = (Sint32) (scaled * 2147483647.0);
+    RIFFchunk.position = RIFFstart;
+    if (WaveNextChunk(src, &RIFFchunk) < 0) {
+        return SDL_SetError("Could not read RIFF header");
     }
 
-    return 0;
-}
+    /* Check main WAVE file identifiers. */
+    if (RIFFchunk.fourcc == RIFF) {
+        Uint32 formtype;
+        /* Read the form type. "WAVE" expected. */
+        if (SDL_RWread(src, &formtype, sizeof(Uint32), 1) != 1) {
+            return SDL_SetError("Could not read RIFF form type");
+        } else if (SDL_SwapLE32(formtype) != WAVE) {
+            return SDL_SetError("RIFF form type is not WAVE (not a Waveform file)");
+        }
+    } else if (RIFFchunk.fourcc == WAVE) {
+        /* RIFF chunk missing or skipped. Length unknown. */
+        RIFFchunk.position = 0;
+        RIFFchunk.length = 0;
+    } else {
+        return SDL_SetError("Could not find RIFF or WAVE identifiers (not a Waveform file)");
+    }
 
+    /* The 4-byte form type is immediately followed by the first chunk.*/
+    chunk->position = RIFFchunk.position + 4;
 
-/* GUIDs that are used by WAVE_FORMAT_EXTENSIBLE */
-static const Uint8 extensible_pcm_guid[16] = { 1, 0, 0, 0, 0, 0, 16, 0, 128, 0, 0, 170, 0, 56, 155, 113 };
-static const Uint8 extensible_ieee_guid[16] = { 3, 0, 0, 0, 0, 0, 16, 0, 128, 0, 0, 170, 0, 56, 155, 113 };
+    /* Use the RIFF chunk size to limit the search for the chunks. This is not
+     * always reliable and the hint can be used to tune the behavior. By
+     * default, it will never search past 4 GiB.
+     */
+    switch (file->riffhint) {
+    case RiffSizeIgnore:
+        RIFFend = RIFFchunk.position + SDL_MAX_UINT32;
+        break;
+    default:
+    case RiffSizeIgnoreZero:
+        if (RIFFchunk.length == 0) {
+            RIFFend = RIFFchunk.position + SDL_MAX_UINT32;
+            break;
+        }
+        /* fallthrough */
+    case RiffSizeForce:
+        RIFFend = RIFFchunk.position + RIFFchunk.length;
+        RIFFlengthknown = SDL_TRUE;
+        break;
+    case RiffSizeMaximum:
+        RIFFend = SDL_MAX_SINT64;
+        break;
+    }
 
-SDL_AudioSpec *
-SDL_LoadWAV_RW(SDL_RWops * src, int freesrc,
-               SDL_AudioSpec * spec, Uint8 ** audio_buf, Uint32 * audio_len)
-{
-    int was_error;
-    Chunk chunk;
-    int lenread;
-    int IEEE_float_encoded, MS_ADPCM_encoded, IMA_ADPCM_encoded;
-    int samplesize;
+    /* Step through all chunks and save information on the fmt, data, and fact
+     * chunks. Ignore the chunks we don't know as per specification. This
+     * currently also ignores cue, list, and slnt chunks.
+     */
+    while ((Uint64)RIFFend > (Uint64)chunk->position + chunk->length + (chunk->length & 1)) {
+        /* Abort after too many chunks or else corrupt files may waste time. */
+        if (chunkcount++ >= chunkcountlimit) {
+            return SDL_SetError("Chunk count in WAVE file exceeds limit of %u", chunkcountlimit);
+        }
+
+        result = WaveNextChunk(src, chunk);
+        if (result == -1) {
+            /* Unexpected EOF. Corrupt file or I/O issues. */
+            if (file->trunchint == TruncVeryStrict) {
+                return SDL_SetError("Unexpected end of WAVE file");
+            }
+            /* Let the checks after this loop sort this issue out. */
+            break;
+        } else if (result == -2) {
+            return SDL_SetError("Could not seek to WAVE chunk header");
+        }
 
-    /* WAV magic header */
-    Uint32 RIFFchunk;
-    Uint32 wavelen = 0;
-    Uint32 WAVEmagic;
-    Uint32 headerDiff = 0;
+        if (chunk->fourcc == FMT) {
+            if (fmtchunk.fourcc == FMT) {
+                /* Multiple fmt chunks. Ignore or error? */
+            } else {
+                /* The fmt chunk must occur before the data chunk. */
+                if (datachunk.fourcc == DATA) {
+                    return SDL_SetError("fmt chunk after data chunk in WAVE file");
+                }
+                fmtchunk = *chunk;
+            }
+        } else if (chunk->fourcc == DATA) {
+            /* Only use the first data chunk. Handling the wavl list madness
+             * may require a different approach.
+             */
+            if (datachunk.fourcc != DATA) {
+                datachunk = *chunk;
+            }
+        } else if (chunk->fourcc == FACT) {
+            /* The fact chunk data must be at least 4 bytes for the
+             * dwSampleLength field. Ignore all fact chunks after the first one.
+             */
+            if (file->fact.status == 0) {
+                if (chunk->length < 4) {
+                    file->fact.status = -1;
+                } else {
+                    /* Let's use src directly, it's just too convenient. */
+                    Sint64 position = SDL_RWseek(src, chunk->position, RW_SEEK_SET);
+                    Uint32 samplelength;
+                    if (position == chunk->position && SDL_RWread(src, &samplelength, sizeof(Uint32), 1) == 1) {
+                        file->fact.status = 1;
+                        file->fact.samplelength = SDL_SwapLE32(samplelength);
+                    } else {
+                        file->fact.status = -1;
+                    }
+                }
+            }
+        }
 
-    /* FMT chunk */
-    WaveFMT *format = NULL;
-    WaveExtensibleFMT *ext = NULL;
+        /* Go through all chunks in verystrict mode or stop the search early if
+         * all required chunks were found.
+         */
+        if (file->trunchint == TruncVeryStrict) {
+            if ((Uint64)RIFFend < (Uint64)chunk->position + chunk->length) {
+                return SDL_SetError("RIFF size truncates chunk");
+            }
+        } else if (fmtchunk.fourcc == FMT && datachunk.fourcc == DATA) {
+            if (file->fact.status == 1 || file->facthint == FactIgnore || file->facthint == FactNoHint) {
+                break;
+            }
+        }
+    }
 
-    SDL_zero(chunk);
+    /* Save the position after the last chunk. This position will be used if the
+     * RIFF length is unknown.
+     */
+    lastchunkpos = chunk->position + chunk->length;
 
-    /* Make sure we are passed a valid data source */
-    was_error = 0;
-    if (src == NULL) {
-        was_error = 1;
-        goto done;
+    /* The fmt chunk is mandatory. */
+    if (fmtchunk.fourcc != FMT) {
+        return SDL_SetError("Missing fmt chunk in WAVE file");
+    }
+    /* A data chunk must be present. */
+    if (datachunk.fourcc != DATA) {
+        return SDL_SetError("Missing data chunk in WAVE file");
+    }
+    /* Check if the last chunk has all of its data in verystrict mode. */
+    if (file->trunchint == TruncVeryStrict) {
+        /* data chunk is handled later. */
+        if (chunk->fourcc != DATA && chunk->length > 0) {
+            Uint8 tmp;
+            Uint64 position = (Uint64)chunk->position + chunk->length - 1;
+            if (position > SDL_MAX_SINT64 || SDL_RWseek(src, (Sint64)position, RW_SEEK_SET) != (Sint64)position) {
+                return SDL_SetError("Could not seek to WAVE chunk data");
+            } else if (SDL_RWread(src, &tmp, 1, 1) != 1) {
+                return SDL_SetError("RIFF size truncates chunk");
+            }
+        }
     }
 
-    /* Check the magic header */
-    RIFFchunk = SDL_ReadLE32(src);
-    wavelen = SDL_ReadLE32(src);
-    if (wavelen == WAVE) {      /* The RIFFchunk has already been read */
-        WAVEmagic = wavelen;
-        wavelen = RIFFchunk;
-        RIFFchunk = RIFF;
-    } else {
-        WAVEmagic = SDL_ReadLE32(src);
-    }
-    if ((RIFFchunk != RIFF) || (WAVEmagic != WAVE)) {
-        SDL_SetError("Unrecognized file type (not WAVE)");
-        was_error = 1;
-        goto done;
-    }
-    headerDiff += sizeof(Uint32);       /* for WAVE */
-
-    /* Read the audio data format chunk */
-    chunk.data = NULL;
-    do {
-        SDL_free(chunk.data);
-        chunk.data = NULL;
-        lenread = ReadChunk(src, &chunk);
-        if (lenread < 0) {
-            was_error = 1;
-            goto done;
-        }
-        /* 2 Uint32's for chunk header+len, plus the lenread */
-        headerDiff += lenread + 2 * sizeof(Uint32);
-    } while ((chunk.magic == FACT) || (chunk.magic == LIST) || (chunk.magic == BEXT) || (chunk.magic == JUNK));
-
-    /* Decode the audio data format */
-    format = (WaveFMT *) chunk.data;
-    if (chunk.magic != FMT) {
-        SDL_SetError("Complex WAVE files not supported");
-        was_error = 1;
-        goto done;
-    }
-    IEEE_float_encoded = MS_ADPCM_encoded = IMA_ADPCM_encoded = 0;
-    switch (SDL_SwapLE16(format->encoding)) {
+    /* Process fmt chunk. */
+    *chunk = fmtchunk;
+
+    /* No need to read more than 1046 bytes of the fmt chunk data with the
+     * formats that are currently supported. (1046 because of MS ADPCM coefficients)
+     */
+    if (WaveReadPartialChunkData(src, chunk, 1046) < 0) {
+        return SDL_SetError("Could not read data of WAVE fmt chunk");
+    }
+
+    /* The fmt chunk data must be at least 14 bytes to include all common fields.
+     * It usually is 16 and larger depending on the header and encoding.
+     */
+    if (chunk->length < 14) {
+        return SDL_SetError("Invalid WAVE fmt chunk length (too small)");
+    } else if (chunk->size < 14) {
+        return SDL_SetError("Could not read data of WAVE fmt chunk");
+    } else if (WaveReadFormat(file) < 0) {
+        return -1;
+    } else if (WaveCheckFormat(file, (size_t)datachunk.length) < 0) {
+        return -1;
+    }
+
+#ifdef SDL_WAVE_DEBUG_LOG_FORMAT
+    WaveDebugLogFormat(file);
+#endif
+#ifdef SDL_WAVE_DEBUG_DUMP_FORMAT
+    WaveDebugDumpFormat(file, RIFFchunk.length, fmtchunk.length, datachunk.length);
+#endif
+
+    WaveFreeChunkData(chunk);
+
+    /* Process data chunk. */
+    *chunk = datachunk;
+
+    if (chunk->length > 0) {
+        result = WaveReadChunkData(src, chunk);
+        if (result == -1) {
+            return -1;
+        } else if (result == -2) {
+            return SDL_SetError("Could not seek data of WAVE data chunk");
+        }
+    }
+
+    if (chunk->length != chunk->size) {
+        /* I/O issues or corrupt file. */
+        if (file->trunchint == TruncVeryStrict || file->trunchint == TruncStrict) {
+            return SDL_SetError("Could not read data of WAVE data chunk");
+        }
+        /* The decoders handle this truncation. */
+    }
+
+    /* Decode or convert the data if necessary. */
+    switch (format->encoding) {
     case PCM_CODE:
-        /* We can understand this */
-        break;
     case IEEE_FLOAT_CODE:
-        IEEE_float_encoded = 1;
-        /* We can understand this */
+        if (PCM_Decode(file, audio_buf, audio_len) < 0) {
+            return -1;
+        }
         break;
-    case MS_ADPCM_CODE:
-        /* Try to understand this */
-        if (InitMS_ADPCM(format) < 0) {
-            was_error = 1;
-            goto done;
+    case ALAW_CODE:
+    case MULAW_CODE:
+        if (LAW_Decode(file, audio_buf, audio_len) < 0) {
+            return -1;
         }
-        MS_ADPCM_encoded = 1;
         break;
-    case IMA_ADPCM_CODE:
-        /* Try to understand this */
-        if (InitIMA_ADPCM(format) < 0) {
-            was_error = 1;
-            goto done;
+    case MS_ADPCM_CODE:
+        if (MS_ADPCM_Decode(file, audio_buf, audio_len) < 0) {
+            return -1;
         }
-        IMA_ADPCM_encoded = 1;
         break;
-    case EXTENSIBLE_CODE:
-        /* note that this ignores channel masks, smaller valid bit counts
-           inside a larger container, and most subtypes. This is just enough
-           to get things that didn't really _need_ WAVE_FORMAT_EXTENSIBLE
-           to be useful working when they use this format flag. */
-        ext = (WaveExtensibleFMT *) format;
-        if (SDL_SwapLE16(ext->size) < 22) {
-            SDL_SetError("bogus extended .wav header");
-            was_error = 1;
-            goto done;
-        }
-        if (SDL_memcmp(ext->subformat, extensible_pcm_guid, 16) == 0) {
-            break;  /* cool. */
-        } else if (SDL_memcmp(ext->subformat, extensible_ieee_guid, 16) == 0) {
-            IEEE_float_encoded = 1;
-            break;
+    case IMA_ADPCM_CODE:
+        if (IMA_ADPCM_Decode(file, audio_buf, audio_len) < 0) {
+            return -1;
         }
         break;
-    case MP3_CODE:
-        SDL_SetError("MPEG Layer 3 data not supported");
-        was_error = 1;
-        goto done;
-    default:
-        SDL_SetError("Unknown WAVE data format: 0x%.4x",
-                     SDL_SwapLE16(format->encoding));
-        was_error = 1;
-        goto done;
     }
+
+    /* Setting up the SDL_AudioSpec. All unsupported formats were filtered out
+     * by checks earlier in this function.
+     */
     SDL_zerop(spec);
-    spec->freq = SDL_SwapLE32(format->frequency);
+    spec->freq = format->frequency;
+    spec->channels = (Uint8)format->channels;
+    spec->samples = 4096;       /* Good default buffer size */
 
-    if (IEEE_float_encoded) {
-        if ((SDL_SwapLE16(format->bitspersample)) != 32) {
-            was_error = 1;
-        } else {
-            spec->format = AUDIO_F32;
-        }
-    } else {
-        switch (SDL_SwapLE16(format->bitspersample)) {
-        case 4:
-            if (MS_ADPCM_encoded || IMA_ADPCM_encoded) {
-                spec->format = AUDIO_S16;
-            } else {
-                was_error = 1;
-            }
-            break;
+    switch (format->encoding) {
+    case MS_ADPCM_CODE:
+    case IMA_ADPCM_CODE:
+    case ALAW_CODE:
+    case MULAW_CODE:
+        /* These can be easily stored in the byte order of the system. */
+        spec->format = AUDIO_S16SYS;
+        break;
+    case IEEE_FLOAT_CODE:
+        spec->format = AUDIO_F32LSB;
+        break;
+    case PCM_CODE:
+        switch (format->bitspersample) {
         case 8:
             spec->format = AUDIO_U8;
             break;
         case 16:
-            spec->format = AUDIO_S16;
-            break;
-        case 24:  /* convert this. */
-            spec->format = AUDIO_S32;
+            spec->format = AUDIO_S16LSB;
             break;
+        case 24: /* Has been shifted to 32 bits. */
         case 32:
-            spec->format = AUDIO_S32;
+            spec->format = AUDIO_S32LSB;
             break;
         default:
-            was_error = 1;
-            break;
+            /* Just in case something unexpected happened in the checks. */
+            return SDL_SetError("Unexpected %u-bit PCM data format", (unsigned int)format->bitspersample);
         }
+        break;
     }
 
-    if (was_error) {
-        SDL_SetError("Unknown %d-bit PCM data format",
-                     SDL_SwapLE16(format->bitspersample));
-        goto done;
+    /* Report the end position back to the cleanup code. */
+    if (RIFFlengthknown) {
+        chunk->position = RIFFend;
+    } else {
+        chunk->position = lastchunkpos;
     }
-    spec->channels = (Uint8) SDL_SwapLE16(format->channels);
-    spec->samples = 4096;       /* Good default buffer size */
 
-    /* Read the audio data chunk */
-    *audio_buf = NULL;
-    do {
-        SDL_free(*audio_buf);
-        *audio_buf = NULL;
-        lenread = ReadChunk(src, &chunk);
-        if (lenread < 0) {
-            was_error = 1;
-            goto done;
-        }
-        *audio_len = lenread;
-        *audio_buf = chunk.data;
-        if (chunk.magic != DATA)
-            headerDiff += lenread + 2 * sizeof(Uint32);
-    } while (chunk.magic != DATA);
-    headerDiff += 2 * sizeof(Uint32);   /* for the data chunk and len */
+    return 0;
+}
 
-    if (MS_ADPCM_encoded) {
-        if (MS_ADPCM_decode(audio_buf, audio_len) < 0) {
-            was_error = 1;
-            goto done;
-        }
-    }
-    if (IMA_ADPCM_encoded) {
-        if (IMA_ADPCM_decode(audio_buf, audio_len) < 0) {
-            was_error = 1;
-            goto done;
-        }
-    }
+SDL_AudioSpec *
+SDL_LoadWAV_RW(SDL_RWops *src, int freesrc, SDL_AudioSpec *spec, Uint8 **audio_buf, Uint32 *audio_len)
+{
+    int result;
+    WaveFile file;
 
-    if (SDL_SwapLE16(format->bitspersample) == 24) {
-        if (ConvertSint24ToSint32(audio_buf, audio_len) < 0) {
-            was_error = 1;
-            goto done;
-        }
+    SDL_zero(file);
+
+    /* Make sure we are passed a valid data source */
+    if (src == NULL) {
+        /* Error may come from RWops. */
+        return NULL;
+    } else if (spec == NULL) {
+        SDL_InvalidParamError("spec");
+        return NULL;
+    } else if (audio_buf == NULL) {
+        SDL_InvalidParamError("audio_buf");
+        return NULL;
+    } else if (audio_len == NULL) {
+        SDL_InvalidParamError("audio_len");
+        return NULL;
     }
 
-    /* Don't return a buffer that isn't a multiple of samplesize */
-    samplesize = ((SDL_AUDIO_BITSIZE(spec->format)) / 8) * spec->channels;
-    *audio_len &= ~(samplesize - 1);
+    *audio_buf = NULL;
+    *audio_len = 0;
 
-  done:
-    SDL_free(format);
-    if (src) {
-        if (freesrc) {
-            SDL_RWclose(src);
-        } else {
-            /* seek to the end of the file (given by the RIFF chunk) */
-            SDL_RWseek(src, wavelen - chunk.length - headerDiff, RW_SEEK_CUR);
-        }
-    }
-    if (was_error) {
+    file.riffhint = WaveGetRiffSizeHint();
+    file.trunchint = WaveGetTruncationHint();
+    file.facthint = WaveGetFactChunkHint();
+
+    result = WaveLoad(src, &file, spec, audio_buf, audio_len);
+    if (result < 0) {
+        SDL_free(*audio_buf);
         spec = NULL;
+        audio_buf = NULL;
+        audio_len = 0;
+    }
+
+    /* Cleanup */
+    if (freesrc) {
+        SDL_RWclose(src);
+    } else {
+        SDL_RWseek(src, file.chunk.position, RW_SEEK_SET);
     }
-    return (spec);
+    WaveFreeChunkData(&file.chunk);
+    SDL_free(file.decoderdata);
+
+    return spec;
 }
 
 /* Since the WAV memory is allocated in the shared library, it must also
    be freed here.  (Necessary under Win32, VC++)
  */
 void
-SDL_FreeWAV(Uint8 * audio_buf)
+SDL_FreeWAV(Uint8 *audio_buf)
 {
     SDL_free(audio_buf);
 }
 
-static int
-ReadChunk(SDL_RWops * src, Chunk * chunk)
-{
-    chunk->magic = SDL_ReadLE32(src);
-    chunk->length = SDL_ReadLE32(src);
-    chunk->data = (Uint8 *) SDL_malloc(chunk->length);
-    if (chunk->data == NULL) {
-        return SDL_OutOfMemory();
-    }
-    if (SDL_RWread(src, chunk->data, chunk->length, 1) != 1) {
-        SDL_free(chunk->data);
-        chunk->data = NULL;
-        return SDL_Error(SDL_EFREAD);
-    }
-    return (chunk->length);
-}
-
 /* vi: set ts=4 sw=4 expandtab: */

+ 103 - 31
sdl.mod/SDL/src/audio/SDL_wave.h

@@ -20,11 +20,12 @@
 */
 #include "../SDL_internal.h"
 
-/* WAVE files are little-endian */
+/* RIFF WAVE files are little-endian */
 
 /*******************************************/
 /* Define values for Microsoft WAVE format */
 /*******************************************/
+/* FOURCC */
 #define RIFF            0x46464952      /* "RIFF" */
 #define WAVE            0x45564157      /* "WAVE" */
 #define FACT            0x74636166      /* "fact" */
@@ -33,45 +34,116 @@
 #define JUNK            0x4B4E554A      /* "JUNK" */
 #define FMT             0x20746D66      /* "fmt " */
 #define DATA            0x61746164      /* "data" */
+/* Format tags */
+#define UNKNOWN_CODE    0x0000
 #define PCM_CODE        0x0001
 #define MS_ADPCM_CODE   0x0002
 #define IEEE_FLOAT_CODE 0x0003
+#define ALAW_CODE       0x0006
+#define MULAW_CODE      0x0007
 #define IMA_ADPCM_CODE  0x0011
-#define MP3_CODE        0x0055
+#define MPEG_CODE       0x0050
+#define MPEGLAYER3_CODE 0x0055
 #define EXTENSIBLE_CODE 0xFFFE
-#define WAVE_MONO       1
-#define WAVE_STEREO     2
 
-/* Normally, these three chunks come consecutively in a WAVE file */
-typedef struct WaveFMT
+/* Stores the WAVE format information. */
+typedef struct WaveFormat
 {
-/* Not saved in the chunk we read:
-    Uint32  FMTchunk;
-    Uint32  fmtlen;
-*/
-    Uint16 encoding;
-    Uint16 channels;            /* 1 = mono, 2 = stereo */
-    Uint32 frequency;           /* One of 11025, 22050, or 44100 Hz */
-    Uint32 byterate;            /* Average bytes per second */
-    Uint16 blockalign;          /* Bytes per sample block */
-    Uint16 bitspersample;       /* One of 8, 12, 16, or 4 for ADPCM */
-} WaveFMT;
-
-/* The general chunk found in the WAVE file */
-typedef struct Chunk
+    Uint16 formattag;       /* Raw value of the first field in the fmt chunk data. */
+    Uint16 encoding;        /* Actual encoding, possibly from the extensible header. */
+    Uint16 channels;        /* Number of channels. */
+    Uint32 frequency;       /* Sampling rate in Hz. */
+    Uint32 byterate;        /* Average bytes per second. */
+    Uint16 blockalign;      /* Bytes per block. */
+    Uint16 bitspersample;   /* Currently supported are 8, 16, 24, 32, and 4 for ADPCM. */
+
+    /* Extra information size. Number of extra bytes starting at byte 18 in the
+     * fmt chunk data. This is at least 22 for the extensible header.
+     */
+    Uint16 extsize;
+
+    /* Extensible WAVE header fields */
+    Uint16 validsamplebits;
+    Uint32 samplesperblock; /* For compressed formats. Can be zero. Actually 16 bits in the header. */
+    Uint32 channelmask;
+    Uint8 subformat[16];    /* A format GUID. */
+} WaveFormat;
+
+/* Stores information on the fact chunk. */
+typedef struct WaveFact {
+    /* Represents the state of the fact chunk in the WAVE file.
+     * Set to -1 if the fact chunk is invalid.
+     * Set to 0 if the fact chunk is not present
+     * Set to 1 if the fact chunk is present and valid.
+     * Set to 2 if samplelength is going to be used as the number of sample frames.
+     */
+    Sint32 status;
+
+    /* Version 1 of the RIFF specification calls the field in the fact chunk
+     * dwFileSize. The Standards Update then calls it dwSampleLength and specifies
+     * that it is 'the length of the data in samples'. WAVE files from Windows
+     * with this chunk have it set to the samples per channel (sample frames).
+     * This is useful to truncate compressed audio to a specific sample count
+     * because a compressed block is usually decoded to a fixed number of
+     * sample frames.
+     */
+    Uint32 samplelength; /* Raw sample length value from the fact chunk. */
+} WaveFact;
+
+/* Generic struct for the chunks in the WAVE file. */
+typedef struct WaveChunk
 {
-    Uint32 magic;
-    Uint32 length;
-    Uint8 *data;
-} Chunk;
+    Uint32 fourcc;   /* FOURCC of the chunk. */
+    Uint32 length;   /* Size of the chunk data. */
+    Sint64 position; /* Position of the data in the stream. */
+    Uint8 *data;     /* When allocated, this points to the chunk data. length is used for the malloc size. */
+    size_t size;     /* Number of bytes in data that could be read from the stream. Can be smaller than length. */
+} WaveChunk;
 
-typedef struct WaveExtensibleFMT
+/* Controls how the size of the RIFF chunk affects the loading of a WAVE file. */
+typedef enum WaveRiffSizeHint {
+    RiffSizeNoHint,
+    RiffSizeForce,
+    RiffSizeIgnoreZero,
+    RiffSizeIgnore,
+    RiffSizeMaximum
+} WaveRiffSizeHint;
+
+/* Controls how a truncated WAVE file is handled. */
+typedef enum WaveTruncationHint {
+    TruncNoHint,
+    TruncVeryStrict,
+    TruncStrict,
+    TruncDropFrame,
+    TruncDropBlock
+} WaveTruncationHint;
+
+/* Controls how the fact chunk affects the loading of a WAVE file. */
+typedef enum WaveFactChunkHint {
+    FactNoHint,
+    FactTruncate,
+    FactStrict,
+    FactIgnoreZero,
+    FactIgnore
+} WaveFactChunkHint;
+
+typedef struct WaveFile
 {
-    WaveFMT format;
-    Uint16 size;
-    Uint16 validbits;
-    Uint32 channelmask;
-    Uint8 subformat[16];  /* a GUID. */
-} WaveExtensibleFMT;
+    WaveChunk chunk;
+    WaveFormat format;
+    WaveFact fact;
+
+    /* Number of sample frames that will be decoded. Calculated either with the
+     * size of the data chunk or, if the appropriate hint is enabled, with the
+     * sample length value from the fact chunk.
+     */
+    Sint64 sampleframes;
+
+    void *decoderdata;   /* Some decoders require extra data for a state. */
+
+    WaveRiffSizeHint riffhint;
+    WaveTruncationHint trunchint;
+    WaveFactChunkHint facthint;
+} WaveFile;
 
 /* vi: set ts=4 sw=4 expandtab: */

+ 21 - 13
sdl.mod/SDL/src/audio/alsa/SDL_alsa_audio.c

@@ -72,7 +72,9 @@ static int (*ALSA_snd_pcm_hw_params_set_period_size_near)
   (snd_pcm_t *, snd_pcm_hw_params_t *, snd_pcm_uframes_t *, int *);
 static int (*ALSA_snd_pcm_hw_params_get_period_size)
   (const snd_pcm_hw_params_t *, snd_pcm_uframes_t *, int *);
-static int (*ALSA_snd_pcm_hw_params_set_periods_near)
+static int (*ALSA_snd_pcm_hw_params_set_periods_min)
+  (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *);
+static int (*ALSA_snd_pcm_hw_params_set_periods_first)
   (snd_pcm_t *, snd_pcm_hw_params_t *, unsigned int *, int *);
 static int (*ALSA_snd_pcm_hw_params_get_periods)
   (const snd_pcm_hw_params_t *, unsigned int *, int *);
@@ -148,7 +150,8 @@ load_alsa_syms(void)
     SDL_ALSA_SYM(snd_pcm_hw_params_set_rate_near);
     SDL_ALSA_SYM(snd_pcm_hw_params_set_period_size_near);
     SDL_ALSA_SYM(snd_pcm_hw_params_get_period_size);
-    SDL_ALSA_SYM(snd_pcm_hw_params_set_periods_near);
+    SDL_ALSA_SYM(snd_pcm_hw_params_set_periods_min);
+    SDL_ALSA_SYM(snd_pcm_hw_params_set_periods_first);
     SDL_ALSA_SYM(snd_pcm_hw_params_get_periods);
     SDL_ALSA_SYM(snd_pcm_hw_params_set_buffer_size_near);
     SDL_ALSA_SYM(snd_pcm_hw_params_get_buffer_size);
@@ -337,7 +340,6 @@ swizzle_alsa_channels(_THIS, void *buffer, Uint32 bufferlen)
 static void
 no_swizzle(_THIS, void *buffer, Uint32 bufferlen)
 {
-    return;
 }
 #endif /* SND_CHMAP_API_VERSION */
 
@@ -346,7 +348,7 @@ static void
 ALSA_PlayDevice(_THIS)
 {
     const Uint8 *sample_buf = (const Uint8 *) this->hidden->mixbuf;
-    const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
+    const int frame_size = ((SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
                                 this->spec.channels;
     snd_pcm_uframes_t frames_left = ((snd_pcm_uframes_t) this->spec.samples);
 
@@ -395,7 +397,7 @@ static int
 ALSA_CaptureFromDevice(_THIS, void *buffer, int buflen)
 {
     Uint8 *sample_buf = (Uint8 *) buffer;
-    const int frame_size = (((int) SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
+    const int frame_size = ((SDL_AUDIO_BITSIZE(this->spec.format)) / 8) *
                                 this->spec.channels;
     const int total_frames = buflen / frame_size;
     snd_pcm_uframes_t frames_left = total_frames;
@@ -462,14 +464,14 @@ ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params)
 {
     int status;
     snd_pcm_hw_params_t *hwparams;
-    snd_pcm_uframes_t bufsize;
     snd_pcm_uframes_t persize;
+    unsigned int periods;
 
     /* Copy the hardware parameters for this setup */
     snd_pcm_hw_params_alloca(&hwparams);
     ALSA_snd_pcm_hw_params_copy(hwparams, params);
 
-    /* Prioritize matching the period size to the requested buffer size */
+    /* Attempt to match the period size to the requested buffer size */
     persize = this->spec.samples;
     status = ALSA_snd_pcm_hw_params_set_period_size_near(
                 this->hidden->pcm_handle, hwparams, &persize, NULL);
@@ -477,10 +479,16 @@ ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params)
         return(-1);
     }
 
-    /* Next try to restrict the parameters to having only two periods */
-    bufsize = this->spec.samples * 2;
-    status = ALSA_snd_pcm_hw_params_set_buffer_size_near(
-                    this->hidden->pcm_handle, hwparams, &bufsize);
+    /* Need to at least double buffer */
+    periods = 2;
+    status = ALSA_snd_pcm_hw_params_set_periods_min(
+                this->hidden->pcm_handle, hwparams, &periods, NULL);
+    if ( status < 0 ) {
+        return(-1);
+    }
+
+    status = ALSA_snd_pcm_hw_params_set_periods_first(
+                this->hidden->pcm_handle, hwparams, &periods, NULL);
     if ( status < 0 ) {
         return(-1);
     }
@@ -495,9 +503,9 @@ ALSA_set_buffer_size(_THIS, snd_pcm_hw_params_t *params)
 
     /* This is useful for debugging */
     if ( SDL_getenv("SDL_AUDIO_ALSA_DEBUG") ) {
-        unsigned int periods = 0;
+        snd_pcm_uframes_t bufsize;
 
-        ALSA_snd_pcm_hw_params_get_periods(hwparams, &periods, NULL);
+        ALSA_snd_pcm_hw_params_get_buffer_size(hwparams, &bufsize);
 
         fprintf(stderr,
             "ALSA: period size = %ld, periods = %u, buffer size = %lu\n",

+ 34 - 4
sdl.mod/SDL/src/audio/coreaudio/SDL_coreaudio.m

@@ -376,7 +376,7 @@ static BOOL update_audio_session(_THIS, SDL_bool open)
             /* An interruption end notification is not guaranteed to be sent if
              we were previously interrupted... resuming if needed when the app
              becomes active seems to be the way to go. */
-			// Note: object: below needs to be nil, as otherwise it filters by the object, and session doesn't send foreground / active notifications.  johna
+            // Note: object: below needs to be nil, as otherwise it filters by the object, and session doesn't send foreground / active notifications.  johna
             [center addObserver:listener
                        selector:@selector(applicationBecameActive:)
                            name:UIApplicationDidBecomeActiveNotification
@@ -417,6 +417,34 @@ outputCallback(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffe
     if (!SDL_AtomicGet(&this->enabled) || SDL_AtomicGet(&this->paused)) {
         /* Supply silence if audio is not enabled or paused */
         SDL_memset(inBuffer->mAudioData, this->spec.silence, inBuffer->mAudioDataBytesCapacity);
+    } else if (this->stream ) {
+        UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
+        Uint8 *ptr = (Uint8 *) inBuffer->mAudioData;
+
+        while (remaining > 0) {
+            if ( SDL_AudioStreamAvailable(this->stream) == 0 ) {
+                /* Generate the data */
+                SDL_LockMutex(this->mixer_lock);
+                (*this->callbackspec.callback)(this->callbackspec.userdata,
+                                               this->hidden->buffer, this->hidden->bufferSize);
+                SDL_UnlockMutex(this->mixer_lock);
+                this->hidden->bufferOffset = 0;
+                SDL_AudioStreamPut(this->stream, this->hidden->buffer, this->hidden->bufferSize);
+            }
+            if ( SDL_AudioStreamAvailable(this->stream) > 0 ) {
+                int got;
+                UInt32 len = SDL_AudioStreamAvailable(this->stream);
+                if ( len > remaining )
+                    len = remaining;
+                got = SDL_AudioStreamGet(this->stream, ptr, len);
+                SDL_assert((got < 0) || (got == len));
+                if (got != len) {
+                    SDL_memset(ptr, this->spec.silence, len);
+                }
+                ptr = ptr + len;
+                remaining -= len;
+            }
+        }
     } else {
         UInt32 remaining = inBuffer->mAudioDataBytesCapacity;
         Uint8 *ptr = (Uint8 *) inBuffer->mAudioData;
@@ -791,13 +819,11 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
 
     while ((!valid_datatype) && (test_format)) {
         this->spec.format = test_format;
-        /* Just a list of valid SDL formats, so people don't pass junk here. */
+        /* CoreAudio handles most of SDL's formats natively, but not U16, apparently. */
         switch (test_format) {
         case AUDIO_U8:
         case AUDIO_S8:
-        case AUDIO_U16LSB:
         case AUDIO_S16LSB:
-        case AUDIO_U16MSB:
         case AUDIO_S16MSB:
         case AUDIO_S32LSB:
         case AUDIO_S32MSB:
@@ -813,6 +839,10 @@ COREAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
             else if (SDL_AUDIO_ISSIGNED(this->spec.format))
                 strdesc->mFormatFlags |= kLinearPCMFormatFlagIsSignedInteger;
             break;
+
+        default:
+            test_format = SDL_NextAudioFormat();
+            break;
         }
     }
 

+ 47 - 126
sdl.mod/SDL/src/audio/netbsd/SDL_netbsdaudio.c

@@ -43,12 +43,7 @@
 #include "../SDL_audiodev_c.h"
 #include "SDL_netbsdaudio.h"
 
-/* Use timer for synchronization */
-/* #define USE_TIMER_SYNC */
-
 /* #define DEBUG_AUDIO */
-/* #define DEBUG_AUDIO_STREAM */
-
 
 static void
 NETBSDAUDIO_DetectDevices(void)
@@ -63,14 +58,14 @@ NETBSDAUDIO_Status(_THIS)
 #ifdef DEBUG_AUDIO
     /* *INDENT-OFF* */
     audio_info_t info;
-    const audio_prinfo *prinfo;
+    const struct audio_prinfo *prinfo;
 
     if (ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info) < 0) {
         fprintf(stderr, "AUDIO_GETINFO failed.\n");
         return;
     }
 
-    prinfo = this->iscapture ? &info.play : &info.record;
+    prinfo = this->iscapture ? &info.record : &info.play;
 
     fprintf(stderr, "\n"
             "[%s info]\n"
@@ -115,90 +110,37 @@ NETBSDAUDIO_Status(_THIS)
             (info.mode == AUMODE_PLAY) ? "PLAY"
             : (info.mode = AUMODE_RECORD) ? "RECORD"
             : (info.mode == AUMODE_PLAY_ALL ? "PLAY_ALL" : "?"));
+
+    fprintf(stderr, "\n"
+            "[audio spec]\n"
+            "format		:   0x%x\n"
+            "size		:   %u\n"
+            "",
+            this->spec.format,
+            this->spec.size);
     /* *INDENT-ON* */
 #endif /* DEBUG_AUDIO */
 }
 
 
-/* This function waits until it is possible to write a full sound buffer */
-static void
-NETBSDAUDIO_WaitDevice(_THIS)
-{
-#ifndef USE_BLOCKING_WRITES     /* Not necessary when using blocking writes */
-    /* See if we need to use timed audio synchronization */
-    if (this->hidden->frame_ticks) {
-        /* Use timer for general audio synchronization */
-        Sint32 ticks;
-
-        ticks = ((Sint32) (this->hidden->next_frame - SDL_GetTicks())) - FUDGE_TICKS;
-        if (ticks > 0) {
-            SDL_Delay(ticks);
-        }
-    } else {
-        /* Use SDL_IOReady() for audio synchronization */
-#ifdef DEBUG_AUDIO
-        fprintf(stderr, "Waiting for audio to get ready\n");
-#endif
-        if (SDL_IOReady(this->hidden->audio_fd, SDL_TRUE, 10 * 1000)
-            <= 0) {
-            const char *message =
-                "Audio timeout - buggy audio driver? (disabled)";
-            /* In general we should never print to the screen,
-               but in this case we have no other way of letting
-               the user know what happened.
-             */
-            fprintf(stderr, "SDL: %s\n", message);
-            SDL_OpenedAudioDeviceDisconnected(this);
-            /* Don't try to close - may hang */
-            this->hidden->audio_fd = -1;
-#ifdef DEBUG_AUDIO
-            fprintf(stderr, "Done disabling audio\n");
-#endif
-        }
-#ifdef DEBUG_AUDIO
-        fprintf(stderr, "Ready!\n");
-#endif
-    }
-#endif /* !USE_BLOCKING_WRITES */
-}
-
 static void
 NETBSDAUDIO_PlayDevice(_THIS)
 {
-    int written, p = 0;
-
-    /* Write the audio data, checking for EAGAIN on broken audio drivers */
-    do {
-        written = write(this->hidden->audio_fd,
-                        &this->hidden->mixbuf[p], this->hidden->mixlen - p);
-
-        if (written > 0)
-            p += written;
-        if (written == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) {
-            /* Non recoverable error has occurred. It should be reported!!! */
-            perror("audio");
-            break;
-        }
-
-#ifdef DEBUG_AUDIO
-        fprintf(stderr, "Wrote %d bytes of audio data\n", written);
-#endif
-
-        if (p < this->hidden->mixlen
-            || ((written < 0) && ((errno == 0) || (errno == EAGAIN)))) {
-            SDL_Delay(1);       /* Let a little CPU time go by */
-        }
-    } while (p < this->hidden->mixlen);
-
-    /* If timer synchronization is enabled, set the next write frame */
-    if (this->hidden->frame_ticks) {
-        this->hidden->next_frame += this->hidden->frame_ticks;
-    }
+    struct SDL_PrivateAudioData *h = this->hidden;
+    int written;
 
-    /* If we couldn't write, assume fatal error for now */
-    if (written < 0) {
+    /* Write the audio data */
+    written = write(h->audio_fd, h->mixbuf, h->mixlen);
+    if (written == -1) {
+        /* Non recoverable error has occurred. It should be reported!!! */
         SDL_OpenedAudioDeviceDisconnected(this);
+        perror("audio");
+        return;
     }
+
+#ifdef DEBUG_AUDIO
+    fprintf(stderr, "Wrote %d bytes of audio data\n", written);
+#endif
 }
 
 static Uint8 *
@@ -212,28 +154,19 @@ static int
 NETBSDAUDIO_CaptureFromDevice(_THIS, void *_buffer, int buflen)
 {
     Uint8 *buffer = (Uint8 *) _buffer;
-    int br, p = 0;
-
-    /* Capture the audio data, checking for EAGAIN on broken audio drivers */
-    do {
-        br = read(this->hidden->audio_fd, buffer + p, buflen - p);
-        if (br > 0)
-            p += br;
-        if (br == -1 && errno != 0 && errno != EAGAIN && errno != EINTR) {
-            /* Non recoverable error has occurred. It should be reported!!! */
-            perror("audio");
-            return p ? p : -1;
-        }
+    int br;
+
+    br = read(this->hidden->audio_fd, buffer, buflen);
+    if (br == -1) {
+        /* Non recoverable error has occurred. It should be reported!!! */
+        perror("audio");
+        return -1;
+    }
 
 #ifdef DEBUG_AUDIO
-        fprintf(stderr, "Captured %d bytes of audio data\n", br);
+    fprintf(stderr, "Captured %d bytes of audio data\n", br);
 #endif
-
-        if (p < buflen
-            || ((br < 0) && ((errno == 0) || (errno == EAGAIN)))) {
-            SDL_Delay(1);       /* Let a little CPU time go by */
-        }
-    } while (p < buflen);
+    return 0;
 }
 
 static void
@@ -271,10 +204,9 @@ NETBSDAUDIO_CloseDevice(_THIS)
 static int
 NETBSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
 {
-    const int flags = iscapture ? OPEN_FLAGS_INPUT : OPEN_FLAGS_OUTPUT;
     SDL_AudioFormat format = 0;
     audio_info_t info;
-    audio_prinfo *prinfo = iscapture ? &info.play : &info.record;
+    struct audio_prinfo *prinfo = iscapture ? &info.record : &info.play;
 
     /* We don't care what the devname is...we'll try to open anything. */
     /*  ...but default to first name in the list... */
@@ -294,25 +226,16 @@ NETBSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
     SDL_zerop(this->hidden);
 
     /* Open the audio device */
-    this->hidden->audio_fd = open(devname, flags, 0);
+    this->hidden->audio_fd = open(devname, iscapture ? O_RDONLY : O_WRONLY);
     if (this->hidden->audio_fd < 0) {
         return SDL_SetError("Couldn't open %s: %s", devname, strerror(errno));
     }
 
     AUDIO_INITINFO(&info);
 
-    /* Calculate the final parameters for this audio specification */
-    SDL_CalculateAudioSpec(&this->spec);
-
-    /* Set to play mode */
-    info.mode = iscapture ? AUMODE_RECORD : AUMODE_PLAY;
-    if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) < 0) {
-        return SDL_SetError("Couldn't put device into play mode");
-    }
+    prinfo->encoding = AUDIO_ENCODING_NONE;
 
-    AUDIO_INITINFO(&info);
-    for (format = SDL_FirstAudioFormat(this->spec.format);
-         format; format = SDL_NextAudioFormat()) {
+    for (format = SDL_FirstAudioFormat(this->spec.format); format;) {
         switch (format) {
         case AUDIO_U8:
             prinfo->encoding = AUDIO_ENCODING_ULINEAR;
@@ -338,34 +261,33 @@ NETBSDAUDIO_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
             prinfo->encoding = AUDIO_ENCODING_ULINEAR_BE;
             prinfo->precision = 16;
             break;
-        default:
-            continue;
         }
-
-        if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == 0) {
+        if (prinfo->encoding != AUDIO_ENCODING_NONE) {
             break;
         }
+        format = SDL_NextAudioFormat();
     }
 
-    if (!format) {
+    if (prinfo->encoding == AUDIO_ENCODING_NONE) {
         return SDL_SetError("No supported encoding for 0x%x", this->spec.format);
     }
 
     this->spec.format = format;
 
-    AUDIO_INITINFO(&info);
-    prinfo->channels = this->spec.channels;
-    if (ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info) == -1) {
-        this->spec.channels = 1;
-    }
-    AUDIO_INITINFO(&info);
-    prinfo->sample_rate = this->spec.freq;
+    /* Calculate spec parameters based on our chosen format */
+    SDL_CalculateAudioSpec(&this->spec);
+
+    info.mode = iscapture ? AUMODE_RECORD : AUMODE_PLAY;
     info.blocksize = this->spec.size;
     info.hiwat = 5;
     info.lowat = 3;
+    prinfo->sample_rate = this->spec.freq;
+    prinfo->channels = this->spec.channels;
     (void) ioctl(this->hidden->audio_fd, AUDIO_SETINFO, &info);
+
     (void) ioctl(this->hidden->audio_fd, AUDIO_GETINFO, &info);
     this->spec.freq = prinfo->sample_rate;
+    this->spec.channels = prinfo->channels;
 
     if (!iscapture) {
         /* Allocate mixing buffer */
@@ -390,7 +312,6 @@ NETBSDAUDIO_Init(SDL_AudioDriverImpl * impl)
     impl->DetectDevices = NETBSDAUDIO_DetectDevices;
     impl->OpenDevice = NETBSDAUDIO_OpenDevice;
     impl->PlayDevice = NETBSDAUDIO_PlayDevice;
-    impl->WaitDevice = NETBSDAUDIO_WaitDevice;
     impl->GetDeviceBuf = NETBSDAUDIO_GetDeviceBuf;
     impl->CloseDevice = NETBSDAUDIO_CloseDevice;
     impl->CaptureFromDevice = NETBSDAUDIO_CaptureFromDevice;

+ 40 - 14
sdl.mod/SDL/src/audio/openslES/SDL_openslES.c

@@ -22,6 +22,10 @@
 
 #if SDL_AUDIO_DRIVER_OPENSLES
 
+/* For more discussion of low latency audio on Android, see this:
+   https://googlesamples.github.io/android-audio-high-performance/guides/opensl_es.html
+*/
+
 #include "SDL_audio.h"
 #include "../SDL_audio_c.h"
 #include "SDL_openslES.h"
@@ -32,9 +36,8 @@
 
 #include <android/log.h>
 
-#define LOG_TAG "SDL_openslES"
-
 #if 0
+#define LOG_TAG "SDL_openslES"
 #define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
 #define LOGI(...)  __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
 //#define LOGV(...)  __android_log_print(ANDROID_LOG_VERBOSE,LOG_TAG,__VA_ARGS__)
@@ -99,7 +102,7 @@ static void openslES_DetectDevices( int iscapture )
 }
 #endif
 
-static void openslES_DestroyEngine();
+static void openslES_DestroyEngine(void);
 
 static int
 openslES_CreateEngine()
@@ -290,19 +293,42 @@ openslES_CreatePCMPlayer(_THIS)
 #define SL_SPEAKER_TOP_BACK_CENTER       ((SLuint32) 0x00010000)
 #define SL_SPEAKER_TOP_BACK_RIGHT        ((SLuint32) 0x00020000)
 */
+#define SL_ANDROID_SPEAKER_STEREO (SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT)
+#define SL_ANDROID_SPEAKER_QUAD (SL_ANDROID_SPEAKER_STEREO | SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT)
+#define SL_ANDROID_SPEAKER_5DOT1 (SL_ANDROID_SPEAKER_QUAD | SL_SPEAKER_FRONT_CENTER  | SL_SPEAKER_LOW_FREQUENCY)
+#define SL_ANDROID_SPEAKER_7DOT1 (SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_SIDE_LEFT | SL_SPEAKER_SIDE_RIGHT)
 
-    if (this->spec.channels == 1) {
-        format_pcm.channelMask = SL_SPEAKER_FRONT_CENTER;
-    } else if (this->spec.channels == 2) {
+    switch (this->spec.channels)
+    {
+    case 1:
+        format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT;
+        break;
+    case 2:
+        format_pcm.channelMask = SL_ANDROID_SPEAKER_STEREO;
+        break;
+    case 3:
+        format_pcm.channelMask = SL_ANDROID_SPEAKER_STEREO | SL_SPEAKER_FRONT_CENTER;
+        break;
+    case 4:
+        format_pcm.channelMask = SL_ANDROID_SPEAKER_QUAD;
+        break;
+    case 5:
+        format_pcm.channelMask = SL_ANDROID_SPEAKER_QUAD | SL_SPEAKER_FRONT_CENTER;
+        break;
+    case 6:
+        format_pcm.channelMask = SL_ANDROID_SPEAKER_5DOT1;
+        break;
+    case 7:
+        format_pcm.channelMask = SL_ANDROID_SPEAKER_5DOT1 | SL_SPEAKER_BACK_CENTER;
+        break;
+    case 8:
+        format_pcm.channelMask = SL_ANDROID_SPEAKER_7DOT1;
+        break;
+    default:
+        /* Unknown number of channels, fall back to stereo */
+        this->spec.channels = 2;
         format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT;
-    } else if (this->spec.channels == 3) {
-        format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT | SL_SPEAKER_FRONT_CENTER;
-    } else if (this->spec.channels == 4) {
-        format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
-              SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT;
-    } else {
-        format_pcm.channelMask = SL_SPEAKER_FRONT_LEFT | SL_SPEAKER_FRONT_RIGHT |
-              SL_SPEAKER_BACK_LEFT | SL_SPEAKER_BACK_RIGHT | SL_SPEAKER_FRONT_CENTER;
+        break;
     }
 
     SLDataSource audioSrc = { &loc_bufq, &format_pcm };

+ 4 - 4
sdl.mod/SDL/src/audio/qsa/SDL_qsa_audio.c

@@ -619,8 +619,8 @@ QSA_Deinitialize(void)
 {
     /* Clear devices array on shutdown */
     /* !!! FIXME: we zero these on init...any reason to do it here? */
-    SDL_zero(qsa_playback_device);
-    SDL_zero(qsa_capture_device);
+    SDL_zeroa(qsa_playback_device);
+    SDL_zeroa(qsa_capture_device);
     qsa_playback_devices = 0;
     qsa_capture_devices = 0;
 }
@@ -629,8 +629,8 @@ static int
 QSA_Init(SDL_AudioDriverImpl * impl)
 {
     /* Clear devices array */
-    SDL_zero(qsa_playback_device);
-    SDL_zero(qsa_capture_device);
+    SDL_zeroa(qsa_playback_device);
+    SDL_zeroa(qsa_capture_device);
     qsa_playback_devices = 0;
     qsa_capture_devices = 0;
 

+ 3 - 19
sdl.mod/SDL/src/audio/wasapi/SDL_wasapi.c

@@ -161,21 +161,6 @@ WASAPI_DetectDevices(void)
     WASAPI_EnumerateEndpoints();
 }
 
-static int
-WASAPI_GetPendingBytes(_THIS)
-{
-    UINT32 frames = 0;
-
-    /* it's okay to fail here; we'll deal with failures in the audio thread. */
-    /* FIXME: need a lock around checking this->hidden->client */
-    if (this->hidden->client != NULL) {  /* definitely activated? */
-        if (FAILED(IAudioClient_GetCurrentPadding(this->hidden->client, &frames))) {
-            return 0;  /* oh well. */
-        }
-    }
-    return ((int) frames) * this->hidden->framesize;
-}
-
 static SDL_INLINE SDL_bool
 WasapiFailed(_THIS, const HRESULT err)
 {
@@ -327,8 +312,8 @@ static void
 WASAPI_WaitDevice(_THIS)
 {
     while (RecoverWasapiIfLost(this) && this->hidden->client && this->hidden->event) {
-        /*SDL_Log("WAITDEVICE");*/
-        if (WaitForSingleObjectEx(this->hidden->event, INFINITE, FALSE) == WAIT_OBJECT_0) {
+        DWORD waitResult = WaitForSingleObjectEx(this->hidden->event, 200, FALSE);
+        if (waitResult == WAIT_OBJECT_0) {
             const UINT32 maxpadding = this->spec.samples;
             UINT32 padding = 0;
             if (!WasapiFailed(this, IAudioClient_GetCurrentPadding(this->hidden->client, &padding))) {
@@ -337,7 +322,7 @@ WASAPI_WaitDevice(_THIS)
                     break;
                 }
             }
-        } else {
+        } else if (waitResult != WAIT_TIMEOUT) {
             /*SDL_Log("WASAPI FAILED EVENT!");*/
             IAudioClient_Stop(this->hidden->client);
             SDL_OpenedAudioDeviceDisconnected(this);
@@ -765,7 +750,6 @@ WASAPI_Init(SDL_AudioDriverImpl * impl)
     impl->OpenDevice = WASAPI_OpenDevice;
     impl->PlayDevice = WASAPI_PlayDevice;
     impl->WaitDevice = WASAPI_WaitDevice;
-    impl->GetPendingBytes = WASAPI_GetPendingBytes;
     impl->GetDeviceBuf = WASAPI_GetDeviceBuf;
     impl->CaptureFromDevice = WASAPI_CaptureFromDevice;
     impl->FlushCapture = WASAPI_FlushCapture;

+ 1 - 1
sdl.mod/SDL/src/audio/winmm/SDL_winmm.c

@@ -387,7 +387,7 @@ WINMM_OpenDevice(_THIS, void *handle, const char *devname, int iscapture)
         return SDL_OutOfMemory();
     }
 
-    SDL_zero(this->hidden->wavebuf);
+    SDL_zeroa(this->hidden->wavebuf);
     for (i = 0; i < NUM_BUFFERS; ++i) {
         this->hidden->wavebuf[i].dwBufferLength = this->spec.size;
         this->hidden->wavebuf[i].dwFlags = WHDR_DONE;

+ 78 - 20
sdl.mod/SDL/src/core/android/SDL_android.c

@@ -24,6 +24,7 @@
 #include "SDL_hints.h"
 #include "SDL_log.h"
 #include "SDL_main.h"
+#include "SDL_timer.h"
 
 #ifdef __ANDROID__
 
@@ -240,6 +241,8 @@ static jmethodID midSetSurfaceViewFormat;
 static jmethodID midSetActivityTitle;
 static jmethodID midSetWindowStyle;
 static jmethodID midSetOrientation;
+static jmethodID midMinimizeWindow;
+static jmethodID midShouldMinimizeOnFocusLoss;
 static jmethodID midGetContext;
 static jmethodID midIsTablet;
 static jmethodID midIsAndroidTV;
@@ -490,6 +493,10 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
                                 "setWindowStyle","(Z)V");
     midSetOrientation = (*env)->GetStaticMethodID(env, mActivityClass,
                                 "setOrientation","(IIZLjava/lang/String;)V");
+    midMinimizeWindow = (*env)->GetStaticMethodID(env, mActivityClass,
+                                "minimizeWindow","()V");
+    midShouldMinimizeOnFocusLoss = (*env)->GetStaticMethodID(env, mActivityClass,
+                                "shouldMinimizeOnFocusLoss","()Z");
     midGetContext = (*env)->GetStaticMethodID(env, mActivityClass,
                                 "getContext","()Landroid/content/Context;");
     midIsTablet = (*env)->GetStaticMethodID(env, mActivityClass,
@@ -532,7 +539,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv *env, jclass cl
 
 
     if (!midGetNativeSurface || !midSetSurfaceViewFormat ||
-       !midSetActivityTitle || !midSetWindowStyle || !midSetOrientation || !midGetContext || !midIsTablet || !midIsAndroidTV || !midInitTouch ||
+       !midSetActivityTitle || !midSetWindowStyle || !midSetOrientation || !midMinimizeWindow || !midShouldMinimizeOnFocusLoss || !midGetContext || !midIsTablet || !midIsAndroidTV || !midInitTouch ||
        !midSendMessage || !midShowTextInput || !midIsScreenKeyboardShown ||
        !midClipboardSetText || !midClipboardGetText || !midClipboardHasText ||
        !midOpenAPKExpansionInputStream || !midGetManifestEnvironmentVariables || !midGetDisplayDPI ||
@@ -622,6 +629,17 @@ JNIEXPORT int JNICALL SDL_JAVA_INTERFACE(nativeRunMain)(JNIEnv *env, jclass cls,
 
     library_file = (*env)->GetStringUTFChars(env, library, NULL);
     library_handle = dlopen(library_file, RTLD_GLOBAL);
+
+    if (!library_handle) {
+        /* When deploying android app bundle format uncompressed native libs may not extract from apk to filesystem.
+           In this case we should use lib name without path. https://bugzilla.libsdl.org/show_bug.cgi?id=4739 */
+        const char *library_name = SDL_strrchr(library_file, '/');
+        if (library_name && *library_name) {
+            library_name += 1;
+            library_handle = dlopen(library_name, RTLD_GLOBAL);
+        }
+    }
+
     if (library_handle) {
         const char *function_name;
         SDL_main_func SDL_main;
@@ -705,6 +723,34 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeDropFile)(
     SDL_SendDropComplete(NULL);
 }
 
+/* Lock / Unlock Mutex */
+void Android_ActivityMutex_Lock() {
+    SDL_LockMutex(Android_ActivityMutex);
+}
+
+void Android_ActivityMutex_Unlock() {
+    SDL_UnlockMutex(Android_ActivityMutex);
+}
+
+/* Lock the Mutex when the Activity is in its 'Running' state */
+void Android_ActivityMutex_Lock_Running() {
+    int pauseSignaled = 0;
+    int resumeSignaled = 0;
+
+retry:
+
+    SDL_LockMutex(Android_ActivityMutex);
+
+    pauseSignaled = SDL_SemValue(Android_PauseSem);
+    resumeSignaled = SDL_SemValue(Android_ResumeSem);
+
+    if (pauseSignaled > resumeSignaled) {
+        SDL_UnlockMutex(Android_ActivityMutex);
+        SDL_Delay(50);
+        goto retry;
+    }
+}
+
 /* Set screen resolution */
 JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetScreenResolution)(
                                     JNIEnv *env, jclass jcls,
@@ -1226,11 +1272,6 @@ static void LocalReferenceHolder_Cleanup(struct LocalReferenceHolder *refholder)
     }
 }
 
-static SDL_bool LocalReferenceHolder_IsActive(void)
-{
-    return (SDL_AtomicGet(&s_active) > 0);
-}
-
 ANativeWindow* Android_JNI_GetNativeWindow(void)
 {
     ANativeWindow *anw = NULL;
@@ -1270,7 +1311,7 @@ void Android_JNI_SetActivityTitle(const char *title)
 {
     JNIEnv *env = Android_JNI_GetEnv();
 
-    jstring jtitle = (jstring)((*env)->NewStringUTF(env, title));
+    jstring jtitle = (*env)->NewStringUTF(env, title);
     (*env)->CallStaticBooleanMethod(env, mActivityClass, midSetActivityTitle, jtitle);
     (*env)->DeleteLocalRef(env, jtitle);
 }
@@ -1285,11 +1326,23 @@ void Android_JNI_SetOrientation(int w, int h, int resizable, const char *hint)
 {
     JNIEnv *env = Android_JNI_GetEnv();
 
-    jstring jhint = (jstring)((*env)->NewStringUTF(env, (hint ? hint : "")));
+    jstring jhint = (*env)->NewStringUTF(env, (hint ? hint : ""));
     (*env)->CallStaticVoidMethod(env, mActivityClass, midSetOrientation, w, h, (resizable? 1 : 0), jhint);
     (*env)->DeleteLocalRef(env, jhint);
 }
 
+void Android_JNI_MinizeWindow()
+{
+    JNIEnv *env = Android_JNI_GetEnv();
+    (*env)->CallStaticVoidMethod(env, mActivityClass, midMinimizeWindow);
+}
+
+SDL_bool Android_JNI_ShouldMinimizeOnFocusLoss()
+{
+    JNIEnv *env = Android_JNI_GetEnv();
+    return (*env)->CallStaticBooleanMethod(env, mActivityClass, midShouldMinimizeOnFocusLoss);
+}
+
 SDL_bool Android_JNI_GetAccelerometerValues(float values[3])
 {
     int i;
@@ -1318,7 +1371,6 @@ static jobject captureBuffer = NULL;
 int Android_JNI_OpenAudioDevice(int iscapture, SDL_AudioSpec *spec)
 {
     int audioformat;
-    int numBufferFrames;
     jobject jbufobj = NULL;
     jobject result;
     int *resultElements;
@@ -1423,7 +1475,6 @@ int Android_JNI_OpenAudioDevice(int iscapture, SDL_AudioSpec *spec)
         audioBufferFormat = audioformat;
         audioBuffer = jbufobj;
     }
-    numBufferFrames = (*env)->GetArrayLength(env, (jarray)jbufobj);
 
     if (!iscapture) {
         isCopy = JNI_FALSE;
@@ -1525,7 +1576,7 @@ int Android_JNI_CaptureAudioBuffer(void *buffer, int buflen)
         if (br > 0) {
             jbyte *ptr = (*env)->GetByteArrayElements(env, (jbyteArray)captureBuffer, &isCopy);
             SDL_memcpy(buffer, ptr, br);
-            (*env)->ReleaseByteArrayElements(env, (jbyteArray)captureBuffer, (jbyte *)ptr, JNI_ABORT);
+            (*env)->ReleaseByteArrayElements(env, (jbyteArray)captureBuffer, ptr, JNI_ABORT);
         }
         break;
     case ENCODING_PCM_16BIT:
@@ -1535,7 +1586,7 @@ int Android_JNI_CaptureAudioBuffer(void *buffer, int buflen)
             jshort *ptr = (*env)->GetShortArrayElements(env, (jshortArray)captureBuffer, &isCopy);
             br *= sizeof(Sint16);
             SDL_memcpy(buffer, ptr, br);
-            (*env)->ReleaseShortArrayElements(env, (jshortArray)captureBuffer, (jshort *)ptr, JNI_ABORT);
+            (*env)->ReleaseShortArrayElements(env, (jshortArray)captureBuffer, ptr, JNI_ABORT);
         }
         break;
     case ENCODING_PCM_FLOAT:
@@ -1545,7 +1596,7 @@ int Android_JNI_CaptureAudioBuffer(void *buffer, int buflen)
             jfloat *ptr = (*env)->GetFloatArrayElements(env, (jfloatArray)captureBuffer, &isCopy);
             br *= sizeof(float);
             SDL_memcpy(buffer, ptr, br);
-            (*env)->ReleaseFloatArrayElements(env, (jfloatArray)captureBuffer, (jfloat *)ptr, JNI_ABORT);
+            (*env)->ReleaseFloatArrayElements(env, (jfloatArray)captureBuffer, ptr, JNI_ABORT);
         }
         break;
     default:
@@ -1634,7 +1685,7 @@ static SDL_bool Android_JNI_ExceptionOccurred(SDL_bool silent)
     jthrowable exception;
 
     /* Detect mismatch LocalReferenceHolder_Init/Cleanup */
-    SDL_assert(LocalReferenceHolder_IsActive());
+    SDL_assert(SDL_AtomicGet(&s_active) > 0);
 
     exception = (*env)->ExceptionOccurred(env);
     if (exception != NULL) {
@@ -1999,7 +2050,6 @@ Sint64 Android_JNI_FileSeek(SDL_RWops *ctx, Sint64 offset, int whence)
             default:
                 return SDL_SetError("Unknown value for 'whence'");
         }
-        whence = SEEK_SET;
 
         ret = lseek(ctx->hidden.androidio.fd, (off_t)offset, SEEK_SET);
         if (ret == -1) return -1;
@@ -2327,11 +2377,19 @@ int Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *bu
     button_texts = (*env)->NewObjectArray(env, messageboxdata->numbuttons,
         clazz, NULL);
     for (i = 0; i < messageboxdata->numbuttons; ++i) {
-        temp = messageboxdata->buttons[i].flags;
+        const SDL_MessageBoxButtonData *sdlButton;
+
+        if (messageboxdata->flags & SDL_MESSAGEBOX_BUTTONS_RIGHT_TO_LEFT) {
+            sdlButton = &messageboxdata->buttons[messageboxdata->numbuttons - 1 - i];
+        } else {
+            sdlButton = &messageboxdata->buttons[i];
+        }
+
+        temp = sdlButton->flags;
         (*env)->SetIntArrayRegion(env, button_flags, i, 1, &temp);
-        temp = messageboxdata->buttons[i].buttonid;
+        temp = sdlButton->buttonid;
         (*env)->SetIntArrayRegion(env, button_ids, i, 1, &temp);
-        text = (*env)->NewStringUTF(env, messageboxdata->buttons[i].text);
+        text = (*env)->NewStringUTF(env, sdlButton->text);
         (*env)->SetObjectArrayElement(env, button_texts, i, text);
         (*env)->DeleteLocalRef(env, text);
     }
@@ -2339,7 +2397,7 @@ int Android_JNI_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *bu
     if (messageboxdata->colorScheme) {
         colors = (*env)->NewIntArray(env, SDL_MESSAGEBOX_COLOR_MAX);
         for (i = 0; i < SDL_MESSAGEBOX_COLOR_MAX; ++i) {
-            temp = (0xFF << 24) |
+            temp = (0xFFU << 24) |
                    (messageboxdata->colorScheme->colors[i].r << 16) |
                    (messageboxdata->colorScheme->colors[i].g << 8) |
                    (messageboxdata->colorScheme->colors[i].b << 0);
@@ -2446,7 +2504,7 @@ SDL_bool SDL_IsDeXMode(void)
 void SDL_AndroidBackButton(void)
 {
     JNIEnv *env = Android_JNI_GetEnv();
-    return (*env)->CallStaticVoidMethod(env, mActivityClass, midManualBackButton);
+    (*env)->CallStaticVoidMethod(env, mActivityClass, midManualBackButton);
 }
 
 const char * SDL_AndroidGetInternalStoragePath(void)

+ 6 - 0
sdl.mod/SDL/src/core/android/SDL_android.h

@@ -39,6 +39,8 @@ extern "C" {
 extern void Android_JNI_SetActivityTitle(const char *title);
 extern void Android_JNI_SetWindowStyle(SDL_bool fullscreen);
 extern void Android_JNI_SetOrientation(int w, int h, int resizable, const char *hint);
+extern void Android_JNI_MinizeWindow(void);
+extern SDL_bool Android_JNI_ShouldMinimizeOnFocusLoss(void);
 
 extern SDL_bool Android_JNI_GetAccelerometerValues(float values[3]);
 extern void Android_JNI_ShowTextInput(SDL_Rect *inputRect);
@@ -129,6 +131,10 @@ SDL_bool SDL_IsAndroidTV(void);
 SDL_bool SDL_IsChromebook(void);
 SDL_bool SDL_IsDeXMode(void);
 
+void Android_ActivityMutex_Lock(void);
+void Android_ActivityMutex_Unlock(void);
+void Android_ActivityMutex_Lock_Running(void);
+
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 /* *INDENT-OFF* */

+ 20 - 8
sdl.mod/SDL/src/core/linux/SDL_dbus.c

@@ -111,8 +111,19 @@ LoadDBUSLibrary(void)
 void
 SDL_DBus_Init(void)
 {
-    if (!dbus.session_conn && LoadDBUSLibrary() != -1) {
+    static SDL_bool is_dbus_available = SDL_TRUE;
+    if (!is_dbus_available) {
+        return;  /* don't keep trying if this fails. */
+    }
+
+    if (!dbus.session_conn) {
         DBusError err;
+
+        if (LoadDBUSLibrary() == -1) {
+            is_dbus_available = SDL_FALSE;  /* can't load at all? Don't keep trying. */
+            return;  /* oh well */
+        }
+
         dbus.error_init(&err);
         dbus.session_conn = dbus.bus_get_private(DBUS_BUS_SESSION, &err);
         if (!dbus.error_is_set(&err)) {
@@ -121,6 +132,7 @@ SDL_DBus_Init(void)
         if (dbus.error_is_set(&err)) {
             dbus.error_free(&err);
             SDL_DBus_Quit();
+            is_dbus_available = SDL_FALSE;
             return;  /* oh well */
         }
         dbus.connection_set_exit_on_disconnect(dbus.system_conn, 0);
@@ -154,15 +166,11 @@ SDL_DBus_Quit(void)
 SDL_DBusContext *
 SDL_DBus_GetContext(void)
 {
-    if(!dbus_handle || !dbus.session_conn){
+    if (!dbus_handle || !dbus.session_conn) {
         SDL_DBus_Init();
     }
     
-    if(dbus_handle && dbus.session_conn){
-        return &dbus;
-    } else {
-        return NULL;
-    }
+    return (dbus_handle && dbus.session_conn) ? &dbus : NULL;
 }
 
 static SDL_bool
@@ -310,7 +318,11 @@ SDL_DBus_QueryProperty(const char *node, const char *path, const char *interface
 void
 SDL_DBus_ScreensaverTickle(void)
 {
-    SDL_DBus_CallVoidMethod("org.gnome.ScreenSaver", "/org/gnome/ScreenSaver", "org.gnome.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
+    if (screensaver_cookie == 0) {  /* no need to tickle if we're inhibiting. */
+        /* org.gnome.ScreenSaver is the legacy interface, but it'll either do nothing or just be a second harmless tickle on newer systems, so we leave it for now. */
+        SDL_DBus_CallVoidMethod("org.gnome.ScreenSaver", "/org/gnome/ScreenSaver", "org.gnome.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
+        SDL_DBus_CallVoidMethod("org.freedesktop.ScreenSaver", "/org/freedesktop/ScreenSaver", "org.freedesktop.ScreenSaver", "SimulateUserActivity", DBUS_TYPE_INVALID);
+    }
 }
 
 SDL_bool

+ 57 - 22
sdl.mod/SDL/src/core/linux/SDL_evdev.c

@@ -129,6 +129,14 @@ static Uint8 EVDEV_MouseButtons[] = {
     SDL_BUTTON_X2 + 3           /*  BTN_TASK        0x117 */
 };
 
+static int
+SDL_EVDEV_SetRelativeMouseMode(SDL_bool enabled)
+{
+    /* Mice already send relative events through this interface */
+    return 0;
+}
+
+
 int
 SDL_EVDEV_Init(void)
 {
@@ -162,6 +170,8 @@ SDL_EVDEV_Init(void)
         _this->kbd = SDL_EVDEV_kbd_init();
     }
 
+    SDL_GetMouse()->SetRelativeMouseMode = SDL_EVDEV_SetRelativeMouseMode;
+
     _this->ref_count += 1;
 
     return 0;
@@ -272,6 +282,12 @@ SDL_EVDEV_Poll(void)
                        position is sent in EV_ABS ABS_X/ABS_Y, switching to
                        next finger after earlist is released) */
                     if (item->is_touchscreen && events[i].code == BTN_TOUCH) {
+                        if (item->touchscreen_data->max_slots == 1) {
+                            if (events[i].value)
+                                item->touchscreen_data->slots[0].delta = EVDEV_TOUCH_SLOTDELTA_DOWN;
+                            else
+                                item->touchscreen_data->slots[0].delta = EVDEV_TOUCH_SLOTDELTA_UP;
+                        }
                         break;
                     }
 
@@ -328,14 +344,20 @@ SDL_EVDEV_Poll(void)
                         }
                         break;
                     case ABS_X:
-                        if (item->is_touchscreen) /* FIXME: temp hack */
-                            break;
-                        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
+                        if (item->is_touchscreen) {
+                            if (item->touchscreen_data->max_slots != 1)
+                                break;
+                            item->touchscreen_data->slots[0].x = events[i].value;
+                        } else
+                            SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, events[i].value, mouse->y);
                         break;
                     case ABS_Y:
-                        if (item->is_touchscreen) /* FIXME: temp hack */
-                            break;
-                        SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value);
+                        if (item->is_touchscreen) {
+                            if (item->touchscreen_data->max_slots != 1)
+                                break;
+                            item->touchscreen_data->slots[0].y = events[i].value;
+                        } else
+                            SDL_SendMouseMotion(mouse->focus, mouse->mouseID, SDL_FALSE, mouse->x, events[i].value);
                         break;
                     default:
                         break;
@@ -379,18 +401,21 @@ SDL_EVDEV_Poll(void)
                                 norm_pressure = 1.0f;
                             }
 
+                            /* FIXME: the touch's window shouldn't be null, but
+                             * the coordinate space of touch positions needs to
+                             * be window-relative in that case. */
                             switch(item->touchscreen_data->slots[j].delta) {
                             case EVDEV_TOUCH_SLOTDELTA_DOWN:
-                                SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_TRUE, norm_x, norm_y, norm_pressure);
+                                SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, SDL_TRUE, norm_x, norm_y, norm_pressure);
                                 item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
                                 break;
                             case EVDEV_TOUCH_SLOTDELTA_UP:
-                                SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, SDL_FALSE, norm_x, norm_y, norm_pressure);
+                                SDL_SendTouch(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, SDL_FALSE, norm_x, norm_y, norm_pressure);
                                 item->touchscreen_data->slots[j].tracking_id = -1;
                                 item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
                                 break;
                             case EVDEV_TOUCH_SLOTDELTA_MOVE:
-                                SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, norm_x, norm_y, norm_pressure);
+                                SDL_SendTouchMotion(item->fd, item->touchscreen_data->slots[j].tracking_id, NULL, norm_x, norm_y, norm_pressure);
                                 item->touchscreen_data->slots[j].delta = EVDEV_TOUCH_SLOTDELTA_NONE;
                                 break;
                             default:
@@ -444,6 +469,7 @@ static int
 SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
 {
     int ret, i;
+    unsigned long xreq, yreq;
     char name[64];
     struct input_absinfo abs_info;
 
@@ -466,7 +492,24 @@ SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
         return SDL_OutOfMemory();
     }
 
-    ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_X), &abs_info);
+    ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
+    if (ret < 0) {
+        SDL_free(item->touchscreen_data->name);
+        SDL_free(item->touchscreen_data);
+        return SDL_SetError("Failed to get evdev touchscreen limits");
+    }
+
+    if (abs_info.maximum == 0) {
+        item->touchscreen_data->max_slots = 1;
+        xreq = EVIOCGABS(ABS_X);
+        yreq = EVIOCGABS(ABS_Y);
+    } else {
+        item->touchscreen_data->max_slots = abs_info.maximum + 1;
+        xreq = EVIOCGABS(ABS_MT_POSITION_X);
+        yreq = EVIOCGABS(ABS_MT_POSITION_Y);
+    }
+
+    ret = ioctl(item->fd, xreq, &abs_info);
     if (ret < 0) {
         SDL_free(item->touchscreen_data->name);
         SDL_free(item->touchscreen_data);
@@ -476,7 +519,7 @@ SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
     item->touchscreen_data->max_x = abs_info.maximum;
     item->touchscreen_data->range_x = abs_info.maximum - abs_info.minimum;
 
-    ret = ioctl(item->fd, EVIOCGABS(ABS_MT_POSITION_Y), &abs_info);
+    ret = ioctl(item->fd, yreq, &abs_info);
     if (ret < 0) {
         SDL_free(item->touchscreen_data->name);
         SDL_free(item->touchscreen_data);
@@ -496,14 +539,6 @@ SDL_EVDEV_init_touchscreen(SDL_evdevlist_item* item)
     item->touchscreen_data->max_pressure = abs_info.maximum;
     item->touchscreen_data->range_pressure = abs_info.maximum - abs_info.minimum;
 
-    ret = ioctl(item->fd, EVIOCGABS(ABS_MT_SLOT), &abs_info);
-    if (ret < 0) {
-        SDL_free(item->touchscreen_data->name);
-        SDL_free(item->touchscreen_data);
-        return SDL_SetError("Failed to get evdev touchscreen limits");
-    }
-    item->touchscreen_data->max_slots = abs_info.maximum + 1;
-
     item->touchscreen_data->slots = SDL_calloc(
         item->touchscreen_data->max_slots,
         sizeof(*item->touchscreen_data->slots));
@@ -556,8 +591,8 @@ SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
      *
      * this is the structure we're trying to emulate
      */
-    __u32* mt_req_code;
-    __s32* mt_req_values;
+    Uint32* mt_req_code;
+    Sint32* mt_req_values;
     size_t mt_req_size;
 
     /* TODO: sync devices other than touchscreen */
@@ -572,7 +607,7 @@ SDL_EVDEV_sync_device(SDL_evdevlist_item *item)
         return;
     }
 
-    mt_req_values = (__s32*)mt_req_code + 1;
+    mt_req_values = (Sint32*)mt_req_code + 1;
 
     *mt_req_code = ABS_MT_TRACKING_ID;
     ret = ioctl(item->fd, EVIOCGMTSLOTS(mt_req_size), mt_req_code);

+ 0 - 1
sdl.mod/SDL/src/core/linux/SDL_evdev_kbd.c

@@ -216,7 +216,6 @@ static void kbd_cleanup(void)
     }
     kbd_cleanup_state = NULL;
 
-    fprintf(stderr, "(SDL restoring keyboard) ");
     ioctl(kbd->console_fd, KDSKBMODE, kbd->old_kbd_mode);
 }
 

+ 13 - 9
sdl.mod/SDL/src/core/linux/SDL_threadprio.c

@@ -22,14 +22,17 @@
 
 #ifdef __LINUX__
 
+#include "SDL_stdinc.h"
+
 #if !SDL_THREADS_DISABLED
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <pthread.h>
 #include "SDL_system.h"
 
-#if SDL_USE_LIBDBUS
 #include "SDL_dbus.h"
+
+#if SDL_USE_LIBDBUS
 /* d-bus queries to org.freedesktop.RealtimeKit1. */
 #define RTKIT_DBUS_NODE "org.freedesktop.RealtimeKit1"
 #define RTKIT_DBUS_PATH "/org/freedesktop/RealtimeKit1"
@@ -86,14 +89,15 @@ SDL_LinuxSetThreadPriority(Sint64 threadID, int priority)
     }
 
 #if SDL_USE_LIBDBUS
-    /* Note that this fails if you're trying to set high priority
-       and you don't have root permission. BUT DON'T RUN AS ROOT!
-
-       You can grant the ability to increase thread priority by
-       running the following command on your application binary:
-          sudo setcap 'cap_sys_nice=eip' <application>
-
-       Let's try setting priority with RealtimeKit...
+    /* Note that this fails you most likely:
+         * Have your process's scheduler incorrectly configured.
+           See the requirements at:
+           http://git.0pointer.net/rtkit.git/tree/README#n16
+         * Encountered dbus/polkit security restrictions. Note
+           that the RealtimeKit1 dbus endpoint is inaccessible
+           over ssh connections for most common distro configs.
+           You might want to check your local config for details:
+           /usr/share/polkit-1/actions/org.freedesktop.RealtimeKit1.policy
 
        README and sample code at: http://git.0pointer.net/rtkit.git
     */

+ 7 - 0
sdl.mod/SDL/src/core/linux/SDL_udev.c

@@ -34,6 +34,7 @@
 #include "SDL_assert.h"
 #include "SDL_loadso.h"
 #include "SDL_timer.h"
+#include "SDL_hints.h"
 #include "../unix/SDL_poll.h"
 
 static const char *SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" };
@@ -420,6 +421,12 @@ device_event(SDL_UDEV_deviceevent type, struct udev_device *dev)
         if (val != NULL && SDL_strcmp(val, "1") == 0 ) {
             devclass |= SDL_UDEV_DEVICE_JOYSTICK;
         }
+
+        val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_ACCELEROMETER");
+        if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE) &&
+            val != NULL && SDL_strcmp(val, "1") == 0 ) {
+            devclass |= SDL_UDEV_DEVICE_JOYSTICK;
+	}
         
         val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_MOUSE");
         if (val != NULL && SDL_strcmp(val, "1") == 0 ) {

+ 65 - 4
sdl.mod/SDL/src/cpuinfo/SDL_cpuinfo.c

@@ -22,7 +22,6 @@
 #include "SDL_config.h"
 #else
 #include "../SDL_internal.h"
-#include "SDL_simd.h"
 #endif
 
 #if defined(__WIN32__) || defined(__WINRT__)
@@ -68,6 +67,13 @@
 #ifndef AT_HWCAP
 #define AT_HWCAP 16
 #endif
+#ifndef AT_PLATFORM
+#define AT_PLATFORM 15
+#endif
+/* Prevent compilation error when including elf.h would also try to define AT_* as an enum */
+#ifndef AT_NULL
+#define AT_NULL 0
+#endif
 #ifndef HWCAP_NEON
 #define HWCAP_NEON (1 << 12)
 #endif
@@ -97,6 +103,7 @@
 #define CPU_HAS_AVX2    (1 << 10)
 #define CPU_HAS_NEON    (1 << 11)
 #define CPU_HAS_AVX512F (1 << 12)
+#define CPU_HAS_ARM_SIMD (1 << 13)
 
 #if SDL_ALTIVEC_BLITTERS && HAVE_SETJMP && !__MACOSX__ && !__OpenBSD__
 /* This is the brute force way of detecting instruction sets...
@@ -326,7 +333,50 @@ CPU_haveAltiVec(void)
     return altivec;
 }
 
-#if defined(__LINUX__) && defined(__ARM_ARCH) && !defined(HAVE_GETAUXVAL)
+#if !defined(__ARM_ARCH)
+static SDL_bool CPU_haveARMSIMD(void) { return 0; }
+
+#elif defined(__linux__)
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <elf.h>
+
+static SDL_bool
+CPU_haveARMSIMD(void)
+{
+    int arm_simd = 0;
+    int fd;
+
+    fd = open("/proc/self/auxv", O_RDONLY);
+    if (fd >= 0)
+    {
+        Elf32_auxv_t aux;
+        while (read(fd, &aux, sizeof aux) == sizeof aux)
+        {
+            if (aux.a_type == AT_PLATFORM)
+            {
+                const char *plat = (const char *) aux.a_un.a_val;
+                arm_simd = strncmp(plat, "v6l", 3) == 0 ||
+                           strncmp(plat, "v7l", 3) == 0;
+            }
+        }
+        close(fd);
+    }
+    return arm_simd;
+}
+
+#else
+static SDL_bool
+CPU_haveARMSIMD(void)
+{
+    #warning SDL_HasARMSIMD is not implemented for this ARM platform. Write me.
+    return 0;
+}
+#endif
+
+#if (defined(__LINUX__) || defined(__ANDROID__)) && defined(__ARM_ARCH) && !defined(HAVE_GETAUXVAL)
 static int
 readProcAuxvForNeon(void)
 {
@@ -603,7 +653,7 @@ SDL_GetCPUCacheLineSize(void)
     if (SDL_strcmp(cpuType, "GenuineIntel") == 0) {
         cpuid(0x00000001, a, b, c, d);
         return (((b >> 8) & 0xff) * 8);
-    } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0) {
+    } else if (SDL_strcmp(cpuType, "AuthenticAMD") == 0 || SDL_strcmp(cpuType, "HygonGenuine") == 0) {
         cpuid(0x80000005, a, b, c, d);
         return (c & 0xff);
     } else {
@@ -621,7 +671,7 @@ SDL_GetCPUFeatures(void)
     if (SDL_CPUFeatures == 0xFFFFFFFF) {
         CPU_calcCPUIDFeatures();
         SDL_CPUFeatures = 0;
-        SDL_SIMDAlignment = 4;  /* a good safe base value */
+        SDL_SIMDAlignment = sizeof(void *);  /* a good safe base value */
         if (CPU_haveRDTSC()) {
             SDL_CPUFeatures |= CPU_HAS_RDTSC;
         }
@@ -669,6 +719,10 @@ SDL_GetCPUFeatures(void)
             SDL_CPUFeatures |= CPU_HAS_AVX512F;
             SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 64);
         }
+        if (CPU_haveARMSIMD()) {
+            SDL_CPUFeatures |= CPU_HAS_ARM_SIMD;
+            SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
+        }
         if (CPU_haveNEON()) {
             SDL_CPUFeatures |= CPU_HAS_NEON;
             SDL_SIMDAlignment = SDL_max(SDL_SIMDAlignment, 16);
@@ -750,6 +804,12 @@ SDL_HasAVX512F(void)
     return CPU_FEATURE_AVAILABLE(CPU_HAS_AVX512F);
 }
 
+SDL_bool
+SDL_HasARMSIMD(void)
+{
+    return CPU_FEATURE_AVAILABLE(CPU_HAS_ARM_SIMD);
+}
+
 SDL_bool
 SDL_HasNEON(void)
 {
@@ -871,6 +931,7 @@ main()
     printf("AVX: %d\n", SDL_HasAVX());
     printf("AVX2: %d\n", SDL_HasAVX2());
     printf("AVX-512F: %d\n", SDL_HasAVX512F());
+    printf("ARM SIMD: %d\n", SDL_HasARMSIMD());
     printf("NEON: %d\n", SDL_HasNEON());
     printf("RAM: %d MB\n", SDL_GetSystemRAM());
     return 0;

+ 0 - 88
sdl.mod/SDL/src/cpuinfo/SDL_simd.h

@@ -1,88 +0,0 @@
-/*
-  Simple DirectMedia Layer
-  Copyright (C) 1997-2019 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, subject to the following restrictions:
-
-  1. The origin of this software must not be misrepresented; you must not
-     claim that you wrote the original software. If you use this software
-     in a product, an acknowledgment in the product documentation would be
-     appreciated but is not required.
-  2. Altered source versions must be plainly marked as such, and must not be
-     misrepresented as being the original software.
-  3. This notice may not be removed or altered from any source distribution.
-*/
-
-#include "SDL.h"
-#include "../SDL_internal.h"
-
-/**
- * \brief Report the alignment this system needs for SIMD allocations.
- *
- * This will return the minimum number of bytes to which a pointer must be
- *  aligned to be compatible with SIMD instructions on the current machine.
- *  For example, if the machine supports SSE only, it will return 16, but if
- *  it supports AVX-512F, it'll return 64 (etc). This only reports values for
- *  instruction sets SDL knows about, so if your SDL build doesn't have
- *  SDL_HasAVX512F(), then it might return 16 for the SSE support it sees and
- *  not 64 for the AVX-512 instructions that exist but SDL doesn't know about.
- *  Plan accordingly.
- */
-extern size_t SDL_SIMDGetAlignment(void);
-
-/**
- * \brief Allocate memory in a SIMD-friendly way.
- *
- * This will allocate a block of memory that is suitable for use with SIMD
- *  instructions. Specifically, it will be properly aligned and padded for
- *  the system's supported vector instructions.
- *
- * The memory returned will be padded such that it is safe to read or write
- *  an incomplete vector at the end of the memory block. This can be useful
- *  so you don't have to drop back to a scalar fallback at the end of your
- *  SIMD processing loop to deal with the final elements without overflowing
- *  the allocated buffer.
- *
- * You must free this memory with SDL_FreeSIMD(), not free() or SDL_free()
- *  or delete[], etc.
- *
- * Note that SDL will only deal with SIMD instruction sets it is aware of;
- *  for example, SDL 2.0.8 knows that SSE wants 16-byte vectors
- *  (SDL_HasSSE()), and AVX2 wants 32 bytes (SDL_HasAVX2()), but doesn't
- *  know that AVX-512 wants 64. To be clear: if you can't decide to use an
- *  instruction set with an SDL_Has*() function, don't use that instruction
- *  set with memory allocated through here.
- *
- * SDL_AllocSIMD(0) will return a non-NULL pointer, assuming the system isn't
- *  out of memory.
- *
- *  \param len The length, in bytes, of the block to allocated. The actual
- *             allocated block might be larger due to padding, etc.
- * \return Pointer to newly-allocated block, NULL if out of memory.
- *
- * \sa SDL_SIMDAlignment
- * \sa SDL_SIMDFree
- */
-extern void * SDL_SIMDAlloc(const size_t len);
-
-/**
- * \brief Deallocate memory obtained from SDL_SIMDAlloc
- *
- * It is not valid to use this function on a pointer from anything but
- *  SDL_SIMDAlloc(). It can't be used on pointers from malloc, realloc,
- *  SDL_malloc, memalign, new[], etc.
- *
- * However, SDL_SIMDFree(NULL) is a legal no-op.
- *
- * \sa SDL_SIMDAlloc
- */
-extern void SDL_SIMDFree(void *ptr);
-
-/* vi: set ts=4 sw=4 expandtab: */
-

+ 42 - 13
sdl.mod/SDL/src/dynapi/SDL_dynapi.c

@@ -251,12 +251,12 @@ static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
     HMODULE hmodule;
     PFN retval = NULL;
     char error[256];
-    if (DosLoadModule(&error, sizeof(error), fname, &hmodule) == NO_ERROR) {
+    if (DosLoadModule(error, sizeof(error), fname, &hmodule) == NO_ERROR) {
         if (DosQueryProcAddr(hmodule, 0, sym, &retval) != NO_ERROR) {
             DosFreeModule(hmodule);
         }
     }
-    return (void *) retval;
+    return (void *)retval;
 }
 
 #else
@@ -264,29 +264,58 @@ static SDL_INLINE void *get_sdlapi_entry(const char *fname, const char *sym)
 #endif
 
 
+static void dynapi_warn(const char *msg)
+{
+    const char *caption = "SDL Dynamic API Failure!";
+    /* SDL_ShowSimpleMessageBox() is a too heavy for here. */
+    #if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__)
+    MessageBoxA(NULL, msg, caption, MB_OK | MB_ICONERROR);
+    #else
+    fprintf(stderr, "\n\n%s\n%s\n\n", caption, msg);
+    fflush(stderr);
+    #endif
+}
+
+/* This is not declared in any header, although it is shared between some
+    parts of SDL, because we don't want anything calling it without an
+    extremely good reason. */
+#if defined(__WATCOMC__)
+void SDL_ExitProcess(int exitcode);
+#pragma aux SDL_ExitProcess aborts;
+#endif
+SDL_NORETURN void SDL_ExitProcess(int exitcode);
+
+
 static void
 SDL_InitDynamicAPILocked(void)
 {
     const char *libname = SDL_getenv_REAL("SDL_DYNAMIC_API");
     SDL_DYNAPI_ENTRYFN entry = NULL;  /* funcs from here by default. */
+    SDL_bool use_internal = SDL_TRUE;
 
     if (libname) {
         entry = (SDL_DYNAPI_ENTRYFN) get_sdlapi_entry(libname, "SDL_DYNAPI_entry");
         if (!entry) {
-            /* !!! FIXME: fail to startup here instead? */
-            /* !!! FIXME: definitely warn user. */
-            /* Just fill in the function pointers from this library. */
+            dynapi_warn("Couldn't load overriding SDL library. Please fix or remove the SDL_DYNAMIC_API environment variable. Using the default SDL.");
+            /* Just fill in the function pointers from this library, later. */
         }
     }
 
-    if (!entry || (entry(SDL_DYNAPI_VERSION, &jump_table, sizeof (jump_table)) < 0)) {
-        /* !!! FIXME: fail to startup here instead? */
-        /* !!! FIXME: definitely warn user. */
-        /* Just fill in the function pointers from this library. */
-        if (!entry) {
-            if (!initialize_jumptable(SDL_DYNAPI_VERSION, &jump_table, sizeof (jump_table))) {
-                /* !!! FIXME: now we're screwed. Should definitely abort now. */
-            }
+    if (entry) {
+        if (entry(SDL_DYNAPI_VERSION, &jump_table, sizeof (jump_table)) < 0) {
+            dynapi_warn("Couldn't override SDL library. Using a newer SDL build might help. Please fix or remove the SDL_DYNAMIC_API environment variable. Using the default SDL.");
+            /* Just fill in the function pointers from this library, later. */
+        } else {
+            use_internal = SDL_FALSE;   /* We overrode SDL! Don't use the internal version! */
+        }
+    }
+
+    /* Just fill in the function pointers from this library. */
+    if (use_internal) {
+        if (initialize_jumptable(SDL_DYNAPI_VERSION, &jump_table, sizeof (jump_table)) < 0) {
+            /* Now we're screwed. Should definitely abort now. */
+            dynapi_warn("Failed to initialize internal SDL dynapi. As this would otherwise crash, we have to abort now.");
+            SDL_ExitProcess(86);
         }
     }
 

+ 14 - 0
sdl.mod/SDL/src/dynapi/SDL_dynapi_overrides.h

@@ -714,3 +714,17 @@
 #define SDL_RenderCopyExF SDL_RenderCopyExF_REAL
 #define SDL_GetTouchDeviceType SDL_GetTouchDeviceType_REAL
 #define SDL_UIKitRunApp SDL_UIKitRunApp_REAL
+#define SDL_SIMDGetAlignment SDL_SIMDGetAlignment_REAL
+#define SDL_SIMDAlloc SDL_SIMDAlloc_REAL
+#define SDL_SIMDFree SDL_SIMDFree_REAL
+#define SDL_RWsize SDL_RWsize_REAL
+#define SDL_RWseek SDL_RWseek_REAL
+#define SDL_RWtell SDL_RWtell_REAL
+#define SDL_RWread SDL_RWread_REAL
+#define SDL_RWwrite SDL_RWwrite_REAL
+#define SDL_RWclose SDL_RWclose_REAL
+#define SDL_LoadFile SDL_LoadFile_REAL
+#define SDL_Metal_CreateView SDL_Metal_CreateView_REAL
+#define SDL_Metal_DestroyView SDL_Metal_DestroyView_REAL
+#define SDL_LockTextureToSurface SDL_LockTextureToSurface_REAL
+#define SDL_HasARMSIMD SDL_HasARMSIMD_REAL

+ 15 - 1
sdl.mod/SDL/src/dynapi/SDL_dynapi_procs.h

@@ -715,7 +715,7 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_HasAVX512F,(void),(),return)
 #ifdef __ANDROID__
 SDL_DYNAPI_PROC(SDL_bool,SDL_IsChromebook,(void),(),return)
 SDL_DYNAPI_PROC(SDL_bool,SDL_IsDeXMode,(void),(),return)
-SDL_DYNAPI_PROC(void,SDL_AndroidBackButton,(void),(),return)
+SDL_DYNAPI_PROC(void,SDL_AndroidBackButton,(void),(),)
 #endif
 SDL_DYNAPI_PROC(double,SDL_exp,(double a),(a),return)
 SDL_DYNAPI_PROC(float,SDL_expf,(float a),(a),return)
@@ -770,3 +770,17 @@ SDL_DYNAPI_PROC(SDL_TouchDeviceType,SDL_GetTouchDeviceType,(SDL_TouchID a),(a),r
 #ifdef __IPHONEOS__
 SDL_DYNAPI_PROC(int,SDL_UIKitRunApp,(int a, char *b, SDL_main_func c),(a,b,c),return)
 #endif
+SDL_DYNAPI_PROC(size_t,SDL_SIMDGetAlignment,(void),(),return)
+SDL_DYNAPI_PROC(void*,SDL_SIMDAlloc,(const size_t a),(a),return)
+SDL_DYNAPI_PROC(void,SDL_SIMDFree,(void *a),(a),)
+SDL_DYNAPI_PROC(Sint64,SDL_RWsize,(SDL_RWops *a),(a),return)
+SDL_DYNAPI_PROC(Sint64,SDL_RWseek,(SDL_RWops *a, Sint64 b, int c),(a,b,c),return)
+SDL_DYNAPI_PROC(Sint64,SDL_RWtell,(SDL_RWops *a),(a),return)
+SDL_DYNAPI_PROC(size_t,SDL_RWread,(SDL_RWops *a, void *b, size_t c, size_t d),(a,b,c,d),return)
+SDL_DYNAPI_PROC(size_t,SDL_RWwrite,(SDL_RWops *a, const void *b, size_t c, size_t d),(a,b,c,d),return)
+SDL_DYNAPI_PROC(int,SDL_RWclose,(SDL_RWops *a),(a),return)
+SDL_DYNAPI_PROC(void*,SDL_LoadFile,(const char *a, size_t *b),(a,b),return)
+SDL_DYNAPI_PROC(SDL_MetalView,SDL_Metal_CreateView,(SDL_Window *a),(a),return)
+SDL_DYNAPI_PROC(void,SDL_Metal_DestroyView,(SDL_MetalView a),(a),)
+SDL_DYNAPI_PROC(int,SDL_LockTextureToSurface,(SDL_Texture *a, const SDL_Rect *b, SDL_Surface **c),(a,b,c),return)
+SDL_DYNAPI_PROC(SDL_bool,SDL_HasARMSIMD,(void),(),return)

+ 3 - 3
sdl.mod/SDL/src/dynapi/gendynapi.pl

@@ -49,9 +49,9 @@ open(SDL_DYNAPI_PROCS_H, '>>', $sdl_dynapi_procs_h) or die("Can't open $sdl_dyna
 open(SDL_DYNAPI_OVERRIDES_H, '>>', $sdl_dynapi_overrides_h) or die("Can't open $sdl_dynapi_overrides_h: $!\n");
 
 opendir(HEADERS, 'include') or die("Can't open include dir: $!\n");
-while (readdir(HEADERS)) {
-    next if not /\.h\Z/;
-    my $header = "include/$_";
+while (my $d = readdir(HEADERS)) {
+    next if not $d =~ /\.h\Z/;
+    my $header = "include/$d";
     open(HEADER, '<', $header) or die("Can't open $header: $!\n");
     while (<HEADER>) {
         chomp;

+ 9 - 9
sdl.mod/SDL/src/events/SDL_events.c

@@ -278,9 +278,9 @@ SDL_LogEvent(const SDL_Event *event)
         #undef PRINT_CONTROLLERDEV_EVENT
 
         #define PRINT_FINGER_EVENT(event) \
-            SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%lld fingerid=%lld x=%f y=%f dx=%f dy=%f pressure=%f)", \
-                (uint) event->tfinger.timestamp, (long long) event->tfinger.touchId, \
-                (long long) event->tfinger.fingerId, event->tfinger.x, event->tfinger.y, \
+            SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%"SDL_PRIs64" fingerid=%"SDL_PRIs64" x=%f y=%f dx=%f dy=%f pressure=%f)", \
+                (uint) event->tfinger.timestamp, event->tfinger.touchId, \
+                event->tfinger.fingerId, event->tfinger.x, event->tfinger.y, \
                 event->tfinger.dx, event->tfinger.dy, event->tfinger.pressure)
         SDL_EVENT_CASE(SDL_FINGERDOWN) PRINT_FINGER_EVENT(event); break;
         SDL_EVENT_CASE(SDL_FINGERUP) PRINT_FINGER_EVENT(event); break;
@@ -288,17 +288,17 @@ SDL_LogEvent(const SDL_Event *event)
         #undef PRINT_FINGER_EVENT
 
         #define PRINT_DOLLAR_EVENT(event) \
-            SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%lld gestureid=%lld numfingers=%u error=%f x=%f y=%f)", \
-                (uint) event->dgesture.timestamp, (long long) event->dgesture.touchId, \
-                (long long) event->dgesture.gestureId, (uint) event->dgesture.numFingers, \
+            SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%"SDL_PRIs64" gestureid=%"SDL_PRIs64" numfingers=%u error=%f x=%f y=%f)", \
+                (uint) event->dgesture.timestamp, event->dgesture.touchId, \
+                event->dgesture.gestureId, (uint) event->dgesture.numFingers, \
                 event->dgesture.error, event->dgesture.x, event->dgesture.y);
         SDL_EVENT_CASE(SDL_DOLLARGESTURE) PRINT_DOLLAR_EVENT(event); break;
         SDL_EVENT_CASE(SDL_DOLLARRECORD) PRINT_DOLLAR_EVENT(event); break;
         #undef PRINT_DOLLAR_EVENT
 
         SDL_EVENT_CASE(SDL_MULTIGESTURE)
-            SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%lld dtheta=%f ddist=%f x=%f y=%f numfingers=%u)",
-                (uint) event->mgesture.timestamp, (long long) event->mgesture.touchId,
+            SDL_snprintf(details, sizeof (details), " (timestamp=%u touchid=%"SDL_PRIs64" dtheta=%f ddist=%f x=%f y=%f numfingers=%u)",
+                (uint) event->mgesture.timestamp, event->mgesture.touchId,
                 event->mgesture.dTheta, event->mgesture.dDist,
                 event->mgesture.x, event->mgesture.y, (uint) event->mgesture.numFingers);
             break;
@@ -728,7 +728,7 @@ SDL_WaitEventTimeout(SDL_Event * event, int timeout)
                 /* Timeout expired and no events */
                 return 0;
             }
-            SDL_Delay(10);
+            SDL_Delay(1);
             break;
         default:
             /* Has events */

+ 45 - 36
sdl.mod/SDL/src/events/SDL_gesture.c

@@ -36,12 +36,14 @@
 
 #define MAXPATHSIZE 1024
 
-#define DOLLARNPOINTS 64
-#define DOLLARSIZE 256
-
 #define ENABLE_DOLLAR
 
-#define PHI 0.618033989
+#define DOLLARNPOINTS 64
+
+#if defined(ENABLE_DOLLAR)
+#  define DOLLARSIZE 256
+#  define PHI 0.618033989
+#endif
 
 typedef struct {
     float x,y;
@@ -335,7 +337,7 @@ static float bestDollarDifference(SDL_FloatPoint* points,SDL_FloatPoint* templ)
 }
 
 /* DollarPath contains raw points, plus (possibly) the calculated length */
-static int dollarNormalize(const SDL_DollarPath *path,SDL_FloatPoint *points)
+static int dollarNormalize(const SDL_DollarPath *path,SDL_FloatPoint *points, SDL_bool is_recording)
 {
     int i;
     float interval;
@@ -381,7 +383,9 @@ static int dollarNormalize(const SDL_DollarPath *path,SDL_FloatPoint *points)
         dist += d;
     }
     if (numPoints < DOLLARNPOINTS-1) {
-        SDL_SetError("ERROR: NumPoints = %i", numPoints);
+        if (is_recording) {
+            SDL_SetError("ERROR: NumPoints = %i", numPoints);
+        }
         return 0;
     }
     /* copy the last point */
@@ -435,7 +439,7 @@ static float dollarRecognize(const SDL_DollarPath *path,int *bestTempl,SDL_Gestu
 
     SDL_memset(points, 0, sizeof(points));
 
-    dollarNormalize(path,points);
+    dollarNormalize(path, points, SDL_FALSE);
 
     /* PrintPath(points); */
     *bestTempl = -1;
@@ -498,43 +502,48 @@ static SDL_GestureTouch * SDL_GetGestureTouch(SDL_TouchID id)
     return NULL;
 }
 
-static int SDL_SendGestureMulti(SDL_GestureTouch* touch,float dTheta,float dDist)
+static void SDL_SendGestureMulti(SDL_GestureTouch* touch,float dTheta,float dDist)
 {
-    SDL_Event event;
-    event.mgesture.type = SDL_MULTIGESTURE;
-    event.mgesture.touchId = touch->id;
-    event.mgesture.x = touch->centroid.x;
-    event.mgesture.y = touch->centroid.y;
-    event.mgesture.dTheta = dTheta;
-    event.mgesture.dDist = dDist;
-    event.mgesture.numFingers = touch->numDownFingers;
-    return SDL_PushEvent(&event) > 0;
+    if (SDL_GetEventState(SDL_MULTIGESTURE) == SDL_ENABLE) {
+        SDL_Event event;
+        event.mgesture.type = SDL_MULTIGESTURE;
+        event.mgesture.touchId = touch->id;
+        event.mgesture.x = touch->centroid.x;
+        event.mgesture.y = touch->centroid.y;
+        event.mgesture.dTheta = dTheta;
+        event.mgesture.dDist = dDist;
+        event.mgesture.numFingers = touch->numDownFingers;
+        SDL_PushEvent(&event);
+    }
 }
 
 #if defined(ENABLE_DOLLAR)
-static int SDL_SendGestureDollar(SDL_GestureTouch* touch,
+static void SDL_SendGestureDollar(SDL_GestureTouch* touch,
                           SDL_GestureID gestureId,float error)
 {
-    SDL_Event event;
-    event.dgesture.type = SDL_DOLLARGESTURE;
-    event.dgesture.touchId = touch->id;
-    event.dgesture.x = touch->centroid.x;
-    event.dgesture.y = touch->centroid.y;
-    event.dgesture.gestureId = gestureId;
-    event.dgesture.error = error;
-    /* A finger came up to trigger this event. */
-    event.dgesture.numFingers = touch->numDownFingers + 1;
-    return SDL_PushEvent(&event) > 0;
+    if (SDL_GetEventState(SDL_DOLLARGESTURE) == SDL_ENABLE) {
+        SDL_Event event;
+        event.dgesture.type = SDL_DOLLARGESTURE;
+        event.dgesture.touchId = touch->id;
+        event.dgesture.x = touch->centroid.x;
+        event.dgesture.y = touch->centroid.y;
+        event.dgesture.gestureId = gestureId;
+        event.dgesture.error = error;
+        /* A finger came up to trigger this event. */
+        event.dgesture.numFingers = touch->numDownFingers + 1;
+        SDL_PushEvent(&event);
+    }
 }
 
-
-static int SDL_SendDollarRecord(SDL_GestureTouch* touch,SDL_GestureID gestureId)
+static void SDL_SendDollarRecord(SDL_GestureTouch* touch,SDL_GestureID gestureId)
 {
-    SDL_Event event;
-    event.dgesture.type = SDL_DOLLARRECORD;
-    event.dgesture.touchId = touch->id;
-    event.dgesture.gestureId = gestureId;
-    return SDL_PushEvent(&event) > 0;
+    if (SDL_GetEventState(SDL_DOLLARRECORD) == SDL_ENABLE) {
+        SDL_Event event;
+        event.dgesture.type = SDL_DOLLARRECORD;
+        event.dgesture.touchId = touch->id;
+        event.dgesture.gestureId = gestureId;
+        SDL_PushEvent(&event);
+    }
 }
 #endif
 
@@ -576,7 +585,7 @@ void SDL_GestureProcessEvent(SDL_Event* event)
 #if defined(ENABLE_DOLLAR)
             if (inTouch->recording) {
                 inTouch->recording = SDL_FALSE;
-                dollarNormalize(&inTouch->dollarPath,path);
+                dollarNormalize(&inTouch->dollarPath, path, SDL_TRUE);
                 /* PrintPath(path); */
                 if (recordAll) {
                     index = SDL_AddDollarGesture(NULL,path);

+ 2 - 2
sdl.mod/SDL/src/events/SDL_keyboard.c

@@ -878,7 +878,7 @@ SDL_GetKeyFromScancode(SDL_Scancode scancode)
 {
     SDL_Keyboard *keyboard = &SDL_keyboard;
 
-    if (((int)scancode) < ((int)SDL_SCANCODE_UNKNOWN) || scancode >= SDL_NUM_SCANCODES) {
+    if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
           SDL_InvalidParamError("scancode");
           return 0;
     }
@@ -905,7 +905,7 @@ const char *
 SDL_GetScancodeName(SDL_Scancode scancode)
 {
     const char *name;
-    if (((int)scancode) < ((int)SDL_SCANCODE_UNKNOWN) || scancode >= SDL_NUM_SCANCODES) {
+    if (((int)scancode) < SDL_SCANCODE_UNKNOWN || scancode >= SDL_NUM_SCANCODES) {
           SDL_InvalidParamError("scancode");
           return "";
     }

+ 43 - 24
sdl.mod/SDL/src/events/SDL_mouse.c

@@ -156,6 +156,8 @@ SDL_MouseInit(void)
     SDL_AddHintCallback(SDL_HINT_MOUSE_TOUCH_EVENTS,
                         SDL_MouseTouchEventsChanged, mouse);
 
+    mouse->was_touch_mouse_events = SDL_FALSE; /* no touch to mouse movement event pending */
+
     mouse->cursor_shown = SDL_TRUE;
 
     return (0);
@@ -244,7 +246,7 @@ SDL_SetMouseFocus(SDL_Window * window)
 
 /* Check to see if we need to synthesize focus events */
 static SDL_bool
-SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate)
+SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate, SDL_bool send_mouse_motion)
 {
     SDL_Mouse *mouse = SDL_GetMouse();
     SDL_bool inWindow = SDL_TRUE;
@@ -275,7 +277,9 @@ SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate)
 #ifdef DEBUG_MOUSE
             printf("Mouse left window, synthesizing move & focus lost event\n");
 #endif
-            SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
+            if (send_mouse_motion) {
+                SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
+            }
             SDL_SetMouseFocus(NULL);
         }
         return SDL_FALSE;
@@ -286,7 +290,9 @@ SDL_UpdateMouseFocus(SDL_Window * window, int x, int y, Uint32 buttonstate)
         printf("Mouse entered window, synthesizing focus gain & move event\n");
 #endif
         SDL_SetMouseFocus(window);
-        SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
+        if (send_mouse_motion) {
+            SDL_PrivateSendMouseMotion(window, mouse->mouseID, 0, x, y);
+        }
     }
     return SDL_TRUE;
 }
@@ -296,7 +302,7 @@ SDL_SendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relative, int
 {
     if (window && !relative) {
         SDL_Mouse *mouse = SDL_GetMouse();
-        if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate)) {
+        if (!SDL_UpdateMouseFocus(window, x, y, mouse->buttonstate, (mouseID == SDL_TOUCH_MOUSEID) ? SDL_FALSE : SDL_TRUE)) {
             return 0;
         }
     }
@@ -333,11 +339,18 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ
             if (window) {
                 float fx = (float)x / (float)window->w;
                 float fy = (float)y / (float)window->h;
-                SDL_SendTouchMotion(SDL_MOUSE_TOUCHID, 0, fx, fy, 1.0f);
+                SDL_SendTouchMotion(SDL_MOUSE_TOUCHID, 0, window, fx, fy, 1.0f);
             }
         }
     }
 
+    /* SDL_HINT_TOUCH_MOUSE_EVENTS: if not set, discard synthetic mouse events coming from platform layer */
+    if (mouse->touch_mouse_events == 0) {
+        if (mouseID == SDL_TOUCH_MOUSEID) {
+            return 0;
+        }
+    }
+
     if (mouseID != SDL_TOUCH_MOUSEID && mouse->relative_mode_warp) {
         int center_x = 0, center_y = 0;
         SDL_GetWindowSize(window, &center_x, &center_y);
@@ -368,19 +381,16 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ
         yrel = y - mouse->last_y;
     }
 
-    /* Drop events that don't change state */
-    if (!xrel && !yrel) {
-#ifdef DEBUG_MOUSE
-        printf("Mouse event didn't change state - dropped!\n");
-#endif
-        return 0;
-    }
-
     /* Ignore relative motion when first positioning the mouse */
     if (!mouse->has_position) {
         xrel = 0;
         yrel = 0;
         mouse->has_position = SDL_TRUE;
+    } else if (!xrel && !yrel) {  /* Drop events that don't change state */
+#ifdef DEBUG_MOUSE
+        printf("Mouse event didn't change state - dropped!\n");
+#endif
+        return 0;
     }
 
     /* Ignore relative motion positioning the first touch */
@@ -439,6 +449,8 @@ SDL_PrivateSendMouseMotion(SDL_Window * window, SDL_MouseID mouseID, int relativ
         event.motion.type = SDL_MOUSEMOTION;
         event.motion.windowID = mouse->focus ? mouse->focus->id : 0;
         event.motion.which = mouseID;
+        /* Set us pending (or clear during a normal mouse movement event) as having triggered */
+        mouse->was_touch_mouse_events = (mouseID == SDL_TOUCH_MOUSEID)? SDL_TRUE : SDL_FALSE;
         event.motion.state = mouse->buttonstate;
         event.motion.x = mouse->x;
         event.motion.y = mouse->y;
@@ -494,11 +506,18 @@ SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state
             if (window) {
                 float fx = (float)mouse->x / (float)window->w;
                 float fy = (float)mouse->y / (float)window->h;
-                SDL_SendTouch(SDL_MOUSE_TOUCHID, 0, track_mouse_down, fx, fy, 1.0f);
+                SDL_SendTouch(SDL_MOUSE_TOUCHID, 0, window, track_mouse_down, fx, fy, 1.0f);
             }
         }
     }
 
+    /* SDL_HINT_TOUCH_MOUSE_EVENTS: if not set, discard synthetic mouse events coming from platform layer */
+    if (mouse->touch_mouse_events == 0) {
+        if (mouseID == SDL_TOUCH_MOUSEID) {
+            return 0;
+        }
+    }
+
     /* Figure out which event to perform */
     switch (state) {
     case SDL_PRESSED:
@@ -516,7 +535,7 @@ SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state
 
     /* We do this after calculating buttonstate so button presses gain focus */
     if (window && state == SDL_PRESSED) {
-        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
+        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate, SDL_TRUE);
     }
 
     if (buttonstate == mouse->buttonstate) {
@@ -566,7 +585,7 @@ SDL_PrivateSendMouseButton(SDL_Window * window, SDL_MouseID mouseID, Uint8 state
 
     /* We do this after dispatching event so button releases can lose focus */
     if (window && state == SDL_RELEASED) {
-        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate);
+        SDL_UpdateMouseFocus(window, mouse->x, mouse->y, buttonstate, SDL_TRUE);
     }
 
     return posted;
@@ -783,14 +802,6 @@ SDL_SetRelativeMouseMode(SDL_bool enabled)
         return 0;
     }
 
-    if (enabled && focusWindow) {
-        /* Center it in the focused window to prevent clicks from going through
-         * to background windows.
-         */
-        SDL_SetMouseFocus(focusWindow);
-        SDL_WarpMouseInWindow(focusWindow, focusWindow->w/2, focusWindow->h/2);
-    }
-
     /* Set the relative mode */
     if (!enabled && mouse->relative_mode_warp) {
         mouse->relative_mode_warp = SDL_FALSE;
@@ -809,6 +820,14 @@ SDL_SetRelativeMouseMode(SDL_bool enabled)
     mouse->scale_accum_x = 0.0f;
     mouse->scale_accum_y = 0.0f;
 
+    if (enabled && focusWindow) {
+        /* Center it in the focused window to prevent clicks from going through
+         * to background windows.
+         */
+        SDL_SetMouseFocus(focusWindow);
+        SDL_WarpMouseInWindow(focusWindow, focusWindow->w/2, focusWindow->h/2);
+    }
+
     if (mouse->focus) {
         SDL_UpdateWindowGrab(mouse->focus);
 

+ 1 - 0
sdl.mod/SDL/src/events/SDL_mouse_c.h

@@ -94,6 +94,7 @@ typedef struct
     int double_click_radius;
     SDL_bool touch_mouse_events;
     SDL_bool mouse_touch_events;
+    SDL_bool was_touch_mouse_events; /* Was a touch-mouse event pending? */
 
     /* Data for double-click tracking */
     int num_clickstates;

+ 36 - 8
sdl.mod/SDL/src/events/SDL_touch.c

@@ -32,9 +32,14 @@ static int SDL_num_touch = 0;
 static SDL_Touch **SDL_touchDevices = NULL;
 
 /* for mapping touch events to mice */
+
+#define SYNTHESIZE_TOUCH_TO_MOUSE 1
+
+#if SYNTHESIZE_TOUCH_TO_MOUSE
 static SDL_bool finger_touching = SDL_FALSE;
 static SDL_FingerID track_fingerid;
 static SDL_TouchID  track_touchid;
+#endif
 
 /* Public functions */
 int
@@ -234,24 +239,26 @@ SDL_DelFinger(SDL_Touch* touch, SDL_FingerID fingerid)
 }
 
 int
-SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid,
+SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window * window,
               SDL_bool down, float x, float y, float pressure)
 {
     int posted;
     SDL_Finger *finger;
+    SDL_Mouse *mouse;
 
     SDL_Touch* touch = SDL_GetTouch(id);
     if (!touch) {
         return -1;
     }
 
+    mouse = SDL_GetMouse();
+
+#if SYNTHESIZE_TOUCH_TO_MOUSE
     /* SDL_HINT_TOUCH_MOUSE_EVENTS: controlling whether touch events should generate synthetic mouse events */
     {
-        SDL_Mouse *mouse = SDL_GetMouse();
         if (mouse->touch_mouse_events) {
             /* FIXME: maybe we should only restrict to a few SDL_TouchDeviceType */
             if (id != SDL_MOUSE_TOUCHID) {
-                SDL_Window *window = SDL_GetMouseFocus();
                 if (window) {
                     if (down) {
                         if (finger_touching == SDL_FALSE) {
@@ -284,6 +291,14 @@ SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid,
             }
         }
     }
+#endif
+
+    /* SDL_HINT_MOUSE_TOUCH_EVENTS: if not set, discard synthetic touch events coming from platform layer */
+    if (mouse->mouse_touch_events == 0) {
+        if (id == SDL_MOUSE_TOUCHID) {
+            return 0;
+        }
+    }
 
     finger = SDL_GetFinger(touch, fingerid);
     if (down) {
@@ -307,6 +322,7 @@ SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid,
             event.tfinger.dx = 0;
             event.tfinger.dy = 0;
             event.tfinger.pressure = pressure;
+            event.tfinger.windowID = window ? SDL_GetWindowID(window) : 0;
             posted = (SDL_PushEvent(&event) > 0);
         }
     } else {
@@ -319,7 +335,7 @@ SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid,
         if (SDL_GetEventState(SDL_FINGERUP) == SDL_ENABLE) {
             SDL_Event event;
             event.tfinger.type = SDL_FINGERUP;
-            event.tfinger.touchId =  id;
+            event.tfinger.touchId = id;
             event.tfinger.fingerId = fingerid;
             /* I don't trust the coordinates passed on fingerUp */
             event.tfinger.x = finger->x;
@@ -327,6 +343,7 @@ SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid,
             event.tfinger.dx = 0;
             event.tfinger.dy = 0;
             event.tfinger.pressure = pressure;
+            event.tfinger.windowID = window ? SDL_GetWindowID(window) : 0;
             posted = (SDL_PushEvent(&event) > 0);
         }
 
@@ -336,11 +353,12 @@ SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid,
 }
 
 int
-SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid,
+SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window * window,
                     float x, float y, float pressure)
 {
     SDL_Touch *touch;
     SDL_Finger *finger;
+    SDL_Mouse *mouse;
     int posted;
     float xrel, yrel, prel;
 
@@ -349,12 +367,13 @@ SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid,
         return -1;
     }
 
+    mouse = SDL_GetMouse();
+
+#if SYNTHESIZE_TOUCH_TO_MOUSE
     /* SDL_HINT_TOUCH_MOUSE_EVENTS: controlling whether touch events should generate synthetic mouse events */
     {
-        SDL_Mouse *mouse = SDL_GetMouse();
         if (mouse->touch_mouse_events) {
             if (id != SDL_MOUSE_TOUCHID) {
-                SDL_Window *window = SDL_GetMouseFocus();
                 if (window) {
                     if (finger_touching == SDL_TRUE && track_touchid == id && track_fingerid == fingerid) {
                         int pos_x = (int)(x * (float)window->w);
@@ -369,10 +388,18 @@ SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid,
             }
         }
     }
+#endif
+
+    /* SDL_HINT_MOUSE_TOUCH_EVENTS: if not set, discard synthetic touch events coming from platform layer */
+    if (mouse->mouse_touch_events == 0) {
+        if (id == SDL_MOUSE_TOUCHID) {
+            return 0;
+        }
+    }
 
     finger = SDL_GetFinger(touch,fingerid);
     if (!finger) {
-        return SDL_SendTouch(id, fingerid, SDL_TRUE, x, y, pressure);
+        return SDL_SendTouch(id, fingerid, window, SDL_TRUE, x, y, pressure);
     }
 
     xrel = x - finger->x;
@@ -404,6 +431,7 @@ SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid,
         event.tfinger.dx = xrel;
         event.tfinger.dy = yrel;
         event.tfinger.pressure = pressure;
+        event.tfinger.windowID = window ? SDL_GetWindowID(window) : 0;
         posted = (SDL_PushEvent(&event) > 0);
     }
     return posted;

+ 2 - 2
sdl.mod/SDL/src/events/SDL_touch_c.h

@@ -44,11 +44,11 @@ extern int SDL_AddTouch(SDL_TouchID id, SDL_TouchDeviceType type, const char *na
 extern SDL_Touch *SDL_GetTouch(SDL_TouchID id);
 
 /* Send a touch down/up event for a touch */
-extern int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid,
+extern int SDL_SendTouch(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window * window,
                          SDL_bool down, float x, float y, float pressure);
 
 /* Send a touch motion event for a touch */
-extern int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid,
+extern int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, SDL_Window * window,
                                float x, float y, float pressure);
 
 /* Remove a touch */

+ 61 - 3
sdl.mod/SDL/src/file/SDL_rwops.c

@@ -361,13 +361,29 @@ stdio_size(SDL_RWops * context)
 static Sint64 SDLCALL
 stdio_seek(SDL_RWops * context, Sint64 offset, int whence)
 {
+    int stdiowhence;
+
+    switch (whence) {
+    case RW_SEEK_SET:
+        stdiowhence = SEEK_SET;
+        break;
+    case RW_SEEK_CUR:
+        stdiowhence = SEEK_CUR;
+        break;
+    case RW_SEEK_END:
+        stdiowhence = SEEK_END;
+        break;
+    default:
+        return SDL_SetError("Unknown value for 'whence'");
+    }
+
 #if defined(FSEEK_OFF_MIN) && defined(FSEEK_OFF_MAX)
     if (offset < (Sint64)(FSEEK_OFF_MIN) || offset > (Sint64)(FSEEK_OFF_MAX)) {
         return SDL_SetError("Seek offset out of range");
     }
 #endif
 
-    if (fseek(context->hidden.stdio.fp, (fseek_off_t)offset, whence) == 0) {
+    if (fseek(context->hidden.stdio.fp, (fseek_off_t)offset, stdiowhence) == 0) {
         Sint64 pos = ftell(context->hidden.stdio.fp);
         if (pos < 0) {
             return SDL_SetError("Couldn't get stream offset");
@@ -462,7 +478,7 @@ mem_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
 
     total_bytes = (maxnum * size);
     if ((maxnum <= 0) || (size <= 0)
-        || ((total_bytes / maxnum) != (size_t) size)) {
+        || ((total_bytes / maxnum) != size)) {
         return 0;
     }
 
@@ -585,7 +601,7 @@ SDL_RWFromFile(const char *file, const char *mode)
         if (fp == NULL) {
             SDL_SetError("Couldn't open %s", file);
         } else {
-            rwops = SDL_RWFromFP(fp, 1);
+            rwops = SDL_RWFromFP(fp, SDL_TRUE);
         }
     }
 #else
@@ -752,6 +768,48 @@ done:
     return data;
 }
 
+void *
+SDL_LoadFile(const char *file, size_t *datasize)
+{
+   return SDL_LoadFile_RW(SDL_RWFromFile(file, "rb"), datasize, 1);
+}
+
+Sint64
+SDL_RWsize(SDL_RWops *context)
+{
+    return context->size(context);
+}
+
+Sint64
+SDL_RWseek(SDL_RWops *context, Sint64 offset, int whence)
+{
+    return context->seek(context, offset, whence);
+}
+
+Sint64
+SDL_RWtell(SDL_RWops *context)
+{
+    return context->seek(context, 0, RW_SEEK_CUR);
+}
+
+size_t
+SDL_RWread(SDL_RWops *context, void *ptr, size_t size, size_t maxnum)
+{
+    return context->read(context, ptr, size, maxnum);
+}
+
+size_t
+SDL_RWwrite(SDL_RWops *context, const void *ptr, size_t size, size_t num)
+{
+    return context->write(context, ptr, size, num);
+}
+
+int
+SDL_RWclose(SDL_RWops *context)
+{
+    return context->close(context);
+}
+
 /* Functions for dynamically reading and writing endian-specific values */
 
 Uint8

+ 21 - 0
sdl.mod/SDL/src/filesystem/cocoa/SDL_sysfilesystem.m

@@ -32,6 +32,7 @@
 #include "SDL_error.h"
 #include "SDL_stdinc.h"
 #include "SDL_filesystem.h"
+#include "SDL_log.h"
 
 char *
 SDL_GetBasePath(void)
@@ -80,7 +81,27 @@ SDL_GetPrefPath(const char *org, const char *app)
     }
 
     char *retval = NULL;
+#if !TARGET_OS_TV
     NSArray *array = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
+#else
+    /* tvOS does not have persistent local storage!
+     * The only place on-device where we can store data is
+     * a cache directory that the OS can empty at any time.
+     *
+     * It's therefore very likely that save data will be erased
+     * between sessions. If you want your app's save data to
+     * actually stick around, you'll need to use iCloud storage.
+     */
+
+    static SDL_bool shown = SDL_FALSE;
+    if (!shown)
+    {
+        shown = SDL_TRUE;
+        SDL_LogCritical(SDL_LOG_CATEGORY_SYSTEM, "tvOS does not have persistent local storage! Use iCloud storage if you want your data to persist between sessions.\n");
+    }
+
+    NSArray *array = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
+#endif /* !TARGET_OS_TV */
 
     if ([array count] > 0) {  /* we only want the first item in the list. */
         NSString *str = [array objectAtIndex:0];

+ 1 - 1
sdl.mod/SDL/src/filesystem/unix/SDL_sysfilesystem.c

@@ -140,7 +140,7 @@ SDL_GetBasePath(void)
         if (retval == NULL) {
             /* older kernels don't have /proc/self ... try PID version... */
             char path[64];
-            const int rc = (int) SDL_snprintf(path, sizeof(path),
+            const int rc = SDL_snprintf(path, sizeof(path),
                                               "/proc/%llu/exe",
                                               (unsigned long long) getpid());
             if ( (rc > 0) && (rc < sizeof(path)) ) {

+ 1 - 1
sdl.mod/SDL/src/hidapi/AUTHORS.txt

@@ -12,5 +12,5 @@ Ludovic Rousseau <[email protected]>:
 
 
 For a comprehensive list of contributions, see the commit list at github:
-	http://github.com/signal11/hidapi/commits/master
+	https://github.com/libusb/hidapi/commits/master
 

+ 1 - 1
sdl.mod/SDL/src/hidapi/README.txt

@@ -122,7 +122,7 @@ HIDAPI may be used by one of three licenses as outlined in LICENSE.txt.
 Download
 =========
 HIDAPI can be downloaded from github
-	git clone git://github.com/signal11/hidapi.git
+	git clone git://github.com/libusb/hidapi.git
 
 Build Instructions
 ===================

+ 744 - 0
sdl.mod/SDL/src/hidapi/SDL_hidapi.c

@@ -0,0 +1,744 @@
+/*
+  Simple DirectMedia Layer
+  Copyright (C) 1997-2019 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, subject to the following restrictions:
+
+  1. The origin of this software must not be misrepresented; you must not
+     claim that you wrote the original software. If you use this software
+     in a product, an acknowledgment in the product documentation would be
+     appreciated but is not required.
+  2. Altered source versions must be plainly marked as such, and must not be
+     misrepresented as being the original software.
+  3. This notice may not be removed or altered from any source distribution.
+*/
+
+/* Original hybrid wrapper for Linux by Valve Software. Their original notes:
+ *
+ * The libusb version doesn't support Bluetooth, but not all Linux
+ * distributions allow access to /dev/hidraw*
+ *
+ * This merges the two, at a small performance cost, until distributions
+ * have granted access to /dev/hidraw*
+ */
+
+#include "../SDL_internal.h"
+#include "SDL_loadso.h"
+
+#ifdef SDL_JOYSTICK_HIDAPI
+
+/* Platform HIDAPI Implementation */
+
+#define hid_device_                     PLATFORM_hid_device_
+#define hid_device                      PLATFORM_hid_device
+#define hid_device_info                 PLATFORM_hid_device_info
+#define hid_init                        PLATFORM_hid_init
+#define hid_exit                        PLATFORM_hid_exit
+#define hid_enumerate                   PLATFORM_hid_enumerate
+#define hid_free_enumeration            PLATFORM_hid_free_enumeration
+#define hid_open                        PLATFORM_hid_open
+#define hid_open_path                   PLATFORM_hid_open_path
+#define hid_write                       PLATFORM_hid_write
+#define hid_read_timeout                PLATFORM_hid_read_timeout
+#define hid_read                        PLATFORM_hid_read
+#define hid_set_nonblocking             PLATFORM_hid_set_nonblocking
+#define hid_send_feature_report         PLATFORM_hid_send_feature_report
+#define hid_get_feature_report          PLATFORM_hid_get_feature_report
+#define hid_close                       PLATFORM_hid_close
+#define hid_get_manufacturer_string     PLATFORM_hid_get_manufacturer_string
+#define hid_get_product_string          PLATFORM_hid_get_product_string
+#define hid_get_serial_number_string    PLATFORM_hid_get_serial_number_string
+#define hid_get_indexed_string          PLATFORM_hid_get_indexed_string
+#define hid_error                       PLATFORM_hid_error
+#define new_hid_device                  PLATFORM_new_hid_device
+#define free_hid_device                 PLATFORM_free_hid_device
+#define input_report                    PLATFORM_input_report
+#define return_data                     PLATFORM_return_data
+#define make_path                       PLATFORM_make_path
+#define read_thread                     PLATFORM_read_thread
+
+#if __LINUX__
+
+#include "../../core/linux/SDL_udev.h"
+#if SDL_USE_LIBUDEV
+static const SDL_UDEV_Symbols *udev_ctx = NULL;
+
+#define udev_device_get_sysattr_value                    udev_ctx->udev_device_get_sysattr_value
+#define udev_new                                         udev_ctx->udev_new
+#define udev_unref                                       udev_ctx->udev_unref
+#define udev_device_new_from_devnum                      udev_ctx->udev_device_new_from_devnum
+#define udev_device_get_parent_with_subsystem_devtype    udev_ctx->udev_device_get_parent_with_subsystem_devtype
+#define udev_device_unref                                udev_ctx->udev_device_unref
+#define udev_enumerate_new                               udev_ctx->udev_enumerate_new
+#define udev_enumerate_add_match_subsystem               udev_ctx->udev_enumerate_add_match_subsystem
+#define udev_enumerate_scan_devices                      udev_ctx->udev_enumerate_scan_devices
+#define udev_enumerate_get_list_entry                    udev_ctx->udev_enumerate_get_list_entry
+#define udev_list_entry_get_name                         udev_ctx->udev_list_entry_get_name
+#define udev_device_new_from_syspath                     udev_ctx->udev_device_new_from_syspath
+#define udev_device_get_devnode                          udev_ctx->udev_device_get_devnode
+#define udev_list_entry_get_next                         udev_ctx->udev_list_entry_get_next
+#define udev_enumerate_unref                             udev_ctx->udev_enumerate_unref
+
+#include "linux/hid.c"
+#define HAVE_PLATFORM_BACKEND 1
+#endif /* SDL_USE_LIBUDEV */
+
+#elif __MACOSX__
+#include "mac/hid.c"
+#define HAVE_PLATFORM_BACKEND 1
+#define udev_ctx 1
+#elif __WINDOWS__
+#include "windows/hid.c"
+#define HAVE_PLATFORM_BACKEND 1
+#define udev_ctx 1
+#else
+#error Need a hid.c for this platform!
+#endif
+
+#undef hid_device_
+#undef hid_device
+#undef hid_device_info
+#undef hid_init
+#undef hid_exit
+#undef hid_enumerate
+#undef hid_free_enumeration
+#undef hid_open
+#undef hid_open_path
+#undef hid_write
+#undef hid_read_timeout
+#undef hid_read
+#undef hid_set_nonblocking
+#undef hid_send_feature_report
+#undef hid_get_feature_report
+#undef hid_close
+#undef hid_get_manufacturer_string
+#undef hid_get_product_string
+#undef hid_get_serial_number_string
+#undef hid_get_indexed_string
+#undef hid_error
+#undef new_hid_device
+#undef free_hid_device
+#undef input_report
+#undef return_data
+#undef make_path
+#undef read_thread
+
+#ifndef SDL_LIBUSB_DYNAMIC
+#if __WINDOWS__
+#define SDL_LIBUSB_DYNAMIC "libusb-1.0.dll"
+#endif /* __WINDOWS__ */
+#endif /* SDL_LIBUSB_DYNAMIC */
+
+#ifdef SDL_LIBUSB_DYNAMIC
+/* libusb HIDAPI Implementation */
+
+/* Include this now, for our dynamically-loaded libusb context */
+#include <libusb.h>
+
+static struct
+{
+    void* libhandle;
+
+    int (*init)(libusb_context **ctx);
+    void (*exit)(libusb_context *ctx);
+    ssize_t (*get_device_list)(libusb_context *ctx, libusb_device ***list);
+    void (*free_device_list)(libusb_device **list, int unref_devices);
+    int (*get_device_descriptor)(libusb_device *dev, struct libusb_device_descriptor *desc);
+    int (*get_active_config_descriptor)(libusb_device *dev,    struct libusb_config_descriptor **config);
+    int (*get_config_descriptor)(
+        libusb_device *dev,
+        uint8_t config_index,
+        struct libusb_config_descriptor **config
+    );
+    void (*free_config_descriptor)(struct libusb_config_descriptor *config);
+    uint8_t (*get_bus_number)(libusb_device *dev);
+    uint8_t (*get_device_address)(libusb_device *dev);
+    int (*open)(libusb_device *dev, libusb_device_handle **dev_handle);
+    void (*close)(libusb_device_handle *dev_handle);
+    int (*claim_interface)(libusb_device_handle *dev_handle, int interface_number);
+    int (*release_interface)(libusb_device_handle *dev_handle, int interface_number);
+    int (*kernel_driver_active)(libusb_device_handle *dev_handle, int interface_number);
+    int (*detach_kernel_driver)(libusb_device_handle *dev_handle, int interface_number);
+    struct libusb_transfer * (*alloc_transfer)(int iso_packets);
+    int (*submit_transfer)(struct libusb_transfer *transfer);
+    int (*cancel_transfer)(struct libusb_transfer *transfer);
+    void (*free_transfer)(struct libusb_transfer *transfer);
+    int (*control_transfer)(
+        libusb_device_handle *dev_handle,
+        uint8_t request_type,
+        uint8_t bRequest,
+        uint16_t wValue,
+        uint16_t wIndex,
+        unsigned char *data,
+        uint16_t wLength,
+        unsigned int timeout
+    );
+    int (*interrupt_transfer)(
+        libusb_device_handle *dev_handle,
+        unsigned char endpoint,
+        unsigned char *data,
+        int length,
+        int *actual_length,
+        unsigned int timeout
+    );
+    int (*handle_events)(libusb_context *ctx);
+    int (*handle_events_completed)(libusb_context *ctx, int *completed);
+} libusb_ctx;
+
+#define libusb_init                            libusb_ctx.init
+#define libusb_exit                            libusb_ctx.exit
+#define libusb_get_device_list                 libusb_ctx.get_device_list
+#define libusb_free_device_list                libusb_ctx.free_device_list
+#define libusb_get_device_descriptor           libusb_ctx.get_device_descriptor
+#define libusb_get_active_config_descriptor    libusb_ctx.get_active_config_descriptor
+#define libusb_get_config_descriptor           libusb_ctx.get_config_descriptor
+#define libusb_free_config_descriptor          libusb_ctx.free_config_descriptor
+#define libusb_get_bus_number                  libusb_ctx.get_bus_number
+#define libusb_get_device_address              libusb_ctx.get_device_address
+#define libusb_open                            libusb_ctx.open
+#define libusb_close                           libusb_ctx.close
+#define libusb_claim_interface                 libusb_ctx.claim_interface
+#define libusb_release_interface               libusb_ctx.release_interface
+#define libusb_kernel_driver_active            libusb_ctx.kernel_driver_active
+#define libusb_detach_kernel_driver            libusb_ctx.detach_kernel_driver
+#define libusb_alloc_transfer                  libusb_ctx.alloc_transfer
+#define libusb_submit_transfer                 libusb_ctx.submit_transfer
+#define libusb_cancel_transfer                 libusb_ctx.cancel_transfer
+#define libusb_free_transfer                   libusb_ctx.free_transfer
+#define libusb_control_transfer                libusb_ctx.control_transfer
+#define libusb_interrupt_transfer              libusb_ctx.interrupt_transfer
+#define libusb_handle_events                   libusb_ctx.handle_events
+#define libusb_handle_events_completed         libusb_ctx.handle_events_completed
+
+#define hid_device_                     LIBUSB_hid_device_
+#define hid_device                      LIBUSB_hid_device
+#define hid_device_info                 LIBUSB_hid_device_info
+#define hid_init                        LIBUSB_hid_init
+#define hid_exit                        LIBUSB_hid_exit
+#define hid_enumerate                   LIBUSB_hid_enumerate
+#define hid_free_enumeration            LIBUSB_hid_free_enumeration
+#define hid_open                        LIBUSB_hid_open
+#define hid_open_path                   LIBUSB_hid_open_path
+#define hid_write                       LIBUSB_hid_write
+#define hid_read_timeout                LIBUSB_hid_read_timeout
+#define hid_read                        LIBUSB_hid_read
+#define hid_set_nonblocking             LIBUSB_hid_set_nonblocking
+#define hid_send_feature_report         LIBUSB_hid_send_feature_report
+#define hid_get_feature_report          LIBUSB_hid_get_feature_report
+#define hid_close                       LIBUSB_hid_close
+#define hid_get_manufacturer_string     LIBUSB_hid_get_manufacturer_string
+#define hid_get_product_string          LIBUSB_hid_get_product_string
+#define hid_get_serial_number_string    LIBUSB_hid_get_serial_number_string
+#define hid_get_indexed_string          LIBUSB_hid_get_indexed_string
+#define hid_error                       LIBUSB_hid_error
+#define new_hid_device                  LIBUSB_new_hid_device
+#define free_hid_device                 LIBUSB_free_hid_device
+#define input_report                    LIBUSB_input_report
+#define return_data                     LIBUSB_return_data
+#define make_path                       LIBUSB_make_path
+#define read_thread                     LIBUSB_read_thread
+
+#ifndef __FreeBSD__
+/* this is awkwardly inlined, so we need to re-implement it here
+ * so we can override the libusb_control_transfer call */
+static int
+SDL_libusb_get_string_descriptor(libusb_device_handle *dev,
+                                 uint8_t descriptor_index, uint16_t lang_id,
+                                 unsigned char *data, int length)
+{
+    return libusb_control_transfer(dev,
+                                   LIBUSB_ENDPOINT_IN | 0x0, /* Endpoint 0 IN */
+                                   LIBUSB_REQUEST_GET_DESCRIPTOR,
+                                   (LIBUSB_DT_STRING << 8) | descriptor_index,
+                                   lang_id,
+                                   data,
+                                   (uint16_t) length,
+                                   1000);
+}
+#define libusb_get_string_descriptor SDL_libusb_get_string_descriptor
+#endif /* __FreeBSD__ */
+
+#undef HIDAPI_H__
+#include "libusb/hid.c"
+
+#undef hid_device_
+#undef hid_device
+#undef hid_device_info
+#undef hid_init
+#undef hid_exit
+#undef hid_enumerate
+#undef hid_free_enumeration
+#undef hid_open
+#undef hid_open_path
+#undef hid_write
+#undef hid_read_timeout
+#undef hid_read
+#undef hid_set_nonblocking
+#undef hid_send_feature_report
+#undef hid_get_feature_report
+#undef hid_close
+#undef hid_get_manufacturer_string
+#undef hid_get_product_string
+#undef hid_get_serial_number_string
+#undef hid_get_indexed_string
+#undef hid_error
+#undef new_hid_device
+#undef free_hid_device
+#undef input_report
+#undef return_data
+#undef make_path
+#undef read_thread
+
+#endif /* SDL_LIBUSB_DYNAMIC */
+
+/* Shared HIDAPI Implementation */
+
+#undef HIDAPI_H__
+#include "hidapi.h"
+
+struct hidapi_backend {
+#define F(x) typeof(x) *x
+    F(hid_write);
+    F(hid_read_timeout);
+    F(hid_read);
+    F(hid_set_nonblocking);
+    F(hid_send_feature_report);
+    F(hid_get_feature_report);
+    F(hid_close);
+    F(hid_get_manufacturer_string);
+    F(hid_get_product_string);
+    F(hid_get_serial_number_string);
+    F(hid_get_indexed_string);
+    F(hid_error);
+#undef F
+};
+
+#if HAVE_PLATFORM_BACKEND
+static const struct hidapi_backend PLATFORM_Backend = {
+    (void*)PLATFORM_hid_write,
+    (void*)PLATFORM_hid_read_timeout,
+    (void*)PLATFORM_hid_read,
+    (void*)PLATFORM_hid_set_nonblocking,
+    (void*)PLATFORM_hid_send_feature_report,
+    (void*)PLATFORM_hid_get_feature_report,
+    (void*)PLATFORM_hid_close,
+    (void*)PLATFORM_hid_get_manufacturer_string,
+    (void*)PLATFORM_hid_get_product_string,
+    (void*)PLATFORM_hid_get_serial_number_string,
+    (void*)PLATFORM_hid_get_indexed_string,
+    (void*)PLATFORM_hid_error
+};
+#endif /* HAVE_PLATFORM_BACKEND */
+
+#ifdef SDL_LIBUSB_DYNAMIC
+static const struct hidapi_backend LIBUSB_Backend = {
+    (void*)LIBUSB_hid_write,
+    (void*)LIBUSB_hid_read_timeout,
+    (void*)LIBUSB_hid_read,
+    (void*)LIBUSB_hid_set_nonblocking,
+    (void*)LIBUSB_hid_send_feature_report,
+    (void*)LIBUSB_hid_get_feature_report,
+    (void*)LIBUSB_hid_close,
+    (void*)LIBUSB_hid_get_manufacturer_string,
+    (void*)LIBUSB_hid_get_product_string,
+    (void*)LIBUSB_hid_get_serial_number_string,
+    (void*)LIBUSB_hid_get_indexed_string,
+    (void*)LIBUSB_hid_error
+};
+#endif /* SDL_LIBUSB_DYNAMIC */
+
+typedef struct _HIDDeviceWrapper HIDDeviceWrapper;
+struct _HIDDeviceWrapper
+{
+    hid_device *device; /* must be first field */
+    const struct hidapi_backend *backend;
+};
+
+static HIDDeviceWrapper *
+CreateHIDDeviceWrapper(hid_device *device, const struct hidapi_backend *backend)
+{
+    HIDDeviceWrapper *ret = SDL_malloc(sizeof(*ret));
+    ret->device = device;
+    ret->backend = backend;
+    return ret;
+}
+
+static hid_device *
+WrapHIDDevice(HIDDeviceWrapper *wrapper)
+{
+    return (hid_device *)wrapper;
+}
+
+static HIDDeviceWrapper *
+UnwrapHIDDevice(hid_device *device)
+{
+    return (HIDDeviceWrapper *)device;
+}
+
+static void
+DeleteHIDDeviceWrapper(HIDDeviceWrapper *device)
+{
+    SDL_free(device);
+}
+
+#define COPY_IF_EXISTS(var) \
+    if (pSrc->var != NULL) { \
+        pDst->var = SDL_strdup(pSrc->var); \
+    } else { \
+        pDst->var = NULL; \
+    }
+#define WCOPY_IF_EXISTS(var) \
+    if (pSrc->var != NULL) { \
+        pDst->var = SDL_wcsdup(pSrc->var); \
+    } else { \
+        pDst->var = NULL; \
+    }
+
+#ifdef SDL_LIBUSB_DYNAMIC
+static void
+LIBUSB_CopyHIDDeviceInfo(struct LIBUSB_hid_device_info *pSrc,
+                         struct hid_device_info *pDst)
+{
+    COPY_IF_EXISTS(path)
+    pDst->vendor_id = pSrc->vendor_id;
+    pDst->product_id = pSrc->product_id;
+    WCOPY_IF_EXISTS(serial_number)
+    pDst->release_number = pSrc->release_number;
+    WCOPY_IF_EXISTS(manufacturer_string)
+    WCOPY_IF_EXISTS(product_string)
+    pDst->usage_page = pSrc->usage_page;
+    pDst->usage = pSrc->usage;
+    pDst->interface_number = pSrc->interface_number;
+    pDst->next = NULL;
+}
+#endif /* SDL_LIBUSB_DYNAMIC */
+
+#if HAVE_PLATFORM_BACKEND
+static void
+PLATFORM_CopyHIDDeviceInfo(struct PLATFORM_hid_device_info *pSrc,
+                           struct hid_device_info *pDst)
+{
+    COPY_IF_EXISTS(path)
+    pDst->vendor_id = pSrc->vendor_id;
+    pDst->product_id = pSrc->product_id;
+    WCOPY_IF_EXISTS(serial_number)
+    pDst->release_number = pSrc->release_number;
+    WCOPY_IF_EXISTS(manufacturer_string)
+    WCOPY_IF_EXISTS(product_string)
+    pDst->usage_page = pSrc->usage_page;
+    pDst->usage = pSrc->usage;
+    pDst->interface_number = pSrc->interface_number;
+    pDst->next = NULL;
+}
+#endif /* HAVE_PLATFORM_BACKEND */
+
+#undef COPY_IF_EXISTS
+#undef WCOPY_IF_EXISTS
+
+static SDL_bool SDL_hidapi_wasinit = SDL_FALSE;
+
+int HID_API_EXPORT HID_API_CALL hid_init(void)
+{
+    int err;
+
+    if (SDL_hidapi_wasinit == SDL_TRUE) {
+        return 0;
+    }
+
+#ifdef SDL_LIBUSB_DYNAMIC
+    libusb_ctx.libhandle = SDL_LoadObject(SDL_LIBUSB_DYNAMIC);
+    if (libusb_ctx.libhandle != NULL) {
+        #define LOAD_LIBUSB_SYMBOL(func) \
+            libusb_ctx.func = SDL_LoadFunction(libusb_ctx.libhandle, "libusb_" #func);
+        LOAD_LIBUSB_SYMBOL(init)
+        LOAD_LIBUSB_SYMBOL(exit)
+        LOAD_LIBUSB_SYMBOL(get_device_list)
+        LOAD_LIBUSB_SYMBOL(free_device_list)
+        LOAD_LIBUSB_SYMBOL(get_device_descriptor)
+        LOAD_LIBUSB_SYMBOL(get_active_config_descriptor)
+        LOAD_LIBUSB_SYMBOL(get_config_descriptor)
+        LOAD_LIBUSB_SYMBOL(free_config_descriptor)
+        LOAD_LIBUSB_SYMBOL(get_bus_number)
+        LOAD_LIBUSB_SYMBOL(get_device_address)
+        LOAD_LIBUSB_SYMBOL(open)
+        LOAD_LIBUSB_SYMBOL(close)
+        LOAD_LIBUSB_SYMBOL(claim_interface)
+        LOAD_LIBUSB_SYMBOL(release_interface)
+        LOAD_LIBUSB_SYMBOL(kernel_driver_active)
+        LOAD_LIBUSB_SYMBOL(detach_kernel_driver)
+        LOAD_LIBUSB_SYMBOL(alloc_transfer)
+        LOAD_LIBUSB_SYMBOL(submit_transfer)
+        LOAD_LIBUSB_SYMBOL(cancel_transfer)
+        LOAD_LIBUSB_SYMBOL(free_transfer)
+        LOAD_LIBUSB_SYMBOL(control_transfer)
+        LOAD_LIBUSB_SYMBOL(interrupt_transfer)
+        LOAD_LIBUSB_SYMBOL(handle_events)
+        LOAD_LIBUSB_SYMBOL(handle_events_completed)
+        #undef LOAD_LIBUSB_SYMBOL
+
+        if ((err = LIBUSB_hid_init()) < 0) {
+            SDL_UnloadObject(libusb_ctx.libhandle);
+            return err;
+        }
+    }
+#endif /* SDL_LIBUSB_DYNAMIC */
+
+#if HAVE_PLATFORM_BACKEND
+#if __LINUX__
+    udev_ctx = SDL_UDEV_GetUdevSyms();
+#endif /* __LINUX __ */
+    if (udev_ctx && (err = PLATFORM_hid_init()) < 0) {
+#ifdef SDL_LIBUSB_DYNAMIC
+        if (libusb_ctx.libhandle) {
+            SDL_UnloadObject(libusb_ctx.libhandle);
+        }
+#endif /* SDL_LIBUSB_DYNAMIC */
+        return err;
+    }
+#endif /* HAVE_PLATFORM_BACKEND */
+
+    return 0;
+}
+
+int HID_API_EXPORT HID_API_CALL hid_exit(void)
+{
+    int err = 0;
+
+    if (SDL_hidapi_wasinit == SDL_FALSE) {
+        return 0;
+    }
+
+#if HAVE_PLATFORM_BACKEND
+    if (udev_ctx) {
+        err = PLATFORM_hid_exit();
+    }
+#endif /* HAVE_PLATFORM_BACKEND */
+#ifdef SDL_LIBUSB_DYNAMIC
+    if (libusb_ctx.libhandle) {
+        err |= LIBUSB_hid_exit(); /* Ehhhhh */
+        SDL_UnloadObject(libusb_ctx.libhandle);
+    }
+#endif /* SDL_LIBUSB_DYNAMIC */
+    return err;
+}
+
+struct hid_device_info HID_API_EXPORT * HID_API_CALL hid_enumerate(unsigned short vendor_id, unsigned short product_id)
+{
+#if HAVE_PLATFORM_BACKEND
+    struct PLATFORM_hid_device_info *raw_devs = NULL;
+    struct PLATFORM_hid_device_info *raw_dev;
+#endif /* HAVE_PLATFORM_BACKEND */
+    struct hid_device_info *devs = NULL, *last = NULL, *new_dev;
+    SDL_bool bFound;
+
+    if (SDL_hidapi_wasinit == SDL_FALSE) {
+        hid_init();
+    }
+
+#if HAVE_PLATFORM_BACKEND
+    if (udev_ctx) {
+        raw_devs = PLATFORM_hid_enumerate(vendor_id, product_id);
+    }
+#endif /* HAVE_PLATFORM_BACKEND */
+
+#ifdef SDL_LIBUSB_DYNAMIC
+    if (libusb_ctx.libhandle) {
+        struct LIBUSB_hid_device_info *usb_devs = LIBUSB_hid_enumerate(vendor_id, product_id);
+        struct LIBUSB_hid_device_info *usb_dev;
+        for (usb_dev = usb_devs; usb_dev; usb_dev = usb_dev->next) {
+            bFound = SDL_FALSE;
+#if HAVE_PLATFORM_BACKEND
+            for (raw_dev = raw_devs; raw_dev; raw_dev = raw_dev->next) {
+                if (usb_dev->vendor_id == raw_dev->vendor_id &&
+                    usb_dev->product_id == raw_dev->product_id) {
+
+                    bFound = SDL_TRUE;
+                    break;
+                }
+            }
+#endif
+
+            if (!bFound) {
+                new_dev = (struct hid_device_info*) SDL_malloc(sizeof(struct hid_device_info));
+                LIBUSB_CopyHIDDeviceInfo(usb_dev, new_dev);
+
+                if (last != NULL) {
+                    last->next = new_dev;
+                } else {
+                    devs = new_dev;
+                }
+                last = new_dev;
+            }
+        }
+        LIBUSB_hid_free_enumeration(usb_devs);
+    }
+#endif /* SDL_LIBUSB_DYNAMIC */
+
+#if HAVE_PLATFORM_BACKEND
+    if (udev_ctx) {
+        for (raw_dev = raw_devs; raw_dev; raw_dev = raw_dev->next) {
+            new_dev = (struct hid_device_info*) SDL_malloc(sizeof(struct hid_device_info));
+            PLATFORM_CopyHIDDeviceInfo(raw_dev, new_dev);
+            new_dev->next = NULL;
+
+            if (last != NULL) {
+                last->next = new_dev;
+            } else {
+                devs = new_dev;
+            }
+            last = new_dev;
+        }
+        PLATFORM_hid_free_enumeration(raw_devs);
+    }
+#endif /* HAVE_PLATFORM_BACKEND */
+
+    return devs;
+}
+
+void  HID_API_EXPORT HID_API_CALL hid_free_enumeration(struct hid_device_info *devs)
+{
+    while (devs) {
+        struct hid_device_info *next = devs->next;
+        SDL_free(devs->path);
+        SDL_free(devs->serial_number);
+        SDL_free(devs->manufacturer_string);
+        SDL_free(devs->product_string);
+        SDL_free(devs);
+        devs = next;
+    }
+}
+
+HID_API_EXPORT hid_device * HID_API_CALL hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
+{
+    hid_device *pDevice = NULL;
+
+    if (SDL_hidapi_wasinit == SDL_FALSE) {
+        hid_init();
+    }
+
+#if HAVE_PLATFORM_BACKEND
+    if (udev_ctx &&
+        (pDevice = (hid_device*) PLATFORM_hid_open(vendor_id, product_id, serial_number)) != NULL) {
+
+        HIDDeviceWrapper *wrapper = CreateHIDDeviceWrapper(pDevice, &PLATFORM_Backend);
+        return WrapHIDDevice(wrapper);
+    }
+#endif /* HAVE_PLATFORM_BACKEND */
+#ifdef SDL_LIBUSB_DYNAMIC
+    if (libusb_ctx.libhandle &&
+        (pDevice = (hid_device*) LIBUSB_hid_open(vendor_id, product_id, serial_number)) != NULL) {
+
+        HIDDeviceWrapper *wrapper = CreateHIDDeviceWrapper(pDevice, &LIBUSB_Backend);
+        return WrapHIDDevice(wrapper);
+    }
+#endif /* SDL_LIBUSB_DYNAMIC */
+    return NULL;
+}
+
+HID_API_EXPORT hid_device * HID_API_CALL hid_open_path(const char *path, int bExclusive /* = false */)
+{
+    hid_device *pDevice = NULL;
+
+    if (SDL_hidapi_wasinit == SDL_FALSE) {
+        hid_init();
+    }
+
+#if HAVE_PLATFORM_BACKEND
+    if (udev_ctx &&
+        (pDevice = (hid_device*) PLATFORM_hid_open_path(path, bExclusive)) != NULL) {
+
+        HIDDeviceWrapper *wrapper = CreateHIDDeviceWrapper(pDevice, &PLATFORM_Backend);
+        return WrapHIDDevice(wrapper);
+    }
+#endif /* HAVE_PLATFORM_BACKEND */
+#ifdef SDL_LIBUSB_DYNAMIC
+    if (libusb_ctx.libhandle &&
+        (pDevice = (hid_device*) LIBUSB_hid_open_path(path, bExclusive)) != NULL) {
+
+        HIDDeviceWrapper *wrapper = CreateHIDDeviceWrapper(pDevice, &LIBUSB_Backend);
+        return WrapHIDDevice(wrapper);
+    }
+#endif /* SDL_LIBUSB_DYNAMIC */
+    return NULL;
+}
+
+int  HID_API_EXPORT HID_API_CALL hid_write(hid_device *device, const unsigned char *data, size_t length)
+{
+    HIDDeviceWrapper *wrapper = UnwrapHIDDevice(device);
+    return wrapper->backend->hid_write(wrapper->device, data, length);
+}
+
+int HID_API_EXPORT HID_API_CALL hid_read_timeout(hid_device *device, unsigned char *data, size_t length, int milliseconds)
+{
+    HIDDeviceWrapper *wrapper = UnwrapHIDDevice(device);
+    return wrapper->backend->hid_read_timeout(wrapper->device, data, length, milliseconds);
+}
+
+int  HID_API_EXPORT HID_API_CALL hid_read(hid_device *device, unsigned char *data, size_t length)
+{
+    HIDDeviceWrapper *wrapper = UnwrapHIDDevice(device);
+    return wrapper->backend->hid_read(wrapper->device, data, length);
+}
+
+int  HID_API_EXPORT HID_API_CALL hid_set_nonblocking(hid_device *device, int nonblock)
+{
+    HIDDeviceWrapper *wrapper = UnwrapHIDDevice(device);
+    return wrapper->backend->hid_set_nonblocking(wrapper->device, nonblock);
+}
+
+int HID_API_EXPORT HID_API_CALL hid_send_feature_report(hid_device *device, const unsigned char *data, size_t length)
+{
+    HIDDeviceWrapper *wrapper = UnwrapHIDDevice(device);
+    return wrapper->backend->hid_send_feature_report(wrapper->device, data, length);
+}
+
+int HID_API_EXPORT HID_API_CALL hid_get_feature_report(hid_device *device, unsigned char *data, size_t length)
+{
+    HIDDeviceWrapper *wrapper = UnwrapHIDDevice(device);
+    return wrapper->backend->hid_get_feature_report(wrapper->device, data, length);
+}
+
+void HID_API_EXPORT HID_API_CALL hid_close(hid_device *device)
+{
+    HIDDeviceWrapper *wrapper = UnwrapHIDDevice(device);
+    wrapper->backend->hid_close(wrapper->device);
+    DeleteHIDDeviceWrapper(wrapper);
+}
+
+int HID_API_EXPORT_CALL hid_get_manufacturer_string(hid_device *device, wchar_t *string, size_t maxlen)
+{
+    HIDDeviceWrapper *wrapper = UnwrapHIDDevice(device);
+    return wrapper->backend->hid_get_manufacturer_string(wrapper->device, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_product_string(hid_device *device, wchar_t *string, size_t maxlen)
+{
+    HIDDeviceWrapper *wrapper = UnwrapHIDDevice(device);
+    return wrapper->backend->hid_get_product_string(wrapper->device, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_serial_number_string(hid_device *device, wchar_t *string, size_t maxlen)
+{
+    HIDDeviceWrapper *wrapper = UnwrapHIDDevice(device);
+    return wrapper->backend->hid_get_serial_number_string(wrapper->device, string, maxlen);
+}
+
+int HID_API_EXPORT_CALL hid_get_indexed_string(hid_device *device, int string_index, wchar_t *string, size_t maxlen)
+{
+    HIDDeviceWrapper *wrapper = UnwrapHIDDevice(device);
+    return wrapper->backend->hid_get_indexed_string(wrapper->device, string_index, string, maxlen);
+}
+
+HID_API_EXPORT const wchar_t* HID_API_CALL hid_error(hid_device *device)
+{
+    HIDDeviceWrapper *wrapper = UnwrapHIDDevice(device);
+    return wrapper->backend->hid_error(wrapper->device);
+}
+
+#endif /* SDL_JOYSTICK_HIDAPI */

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