diff --git a/.hgtags b/.hgtags
index 461cbbbaa8..c39f995761 100644
--- a/.hgtags
+++ b/.hgtags
@@ -30,3 +30,4 @@ f285b9487756ff681f76c85644222c03a7bfa1c7 release-2.0.3
704a0bfecf754e4e1383f83c7d5118b00cae26ea release-2.0.3
e12c387305129c847b3928a123300b113782fe3f release-2.0.4
007dfe83abf81b1ff5df40186f65e8e64987b825 release-2.0.5
+8df7a59b55283aa09889522369a2b32674c048de release-2.0.6
diff --git a/Android.mk b/Android.mk
index 5c362ceba4..d593d68d28 100755
--- a/Android.mk
+++ b/Android.mk
@@ -31,6 +31,7 @@ LOCAL_SRC_FILES := \
$(wildcard $(LOCAL_PATH)/src/haptic/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/joystick/*.c) \
$(wildcard $(LOCAL_PATH)/src/joystick/android/*.c) \
+ $(LOCAL_PATH)/src/joystick/steam/SDL_steamcontroller.c \
$(wildcard $(LOCAL_PATH)/src/loadso/dlopen/*.c) \
$(wildcard $(LOCAL_PATH)/src/power/*.c) \
$(wildcard $(LOCAL_PATH)/src/power/android/*.c) \
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8a5e592a49..73d94077fb 100644
--- a/CMakeLists.txt
+++ b/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 6)
+set(SDL_MICRO_VERSION 7)
set(SDL_INTERFACE_AGE 0)
-set(SDL_BINARY_AGE 6)
+set(SDL_BINARY_AGE 7)
set(SDL_VERSION "${SDL_MAJOR_VERSION}.${SDL_MINOR_VERSION}.${SDL_MICRO_VERSION}")
# Set defaults preventing destination file conflicts
@@ -653,7 +653,7 @@ if(LIBC)
check_include_file(sys/types.h HAVE_SYS_TYPES_H)
foreach(_HEADER
stdio.h stdlib.h stddef.h stdarg.h malloc.h memory.h string.h limits.h
- strings.h wchar.h inttypes.h stdint.h ctype.h math.h iconv.h signal.h)
+ strings.h wchar.h inttypes.h stdint.h ctype.h math.h iconv.h signal.h libunwind.h)
string(TOUPPER "HAVE_${_HEADER}" _UPPER)
string(REPLACE "." "_" _HAVE_H ${_UPPER})
check_include_file("${_HEADER}" ${_HAVE_H})
@@ -669,7 +669,7 @@ if(LIBC)
foreach(_FN
strtod malloc calloc realloc free getenv setenv putenv unsetenv
qsort abs bcopy memset memcpy memmove memcmp strlen strlcpy strlcat
- strdup _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa
+ _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa
_uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull
atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp
vsscanf vsnprintf fopen64 fseeko fseeko64 sigaction setjmp
@@ -816,7 +816,7 @@ if(ANDROID)
endif()
if(SDL_JOYSTICK)
set(SDL_JOYSTICK_ANDROID 1)
- file(GLOB ANDROID_JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/android/*.c)
+ 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})
set(HAVE_SDL_JOYSTICK TRUE)
endif()
@@ -1055,7 +1055,7 @@ elseif(UNIX AND NOT APPLE AND NOT ANDROID)
CheckUSBHID() # seems to be BSD specific - limit the test to BSD only?
if(LINUX AND NOT ANDROID)
set(SDL_JOYSTICK_LINUX 1)
- file(GLOB JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/linux/*.c)
+ file(GLOB JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/linux/*.c ${SDL2_SOURCE_DIR}/src/joystick/steam/*.c)
set(SOURCE_FILES ${SOURCE_FILES} ${JOYSTICK_SOURCES})
set(HAVE_SDL_JOYSTICK TRUE)
endif()
@@ -1352,7 +1352,7 @@ elseif(APPLE)
# !!! FIXME: we need Carbon for some very old API calls in
# !!! FIXME: src/video/cocoa/SDL_cocoakeyboard.c, but we should figure out
# !!! FIXME: how to dump those.
- if (APPLE AND NOT IOS)
+ if(NOT IOS)
set(SDL_FRAMEWORK_COCOA 1)
set(SDL_FRAMEWORK_CARBON 1)
endif()
@@ -1373,6 +1373,8 @@ elseif(APPLE)
if(SDL_AUDIO)
set(SDL_AUDIO_DRIVER_COREAUDIO 1)
file(GLOB AUDIO_SOURCES ${SDL2_SOURCE_DIR}/src/audio/coreaudio/*.m)
+ # !!! FIXME: modern CMake doesn't need "LANGUAGE C" for Objective-C.
+ set_source_files_properties(${AUDIO_SOURCES} PROPERTIES LANGUAGE C)
set(SOURCE_FILES ${SOURCE_FILES} ${AUDIO_SOURCES})
set(HAVE_SDL_AUDIO TRUE)
set(SDL_FRAMEWORK_COREAUDIO 1)
@@ -1382,7 +1384,7 @@ elseif(APPLE)
if(SDL_JOYSTICK)
set(SDL_JOYSTICK_IOKIT 1)
if (IOS)
- file(GLOB JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/iphoneos/*.m)
+ file(GLOB JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/iphoneos/*.m ${SDL2_SOURCE_DIR}/src/joystick/steam/*.c)
else()
file(GLOB JOYSTICK_SOURCES ${SDL2_SOURCE_DIR}/src/joystick/darwin/*.c)
endif()
@@ -1767,7 +1769,7 @@ install(EXPORT SDL2Targets
)
install(
FILES
- ${CMAKE_SOURCE_DIR}/SDL2Config.cmake
+ ${CMAKE_CURRENT_SOURCE_DIR}/SDL2Config.cmake
${CMAKE_BINARY_DIR}/SDL2ConfigVersion.cmake
DESTINATION ${PKG_PREFIX}
COMPONENT Devel
@@ -1808,10 +1810,12 @@ endif()
##### Uninstall target #####
-configure_file(
- "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
- "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
- IMMEDIATE @ONLY)
+if(NOT TARGET uninstall)
+ configure_file(
+ "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
+ "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
+ IMMEDIATE @ONLY)
-add_custom_target(uninstall
- COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
+ add_custom_target(uninstall
+ COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
+endif()
diff --git a/VisualC-WinRT/UWP_VS2015/SDL-UWP.sln b/VisualC-WinRT/UWP_VS2015/SDL-UWP.sln
new file mode 100644
index 0000000000..0a786e7d83
--- /dev/null
+++ b/VisualC-WinRT/UWP_VS2015/SDL-UWP.sln
@@ -0,0 +1,34 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 14
+VisualStudioVersion = 14.0.25420.1
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDL2-UWP", "SDL-UWP.vcxproj", "{89E9B32E-A86A-47C3-A948-D2B1622925CE}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|ARM = Release|ARM
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {89E9B32E-A86A-47C3-A948-D2B1622925CE}.Debug|ARM.ActiveCfg = Debug|ARM
+ {89E9B32E-A86A-47C3-A948-D2B1622925CE}.Debug|ARM.Build.0 = Debug|ARM
+ {89E9B32E-A86A-47C3-A948-D2B1622925CE}.Debug|x64.ActiveCfg = Debug|x64
+ {89E9B32E-A86A-47C3-A948-D2B1622925CE}.Debug|x64.Build.0 = Debug|x64
+ {89E9B32E-A86A-47C3-A948-D2B1622925CE}.Debug|x86.ActiveCfg = Debug|Win32
+ {89E9B32E-A86A-47C3-A948-D2B1622925CE}.Debug|x86.Build.0 = Debug|Win32
+ {89E9B32E-A86A-47C3-A948-D2B1622925CE}.Release|ARM.ActiveCfg = Release|ARM
+ {89E9B32E-A86A-47C3-A948-D2B1622925CE}.Release|ARM.Build.0 = Release|ARM
+ {89E9B32E-A86A-47C3-A948-D2B1622925CE}.Release|x64.ActiveCfg = Release|x64
+ {89E9B32E-A86A-47C3-A948-D2B1622925CE}.Release|x64.Build.0 = Release|x64
+ {89E9B32E-A86A-47C3-A948-D2B1622925CE}.Release|x86.ActiveCfg = Release|Win32
+ {89E9B32E-A86A-47C3-A948-D2B1622925CE}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/VisualC-WinRT/WinPhone80_VS2012/SDL-WinPhone80.sln b/VisualC-WinRT/WinPhone80_VS2012/SDL-WinPhone80.sln
new file mode 100644
index 0000000000..f5090305c9
--- /dev/null
+++ b/VisualC-WinRT/WinPhone80_VS2012/SDL-WinPhone80.sln
@@ -0,0 +1,26 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2012
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDL2-WinPhone80", "SDL-WinPhone80.vcxproj", "{33048AF1-031A-4CE6-B61E-FAD2DB832E9E}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|Win32 = Debug|Win32
+ Release|ARM = Release|ARM
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {33048AF1-031A-4CE6-B61E-FAD2DB832E9E}.Debug|ARM.ActiveCfg = Debug|ARM
+ {33048AF1-031A-4CE6-B61E-FAD2DB832E9E}.Debug|ARM.Build.0 = Debug|ARM
+ {33048AF1-031A-4CE6-B61E-FAD2DB832E9E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {33048AF1-031A-4CE6-B61E-FAD2DB832E9E}.Debug|Win32.Build.0 = Debug|Win32
+ {33048AF1-031A-4CE6-B61E-FAD2DB832E9E}.Release|ARM.ActiveCfg = Release|ARM
+ {33048AF1-031A-4CE6-B61E-FAD2DB832E9E}.Release|ARM.Build.0 = Release|ARM
+ {33048AF1-031A-4CE6-B61E-FAD2DB832E9E}.Release|Win32.ActiveCfg = Release|Win32
+ {33048AF1-031A-4CE6-B61E-FAD2DB832E9E}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/VisualC-WinRT/WinPhone81_VS2013/SDL-WinPhone81.sln b/VisualC-WinRT/WinPhone81_VS2013/SDL-WinPhone81.sln
new file mode 100644
index 0000000000..1d8347489d
--- /dev/null
+++ b/VisualC-WinRT/WinPhone81_VS2013/SDL-WinPhone81.sln
@@ -0,0 +1,28 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.40629.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDL2-WinPhone81", "SDL-WinPhone81.vcxproj", "{48FADC0E-964D-4DAB-BCED-372E0AD19577}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|Win32 = Debug|Win32
+ Release|ARM = Release|ARM
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {48FADC0E-964D-4DAB-BCED-372E0AD19577}.Debug|ARM.ActiveCfg = Debug|ARM
+ {48FADC0E-964D-4DAB-BCED-372E0AD19577}.Debug|ARM.Build.0 = Debug|ARM
+ {48FADC0E-964D-4DAB-BCED-372E0AD19577}.Debug|Win32.ActiveCfg = Debug|Win32
+ {48FADC0E-964D-4DAB-BCED-372E0AD19577}.Debug|Win32.Build.0 = Debug|Win32
+ {48FADC0E-964D-4DAB-BCED-372E0AD19577}.Release|ARM.ActiveCfg = Release|ARM
+ {48FADC0E-964D-4DAB-BCED-372E0AD19577}.Release|ARM.Build.0 = Release|ARM
+ {48FADC0E-964D-4DAB-BCED-372E0AD19577}.Release|Win32.ActiveCfg = Release|Win32
+ {48FADC0E-964D-4DAB-BCED-372E0AD19577}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/VisualC-WinRT/WinRT81_VS2013/SDL-WinRT81.sln b/VisualC-WinRT/WinRT81_VS2013/SDL-WinRT81.sln
new file mode 100644
index 0000000000..be543c931a
--- /dev/null
+++ b/VisualC-WinRT/WinRT81_VS2013/SDL-WinRT81.sln
@@ -0,0 +1,34 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 2013
+VisualStudioVersion = 12.0.40629.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDL2-WinRT81", "SDL-WinRT81.vcxproj", "{C8DF6173-06A1-4F56-A9BC-2002596B30E9}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|ARM = Debug|ARM
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|ARM = Release|ARM
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {C8DF6173-06A1-4F56-A9BC-2002596B30E9}.Debug|ARM.ActiveCfg = Debug|ARM
+ {C8DF6173-06A1-4F56-A9BC-2002596B30E9}.Debug|ARM.Build.0 = Debug|ARM
+ {C8DF6173-06A1-4F56-A9BC-2002596B30E9}.Debug|Win32.ActiveCfg = Debug|Win32
+ {C8DF6173-06A1-4F56-A9BC-2002596B30E9}.Debug|Win32.Build.0 = Debug|Win32
+ {C8DF6173-06A1-4F56-A9BC-2002596B30E9}.Debug|x64.ActiveCfg = Debug|x64
+ {C8DF6173-06A1-4F56-A9BC-2002596B30E9}.Debug|x64.Build.0 = Debug|x64
+ {C8DF6173-06A1-4F56-A9BC-2002596B30E9}.Release|ARM.ActiveCfg = Release|ARM
+ {C8DF6173-06A1-4F56-A9BC-2002596B30E9}.Release|ARM.Build.0 = Release|ARM
+ {C8DF6173-06A1-4F56-A9BC-2002596B30E9}.Release|Win32.ActiveCfg = Release|Win32
+ {C8DF6173-06A1-4F56-A9BC-2002596B30E9}.Release|Win32.Build.0 = Release|Win32
+ {C8DF6173-06A1-4F56-A9BC-2002596B30E9}.Release|x64.ActiveCfg = Release|x64
+ {C8DF6173-06A1-4F56-A9BC-2002596B30E9}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/VisualC/SDL/SDL_VS2008.vcproj b/VisualC/SDL/SDL_VS2008.vcproj
deleted file mode 100644
index e4ecdc0c17..0000000000
--- a/VisualC/SDL/SDL_VS2008.vcproj
+++ /dev/null
@@ -1,1543 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/SDL_VS2008.sln b/VisualC/SDL_VS2008.sln
deleted file mode 100644
index 83c3ccf779..0000000000
--- a/VisualC/SDL_VS2008.sln
+++ /dev/null
@@ -1,280 +0,0 @@
-Microsoft Visual Studio Solution File, Format Version 10.00
-# Visual Studio 2008
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDL2", "SDL\SDL_VS2008.vcproj", "{81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDL2main", "SDLmain\SDLmain_VS2008.vcproj", "{DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "checkkeys", "tests\checkkeys\checkkeys_VS2008.vcproj", "{26828762-C95D-4637-9CB1-7F0979523813}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "loopwave", "tests\loopwave\loopwave_VS2008.vcproj", "{AAAD1CB5-7ADA-47AE-85A0-08A6EC48FAFB}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testatomic", "tests\testatomic\testatomic_VS2008.vcproj", "{66B32F7E-5716-48D0-B5B9-D832FD052DD5}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testautomation", "tests\testautomation\testautomation_VS2008.vcproj", "{9C7E8C03-3130-436D-A97E-E8F8ED1AC4EA}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testdraw2", "tests\testdraw2\testdraw2_VS2008.vcproj", "{8682FE1E-0CF6-4EDD-9BB5-1733D8C8B4DF}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testfile", "tests\testfile\testfile_VS2008.vcproj", "{CAE4F1D0-314F-4B10-805B-0EFD670133A0}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testgesture", "tests\testgesture\testgesture_VS2008.vcproj", "{79CEE57E-1BC3-4FF6-90B3-9E39763CDAFF}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testgl2", "tests\testgl2\testgl2_VS2008.vcproj", "{8B5CFB38-CCBA-40A8-AD7A-89C57B070884}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testjoystick", "tests\testjoystick\testjoystick_VS2008.vcproj", "{55812185-D13C-4022-9C81-32E0F4A08304}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testoverlay2", "tests\testoverlay2\testoverlay2_VS2008.vcproj", "{B51E0D74-F0A2-45A2-BD2A-8B7D95B8204A}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testplatform", "tests\testplatform\testplatform_VS2008.vcproj", "{26932B24-EFC6-4E3A-B277-ED653DA37968}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testpower", "tests\testpower\testpower_VS2008.vcproj", "{C4E04D18-EF76-4B42-B4C2-16A1BACDC0A3}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testrendertarget", "tests\testrendertarget\testrendertarget_VS2008.vcproj", "{2D17C1EB-1157-460E-9A99-A82BFC1F9D1E}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testrumble", "tests\testrumble\testrumble_VS2008.vcproj", "{BFF40245-E9A6-4297-A425-A554E5D767E8}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testscale", "tests\testscale\testscale_VS2008.vcproj", "{5D0930C0-7C91-4ECE-9014-7B7DDE9502E6}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testshape", "tests\testshape\testshape_VS2008.vcproj", "{31A3E4E1-AAE9-4EF3-9B23-18D0924BE4D2}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testsprite2", "tests\testsprite2\testsprite2_VS2008.vcproj", "{40FB7794-D3C3-4CFE-BCF4-A80C96635682}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDL2test", "SDLtest\SDLtest_VS2008.vcproj", "{DA956FD3-E143-46F2-9FE5-C77BEBC56B1A}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testgamecontroller", "tests\testgamecontroller\testgamecontroller_VS2008.vcproj", "{55812185-D13C-4022-9C81-32E0F4A08305}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testgles2", "tests\testgles2\testgles2_VS2008.vcproj", "{E9558DFE-1961-4DD4-B09B-DD0EEFD5C315}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "controllermap", "tests\controllermap\controllermap_VS2008.vcproj", "{55812185-D13C-4022-9C81-32E0F4A08306}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{D69D5741-611F-4E14-8541-1FEE94F50B5A}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testvulkan", "tests\testvulkan\testvulkan_VS2008.vcproj", "{0D604DFD-AAB6-442C-9368-F91A344146AB}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Win32 = Debug|Win32
- Debug|x64 = Debug|x64
- Release|Win32 = Release|Win32
- Release|x64 = Release|x64
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Debug|Win32.ActiveCfg = Debug|Win32
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Debug|Win32.Build.0 = Debug|Win32
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Debug|x64.ActiveCfg = Debug|x64
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Debug|x64.Build.0 = Debug|x64
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Release|Win32.ActiveCfg = Release|Win32
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Release|Win32.Build.0 = Release|Win32
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Release|x64.ActiveCfg = Release|x64
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Release|x64.Build.0 = Release|x64
- {DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}.Debug|Win32.ActiveCfg = Debug|Win32
- {DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}.Debug|Win32.Build.0 = Debug|Win32
- {DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}.Debug|x64.ActiveCfg = Debug|x64
- {DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}.Debug|x64.Build.0 = Debug|x64
- {DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}.Release|Win32.ActiveCfg = Release|Win32
- {DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}.Release|Win32.Build.0 = Release|Win32
- {DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}.Release|x64.ActiveCfg = Release|x64
- {DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}.Release|x64.Build.0 = Release|x64
- {26828762-C95D-4637-9CB1-7F0979523813}.Debug|Win32.ActiveCfg = Debug|Win32
- {26828762-C95D-4637-9CB1-7F0979523813}.Debug|Win32.Build.0 = Debug|Win32
- {26828762-C95D-4637-9CB1-7F0979523813}.Debug|x64.ActiveCfg = Debug|x64
- {26828762-C95D-4637-9CB1-7F0979523813}.Debug|x64.Build.0 = Debug|x64
- {26828762-C95D-4637-9CB1-7F0979523813}.Release|Win32.ActiveCfg = Release|Win32
- {26828762-C95D-4637-9CB1-7F0979523813}.Release|Win32.Build.0 = Release|Win32
- {26828762-C95D-4637-9CB1-7F0979523813}.Release|x64.ActiveCfg = Release|x64
- {26828762-C95D-4637-9CB1-7F0979523813}.Release|x64.Build.0 = Release|x64
- {AAAD1CB5-7ADA-47AE-85A0-08A6EC48FAFB}.Debug|Win32.ActiveCfg = Debug|Win32
- {AAAD1CB5-7ADA-47AE-85A0-08A6EC48FAFB}.Debug|Win32.Build.0 = Debug|Win32
- {AAAD1CB5-7ADA-47AE-85A0-08A6EC48FAFB}.Debug|x64.ActiveCfg = Debug|x64
- {AAAD1CB5-7ADA-47AE-85A0-08A6EC48FAFB}.Debug|x64.Build.0 = Debug|x64
- {AAAD1CB5-7ADA-47AE-85A0-08A6EC48FAFB}.Release|Win32.ActiveCfg = Release|Win32
- {AAAD1CB5-7ADA-47AE-85A0-08A6EC48FAFB}.Release|Win32.Build.0 = Release|Win32
- {AAAD1CB5-7ADA-47AE-85A0-08A6EC48FAFB}.Release|x64.ActiveCfg = Release|x64
- {AAAD1CB5-7ADA-47AE-85A0-08A6EC48FAFB}.Release|x64.Build.0 = Release|x64
- {66B32F7E-5716-48D0-B5B9-D832FD052DD5}.Debug|Win32.ActiveCfg = Debug|Win32
- {66B32F7E-5716-48D0-B5B9-D832FD052DD5}.Debug|Win32.Build.0 = Debug|Win32
- {66B32F7E-5716-48D0-B5B9-D832FD052DD5}.Debug|x64.ActiveCfg = Debug|x64
- {66B32F7E-5716-48D0-B5B9-D832FD052DD5}.Debug|x64.Build.0 = Debug|x64
- {66B32F7E-5716-48D0-B5B9-D832FD052DD5}.Release|Win32.ActiveCfg = Release|Win32
- {66B32F7E-5716-48D0-B5B9-D832FD052DD5}.Release|Win32.Build.0 = Release|Win32
- {66B32F7E-5716-48D0-B5B9-D832FD052DD5}.Release|x64.ActiveCfg = Release|x64
- {66B32F7E-5716-48D0-B5B9-D832FD052DD5}.Release|x64.Build.0 = Release|x64
- {9C7E8C03-3130-436D-A97E-E8F8ED1AC4EA}.Debug|Win32.ActiveCfg = Debug|Win32
- {9C7E8C03-3130-436D-A97E-E8F8ED1AC4EA}.Debug|Win32.Build.0 = Debug|Win32
- {9C7E8C03-3130-436D-A97E-E8F8ED1AC4EA}.Debug|x64.ActiveCfg = Debug|x64
- {9C7E8C03-3130-436D-A97E-E8F8ED1AC4EA}.Debug|x64.Build.0 = Debug|x64
- {9C7E8C03-3130-436D-A97E-E8F8ED1AC4EA}.Release|Win32.ActiveCfg = Release|Win32
- {9C7E8C03-3130-436D-A97E-E8F8ED1AC4EA}.Release|Win32.Build.0 = Release|Win32
- {9C7E8C03-3130-436D-A97E-E8F8ED1AC4EA}.Release|x64.ActiveCfg = Release|x64
- {9C7E8C03-3130-436D-A97E-E8F8ED1AC4EA}.Release|x64.Build.0 = Release|x64
- {8682FE1E-0CF6-4EDD-9BB5-1733D8C8B4DF}.Debug|Win32.ActiveCfg = Debug|Win32
- {8682FE1E-0CF6-4EDD-9BB5-1733D8C8B4DF}.Debug|Win32.Build.0 = Debug|Win32
- {8682FE1E-0CF6-4EDD-9BB5-1733D8C8B4DF}.Debug|x64.ActiveCfg = Debug|x64
- {8682FE1E-0CF6-4EDD-9BB5-1733D8C8B4DF}.Debug|x64.Build.0 = Debug|x64
- {8682FE1E-0CF6-4EDD-9BB5-1733D8C8B4DF}.Release|Win32.ActiveCfg = Release|Win32
- {8682FE1E-0CF6-4EDD-9BB5-1733D8C8B4DF}.Release|Win32.Build.0 = Release|Win32
- {8682FE1E-0CF6-4EDD-9BB5-1733D8C8B4DF}.Release|x64.ActiveCfg = Release|x64
- {8682FE1E-0CF6-4EDD-9BB5-1733D8C8B4DF}.Release|x64.Build.0 = Release|x64
- {CAE4F1D0-314F-4B10-805B-0EFD670133A0}.Debug|Win32.ActiveCfg = Debug|Win32
- {CAE4F1D0-314F-4B10-805B-0EFD670133A0}.Debug|Win32.Build.0 = Debug|Win32
- {CAE4F1D0-314F-4B10-805B-0EFD670133A0}.Debug|x64.ActiveCfg = Debug|x64
- {CAE4F1D0-314F-4B10-805B-0EFD670133A0}.Debug|x64.Build.0 = Debug|x64
- {CAE4F1D0-314F-4B10-805B-0EFD670133A0}.Release|Win32.ActiveCfg = Release|Win32
- {CAE4F1D0-314F-4B10-805B-0EFD670133A0}.Release|Win32.Build.0 = Release|Win32
- {CAE4F1D0-314F-4B10-805B-0EFD670133A0}.Release|x64.ActiveCfg = Release|x64
- {CAE4F1D0-314F-4B10-805B-0EFD670133A0}.Release|x64.Build.0 = Release|x64
- {79CEE57E-1BC3-4FF6-90B3-9E39763CDAFF}.Debug|Win32.ActiveCfg = Debug|Win32
- {79CEE57E-1BC3-4FF6-90B3-9E39763CDAFF}.Debug|Win32.Build.0 = Debug|Win32
- {79CEE57E-1BC3-4FF6-90B3-9E39763CDAFF}.Debug|x64.ActiveCfg = Debug|x64
- {79CEE57E-1BC3-4FF6-90B3-9E39763CDAFF}.Debug|x64.Build.0 = Debug|x64
- {79CEE57E-1BC3-4FF6-90B3-9E39763CDAFF}.Release|Win32.ActiveCfg = Release|Win32
- {79CEE57E-1BC3-4FF6-90B3-9E39763CDAFF}.Release|Win32.Build.0 = Release|Win32
- {79CEE57E-1BC3-4FF6-90B3-9E39763CDAFF}.Release|x64.ActiveCfg = Release|x64
- {79CEE57E-1BC3-4FF6-90B3-9E39763CDAFF}.Release|x64.Build.0 = Release|x64
- {8B5CFB38-CCBA-40A8-AD7A-89C57B070884}.Debug|Win32.ActiveCfg = Debug|Win32
- {8B5CFB38-CCBA-40A8-AD7A-89C57B070884}.Debug|Win32.Build.0 = Debug|Win32
- {8B5CFB38-CCBA-40A8-AD7A-89C57B070884}.Debug|x64.ActiveCfg = Debug|x64
- {8B5CFB38-CCBA-40A8-AD7A-89C57B070884}.Debug|x64.Build.0 = Debug|x64
- {8B5CFB38-CCBA-40A8-AD7A-89C57B070884}.Release|Win32.ActiveCfg = Release|Win32
- {8B5CFB38-CCBA-40A8-AD7A-89C57B070884}.Release|Win32.Build.0 = Release|Win32
- {8B5CFB38-CCBA-40A8-AD7A-89C57B070884}.Release|x64.ActiveCfg = Release|x64
- {8B5CFB38-CCBA-40A8-AD7A-89C57B070884}.Release|x64.Build.0 = Release|x64
- {55812185-D13C-4022-9C81-32E0F4A08304}.Debug|Win32.ActiveCfg = Debug|Win32
- {55812185-D13C-4022-9C81-32E0F4A08304}.Debug|Win32.Build.0 = Debug|Win32
- {55812185-D13C-4022-9C81-32E0F4A08304}.Debug|x64.ActiveCfg = Debug|x64
- {55812185-D13C-4022-9C81-32E0F4A08304}.Debug|x64.Build.0 = Debug|x64
- {55812185-D13C-4022-9C81-32E0F4A08304}.Release|Win32.ActiveCfg = Release|Win32
- {55812185-D13C-4022-9C81-32E0F4A08304}.Release|Win32.Build.0 = Release|Win32
- {55812185-D13C-4022-9C81-32E0F4A08304}.Release|x64.ActiveCfg = Release|x64
- {55812185-D13C-4022-9C81-32E0F4A08304}.Release|x64.Build.0 = Release|x64
- {B51E0D74-F0A2-45A2-BD2A-8B7D95B8204A}.Debug|Win32.ActiveCfg = Debug|Win32
- {B51E0D74-F0A2-45A2-BD2A-8B7D95B8204A}.Debug|Win32.Build.0 = Debug|Win32
- {B51E0D74-F0A2-45A2-BD2A-8B7D95B8204A}.Debug|x64.ActiveCfg = Debug|x64
- {B51E0D74-F0A2-45A2-BD2A-8B7D95B8204A}.Debug|x64.Build.0 = Debug|x64
- {B51E0D74-F0A2-45A2-BD2A-8B7D95B8204A}.Release|Win32.ActiveCfg = Release|Win32
- {B51E0D74-F0A2-45A2-BD2A-8B7D95B8204A}.Release|Win32.Build.0 = Release|Win32
- {B51E0D74-F0A2-45A2-BD2A-8B7D95B8204A}.Release|x64.ActiveCfg = Release|x64
- {B51E0D74-F0A2-45A2-BD2A-8B7D95B8204A}.Release|x64.Build.0 = Release|x64
- {26932B24-EFC6-4E3A-B277-ED653DA37968}.Debug|Win32.ActiveCfg = Debug|Win32
- {26932B24-EFC6-4E3A-B277-ED653DA37968}.Debug|Win32.Build.0 = Debug|Win32
- {26932B24-EFC6-4E3A-B277-ED653DA37968}.Debug|x64.ActiveCfg = Debug|x64
- {26932B24-EFC6-4E3A-B277-ED653DA37968}.Debug|x64.Build.0 = Debug|x64
- {26932B24-EFC6-4E3A-B277-ED653DA37968}.Release|Win32.ActiveCfg = Release|Win32
- {26932B24-EFC6-4E3A-B277-ED653DA37968}.Release|Win32.Build.0 = Release|Win32
- {26932B24-EFC6-4E3A-B277-ED653DA37968}.Release|x64.ActiveCfg = Release|x64
- {26932B24-EFC6-4E3A-B277-ED653DA37968}.Release|x64.Build.0 = Release|x64
- {C4E04D18-EF76-4B42-B4C2-16A1BACDC0A3}.Debug|Win32.ActiveCfg = Debug|Win32
- {C4E04D18-EF76-4B42-B4C2-16A1BACDC0A3}.Debug|Win32.Build.0 = Debug|Win32
- {C4E04D18-EF76-4B42-B4C2-16A1BACDC0A3}.Debug|x64.ActiveCfg = Debug|x64
- {C4E04D18-EF76-4B42-B4C2-16A1BACDC0A3}.Debug|x64.Build.0 = Debug|x64
- {C4E04D18-EF76-4B42-B4C2-16A1BACDC0A3}.Release|Win32.ActiveCfg = Release|Win32
- {C4E04D18-EF76-4B42-B4C2-16A1BACDC0A3}.Release|Win32.Build.0 = Release|Win32
- {C4E04D18-EF76-4B42-B4C2-16A1BACDC0A3}.Release|x64.ActiveCfg = Release|x64
- {C4E04D18-EF76-4B42-B4C2-16A1BACDC0A3}.Release|x64.Build.0 = Release|x64
- {2D17C1EB-1157-460E-9A99-A82BFC1F9D1E}.Debug|Win32.ActiveCfg = Debug|Win32
- {2D17C1EB-1157-460E-9A99-A82BFC1F9D1E}.Debug|Win32.Build.0 = Debug|Win32
- {2D17C1EB-1157-460E-9A99-A82BFC1F9D1E}.Debug|x64.ActiveCfg = Debug|x64
- {2D17C1EB-1157-460E-9A99-A82BFC1F9D1E}.Debug|x64.Build.0 = Debug|x64
- {2D17C1EB-1157-460E-9A99-A82BFC1F9D1E}.Release|Win32.ActiveCfg = Release|Win32
- {2D17C1EB-1157-460E-9A99-A82BFC1F9D1E}.Release|Win32.Build.0 = Release|Win32
- {2D17C1EB-1157-460E-9A99-A82BFC1F9D1E}.Release|x64.ActiveCfg = Release|x64
- {2D17C1EB-1157-460E-9A99-A82BFC1F9D1E}.Release|x64.Build.0 = Release|x64
- {BFF40245-E9A6-4297-A425-A554E5D767E8}.Debug|Win32.ActiveCfg = Debug|Win32
- {BFF40245-E9A6-4297-A425-A554E5D767E8}.Debug|Win32.Build.0 = Debug|Win32
- {BFF40245-E9A6-4297-A425-A554E5D767E8}.Debug|x64.ActiveCfg = Debug|x64
- {BFF40245-E9A6-4297-A425-A554E5D767E8}.Debug|x64.Build.0 = Debug|x64
- {BFF40245-E9A6-4297-A425-A554E5D767E8}.Release|Win32.ActiveCfg = Release|Win32
- {BFF40245-E9A6-4297-A425-A554E5D767E8}.Release|Win32.Build.0 = Release|Win32
- {BFF40245-E9A6-4297-A425-A554E5D767E8}.Release|x64.ActiveCfg = Release|x64
- {BFF40245-E9A6-4297-A425-A554E5D767E8}.Release|x64.Build.0 = Release|x64
- {5D0930C0-7C91-4ECE-9014-7B7DDE9502E6}.Debug|Win32.ActiveCfg = Debug|Win32
- {5D0930C0-7C91-4ECE-9014-7B7DDE9502E6}.Debug|Win32.Build.0 = Debug|Win32
- {5D0930C0-7C91-4ECE-9014-7B7DDE9502E6}.Debug|x64.ActiveCfg = Debug|x64
- {5D0930C0-7C91-4ECE-9014-7B7DDE9502E6}.Debug|x64.Build.0 = Debug|x64
- {5D0930C0-7C91-4ECE-9014-7B7DDE9502E6}.Release|Win32.ActiveCfg = Release|Win32
- {5D0930C0-7C91-4ECE-9014-7B7DDE9502E6}.Release|Win32.Build.0 = Release|Win32
- {5D0930C0-7C91-4ECE-9014-7B7DDE9502E6}.Release|x64.ActiveCfg = Release|x64
- {5D0930C0-7C91-4ECE-9014-7B7DDE9502E6}.Release|x64.Build.0 = Release|x64
- {31A3E4E1-AAE9-4EF3-9B23-18D0924BE4D2}.Debug|Win32.ActiveCfg = Debug|Win32
- {31A3E4E1-AAE9-4EF3-9B23-18D0924BE4D2}.Debug|Win32.Build.0 = Debug|Win32
- {31A3E4E1-AAE9-4EF3-9B23-18D0924BE4D2}.Debug|x64.ActiveCfg = Debug|x64
- {31A3E4E1-AAE9-4EF3-9B23-18D0924BE4D2}.Debug|x64.Build.0 = Debug|x64
- {31A3E4E1-AAE9-4EF3-9B23-18D0924BE4D2}.Release|Win32.ActiveCfg = Release|Win32
- {31A3E4E1-AAE9-4EF3-9B23-18D0924BE4D2}.Release|Win32.Build.0 = Release|Win32
- {31A3E4E1-AAE9-4EF3-9B23-18D0924BE4D2}.Release|x64.ActiveCfg = Release|x64
- {31A3E4E1-AAE9-4EF3-9B23-18D0924BE4D2}.Release|x64.Build.0 = Release|x64
- {40FB7794-D3C3-4CFE-BCF4-A80C96635682}.Debug|Win32.ActiveCfg = Debug|Win32
- {40FB7794-D3C3-4CFE-BCF4-A80C96635682}.Debug|Win32.Build.0 = Debug|Win32
- {40FB7794-D3C3-4CFE-BCF4-A80C96635682}.Debug|x64.ActiveCfg = Debug|x64
- {40FB7794-D3C3-4CFE-BCF4-A80C96635682}.Debug|x64.Build.0 = Debug|x64
- {40FB7794-D3C3-4CFE-BCF4-A80C96635682}.Release|Win32.ActiveCfg = Release|Win32
- {40FB7794-D3C3-4CFE-BCF4-A80C96635682}.Release|Win32.Build.0 = Release|Win32
- {40FB7794-D3C3-4CFE-BCF4-A80C96635682}.Release|x64.ActiveCfg = Release|x64
- {40FB7794-D3C3-4CFE-BCF4-A80C96635682}.Release|x64.Build.0 = Release|x64
- {DA956FD3-E143-46F2-9FE5-C77BEBC56B1A}.Debug|Win32.ActiveCfg = Debug|Win32
- {DA956FD3-E143-46F2-9FE5-C77BEBC56B1A}.Debug|Win32.Build.0 = Debug|Win32
- {DA956FD3-E143-46F2-9FE5-C77BEBC56B1A}.Debug|x64.ActiveCfg = Debug|x64
- {DA956FD3-E143-46F2-9FE5-C77BEBC56B1A}.Debug|x64.Build.0 = Debug|x64
- {DA956FD3-E143-46F2-9FE5-C77BEBC56B1A}.Release|Win32.ActiveCfg = Release|Win32
- {DA956FD3-E143-46F2-9FE5-C77BEBC56B1A}.Release|Win32.Build.0 = Release|Win32
- {DA956FD3-E143-46F2-9FE5-C77BEBC56B1A}.Release|x64.ActiveCfg = Release|x64
- {DA956FD3-E143-46F2-9FE5-C77BEBC56B1A}.Release|x64.Build.0 = Release|x64
- {55812185-D13C-4022-9C81-32E0F4A08305}.Debug|Win32.ActiveCfg = Debug|Win32
- {55812185-D13C-4022-9C81-32E0F4A08305}.Debug|Win32.Build.0 = Debug|Win32
- {55812185-D13C-4022-9C81-32E0F4A08305}.Debug|x64.ActiveCfg = Debug|x64
- {55812185-D13C-4022-9C81-32E0F4A08305}.Debug|x64.Build.0 = Debug|x64
- {55812185-D13C-4022-9C81-32E0F4A08305}.Release|Win32.ActiveCfg = Release|Win32
- {55812185-D13C-4022-9C81-32E0F4A08305}.Release|Win32.Build.0 = Release|Win32
- {55812185-D13C-4022-9C81-32E0F4A08305}.Release|x64.ActiveCfg = Release|x64
- {55812185-D13C-4022-9C81-32E0F4A08305}.Release|x64.Build.0 = Release|x64
- {E9558DFE-1961-4DD4-B09B-DD0EEFD5C315}.Debug|Win32.ActiveCfg = Debug|Win32
- {E9558DFE-1961-4DD4-B09B-DD0EEFD5C315}.Debug|Win32.Build.0 = Debug|Win32
- {E9558DFE-1961-4DD4-B09B-DD0EEFD5C315}.Debug|x64.ActiveCfg = Debug|x64
- {E9558DFE-1961-4DD4-B09B-DD0EEFD5C315}.Debug|x64.Build.0 = Debug|x64
- {E9558DFE-1961-4DD4-B09B-DD0EEFD5C315}.Release|Win32.ActiveCfg = Release|Win32
- {E9558DFE-1961-4DD4-B09B-DD0EEFD5C315}.Release|Win32.Build.0 = Release|Win32
- {E9558DFE-1961-4DD4-B09B-DD0EEFD5C315}.Release|x64.ActiveCfg = Release|x64
- {E9558DFE-1961-4DD4-B09B-DD0EEFD5C315}.Release|x64.Build.0 = Release|x64
- {55812185-D13C-4022-9C81-32E0F4A08306}.Debug|Win32.ActiveCfg = Debug|Win32
- {55812185-D13C-4022-9C81-32E0F4A08306}.Debug|Win32.Build.0 = Debug|Win32
- {55812185-D13C-4022-9C81-32E0F4A08306}.Debug|x64.ActiveCfg = Debug|x64
- {55812185-D13C-4022-9C81-32E0F4A08306}.Debug|x64.Build.0 = Debug|x64
- {55812185-D13C-4022-9C81-32E0F4A08306}.Release|Win32.ActiveCfg = Release|Win32
- {55812185-D13C-4022-9C81-32E0F4A08306}.Release|Win32.Build.0 = Release|Win32
- {55812185-D13C-4022-9C81-32E0F4A08306}.Release|x64.ActiveCfg = Release|x64
- {55812185-D13C-4022-9C81-32E0F4A08306}.Release|x64.Build.0 = Release|x64
- {0D604DFD-AAB6-442C-9368-F91A344146AB}.Debug|Win32.ActiveCfg = Debug|Win32
- {0D604DFD-AAB6-442C-9368-F91A344146AB}.Debug|Win32.Build.0 = Debug|Win32
- {0D604DFD-AAB6-442C-9368-F91A344146AB}.Debug|x64.ActiveCfg = Debug|x64
- {0D604DFD-AAB6-442C-9368-F91A344146AB}.Debug|x64.Build.0 = Debug|x64
- {0D604DFD-AAB6-442C-9368-F91A344146AB}.Release|Win32.ActiveCfg = Release|Win32
- {0D604DFD-AAB6-442C-9368-F91A344146AB}.Release|Win32.Build.0 = Release|Win32
- {0D604DFD-AAB6-442C-9368-F91A344146AB}.Release|x64.ActiveCfg = Release|x64
- {0D604DFD-AAB6-442C-9368-F91A344146AB}.Release|x64.Build.0 = Release|x64
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {AAAD1CB5-7ADA-47AE-85A0-08A6EC48FAFB} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {66B32F7E-5716-48D0-B5B9-D832FD052DD5} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {9C7E8C03-3130-436D-A97E-E8F8ED1AC4EA} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {8682FE1E-0CF6-4EDD-9BB5-1733D8C8B4DF} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {CAE4F1D0-314F-4B10-805B-0EFD670133A0} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {79CEE57E-1BC3-4FF6-90B3-9E39763CDAFF} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {8B5CFB38-CCBA-40A8-AD7A-89C57B070884} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {55812185-D13C-4022-9C81-32E0F4A08304} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {B51E0D74-F0A2-45A2-BD2A-8B7D95B8204A} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {26932B24-EFC6-4E3A-B277-ED653DA37968} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {C4E04D18-EF76-4B42-B4C2-16A1BACDC0A3} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {2D17C1EB-1157-460E-9A99-A82BFC1F9D1E} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {BFF40245-E9A6-4297-A425-A554E5D767E8} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {5D0930C0-7C91-4ECE-9014-7B7DDE9502E6} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {31A3E4E1-AAE9-4EF3-9B23-18D0924BE4D2} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {40FB7794-D3C3-4CFE-BCF4-A80C96635682} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {55812185-D13C-4022-9C81-32E0F4A08305} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {E9558DFE-1961-4DD4-B09B-DD0EEFD5C315} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {55812185-D13C-4022-9C81-32E0F4A08306} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {26828762-C95D-4637-9CB1-7F0979523813} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- {0D604DFD-AAB6-442C-9368-F91A344146AB} = {D69D5741-611F-4E14-8541-1FEE94F50B5A}
- EndGlobalSection
-EndGlobal
diff --git a/VisualC/SDLmain/SDLmain_VS2008.vcproj b/VisualC/SDLmain/SDLmain_VS2008.vcproj
deleted file mode 100644
index 354bf536c7..0000000000
--- a/VisualC/SDLmain/SDLmain_VS2008.vcproj
+++ /dev/null
@@ -1,294 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/SDLtest/SDLtest.vcxproj b/VisualC/SDLtest/SDLtest.vcxproj
index 6190a7dfa7..e2e39f935f 100644
--- a/VisualC/SDLtest/SDLtest.vcxproj
+++ b/VisualC/SDLtest/SDLtest.vcxproj
@@ -164,9 +164,10 @@
+
-
\ No newline at end of file
+
diff --git a/VisualC/SDLtest/SDLtest_VS2008.vcproj b/VisualC/SDLtest/SDLtest_VS2008.vcproj
deleted file mode 100644
index 8b9074794c..0000000000
--- a/VisualC/SDLtest/SDLtest_VS2008.vcproj
+++ /dev/null
@@ -1,350 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/checkkeys/checkkeys_VS2008.vcproj b/VisualC/tests/checkkeys/checkkeys_VS2008.vcproj
deleted file mode 100644
index b02c4cfa7d..0000000000
--- a/VisualC/tests/checkkeys/checkkeys_VS2008.vcproj
+++ /dev/null
@@ -1,388 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/controllermap/controllermap_VS2008.vcproj b/VisualC/tests/controllermap/controllermap_VS2008.vcproj
deleted file mode 100644
index 1ecce67373..0000000000
--- a/VisualC/tests/controllermap/controllermap_VS2008.vcproj
+++ /dev/null
@@ -1,480 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/loopwave/loopwave_VS2008.vcproj b/VisualC/tests/loopwave/loopwave_VS2008.vcproj
deleted file mode 100644
index 1cbf89a8cd..0000000000
--- a/VisualC/tests/loopwave/loopwave_VS2008.vcproj
+++ /dev/null
@@ -1,396 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testatomic/testatomic_VS2008.vcproj b/VisualC/tests/testatomic/testatomic_VS2008.vcproj
deleted file mode 100644
index 5f4452b580..0000000000
--- a/VisualC/tests/testatomic/testatomic_VS2008.vcproj
+++ /dev/null
@@ -1,348 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testautomation/testautomation_VS2008.vcproj b/VisualC/tests/testautomation/testautomation_VS2008.vcproj
deleted file mode 100755
index dc1bec0f44..0000000000
--- a/VisualC/tests/testautomation/testautomation_VS2008.vcproj
+++ /dev/null
@@ -1,431 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testdraw2/testdraw2_VS2008.vcproj b/VisualC/tests/testdraw2/testdraw2_VS2008.vcproj
deleted file mode 100644
index 16612aeaac..0000000000
--- a/VisualC/tests/testdraw2/testdraw2_VS2008.vcproj
+++ /dev/null
@@ -1,355 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testfile/testfile_VS2008.vcproj b/VisualC/tests/testfile/testfile_VS2008.vcproj
deleted file mode 100644
index 46f796a4a1..0000000000
--- a/VisualC/tests/testfile/testfile_VS2008.vcproj
+++ /dev/null
@@ -1,348 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testgamecontroller/testgamecontroller_VS2008.vcproj b/VisualC/tests/testgamecontroller/testgamecontroller_VS2008.vcproj
deleted file mode 100644
index 1b31f57b0a..0000000000
--- a/VisualC/tests/testgamecontroller/testgamecontroller_VS2008.vcproj
+++ /dev/null
@@ -1,480 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testgesture/testgesture_VS2008.vcproj b/VisualC/tests/testgesture/testgesture_VS2008.vcproj
deleted file mode 100644
index 4fff2273ea..0000000000
--- a/VisualC/tests/testgesture/testgesture_VS2008.vcproj
+++ /dev/null
@@ -1,348 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testgl2/testgl2_VS2008.vcproj b/VisualC/tests/testgl2/testgl2_VS2008.vcproj
deleted file mode 100644
index 0c42dc72a1..0000000000
--- a/VisualC/tests/testgl2/testgl2_VS2008.vcproj
+++ /dev/null
@@ -1,359 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testgles2/testgles2_VS2008.vcproj b/VisualC/tests/testgles2/testgles2_VS2008.vcproj
deleted file mode 100644
index efe5355b86..0000000000
--- a/VisualC/tests/testgles2/testgles2_VS2008.vcproj
+++ /dev/null
@@ -1,352 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testjoystick/testjoystick_VS2008.vcproj b/VisualC/tests/testjoystick/testjoystick_VS2008.vcproj
deleted file mode 100644
index eb1a19fa6b..0000000000
--- a/VisualC/tests/testjoystick/testjoystick_VS2008.vcproj
+++ /dev/null
@@ -1,348 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testoverlay2/testoverlay2_VS2008.vcproj b/VisualC/tests/testoverlay2/testoverlay2_VS2008.vcproj
deleted file mode 100644
index 578a7c34a2..0000000000
--- a/VisualC/tests/testoverlay2/testoverlay2_VS2008.vcproj
+++ /dev/null
@@ -1,392 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testplatform/testplatform_VS2008.vcproj b/VisualC/tests/testplatform/testplatform_VS2008.vcproj
deleted file mode 100644
index 014faeeaa0..0000000000
--- a/VisualC/tests/testplatform/testplatform_VS2008.vcproj
+++ /dev/null
@@ -1,364 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testpower/testpower_VS2008.vcproj b/VisualC/tests/testpower/testpower_VS2008.vcproj
deleted file mode 100644
index e140e6b947..0000000000
--- a/VisualC/tests/testpower/testpower_VS2008.vcproj
+++ /dev/null
@@ -1,348 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testrendertarget/testrendertarget_VS2008.vcproj b/VisualC/tests/testrendertarget/testrendertarget_VS2008.vcproj
deleted file mode 100644
index d13432ac22..0000000000
--- a/VisualC/tests/testrendertarget/testrendertarget_VS2008.vcproj
+++ /dev/null
@@ -1,443 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testrumble/testrumble_VS2008.vcproj b/VisualC/tests/testrumble/testrumble_VS2008.vcproj
deleted file mode 100644
index ea4a858365..0000000000
--- a/VisualC/tests/testrumble/testrumble_VS2008.vcproj
+++ /dev/null
@@ -1,348 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testscale/testscale_VS2008.vcproj b/VisualC/tests/testscale/testscale_VS2008.vcproj
deleted file mode 100644
index 5a15fccf8d..0000000000
--- a/VisualC/tests/testscale/testscale_VS2008.vcproj
+++ /dev/null
@@ -1,443 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testshape/testshape_VS2008.vcproj b/VisualC/tests/testshape/testshape_VS2008.vcproj
deleted file mode 100644
index 73db789315..0000000000
--- a/VisualC/tests/testshape/testshape_VS2008.vcproj
+++ /dev/null
@@ -1,348 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testsprite2/testsprite2_VS2008.vcproj b/VisualC/tests/testsprite2/testsprite2_VS2008.vcproj
deleted file mode 100644
index 7236ecc4f8..0000000000
--- a/VisualC/tests/testsprite2/testsprite2_VS2008.vcproj
+++ /dev/null
@@ -1,399 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/VisualC/tests/testvulkan/testvulkan_VS2008.vcproj b/VisualC/tests/testvulkan/testvulkan_VS2008.vcproj
deleted file mode 100644
index e413b52e9b..0000000000
--- a/VisualC/tests/testvulkan/testvulkan_VS2008.vcproj
+++ /dev/null
@@ -1,355 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/WhatsNew.txt b/WhatsNew.txt
index 38e0496234..6f8489e340 100644
--- a/WhatsNew.txt
+++ b/WhatsNew.txt
@@ -1,6 +1,34 @@
This is a list of major changes in SDL's version history.
+---------------------------------------------------------------------------
+2.0.7:
+---------------------------------------------------------------------------
+
+General:
+* Added audio stream conversion functions:
+ SDL_NewAudioStream
+ SDL_AudioStreamPut
+ SDL_AudioStreamGet
+ SDL_AudioStreamAvailable
+ SDL_AudioStreamFlush
+ SDL_AudioStreamClear
+ SDL_FreeAudioStream
+* Added functions to query and set the SDL memory allocation functions:
+ SDL_GetMemoryFunctions()
+ SDL_SetMemoryFunctions()
+ SDL_GetNumAllocations()
+* Added locking functions for multi-threaded access to the joystick and game controller APIs:
+ SDL_LockJoysticks()
+ SDL_UnlockJoysticks()
+* The following functions are now thread-safe:
+ SDL_SetEventFilter()
+ SDL_GetEventFilter()
+ SDL_AddEventWatch()
+ SDL_DelEventWatch()
+
+
+General:
---------------------------------------------------------------------------
2.0.6:
---------------------------------------------------------------------------
diff --git a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj
index 19c472794a..e7842c664c 100755
--- a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj
+++ b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj
@@ -90,6 +90,8 @@
56F9D5601DF73BA400C15B5D /* SDL_dataqueue.c in Sources */ = {isa = PBXBuildFile; fileRef = 566726431DF72CF5001DD3DB /* SDL_dataqueue.c */; };
93CB792313FC5E5200BD3E05 /* SDL_uikitviewcontroller.h in Headers */ = {isa = PBXBuildFile; fileRef = 93CB792213FC5E5200BD3E05 /* SDL_uikitviewcontroller.h */; };
93CB792613FC5F5300BD3E05 /* SDL_uikitviewcontroller.m in Sources */ = {isa = PBXBuildFile; fileRef = 93CB792513FC5F5300BD3E05 /* SDL_uikitviewcontroller.m */; };
+ A7A9EEA91F702631002A5589 /* SDL_steamcontroller.c in Sources */ = {isa = PBXBuildFile; fileRef = A7A9EEA71F702631002A5589 /* SDL_steamcontroller.c */; };
+ A7A9EEAA1F702631002A5589 /* SDL_steamcontroller.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A9EEA81F702631002A5589 /* SDL_steamcontroller.h */; };
AA0AD06216647BBB00CE5896 /* SDL_gamecontroller.c in Sources */ = {isa = PBXBuildFile; fileRef = AA0AD06116647BBB00CE5896 /* SDL_gamecontroller.c */; };
AA0AD06516647BD400CE5896 /* SDL_gamecontroller.h in Headers */ = {isa = PBXBuildFile; fileRef = AA0AD06416647BD400CE5896 /* SDL_gamecontroller.h */; };
AA0F8495178D5F1A00823F9D /* SDL_systls.c in Sources */ = {isa = PBXBuildFile; fileRef = AA0F8494178D5F1A00823F9D /* SDL_systls.c */; };
@@ -393,6 +395,8 @@
56ED04E2118A8EFD00A56AA6 /* SDL_syspower.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SDL_syspower.m; path = ../../src/power/uikit/SDL_syspower.m; sourceTree = SOURCE_ROOT; };
93CB792213FC5E5200BD3E05 /* SDL_uikitviewcontroller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_uikitviewcontroller.h; sourceTree = ""; };
93CB792513FC5F5300BD3E05 /* SDL_uikitviewcontroller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SDL_uikitviewcontroller.m; sourceTree = ""; };
+ A7A9EEA71F702631002A5589 /* SDL_steamcontroller.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_steamcontroller.c; sourceTree = ""; };
+ A7A9EEA81F702631002A5589 /* SDL_steamcontroller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_steamcontroller.h; sourceTree = ""; };
AA0AD06116647BBB00CE5896 /* SDL_gamecontroller.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_gamecontroller.c; sourceTree = ""; };
AA0AD06416647BD400CE5896 /* SDL_gamecontroller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_gamecontroller.h; sourceTree = ""; };
AA0F8494178D5F1A00823F9D /* SDL_systls.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_systls.c; sourceTree = ""; };
@@ -725,6 +729,15 @@
name = uikit;
sourceTree = "";
};
+ A7A9EEA61F702607002A5589 /* steam */ = {
+ isa = PBXGroup;
+ children = (
+ A7A9EEA71F702631002A5589 /* SDL_steamcontroller.c */,
+ A7A9EEA81F702631002A5589 /* SDL_steamcontroller.h */,
+ );
+ path = steam;
+ sourceTree = "";
+ };
FD3F4A6F0DEA620800C5B771 /* stdlib */ = {
isa = PBXGroup;
children = (
@@ -742,6 +755,7 @@
FD5F9D080E0E08B3008E885B /* joystick */ = {
isa = PBXGroup;
children = (
+ A7A9EEA61F702607002A5589 /* steam */,
FD689EFF0E26E5B600F90B21 /* iphoneos */,
AA0AD06116647BBB00CE5896 /* SDL_gamecontroller.c */,
FD5F9D1E0E0E08B3008E885B /* SDL_joystick.c */,
@@ -1124,6 +1138,7 @@
04F7807E12FB751400FC43C0 /* SDL_drawline.h in Headers */,
04F7808012FB751400FC43C0 /* SDL_drawpoint.h in Headers */,
04F7808412FB753F00FC43C0 /* SDL_nullframebuffer_c.h in Headers */,
+ A7A9EEAA1F702631002A5589 /* SDL_steamcontroller.h in Headers */,
0442EC5012FE1C1E004C9285 /* SDL_render_sw_c.h in Headers */,
FA1DC2721C62BE65008F99A0 /* SDL_uikitclipboard.h in Headers */,
0402A85A12FE70C600CECEE3 /* SDL_shaders_gles2.h in Headers */,
@@ -1236,7 +1251,7 @@
29B97313FDCFA39411CA2CEA /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0800;
+ LastUpgradeCheck = 0900;
TargetAttributes = {
00B4F48B12F6A69C0084EC00 = {
DevelopmentTeam = UZ5V327NE3;
@@ -1398,6 +1413,7 @@
files = (
FD6526810DE8FCDD002AD96B /* SDL_systimer.c in Sources */,
FD6526800DE8FCDD002AD96B /* SDL_timer.c in Sources */,
+ A7A9EEA91F702631002A5589 /* SDL_steamcontroller.c in Sources */,
FD3F4A7B0DEA620800C5B771 /* SDL_string.c in Sources */,
FD6526660DE8FCDD002AD96B /* SDL_dummyaudio.c in Sources */,
FD6526670DE8FCDD002AD96B /* SDL_audio.c in Sources */,
@@ -1524,13 +1540,36 @@
C01FCF4F08A954540054247B /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
+ GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 5.1.1;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 6.1;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
@@ -1540,11 +1579,34 @@
C01FCF5008A954540054247B /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ GCC_NO_COMMON_BLOCKS = YES;
GCC_SYMBOLS_PRIVATE_EXTERN = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 5.1.1;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 6.1;
SDKROOT = iphoneos;
TARGETED_DEVICE_FAMILY = "1,2";
};
diff --git a/Xcode-iOS/SDLtest/SDL2test.xcodeproj/project.pbxproj b/Xcode-iOS/SDLtest/SDL2test.xcodeproj/project.pbxproj
index 0d4fce7e93..99afeb1ee0 100644
--- a/Xcode-iOS/SDLtest/SDL2test.xcodeproj/project.pbxproj
+++ b/Xcode-iOS/SDLtest/SDL2test.xcodeproj/project.pbxproj
@@ -21,6 +21,8 @@
AA1EE46D176059AB0029C7A5 /* SDL_test_log.c in Sources */ = {isa = PBXBuildFile; fileRef = AA1EE45F176059AB0029C7A5 /* SDL_test_log.c */; };
AA1EE46E176059AB0029C7A5 /* SDL_test_md5.c in Sources */ = {isa = PBXBuildFile; fileRef = AA1EE460176059AB0029C7A5 /* SDL_test_md5.c */; };
AA1EE46F176059AB0029C7A5 /* SDL_test_random.c in Sources */ = {isa = PBXBuildFile; fileRef = AA1EE461176059AB0029C7A5 /* SDL_test_random.c */; };
+ AAF030011F9009B100B9A9FB /* SDL_test_memory.c in Sources */ = {isa = PBXBuildFile; fileRef = AAF02FFF1F9009B100B9A9FB /* SDL_test_memory.c */; };
+ AAF030021F9009B100B9A9FB /* SDL_test_assert.c in Sources */ = {isa = PBXBuildFile; fileRef = AAF030001F9009B100B9A9FB /* SDL_test_assert.c */; };
FA3D99011BC4E5BC002C96C8 /* SDL_test_common.c in Sources */ = {isa = PBXBuildFile; fileRef = AA1EE454176059AB0029C7A5 /* SDL_test_common.c */; };
FA3D99021BC4E5BC002C96C8 /* SDL_test_compare.c in Sources */ = {isa = PBXBuildFile; fileRef = AA1EE455176059AB0029C7A5 /* SDL_test_compare.c */; };
FA3D99031BC4E5BC002C96C8 /* SDL_test_crc32.c in Sources */ = {isa = PBXBuildFile; fileRef = AA1EE456176059AB0029C7A5 /* SDL_test_crc32.c */; };
@@ -65,6 +67,8 @@
AA1EE45F176059AB0029C7A5 /* SDL_test_log.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SDL_test_log.c; path = ../../src/test/SDL_test_log.c; sourceTree = ""; };
AA1EE460176059AB0029C7A5 /* SDL_test_md5.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SDL_test_md5.c; path = ../../src/test/SDL_test_md5.c; sourceTree = ""; };
AA1EE461176059AB0029C7A5 /* SDL_test_random.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SDL_test_random.c; path = ../../src/test/SDL_test_random.c; sourceTree = ""; };
+ AAF02FFF1F9009B100B9A9FB /* SDL_test_memory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SDL_test_memory.c; path = ../../src/test/SDL_test_memory.c; sourceTree = ""; };
+ AAF030001F9009B100B9A9FB /* SDL_test_assert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SDL_test_assert.c; path = ../../src/test/SDL_test_assert.c; sourceTree = ""; };
FA3D98F81BC4E5A2002C96C8 /* libSDL2test-TV.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libSDL2test-TV.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
@@ -106,6 +110,7 @@
AA1EE453176059770029C7A5 /* Library Source */ = {
isa = PBXGroup;
children = (
+ AAF030001F9009B100B9A9FB /* SDL_test_assert.c */,
AA1EE454176059AB0029C7A5 /* SDL_test_common.c */,
AA1EE455176059AB0029C7A5 /* SDL_test_compare.c */,
AA1EE456176059AB0029C7A5 /* SDL_test_crc32.c */,
@@ -119,6 +124,7 @@
AA1EE45E176059AB0029C7A5 /* SDL_test_imagePrimitivesBlend.c */,
AA1EE45F176059AB0029C7A5 /* SDL_test_log.c */,
AA1EE460176059AB0029C7A5 /* SDL_test_md5.c */,
+ AAF02FFF1F9009B100B9A9FB /* SDL_test_memory.c */,
AA1EE461176059AB0029C7A5 /* SDL_test_random.c */,
);
name = "Library Source";
@@ -213,12 +219,14 @@
AA1EE464176059AB0029C7A5 /* SDL_test_crc32.c in Sources */,
AA1EE465176059AB0029C7A5 /* SDL_test_font.c in Sources */,
AA1EE466176059AB0029C7A5 /* SDL_test_fuzzer.c in Sources */,
+ AAF030021F9009B100B9A9FB /* SDL_test_assert.c in Sources */,
AA1EE467176059AB0029C7A5 /* SDL_test_harness.c in Sources */,
AA1EE468176059AB0029C7A5 /* SDL_test_imageBlit.c in Sources */,
AA1EE469176059AB0029C7A5 /* SDL_test_imageBlitBlend.c in Sources */,
AA1EE46A176059AB0029C7A5 /* SDL_test_imageFace.c in Sources */,
AA1EE46B176059AB0029C7A5 /* SDL_test_imagePrimitives.c in Sources */,
AA1EE46C176059AB0029C7A5 /* SDL_test_imagePrimitivesBlend.c in Sources */,
+ AAF030011F9009B100B9A9FB /* SDL_test_memory.c in Sources */,
AA1EE46D176059AB0029C7A5 /* SDL_test_log.c in Sources */,
AA1EE46E176059AB0029C7A5 /* SDL_test_md5.c in Sources */,
AA1EE46F176059AB0029C7A5 /* SDL_test_random.c in Sources */,
diff --git a/Xcode/SDL/Info-Framework.plist b/Xcode/SDL/Info-Framework.plist
index 0be3ae5df2..a509c89eb2 100644
--- a/Xcode/SDL/Info-Framework.plist
+++ b/Xcode/SDL/Info-Framework.plist
@@ -19,10 +19,10 @@
CFBundlePackageType
FMWK
CFBundleShortVersionString
- 2.0.6
+ 2.0.7
CFBundleSignature
SDLX
CFBundleVersion
- 2.0.6
+ 2.0.7
diff --git a/Xcode/SDL/SDL.xcodeproj/project.pbxproj b/Xcode/SDL/SDL.xcodeproj/project.pbxproj
index 0f64bad0d9..4208d9af94 100755
--- a/Xcode/SDL/SDL.xcodeproj/project.pbxproj
+++ b/Xcode/SDL/SDL.xcodeproj/project.pbxproj
@@ -2355,7 +2355,7 @@
0867D690FE84028FC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
- LastUpgradeCheck = 0730;
+ LastUpgradeCheck = 0900;
};
buildConfigurationList = 0073178E0858DB0500B2BC32 /* Build configuration list for PBXProject "SDL" */;
compatibilityVersion = "Xcode 3.2";
@@ -2803,12 +2803,19 @@
00CFA621106A567900758660 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@@ -2840,7 +2847,7 @@
CLANG_LINK_OBJC_RUNTIME = NO;
COMBINE_HIDPI_IMAGES = YES;
DYLIB_COMPATIBILITY_VERSION = 1.0.0;
- DYLIB_CURRENT_VERSION = 7.0.0;
+ DYLIB_CURRENT_VERSION = 8.0.0;
FRAMEWORK_VERSION = A;
HEADER_SEARCH_PATHS = (
/usr/X11R6/include,
@@ -2888,12 +2895,19 @@
00CFA627106A568900758660 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
@@ -2925,7 +2939,7 @@
CLANG_LINK_OBJC_RUNTIME = NO;
COMBINE_HIDPI_IMAGES = YES;
DYLIB_COMPATIBILITY_VERSION = 1.0.0;
- DYLIB_CURRENT_VERSION = 7.0.0;
+ DYLIB_CURRENT_VERSION = 8.0.0;
FRAMEWORK_VERSION = A;
HEADER_SEARCH_PATHS = (
/usr/X11R6/include,
diff --git a/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj b/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj
index 144d24ca5e..cff071c7b7 100755
--- a/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj
+++ b/Xcode/SDLTest/SDLTest.xcodeproj/project.pbxproj
@@ -348,6 +348,7 @@
00794EF009D23739003FC8A1 /* utf8.txt in CopyFiles */ = {isa = PBXBuildFile; fileRef = 00794E6309D20839003FC8A1 /* utf8.txt */; };
00794EF709D237DE003FC8A1 /* moose.dat in CopyFiles */ = {isa = PBXBuildFile; fileRef = 00794E5E09D20839003FC8A1 /* moose.dat */; };
453774A5120915E3002F0F45 /* testshape.c in Sources */ = {isa = PBXBuildFile; fileRef = 453774A4120915E3002F0F45 /* testshape.c */; };
+ AAF02FFA1F90092700B9A9FB /* SDL_test_memory.c in Sources */ = {isa = PBXBuildFile; fileRef = AAF02FF41F90089800B9A9FB /* SDL_test_memory.c */; };
BBFC08C0164C6862003E6A99 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 002F33A709CA188600EBEB88 /* Cocoa.framework */; };
BBFC08C1164C6862003E6A99 /* CoreAudio.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 002A863B10730545007319AE /* CoreAudio.framework */; };
BBFC08C2164C6862003E6A99 /* ForceFeedback.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 002A863C10730545007319AE /* ForceFeedback.framework */; };
@@ -1152,6 +1153,7 @@
092D6D75FFB313BB7F000001 /* testlock.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = testlock.c; path = ../../test/testlock.c; sourceTree = SOURCE_ROOT; };
4537749212091504002F0F45 /* testshape */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testshape; sourceTree = BUILT_PRODUCTS_DIR; };
453774A4120915E3002F0F45 /* testshape.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = testshape.c; path = ../../test/testshape.c; sourceTree = SOURCE_ROOT; };
+ AAF02FF41F90089800B9A9FB /* SDL_test_memory.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SDL_test_memory.c; path = ../../src/test/SDL_test_memory.c; sourceTree = ""; };
BBFC088E164C6820003E6A99 /* testgamecontroller.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = testgamecontroller.c; path = ../../test/testgamecontroller.c; sourceTree = ""; };
BBFC08CD164C6862003E6A99 /* testgamecontroller */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testgamecontroller; sourceTree = BUILT_PRODUCTS_DIR; };
BEC566B60761D90300A33029 /* checkkeys */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = checkkeys; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -2212,6 +2214,7 @@
DB166D8F16A1D1A500A1396C /* SDL_test_imagePrimitivesBlend.c */,
DB166D9016A1D1A500A1396C /* SDL_test_log.c */,
DB166D9116A1D1A500A1396C /* SDL_test_md5.c */,
+ AAF02FF41F90089800B9A9FB /* SDL_test_memory.c */,
DB166D9216A1D1A500A1396C /* SDL_test_random.c */,
);
name = SDL_Test;
@@ -3393,6 +3396,7 @@
DB166D9E16A1D1A500A1396C /* SDL_test_imagePrimitivesBlend.c in Sources */,
DB166D9F16A1D1A500A1396C /* SDL_test_log.c in Sources */,
DB166DA016A1D1A500A1396C /* SDL_test_md5.c in Sources */,
+ AAF02FFA1F90092700B9A9FB /* SDL_test_memory.c in Sources */,
DB166DA116A1D1A500A1396C /* SDL_test_random.c in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
diff --git a/android-project/src/org/libsdl/app/SDL.java b/android-project/src/org/libsdl/app/SDL.java
new file mode 100644
index 0000000000..cfe4830945
--- /dev/null
+++ b/android-project/src/org/libsdl/app/SDL.java
@@ -0,0 +1,37 @@
+package org.libsdl.app;
+
+import android.content.Context;
+
+/**
+ SDL library initialization
+*/
+public class SDL {
+
+ // This function should be called first and sets up the native code
+ // so it can call into the Java classes
+ public static void setupJNI() {
+ SDLActivity.nativeSetupJNI();
+ SDLAudioManager.nativeSetupJNI();
+ SDLControllerManager.nativeSetupJNI();
+ }
+
+ // This function should be called each time the activity is started
+ public static void initialize() {
+ setContext(null);
+
+ SDLActivity.initialize();
+ SDLAudioManager.initialize();
+ SDLControllerManager.initialize();
+ }
+
+ // This function stores the current activity (SDL or not)
+ public static void setContext(Context context) {
+ mContext = context;
+ }
+
+ public static Context getContext() {
+ return mContext;
+ }
+
+ protected static Context mContext;
+}
diff --git a/android-project/src/org/libsdl/app/SDLActivity.java b/android-project/src/org/libsdl/app/SDLActivity.java
index d3da10e68e..9119473f53 100644
--- a/android-project/src/org/libsdl/app/SDLActivity.java
+++ b/android-project/src/org/libsdl/app/SDLActivity.java
@@ -2,12 +2,9 @@
import java.io.IOException;
import java.io.InputStream;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.List;
import java.lang.reflect.Method;
+import java.util.Objects;
import android.app.*;
import android.content.*;
@@ -26,7 +23,6 @@
import android.util.SparseArray;
import android.graphics.*;
import android.graphics.drawable.Drawable;
-import android.media.*;
import android.hardware.*;
import android.content.pm.ActivityInfo;
@@ -56,24 +52,17 @@ public enum NativeState {
public static boolean mSeparateMouseAndTouch;
// Main components
- protected static Context mContext;
protected static SDLActivity mSingleton;
protected static SDLSurface mSurface;
protected static View mTextEdit;
protected static boolean mScreenKeyboardShown;
protected static ViewGroup mLayout;
- protected static SDLJoystickHandler mJoystickHandler;
- protected static SDLHapticHandler mHapticHandler;
protected static SDLClipboardHandler mClipboardHandler;
// This is what SDL runs in. It invokes SDL_main(), eventually
protected static Thread mSDLThread;
- // Audio
- protected static AudioTrack mAudioTrack;
- protected static AudioRecord mAudioRecord;
-
/**
* This method returns the name of the shared object with the application entry point
* It can be overridden by derived classes.
@@ -136,17 +125,12 @@ protected String[] getArguments() {
public static void initialize() {
// The static nature of the singleton and Android quirkyness force us to initialize everything here
// Otherwise, when exiting the app and returning to it, these variables *keep* their pre exit values
- mContext = null;
mSingleton = null;
mSurface = null;
mTextEdit = null;
mLayout = null;
- mJoystickHandler = null;
- mHapticHandler = null;
mClipboardHandler = null;
mSDLThread = null;
- mAudioTrack = null;
- mAudioRecord = null;
mExitCalledFromJava = false;
mBrokenLibraries = false;
mIsResumedCalled = false;
@@ -157,9 +141,6 @@ public static void initialize() {
}
// Setup
- public static void setContext(Context context) {
- mContext = context;
- }
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.v(TAG, "Device: " + android.os.Build.DEVICE);
@@ -167,11 +148,6 @@ protected void onCreate(Bundle savedInstanceState) {
Log.v(TAG, "onCreate()");
super.onCreate(savedInstanceState);
- SDLActivity.initialize();
-
- // So we can call stuff from static callbacks
- mContext = mSingleton = this;
-
// Load shared libraries
String errorMsgBrokenLib = "";
try {
@@ -209,16 +185,14 @@ public void onClick(DialogInterface dialog,int id) {
}
// Set up JNI
- SDLActivity.nativeSetupJNI();
+ SDL.setupJNI();
- if (Build.VERSION.SDK_INT >= 16) {
- mJoystickHandler = new SDLJoystickHandler_API16();
- } else if (Build.VERSION.SDK_INT >= 12) {
- mJoystickHandler = new SDLJoystickHandler_API12();
- } else {
- mJoystickHandler = new SDLJoystickHandler();
- }
- mHapticHandler = new SDLHapticHandler();
+ // Initialize state
+ SDL.initialize();
+
+ // So we can call stuff from static callbacks
+ mSingleton = this;
+ SDL.setContext(this);
if (Build.VERSION.SDK_INT >= 11) {
mClipboardHandler = new SDLClipboardHandler_API11();
@@ -422,7 +396,6 @@ public void run() {
mSurface.handleResume();
mCurrentNativeState = mNextNativeState;
}
- return;
}
}
@@ -461,7 +434,7 @@ protected boolean onUnhandledMessage(int command, Object param) {
protected static class SDLCommandHandler extends Handler {
@Override
public void handleMessage(Message msg) {
- Context context = getContext();
+ Context context = SDL.getContext();
if (context == null) {
Log.e(TAG, "error handling message, getContext() returned null");
return;
@@ -529,12 +502,6 @@ boolean sendCommand(int command, Object data) {
public static native void nativeResume();
public static native void onNativeDropFile(String filename);
public static native void onNativeResize(int x, int y, int format, float rate);
- public static native int onNativePadDown(int device_id, int keycode);
- public static native int onNativePadUp(int device_id, int keycode);
- public static native void onNativeJoy(int device_id, int axis,
- float value);
- public static native void onNativeHat(int device_id, int hat_id,
- int x, int y);
public static native void onNativeKeyDown(int keycode);
public static native void onNativeKeyUp(int keycode);
public static native void onNativeKeyboardFocusLost();
@@ -546,12 +513,6 @@ public static native void onNativeTouch(int touchDevId, int pointerFingerId,
public static native void onNativeClipboardChanged();
public static native void onNativeSurfaceChanged();
public static native void onNativeSurfaceDestroyed();
- public static native int nativeAddJoystick(int device_id, String name, String desc,
- int is_accelerometer, int nbuttons,
- int naxes, int nhats, int nballs);
- public static native int nativeRemoveJoystick(int device_id);
- public static native int nativeAddHaptic(int device_id, String name);
- public static native int nativeRemoveHaptic(int device_id);
public static native String nativeGetHint(String name);
/**
@@ -581,7 +542,7 @@ public void setOrientationBis(int w, int h, boolean resizable, String hint)
{
int orientation = -1;
- if (hint != "") {
+ if (!Objects.equals(hint, "")) {
if (hint.contains("LandscapeRight") && hint.contains("LandscapeLeft")) {
orientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE;
} else if (hint.contains("LandscapeRight")) {
@@ -614,8 +575,6 @@ public void setOrientationBis(int w, int h, boolean resizable, String hint)
if (orientation != -1) {
mSingleton.setRequestedOrientation(orientation);
}
-
- return;
}
@@ -624,20 +583,17 @@ public void setOrientationBis(int w, int h, boolean resizable, String hint)
*/
public static boolean isScreenKeyboardShown()
{
- if (mTextEdit == null) {
- return false;
- }
+ if (mTextEdit == null) {
+ return false;
+ }
- if (mScreenKeyboardShown == false) {
- return false;
- }
+ if (!mScreenKeyboardShown) {
+ return false;
+ }
- InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
- if (imm.isAcceptingText()) {
- return true;
- }
+ InputMethodManager imm = (InputMethodManager) SDL.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ return imm.isAcceptingText();
- return false;
}
/**
@@ -654,7 +610,7 @@ public static boolean sendMessage(int command, int param) {
* This method is called by SDL using JNI.
*/
public static Context getContext() {
- return mContext;
+ return SDL.getContext();
}
static class ShowTextInputTask implements Runnable {
@@ -681,7 +637,7 @@ public void run() {
params.topMargin = y;
if (mTextEdit == null) {
- mTextEdit = new DummyEdit(getContext());
+ mTextEdit = new DummyEdit(SDL.getContext());
mLayout.addView(mTextEdit, params);
} else {
@@ -691,7 +647,7 @@ public void run() {
mTextEdit.setVisibility(View.VISIBLE);
mTextEdit.requestFocus();
- InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+ InputMethodManager imm = (InputMethodManager) SDL.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
imm.showSoftInput(mTextEdit, 0);
mScreenKeyboardShown = true;
@@ -715,10 +671,7 @@ public static boolean isTextInputEvent(KeyEvent event) {
}
}
- if (event.isPrintingKey() || event.getKeyCode() == KeyEvent.KEYCODE_SPACE) {
- return true;
- }
- return false;
+ return event.isPrintingKey() || event.getKeyCode() == KeyEvent.KEYCODE_SPACE;
}
/**
@@ -731,156 +684,6 @@ public static Surface getNativeSurface() {
return SDLActivity.mSurface.getNativeSurface();
}
- // Audio
-
- /**
- * This method is called by SDL using JNI.
- */
- public static int audioOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
- int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
- int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
- int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
-
- Log.v(TAG, "SDL audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
-
- // Let the user pick a larger buffer if they really want -- but ye
- // gods they probably shouldn't, the minimums are horrifyingly high
- // latency already
- desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
-
- if (mAudioTrack == null) {
- mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
- channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
-
- // Instantiating AudioTrack can "succeed" without an exception and the track may still be invalid
- // Ref: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/AudioTrack.java
- // Ref: http://developer.android.com/reference/android/media/AudioTrack.html#getState()
-
- if (mAudioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
- Log.e(TAG, "Failed during initialization of Audio Track");
- mAudioTrack = null;
- return -1;
- }
-
- mAudioTrack.play();
- }
-
- Log.v(TAG, "SDL audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
-
- return 0;
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static void audioWriteShortBuffer(short[] buffer) {
- for (int i = 0; i < buffer.length; ) {
- int result = mAudioTrack.write(buffer, i, buffer.length - i);
- if (result > 0) {
- i += result;
- } else if (result == 0) {
- try {
- Thread.sleep(1);
- } catch(InterruptedException e) {
- // Nom nom
- }
- } else {
- Log.w(TAG, "SDL audio: error return from write(short)");
- return;
- }
- }
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static void audioWriteByteBuffer(byte[] buffer) {
- for (int i = 0; i < buffer.length; ) {
- int result = mAudioTrack.write(buffer, i, buffer.length - i);
- if (result > 0) {
- i += result;
- } else if (result == 0) {
- try {
- Thread.sleep(1);
- } catch(InterruptedException e) {
- // Nom nom
- }
- } else {
- Log.w(TAG, "SDL audio: error return from write(byte)");
- return;
- }
- }
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static int captureOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
- int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
- int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
- int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
-
- Log.v(TAG, "SDL capture: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
-
- // Let the user pick a larger buffer if they really want -- but ye
- // gods they probably shouldn't, the minimums are horrifyingly high
- // latency already
- desiredFrames = Math.max(desiredFrames, (AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
-
- if (mAudioRecord == null) {
- mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate,
- channelConfig, audioFormat, desiredFrames * frameSize);
-
- // see notes about AudioTrack state in audioOpen(), above. Probably also applies here.
- if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
- Log.e(TAG, "Failed during initialization of AudioRecord");
- mAudioRecord.release();
- mAudioRecord = null;
- return -1;
- }
-
- mAudioRecord.startRecording();
- }
-
- Log.v(TAG, "SDL capture: got " + ((mAudioRecord.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioRecord.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioRecord.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
-
- return 0;
- }
-
- /** This method is called by SDL using JNI. */
- public static int captureReadShortBuffer(short[] buffer, boolean blocking) {
- // !!! FIXME: this is available in API Level 23. Until then, we always block. :(
- //return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
- return mAudioRecord.read(buffer, 0, buffer.length);
- }
-
- /** This method is called by SDL using JNI. */
- public static int captureReadByteBuffer(byte[] buffer, boolean blocking) {
- // !!! FIXME: this is available in API Level 23. Until then, we always block. :(
- //return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
- return mAudioRecord.read(buffer, 0, buffer.length);
- }
-
-
- /** This method is called by SDL using JNI. */
- public static void audioClose() {
- if (mAudioTrack != null) {
- mAudioTrack.stop();
- mAudioTrack.release();
- mAudioTrack = null;
- }
- }
-
- /** This method is called by SDL using JNI. */
- public static void captureClose() {
- if (mAudioRecord != null) {
- mAudioRecord.stop();
- mAudioRecord.release();
- mAudioRecord = null;
- }
- }
-
-
// Input
/**
@@ -900,67 +703,20 @@ public static int[] inputGetInputDeviceIds(int sources) {
return Arrays.copyOf(filtered, used);
}
- // Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance
- public static boolean handleJoystickMotionEvent(MotionEvent event) {
- return mJoystickHandler.handleMotionEvent(event);
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static void pollInputDevices() {
- if (SDLActivity.mSDLThread != null) {
- mJoystickHandler.pollInputDevices();
- }
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static void pollHapticDevices() {
- if (SDLActivity.mSDLThread != null) {
- mHapticHandler.pollHapticDevices();
- }
- }
-
- /**
- * This method is called by SDL using JNI.
- */
- public static void hapticRun(int device_id, int length) {
- if (SDLActivity.mSDLThread != null) {
- mHapticHandler.run(device_id, length);
- }
- }
-
- // Check if a given device is considered a possible SDL joystick
- public static boolean isDeviceSDLJoystick(int deviceId) {
- InputDevice device = InputDevice.getDevice(deviceId);
- // We cannot use InputDevice.isVirtual before API 16, so let's accept
- // only nonnegative device ids (VIRTUAL_KEYBOARD equals -1)
- if ((device == null) || (deviceId < 0)) {
- return false;
- }
- int sources = device.getSources();
- return (((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) ||
- ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) ||
- ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
- );
- }
-
// APK expansion files support
/** com.android.vending.expansion.zipfile.ZipResourceFile object or null. */
- private Object expansionFile;
+ private static Object expansionFile;
/** com.android.vending.expansion.zipfile.ZipResourceFile's getInputStream() or null. */
- private Method expansionFileMethod;
+ private static Method expansionFileMethod;
/**
* This method is called by SDL using JNI.
* @return an InputStream on success or null if no expansion file was used.
* @throws IOException on errors. Message is set for the SDL error message.
*/
- public InputStream openAPKExpansionInputStream(String fileName) throws IOException {
+ public static InputStream openAPKExpansionInputStream(String fileName) throws IOException {
// Get a ZipResourceFile representing a merger of both the main and patch files
if (expansionFile == null) {
String mainHint = nativeGetHint("SDL_ANDROID_APK_EXPANSION_MAIN_FILE_VERSION");
@@ -987,7 +743,7 @@ public InputStream openAPKExpansionInputStream(String fileName) throws IOExcepti
// not a part of Android SDK we access it using reflection
expansionFile = Class.forName("com.android.vending.expansion.zipfile.APKExpansionSupport")
.getMethod("getAPKExpansionZipFile", Context.class, int.class, int.class)
- .invoke(null, this, mainVersion, patchVersion);
+ .invoke(null, SDL.getContext(), mainVersion, patchVersion);
expansionFileMethod = expansionFile.getClass()
.getMethod("getInputStream", String.class);
@@ -1241,7 +997,6 @@ public static String clipboardGetText() {
*/
public static void clipboardSetText(String string) {
mClipboardHandler.clipboardSetText(string);
- return;
}
}
@@ -1452,14 +1207,14 @@ public boolean onKey(View v, int keyCode, KeyEvent event) {
// 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 (SDLActivity.isDeviceSDLJoystick(event.getDeviceId())) {
+ if (SDLControllerManager.isDeviceSDLJoystick(event.getDeviceId())) {
// Note that we process events with specific key codes here
if (event.getAction() == KeyEvent.ACTION_DOWN) {
- if (SDLActivity.onNativePadDown(event.getDeviceId(), keyCode) == 0) {
+ if (SDLControllerManager.onNativePadDown(event.getDeviceId(), keyCode) == 0) {
return true;
}
} else if (event.getAction() == KeyEvent.ACTION_UP) {
- if (SDLActivity.onNativePadUp(event.getDeviceId(), keyCode) == 0) {
+ if (SDLControllerManager.onNativePadUp(event.getDeviceId(), keyCode) == 0) {
return true;
}
}
@@ -1759,331 +1514,6 @@ public boolean deleteSurroundingText(int beforeLength, int afterLength) {
}
}
-/* A null joystick handler for API level < 12 devices (the accelerometer is handled separately) */
-class SDLJoystickHandler {
-
- /**
- * Handles given MotionEvent.
- * @param event the event to be handled.
- * @return if given event was processed.
- */
- public boolean handleMotionEvent(MotionEvent event) {
- return false;
- }
-
- /**
- * Handles adding and removing of input devices.
- */
- public void pollInputDevices() {
- }
-}
-
-/* Actual joystick functionality available for API >= 12 devices */
-class SDLJoystickHandler_API12 extends SDLJoystickHandler {
-
- static class SDLJoystick {
- public int device_id;
- public String name;
- public String desc;
- public ArrayList axes;
- public ArrayList hats;
- }
- static class RangeComparator implements Comparator {
- @Override
- public int compare(InputDevice.MotionRange arg0, InputDevice.MotionRange arg1) {
- return arg0.getAxis() - arg1.getAxis();
- }
- }
-
- private ArrayList mJoysticks;
-
- public SDLJoystickHandler_API12() {
-
- mJoysticks = new ArrayList();
- }
-
- @Override
- public void pollInputDevices() {
- int[] deviceIds = InputDevice.getDeviceIds();
- // It helps processing the device ids in reverse order
- // For example, in the case of the XBox 360 wireless dongle,
- // so the first controller seen by SDL matches what the receiver
- // considers to be the first controller
-
- for(int i=deviceIds.length-1; i>-1; i--) {
- SDLJoystick joystick = getJoystick(deviceIds[i]);
- if (joystick == null) {
- joystick = new SDLJoystick();
- InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
- if (SDLActivity.isDeviceSDLJoystick(deviceIds[i])) {
- joystick.device_id = deviceIds[i];
- joystick.name = joystickDevice.getName();
- joystick.desc = getJoystickDescriptor(joystickDevice);
- joystick.axes = new ArrayList();
- joystick.hats = new ArrayList();
-
- List ranges = joystickDevice.getMotionRanges();
- Collections.sort(ranges, new RangeComparator());
- for (InputDevice.MotionRange range : ranges ) {
- if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
- if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
- range.getAxis() == MotionEvent.AXIS_HAT_Y) {
- joystick.hats.add(range);
- }
- else {
- joystick.axes.add(range);
- }
- }
- }
-
- mJoysticks.add(joystick);
- SDLActivity.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc, 0, -1,
- joystick.axes.size(), joystick.hats.size()/2, 0);
- }
- }
- }
-
- /* Check removed devices */
- ArrayList removedDevices = new ArrayList();
- for(int i=0; i < mJoysticks.size(); i++) {
- int device_id = mJoysticks.get(i).device_id;
- int j;
- for (j=0; j < deviceIds.length; j++) {
- if (device_id == deviceIds[j]) break;
- }
- if (j == deviceIds.length) {
- removedDevices.add(Integer.valueOf(device_id));
- }
- }
-
- for(int i=0; i < removedDevices.size(); i++) {
- int device_id = removedDevices.get(i).intValue();
- SDLActivity.nativeRemoveJoystick(device_id);
- for (int j=0; j < mJoysticks.size(); j++) {
- if (mJoysticks.get(j).device_id == device_id) {
- mJoysticks.remove(j);
- break;
- }
- }
- }
- }
-
- protected SDLJoystick getJoystick(int device_id) {
- for(int i=0; i < mJoysticks.size(); i++) {
- if (mJoysticks.get(i).device_id == device_id) {
- return mJoysticks.get(i);
- }
- }
- return null;
- }
-
- @Override
- public boolean handleMotionEvent(MotionEvent event) {
- if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
- int actionPointerIndex = event.getActionIndex();
- int action = event.getActionMasked();
- switch(action) {
- case MotionEvent.ACTION_MOVE:
- SDLJoystick joystick = getJoystick(event.getDeviceId());
- if ( joystick != null ) {
- for (int i = 0; i < joystick.axes.size(); i++) {
- InputDevice.MotionRange range = joystick.axes.get(i);
- /* Normalize the value to -1...1 */
- float value = ( event.getAxisValue( range.getAxis(), actionPointerIndex) - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
- SDLActivity.onNativeJoy(joystick.device_id, i, value );
- }
- for (int i = 0; i < joystick.hats.size(); i+=2) {
- int hatX = Math.round(event.getAxisValue( joystick.hats.get(i).getAxis(), actionPointerIndex ) );
- int hatY = Math.round(event.getAxisValue( joystick.hats.get(i+1).getAxis(), actionPointerIndex ) );
- SDLActivity.onNativeHat(joystick.device_id, i/2, hatX, hatY );
- }
- }
- break;
- default:
- break;
- }
- }
- return true;
- }
-
- public String getJoystickDescriptor(InputDevice joystickDevice) {
- return joystickDevice.getName();
- }
-}
-
-
-class SDLJoystickHandler_API16 extends SDLJoystickHandler_API12 {
-
- @Override
- public String getJoystickDescriptor(InputDevice joystickDevice) {
- String desc = joystickDevice.getDescriptor();
-
- if (desc != null && desc != "") {
- return desc;
- }
-
- return super.getJoystickDescriptor(joystickDevice);
- }
-}
-
-class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
- // Generic Motion (mouse hover, joystick...) events go here
- @Override
- public boolean onGenericMotion(View v, MotionEvent event) {
- float x, y;
- int action;
-
- switch ( event.getSource() ) {
- case InputDevice.SOURCE_JOYSTICK:
- case InputDevice.SOURCE_GAMEPAD:
- case InputDevice.SOURCE_DPAD:
- return SDLActivity.handleJoystickMotionEvent(event);
-
- case InputDevice.SOURCE_MOUSE:
- if (!SDLActivity.mSeparateMouseAndTouch) {
- break;
- }
- action = event.getActionMasked();
- switch (action) {
- case MotionEvent.ACTION_SCROLL:
- x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
- y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
- SDLActivity.onNativeMouse(0, action, x, y);
- return true;
-
- case MotionEvent.ACTION_HOVER_MOVE:
- x = event.getX(0);
- y = event.getY(0);
-
- SDLActivity.onNativeMouse(0, action, x, y);
- return true;
-
- default:
- break;
- }
- break;
-
- default:
- break;
- }
-
- // Event was not managed
- return false;
- }
-}
-
-class SDLHapticHandler {
-
- class SDLHaptic {
- public int device_id;
- public String name;
- public Vibrator vib;
- }
-
- private ArrayList mHaptics;
-
- public SDLHapticHandler() {
- mHaptics = new ArrayList();
- }
-
- public void run(int device_id, int length) {
- SDLHaptic haptic = getHaptic(device_id);
- if (haptic != null) {
- haptic.vib.vibrate (length);
- }
- }
-
- public void pollHapticDevices() {
-
- final int deviceId_VIBRATOR_SERVICE = 999999;
- boolean hasVibratorService = false;
-
- int[] deviceIds = InputDevice.getDeviceIds();
- // It helps processing the device ids in reverse order
- // For example, in the case of the XBox 360 wireless dongle,
- // so the first controller seen by SDL matches what the receiver
- // considers to be the first controller
-
- if (Build.VERSION.SDK_INT >= 16)
- {
- for (int i = deviceIds.length-1; i > -1; i--) {
- SDLHaptic haptic = getHaptic(deviceIds[i]);
- if (haptic == null) {
- InputDevice device = InputDevice.getDevice(deviceIds[i]);
- Vibrator vib = device.getVibrator();
- if (vib.hasVibrator()) {
- haptic = new SDLHaptic();
- haptic.device_id = deviceIds[i];
- haptic.name = device.getName();
- haptic.vib = vib;
- mHaptics.add(haptic);
- SDLActivity.nativeAddHaptic(haptic.device_id, haptic.name);
- }
- }
- }
- }
-
- /* Check VIBRATOR_SERVICE */
- Vibrator vib = (Vibrator) SDLActivity.mSingleton.getContext().getSystemService(Context.VIBRATOR_SERVICE);
- if (vib != null) {
- if (Build.VERSION.SDK_INT >= 11) {
- hasVibratorService = vib.hasVibrator();
- } else {
- hasVibratorService = true;
- }
-
- if (hasVibratorService) {
- SDLHaptic haptic = getHaptic(deviceId_VIBRATOR_SERVICE);
- if (haptic == null) {
- haptic = new SDLHaptic();
- haptic.device_id = deviceId_VIBRATOR_SERVICE;
- haptic.name = "VIBRATOR_SERVICE";
- haptic.vib = vib;
- mHaptics.add(haptic);
- SDLActivity.nativeAddHaptic(haptic.device_id, haptic.name);
- }
- }
- }
-
- /* Check removed devices */
- ArrayList removedDevices = new ArrayList();
- for(int i=0; i < mHaptics.size(); i++) {
- int device_id = mHaptics.get(i).device_id;
- int j;
- for (j=0; j < deviceIds.length; j++) {
- if (device_id == deviceIds[j]) break;
- }
-
- if (device_id == deviceId_VIBRATOR_SERVICE && hasVibratorService) {
- // don't remove the vibrator if it is still present
- } else if (j == deviceIds.length) {
- removedDevices.add(device_id);
- }
- }
-
- for(int i=0; i < removedDevices.size(); i++) {
- int device_id = removedDevices.get(i);
- SDLActivity.nativeRemoveHaptic(device_id);
- for (int j=0; j < mHaptics.size(); j++) {
- if (mHaptics.get(j).device_id == device_id) {
- mHaptics.remove(j);
- break;
- }
- }
- }
- }
-
- protected SDLHaptic getHaptic(int device_id) {
- for(int i=0; i < mHaptics.size(); i++) {
- if (mHaptics.get(i).device_id == device_id) {
- return mHaptics.get(i);
- }
- }
- return null;
- }
-}
-
-
interface SDLClipboardHandler {
public boolean clipboardHasText();
@@ -2100,7 +1530,7 @@ class SDLClipboardHandler_API11 implements
protected android.content.ClipboardManager mClipMgr;
SDLClipboardHandler_API11() {
- mClipMgr = (android.content.ClipboardManager) SDLActivity.mSingleton.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
+ mClipMgr = (android.content.ClipboardManager) SDL.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
mClipMgr.addPrimaryClipChangedListener(this);
}
@@ -2139,7 +1569,7 @@ class SDLClipboardHandler_Old implements
protected android.text.ClipboardManager mClipMgrOld;
SDLClipboardHandler_Old() {
- mClipMgrOld = (android.text.ClipboardManager) SDLActivity.mSingleton.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
+ mClipMgrOld = (android.text.ClipboardManager) SDL.getContext().getSystemService(Context.CLIPBOARD_SERVICE);
}
@Override
@@ -2160,8 +1590,6 @@ public String clipboardGetText() {
@Override
public void clipboardSetText(String string) {
mClipMgrOld.setText(string);
- return;
}
}
-
diff --git a/android-project/src/org/libsdl/app/SDLAudioManager.java b/android-project/src/org/libsdl/app/SDLAudioManager.java
new file mode 100644
index 0000000000..26baf8220a
--- /dev/null
+++ b/android-project/src/org/libsdl/app/SDLAudioManager.java
@@ -0,0 +1,178 @@
+package org.libsdl.app;
+
+import android.media.*;
+import android.util.Log;
+
+public class SDLAudioManager
+{
+ protected static final String TAG = "SDLAudio";
+
+ protected static AudioTrack mAudioTrack;
+ protected static AudioRecord mAudioRecord;
+
+ public static void initialize() {
+ mAudioTrack = null;
+ mAudioRecord = null;
+ }
+
+ // Audio
+
+ /**
+ * This method is called by SDL using JNI.
+ */
+ public static int audioOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
+ int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
+ int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
+
+ Log.v(TAG, "SDL audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+
+ // Let the user pick a larger buffer if they really want -- but ye
+ // gods they probably shouldn't, the minimums are horrifyingly high
+ // latency already
+ desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
+
+ if (mAudioTrack == null) {
+ mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
+ channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
+
+ // Instantiating AudioTrack can "succeed" without an exception and the track may still be invalid
+ // Ref: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/AudioTrack.java
+ // Ref: http://developer.android.com/reference/android/media/AudioTrack.html#getState()
+
+ if (mAudioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
+ Log.e(TAG, "Failed during initialization of Audio Track");
+ mAudioTrack = null;
+ return -1;
+ }
+
+ mAudioTrack.play();
+ }
+
+ Log.v(TAG, "SDL audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+
+ return 0;
+ }
+
+ /**
+ * This method is called by SDL using JNI.
+ */
+ public static void audioWriteShortBuffer(short[] buffer) {
+ if (mAudioTrack == null) {
+ Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
+ return;
+ }
+
+ for (int i = 0; i < buffer.length; ) {
+ int result = mAudioTrack.write(buffer, i, buffer.length - i);
+ if (result > 0) {
+ i += result;
+ } else if (result == 0) {
+ try {
+ Thread.sleep(1);
+ } catch(InterruptedException e) {
+ // Nom nom
+ }
+ } else {
+ Log.w(TAG, "SDL audio: error return from write(short)");
+ return;
+ }
+ }
+ }
+
+ /**
+ * This method is called by SDL using JNI.
+ */
+ public static void audioWriteByteBuffer(byte[] buffer) {
+ if (mAudioTrack == null) {
+ Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
+ return;
+ }
+
+ for (int i = 0; i < buffer.length; ) {
+ int result = mAudioTrack.write(buffer, i, buffer.length - i);
+ if (result > 0) {
+ i += result;
+ } else if (result == 0) {
+ try {
+ Thread.sleep(1);
+ } catch(InterruptedException e) {
+ // Nom nom
+ }
+ } else {
+ Log.w(TAG, "SDL audio: error return from write(byte)");
+ return;
+ }
+ }
+ }
+
+ /**
+ * This method is called by SDL using JNI.
+ */
+ public static int captureOpen(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
+ int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
+ int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
+
+ Log.v(TAG, "SDL capture: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + (sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+
+ // Let the user pick a larger buffer if they really want -- but ye
+ // gods they probably shouldn't, the minimums are horrifyingly high
+ // latency already
+ desiredFrames = Math.max(desiredFrames, (AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
+
+ if (mAudioRecord == null) {
+ mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate,
+ channelConfig, audioFormat, desiredFrames * frameSize);
+
+ // see notes about AudioTrack state in audioOpen(), above. Probably also applies here.
+ if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
+ Log.e(TAG, "Failed during initialization of AudioRecord");
+ mAudioRecord.release();
+ mAudioRecord = null;
+ return -1;
+ }
+
+ mAudioRecord.startRecording();
+ }
+
+ Log.v(TAG, "SDL capture: got " + ((mAudioRecord.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioRecord.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + (mAudioRecord.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+
+ return 0;
+ }
+
+ /** This method is called by SDL using JNI. */
+ public static int captureReadShortBuffer(short[] buffer, boolean blocking) {
+ // !!! FIXME: this is available in API Level 23. Until then, we always block. :(
+ //return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
+ return mAudioRecord.read(buffer, 0, buffer.length);
+ }
+
+ /** This method is called by SDL using JNI. */
+ public static int captureReadByteBuffer(byte[] buffer, boolean blocking) {
+ // !!! FIXME: this is available in API Level 23. Until then, we always block. :(
+ //return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
+ return mAudioRecord.read(buffer, 0, buffer.length);
+ }
+
+
+ /** This method is called by SDL using JNI. */
+ public static void audioClose() {
+ if (mAudioTrack != null) {
+ mAudioTrack.stop();
+ mAudioTrack.release();
+ mAudioTrack = null;
+ }
+ }
+
+ /** This method is called by SDL using JNI. */
+ public static void captureClose() {
+ if (mAudioRecord != null) {
+ mAudioRecord.stop();
+ mAudioRecord.release();
+ mAudioRecord = null;
+ }
+ }
+
+ public static native int nativeSetupJNI();
+}
diff --git a/android-project/src/org/libsdl/app/SDLControllerManager.java b/android-project/src/org/libsdl/app/SDLControllerManager.java
new file mode 100644
index 0000000000..36294422fc
--- /dev/null
+++ b/android-project/src/org/libsdl/app/SDLControllerManager.java
@@ -0,0 +1,433 @@
+package org.libsdl.app;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Objects;
+
+import android.content.Context;
+import android.os.*;
+import android.view.*;
+import android.util.Log;
+
+
+public class SDLControllerManager
+{
+
+ public static native int nativeSetupJNI();
+
+ public static native int nativeAddJoystick(int device_id, String name, String desc,
+ int is_accelerometer, int nbuttons,
+ int naxes, int nhats, int nballs);
+ public static native int nativeRemoveJoystick(int device_id);
+ public static native int nativeAddHaptic(int device_id, String name);
+ public static native int nativeRemoveHaptic(int device_id);
+ public static native int onNativePadDown(int device_id, int keycode);
+ public static native int onNativePadUp(int device_id, int keycode);
+ public static native void onNativeJoy(int device_id, int axis,
+ float value);
+ public static native void onNativeHat(int device_id, int hat_id,
+ int x, int y);
+
+ protected static SDLJoystickHandler mJoystickHandler;
+ protected static SDLHapticHandler mHapticHandler;
+
+ private static final String TAG = "SDLControllerManager";
+
+ public static void initialize() {
+ mJoystickHandler = null;
+ mHapticHandler = null;
+
+ SDLControllerManager.setup();
+ }
+
+ public static void setup() {
+ if (Build.VERSION.SDK_INT >= 16) {
+ mJoystickHandler = new SDLJoystickHandler_API16();
+ } else if (Build.VERSION.SDK_INT >= 12) {
+ mJoystickHandler = new SDLJoystickHandler_API12();
+ } else {
+ mJoystickHandler = new SDLJoystickHandler();
+ }
+ mHapticHandler = new SDLHapticHandler();
+ }
+
+ // Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance
+ public static boolean handleJoystickMotionEvent(MotionEvent event) {
+ return mJoystickHandler.handleMotionEvent(event);
+ }
+
+ /**
+ * This method is called by SDL using JNI.
+ */
+ public static void pollInputDevices() {
+ mJoystickHandler.pollInputDevices();
+ }
+
+ /**
+ * This method is called by SDL using JNI.
+ */
+ public static void pollHapticDevices() {
+ mHapticHandler.pollHapticDevices();
+ }
+
+ /**
+ * This method is called by SDL using JNI.
+ */
+ public static void hapticRun(int device_id, int length) {
+ mHapticHandler.run(device_id, length);
+ }
+
+ // Check if a given device is considered a possible SDL joystick
+ public static boolean isDeviceSDLJoystick(int deviceId) {
+ InputDevice device = InputDevice.getDevice(deviceId);
+ // We cannot use InputDevice.isVirtual before API 16, so let's accept
+ // only nonnegative device ids (VIRTUAL_KEYBOARD equals -1)
+ if ((device == null) || (deviceId < 0)) {
+ return false;
+ }
+ int sources = device.getSources();
+
+ if ((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) {
+ Log.v(TAG, "Input device " + device.getName() + " is a joystick.");
+ }
+ if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) {
+ Log.v(TAG, "Input device " + device.getName() + " is a dpad.");
+ }
+ if ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) {
+ Log.v(TAG, "Input device " + device.getName() + " is a gamepad.");
+ }
+
+ return (((sources & InputDevice.SOURCE_CLASS_JOYSTICK) == InputDevice.SOURCE_CLASS_JOYSTICK) ||
+ ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) ||
+ ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
+ );
+ }
+
+}
+
+/* A null joystick handler for API level < 12 devices (the accelerometer is handled separately) */
+class SDLJoystickHandler {
+
+ /**
+ * Handles given MotionEvent.
+ * @param event the event to be handled.
+ * @return if given event was processed.
+ */
+ public boolean handleMotionEvent(MotionEvent event) {
+ return false;
+ }
+
+ /**
+ * Handles adding and removing of input devices.
+ */
+ public void pollInputDevices() {
+ }
+}
+
+/* Actual joystick functionality available for API >= 12 devices */
+class SDLJoystickHandler_API12 extends SDLJoystickHandler {
+
+ static class SDLJoystick {
+ public int device_id;
+ public String name;
+ public String desc;
+ public ArrayList axes;
+ public ArrayList hats;
+ }
+ static class RangeComparator implements Comparator {
+ @Override
+ public int compare(InputDevice.MotionRange arg0, InputDevice.MotionRange arg1) {
+ return arg0.getAxis() - arg1.getAxis();
+ }
+ }
+
+ private ArrayList mJoysticks;
+
+ public SDLJoystickHandler_API12() {
+
+ mJoysticks = new ArrayList();
+ }
+
+ @Override
+ public void pollInputDevices() {
+ int[] deviceIds = InputDevice.getDeviceIds();
+ // It helps processing the device ids in reverse order
+ // For example, in the case of the XBox 360 wireless dongle,
+ // so the first controller seen by SDL matches what the receiver
+ // considers to be the first controller
+
+ for(int i=deviceIds.length-1; i>-1; i--) {
+ SDLJoystick joystick = getJoystick(deviceIds[i]);
+ if (joystick == null) {
+ joystick = new SDLJoystick();
+ InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
+ if (SDLControllerManager.isDeviceSDLJoystick(deviceIds[i])) {
+ joystick.device_id = deviceIds[i];
+ joystick.name = joystickDevice.getName();
+ joystick.desc = getJoystickDescriptor(joystickDevice);
+ joystick.axes = new ArrayList();
+ joystick.hats = new ArrayList();
+
+ List ranges = joystickDevice.getMotionRanges();
+ Collections.sort(ranges, new RangeComparator());
+ for (InputDevice.MotionRange range : ranges ) {
+ if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
+ if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
+ range.getAxis() == MotionEvent.AXIS_HAT_Y) {
+ joystick.hats.add(range);
+ }
+ else {
+ joystick.axes.add(range);
+ }
+ }
+ }
+
+ mJoysticks.add(joystick);
+ SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc, 0, -1,
+ joystick.axes.size(), joystick.hats.size()/2, 0);
+ }
+ }
+ }
+
+ /* Check removed devices */
+ ArrayList removedDevices = new ArrayList();
+ for(int i=0; i < mJoysticks.size(); i++) {
+ int device_id = mJoysticks.get(i).device_id;
+ int j;
+ for (j=0; j < deviceIds.length; j++) {
+ if (device_id == deviceIds[j]) break;
+ }
+ if (j == deviceIds.length) {
+ removedDevices.add(Integer.valueOf(device_id));
+ }
+ }
+
+ for(int i=0; i < removedDevices.size(); i++) {
+ int device_id = removedDevices.get(i).intValue();
+ SDLControllerManager.nativeRemoveJoystick(device_id);
+ for (int j=0; j < mJoysticks.size(); j++) {
+ if (mJoysticks.get(j).device_id == device_id) {
+ mJoysticks.remove(j);
+ break;
+ }
+ }
+ }
+ }
+
+ protected SDLJoystick getJoystick(int device_id) {
+ for(int i=0; i < mJoysticks.size(); i++) {
+ if (mJoysticks.get(i).device_id == device_id) {
+ return mJoysticks.get(i);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public boolean handleMotionEvent(MotionEvent event) {
+ if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
+ int actionPointerIndex = event.getActionIndex();
+ int action = event.getActionMasked();
+ switch(action) {
+ case MotionEvent.ACTION_MOVE:
+ SDLJoystick joystick = getJoystick(event.getDeviceId());
+ if ( joystick != null ) {
+ for (int i = 0; i < joystick.axes.size(); i++) {
+ InputDevice.MotionRange range = joystick.axes.get(i);
+ /* Normalize the value to -1...1 */
+ float value = ( event.getAxisValue( range.getAxis(), actionPointerIndex) - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
+ SDLControllerManager.onNativeJoy(joystick.device_id, i, value );
+ }
+ for (int i = 0; i < joystick.hats.size(); i+=2) {
+ int hatX = Math.round(event.getAxisValue( joystick.hats.get(i).getAxis(), actionPointerIndex ) );
+ int hatY = Math.round(event.getAxisValue( joystick.hats.get(i+1).getAxis(), actionPointerIndex ) );
+ SDLControllerManager.onNativeHat(joystick.device_id, i/2, hatX, hatY );
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return true;
+ }
+
+ public String getJoystickDescriptor(InputDevice joystickDevice) {
+ return joystickDevice.getName();
+ }
+}
+
+
+class SDLJoystickHandler_API16 extends SDLJoystickHandler_API12 {
+
+ @Override
+ public String getJoystickDescriptor(InputDevice joystickDevice) {
+ String desc = joystickDevice.getDescriptor();
+
+ if (desc != null && !Objects.equals(desc, "")) {
+ return desc;
+ }
+
+ return super.getJoystickDescriptor(joystickDevice);
+ }
+}
+
+class SDLHapticHandler {
+
+ class SDLHaptic {
+ public int device_id;
+ public String name;
+ public Vibrator vib;
+ }
+
+ private ArrayList mHaptics;
+
+ public SDLHapticHandler() {
+ mHaptics = new ArrayList();
+ }
+
+ public void run(int device_id, int length) {
+ SDLHaptic haptic = getHaptic(device_id);
+ if (haptic != null) {
+ haptic.vib.vibrate (length);
+ }
+ }
+
+ public void pollHapticDevices() {
+
+ final int deviceId_VIBRATOR_SERVICE = 999999;
+ boolean hasVibratorService = false;
+
+ int[] deviceIds = InputDevice.getDeviceIds();
+ // It helps processing the device ids in reverse order
+ // For example, in the case of the XBox 360 wireless dongle,
+ // so the first controller seen by SDL matches what the receiver
+ // considers to be the first controller
+
+ if (Build.VERSION.SDK_INT >= 16)
+ {
+ for (int i = deviceIds.length - 1; i > -1; i--) {
+ SDLHaptic haptic = getHaptic(deviceIds[i]);
+ if (haptic == null) {
+ InputDevice device = InputDevice.getDevice(deviceIds[i]);
+ Vibrator vib = device.getVibrator();
+ if (vib.hasVibrator()) {
+ haptic = new SDLHaptic();
+ haptic.device_id = deviceIds[i];
+ haptic.name = device.getName();
+ haptic.vib = vib;
+ mHaptics.add(haptic);
+ SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
+ }
+ }
+ }
+ }
+
+ /* Check VIBRATOR_SERVICE */
+ Vibrator vib = (Vibrator) SDL.getContext().getSystemService(Context.VIBRATOR_SERVICE);
+ if (vib != null) {
+ if (Build.VERSION.SDK_INT >= 11) {
+ hasVibratorService = vib.hasVibrator();
+ } else {
+ hasVibratorService = true;
+ }
+
+ if (hasVibratorService) {
+ SDLHaptic haptic = getHaptic(deviceId_VIBRATOR_SERVICE);
+ if (haptic == null) {
+ haptic = new SDLHaptic();
+ haptic.device_id = deviceId_VIBRATOR_SERVICE;
+ haptic.name = "VIBRATOR_SERVICE";
+ haptic.vib = vib;
+ mHaptics.add(haptic);
+ SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
+ }
+ }
+ }
+
+ /* Check removed devices */
+ ArrayList removedDevices = new ArrayList();
+ for(int i=0; i < mHaptics.size(); i++) {
+ int device_id = mHaptics.get(i).device_id;
+ int j;
+ for (j=0; j < deviceIds.length; j++) {
+ if (device_id == deviceIds[j]) break;
+ }
+
+ if (device_id == deviceId_VIBRATOR_SERVICE && hasVibratorService) {
+ // don't remove the vibrator if it is still present
+ } else if (j == deviceIds.length) {
+ removedDevices.add(device_id);
+ }
+ }
+
+ for(int i=0; i < removedDevices.size(); i++) {
+ int device_id = removedDevices.get(i);
+ SDLControllerManager.nativeRemoveHaptic(device_id);
+ for (int j=0; j < mHaptics.size(); j++) {
+ if (mHaptics.get(j).device_id == device_id) {
+ mHaptics.remove(j);
+ break;
+ }
+ }
+ }
+ }
+
+ protected SDLHaptic getHaptic(int device_id) {
+ for(int i=0; i < mHaptics.size(); i++) {
+ if (mHaptics.get(i).device_id == device_id) {
+ return mHaptics.get(i);
+ }
+ }
+ return null;
+ }
+}
+
+class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
+ // Generic Motion (mouse hover, joystick...) events go here
+ @Override
+ public boolean onGenericMotion(View v, MotionEvent event) {
+ float x, y;
+ int action;
+
+ switch ( event.getSource() ) {
+ case InputDevice.SOURCE_JOYSTICK:
+ case InputDevice.SOURCE_GAMEPAD:
+ case InputDevice.SOURCE_DPAD:
+ return SDLControllerManager.handleJoystickMotionEvent(event);
+
+ case InputDevice.SOURCE_MOUSE:
+ if (!SDLActivity.mSeparateMouseAndTouch) {
+ break;
+ }
+ action = event.getActionMasked();
+ switch (action) {
+ case MotionEvent.ACTION_SCROLL:
+ x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
+ y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
+ SDLActivity.onNativeMouse(0, action, x, y);
+ return true;
+
+ case MotionEvent.ACTION_HOVER_MOVE:
+ x = event.getX(0);
+ y = event.getY(0);
+
+ SDLActivity.onNativeMouse(0, action, x, y);
+ return true;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ // Event was not managed
+ return false;
+ }
+}
+
diff --git a/cmake_uninstall.cmake.in b/cmake_uninstall.cmake.in
index e3a5a4be9f..1761561b3b 100644
--- a/cmake_uninstall.cmake.in
+++ b/cmake_uninstall.cmake.in
@@ -1,8 +1,8 @@
-if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
- message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
-endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
+if (NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
+ message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_BINARY_DIR@/install_manifest.txt\"")
+endif(NOT EXISTS "@CMAKE_BINARY_DIR@/install_manifest.txt")
-file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
+file(READ "@CMAKE_BINARY_DIR@/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
foreach (file ${files})
message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
diff --git a/configure b/configure
index 14623c8cb5..b622085ed5 100755
--- a/configure
+++ b/configure
@@ -2710,9 +2710,9 @@ orig_CFLAGS="$CFLAGS"
#
SDL_MAJOR_VERSION=2
SDL_MINOR_VERSION=0
-SDL_MICRO_VERSION=6
+SDL_MICRO_VERSION=7
SDL_INTERFACE_AGE=0
-SDL_BINARY_AGE=6
+SDL_BINARY_AGE=7
SDL_VERSION=$SDL_MAJOR_VERSION.$SDL_MINOR_VERSION.$SDL_MICRO_VERSION
@@ -16635,7 +16635,7 @@ fi
rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
fi
- for ac_func in malloc calloc realloc free getenv setenv putenv unsetenv qsort abs bcopy memset memcpy memmove wcslen wcscmp strlen strlcpy strlcat strdup _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp vsscanf vsnprintf fopen64 fseeko fseeko64 sigaction setjmp nanosleep sysconf sysctlbyname getauxval poll
+ for ac_func in malloc calloc realloc free getenv setenv putenv unsetenv qsort abs bcopy memset memcpy memmove wcslen wcscmp strlen strlcpy strlcat _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp vsscanf vsnprintf fopen64 fseeko fseeko64 sigaction setjmp nanosleep sysconf sysctlbyname getauxval poll
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -16761,6 +16761,19 @@ $as_echo "#define HAVE_SA_SIGACTION 1" >>confdefs.h
fi
+
+ for ac_header in libunwind.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "libunwind.h" "ac_cv_header_libunwind_h" "$ac_includes_default"
+if test "x$ac_cv_header_libunwind_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBUNWIND_H 1
+_ACEOF
+
+fi
+
+done
+
fi
@@ -23839,6 +23852,7 @@ $as_echo "#define SDL_AUDIO_DRIVER_ANDROID 1" >>confdefs.h
$as_echo "#define SDL_JOYSTICK_LINUX 1" >>confdefs.h
SOURCES="$SOURCES $srcdir/src/joystick/linux/*.c"
+ SOURCES="$SOURCES $srcdir/src/joystick/steam/*.c"
have_joystick=yes
;;
android)
@@ -23846,6 +23860,7 @@ $as_echo "#define SDL_JOYSTICK_LINUX 1" >>confdefs.h
$as_echo "#define SDL_JOYSTICK_ANDROID 1" >>confdefs.h
SOURCES="$SOURCES $srcdir/src/joystick/android/*.c"
+ SOURCES="$SOURCES $srcdir/src/joystick/steam/*.c"
have_joystick=yes
;;
esac
@@ -24243,6 +24258,7 @@ $as_echo "#define SDL_AUDIO_DRIVER_COREAUDIO 1" >>confdefs.h
$as_echo "#define SDL_JOYSTICK_MFI 1" >>confdefs.h
SOURCES="$SOURCES $srcdir/src/joystick/iphoneos/*.m"
+ SOURCES="$SOURCES $srcdir/src/joystick/steam/*.c"
have_joystick=yes
fi
# Set up files for the haptic library
diff --git a/configure.in b/configure.in
index e91851e288..5ac2130844 100644
--- a/configure.in
+++ b/configure.in
@@ -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=6
+SDL_MICRO_VERSION=7
SDL_INTERFACE_AGE=0
-SDL_BINARY_AGE=6
+SDL_BINARY_AGE=7
SDL_VERSION=$SDL_MAJOR_VERSION.$SDL_MINOR_VERSION.$SDL_MICRO_VERSION
AC_SUBST(SDL_MAJOR_VERSION)
@@ -268,7 +268,7 @@ if test x$enable_libc = xyes; then
AC_DEFINE(HAVE_MPROTECT, 1, [ ])
]),
)
- AC_CHECK_FUNCS(malloc calloc realloc free getenv setenv putenv unsetenv qsort abs bcopy memset memcpy memmove wcslen wcscmp strlen strlcpy strlcat strdup _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp vsscanf vsnprintf fopen64 fseeko fseeko64 sigaction setjmp nanosleep sysconf sysctlbyname getauxval poll)
+ AC_CHECK_FUNCS(malloc calloc realloc free getenv setenv putenv unsetenv qsort abs bcopy memset memcpy memmove wcslen wcscmp strlen strlcpy strlcat _strrev _strupr _strlwr strchr strrchr strstr itoa _ltoa _uitoa _ultoa strtol strtoul _i64toa _ui64toa strtoll strtoull atoi atof strcmp strncmp _stricmp strcasecmp _strnicmp strncasecmp vsscanf vsnprintf fopen64 fseeko fseeko64 sigaction setjmp nanosleep sysconf sysctlbyname getauxval poll)
AC_CHECK_LIB(m, pow, [LIBS="$LIBS -lm"; EXTRA_LDFLAGS="$EXTRA_LDFLAGS -lm"])
AC_CHECK_FUNCS(atan atan2 acos asin ceil copysign cos cosf fabs floor log pow scalbn sin sinf sqrt sqrtf tan tanf)
@@ -277,6 +277,9 @@ if test x$enable_libc = xyes; then
AC_CHECK_FUNCS(iconv)
AC_CHECK_MEMBER(struct sigaction.sa_sigaction,[AC_DEFINE([HAVE_SA_SIGACTION], 1, [ ])], ,[#include ])
+
+ dnl Check for additional non-standard headers
+ AC_CHECK_HEADERS(libunwind.h)
fi
dnl AC_CHECK_SIZEOF(void*)
@@ -3360,11 +3363,13 @@ case "$host" in
linux)
AC_DEFINE(SDL_JOYSTICK_LINUX, 1, [ ])
SOURCES="$SOURCES $srcdir/src/joystick/linux/*.c"
+ SOURCES="$SOURCES $srcdir/src/joystick/steam/*.c"
have_joystick=yes
;;
android)
AC_DEFINE(SDL_JOYSTICK_ANDROID, 1, [ ])
SOURCES="$SOURCES $srcdir/src/joystick/android/*.c"
+ SOURCES="$SOURCES $srcdir/src/joystick/steam/*.c"
have_joystick=yes
;;
esac
@@ -3644,6 +3649,7 @@ AC_HELP_STRING([--enable-render-d3d], [enable the Direct3D render driver [[defau
if test x$enable_joystick = xyes; then
AC_DEFINE(SDL_JOYSTICK_MFI, 1, [ ])
SOURCES="$SOURCES $srcdir/src/joystick/iphoneos/*.m"
+ SOURCES="$SOURCES $srcdir/src/joystick/steam/*.c"
have_joystick=yes
fi
# Set up files for the haptic library
diff --git a/debian/changelog b/debian/changelog
index 48c9d75392..e9786f7f81 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+libsdl2 (2.0.7ubuntu1) UNRELEASED; urgency=low
+
+ * Updated SDL to version 2.0.7
+
+ -- Sam Lantinga Thu, 12 Oct 2017 08:01:16 -0800
+
libsdl2 (2.0.6ubuntu1) UNRELEASED; urgency=low
* Updated SDL to version 2.0.6
diff --git a/docs/README-ios.md b/docs/README-ios.md
index 18c4bc0669..bf34fe482f 100644
--- a/docs/README-ios.md
+++ b/docs/README-ios.md
@@ -9,8 +9,8 @@ Requirements: Mac OS X 10.8 or later and the iOS 7+ SDK.
Instructions:
-2. Open SDL.xcodeproj (located in Xcode-iOS/SDL) in Xcode.
-4. Select your desired target, and hit build.
+1. Open SDL.xcodeproj (located in Xcode-iOS/SDL) in Xcode.
+2. Select your desired target, and hit build.
There are three build targets:
- libSDL.a:
@@ -25,9 +25,8 @@ There are three build targets:
Build SDL for iOS from the command line
==============================================================================
-1. Follow step 1 above.
-2. cd (PATH WHERE THE SDL CODE IS)/build-scripts
-3. ./iosbuild.sh
+1. cd (PATH WHERE THE SDL CODE IS)/build-scripts
+2. ./iosbuild.sh
If everything goes fine, you should see a build/ios directory, inside there's
two directories "lib" and "include".
diff --git a/include/SDL_audio.h b/include/SDL_audio.h
index 53277cb7e9..f119c2b267 100644
--- a/include/SDL_audio.h
+++ b/include/SDL_audio.h
@@ -164,6 +164,15 @@ typedef void (SDLCALL * SDL_AudioCallback) (void *userdata, Uint8 * stream,
/**
* The calculated values in this structure are calculated by SDL_OpenAudio().
+ *
+ * For multi-channel audio, the default SDL channel mapping is:
+ * 2: FL FR (stereo)
+ * 3: FL FR LFE (2.1 surround)
+ * 4: FL FR BL BR (quad)
+ * 5: FL FR FC BL BR (quad + center)
+ * 6: FL FR FC LFE SL SR (5.1 surround - last two can also be BL BR)
+ * 7: FL FR FC LFE BC SL SR (6.1 surround)
+ * 8: FL FR FC LFE BL BR SL SR (7.1 surround)
*/
typedef struct SDL_AudioSpec
{
@@ -477,6 +486,132 @@ extern DECLSPEC int SDLCALL SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
*/
extern DECLSPEC int SDLCALL SDL_ConvertAudio(SDL_AudioCVT * cvt);
+/* SDL_AudioStream is a new audio conversion interface.
+ The benefits vs SDL_AudioCVT:
+ - it can handle resampling data in chunks without generating
+ artifacts, when it doesn't have the complete buffer available.
+ - it can handle incoming data in any variable size.
+ - You push data as you have it, and pull it when you need it
+ */
+/* this is opaque to the outside world. */
+struct _SDL_AudioStream;
+typedef struct _SDL_AudioStream SDL_AudioStream;
+
+/**
+ * Create a new audio stream
+ *
+ * \param src_format The format of the source audio
+ * \param src_channels The number of channels of the source audio
+ * \param src_rate The sampling rate of the source audio
+ * \param dst_format The format of the desired audio output
+ * \param dst_channels The number of channels of the desired audio output
+ * \param dst_rate The sampling rate of the desired audio output
+ * \return 0 on success, or -1 on error.
+ *
+ * \sa SDL_AudioStreamPut
+ * \sa SDL_AudioStreamGet
+ * \sa SDL_AudioStreamAvailable
+ * \sa SDL_AudioStreamFlush
+ * \sa SDL_AudioStreamClear
+ * \sa SDL_FreeAudioStream
+ */
+extern DECLSPEC SDL_AudioStream * SDLCALL SDL_NewAudioStream(const SDL_AudioFormat src_format,
+ const Uint8 src_channels,
+ const int src_rate,
+ const SDL_AudioFormat dst_format,
+ const Uint8 dst_channels,
+ const int dst_rate);
+
+/**
+ * Add data to be converted/resampled to the stream
+ *
+ * \param stream The stream the audio data is being added to
+ * \param buf A pointer to the audio data to add
+ * \param int The number of bytes to write to the stream
+ * \return 0 on success, or -1 on error.
+ *
+ * \sa SDL_NewAudioStream
+ * \sa SDL_AudioStreamGet
+ * \sa SDL_AudioStreamAvailable
+ * \sa SDL_AudioStreamFlush
+ * \sa SDL_AudioStreamClear
+ * \sa SDL_FreeAudioStream
+ */
+extern DECLSPEC int SDLCALL SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len);
+
+/**
+ * Get converted/resampled data from the stream
+ *
+ * \param stream The stream the audio is being requested from
+ * \param buf A buffer to fill with audio data
+ * \param len The maximum number of bytes to fill
+ * \return The number of bytes read from the stream, or -1 on error
+ *
+ * \sa SDL_NewAudioStream
+ * \sa SDL_AudioStreamPut
+ * \sa SDL_AudioStreamAvailable
+ * \sa SDL_AudioStreamFlush
+ * \sa SDL_AudioStreamClear
+ * \sa SDL_FreeAudioStream
+ */
+extern DECLSPEC int SDLCALL SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len);
+
+/**
+ * Get the number of converted/resampled bytes available. The stream may be
+ * buffering data behind the scenes until it has enough to resample
+ * correctly, so this number might be lower than what you expect, or even
+ * be zero. Add more data or flush the stream if you need the data now.
+ *
+ * \sa SDL_NewAudioStream
+ * \sa SDL_AudioStreamPut
+ * \sa SDL_AudioStreamGet
+ * \sa SDL_AudioStreamFlush
+ * \sa SDL_AudioStreamClear
+ * \sa SDL_FreeAudioStream
+ */
+extern DECLSPEC int SDLCALL SDL_AudioStreamAvailable(SDL_AudioStream *stream);
+
+/**
+ * Tell the stream that you're done sending data, and anything being buffered
+ * should be converted/resampled and made available immediately.
+ *
+ * It is legal to add more data to a stream after flushing, but there will
+ * be audio gaps in the output. Generally this is intended to signal the
+ * end of input, so the complete output becomes available.
+ *
+ * \sa SDL_NewAudioStream
+ * \sa SDL_AudioStreamPut
+ * \sa SDL_AudioStreamGet
+ * \sa SDL_AudioStreamAvailable
+ * \sa SDL_AudioStreamClear
+ * \sa SDL_FreeAudioStream
+ */
+extern DECLSPEC int SDLCALL SDL_AudioStreamFlush(SDL_AudioStream *stream);
+
+/**
+ * Clear any pending data in the stream without converting it
+ *
+ * \sa SDL_NewAudioStream
+ * \sa SDL_AudioStreamPut
+ * \sa SDL_AudioStreamGet
+ * \sa SDL_AudioStreamAvailable
+ * \sa SDL_AudioStreamFlush
+ * \sa SDL_FreeAudioStream
+ */
+extern DECLSPEC void SDLCALL SDL_AudioStreamClear(SDL_AudioStream *stream);
+
+/**
+ * Free an audio stream
+ *
+ * \sa SDL_NewAudioStream
+ * \sa SDL_AudioStreamPut
+ * \sa SDL_AudioStreamGet
+ * \sa SDL_AudioStreamAvailable
+ * \sa SDL_AudioStreamFlush
+ * \sa SDL_AudioStreamClear
+ */
+extern DECLSPEC void SDLCALL SDL_FreeAudioStream(SDL_AudioStream *stream);
+
#define SDL_MIX_MAXVOLUME 128
/**
* This takes two audio buffers of the playing audio format and mixes
@@ -532,7 +667,7 @@ extern DECLSPEC void SDLCALL SDL_MixAudioFormat(Uint8 * dst,
* \param dev The device ID to which we will queue audio.
* \param data The data to queue to the device for later playback.
* \param len The number of bytes (not samples!) to which (data) points.
- * \return zero on success, -1 on error.
+ * \return 0 on success, or -1 on error.
*
* \sa SDL_GetQueuedAudioSize
* \sa SDL_ClearQueuedAudio
diff --git a/include/SDL_config.h.cmake b/include/SDL_config.h.cmake
index 9befa422f1..9b20398d0d 100644
--- a/include/SDL_config.h.cmake
+++ b/include/SDL_config.h.cmake
@@ -72,6 +72,7 @@
#cmakedefine HAVE_SYS_TYPES_H 1
#cmakedefine HAVE_WCHAR_H 1
#cmakedefine HAVE_PTHREAD_NP_H 1
+#cmakedefine HAVE_LIBUNWIND_H 1
/* C library functions */
#cmakedefine HAVE_MALLOC 1
@@ -99,7 +100,6 @@
#cmakedefine HAVE_STRLEN 1
#cmakedefine HAVE_STRLCPY 1
#cmakedefine HAVE_STRLCAT 1
-#cmakedefine HAVE_STRDUP 1
#cmakedefine HAVE__STRREV 1
#cmakedefine HAVE__STRUPR 1
#cmakedefine HAVE__STRLWR 1
diff --git a/include/SDL_config.h.in b/include/SDL_config.h.in
index 988d3d93d0..a28e83ff07 100644
--- a/include/SDL_config.h.in
+++ b/include/SDL_config.h.in
@@ -75,6 +75,7 @@
#undef HAVE_SYS_TYPES_H
#undef HAVE_WCHAR_H
#undef HAVE_PTHREAD_NP_H
+#undef HAVE_LIBUNWIND_H
/* C library functions */
#undef HAVE_MALLOC
@@ -102,7 +103,6 @@
#undef HAVE_STRLEN
#undef HAVE_STRLCPY
#undef HAVE_STRLCAT
-#undef HAVE_STRDUP
#undef HAVE__STRREV
#undef HAVE__STRUPR
#undef HAVE__STRLWR
diff --git a/include/SDL_config_android.h b/include/SDL_config_android.h
index c3169e557c..f2182165dc 100644
--- a/include/SDL_config_android.h
+++ b/include/SDL_config_android.h
@@ -68,7 +68,6 @@
#define HAVE_STRLEN 1
#define HAVE_STRLCPY 1
#define HAVE_STRLCAT 1
-#define HAVE_STRDUP 1
#define HAVE_STRCHR 1
#define HAVE_STRRCHR 1
#define HAVE_STRSTR 1
diff --git a/include/SDL_config_iphoneos.h b/include/SDL_config_iphoneos.h
index 94ab6933c4..38dcd9a77d 100644
--- a/include/SDL_config_iphoneos.h
+++ b/include/SDL_config_iphoneos.h
@@ -44,6 +44,7 @@
#define HAVE_STDIO_H 1
#define HAVE_STRING_H 1
#define HAVE_SYS_TYPES_H 1
+#define HAVE_LIBUNWIND_H 1
/* C library functions */
#define HAVE_MALLOC 1
@@ -66,7 +67,6 @@
#define HAVE_STRLEN 1
#define HAVE_STRLCPY 1
#define HAVE_STRLCAT 1
-#define HAVE_STRDUP 1
#define HAVE_STRCHR 1
#define HAVE_STRRCHR 1
#define HAVE_STRSTR 1
diff --git a/include/SDL_config_macosx.h b/include/SDL_config_macosx.h
index 67f879a492..f75507894e 100644
--- a/include/SDL_config_macosx.h
+++ b/include/SDL_config_macosx.h
@@ -49,6 +49,7 @@
#define HAVE_STDIO_H 1
#define HAVE_STRING_H 1
#define HAVE_SYS_TYPES_H 1
+#define HAVE_LIBUNWIND_H 1
/* C library functions */
#define HAVE_MALLOC 1
@@ -70,7 +71,6 @@
#define HAVE_STRLEN 1
#define HAVE_STRLCPY 1
#define HAVE_STRLCAT 1
-#define HAVE_STRDUP 1
#define HAVE_STRCHR 1
#define HAVE_STRRCHR 1
#define HAVE_STRSTR 1
diff --git a/include/SDL_config_pandora.h b/include/SDL_config_pandora.h
index f6f52fc11e..f421c74a88 100644
--- a/include/SDL_config_pandora.h
+++ b/include/SDL_config_pandora.h
@@ -70,7 +70,6 @@
#define HAVE_MEMCPY 1
#define HAVE_MEMMOVE 1
#define HAVE_STRLEN 1
-#define HAVE_STRDUP 1
#define HAVE_STRCHR 1
#define HAVE_STRRCHR 1
#define HAVE_STRSTR 1
diff --git a/include/SDL_config_psp.h b/include/SDL_config_psp.h
index 0e61979066..b76cf7de22 100644
--- a/include/SDL_config_psp.h
+++ b/include/SDL_config_psp.h
@@ -66,7 +66,6 @@
#define HAVE_STRLEN 1
#define HAVE_STRLCPY 1
#define HAVE_STRLCAT 1
-#define HAVE_STRDUP 1
#define HAVE_STRCHR 1
#define HAVE_STRRCHR 1
#define HAVE_STRSTR 1
diff --git a/include/SDL_config_wiz.h b/include/SDL_config_wiz.h
index 3afd8d8af4..0c8f02d8b7 100644
--- a/include/SDL_config_wiz.h
+++ b/include/SDL_config_wiz.h
@@ -64,7 +64,6 @@
#define HAVE_MEMCPY 1
#define HAVE_MEMMOVE 1
#define HAVE_STRLEN 1
-#define HAVE_STRDUP 1
#define HAVE_STRCHR 1
#define HAVE_STRRCHR 1
#define HAVE_STRSTR 1
diff --git a/include/SDL_joystick.h b/include/SDL_joystick.h
index 698b09c142..f598dc828d 100644
--- a/include/SDL_joystick.h
+++ b/include/SDL_joystick.h
@@ -106,6 +106,20 @@ typedef enum
} SDL_JoystickPowerLevel;
/* Function prototypes */
+
+/**
+ * Locking for multi-threaded access to the joystick API
+ *
+ * If you are using the joystick API or handling events from multiple threads
+ * you should use these locking functions to protect access to the joysticks.
+ *
+ * In particular, you are guaranteed that the joystick list won't change, so
+ * the API functions that take a joystick index will be valid, and joystick
+ * and game controller events will not be delivered.
+ */
+extern DECLSPEC void SDLCALL SDL_LockJoysticks(void);
+extern DECLSPEC void SDLCALL SDL_UnlockJoysticks(void);
+
/**
* Count the number of joysticks attached to the system right now
*/
diff --git a/include/SDL_stdinc.h b/include/SDL_stdinc.h
index 546544f10d..72402299f2 100644
--- a/include/SDL_stdinc.h
+++ b/include/SDL_stdinc.h
@@ -146,35 +146,51 @@ typedef enum
/**
* \brief A signed 8-bit integer type.
*/
+#define SDL_MAX_SINT8 ((Sint8)0x7F) /* 127 */
+#define SDL_MIN_SINT8 ((Sint8)(~0x7F)) /* -128 */
typedef int8_t Sint8;
/**
* \brief An unsigned 8-bit integer type.
*/
+#define SDL_MAX_UINT8 ((Uint8)0xFF) /* 255 */
+#define SDL_MIN_UINT8 ((Uint8)0x00) /* 0 */
typedef uint8_t Uint8;
/**
* \brief A signed 16-bit integer type.
*/
+#define SDL_MAX_SINT16 ((Sint16)0x7FFF) /* 32767 */
+#define SDL_MIN_SINT16 ((Sint16)(~0x7FFF)) /* -32768 */
typedef int16_t Sint16;
/**
* \brief An unsigned 16-bit integer type.
*/
+#define SDL_MAX_UINT16 ((Uint16)0xFFFF) /* 65535 */
+#define SDL_MIN_UINT16 ((Uint16)0x0000) /* 0 */
typedef uint16_t Uint16;
/**
* \brief A signed 32-bit integer type.
*/
+#define SDL_MAX_SINT32 ((Sint32)0x7FFFFFFF) /* 2147483647 */
+#define SDL_MIN_SINT32 ((Sint32)(~0x7FFFFFFF)) /* -2147483648 */
typedef int32_t Sint32;
/**
* \brief An unsigned 32-bit integer type.
*/
+#define SDL_MAX_UINT32 ((Uint32)0xFFFFFFFFu) /* 4294967295 */
+#define SDL_MIN_UINT32 ((Uint32)0x00000000) /* 0 */
typedef uint32_t Uint32;
/**
* \brief A signed 64-bit integer type.
*/
+#define SDL_MAX_SINT64 ((Sint64)0x7FFFFFFFFFFFFFFFll) /* 9223372036854775807 */
+#define SDL_MIN_SINT64 ((Sint64)(~0x7FFFFFFFFFFFFFFFll)) /* -9223372036854775808 */
typedef int64_t Sint64;
/**
* \brief An unsigned 64-bit integer type.
*/
+#define SDL_MAX_UINT64 ((Uint64)0xFFFFFFFFFFFFFFFFull) /* 18446744073709551615 */
+#define SDL_MIN_UINT64 ((Uint64)(0x0000000000000000ull)) /* 0 */
typedef uint64_t Uint64;
/* @} *//* Basic data types */
@@ -347,6 +363,37 @@ extern DECLSPEC void *SDLCALL SDL_calloc(size_t nmemb, size_t size);
extern DECLSPEC void *SDLCALL SDL_realloc(void *mem, size_t size);
extern DECLSPEC void SDLCALL SDL_free(void *mem);
+typedef void *(SDLCALL *SDL_malloc_func)(size_t size);
+typedef void *(SDLCALL *SDL_calloc_func)(size_t nmemb, size_t size);
+typedef void *(SDLCALL *SDL_realloc_func)(void *mem, size_t size);
+typedef void (SDLCALL *SDL_free_func)(void *mem);
+
+/**
+ * \brief Get the current set of SDL memory functions
+ */
+extern DECLSPEC void SDLCALL SDL_GetMemoryFunctions(SDL_malloc_func *malloc_func,
+ SDL_calloc_func *calloc_func,
+ SDL_realloc_func *realloc_func,
+ SDL_free_func *free_func);
+
+/**
+ * \brief Replace SDL's memory allocation functions with a custom set
+ *
+ * \note If you are replacing SDL's memory functions, you should call
+ * SDL_GetNumAllocations() and be very careful if it returns non-zero.
+ * That means that your free function will be called with memory
+ * allocated by the previous memory allocation functions.
+ */
+extern DECLSPEC int SDLCALL SDL_SetMemoryFunctions(SDL_malloc_func malloc_func,
+ SDL_calloc_func calloc_func,
+ SDL_realloc_func realloc_func,
+ SDL_free_func free_func);
+
+/**
+ * \brief Get the number of outstanding (unfreed) allocations
+ */
+extern DECLSPEC int SDLCALL SDL_GetNumAllocations(void);
+
extern DECLSPEC char *SDLCALL SDL_getenv(const char *name);
extern DECLSPEC int SDLCALL SDL_setenv(const char *name, const char *value, int overwrite);
diff --git a/include/SDL_test.h b/include/SDL_test.h
index 62c1be37bf..f55afcb022 100644
--- a/include/SDL_test.h
+++ b/include/SDL_test.h
@@ -31,17 +31,18 @@
#define SDL_test_h_
#include "SDL.h"
+#include "SDL_test_assert.h"
#include "SDL_test_common.h"
+#include "SDL_test_compare.h"
+#include "SDL_test_crc32.h"
#include "SDL_test_font.h"
-#include "SDL_test_random.h"
#include "SDL_test_fuzzer.h"
-#include "SDL_test_crc32.h"
-#include "SDL_test_md5.h"
-#include "SDL_test_log.h"
-#include "SDL_test_assert.h"
#include "SDL_test_harness.h"
#include "SDL_test_images.h"
-#include "SDL_test_compare.h"
+#include "SDL_test_log.h"
+#include "SDL_test_md5.h"
+#include "SDL_test_memory.h"
+#include "SDL_test_random.h"
#include "begin_code.h"
/* Set up for C function definitions, even when using C++ */
diff --git a/include/SDL_test_crc32.h b/include/SDL_test_crc32.h
index 65aa64edb3..add480c349 100644
--- a/include/SDL_test_crc32.h
+++ b/include/SDL_test_crc32.h
@@ -93,7 +93,7 @@ extern "C" {
* \returns 0 for OK, -1 on error
*
*/
-int SDLTest_crc32Calc(SDLTest_Crc32Context * crcContext, CrcUint8 *inBuf, CrcUint32 inLen, CrcUint32 *crc32);
+int SDLTest_Crc32Calc(SDLTest_Crc32Context * crcContext, CrcUint8 *inBuf, CrcUint32 inLen, CrcUint32 *crc32);
/* Same routine broken down into three steps */
int SDLTest_Crc32CalcStart(SDLTest_Crc32Context * crcContext, CrcUint32 *crc32);
diff --git a/include/SDL_test_memory.h b/include/SDL_test_memory.h
new file mode 100644
index 0000000000..43b67f521b
--- /dev/null
+++ b/include/SDL_test_memory.h
@@ -0,0 +1,63 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2017 Sam Lantinga
+
+ 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_test_memory.h
+ *
+ * Include file for SDL test framework.
+ *
+ * This code is a part of the SDL2_test library, not the main SDL library.
+ */
+
+#ifndef SDL_test_memory_h_
+#define SDL_test_memory_h_
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/**
+ * \brief Start tracking SDL memory allocations
+ *
+ * \note This should be called before any other SDL functions for complete tracking coverage
+ */
+int SDLTest_TrackAllocations();
+
+/**
+ * \brief Print a log of any outstanding allocations
+ *
+ * \note This can be called after SDL_Quit()
+ */
+void SDLTest_LogAllocations();
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+}
+#endif
+#include "close_code.h"
+
+#endif /* SDL_test_memory_h_ */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/include/SDL_thread.h b/include/SDL_thread.h
index cf1ce492fa..d0f6575cd5 100644
--- a/include/SDL_thread.h
+++ b/include/SDL_thread.h
@@ -90,14 +90,11 @@ typedef int (SDLCALL * SDL_ThreadFunction) (void *data);
* library!
*/
#define SDL_PASSED_BEGINTHREAD_ENDTHREAD
-#include /* This has _beginthread() and _endthread() defined! */
-
-typedef uintptr_t(__cdecl * pfnSDL_CurrentBeginThread) (void *, unsigned,
- unsigned (__stdcall *
- func) (void
- *),
- void *arg, unsigned,
- unsigned *threadID);
+#include /* _beginthreadex() and _endthreadex() */
+
+typedef uintptr_t(__cdecl * pfnSDL_CurrentBeginThread)
+ (void *, unsigned, unsigned (__stdcall *func)(void *),
+ void * /*arg*/, unsigned, unsigned * /* threadID */);
typedef void (__cdecl * pfnSDL_CurrentEndThread) (unsigned code);
/**
@@ -124,7 +121,11 @@ SDL_CreateThread(SDL_ThreadFunction fn, const char *name, void *data,
* into a dll with Watcom's runtime statically linked.
*/
#define SDL_PASSED_BEGINTHREAD_ENDTHREAD
+#ifndef __EMX__
#include
+#else
+#include
+#endif
typedef int (*pfnSDL_CurrentBeginThread)(void (*func)(void *), void *, unsigned, void * /*arg*/);
typedef void (*pfnSDL_CurrentEndThread)(void);
extern DECLSPEC SDL_Thread *SDLCALL
diff --git a/include/SDL_version.h b/include/SDL_version.h
index 8471b65438..5b4c402486 100644
--- a/include/SDL_version.h
+++ b/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 6
+#define SDL_PATCHLEVEL 7
/**
* \brief Macro to determine SDL version program was compiled against.
diff --git a/src/SDL_assert.c b/src/SDL_assert.c
index 47309eb7ce..1eca9232d2 100644
--- a/src/SDL_assert.c
+++ b/src/SDL_assert.c
@@ -278,19 +278,19 @@ SDL_PromptAssertion(const SDL_assert_data *data, void *userdata)
break;
}
- if (SDL_strcmp(buf, "a") == 0) {
+ if (SDL_strncmp(buf, "a", 1) == 0) {
state = SDL_ASSERTION_ABORT;
break;
- } else if (SDL_strcmp(buf, "b") == 0) {
+ } else if (SDL_strncmp(buf, "b", 1) == 0) {
state = SDL_ASSERTION_BREAK;
break;
- } else if (SDL_strcmp(buf, "r") == 0) {
+ } else if (SDL_strncmp(buf, "r", 1) == 0) {
state = SDL_ASSERTION_RETRY;
break;
- } else if (SDL_strcmp(buf, "i") == 0) {
+ } else if (SDL_strncmp(buf, "i", 1) == 0) {
state = SDL_ASSERTION_IGNORE;
break;
- } else if (SDL_strcmp(buf, "A") == 0) {
+ } else if (SDL_strncmp(buf, "A", 1) == 0) {
state = SDL_ASSERTION_ALWAYS_IGNORE;
break;
}
diff --git a/src/SDL_dataqueue.c b/src/SDL_dataqueue.c
index db1adaad8e..84370fcbcc 100644
--- a/src/SDL_dataqueue.c
+++ b/src/SDL_dataqueue.c
@@ -225,6 +225,31 @@ SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *_data, const size_t _len)
return 0;
}
+size_t
+SDL_PeekIntoDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
+{
+ size_t len = _len;
+ Uint8 *buf = (Uint8 *) _buf;
+ Uint8 *ptr = buf;
+ SDL_DataQueuePacket *packet;
+
+ if (!queue) {
+ return 0;
+ }
+
+ for (packet = queue->head; len && packet; packet = packet->next) {
+ const size_t avail = packet->datalen - packet->startpos;
+ const size_t cpy = SDL_min(len, avail);
+ SDL_assert(queue->queued_bytes >= avail);
+
+ SDL_memcpy(ptr, packet->data + packet->startpos, cpy);
+ ptr += cpy;
+ len -= cpy;
+ }
+
+ return (size_t) (ptr - buf);
+}
+
size_t
SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *_buf, const size_t _len)
{
diff --git a/src/SDL_dataqueue.h b/src/SDL_dataqueue.h
index a5e3e1c60e..8f135c0cfc 100644
--- a/src/SDL_dataqueue.h
+++ b/src/SDL_dataqueue.h
@@ -31,6 +31,7 @@ void SDL_FreeDataQueue(SDL_DataQueue *queue);
void SDL_ClearDataQueue(SDL_DataQueue *queue, const size_t slack);
int SDL_WriteToDataQueue(SDL_DataQueue *queue, const void *data, const size_t len);
size_t SDL_ReadFromDataQueue(SDL_DataQueue *queue, void *buf, const size_t len);
+size_t SDL_PeekIntoDataQueue(SDL_DataQueue *queue, void *buf, const size_t len);
size_t SDL_CountDataQueue(SDL_DataQueue *queue);
/* this sets a section of the data queue aside (possibly allocating memory for it)
diff --git a/src/audio/SDL_audio_c.h b/src/audio/SDL_audio_c.h
index 58ecf10a5e..38c5bbb77d 100644
--- a/src/audio/SDL_audio_c.h
+++ b/src/audio/SDL_audio_c.h
@@ -74,46 +74,6 @@ extern SDL_AudioFilter SDL_Convert_F32_to_S32;
extern int SDL_PrepareResampleFilter(void);
extern void SDL_FreeResampleFilter(void);
-
-/* SDL_AudioStream is a new audio conversion interface. It
- might eventually become a public API.
- The benefits vs SDL_AudioCVT:
- - it can handle resampling data in chunks without generating
- artifacts, when it doesn't have the complete buffer available.
- - it can handle incoming data in any variable size.
- - You push data as you have it, and pull it when you need it
-
- (Note that currently this converts as data is put into the stream, so
- you need to push more than a handful of bytes if you want decent
- resampling. This can be changed later.)
- */
-
-/* this is opaque to the outside world. */
-typedef struct SDL_AudioStream SDL_AudioStream;
-
-/* create a new stream */
-extern SDL_AudioStream *SDL_NewAudioStream(const SDL_AudioFormat src_format,
- const Uint8 src_channels,
- const int src_rate,
- const SDL_AudioFormat dst_format,
- const Uint8 dst_channels,
- const int dst_rate);
-
-/* add data to be converted/resampled to the stream */
-extern int SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 len);
-
-/* get converted/resampled data from the stream */
-extern int SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, const Uint32 len);
-
-/* clear any pending data in the stream without converting it. */
-extern void SDL_AudioStreamClear(SDL_AudioStream *stream);
-
-/* number of converted/resampled bytes available */
-extern int SDL_AudioStreamAvailable(SDL_AudioStream *stream);
-
-/* dispose of a stream */
-extern void SDL_FreeAudioStream(SDL_AudioStream *stream);
-
#endif /* SDL_audio_c_h_ */
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/audio/SDL_audiocvt.c b/src/audio/SDL_audiocvt.c
index 4b24ccdb39..d270ab9af1 100644
--- a/src/audio/SDL_audiocvt.c
+++ b/src/audio/SDL_audiocvt.c
@@ -22,6 +22,9 @@
/* Functions for audio drivers to perform runtime conversion of audio format */
+/* FIXME: Channel weights when converting from more channels to fewer may need to be adjusted, see https://msdn.microsoft.com/en-us/library/windows/desktop/ff819070(v=vs.85).aspx
+*/
+
#include "SDL.h"
#include "SDL_audio.h"
#include "SDL_audio_c.h"
@@ -31,6 +34,8 @@
#include "../SDL_dataqueue.h"
#include "SDL_cpuinfo.h"
+#define DEBUG_AUDIOSTREAM 0
+
#ifdef __SSE3__
#define HAVE_SSE3_INTRINSICS 1
#endif
@@ -134,7 +139,7 @@ SDL_ConvertQuadToStereo(SDL_AudioCVT * cvt, SDL_AudioFormat format)
dst[1] = (src[1] + src[3]) * 0.5f; /* right */
}
- cvt->len_cvt /= 3;
+ cvt->len_cvt /= 2;
if (cvt->filters[++cvt->filter_index]) {
cvt->filters[cvt->filter_index] (cvt, format);
}
@@ -467,37 +472,42 @@ SDL_FreeResampleFilter(void)
static int
ResamplerPadding(const int inrate, const int outrate)
{
- return (inrate > outrate) ? (int) SDL_ceil(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate))) : RESAMPLER_SAMPLES_PER_ZERO_CROSSING;
+ if (inrate == outrate) {
+ return 0;
+ } else if (inrate > outrate) {
+ return (int) SDL_ceil(((float) (RESAMPLER_SAMPLES_PER_ZERO_CROSSING * inrate) / ((float) outrate)));
+ }
+ return RESAMPLER_SAMPLES_PER_ZERO_CROSSING;
}
/* lpadding and rpadding are expected to be buffers of (ResamplePadding(inrate, outrate) * chans * sizeof (float)) bytes. */
static int
SDL_ResampleAudio(const int chans, const int inrate, const int outrate,
- float *lpadding, float *rpadding, const float *inbuf,
- const int inbuflen, float *outbuf, const int outbuflen)
+ const float *lpadding, const float *rpadding,
+ const float *inbuf, const int inbuflen,
+ float *outbuf, const int outbuflen)
{
- const float outtimeincr = 1.0f / ((float) outrate);
- const float ratio = ((float) outrate) / ((float) inrate);
+ const double finrate = (double) inrate;
+ const double outtimeincr = 1.0 / ((float) outrate);
+ const double ratio = ((float) outrate) / ((float) inrate);
const int paddinglen = ResamplerPadding(inrate, outrate);
const int framelen = chans * (int)sizeof (float);
const int inframes = inbuflen / framelen;
const int wantedoutframes = (int) ((inbuflen / framelen) * ratio); /* outbuflen isn't total to write, it's total available. */
const int maxoutframes = outbuflen / framelen;
- const int outframes = (wantedoutframes < maxoutframes) ? wantedoutframes : maxoutframes;
+ const int outframes = SDL_min(wantedoutframes, maxoutframes);
float *dst = outbuf;
- float outtime = 0.0f;
+ double outtime = 0.0;
int i, j, chan;
for (i = 0; i < outframes; i++) {
const int srcindex = (int) (outtime * inrate);
- const float finrate = (float) inrate;
- const float intime = ((float) srcindex) / finrate;
- const float innexttime = ((float) (srcindex + 1)) / finrate;
-
- const float interpolation1 = 1.0f - (innexttime - outtime) / (innexttime - intime);
+ const double intime = ((double) srcindex) / finrate;
+ const double innexttime = ((double) (srcindex + 1)) / finrate;
+ const double interpolation1 = 1.0 - ((innexttime - outtime) / (innexttime - intime));
const int filterindex1 = (int) (interpolation1 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING);
- const float interpolation2 = 1.0f - interpolation1;
- const int filterindex2 = interpolation2 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING;
+ const double interpolation2 = 1.0 - interpolation1;
+ const int filterindex2 = (int) (interpolation2 * RESAMPLER_SAMPLES_PER_ZERO_CROSSING);
for (chan = 0; chan < chans; chan++) {
float outsample = 0.0f;
@@ -508,14 +518,14 @@ SDL_ResampleAudio(const int chans, const int inrate, const int outrate,
const int srcframe = srcindex - j;
/* !!! FIXME: we can bubble this conditional out of here by doing a pre loop. */
const float insample = (srcframe < 0) ? lpadding[((paddinglen + srcframe) * chans) + chan] : inbuf[(srcframe * chans) + chan];
- outsample += (insample * (ResamplerFilter[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation1 * ResamplerFilterDifference[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
+ outsample += (float)(insample * (ResamplerFilter[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation1 * ResamplerFilterDifference[filterindex1 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
}
for (j = 0; (filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)) < RESAMPLER_FILTER_SIZE; j++) {
const int srcframe = srcindex + 1 + j;
/* !!! FIXME: we can bubble this conditional out of here by doing a post loop. */
const float insample = (srcframe >= inframes) ? rpadding[((srcframe - inframes) * chans) + chan] : inbuf[(srcframe * chans) + chan];
- outsample += (insample * (ResamplerFilter[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation2 * ResamplerFilterDifference[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
+ outsample += (float)(insample * (ResamplerFilter[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)] + (interpolation2 * ResamplerFilterDifference[filterindex2 + (j * RESAMPLER_SAMPLES_PER_ZERO_CROSSING)])));
}
*(dst++) = outsample;
}
@@ -714,18 +724,17 @@ SDL_ResampleCVT(SDL_AudioCVT *cvt, const int chans, const SDL_AudioFormat format
SDL_assert(format == AUDIO_F32SYS);
/* we keep no streaming state here, so pad with silence on both ends. */
- padding = SDL_stack_alloc(float, paddingsamples);
+ padding = (float *) SDL_calloc(paddingsamples, sizeof (float));
if (!padding) {
SDL_OutOfMemory();
return;
}
- SDL_memset(padding, '\0', paddingsamples * sizeof (float));
cvt->len_cvt = SDL_ResampleAudio(chans, inrate, outrate, padding, padding, src, srclen, dst, dstlen);
- SDL_stack_free(padding);
+ SDL_free(padding);
- SDL_memcpy(cvt->buf, dst, cvt->len_cvt); /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
+ SDL_memmove(cvt->buf, dst, cvt->len_cvt); /* !!! FIXME: remove this if we can get the resampler to work in-place again. */
if (cvt->filters[++cvt->filter_index]) {
cvt->filters[cvt->filter_index](cvt, format);
@@ -1071,11 +1080,15 @@ typedef int (*SDL_ResampleAudioStreamFunc)(SDL_AudioStream *stream, const void *
typedef void (*SDL_ResetAudioStreamResamplerFunc)(SDL_AudioStream *stream);
typedef void (*SDL_CleanupAudioStreamResamplerFunc)(SDL_AudioStream *stream);
-struct SDL_AudioStream
+struct _SDL_AudioStream
{
SDL_AudioCVT cvt_before_resampling;
SDL_AudioCVT cvt_after_resampling;
SDL_DataQueue *queue;
+ SDL_bool first_run;
+ Uint8 *staging_buffer;
+ int staging_buffer_size;
+ int staging_buffer_filled;
Uint8 *work_buffer_base; /* maybe unaligned pointer from SDL_realloc(). */
int work_buffer_len;
int src_sample_frame_size;
@@ -1089,6 +1102,8 @@ struct SDL_AudioStream
double rate_incr;
Uint8 pre_resample_channels;
int packetlen;
+ int resampler_padding_samples;
+ float *resampler_padding;
void *resampler_state;
SDL_ResampleAudioStreamFunc resampler_func;
SDL_ResetAudioStreamResamplerFunc reset_resampler_func;
@@ -1129,16 +1144,7 @@ SDL_ResampleAudioStream_SRC(SDL_AudioStream *stream, const void *_inbuf, const i
SRC_DATA data;
int result;
- if (inbuf == ((const float *) outbuf)) { /* libsamplerate can't work in-place. */
- Uint8 *ptr = EnsureStreamBufferSize(stream, inbuflen + outbuflen);
- if (ptr == NULL) {
- SDL_OutOfMemory();
- return 0;
- }
- SDL_memcpy(ptr + outbuflen, ptr, inbuflen);
- inbuf = (const float *) (ptr + outbuflen);
- outbuf = (float *) ptr;
- }
+ SDL_assert(inbuf != ((const float *) outbuf)); /* SDL_AudioStreamPut() shouldn't allow in-place resamples. */
data.data_in = (float *)inbuf; /* Older versions of libsamplerate had a non-const pointer, but didn't write to it */
data.input_frames = inbuflen / framelen;
@@ -1213,54 +1219,33 @@ SetupLibSampleRateResampling(SDL_AudioStream *stream)
static int
SDL_ResampleAudioStream(SDL_AudioStream *stream, const void *_inbuf, const int inbuflen, void *_outbuf, const int outbuflen)
{
+ const Uint8 *inbufend = ((const Uint8 *) _inbuf) + inbuflen;
const float *inbuf = (const float *) _inbuf;
float *outbuf = (float *) _outbuf;
const int chans = (int) stream->pre_resample_channels;
const int inrate = stream->src_rate;
const int outrate = stream->dst_rate;
- const int paddingsamples = ResamplerPadding(inrate, outrate) * chans;
+ const int paddingsamples = stream->resampler_padding_samples;
const int paddingbytes = paddingsamples * sizeof (float);
float *lpadding = (float *) stream->resampler_state;
- float *rpadding;
+ const float *rpadding = (const float *) inbufend; /* we set this up so there are valid padding samples at the end of the input buffer. */
+ const int cpy = SDL_min(inbuflen, paddingbytes);
int retval;
- if (inbuf == ((const float *) outbuf)) { /* !!! FIXME can't work in-place (for now!). */
- Uint8 *ptr = EnsureStreamBufferSize(stream, inbuflen + outbuflen);
- if (ptr == NULL) {
- SDL_OutOfMemory();
- return 0;
- }
- SDL_memcpy(ptr + outbuflen, ptr, inbuflen);
- inbuf = (const float *) (ptr + outbuflen);
- outbuf = (float *) ptr;
- }
-
- /* !!! FIXME: streaming current resamples on Put, because of probably good reasons I can't remember right now, but if we resample on Get, we'd be able to access legit right padding values. */
- rpadding = SDL_stack_alloc(float, paddingsamples);
- if (!rpadding) {
- SDL_OutOfMemory();
- return 0;
- }
- SDL_memset(rpadding, '\0', paddingbytes);
+ SDL_assert(inbuf != ((const float *) outbuf)); /* SDL_AudioStreamPut() shouldn't allow in-place resamples. */
retval = SDL_ResampleAudio(chans, inrate, outrate, lpadding, rpadding, inbuf, inbuflen, outbuf, outbuflen);
- SDL_stack_free(rpadding);
-
/* update our left padding with end of current input, for next run. */
- SDL_memcpy(lpadding, ((const Uint8 *) inbuf) + (inbuflen - paddingbytes), paddingbytes);
-
+ SDL_memcpy((lpadding + paddingsamples) - (cpy / sizeof (float)), inbufend - cpy, cpy);
return retval;
}
static void
SDL_ResetAudioStreamResampler(SDL_AudioStream *stream)
{
- /* set all the left padding to silence. */
- const int inrate = stream->src_rate;
- const int outrate = stream->dst_rate;
- const int chans = (int) stream->pre_resample_channels;
- const int len = ResamplerPadding(inrate, outrate) * chans;
+ /* set all the padding to silence. */
+ const int len = stream->resampler_padding_samples;
SDL_memset(stream->resampler_state, '\0', len * sizeof (float));
}
@@ -1293,6 +1278,7 @@ SDL_NewAudioStream(const SDL_AudioFormat src_format,
the resampled data (!!! FIXME: decide if that works in practice, though!). */
pre_resample_channels = SDL_min(src_channels, dst_channels);
+ retval->first_run = SDL_TRUE;
retval->src_sample_frame_size = (SDL_AUDIO_BITSIZE(src_format) / 8) * src_channels;
retval->src_format = src_format;
retval->src_channels = src_channels;
@@ -1304,8 +1290,26 @@ SDL_NewAudioStream(const SDL_AudioFormat src_format,
retval->pre_resample_channels = pre_resample_channels;
retval->packetlen = packetlen;
retval->rate_incr = ((double) dst_rate) / ((double) src_rate);
+ retval->resampler_padding_samples = ResamplerPadding(retval->src_rate, retval->dst_rate) * pre_resample_channels;
+ retval->resampler_padding = (float *) SDL_calloc(retval->resampler_padding_samples, sizeof (float));
+
+ if (retval->resampler_padding == NULL) {
+ SDL_FreeAudioStream(retval);
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+ retval->staging_buffer_size = ((retval->resampler_padding_samples / retval->pre_resample_channels) * retval->src_sample_frame_size);
+ if (retval->staging_buffer_size > 0) {
+ retval->staging_buffer = (Uint8 *) SDL_malloc(retval->staging_buffer_size);
+ if (retval->staging_buffer == NULL) {
+ SDL_FreeAudioStream(retval);
+ SDL_OutOfMemory();
+ return NULL;
+ }
+ }
- /* Not resampling? It's an easy conversion (and maybe not even that!). */
+ /* Not resampling? It's an easy conversion (and maybe not even that!) */
if (src_rate == dst_rate) {
retval->cvt_before_resampling.needed = SDL_FALSE;
if (SDL_BuildAudioCVT(&retval->cvt_after_resampling, src_format, src_channels, dst_rate, dst_format, dst_channels, dst_rate) < 0) {
@@ -1325,9 +1329,7 @@ SDL_NewAudioStream(const SDL_AudioFormat src_format,
#endif
if (!retval->resampler_func) {
- const int chans = (int) pre_resample_channels;
- const int len = ResamplerPadding(src_rate, dst_rate) * chans;
- retval->resampler_state = SDL_calloc(len, sizeof (float));
+ retval->resampler_state = SDL_calloc(retval->resampler_padding_samples, sizeof (float));
if (!retval->resampler_state) {
SDL_FreeAudioStream(retval);
SDL_OutOfMemory();
@@ -1362,11 +1364,16 @@ SDL_NewAudioStream(const SDL_AudioFormat src_format,
return retval;
}
-int
-SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _buflen)
+static int
+SDL_AudioStreamPutInternal(SDL_AudioStream *stream, const void *buf, int len, int *maxputbytes)
{
- int buflen = (int) _buflen;
- const void *origbuf = buf;
+ int buflen = len;
+ int workbuflen;
+ Uint8 *workbuf;
+ Uint8 *resamplebuf = NULL;
+ int resamplebuflen = 0;
+ int neededpaddingbytes;
+ int paddingbytes;
/* !!! FIXME: several converters can take advantage of SIMD, but only
!!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize()
@@ -1376,93 +1383,246 @@ SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, const Uint32 _bufle
!!! FIXME: isn't a multiple of 16. In these cases, we should chop off
!!! FIXME: a few samples at the end and convert them separately. */
- if (!stream) {
- return SDL_InvalidParamError("stream");
- } else if (!buf) {
- return SDL_InvalidParamError("buf");
- } else if (buflen == 0) {
- return 0; /* nothing to do. */
- } else if ((buflen % stream->src_sample_frame_size) != 0) {
- return SDL_SetError("Can't add partial sample frames");
+ /* no padding prepended on first run. */
+ neededpaddingbytes = stream->resampler_padding_samples * sizeof (float);
+ paddingbytes = stream->first_run ? 0 : neededpaddingbytes;
+ stream->first_run = SDL_FALSE;
+
+ /* Make sure the work buffer can hold all the data we need at once... */
+ workbuflen = buflen;
+ if (stream->cvt_before_resampling.needed) {
+ workbuflen *= stream->cvt_before_resampling.len_mult;
}
+ if (stream->dst_rate != stream->src_rate) {
+ /* resamples can't happen in place, so make space for second buf. */
+ const int framesize = stream->pre_resample_channels * sizeof (float);
+ const int frames = workbuflen / framesize;
+ resamplebuflen = ((int) SDL_ceil(frames * stream->rate_incr)) * framesize;
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: will resample %d bytes to %d (ratio=%.6f)\n", workbuflen, resamplebuflen, stream->rate_incr);
+ #endif
+ workbuflen += resamplebuflen;
+ }
+
+ if (stream->cvt_after_resampling.needed) {
+ /* !!! FIXME: buffer might be big enough already? */
+ workbuflen *= stream->cvt_after_resampling.len_mult;
+ }
+
+ workbuflen += neededpaddingbytes;
+
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: Putting %d bytes of preconverted audio, need %d byte work buffer\n", buflen, workbuflen);
+ #endif
+
+ workbuf = EnsureStreamBufferSize(stream, workbuflen);
+ if (!workbuf) {
+ return -1; /* probably out of memory. */
+ }
+
+ resamplebuf = workbuf; /* default if not resampling. */
+
+ SDL_memcpy(workbuf + paddingbytes, buf, buflen);
+
if (stream->cvt_before_resampling.needed) {
- const int workbuflen = buflen * stream->cvt_before_resampling.len_mult; /* will be "* 1" if not needed */
- Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
- if (workbuf == NULL) {
- return -1; /* probably out of memory. */
- }
- SDL_assert(buf == origbuf);
- SDL_memcpy(workbuf, buf, buflen);
- stream->cvt_before_resampling.buf = workbuf;
+ stream->cvt_before_resampling.buf = workbuf + paddingbytes;
stream->cvt_before_resampling.len = buflen;
if (SDL_ConvertAudio(&stream->cvt_before_resampling) == -1) {
return -1; /* uhoh! */
}
- buf = workbuf;
buflen = stream->cvt_before_resampling.len_cvt;
+
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: After initial conversion we have %d bytes\n", buflen);
+ #endif
}
if (stream->dst_rate != stream->src_rate) {
- const int workbuflen = buflen * ((int) SDL_ceil(stream->rate_incr));
- Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
- if (workbuf == NULL) {
- return -1; /* probably out of memory. */
+ /* save off some samples at the end; they are used for padding now so
+ the resampler is coherent and then used at the start of the next
+ put operation. Prepend last put operation's padding, too. */
+
+ /* prepend prior put's padding. :P */
+ if (paddingbytes) {
+ SDL_memcpy(workbuf, stream->resampler_padding, paddingbytes);
+ buflen += paddingbytes;
}
- /* don't SDL_memcpy(workbuf, buf, buflen) here; our resampler can work inplace or not,
- libsamplerate needs buffers to be separate; either way, avoid a copy here if possible. */
- if (buf != origbuf) {
- buf = workbuf; /* in case we realloc()'d the pointer. */
+
+ /* save off the data at the end for the next run. */
+ SDL_memcpy(stream->resampler_padding, workbuf + (buflen - neededpaddingbytes), neededpaddingbytes);
+
+ resamplebuf = workbuf + buflen; /* skip to second piece of workbuf. */
+ SDL_assert(buflen >= neededpaddingbytes);
+ if (buflen > neededpaddingbytes) {
+ buflen = stream->resampler_func(stream, workbuf, buflen - neededpaddingbytes, resamplebuf, resamplebuflen);
+ } else {
+ buflen = 0;
}
- buflen = stream->resampler_func(stream, buf, buflen, workbuf, workbuflen);
- buf = EnsureStreamBufferSize(stream, workbuflen);
- SDL_assert(buf != NULL); /* shouldn't be growing, just aligning. */
+
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: After resampling we have %d bytes\n", buflen);
+ #endif
}
- if (stream->cvt_after_resampling.needed) {
- const int workbuflen = buflen * stream->cvt_after_resampling.len_mult; /* will be "* 1" if not needed */
- Uint8 *workbuf = EnsureStreamBufferSize(stream, workbuflen);
- if (workbuf == NULL) {
- return -1; /* probably out of memory. */
- }
- if (buf == origbuf) { /* copy if we haven't before. */
- SDL_memcpy(workbuf, origbuf, buflen);
- }
- stream->cvt_after_resampling.buf = workbuf;
+ if (stream->cvt_after_resampling.needed && (buflen > 0)) {
+ stream->cvt_after_resampling.buf = resamplebuf;
stream->cvt_after_resampling.len = buflen;
if (SDL_ConvertAudio(&stream->cvt_after_resampling) == -1) {
return -1; /* uhoh! */
}
- buf = workbuf;
buflen = stream->cvt_after_resampling.len_cvt;
+
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: After final conversion we have %d bytes\n", buflen);
+ #endif
+ }
+
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: Final output is %d bytes\n", buflen);
+ #endif
+
+ if (maxputbytes) {
+ const int maxbytes = *maxputbytes;
+ if (buflen > maxbytes)
+ buflen = maxbytes;
+ *maxputbytes -= buflen;
}
- return SDL_WriteToDataQueue(stream->queue, buf, buflen);
+ /* resamplebuf holds the final output, even if we didn't resample. */
+ return buflen ? SDL_WriteToDataQueue(stream->queue, resamplebuf, buflen) : 0;
}
-void
-SDL_AudioStreamClear(SDL_AudioStream *stream)
+int
+SDL_AudioStreamPut(SDL_AudioStream *stream, const void *buf, int len)
{
+ /* !!! FIXME: several converters can take advantage of SIMD, but only
+ !!! FIXME: if the data is aligned to 16 bytes. EnsureStreamBufferSize()
+ !!! FIXME: guarantees the buffer will align, but the
+ !!! FIXME: converters will iterate over the data backwards if
+ !!! FIXME: the output grows, and this means we won't align if buflen
+ !!! FIXME: isn't a multiple of 16. In these cases, we should chop off
+ !!! FIXME: a few samples at the end and convert them separately. */
+
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: wants to put %d preconverted bytes\n", buflen);
+ #endif
+
if (!stream) {
- SDL_InvalidParamError("stream");
- } else {
- SDL_ClearDataQueue(stream->queue, stream->packetlen * 2);
- if (stream->reset_resampler_func) {
- stream->reset_resampler_func(stream);
+ return SDL_InvalidParamError("stream");
+ } else if (!buf) {
+ return SDL_InvalidParamError("buf");
+ } else if (len == 0) {
+ return 0; /* nothing to do. */
+ } else if ((len % stream->src_sample_frame_size) != 0) {
+ return SDL_SetError("Can't add partial sample frames");
+ }
+
+ if (!stream->cvt_before_resampling.needed &&
+ (stream->dst_rate == stream->src_rate) &&
+ !stream->cvt_after_resampling.needed) {
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: no conversion needed at all, queueing %d bytes.\n", len);
+ #endif
+ return SDL_WriteToDataQueue(stream->queue, buf, len);
+ }
+
+ while (len > 0) {
+ int amount;
+
+ /* If we don't have a staging buffer or we're given enough data that
+ we don't need to store it for later, skip the staging process.
+ */
+ if (!stream->staging_buffer_filled && len >= stream->staging_buffer_size) {
+ return SDL_AudioStreamPutInternal(stream, buf, len, NULL);
}
+
+ /* If there's not enough data to fill the staging buffer, just save it */
+ if ((stream->staging_buffer_filled + len) < stream->staging_buffer_size) {
+ SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, len);
+ stream->staging_buffer_filled += len;
+ return 0;
+ }
+
+ /* Fill the staging buffer, process it, and continue */
+ amount = (stream->staging_buffer_size - stream->staging_buffer_filled);
+ SDL_assert(amount > 0);
+ SDL_memcpy(stream->staging_buffer + stream->staging_buffer_filled, buf, amount);
+ stream->staging_buffer_filled = 0;
+ if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, NULL) < 0) {
+ return -1;
+ }
+ buf = (void *)((Uint8 *)buf + amount);
+ len -= amount;
}
+ return 0;
}
+int SDL_AudioStreamFlush(SDL_AudioStream *stream)
+{
+ if (!stream) {
+ return SDL_InvalidParamError("stream");
+ }
+
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: flushing! staging_buffer_filled=%d bytes\n", stream->staging_buffer_filled);
+ #endif
+
+ /* shouldn't use a staging buffer if we're not resampling. */
+ SDL_assert((stream->dst_rate != stream->src_rate) || (stream->staging_buffer_filled == 0));
+
+ if (stream->staging_buffer_filled > 0) {
+ /* push the staging buffer + silence. We need to flush out not just
+ the staging buffer, but the piece that the stream was saving off
+ for right-side resampler padding. */
+ const SDL_bool first_run = stream->first_run;
+ const int filled = stream->staging_buffer_filled;
+ int actual_input_frames = filled / stream->src_sample_frame_size;
+ if (!first_run)
+ actual_input_frames += stream->resampler_padding_samples / stream->pre_resample_channels;
+
+ if (actual_input_frames > 0) { /* don't bother if nothing to flush. */
+ /* This is how many bytes we're expecting without silence appended. */
+ int flush_remaining = ((int) SDL_ceil(actual_input_frames * stream->rate_incr)) * stream->dst_sample_frame_size;
+
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: flushing with padding to get max %d bytes!\n", flush_remaining);
+ #endif
+
+ SDL_memset(stream->staging_buffer + filled, '\0', stream->staging_buffer_size - filled);
+ if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
+ return -1;
+ }
+
+ /* we have flushed out (or initially filled) the pending right-side
+ resampler padding, but we need to push more silence to guarantee
+ the staging buffer is fully flushed out, too. */
+ SDL_memset(stream->staging_buffer, '\0', filled);
+ if (SDL_AudioStreamPutInternal(stream, stream->staging_buffer, stream->staging_buffer_size, &flush_remaining) < 0) {
+ return -1;
+ }
+ }
+ }
+
+ stream->staging_buffer_filled = 0;
+ stream->first_run = SDL_TRUE;
+
+ return 0;
+}
/* get converted/resampled data from the stream */
int
-SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, const Uint32 len)
+SDL_AudioStreamGet(SDL_AudioStream *stream, void *buf, int len)
{
+ #if DEBUG_AUDIOSTREAM
+ printf("AUDIOSTREAM: want to get %d converted bytes\n", len);
+ #endif
+
if (!stream) {
return SDL_InvalidParamError("stream");
} else if (!buf) {
return SDL_InvalidParamError("buf");
- } else if (len == 0) {
+ } else if (len <= 0) {
return 0; /* nothing to do. */
} else if ((len % stream->dst_sample_frame_size) != 0) {
return SDL_SetError("Can't request partial sample frames");
@@ -1478,6 +1638,21 @@ SDL_AudioStreamAvailable(SDL_AudioStream *stream)
return stream ? (int) SDL_CountDataQueue(stream->queue) : 0;
}
+void
+SDL_AudioStreamClear(SDL_AudioStream *stream)
+{
+ if (!stream) {
+ SDL_InvalidParamError("stream");
+ } else {
+ SDL_ClearDataQueue(stream->queue, stream->packetlen * 2);
+ if (stream->reset_resampler_func) {
+ stream->reset_resampler_func(stream);
+ }
+ stream->first_run = SDL_TRUE;
+ stream->staging_buffer_filled = 0;
+ }
+}
+
/* dispose of a stream */
void
SDL_FreeAudioStream(SDL_AudioStream *stream)
@@ -1487,7 +1662,9 @@ SDL_FreeAudioStream(SDL_AudioStream *stream)
stream->cleanup_resampler_func(stream);
}
SDL_FreeDataQueue(stream->queue);
+ SDL_free(stream->staging_buffer);
SDL_free(stream->work_buffer_base);
+ SDL_free(stream->resampler_padding);
SDL_free(stream);
}
}
diff --git a/src/audio/SDL_audiotypecvt.c b/src/audio/SDL_audiotypecvt.c
index 86f883c0b0..bd717f4cc2 100644
--- a/src/audio/SDL_audiotypecvt.c
+++ b/src/audio/SDL_audiotypecvt.c
@@ -170,7 +170,14 @@ SDL_Convert_F32_to_S8_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S8");
for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
- *dst = (Sint8) (*src * 127.0f);
+ const float sample = *src;
+ if (sample > 1.0f) {
+ *dst = 127;
+ } else if (sample < -1.0f) {
+ *dst = -127;
+ } else {
+ *dst = (Sint8)(sample * 127.0f);
+ }
}
cvt->len_cvt /= 4;
@@ -189,7 +196,14 @@ SDL_Convert_F32_to_U8_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U8");
for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
- *dst = (Uint8) ((*src + 1.0f) * 127.0f);
+ const float sample = *src;
+ if (sample > 1.0f) {
+ *dst = 255;
+ } else if (sample < -1.0f) {
+ *dst = 0;
+ } else {
+ *dst = (Uint8)((sample + 1.0f) * 127.0f);
+ }
}
cvt->len_cvt /= 4;
@@ -208,7 +222,14 @@ SDL_Convert_F32_to_S16_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S16");
for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
- *dst = (Sint16) (*src * 32767.0f);
+ const float sample = *src;
+ if (sample > 1.0f) {
+ *dst = 32767;
+ } else if (sample < -1.0f) {
+ *dst = -32767;
+ } else {
+ *dst = (Sint16)(sample * 32767.0f);
+ }
}
cvt->len_cvt /= 2;
@@ -227,7 +248,14 @@ SDL_Convert_F32_to_U16_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_U16");
for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
- *dst = (Uint16) ((*src + 1.0f) * 32767.0f);
+ const float sample = *src;
+ if (sample > 1.0f) {
+ *dst = 65534;
+ } else if (sample < -1.0f) {
+ *dst = 0;
+ } else {
+ *dst = (Uint16)((sample + 1.0f) * 32767.0f);
+ }
}
cvt->len_cvt /= 2;
@@ -246,7 +274,14 @@ SDL_Convert_F32_to_S32_Scalar(SDL_AudioCVT *cvt, SDL_AudioFormat format)
LOG_DEBUG_CONVERT("AUDIO_F32", "AUDIO_S32");
for (i = cvt->len_cvt / sizeof (float); i; --i, ++src, ++dst) {
- *dst = (Sint32) (((double) *src) * 2147483647.0);
+ const float sample = *src;
+ if (sample > 1.0f) {
+ *dst = 2147483647;
+ } else if (sample < -1.0f) {
+ *dst = -2147483647;
+ } else {
+ *dst = (Sint32)((double)sample * 2147483647.0);
+ }
}
if (cvt->filters[++cvt->filter_index]) {
diff --git a/src/audio/coreaudio/SDL_coreaudio.m b/src/audio/coreaudio/SDL_coreaudio.m
index 33c239d736..dc04dbe28f 100644
--- a/src/audio/coreaudio/SDL_coreaudio.m
+++ b/src/audio/coreaudio/SDL_coreaudio.m
@@ -541,15 +541,18 @@ static BOOL update_audio_session(_THIS, SDL_bool open)
update_audio_session(this, SDL_FALSE);
#endif
- if (this->hidden->thread) {
- SDL_AtomicSet(&this->hidden->shutdown, 1);
- SDL_WaitThread(this->hidden->thread, NULL);
- }
+ /* if callback fires again, feed silence; don't call into the app. */
+ SDL_AtomicSet(&this->paused, 1);
if (this->hidden->audioQueue) {
AudioQueueDispose(this->hidden->audioQueue, 1);
}
+ if (this->hidden->thread) {
+ SDL_AtomicSet(&this->hidden->shutdown, 1);
+ SDL_WaitThread(this->hidden->thread, NULL);
+ }
+
if (this->hidden->ready_semaphore) {
SDL_DestroySemaphore(this->hidden->ready_semaphore);
}
@@ -731,12 +734,9 @@ static BOOL update_audio_session(_THIS, SDL_bool open)
CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.10, 1);
}
- if (this->iscapture) { /* just stop immediately for capture devices. */
- AudioQueueStop(this->hidden->audioQueue, 1);
- } else { /* Drain off any pending playback. */
+ if (!this->iscapture) { /* Drain off any pending playback. */
const CFTimeInterval secs = (((this->spec.size / (SDL_AUDIO_BITSIZE(this->spec.format) / 8)) / this->spec.channels) / ((CFTimeInterval) this->spec.freq)) * 2.0;
CFRunLoopRunInMode(kCFRunLoopDefaultMode, secs, 0);
- AudioQueueStop(this->hidden->audioQueue, 0);
}
return 0;
diff --git a/src/core/android/SDL_android.c b/src/core/android/SDL_android.c
index a7f4e52fbb..48cf7b7962 100644
--- a/src/core/android/SDL_android.c
+++ b/src/core/android/SDL_android.c
@@ -56,6 +56,8 @@
#define CONCAT1(prefix, class, function) CONCAT2(prefix, class, function)
#define CONCAT2(prefix, class, function) Java_ ## prefix ## _ ## class ## _ ## function
#define SDL_JAVA_INTERFACE(function) CONCAT1(SDL_JAVA_PREFIX, SDLActivity, function)
+#define SDL_JAVA_AUDIO_INTERFACE(function) CONCAT1(SDL_JAVA_PREFIX, SDLAudioManager, function)
+#define SDL_JAVA_CONTROLLER_INTERFACE(function) CONCAT1(SDL_JAVA_PREFIX, SDLControllerManager, function)
#define SDL_JAVA_INTERFACE_INPUT_CONNECTION(function) CONCAT1(SDL_JAVA_PREFIX, SDLInputConnection, function)
@@ -75,39 +77,6 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeResize)(
JNIEnv* env, jclass jcls,
jint width, jint height, jint format, jfloat rate);
-JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(onNativePadDown)(
- JNIEnv* env, jclass jcls,
- jint device_id, jint keycode);
-
-JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(onNativePadUp)(
- JNIEnv* env, jclass jcls,
- jint device_id, jint keycode);
-
-JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeJoy)(
- JNIEnv* env, jclass jcls,
- jint device_id, jint axis, jfloat value);
-
-JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeHat)(
- JNIEnv* env, jclass jcls,
- jint device_id, jint hat_id, jint x, jint y);
-
-JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeAddJoystick)(
- JNIEnv* env, jclass jcls,
- jint device_id, jstring device_name, jstring device_desc, jint is_accelerometer,
- jint nbuttons, jint naxes, jint nhats, jint nballs);
-
-JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeRemoveJoystick)(
- JNIEnv* env, jclass jcls,
- jint device_id);
-
-JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeAddHaptic)(
- JNIEnv* env, jclass jcls,
- jint device_id, jstring device_name);
-
-JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeRemoveHaptic)(
- JNIEnv* env, jclass jcls,
- jint device_id);
-
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeSurfaceChanged)(
JNIEnv* env, jclass jcls);
@@ -166,6 +135,48 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE_INPUT_CONNECTION(nativeSetComposingTex
JNIEnv* env, jclass cls,
jstring text, jint newCursorPosition);
+/* Java class SDLAudioManager */
+JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(
+ JNIEnv *env, jclass jcls);
+
+/* Java class SDLControllerManager */
+JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(
+ JNIEnv *env, jclass jcls);
+
+JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativePadDown)(
+ JNIEnv* env, jclass jcls,
+ jint device_id, jint keycode);
+
+JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativePadUp)(
+ JNIEnv* env, jclass jcls,
+ jint device_id, jint keycode);
+
+JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeJoy)(
+ JNIEnv* env, jclass jcls,
+ jint device_id, jint axis, jfloat value);
+
+JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat)(
+ JNIEnv* env, jclass jcls,
+ jint device_id, jint hat_id, jint x, jint y);
+
+JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
+ JNIEnv* env, jclass jcls,
+ jint device_id, jstring device_name, jstring device_desc, jint is_accelerometer,
+ jint nbuttons, jint naxes, jint nhats, jint nballs);
+
+JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick)(
+ JNIEnv* env, jclass jcls,
+ jint device_id);
+
+JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddHaptic)(
+ JNIEnv* env, jclass jcls,
+ jint device_id, jstring device_name);
+
+JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveHaptic)(
+ JNIEnv* env, jclass jcls,
+ jint device_id);
+
+
/* Uncomment this to log messages entering and exiting methods in this file */
/* #define DEBUG_JNI */
@@ -189,17 +200,6 @@ static jclass mActivityClass;
/* method signatures */
static jmethodID midGetNativeSurface;
-static jmethodID midAudioOpen;
-static jmethodID midAudioWriteShortBuffer;
-static jmethodID midAudioWriteByteBuffer;
-static jmethodID midAudioClose;
-static jmethodID midCaptureOpen;
-static jmethodID midCaptureReadShortBuffer;
-static jmethodID midCaptureReadByteBuffer;
-static jmethodID midCaptureClose;
-static jmethodID midPollInputDevices;
-static jmethodID midPollHapticDevices;
-static jmethodID midHapticRun;
static jmethodID midSetActivityTitle;
static jmethodID midSetOrientation;
static jmethodID midGetContext;
@@ -210,7 +210,28 @@ static jmethodID midIsScreenKeyboardShown;
static jmethodID midClipboardSetText;
static jmethodID midClipboardGetText;
static jmethodID midClipboardHasText;
+static jmethodID midOpenAPKExpansionInputStream;
+/* audio manager */
+static jclass mAudioManagerClass;
+
+/* method signatures */
+static jmethodID midAudioOpen;
+static jmethodID midAudioWriteShortBuffer;
+static jmethodID midAudioWriteByteBuffer;
+static jmethodID midAudioClose;
+static jmethodID midCaptureOpen;
+static jmethodID midCaptureReadShortBuffer;
+static jmethodID midCaptureReadByteBuffer;
+static jmethodID midCaptureClose;
+
+/* controller manager */
+static jclass mControllerManagerClass;
+
+/* method signatures */
+static jmethodID midPollInputDevices;
+static jmethodID midPollHapticDevices;
+static jmethodID midHapticRun;
/* static fields */
static jfieldID fidSeparateMouseAndTouch;
@@ -245,7 +266,17 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
return JNI_VERSION_1_4;
}
-/* Called before SDL_main() to initialize JNI bindings */
+void checkJNIReady()
+{
+ if (!mActivityClass || !mAudioManagerClass || !mControllerManagerClass) {
+ // We aren't fully initialized, let's just return.
+ return;
+ }
+
+ SDL_SetMainReady();
+}
+
+/* Activity initialization -- called before SDL_main() to initialize JNI bindings */
JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv* mEnv, jclass cls)
{
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "nativeSetupJNI()");
@@ -256,28 +287,6 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv* mEnv, jclass c
midGetNativeSurface = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"getNativeSurface","()Landroid/view/Surface;");
- midAudioOpen = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
- "audioOpen", "(IZZI)I");
- midAudioWriteShortBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
- "audioWriteShortBuffer", "([S)V");
- midAudioWriteByteBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
- "audioWriteByteBuffer", "([B)V");
- midAudioClose = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
- "audioClose", "()V");
- midCaptureOpen = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
- "captureOpen", "(IZZI)I");
- midCaptureReadShortBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
- "captureReadShortBuffer", "([SZ)I");
- midCaptureReadByteBuffer = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
- "captureReadByteBuffer", "([BZ)I");
- midCaptureClose = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
- "captureClose", "()V");
- midPollInputDevices = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
- "pollInputDevices", "()V");
- midPollHapticDevices = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
- "pollHapticDevices", "()V");
- midHapticRun = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
- "hapticRun", "(II)V");
midSetActivityTitle = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"setActivityTitle","(Ljava/lang/String;)Z");
midSetOrientation = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
@@ -298,16 +307,14 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv* mEnv, jclass c
"clipboardGetText", "()Ljava/lang/String;");
midClipboardHasText = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
"clipboardHasText", "()Z");
-
- bHasNewData = SDL_FALSE;
+ midOpenAPKExpansionInputStream = (*mEnv)->GetStaticMethodID(mEnv, mActivityClass,
+ "openAPKExpansionInputStream", "(Ljava/lang/String;)Ljava/io/InputStream;");
if (!midGetNativeSurface ||
- !midAudioOpen || !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioClose ||
- !midCaptureOpen || !midCaptureReadShortBuffer || !midCaptureReadByteBuffer || !midCaptureClose ||
- !midPollInputDevices || !midPollHapticDevices || !midHapticRun ||
!midSetActivityTitle || !midSetOrientation || !midGetContext || !midInputGetInputDeviceIds ||
!midSendMessage || !midShowTextInput || !midIsScreenKeyboardShown ||
- !midClipboardSetText || !midClipboardGetText || !midClipboardHasText) {
+ !midClipboardSetText || !midClipboardGetText || !midClipboardHasText ||
+ !midOpenAPKExpansionInputStream) {
__android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLActivity.java?");
}
@@ -317,7 +324,64 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(nativeSetupJNI)(JNIEnv* mEnv, jclass c
__android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java static fields, do you have the latest version of SDLActivity.java?");
}
- SDL_SetMainReady();
+ checkJNIReady();
+}
+
+/* Audio initialization -- called before SDL_main() to initialize JNI bindings */
+JNIEXPORT void JNICALL SDL_JAVA_AUDIO_INTERFACE(nativeSetupJNI)(JNIEnv* mEnv, jclass cls)
+{
+ __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "AUDIO nativeSetupJNI()");
+
+ Android_JNI_SetupThread();
+
+ mAudioManagerClass = (jclass)((*mEnv)->NewGlobalRef(mEnv, cls));
+
+ midAudioOpen = (*mEnv)->GetStaticMethodID(mEnv, mAudioManagerClass,
+ "audioOpen", "(IZZI)I");
+ midAudioWriteShortBuffer = (*mEnv)->GetStaticMethodID(mEnv, mAudioManagerClass,
+ "audioWriteShortBuffer", "([S)V");
+ midAudioWriteByteBuffer = (*mEnv)->GetStaticMethodID(mEnv, mAudioManagerClass,
+ "audioWriteByteBuffer", "([B)V");
+ midAudioClose = (*mEnv)->GetStaticMethodID(mEnv, mAudioManagerClass,
+ "audioClose", "()V");
+ midCaptureOpen = (*mEnv)->GetStaticMethodID(mEnv, mAudioManagerClass,
+ "captureOpen", "(IZZI)I");
+ midCaptureReadShortBuffer = (*mEnv)->GetStaticMethodID(mEnv, mAudioManagerClass,
+ "captureReadShortBuffer", "([SZ)I");
+ midCaptureReadByteBuffer = (*mEnv)->GetStaticMethodID(mEnv, mAudioManagerClass,
+ "captureReadByteBuffer", "([BZ)I");
+ midCaptureClose = (*mEnv)->GetStaticMethodID(mEnv, mAudioManagerClass,
+ "captureClose", "()V");
+
+ if (!midAudioOpen || !midAudioWriteShortBuffer || !midAudioWriteByteBuffer || !midAudioClose ||
+ !midCaptureOpen || !midCaptureReadShortBuffer || !midCaptureReadByteBuffer || !midCaptureClose) {
+ __android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLAudioManager.java?");
+ }
+
+ checkJNIReady();
+}
+
+/* Controller initialization -- called before SDL_main() to initialize JNI bindings */
+JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeSetupJNI)(JNIEnv* mEnv, jclass cls)
+{
+ __android_log_print(ANDROID_LOG_VERBOSE, "SDL", "CONTROLLER nativeSetupJNI()");
+
+ Android_JNI_SetupThread();
+
+ mControllerManagerClass = (jclass)((*mEnv)->NewGlobalRef(mEnv, cls));
+
+ midPollInputDevices = (*mEnv)->GetStaticMethodID(mEnv, mControllerManagerClass,
+ "pollInputDevices", "()V");
+ midPollHapticDevices = (*mEnv)->GetStaticMethodID(mEnv, mControllerManagerClass,
+ "pollHapticDevices", "()V");
+ midHapticRun = (*mEnv)->GetStaticMethodID(mEnv, mControllerManagerClass,
+ "hapticRun", "(II)V");
+
+ if (!midPollInputDevices || !midPollHapticDevices || !midHapticRun) {
+ __android_log_print(ANDROID_LOG_WARN, "SDL", "Missing some Java callbacks, do you have the latest version of SDLControllerManager.java?");
+ }
+
+ checkJNIReady();
}
/* SDL main function prototype */
@@ -421,7 +485,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeResize)(
}
/* Paddown */
-JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(onNativePadDown)(
+JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativePadDown)(
JNIEnv* env, jclass jcls,
jint device_id, jint keycode)
{
@@ -429,7 +493,7 @@ JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(onNativePadDown)(
}
/* Padup */
-JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(onNativePadUp)(
+JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativePadUp)(
JNIEnv* env, jclass jcls,
jint device_id, jint keycode)
{
@@ -437,7 +501,7 @@ JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(onNativePadUp)(
}
/* Joy */
-JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeJoy)(
+JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeJoy)(
JNIEnv* env, jclass jcls,
jint device_id, jint axis, jfloat value)
{
@@ -445,7 +509,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeJoy)(
}
/* POV Hat */
-JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeHat)(
+JNIEXPORT void JNICALL SDL_JAVA_CONTROLLER_INTERFACE(onNativeHat)(
JNIEnv* env, jclass jcls,
jint device_id, jint hat_id, jint x, jint y)
{
@@ -453,7 +517,7 @@ JNIEXPORT void JNICALL SDL_JAVA_INTERFACE(onNativeHat)(
}
-JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeAddJoystick)(
+JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddJoystick)(
JNIEnv* env, jclass jcls,
jint device_id, jstring device_name, jstring device_desc, jint is_accelerometer,
jint nbuttons, jint naxes, jint nhats, jint nballs)
@@ -470,14 +534,14 @@ JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeAddJoystick)(
return retval;
}
-JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeRemoveJoystick)(
+JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveJoystick)(
JNIEnv* env, jclass jcls,
jint device_id)
{
return Android_RemoveJoystick(device_id);
}
-JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeAddHaptic)(
+JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeAddHaptic)(
JNIEnv* env, jclass jcls, jint device_id, jstring device_name)
{
int retval;
@@ -490,7 +554,7 @@ JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeAddHaptic)(
return retval;
}
-JNIEXPORT jint JNICALL SDL_JAVA_INTERFACE(nativeRemoveHaptic)(
+JNIEXPORT jint JNICALL SDL_JAVA_CONTROLLER_INTERFACE(nativeRemoveHaptic)(
JNIEnv* env, jclass jcls, jint device_id)
{
return Android_RemoveHaptic(device_id);
@@ -882,7 +946,7 @@ int Android_JNI_OpenAudioDevice(int iscapture, int sampleRate, int is16Bit, int
if (iscapture) {
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device for capture");
captureBuffer16Bit = is16Bit;
- if ((*env)->CallStaticIntMethod(env, mActivityClass, midCaptureOpen, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames) != 0) {
+ if ((*env)->CallStaticIntMethod(env, mAudioManagerClass, midCaptureOpen, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames) != 0) {
/* Error during audio initialization */
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: error on AudioRecord initialization!");
return 0;
@@ -890,7 +954,7 @@ int Android_JNI_OpenAudioDevice(int iscapture, int sampleRate, int is16Bit, int
} else {
__android_log_print(ANDROID_LOG_VERBOSE, "SDL", "SDL audio: opening device for output");
audioBuffer16Bit = is16Bit;
- if ((*env)->CallStaticIntMethod(env, mActivityClass, midAudioOpen, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames) != 0) {
+ if ((*env)->CallStaticIntMethod(env, mAudioManagerClass, midAudioOpen, sampleRate, audioBuffer16Bit, audioBufferStereo, desiredBufferFrames) != 0) {
/* Error during audio initialization */
__android_log_print(ANDROID_LOG_WARN, "SDL", "SDL audio: error on AudioTrack initialization!");
return 0;
@@ -958,10 +1022,10 @@ void Android_JNI_WriteAudioBuffer(void)
if (audioBuffer16Bit) {
(*mAudioEnv)->ReleaseShortArrayElements(mAudioEnv, (jshortArray)audioBuffer, (jshort *)audioBufferPinned, JNI_COMMIT);
- (*mAudioEnv)->CallStaticVoidMethod(mAudioEnv, mActivityClass, midAudioWriteShortBuffer, (jshortArray)audioBuffer);
+ (*mAudioEnv)->CallStaticVoidMethod(mAudioEnv, mAudioManagerClass, midAudioWriteShortBuffer, (jshortArray)audioBuffer);
} else {
(*mAudioEnv)->ReleaseByteArrayElements(mAudioEnv, (jbyteArray)audioBuffer, (jbyte *)audioBufferPinned, JNI_COMMIT);
- (*mAudioEnv)->CallStaticVoidMethod(mAudioEnv, mActivityClass, midAudioWriteByteBuffer, (jbyteArray)audioBuffer);
+ (*mAudioEnv)->CallStaticVoidMethod(mAudioEnv, mAudioManagerClass, midAudioWriteByteBuffer, (jbyteArray)audioBuffer);
}
/* JNI_COMMIT means the changes are committed to the VM but the buffer remains pinned */
@@ -975,7 +1039,7 @@ int Android_JNI_CaptureAudioBuffer(void *buffer, int buflen)
if (captureBuffer16Bit) {
SDL_assert((*env)->GetArrayLength(env, (jshortArray)captureBuffer) == (buflen / 2));
- br = (*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_TRUE);
+ br = (*env)->CallStaticIntMethod(env, mAudioManagerClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_TRUE);
if (br > 0) {
jshort *ptr = (*env)->GetShortArrayElements(env, (jshortArray)captureBuffer, &isCopy);
br *= 2;
@@ -984,7 +1048,7 @@ int Android_JNI_CaptureAudioBuffer(void *buffer, int buflen)
}
} else {
SDL_assert((*env)->GetArrayLength(env, (jshortArray)captureBuffer) == buflen);
- br = (*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_TRUE);
+ br = (*env)->CallStaticIntMethod(env, mAudioManagerClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_TRUE);
if (br > 0) {
jbyte *ptr = (*env)->GetByteArrayElements(env, (jbyteArray)captureBuffer, &isCopy);
SDL_memcpy(buffer, ptr, br);
@@ -1008,9 +1072,9 @@ void Android_JNI_FlushCapturedAudio(void)
}
#else
if (captureBuffer16Bit) {
- (*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_FALSE);
+ (*env)->CallStaticIntMethod(env, mAudioManagerClass, midCaptureReadShortBuffer, (jshortArray)captureBuffer, JNI_FALSE);
} else {
- (*env)->CallStaticIntMethod(env, mActivityClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_FALSE);
+ (*env)->CallStaticIntMethod(env, mAudioManagerClass, midCaptureReadByteBuffer, (jbyteArray)captureBuffer, JNI_FALSE);
}
#endif
}
@@ -1020,13 +1084,13 @@ void Android_JNI_CloseAudioDevice(const int iscapture)
JNIEnv *env = Android_JNI_GetEnv();
if (iscapture) {
- (*env)->CallStaticVoidMethod(env, mActivityClass, midCaptureClose);
+ (*env)->CallStaticVoidMethod(env, mAudioManagerClass, midCaptureClose);
if (captureBuffer) {
(*env)->DeleteGlobalRef(env, captureBuffer);
captureBuffer = NULL;
}
} else {
- (*env)->CallStaticVoidMethod(env, mActivityClass, midAudioClose);
+ (*env)->CallStaticVoidMethod(env, mAudioManagerClass, midAudioClose);
if (audioBuffer) {
(*env)->DeleteGlobalRef(env, audioBuffer);
audioBuffer = NULL;
@@ -1160,13 +1224,7 @@ static int Internal_Android_JNI_FileOpen(SDL_RWops* ctx)
inputStream = (*mEnv)->CallObjectMethod(mEnv, assetManager, mid, fileNameJString, 1 /* ACCESS_RANDOM */);
if (Android_JNI_ExceptionOccurred(SDL_FALSE)) {
/* Try fallback to APK expansion files */
- mid = (*mEnv)->GetMethodID(mEnv, (*mEnv)->GetObjectClass(mEnv, context),
- "openAPKExpansionInputStream", "(Ljava/lang/String;)Ljava/io/InputStream;");
- if (!mid) {
- SDL_SetError("No openAPKExpansionInputStream() in Java class");
- goto failure; /* Java class is missing the required method */
- }
- inputStream = (*mEnv)->CallObjectMethod(mEnv, context, mid, fileNameJString);
+ inputStream = (*mEnv)->CallStaticObjectMethod(mEnv, mActivityClass, midOpenAPKExpansionInputStream, fileNameJString);
/* Exception is checked first because it always needs to be cleared.
* If no exception occurred then the last SDL error message is kept.
@@ -1673,19 +1731,19 @@ void Android_JNI_SetSeparateMouseAndTouch(SDL_bool new_value)
void Android_JNI_PollInputDevices(void)
{
JNIEnv *env = Android_JNI_GetEnv();
- (*env)->CallStaticVoidMethod(env, mActivityClass, midPollInputDevices);
+ (*env)->CallStaticVoidMethod(env, mControllerManagerClass, midPollInputDevices);
}
void Android_JNI_PollHapticDevices(void)
{
JNIEnv *env = Android_JNI_GetEnv();
- (*env)->CallStaticVoidMethod(env, mActivityClass, midPollHapticDevices);
+ (*env)->CallStaticVoidMethod(env, mControllerManagerClass, midPollHapticDevices);
}
void Android_JNI_HapticRun(int device_id, int length)
{
JNIEnv *env = Android_JNI_GetEnv();
- (*env)->CallStaticVoidMethod(env, mActivityClass, midHapticRun, device_id, length);
+ (*env)->CallStaticVoidMethod(env, mControllerManagerClass, midHapticRun, device_id, length);
}
@@ -1862,6 +1920,11 @@ const char * SDL_AndroidGetInternalStoragePath(void)
/* context = SDLActivity.getContext(); */
context = (*env)->CallStaticObjectMethod(env, mActivityClass, midGetContext);
+ if (!context) {
+ SDL_SetError("Couldn't get Android context!");
+ LocalReferenceHolder_Cleanup(&refs);
+ return NULL;
+ }
/* fileObj = context.getFilesDir(); */
mid = (*env)->GetMethodID(env, (*env)->GetObjectClass(env, context),
diff --git a/src/core/linux/SDL_ibus.c b/src/core/linux/SDL_ibus.c
index 0fcec87a11..f537380963 100644
--- a/src/core/linux/SDL_ibus.c
+++ b/src/core/linux/SDL_ibus.c
@@ -479,7 +479,7 @@ IBus_SimpleMessage(const char *method)
SDL_DBusContext *dbus = SDL_DBus_GetContext();
if (IBus_CheckConnection(dbus)) {
- SDL_DBus_CallVoidMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, method);
+ SDL_DBus_CallVoidMethodOnConnection(ibus_conn, IBUS_SERVICE, input_ctx_path, IBUS_INPUT_INTERFACE, method, DBUS_TYPE_INVALID);
}
}
diff --git a/src/core/linux/SDL_udev.c b/src/core/linux/SDL_udev.c
index 502490b70f..37bc4224f8 100644
--- a/src/core/linux/SDL_udev.c
+++ b/src/core/linux/SDL_udev.c
@@ -36,14 +36,7 @@
#include "SDL_timer.h"
#include "../unix/SDL_poll.h"
-static const char *SDL_UDEV_LIBS[] = {
-#ifdef SDL_UDEV_DYNAMIC
- SDL_UDEV_DYNAMIC
-#else
- "libudev.so.1",
- "libudev.so.0"
-#endif
-};
+static const char *SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" };
#define _THIS SDL_UDEV_PrivateData *_this
static _THIS = NULL;
@@ -261,6 +254,19 @@ SDL_UDEV_LoadLibrary(void)
return 0;
}
+#ifdef SDL_UDEV_DYNAMIC
+ /* Check for the build environment's libudev first */
+ if (_this->udev_handle == NULL) {
+ _this->udev_handle = SDL_LoadObject(SDL_UDEV_DYNAMIC);
+ if (_this->udev_handle != NULL) {
+ retval = SDL_UDEV_load_syms();
+ if (retval < 0) {
+ SDL_UDEV_UnloadLibrary();
+ }
+ }
+ }
+#endif
+
if (_this->udev_handle == NULL) {
for( i = 0 ; i < SDL_arraysize(SDL_UDEV_LIBS); i++) {
_this->udev_handle = SDL_LoadObject(SDL_UDEV_LIBS[i]);
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index 95943bc1f6..ac3980f5fe 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -635,3 +635,15 @@
#define SDL_Vulkan_GetInstanceExtensions SDL_Vulkan_GetInstanceExtensions_REAL
#define SDL_Vulkan_CreateSurface SDL_Vulkan_CreateSurface_REAL
#define SDL_Vulkan_GetDrawableSize SDL_Vulkan_GetDrawableSize_REAL
+#define SDL_LockJoysticks SDL_LockJoysticks_REAL
+#define SDL_UnlockJoysticks SDL_UnlockJoysticks_REAL
+#define SDL_GetMemoryFunctions SDL_GetMemoryFunctions_REAL
+#define SDL_SetMemoryFunctions SDL_SetMemoryFunctions_REAL
+#define SDL_GetNumAllocations SDL_GetNumAllocations_REAL
+#define SDL_NewAudioStream SDL_NewAudioStream_REAL
+#define SDL_AudioStreamPut SDL_AudioStreamPut_REAL
+#define SDL_AudioStreamGet SDL_AudioStreamGet_REAL
+#define SDL_AudioStreamClear SDL_AudioStreamClear_REAL
+#define SDL_AudioStreamAvailable SDL_AudioStreamAvailable_REAL
+#define SDL_FreeAudioStream SDL_FreeAudioStream_REAL
+#define SDL_AudioStreamFlush SDL_AudioStreamFlush_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index b7466fdb64..8c0f8b7154 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -669,3 +669,15 @@ SDL_DYNAPI_PROC(void,SDL_Vulkan_UnloadLibrary,(void),(),)
SDL_DYNAPI_PROC(SDL_bool,SDL_Vulkan_GetInstanceExtensions,(SDL_Window *a, unsigned int *b, const char **c),(a,b,c),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_Vulkan_CreateSurface,(SDL_Window *a, VkInstance b, VkSurfaceKHR *c),(a,b,c),return)
SDL_DYNAPI_PROC(void,SDL_Vulkan_GetDrawableSize,(SDL_Window *a, int *b, int *c),(a,b,c),)
+SDL_DYNAPI_PROC(void,SDL_LockJoysticks,(void),(),)
+SDL_DYNAPI_PROC(void,SDL_UnlockJoysticks,(void),(),)
+SDL_DYNAPI_PROC(void,SDL_GetMemoryFunctions,(SDL_malloc_func *a, SDL_calloc_func *b, SDL_realloc_func *c, SDL_free_func *d),(a,b,c,d),)
+SDL_DYNAPI_PROC(int,SDL_SetMemoryFunctions,(SDL_malloc_func a, SDL_calloc_func b, SDL_realloc_func c, SDL_free_func d),(a,b,c,d),return)
+SDL_DYNAPI_PROC(int,SDL_GetNumAllocations,(void),(),return)
+SDL_DYNAPI_PROC(SDL_AudioStream*,SDL_NewAudioStream,(const SDL_AudioFormat a, const Uint8 b, const int c, const SDL_AudioFormat d, const Uint8 e, const int f),(a,b,c,d,e,f),return)
+SDL_DYNAPI_PROC(int,SDL_AudioStreamPut,(SDL_AudioStream *a, const void *b, int c),(a,b,c),return)
+SDL_DYNAPI_PROC(int,SDL_AudioStreamGet,(SDL_AudioStream *a, void *b, int c),(a,b,c),return)
+SDL_DYNAPI_PROC(void,SDL_AudioStreamClear,(SDL_AudioStream *a),(a),)
+SDL_DYNAPI_PROC(int,SDL_AudioStreamAvailable,(SDL_AudioStream *a),(a),return)
+SDL_DYNAPI_PROC(void,SDL_FreeAudioStream,(SDL_AudioStream *a),(a),)
+SDL_DYNAPI_PROC(int,SDL_AudioStreamFlush,(SDL_AudioStream *a),(a),return)
diff --git a/src/events/SDL_events.c b/src/events/SDL_events.c
index c87dc9930c..777c27399d 100644
--- a/src/events/SDL_events.c
+++ b/src/events/SDL_events.c
@@ -38,17 +38,18 @@
/* An arbitrary limit so we don't have unbounded growth */
#define SDL_MAX_QUEUED_EVENTS 65535
-/* Public data -- the event filter */
-SDL_EventFilter SDL_EventOK = NULL;
-void *SDL_EventOKParam;
-
typedef struct SDL_EventWatcher {
SDL_EventFilter callback;
void *userdata;
- struct SDL_EventWatcher *next;
+ SDL_bool removed;
} SDL_EventWatcher;
+static SDL_mutex *SDL_event_watchers_lock;
+static SDL_EventWatcher SDL_EventOK;
static SDL_EventWatcher *SDL_event_watchers = NULL;
+static int SDL_event_watchers_count = 0;
+static SDL_bool SDL_event_watchers_dispatching = SDL_FALSE;
+static SDL_bool SDL_event_watchers_removed = SDL_FALSE;
typedef struct {
Uint32 bits[8];
@@ -367,12 +368,17 @@ SDL_StopEventLoop(void)
SDL_disabled_events[i] = NULL;
}
- while (SDL_event_watchers) {
- SDL_EventWatcher *tmp = SDL_event_watchers;
- SDL_event_watchers = tmp->next;
- SDL_free(tmp);
+ if (SDL_event_watchers_lock) {
+ SDL_UnlockMutex(SDL_event_watchers_lock);
+ SDL_DestroyMutex(SDL_event_watchers_lock);
+ SDL_event_watchers_lock = NULL;
+ }
+ if (SDL_event_watchers) {
+ SDL_free(SDL_event_watchers);
+ SDL_event_watchers = NULL;
+ SDL_event_watchers_count = 0;
}
- SDL_EventOK = NULL;
+ SDL_zero(SDL_EventOK);
if (SDL_EventQ.lock) {
SDL_UnlockMutex(SDL_EventQ.lock);
@@ -395,9 +401,16 @@ SDL_StartEventLoop(void)
#if !SDL_THREADS_DISABLED
if (!SDL_EventQ.lock) {
SDL_EventQ.lock = SDL_CreateMutex();
+ if (SDL_EventQ.lock == NULL) {
+ return -1;
+ }
}
- if (SDL_EventQ.lock == NULL) {
- return -1;
+
+ if (!SDL_event_watchers_lock) {
+ SDL_event_watchers_lock = SDL_CreateMutex();
+ if (SDL_event_watchers_lock == NULL) {
+ return -1;
+ }
}
#endif /* !SDL_THREADS_DISABLED */
@@ -606,7 +619,7 @@ SDL_FlushEvents(Uint32 minType, Uint32 maxType)
#endif
/* Lock the event queue */
- if (SDL_EventQ.lock && SDL_LockMutex(SDL_EventQ.lock) == 0) {
+ if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
SDL_EventEntry *entry, *next;
Uint32 type;
for (entry = SDL_EventQ.head; entry; entry = next) {
@@ -616,7 +629,9 @@ SDL_FlushEvents(Uint32 minType, Uint32 maxType)
SDL_CutEvent(entry);
}
}
- SDL_UnlockMutex(SDL_EventQ.lock);
+ if (SDL_EventQ.lock) {
+ SDL_UnlockMutex(SDL_EventQ.lock);
+ }
}
}
@@ -688,16 +703,46 @@ SDL_WaitEventTimeout(SDL_Event * event, int timeout)
int
SDL_PushEvent(SDL_Event * event)
{
- SDL_EventWatcher *curr;
-
event->common.timestamp = SDL_GetTicks();
- if (SDL_EventOK && !SDL_EventOK(SDL_EventOKParam, event)) {
- return 0;
- }
+ if (SDL_EventOK.callback || SDL_event_watchers_count > 0) {
+ if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
+ if (SDL_EventOK.callback && !SDL_EventOK.callback(SDL_EventOK.userdata, event)) {
+ if (SDL_event_watchers_lock) {
+ SDL_UnlockMutex(SDL_event_watchers_lock);
+ }
+ return 0;
+ }
+
+ if (SDL_event_watchers_count > 0) {
+ /* Make sure we only dispatch the current watcher list */
+ int i, event_watchers_count = SDL_event_watchers_count;
+
+ SDL_event_watchers_dispatching = SDL_TRUE;
+ for (i = 0; i < event_watchers_count; ++i) {
+ if (!SDL_event_watchers[i].removed) {
+ SDL_event_watchers[i].callback(SDL_event_watchers[i].userdata, event);
+ }
+ }
+ SDL_event_watchers_dispatching = SDL_FALSE;
+
+ if (SDL_event_watchers_removed) {
+ for (i = SDL_event_watchers_count; i--; ) {
+ if (SDL_event_watchers[i].removed) {
+ --SDL_event_watchers_count;
+ if (i < SDL_event_watchers_count) {
+ SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i+1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i]));
+ }
+ }
+ }
+ SDL_event_watchers_removed = SDL_FALSE;
+ }
+ }
- for (curr = SDL_event_watchers; curr; curr = curr->next) {
- curr->callback(curr->userdata, event);
+ if (SDL_event_watchers_lock) {
+ SDL_UnlockMutex(SDL_event_watchers_lock);
+ }
+ }
}
if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
@@ -712,69 +757,89 @@ SDL_PushEvent(SDL_Event * event)
void
SDL_SetEventFilter(SDL_EventFilter filter, void *userdata)
{
- /* Set filter and discard pending events */
- SDL_EventOK = NULL;
- SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
- SDL_EventOKParam = userdata;
- SDL_EventOK = filter;
+ if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
+ /* Set filter and discard pending events */
+ SDL_EventOK.callback = filter;
+ SDL_EventOK.userdata = userdata;
+ SDL_FlushEvents(SDL_FIRSTEVENT, SDL_LASTEVENT);
+
+ if (SDL_event_watchers_lock) {
+ SDL_UnlockMutex(SDL_event_watchers_lock);
+ }
+ }
}
SDL_bool
SDL_GetEventFilter(SDL_EventFilter * filter, void **userdata)
{
+ SDL_EventWatcher event_ok;
+
+ if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
+ event_ok = SDL_EventOK;
+
+ if (SDL_event_watchers_lock) {
+ SDL_UnlockMutex(SDL_event_watchers_lock);
+ }
+ } else {
+ SDL_zero(event_ok);
+ }
+
if (filter) {
- *filter = SDL_EventOK;
+ *filter = event_ok.callback;
}
if (userdata) {
- *userdata = SDL_EventOKParam;
+ *userdata = event_ok.userdata;
}
- return SDL_EventOK ? SDL_TRUE : SDL_FALSE;
+ return event_ok.callback ? SDL_TRUE : SDL_FALSE;
}
-/* FIXME: This is not thread-safe yet */
void
SDL_AddEventWatch(SDL_EventFilter filter, void *userdata)
{
- SDL_EventWatcher *watcher, *tail;
-
- watcher = (SDL_EventWatcher *)SDL_malloc(sizeof(*watcher));
- if (!watcher) {
- /* Uh oh... */
- return;
- }
-
- /* create the watcher */
- watcher->callback = filter;
- watcher->userdata = userdata;
- watcher->next = NULL;
+ if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
+ SDL_EventWatcher *event_watchers;
+
+ event_watchers = SDL_realloc(SDL_event_watchers, (SDL_event_watchers_count + 1) * sizeof(*event_watchers));
+ if (event_watchers) {
+ SDL_EventWatcher *watcher;
+
+ SDL_event_watchers = event_watchers;
+ watcher = &SDL_event_watchers[SDL_event_watchers_count];
+ watcher->callback = filter;
+ watcher->userdata = userdata;
+ watcher->removed = SDL_FALSE;
+ ++SDL_event_watchers_count;
+ }
- /* add the watcher to the end of the list */
- if (SDL_event_watchers) {
- for (tail = SDL_event_watchers; tail->next; tail = tail->next) {
- continue;
+ if (SDL_event_watchers_lock) {
+ SDL_UnlockMutex(SDL_event_watchers_lock);
}
- tail->next = watcher;
- } else {
- SDL_event_watchers = watcher;
}
}
-/* FIXME: This is not thread-safe yet */
void
SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
{
- SDL_EventWatcher *prev = NULL;
- SDL_EventWatcher *curr;
-
- for (curr = SDL_event_watchers; curr; prev = curr, curr = curr->next) {
- if (curr->callback == filter && curr->userdata == userdata) {
- if (prev) {
- prev->next = curr->next;
- } else {
- SDL_event_watchers = curr->next;
+ if (!SDL_event_watchers_lock || SDL_LockMutex(SDL_event_watchers_lock) == 0) {
+ int i;
+
+ for (i = 0; i < SDL_event_watchers_count; ++i) {
+ if (SDL_event_watchers[i].callback == filter && SDL_event_watchers[i].userdata == userdata) {
+ if (SDL_event_watchers_dispatching) {
+ SDL_event_watchers[i].removed = SDL_TRUE;
+ SDL_event_watchers_removed = SDL_TRUE;
+ } else {
+ --SDL_event_watchers_count;
+ if (i < SDL_event_watchers_count) {
+ SDL_memmove(&SDL_event_watchers[i], &SDL_event_watchers[i+1], (SDL_event_watchers_count - i) * sizeof(SDL_event_watchers[i]));
+ }
+ }
+ break;
}
- SDL_free(curr);
- break;
+ }
+
+ if (SDL_event_watchers_lock) {
+ SDL_UnlockMutex(SDL_event_watchers_lock);
}
}
}
@@ -782,7 +847,7 @@ SDL_DelEventWatch(SDL_EventFilter filter, void *userdata)
void
SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
{
- if (SDL_EventQ.lock && SDL_LockMutex(SDL_EventQ.lock) == 0) {
+ if (!SDL_EventQ.lock || SDL_LockMutex(SDL_EventQ.lock) == 0) {
SDL_EventEntry *entry, *next;
for (entry = SDL_EventQ.head; entry; entry = next) {
next = entry->next;
@@ -790,7 +855,9 @@ SDL_FilterEvents(SDL_EventFilter filter, void *userdata)
SDL_CutEvent(entry);
}
}
- SDL_UnlockMutex(SDL_EventQ.lock);
+ if (SDL_EventQ.lock) {
+ SDL_UnlockMutex(SDL_EventQ.lock);
+ }
}
}
diff --git a/src/events/SDL_events_c.h b/src/events/SDL_events_c.h
index 83b0e143b3..56e48dd2cb 100644
--- a/src/events/SDL_events_c.h
+++ b/src/events/SDL_events_c.h
@@ -46,8 +46,4 @@ extern void SDL_QuitQuit(void);
extern void SDL_SendPendingQuit(void);
-/* The event filter function */
-extern SDL_EventFilter SDL_EventOK;
-extern void *SDL_EventOKParam;
-
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/events/SDL_mouse.c b/src/events/SDL_mouse.c
index 7a7bb2e4a7..80c367f88b 100644
--- a/src/events/SDL_mouse.c
+++ b/src/events/SDL_mouse.c
@@ -81,6 +81,8 @@ SDL_MouseInit(void)
{
SDL_Mouse *mouse = SDL_GetMouse();
+ SDL_zerop(mouse);
+
SDL_AddHintCallback(SDL_HINT_MOUSE_NORMAL_SPEED_SCALE,
SDL_MouseNormalSpeedScaleChanged, mouse);
@@ -578,17 +580,18 @@ SDL_MouseQuit(void)
SDL_FreeCursor(cursor);
cursor = next;
}
+ mouse->cursors = NULL;
if (mouse->def_cursor && mouse->FreeCursor) {
mouse->FreeCursor(mouse->def_cursor);
+ mouse->def_cursor = NULL;
}
if (mouse->clickstate) {
SDL_free(mouse->clickstate);
+ mouse->clickstate = NULL;
}
- SDL_zerop(mouse);
-
SDL_DelHintCallback(SDL_HINT_MOUSE_NORMAL_SPEED_SCALE,
SDL_MouseNormalSpeedScaleChanged, mouse);
diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c
index 575593a4be..13953de51c 100644
--- a/src/joystick/SDL_gamecontroller.c
+++ b/src/joystick/SDL_gamecontroller.c
@@ -24,15 +24,20 @@
#include "SDL_events.h"
#include "SDL_assert.h"
+#include "SDL_hints.h"
#include "SDL_sysjoystick.h"
#include "SDL_joystick_c.h"
-#include "SDL_hints.h"
#include "SDL_gamecontrollerdb.h"
#if !SDL_EVENTS_DISABLED
#include "../events/SDL_events_c.h"
#endif
+#if defined(__ANDROID__)
+#include "SDL_system.h"
+#endif
+
+
#define SDL_CONTROLLER_PLATFORM_FIELD "platform:"
/* a list of currently opened game controllers */
@@ -901,14 +906,20 @@ static ControllerMapping_t *SDL_PrivateGetControllerMappingForNameAndGUID(const
static ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
{
- const char *name = SDL_JoystickNameForIndex(device_index);
- SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(device_index);
- ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid);
+ const char *name;
+ SDL_JoystickGUID guid;
+ ControllerMapping_t *mapping;
+
+ SDL_LockJoysticks();
+ name = SDL_JoystickNameForIndex(device_index);
+ guid = SDL_JoystickGetDeviceGUID(device_index);
+ mapping = SDL_PrivateGetControllerMappingForNameAndGUID(name, guid);
#if SDL_JOYSTICK_XINPUT
if (!mapping && SDL_SYS_IsXInputGamepad_DeviceIndex(device_index)) {
mapping = s_pXInputMapping;
}
#endif
+ SDL_UnlockJoysticks();
return mapping;
}
@@ -1157,12 +1168,30 @@ SDL_GameControllerLoadHints()
}
}
+/*
+ * Fill the given buffer with the expected controller mapping filepath.
+ * Usually this will just be CONTROLLER_MAPPING_FILE, but for Android,
+ * we want to get the internal storage path.
+ */
+static SDL_bool SDL_GetControllerMappingFilePath(char *path, size_t size)
+{
+#ifdef CONTROLLER_MAPPING_FILE
+#define STRING(X) SDL_STRINGIFY_ARG(X)
+ return SDL_strlcpy(path, STRING(CONTROLLER_MAPPING_FILE), size) < size;
+#elif defined(__ANDROID__)
+ return SDL_snprintf(path, size, "%s/controller_map.txt", SDL_AndroidGetInternalStoragePath()) < size;
+#else
+ return SDL_FALSE;
+#endif
+}
+
/*
* Initialize the game controller system, mostly load our DB of controller config mappings
*/
int
SDL_GameControllerInitMappings(void)
{
+ char szControllerMapPath[1024];
int i = 0;
const char *pMappingString = NULL;
pMappingString = s_ControllerMappings[i];
@@ -1173,6 +1202,10 @@ SDL_GameControllerInitMappings(void)
pMappingString = s_ControllerMappings[i];
}
+ if (SDL_GetControllerMappingFilePath(szControllerMapPath, sizeof(szControllerMapPath))) {
+ SDL_GameControllerAddMappingsFromFile(szControllerMapPath);
+ }
+
/* load in any user supplied config */
SDL_GameControllerLoadHints();
@@ -1316,7 +1349,7 @@ SDL_GameControllerOpen(int device_index)
return (NULL);
}
- SDL_LockJoystickList();
+ SDL_LockJoysticks();
gamecontrollerlist = SDL_gamecontrollers;
/* If the controller is already open, return it */
@@ -1324,7 +1357,7 @@ SDL_GameControllerOpen(int device_index)
if (SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id) {
gamecontroller = gamecontrollerlist;
++gamecontroller->ref_count;
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return (gamecontroller);
}
gamecontrollerlist = gamecontrollerlist->next;
@@ -1334,7 +1367,7 @@ SDL_GameControllerOpen(int device_index)
pSupportedController = SDL_PrivateGetControllerMapping(device_index);
if (!pSupportedController) {
SDL_SetError("Couldn't find mapping for device (%d)", device_index);
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return NULL;
}
@@ -1342,14 +1375,14 @@ SDL_GameControllerOpen(int device_index)
gamecontroller = (SDL_GameController *) SDL_calloc(1, sizeof(*gamecontroller));
if (gamecontroller == NULL) {
SDL_OutOfMemory();
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return NULL;
}
gamecontroller->joystick = SDL_JoystickOpen(device_index);
if (!gamecontroller->joystick) {
SDL_free(gamecontroller);
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return NULL;
}
@@ -1359,7 +1392,7 @@ SDL_GameControllerOpen(int device_index)
SDL_OutOfMemory();
SDL_JoystickClose(gamecontroller->joystick);
SDL_free(gamecontroller);
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return NULL;
}
}
@@ -1370,7 +1403,7 @@ SDL_GameControllerOpen(int device_index)
SDL_JoystickClose(gamecontroller->joystick);
SDL_free(gamecontroller->last_match_axis);
SDL_free(gamecontroller);
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return NULL;
}
}
@@ -1383,7 +1416,7 @@ SDL_GameControllerOpen(int device_index)
gamecontroller->next = SDL_gamecontrollers;
SDL_gamecontrollers = gamecontroller;
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return (gamecontroller);
}
@@ -1556,16 +1589,16 @@ SDL_GameControllerFromInstanceID(SDL_JoystickID joyid)
{
SDL_GameController *gamecontroller;
- SDL_LockJoystickList();
+ SDL_LockJoysticks();
gamecontroller = SDL_gamecontrollers;
while (gamecontroller) {
if (gamecontroller->joystick->instance_id == joyid) {
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return gamecontroller;
}
gamecontroller = gamecontroller->next;
}
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return NULL;
}
@@ -1641,11 +1674,11 @@ SDL_GameControllerClose(SDL_GameController * gamecontroller)
if (!gamecontroller)
return;
- SDL_LockJoystickList();
+ SDL_LockJoysticks();
/* First decrement ref count */
if (--gamecontroller->ref_count > 0) {
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return;
}
@@ -1672,7 +1705,7 @@ SDL_GameControllerClose(SDL_GameController * gamecontroller)
SDL_free(gamecontroller->last_hat_mask);
SDL_free(gamecontroller);
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
}
@@ -1682,12 +1715,12 @@ SDL_GameControllerClose(SDL_GameController * gamecontroller)
void
SDL_GameControllerQuit(void)
{
- SDL_LockJoystickList();
+ SDL_LockJoysticks();
while (SDL_gamecontrollers) {
SDL_gamecontrollers->ref_count = 1;
SDL_GameControllerClose(SDL_gamecontrollers);
}
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
}
void
diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h
index 8caf8477cc..951cd0b6f7 100644
--- a/src/joystick/SDL_gamecontrollerdb.h
+++ b/src/joystick/SDL_gamecontrollerdb.h
@@ -163,6 +163,7 @@ static const char *s_ControllerMappings [] =
"030000000d0500000308000010010000,Nostromo n45 Dual Analog Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b9,leftshoulder:b4,leftstick:b12,lefttrigger:b5,leftx:a0,lefty:a1,rightshoulder:b6,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b10,x:b2,y:b3,",
"05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2,",
"030000006f0e00006401000001010000,PDP Battlefield One,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+ "03000000ff1100004133000010010000,PS2 Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,",
"030000004c0500006802000010010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
"050000004c0500006802000000010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:a12,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:a13,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
"030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,",
@@ -191,6 +192,10 @@ static const char *s_ControllerMappings [] =
"03000000a30600000cff000010010000,Saitek P2500 Force Rumble Pad,a:b2,b:b3,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b8,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b9,righttrigger:b7,rightx:a3,righty:a2,x:b0,y:b1,",
"03000000a30600000b04000000010000,Saitek P990 Dual Analog Pad,a:b1,b:b2,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a3,righty:a2,start:b8,x:b0,y:b3,",
"03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
+ "05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
+ "03000000de2800000112000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
+ "05000000de2800000212000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
+ "03000000de2800004211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
"03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"03000000de280000ff11000001000000,Steam Virtual Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
"xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
@@ -201,13 +206,18 @@ static const char *s_ControllerMappings [] =
"03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,",
#endif
#if defined(__ANDROID__)
+ "64633436313965656664373634323364,Microsoft X-Box 360 pad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,",
"4e564944494120436f72706f72617469,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+ "61363931656135336130663561616264,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+ "37336435666338653565313731303834,NVIDIA Controller,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
+ "35643031303033326130316330353564,PS4 Controller,a:b1,b:b17,back:b15,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:+a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:+a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,",
+ "05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
+ "34356136633366613530316338376136,Xbox Wireless Controller,a:b0,b:b1,back:b9,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b3,leftstick:b15,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b16,righttrigger:a5,rightx:a3,righty:a4,x:b17,y:b2,",
#endif
#if defined(SDL_JOYSTICK_MFI)
"4d466947616d65706164010000000000,MFi Extended Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a5,rightx:a3,righty:a4,start:b6,x:b2,y:b3,",
"4d466947616d65706164020000000000,MFi Gamepad,a:b0,b:b1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,rightshoulder:b5,start:b6,x:b2,y:b3,",
- "03000000de2800000211000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
- "03000000de280000fc11000001000000,Steam Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,",
+ "05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
#endif
#if defined(SDL_JOYSTICK_EMSCRIPTEN)
"emscripten,Standard Gamepad,a:b0,b:b1,back:b8,dpdown:b13,dpleft:b14,dpright:b15,dpup:b12,guide:b16,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,",
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index 0724db258a..b49b28ec3f 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -40,7 +40,7 @@ static SDL_bool SDL_updating_joystick = SDL_FALSE;
static SDL_mutex *SDL_joystick_lock = NULL; /* This needs to support recursive locks */
void
-SDL_LockJoystickList(void)
+SDL_LockJoysticks(void)
{
if (SDL_joystick_lock) {
SDL_LockMutex(SDL_joystick_lock);
@@ -48,7 +48,7 @@ SDL_LockJoystickList(void)
}
void
-SDL_UnlockJoystickList(void)
+SDL_UnlockJoysticks(void)
{
if (SDL_joystick_lock) {
SDL_UnlockMutex(SDL_joystick_lock);
@@ -168,7 +168,7 @@ SDL_JoystickOpen(int device_index)
return (NULL);
}
- SDL_LockJoystickList();
+ SDL_LockJoysticks();
joysticklist = SDL_joysticks;
/* If the joystick is already open, return it
@@ -178,7 +178,7 @@ SDL_JoystickOpen(int device_index)
if (SDL_JoystickGetDeviceInstanceID(device_index) == joysticklist->instance_id) {
joystick = joysticklist;
++joystick->ref_count;
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return (joystick);
}
joysticklist = joysticklist->next;
@@ -188,13 +188,13 @@ SDL_JoystickOpen(int device_index)
joystick = (SDL_Joystick *) SDL_calloc(sizeof(*joystick), 1);
if (joystick == NULL) {
SDL_OutOfMemory();
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return NULL;
}
if (SDL_SYS_JoystickOpen(joystick, device_index) < 0) {
SDL_free(joystick);
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return NULL;
}
@@ -222,7 +222,7 @@ SDL_JoystickOpen(int device_index)
|| ((joystick->nbuttons > 0) && !joystick->buttons)) {
SDL_OutOfMemory();
SDL_JoystickClose(joystick);
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return NULL;
}
joystick->epowerlevel = SDL_JOYSTICK_POWER_UNKNOWN;
@@ -244,7 +244,7 @@ SDL_JoystickOpen(int device_index)
joystick->next = SDL_joysticks;
SDL_joysticks = joystick;
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
SDL_SYS_JoystickUpdate(joystick);
@@ -460,14 +460,14 @@ SDL_JoystickFromInstanceID(SDL_JoystickID joyid)
{
SDL_Joystick *joystick;
- SDL_LockJoystickList();
+ SDL_LockJoysticks();
for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
if (joystick->instance_id == joyid) {
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return joystick;
}
}
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return NULL;
}
@@ -497,16 +497,16 @@ SDL_JoystickClose(SDL_Joystick * joystick)
return;
}
- SDL_LockJoystickList();
+ SDL_LockJoysticks();
/* First decrement ref count */
if (--joystick->ref_count > 0) {
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return;
}
if (SDL_updating_joystick) {
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return;
}
@@ -538,7 +538,7 @@ SDL_JoystickClose(SDL_Joystick * joystick)
SDL_free(joystick->buttons);
SDL_free(joystick);
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
}
void
@@ -547,7 +547,7 @@ SDL_JoystickQuit(void)
/* Make sure we're not getting called in the middle of updating joysticks */
SDL_assert(!SDL_updating_joystick);
- SDL_LockJoystickList();
+ SDL_LockJoysticks();
/* Stop the event polling */
while (SDL_joysticks) {
@@ -558,7 +558,7 @@ SDL_JoystickQuit(void)
/* Quit the joystick setup */
SDL_SYS_JoystickQuit();
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
#if !SDL_EVENTS_DISABLED
SDL_QuitSubSystem(SDL_INIT_EVENTS);
@@ -601,10 +601,7 @@ void SDL_PrivateJoystickAdded(int device_index)
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = device_index;
- if ((SDL_EventOK == NULL) ||
- (*SDL_EventOK) (SDL_EventOKParam, &event)) {
- SDL_PushEvent(&event);
- }
+ SDL_PushEvent(&event);
}
#endif /* !SDL_EVENTS_DISABLED */
}
@@ -647,10 +644,7 @@ void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
if (SDL_GetEventState(event.type) == SDL_ENABLE) {
event.jdevice.which = device_instance;
- if ((SDL_EventOK == NULL) ||
- (*SDL_EventOK) (SDL_EventOKParam, &event)) {
- SDL_PushEvent(&event);
- }
+ SDL_PushEvent(&event);
}
UpdateEventsForDeviceRemoval();
@@ -847,18 +841,18 @@ SDL_JoystickUpdate(void)
{
SDL_Joystick *joystick;
- SDL_LockJoystickList();
+ SDL_LockJoysticks();
if (SDL_updating_joystick) {
/* The joysticks are already being updated */
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
return;
}
SDL_updating_joystick = SDL_TRUE;
/* Make sure the list is unlocked while dispatching events to prevent application deadlocks */
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
SDL_SYS_JoystickUpdate(joystick);
@@ -885,7 +879,7 @@ SDL_JoystickUpdate(void)
}
}
- SDL_LockJoystickList();
+ SDL_LockJoysticks();
SDL_updating_joystick = SDL_FALSE;
@@ -901,7 +895,7 @@ SDL_JoystickUpdate(void)
*/
SDL_SYS_JoystickDetect();
- SDL_UnlockJoystickList();
+ SDL_UnlockJoysticks();
}
int
diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h
index 5339b83780..85d3920042 100644
--- a/src/joystick/SDL_joystick_c.h
+++ b/src/joystick/SDL_joystick_c.h
@@ -33,10 +33,6 @@ extern void SDL_GameControllerQuitMappings(void);
extern int SDL_GameControllerInit(void);
extern void SDL_GameControllerQuit(void);
-/* Locking for multi-threaded access to the joystick API */
-extern void SDL_LockJoystickList(void);
-extern void SDL_UnlockJoystickList(void);
-
/* Function to extract information from an SDL joystick GUID */
extern void SDL_GetJoystickGUIDInfo(SDL_JoystickGUID guid, Uint16 *vendor, Uint16 *product, Uint16 *version);
diff --git a/src/joystick/android/SDL_sysjoystick.c b/src/joystick/android/SDL_sysjoystick.c
index 59adb85bd2..05f1bcde1d 100644
--- a/src/joystick/android/SDL_sysjoystick.c
+++ b/src/joystick/android/SDL_sysjoystick.c
@@ -35,6 +35,7 @@
#include "SDL_sysjoystick_c.h"
#include "../SDL_joystick_c.h"
#include "../../core/android/SDL_android.h"
+#include "../steam/SDL_steamcontroller.h"
#include "android/keycodes.h"
@@ -216,7 +217,7 @@ Android_OnJoy(int device_id, int axis, float value)
/* Android gives joy info normalized as [-1.0, 1.0] or [0.0, 1.0] */
SDL_joylist_item *item = JoystickByDeviceId(device_id);
if (item && item->joystick) {
- SDL_PrivateJoystickAxis(item->joystick, axis, (Sint16) (32767.*value) );
+ SDL_PrivateJoystickAxis(item->joystick, axis, (Sint16) (32767.*value));
}
return 0;
@@ -234,7 +235,7 @@ Android_OnHat(int device_id, int hat_id, int x, int y)
if (x >= -1 && x <=1 && y >= -1 && y <= 1) {
SDL_joylist_item *item = JoystickByDeviceId(device_id);
if (item && item->joystick) {
- SDL_PrivateJoystickHat(item->joystick, hat_id, position_map[y+1][x+1] );
+ SDL_PrivateJoystickHat(item->joystick, hat_id, position_map[y+1][x+1]);
}
return 0;
}
@@ -254,8 +255,8 @@ Android_AddJoystick(int device_id, const char *name, const char *desc, SDL_bool
}
/* the GUID is just the first 16 chars of the name for now */
- SDL_zero( guid );
- SDL_memcpy( &guid, desc, SDL_min( sizeof(guid), SDL_strlen( desc) ) );
+ SDL_zero(guid);
+ SDL_memcpy(&guid, desc, SDL_min(sizeof(guid), SDL_strlen(desc)));
item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
if (item == NULL) {
@@ -266,7 +267,7 @@ Android_AddJoystick(int device_id, const char *name, const char *desc, SDL_bool
item->guid = guid;
item->device_id = device_id;
item->name = SDL_strdup(name);
- if ( item->name == NULL ) {
+ if (item->name == NULL) {
SDL_free(item);
return -1;
}
@@ -349,6 +350,79 @@ Android_RemoveJoystick(int device_id)
}
+static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
+{
+ SDL_joylist_item *item;
+
+ item = (SDL_joylist_item *)SDL_calloc(1, sizeof (SDL_joylist_item));
+ if (item == NULL) {
+ return SDL_FALSE;
+ }
+
+ *device_instance = item->device_instance = instance_counter++;
+ item->device_id = -1;
+ item->name = SDL_strdup(name);
+ item->guid = guid;
+ SDL_GetSteamControllerInputs(&item->nbuttons,
+ &item->naxes,
+ &item->nhats);
+ item->m_bSteamController = SDL_TRUE;
+
+ if (SDL_joylist_tail == NULL) {
+ SDL_joylist = SDL_joylist_tail = item;
+ } else {
+ SDL_joylist_tail->next = item;
+ SDL_joylist_tail = item;
+ }
+
+ /* Need to increment the joystick count before we post the event */
+ ++numjoysticks;
+
+ SDL_PrivateJoystickAdded(numjoysticks - 1);
+
+ return SDL_TRUE;
+}
+
+static void SteamControllerDisconnectedCallback(int device_instance)
+{
+ SDL_joylist_item *item = SDL_joylist;
+ SDL_joylist_item *prev = NULL;
+
+ while (item != NULL) {
+ if (item->device_instance == device_instance) {
+ break;
+ }
+ prev = item;
+ item = item->next;
+ }
+
+ if (item == NULL) {
+ return;
+ }
+
+ if (item->joystick) {
+ item->joystick->hwdata = NULL;
+ }
+
+ if (prev != NULL) {
+ prev->next = item->next;
+ } else {
+ SDL_assert(SDL_joylist == item);
+ SDL_joylist = item->next;
+ }
+ if (item == SDL_joylist_tail) {
+ SDL_joylist_tail = prev;
+ }
+
+ /* Need to decrement the joystick count before we post the event */
+ --numjoysticks;
+
+ SDL_PrivateJoystickRemoved(item->device_instance);
+
+ SDL_free(item->name);
+ SDL_free(item);
+}
+
int
SDL_SYS_JoystickInit(void)
{
@@ -359,6 +433,9 @@ SDL_SYS_JoystickInit(void)
Android_AddJoystick(ANDROID_ACCELEROMETER_DEVICE_ID, ANDROID_ACCELEROMETER_NAME, ANDROID_ACCELEROMETER_NAME, SDL_TRUE, 0, 3, 0, 0);
}
+ SDL_InitSteamControllers(SteamControllerConnectedCallback,
+ SteamControllerDisconnectedCallback);
+
return (numjoysticks);
}
@@ -381,6 +458,8 @@ SDL_SYS_JoystickDetect(void)
timeout = SDL_GetTicks() + 3000;
Android_JNI_PollInputDevices();
}
+
+ SDL_UpdateSteamControllers();
}
static SDL_joylist_item *
@@ -449,7 +528,7 @@ SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
{
SDL_joylist_item *item = JoystickByDevIndex(device_index);
- if (item == NULL ) {
+ if (item == NULL) {
return SDL_SetError("No such device");
}
@@ -477,30 +556,34 @@ SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
void
SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
{
- int i;
- Sint16 value;
- float values[3];
- SDL_joylist_item *item = SDL_joylist;
+ SDL_joylist_item *item = (SDL_joylist_item *) joystick->hwdata;
- while (item) {
- if (item->is_accelerometer) {
- if (item->joystick) {
- if (Android_JNI_GetAccelerometerValues(values)) {
- for ( i = 0; i < 3; i++ ) {
- if (values[i] > 1.0f) {
- values[i] = 1.0f;
- } else if (values[i] < -1.0f) {
- values[i] = -1.0f;
- }
-
- value = (Sint16)(values[i] * 32767.0f);
- SDL_PrivateJoystickAxis(item->joystick, i, value);
- }
+ if (item == NULL) {
+ return;
+ }
+
+ if (item->m_bSteamController) {
+ SDL_UpdateSteamController(joystick);
+ return;
+ }
+
+ if (item->is_accelerometer) {
+ int i;
+ Sint16 value;
+ float values[3];
+
+ if (Android_JNI_GetAccelerometerValues(values)) {
+ for (i = 0; i < 3; i++) {
+ if (values[i] > 1.0f) {
+ values[i] = 1.0f;
+ } else if (values[i] < -1.0f) {
+ values[i] = -1.0f;
}
+
+ value = (Sint16)(values[i] * 32767.0f);
+ SDL_PrivateJoystickAxis(item->joystick, i, value);
}
- break;
}
- item = item->next;
}
}
@@ -518,6 +601,10 @@ SDL_SYS_JoystickClose(SDL_Joystick * joystick)
void
SDL_SYS_JoystickQuit(void)
{
+/* We don't have any way to scan for joysticks at init, so don't wipe the list
+ * of joysticks here in case this is a reinit.
+ */
+#if 0
SDL_joylist_item *item = NULL;
SDL_joylist_item *next = NULL;
@@ -531,9 +618,12 @@ SDL_SYS_JoystickQuit(void)
numjoysticks = 0;
instance_counter = 0;
+#endif /* 0 */
+
+ SDL_QuitSteamControllers();
}
-SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
+SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index)
{
return JoystickByDevIndex(device_index)->guid;
}
diff --git a/src/joystick/android/SDL_sysjoystick_c.h b/src/joystick/android/SDL_sysjoystick_c.h
index cae7aff168..5002222e3d 100644
--- a/src/joystick/android/SDL_sysjoystick_c.h
+++ b/src/joystick/android/SDL_sysjoystick_c.h
@@ -46,6 +46,9 @@ typedef struct SDL_joylist_item
SDL_Joystick *joystick;
int nbuttons, naxes, nhats, nballs;
+ /* Steam Controller support */
+ SDL_bool m_bSteamController;
+
struct SDL_joylist_item *next;
} SDL_joylist_item;
diff --git a/src/joystick/iphoneos/SDL_sysjoystick.m b/src/joystick/iphoneos/SDL_sysjoystick.m
index 3af5350be1..ec0b2e1e0a 100644
--- a/src/joystick/iphoneos/SDL_sysjoystick.m
+++ b/src/joystick/iphoneos/SDL_sysjoystick.m
@@ -26,12 +26,15 @@
/* needed for SDL_IPHONE_MAX_GFORCE macro */
#include "SDL_config_iphoneos.h"
+#include "SDL_assert.h"
#include "SDL_events.h"
#include "SDL_joystick.h"
#include "SDL_hints.h"
#include "SDL_stdinc.h"
#include "../SDL_sysjoystick.h"
#include "../SDL_joystick_c.h"
+#include "../steam/SDL_steamcontroller.h"
+
#if !SDL_EVENTS_DISABLED
#include "../../events/SDL_events_c.h"
@@ -242,7 +245,7 @@
--numjoysticks;
- SDL_PrivateJoystickRemoved(device->instance_id);
+ SDL_PrivateJoystickRemoved(device->instance_id);
SDL_free(device->name);
SDL_free(device);
@@ -266,6 +269,50 @@
}
#endif /* TARGET_OS_TV */
+static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
+{
+ SDL_JoystickDeviceItem *device = (SDL_JoystickDeviceItem *)SDL_calloc(1, sizeof(SDL_JoystickDeviceItem));
+ if (device == NULL) {
+ return SDL_FALSE;
+ }
+
+ *device_instance = device->instance_id = instancecounter++;
+ device->name = SDL_strdup(name);
+ device->guid = guid;
+ SDL_GetSteamControllerInputs(&device->nbuttons,
+ &device->naxes,
+ &device->nhats);
+ device->m_bSteamController = SDL_TRUE;
+
+ if (deviceList == NULL) {
+ deviceList = device;
+ } else {
+ SDL_JoystickDeviceItem *lastdevice = deviceList;
+ while (lastdevice->next != NULL) {
+ lastdevice = lastdevice->next;
+ }
+ lastdevice->next = device;
+ }
+
+ ++numjoysticks;
+
+ SDL_PrivateJoystickAdded(numjoysticks - 1);
+
+ return SDL_TRUE;
+}
+
+static void SteamControllerDisconnectedCallback(int device_instance)
+{
+ SDL_JoystickDeviceItem *item;
+
+ for (item = deviceList; item; item = item->next) {
+ if (item->instance_id == device_instance) {
+ SDL_SYS_RemoveJoystickDevice(item);
+ break;
+ }
+ }
+}
+
/* Function to scan the system for joysticks.
* Joystick 0 should be the system default joystick.
* It should return 0, or -1 on an unrecoverable fatal error.
@@ -276,6 +323,9 @@
@autoreleasepool {
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
+ SDL_InitSteamControllers(SteamControllerConnectedCallback,
+ SteamControllerDisconnectedCallback);
+
#if !TARGET_OS_TV
if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE)) {
/* Default behavior, accelerometer as joystick */
@@ -335,6 +385,7 @@
void
SDL_SYS_JoystickDetect(void)
{
+ SDL_UpdateSteamControllers();
}
/* Function to get the device-dependent name of a joystick */
@@ -628,6 +679,11 @@ SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
if (device == NULL) {
return;
}
+
+ if (device->m_bSteamController) {
+ SDL_UpdateSteamController(joystick);
+ return;
+ }
if (device->accelerometer) {
SDL_SYS_AccelerometerUpdate(joystick);
@@ -696,6 +752,8 @@ SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
#endif /* !TARGET_OS_TV */
}
+ SDL_QuitSteamControllers();
+
numjoysticks = 0;
}
diff --git a/src/joystick/iphoneos/SDL_sysjoystick_c.h b/src/joystick/iphoneos/SDL_sysjoystick_c.h
index dc0e7beeb5..30edb999ec 100644
--- a/src/joystick/iphoneos/SDL_sysjoystick_c.h
+++ b/src/joystick/iphoneos/SDL_sysjoystick_c.h
@@ -44,6 +44,9 @@ typedef struct joystick_hwdata
int nbuttons;
int nhats;
+ /* Steam Controller support */
+ SDL_bool m_bSteamController;
+
struct joystick_hwdata *next;
} joystick_hwdata;
diff --git a/src/joystick/linux/SDL_sysjoystick.c b/src/joystick/linux/SDL_sysjoystick.c
index 1f19d1d392..84d99a2c2b 100644
--- a/src/joystick/linux/SDL_sysjoystick.c
+++ b/src/joystick/linux/SDL_sysjoystick.c
@@ -38,8 +38,10 @@
#include "SDL_assert.h"
#include "SDL_joystick.h"
#include "SDL_endian.h"
+#include "../../events/SDL_events_c.h"
#include "../SDL_sysjoystick.h"
#include "../SDL_joystick_c.h"
+#include "../steam/SDL_steamcontroller.h"
#include "SDL_sysjoystick_c.h"
/* This isn't defined in older Linux kernel headers */
@@ -66,6 +68,9 @@ typedef struct SDL_joylist_item
dev_t devnum;
struct joystick_hwdata *hwdata;
struct SDL_joylist_item *next;
+
+ /* Steam Controller support */
+ SDL_bool m_bSteamController;
} SDL_joylist_item;
static SDL_joylist_item *SDL_joylist = NULL;
@@ -73,6 +78,7 @@ static SDL_joylist_item *SDL_joylist_tail = NULL;
static int numjoysticks = 0;
static int instance_counter = 0;
+
#define test_bit(nr, addr) \
(((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
#define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1)
@@ -428,6 +434,77 @@ JoystickInitWithUdev(void)
}
#endif
+static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
+{
+ SDL_joylist_item *item;
+
+ item = (SDL_joylist_item *) SDL_calloc(1, sizeof (SDL_joylist_item));
+ if (item == NULL) {
+ return SDL_FALSE;
+ }
+
+ item->path = SDL_strdup("");
+ item->name = SDL_strdup(name);
+ item->guid = guid;
+ item->m_bSteamController = SDL_TRUE;
+
+ if ((item->path == NULL) || (item->name == NULL)) {
+ SDL_free(item->path);
+ SDL_free(item->name);
+ SDL_free(item);
+ return SDL_FALSE;
+ }
+
+ *device_instance = item->device_instance = instance_counter++;
+ if (SDL_joylist_tail == NULL) {
+ SDL_joylist = SDL_joylist_tail = item;
+ } else {
+ SDL_joylist_tail->next = item;
+ SDL_joylist_tail = item;
+ }
+
+ /* Need to increment the joystick count before we post the event */
+ ++numjoysticks;
+
+ SDL_PrivateJoystickAdded(numjoysticks - 1);
+
+ return SDL_TRUE;
+}
+
+static void SteamControllerDisconnectedCallback(int device_instance)
+{
+ SDL_joylist_item *item;
+ SDL_joylist_item *prev = NULL;
+
+ for (item = SDL_joylist; item != NULL; item = item->next) {
+ /* found it, remove it. */
+ if (item->device_instance == device_instance) {
+ if (item->hwdata) {
+ item->hwdata->item = NULL;
+ }
+ if (prev != NULL) {
+ prev->next = item->next;
+ } else {
+ SDL_assert(SDL_joylist == item);
+ SDL_joylist = item->next;
+ }
+ if (item == SDL_joylist_tail) {
+ SDL_joylist_tail = prev;
+ }
+
+ /* Need to decrement the joystick count before we post the event */
+ --numjoysticks;
+
+ SDL_PrivateJoystickRemoved(item->device_instance);
+
+ SDL_free(item->name);
+ SDL_free(item);
+ return;
+ }
+ prev = item;
+ }
+}
+
int
SDL_SYS_JoystickInit(void)
{
@@ -447,6 +524,9 @@ SDL_SYS_JoystickInit(void)
SDL_free(envcopy);
}
+ SDL_InitSteamControllers(SteamControllerConnectedCallback,
+ SteamControllerDisconnectedCallback);
+
#if SDL_USE_LIBUDEV
return JoystickInitWithUdev();
#else
@@ -466,7 +546,8 @@ SDL_SYS_JoystickDetect(void)
#if SDL_USE_LIBUDEV
SDL_UDEV_Poll();
#endif
-
+
+ SDL_UpdateSteamControllers();
}
static SDL_joylist_item *
@@ -650,47 +731,53 @@ int
SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
{
SDL_joylist_item *item = JoystickByDevIndex(device_index);
- char *fname = NULL;
- int fd = -1;
if (item == NULL) {
return SDL_SetError("No such device");
}
- fname = item->path;
- fd = open(fname, O_RDONLY, 0);
- if (fd < 0) {
- return SDL_SetError("Unable to open %s", fname);
- }
-
joystick->instance_id = item->device_instance;
joystick->hwdata = (struct joystick_hwdata *)
- SDL_malloc(sizeof(*joystick->hwdata));
+ SDL_calloc(1, sizeof(*joystick->hwdata));
if (joystick->hwdata == NULL) {
- close(fd);
return SDL_OutOfMemory();
}
- SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
joystick->hwdata->item = item;
joystick->hwdata->guid = item->guid;
- joystick->hwdata->fd = fd;
- joystick->hwdata->fname = SDL_strdup(item->path);
- if (joystick->hwdata->fname == NULL) {
- SDL_free(joystick->hwdata);
- joystick->hwdata = NULL;
- close(fd);
- return SDL_OutOfMemory();
+ joystick->hwdata->m_bSteamController = item->m_bSteamController;
+
+ if (item->m_bSteamController) {
+ joystick->hwdata->fd = -1;
+ SDL_GetSteamControllerInputs(&joystick->nbuttons,
+ &joystick->naxes,
+ &joystick->nhats);
+ } else {
+ int fd = open(item->path, O_RDONLY, 0);
+ if (fd < 0) {
+ SDL_free(joystick->hwdata);
+ joystick->hwdata = NULL;
+ return SDL_SetError("Unable to open %s", item->path);
+ }
+
+ joystick->hwdata->fd = fd;
+ joystick->hwdata->fname = SDL_strdup(item->path);
+ if (joystick->hwdata->fname == NULL) {
+ SDL_free(joystick->hwdata);
+ joystick->hwdata = NULL;
+ close(fd);
+ return SDL_OutOfMemory();
+ }
+
+ /* Set the joystick to non-blocking read mode */
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+
+ /* Get the number of buttons and axes on the joystick */
+ ConfigJoystick(joystick, fd);
}
SDL_assert(item->hwdata == NULL);
item->hwdata = joystick->hwdata;
- /* Set the joystick to non-blocking read mode */
- fcntl(fd, F_SETFL, O_NONBLOCK);
-
- /* Get the number of buttons and axes on the joystick */
- ConfigJoystick(joystick, fd);
-
/* mark joystick as fresh and ready */
joystick->hwdata->fresh = 1;
@@ -881,6 +968,11 @@ SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
{
int i;
+ if (joystick->hwdata->m_bSteamController) {
+ SDL_UpdateSteamController(joystick);
+ return;
+ }
+
HandleInputEvents(joystick);
/* Deliver ball motion updates */
@@ -902,7 +994,9 @@ void
SDL_SYS_JoystickClose(SDL_Joystick * joystick)
{
if (joystick->hwdata) {
- close(joystick->hwdata->fd);
+ if (joystick->hwdata->fd >= 0) {
+ close(joystick->hwdata->fd);
+ }
if (joystick->hwdata->item) {
joystick->hwdata->item->hwdata = NULL;
}
@@ -936,6 +1030,8 @@ SDL_SYS_JoystickQuit(void)
SDL_UDEV_DelCallback(joystick_udev_callback);
SDL_UDEV_Quit();
#endif
+
+ SDL_QuitSteamControllers();
}
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
diff --git a/src/joystick/linux/SDL_sysjoystick_c.h b/src/joystick/linux/SDL_sysjoystick_c.h
index 5c2ed5bec6..0743c6e588 100644
--- a/src/joystick/linux/SDL_sysjoystick_c.h
+++ b/src/joystick/linux/SDL_sysjoystick_c.h
@@ -52,6 +52,9 @@ struct joystick_hwdata
} abs_correct[ABS_MAX];
int fresh;
+
+ /* Steam Controller support */
+ SDL_bool m_bSteamController;
};
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/joystick/steam/SDL_steamcontroller.c b/src/joystick/steam/SDL_steamcontroller.c
new file mode 100644
index 0000000000..800fb46f03
--- /dev/null
+++ b/src/joystick/steam/SDL_steamcontroller.c
@@ -0,0 +1,52 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2017 Sam Lantinga
+
+ 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_internal.h"
+
+#include "../SDL_sysjoystick.h"
+#include "../SDL_joystick_c.h"
+#include "SDL_steamcontroller.h"
+
+
+void SDL_InitSteamControllers(SteamControllerConnectedCallback_t connectedCallback,
+ SteamControllerDisconnectedCallback_t disconnectedCallback)
+{
+}
+
+void SDL_GetSteamControllerInputs(int *nbuttons, int *naxes, int *nhats)
+{
+ *nbuttons = 0;
+ *naxes = 0;
+ *nhats = 0;
+}
+
+void SDL_UpdateSteamControllers(void)
+{
+}
+
+void SDL_UpdateSteamController(SDL_Joystick *joystick)
+{
+}
+
+void SDL_QuitSteamControllers(void)
+{
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/joystick/steam/SDL_steamcontroller.h b/src/joystick/steam/SDL_steamcontroller.h
new file mode 100644
index 0000000000..bb0ec2a196
--- /dev/null
+++ b/src/joystick/steam/SDL_steamcontroller.h
@@ -0,0 +1,33 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2017 Sam Lantinga
+
+ 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_internal.h"
+
+typedef SDL_bool (*SteamControllerConnectedCallback_t)(const char *name, SDL_JoystickGUID guid, int *device_instance);
+typedef void (*SteamControllerDisconnectedCallback_t)(int device_instance);
+
+void SDL_InitSteamControllers(SteamControllerConnectedCallback_t connectedCallback,
+ SteamControllerDisconnectedCallback_t disconnectedCallback);
+void SDL_GetSteamControllerInputs(int *nbuttons, int *naxes, int *nhats);
+void SDL_UpdateSteamControllers(void);
+void SDL_UpdateSteamController(SDL_Joystick *joystick);
+void SDL_QuitSteamControllers(void);
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/main/windows/version.rc b/src/main/windows/version.rc
index f02cc9055d..b8968ce6e0 100644
--- a/src/main/windows/version.rc
+++ b/src/main/windows/version.rc
@@ -9,8 +9,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
//
VS_VERSION_INFO VERSIONINFO
- FILEVERSION 2,0,6,0
- PRODUCTVERSION 2,0,6,0
+ FILEVERSION 2,0,7,0
+ PRODUCTVERSION 2,0,7,0
FILEFLAGSMASK 0x3fL
FILEFLAGS 0x0L
FILEOS 0x40004L
@@ -23,12 +23,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "\0"
VALUE "FileDescription", "SDL\0"
- VALUE "FileVersion", "2, 0, 6, 0\0"
+ VALUE "FileVersion", "2, 0, 7, 0\0"
VALUE "InternalName", "SDL\0"
VALUE "LegalCopyright", "Copyright © 2017 Sam Lantinga\0"
VALUE "OriginalFilename", "SDL2.dll\0"
VALUE "ProductName", "Simple DirectMedia Layer\0"
- VALUE "ProductVersion", "2, 0, 6, 0\0"
+ VALUE "ProductVersion", "2, 0, 7, 0\0"
END
END
BLOCK "VarFileInfo"
diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index 71f707c1ac..7a4dfeffd8 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -219,7 +219,35 @@ SDL_RendererEventWatch(void *userdata, SDL_Event *event)
event->button.x = (int)(event->button.x / (renderer->scale.x * renderer->dpi_scale.x));
event->button.y = (int)(event->button.y / (renderer->scale.y * renderer->dpi_scale.y));
}
+ } else if (event->type == SDL_FINGERDOWN ||
+ event->type == SDL_FINGERUP ||
+ event->type == SDL_FINGERMOTION) {
+ if (renderer->logical_w) {
+ int w = 1;
+ int h = 1;
+ SDL_GetRendererOutputSize(renderer, &w, &h);
+
+ event->tfinger.x *= (w - 1);
+ event->tfinger.y *= (h - 1);
+
+ event->tfinger.x -= (renderer->viewport.x * renderer->dpi_scale.x);
+ event->tfinger.y -= (renderer->viewport.y * renderer->dpi_scale.y);
+ event->tfinger.x = (event->tfinger.x / (renderer->scale.x * renderer->dpi_scale.x));
+ event->tfinger.y = (event->tfinger.y / (renderer->scale.y * renderer->dpi_scale.y));
+
+ if (renderer->logical_w > 1) {
+ event->tfinger.x = event->tfinger.x / (renderer->logical_w - 1);
+ } else {
+ event->tfinger.x = 0.5f;
+ }
+ if (renderer->logical_h > 1) {
+ event->tfinger.y = event->tfinger.y / (renderer->logical_h - 1);
+ } else {
+ event->tfinger.y = 0.5f;
+ }
+ }
}
+
return 0;
}
diff --git a/src/render/SDL_yuv_sw.c b/src/render/SDL_yuv_sw.c
index 9d202e0e7f..49fce6db2c 100644
--- a/src/render/SDL_yuv_sw.c
+++ b/src/render/SDL_yuv_sw.c
@@ -265,7 +265,18 @@ Color32DitherYV12Mod1X(int *colortab, Uint32 * rgb_2_pix,
int cr_r;
int crb_g;
int cb_b;
- int cols_2 = cols / 2;
+ int cols_2 = (cols + 1) / 2;
+ /* not even dimensions */
+ int skip_last_col = 0;
+ int skip_last_row = 0;
+
+ if ( (cols & 0x1) ) {
+ skip_last_col = 1;
+ }
+
+ if ( (rows & 0x1) ) {
+ skip_last_row = 1;
+ }
row1 = (unsigned int *) out;
row2 = row1 + cols + mod;
@@ -273,7 +284,7 @@ Color32DitherYV12Mod1X(int *colortab, Uint32 * rgb_2_pix,
mod += cols + mod;
- y = rows / 2;
+ y = (rows + 1) / 2;
while (y--) {
x = cols_2;
while (x--) {
@@ -290,20 +301,27 @@ Color32DitherYV12Mod1X(int *colortab, Uint32 * rgb_2_pix,
*row1++ = (rgb_2_pix[L + cr_r] |
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
+ if (!(x == 0 && skip_last_col)) {
L = *lum++;
*row1++ = (rgb_2_pix[L + cr_r] |
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
+ } /* skip col */
+ if (!(y == 0 && skip_last_row)) {
+
/* Now, do second row. */
L = *lum2++;
*row2++ = (rgb_2_pix[L + cr_r] |
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
+ if (!(x == 1 && skip_last_col)) {
L = *lum2++;
*row2++ = (rgb_2_pix[L + cr_r] |
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
+ } /* skip col */
+ } /* skip row */
}
/*
@@ -670,7 +688,12 @@ Color32DitherYUY2Mod1X(int *colortab, Uint32 * rgb_2_pix,
int cr_r;
int crb_g;
int cb_b;
- int cols_2 = cols / 2;
+ int cols_2 = (cols + 1) / 2;
+ /* not even dimensions */
+ int skip_last_col = 0;
+ if ( (cols & 0x1) ) {
+ skip_last_col = 1;
+ }
row = (unsigned int *) out;
y = rows;
@@ -693,9 +716,11 @@ Color32DitherYUY2Mod1X(int *colortab, Uint32 * rgb_2_pix,
L = *lum;
lum += 2;
+
+ if (!(x == 0 && skip_last_col)) {
*row++ = (rgb_2_pix[L + cr_r] |
rgb_2_pix[L + crb_g] | rgb_2_pix[L + cb_b]);
-
+ } /* skip col */
}
row += mod;
@@ -1022,6 +1047,13 @@ SDL_SW_SetupYUVDisplay(SDL_SW_YUVTexture * swdata, Uint32 target_format)
swdata->Display2X = Color32DitherYUY2Mod2X;
}
break;
+ case SDL_PIXELFORMAT_NV21:
+ case SDL_PIXELFORMAT_NV12:
+ /* no Display{1,2}X function */
+ swdata->Display1X = NULL;
+ swdata->Display2X = NULL;
+ break;
+
default:
/* We should never get here (caught above) */
break;
@@ -1049,6 +1081,8 @@ SDL_SW_CreateYUVTexture(Uint32 format, int w, int h)
case SDL_PIXELFORMAT_YUY2:
case SDL_PIXELFORMAT_UYVY:
case SDL_PIXELFORMAT_YVYU:
+ case SDL_PIXELFORMAT_NV12:
+ case SDL_PIXELFORMAT_NV21:
break;
default:
SDL_SetError("Unsupported YUV format");
@@ -1065,7 +1099,35 @@ SDL_SW_CreateYUVTexture(Uint32 format, int w, int h)
swdata->target_format = SDL_PIXELFORMAT_UNKNOWN;
swdata->w = w;
swdata->h = h;
- swdata->pixels = (Uint8 *) SDL_malloc(w * h * 2);
+ {
+ const int sz_plane = w * h;
+ const int sz_plane_chroma = ((w + 1) / 2) * ((h + 1) / 2);
+ const int sz_plane_packed = ((w + 1) / 2) * h;
+ int dst_size = 0;
+ switch(format)
+ {
+ case SDL_PIXELFORMAT_YV12: /**< Planar mode: Y + V + U (3 planes) */
+ case SDL_PIXELFORMAT_IYUV: /**< Planar mode: Y + U + V (3 planes) */
+ dst_size = sz_plane + sz_plane_chroma + sz_plane_chroma;
+ break;
+
+ case SDL_PIXELFORMAT_YUY2: /**< Packed mode: Y0+U0+Y1+V0 (1 plane) */
+ case SDL_PIXELFORMAT_UYVY: /**< Packed mode: U0+Y0+V0+Y1 (1 plane) */
+ case SDL_PIXELFORMAT_YVYU: /**< Packed mode: Y0+V0+Y1+U0 (1 plane) */
+ dst_size = 4 * sz_plane_packed;
+ break;
+
+ case SDL_PIXELFORMAT_NV12: /**< Planar mode: Y + U/V interleaved (2 planes) */
+ case SDL_PIXELFORMAT_NV21: /**< Planar mode: Y + V/U interleaved (2 planes) */
+ dst_size = sz_plane + sz_plane_chroma + sz_plane_chroma;
+ break;
+
+ default:
+ SDL_assert(0 && "We should never get here (caught above)");
+ break;
+ }
+ swdata->pixels = (Uint8 *) SDL_malloc(dst_size);
+ }
swdata->colortab = (int *) SDL_malloc(4 * 256 * sizeof(int));
swdata->rgb_2_pix = (Uint32 *) SDL_malloc(3 * 768 * sizeof(Uint32));
if (!swdata->pixels || !swdata->colortab || !swdata->rgb_2_pix) {
@@ -1095,18 +1157,27 @@ SDL_SW_CreateYUVTexture(Uint32 format, int w, int h)
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
swdata->pitches[0] = w;
- swdata->pitches[1] = swdata->pitches[0] / 2;
- swdata->pitches[2] = swdata->pitches[0] / 2;
+ swdata->pitches[1] = (swdata->pitches[0] + 1) / 2;
+ swdata->pitches[2] = (swdata->pitches[0] + 1) / 2;
swdata->planes[0] = swdata->pixels;
swdata->planes[1] = swdata->planes[0] + swdata->pitches[0] * h;
- swdata->planes[2] = swdata->planes[1] + swdata->pitches[1] * h / 2;
+ swdata->planes[2] = swdata->planes[1] + swdata->pitches[1] * ((h + 1) / 2);
break;
case SDL_PIXELFORMAT_YUY2:
case SDL_PIXELFORMAT_UYVY:
case SDL_PIXELFORMAT_YVYU:
- swdata->pitches[0] = w * 2;
+ swdata->pitches[0] = ((w + 1) / 2) * 4;
swdata->planes[0] = swdata->pixels;
break;
+
+ case SDL_PIXELFORMAT_NV12:
+ case SDL_PIXELFORMAT_NV21:
+ swdata->pitches[0] = w;
+ swdata->pitches[1] = 2 * ((swdata->pitches[0] + 1) / 2);
+ swdata->planes[0] = swdata->pixels;
+ swdata->planes[1] = swdata->planes[0] + swdata->pitches[0] * h;
+ break;
+
default:
SDL_assert(0 && "We should never get here (caught above)");
break;
@@ -1135,7 +1206,7 @@ SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
if (rect->x == 0 && rect->y == 0 &&
rect->w == swdata->w && rect->h == swdata->h) {
SDL_memcpy(swdata->pixels, pixels,
- (swdata->h * swdata->w) + (swdata->h * swdata->w) / 2);
+ (swdata->h * swdata->w) + 2* ((swdata->h + 1) /2) * ((swdata->w + 1) / 2));
} else {
Uint8 *src, *dst;
int row;
@@ -1150,28 +1221,28 @@ SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
src += pitch;
dst += swdata->w;
}
-
+
/* Copy the next plane */
src = (Uint8 *) pixels + rect->h * pitch;
dst = swdata->pixels + swdata->h * swdata->w;
- dst += rect->y/2 * swdata->w/2 + rect->x/2;
- length = rect->w / 2;
- for (row = 0; row < rect->h/2; ++row) {
+ dst += rect->y/2 * ((swdata->w + 1) / 2) + rect->x/2;
+ length = (rect->w + 1) / 2;
+ for (row = 0; row < (rect->h + 1)/2; ++row) {
SDL_memcpy(dst, src, length);
- src += pitch/2;
- dst += swdata->w/2;
+ src += (pitch + 1)/2;
+ dst += (swdata->w + 1)/2;
}
/* Copy the next plane */
- src = (Uint8 *) pixels + rect->h * pitch + (rect->h * pitch) / 4;
+ src = (Uint8 *) pixels + rect->h * pitch + ((rect->h + 1) / 2) * ((pitch + 1) / 2);
dst = swdata->pixels + swdata->h * swdata->w +
- (swdata->h * swdata->w) / 4;
- dst += rect->y/2 * swdata->w/2 + rect->x/2;
- length = rect->w / 2;
- for (row = 0; row < rect->h/2; ++row) {
+ ((swdata->h + 1)/2) * ((swdata->w+1) / 2);
+ dst += rect->y/2 * ((swdata->w + 1)/2) + rect->x/2;
+ length = (rect->w + 1) / 2;
+ for (row = 0; row < (rect->h + 1)/2; ++row) {
SDL_memcpy(dst, src, length);
- src += pitch/2;
- dst += swdata->w/2;
+ src += (pitch + 1)/2;
+ dst += (swdata->w + 1)/2;
}
}
break;
@@ -1187,7 +1258,7 @@ SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
dst =
swdata->planes[0] + rect->y * swdata->pitches[0] +
rect->x * 2;
- length = rect->w * 2;
+ length = 4 * ((rect->w + 1) / 2);
for (row = 0; row < rect->h; ++row) {
SDL_memcpy(dst, src, length);
src += pitch;
@@ -1195,6 +1266,42 @@ SDL_SW_UpdateYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
}
}
break;
+ case SDL_PIXELFORMAT_NV12:
+ case SDL_PIXELFORMAT_NV21:
+ {
+ if (rect->x == 0 && rect->y == 0 && rect->w == swdata->w && rect->h == swdata->h) {
+ SDL_memcpy(swdata->pixels, pixels,
+ (swdata->h * swdata->w) + 2* ((swdata->h + 1) /2) * ((swdata->w + 1) / 2));
+ } else {
+
+ Uint8 *src, *dst;
+ int row;
+ size_t length;
+
+ /* Copy the Y plane */
+ src = (Uint8 *) pixels;
+ dst = swdata->pixels + rect->y * swdata->w + rect->x;
+ length = rect->w;
+ for (row = 0; row < rect->h; ++row) {
+ SDL_memcpy(dst, src, length);
+ src += pitch;
+ dst += swdata->w;
+ }
+
+ /* Copy the next plane */
+ src = (Uint8 *) pixels + rect->h * pitch;
+ dst = swdata->pixels + swdata->h * swdata->w;
+ dst += 2 * ((rect->y + 1)/2) * ((swdata->w + 1) / 2) + 2 * (rect->x/2);
+ length = 2 * ((rect->w + 1) / 2);
+ for (row = 0; row < (rect->h + 1)/2; ++row) {
+ SDL_memcpy(dst, src, length);
+ src += 2 * ((pitch + 1)/2);
+ dst += 2 * ((swdata->w + 1)/2);
+ }
+ }
+ }
+ break;
+
}
return 0;
}
@@ -1226,14 +1333,14 @@ SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
dst = swdata->pixels + swdata->h * swdata->w;
} else {
dst = swdata->pixels + swdata->h * swdata->w +
- (swdata->h * swdata->w) / 4;
+ ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2);
}
- dst += rect->y/2 * swdata->w/2 + rect->x/2;
- length = rect->w / 2;
- for (row = 0; row < rect->h/2; ++row) {
+ dst += rect->y/2 * ((swdata->w + 1)/2) + rect->x/2;
+ length = (rect->w + 1) / 2;
+ for (row = 0; row < (rect->h + 1)/2; ++row) {
SDL_memcpy(dst, src, length);
src += Upitch;
- dst += swdata->w/2;
+ dst += (swdata->w + 1)/2;
}
/* Copy the V plane */
@@ -1242,14 +1349,14 @@ SDL_SW_UpdateYUVTexturePlanar(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
dst = swdata->pixels + swdata->h * swdata->w;
} else {
dst = swdata->pixels + swdata->h * swdata->w +
- (swdata->h * swdata->w) / 4;
+ ((swdata->h + 1) / 2) * ((swdata->w + 1) / 2);
}
- dst += rect->y/2 * swdata->w/2 + rect->x/2;
- length = rect->w / 2;
- for (row = 0; row < rect->h/2; ++row) {
+ dst += rect->y/2 * ((swdata->w + 1)/2) + rect->x/2;
+ length = (rect->w + 1) / 2;
+ for (row = 0; row < (rect->h + 1)/2; ++row) {
SDL_memcpy(dst, src, length);
src += Vpitch;
- dst += swdata->w/2;
+ dst += (swdata->w + 1)/2;
}
return 0;
}
@@ -1261,11 +1368,13 @@ SDL_SW_LockYUVTexture(SDL_SW_YUVTexture * swdata, const SDL_Rect * rect,
switch (swdata->format) {
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
+ case SDL_PIXELFORMAT_NV12:
+ case SDL_PIXELFORMAT_NV21:
if (rect
&& (rect->x != 0 || rect->y != 0 || rect->w != swdata->w
|| rect->h != swdata->h)) {
return SDL_SetError
- ("YV12 and IYUV textures only support full surface locks");
+ ("YV12, IYUV, NV12, NV21 textures only support full surface locks");
}
break;
}
@@ -1383,6 +1492,12 @@ SDL_SW_CopyYUVToRGB(SDL_SW_YUVTexture * swdata, const SDL_Rect * srcrect,
Cr = lum + 1;
Cb = lum + 3;
break;
+ case SDL_PIXELFORMAT_NV12:
+ case SDL_PIXELFORMAT_NV21:
+ return SDL_ConvertPixels(swdata->w, swdata->h,
+ swdata->format, swdata->planes[0], swdata->pitches[0],
+ target_format, pixels, pitch);
+ break;
default:
return SDL_SetError("Unsupported YUV format in copy");
}
diff --git a/src/render/opengl/SDL_render_gl.c b/src/render/opengl/SDL_render_gl.c
index 305a744a06..a950d8b815 100644
--- a/src/render/opengl/SDL_render_gl.c
+++ b/src/render/opengl/SDL_render_gl.c
@@ -752,12 +752,12 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
if (texture->format == SDL_PIXELFORMAT_YV12 ||
texture->format == SDL_PIXELFORMAT_IYUV) {
/* Need to add size for the U and V planes */
- size += (2 * (texture->h * data->pitch) / 4);
+ size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
}
if (texture->format == SDL_PIXELFORMAT_NV12 ||
texture->format == SDL_PIXELFORMAT_NV21) {
/* Need to add size for the U/V plane */
- size += ((texture->h * data->pitch) / 2);
+ size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
}
data->pixels = SDL_calloc(1, size);
if (!data->pixels) {
@@ -875,8 +875,8 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
GL_CLAMP_TO_EDGE);
renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
- renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,
- texture_h/2, 0, format, type, NULL);
+ renderdata->glTexImage2D(data->type, 0, internalFormat, (texture_w+1)/2,
+ (texture_h+1)/2, 0, format, type, NULL);
renderdata->glBindTexture(data->type, data->vtexture);
renderdata->glTexParameteri(data->type, GL_TEXTURE_MIN_FILTER,
@@ -887,8 +887,8 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
GL_CLAMP_TO_EDGE);
renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
- renderdata->glTexImage2D(data->type, 0, internalFormat, texture_w/2,
- texture_h/2, 0, format, type, NULL);
+ renderdata->glTexImage2D(data->type, 0, internalFormat, (texture_w+1)/2,
+ (texture_h+1)/2, 0, format, type, NULL);
renderdata->glDisable(data->type);
}
@@ -909,8 +909,8 @@ GL_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
GL_CLAMP_TO_EDGE);
renderdata->glTexParameteri(data->type, GL_TEXTURE_WRAP_T,
GL_CLAMP_TO_EDGE);
- renderdata->glTexImage2D(data->type, 0, GL_LUMINANCE_ALPHA, texture_w/2,
- texture_h/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
+ renderdata->glTexImage2D(data->type, 0, GL_LUMINANCE_ALPHA, (texture_w+1)/2,
+ (texture_h+1)/2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
renderdata->glDisable(data->type);
}
@@ -937,7 +937,7 @@ GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
rect->h, data->format, data->formattype,
pixels);
if (data->yuv) {
- renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / 2));
+ renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, ((pitch + 1) / 2));
/* Skip to the correct offset into the next texture */
pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
@@ -947,29 +947,29 @@ GL_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
renderdata->glBindTexture(data->type, data->utexture);
}
renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
- rect->w/2, rect->h/2,
+ (rect->w+1)/2, (rect->h+1)/2,
data->format, data->formattype, pixels);
/* Skip to the correct offset into the next texture */
- pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
+ pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2));
if (texture->format == SDL_PIXELFORMAT_YV12) {
renderdata->glBindTexture(data->type, data->utexture);
} else {
renderdata->glBindTexture(data->type, data->vtexture);
}
renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
- rect->w/2, rect->h/2,
+ (rect->w+1)/2, (rect->h+1)/2,
data->format, data->formattype, pixels);
}
if (data->nv12) {
- renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, (pitch / 2));
+ renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, ((pitch + 1) / 2));
/* Skip to the correct offset into the next texture */
pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
renderdata->glBindTexture(data->type, data->utexture);
renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
- rect->w/2, rect->h/2,
+ (rect->w + 1)/2, (rect->h + 1)/2,
GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels);
}
renderdata->glDisable(data->type);
@@ -1000,13 +1000,13 @@ GL_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Upitch);
renderdata->glBindTexture(data->type, data->utexture);
renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
- rect->w/2, rect->h/2,
+ (rect->w + 1)/2, (rect->h + 1)/2,
data->format, data->formattype, Uplane);
renderdata->glPixelStorei(GL_UNPACK_ROW_LENGTH, Vpitch);
renderdata->glBindTexture(data->type, data->vtexture);
renderdata->glTexSubImage2D(data->type, 0, rect->x/2, rect->y/2,
- rect->w/2, rect->h/2,
+ (rect->w + 1)/2, (rect->h + 1)/2,
data->format, data->formattype, Vplane);
renderdata->glDisable(data->type);
diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c
index 0e87f2aa2f..bd343cf4fe 100644
--- a/src/render/opengles2/SDL_render_gles2.c
+++ b/src/render/opengles2/SDL_render_gles2.c
@@ -619,11 +619,11 @@ GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
size = texture->h * data->pitch;
if (data->yuv) {
/* Need to add size for the U and V planes */
- size += (2 * (texture->h * data->pitch) / 4);
+ size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
}
if (data->nv12) {
/* Need to add size for the U/V plane */
- size += ((texture->h * data->pitch) / 2);
+ size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
}
data->pixel_data = SDL_calloc(1, size);
if (!data->pixel_data) {
@@ -646,7 +646,7 @@ GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- renderdata->glTexImage2D(data->texture_type, 0, format, texture->w / 2, texture->h / 2, 0, format, type, NULL);
+ renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL);
renderdata->glGenTextures(1, &data->texture_u);
if (GL_CheckError("glGenTexures()", renderer) < 0) {
@@ -658,7 +658,7 @@ GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- renderdata->glTexImage2D(data->texture_type, 0, format, texture->w / 2, texture->h / 2, 0, format, type, NULL);
+ renderdata->glTexImage2D(data->texture_type, 0, format, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, format, type, NULL);
if (GL_CheckError("glTexImage2D()", renderer) < 0) {
return -1;
}
@@ -675,7 +675,7 @@ GLES2_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_MAG_FILTER, scaleMode);
renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
renderdata->glTexParameteri(data->texture_type, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- renderdata->glTexImage2D(data->texture_type, 0, GL_LUMINANCE_ALPHA, texture->w / 2, texture->h / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
+ renderdata->glTexImage2D(data->texture_type, 0, GL_LUMINANCE_ALPHA, (texture->w + 1) / 2, (texture->h + 1) / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, NULL);
if (GL_CheckError("glTexImage2D()", renderer) < 0) {
return -1;
}
@@ -775,14 +775,15 @@ GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect
GLES2_TexSubImage2D(data, tdata->texture_type,
rect->x / 2,
rect->y / 2,
- rect->w / 2,
- rect->h / 2,
+ (rect->w + 1) / 2,
+ (rect->h + 1) / 2,
tdata->pixel_format,
tdata->pixel_type,
- pixels, pitch / 2, 1);
+ pixels, (pitch + 1) / 2, 1);
+
/* Skip to the correct offset into the next texture */
- pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
+ pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1)/2));
if (texture->format == SDL_PIXELFORMAT_YV12) {
data->glBindTexture(tdata->texture_type, tdata->texture_u);
} else {
@@ -791,11 +792,11 @@ GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect
GLES2_TexSubImage2D(data, tdata->texture_type,
rect->x / 2,
rect->y / 2,
- rect->w / 2,
- rect->h / 2,
+ (rect->w + 1) / 2,
+ (rect->h + 1) / 2,
tdata->pixel_format,
tdata->pixel_type,
- pixels, pitch / 2, 1);
+ pixels, (pitch + 1) / 2, 1);
}
if (tdata->nv12) {
@@ -805,11 +806,11 @@ GLES2_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect
GLES2_TexSubImage2D(data, tdata->texture_type,
rect->x / 2,
rect->y / 2,
- rect->w / 2,
- rect->h / 2,
+ (rect->w + 1) / 2,
+ (rect->h + 1) / 2,
GL_LUMINANCE_ALPHA,
GL_UNSIGNED_BYTE,
- pixels, pitch, 2);
+ pixels, 2 * ((pitch + 1) / 2), 2);
}
return GL_CheckError("glTexSubImage2D()", renderer);
@@ -836,8 +837,8 @@ GLES2_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
GLES2_TexSubImage2D(data, tdata->texture_type,
rect->x / 2,
rect->y / 2,
- rect->w / 2,
- rect->h / 2,
+ (rect->w + 1) / 2,
+ (rect->h + 1) / 2,
tdata->pixel_format,
tdata->pixel_type,
Vplane, Vpitch, 1);
@@ -846,8 +847,8 @@ GLES2_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
GLES2_TexSubImage2D(data, tdata->texture_type,
rect->x / 2,
rect->y / 2,
- rect->w / 2,
- rect->h / 2,
+ (rect->w + 1) / 2,
+ (rect->h + 1) / 2,
tdata->pixel_format,
tdata->pixel_type,
Uplane, Upitch, 1);
@@ -2030,8 +2031,9 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags)
}
window_flags = SDL_GetWindowFlags(window);
+ /* OpenGL ES 3.0 is a superset of OpenGL ES 2.0 */
if (!(window_flags & SDL_WINDOW_OPENGL) ||
- profile_mask != SDL_GL_CONTEXT_PROFILE_ES || major != RENDERER_CONTEXT_MAJOR || minor != RENDERER_CONTEXT_MINOR) {
+ profile_mask != SDL_GL_CONTEXT_PROFILE_ES || major < RENDERER_CONTEXT_MAJOR) {
changed_window = SDL_TRUE;
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
diff --git a/src/stdlib/SDL_malloc.c b/src/stdlib/SDL_malloc.c
index db3b107857..225b19000a 100644
--- a/src/stdlib/SDL_malloc.c
+++ b/src/stdlib/SDL_malloc.c
@@ -26,33 +26,11 @@
#include "../SDL_internal.h"
/* This file contains portable memory management functions for SDL */
-
#include "SDL_stdinc.h"
+#include "SDL_atomic.h"
+#include "SDL_error.h"
-#if defined(HAVE_MALLOC)
-
-void *SDL_malloc(size_t size)
-{
- return malloc(size);
-}
-
-void *SDL_calloc(size_t nmemb, size_t size)
-{
- return calloc(nmemb, size);
-}
-
-void *SDL_realloc(void *ptr, size_t size)
-{
- return realloc(ptr, size);
-}
-
-void SDL_free(void *ptr)
-{
- free(ptr);
-}
-
-#else /* the rest of this is a LOT of tapdancing to implement malloc. :) */
-
+#ifndef HAVE_MALLOC
#define LACKS_SYS_TYPES_H
#define LACKS_STDIO_H
#define LACKS_STRINGS_H
@@ -60,6 +38,7 @@ void SDL_free(void *ptr)
#define LACKS_STDLIB_H
#define ABORT
#define USE_LOCKS 1
+#define USE_DL_PREFIX
/*
This is a version (aka dlmalloc) of malloc/free/realloc written by
@@ -636,12 +615,12 @@ DEFAULT_MMAP_THRESHOLD default: 256K
#define MALLINFO_FIELD_TYPE size_t
#endif /* MALLINFO_FIELD_TYPE */
+#ifndef memset
#define memset SDL_memset
+#endif
+#ifndef memcpy
#define memcpy SDL_memcpy
-#define malloc SDL_malloc
-#define calloc SDL_calloc
-#define realloc SDL_realloc
-#define free SDL_free
+#endif
/*
mallopt tuning options. SVID/XPG defines four standard parameter
@@ -5265,4 +5244,133 @@ mspace_mallopt(int param_number, int value)
#endif /* !HAVE_MALLOC */
+#ifdef HAVE_MALLOC
+#define real_malloc malloc
+#define real_calloc calloc
+#define real_realloc realloc
+#define real_free free
+#else
+#define real_malloc dlmalloc
+#define real_calloc dlcalloc
+#define real_realloc dlrealloc
+#define real_free dlfree
+#endif
+
+/* Memory functions used by SDL that can be replaced by the application */
+static struct
+{
+ SDL_malloc_func malloc_func;
+ SDL_calloc_func calloc_func;
+ SDL_realloc_func realloc_func;
+ SDL_free_func free_func;
+ SDL_atomic_t num_allocations;
+} s_mem = {
+ real_malloc, real_calloc, real_realloc, real_free, { 0 }
+};
+
+void SDL_GetMemoryFunctions(SDL_malloc_func *malloc_func,
+ SDL_calloc_func *calloc_func,
+ SDL_realloc_func *realloc_func,
+ SDL_free_func *free_func)
+{
+ if (malloc_func) {
+ *malloc_func = s_mem.malloc_func;
+ }
+ if (calloc_func) {
+ *calloc_func = s_mem.calloc_func;
+ }
+ if (realloc_func) {
+ *realloc_func = s_mem.realloc_func;
+ }
+ if (free_func) {
+ *free_func = s_mem.free_func;
+ }
+}
+
+int SDL_SetMemoryFunctions(SDL_malloc_func malloc_func,
+ SDL_calloc_func calloc_func,
+ SDL_realloc_func realloc_func,
+ SDL_free_func free_func)
+{
+ if (!malloc_func) {
+ return SDL_InvalidParamError("malloc_func");
+ }
+ if (!calloc_func) {
+ return SDL_InvalidParamError("calloc_func");
+ }
+ if (!realloc_func) {
+ return SDL_InvalidParamError("realloc_func");
+ }
+ if (!free_func) {
+ return SDL_InvalidParamError("free_func");
+ }
+
+ s_mem.malloc_func = malloc_func;
+ s_mem.calloc_func = calloc_func;
+ s_mem.realloc_func = realloc_func;
+ s_mem.free_func = free_func;
+ return 0;
+}
+
+int SDL_GetNumAllocations(void)
+{
+ return SDL_AtomicGet(&s_mem.num_allocations);
+}
+
+void *SDL_malloc(size_t size)
+{
+ void *mem;
+
+ if (!size) {
+ size = 1;
+ }
+
+ mem = s_mem.malloc_func(size);
+ if (mem) {
+ SDL_AtomicIncRef(&s_mem.num_allocations);
+ }
+ return mem;
+}
+
+void *SDL_calloc(size_t nmemb, size_t size)
+{
+ void *mem;
+
+ if (!nmemb || !size) {
+ nmemb = 1;
+ size = 1;
+ }
+
+ mem = s_mem.calloc_func(nmemb, size);
+ if (mem) {
+ SDL_AtomicIncRef(&s_mem.num_allocations);
+ }
+ return mem;
+}
+
+void *SDL_realloc(void *ptr, size_t size)
+{
+ void *mem;
+
+ if (!ptr && !size) {
+ size = 1;
+ }
+
+ mem = s_mem.realloc_func(ptr, size);
+ if (mem && !ptr) {
+ SDL_AtomicIncRef(&s_mem.num_allocations);
+ }
+ return mem;
+}
+
+void SDL_free(void *ptr)
+{
+ if (!ptr) {
+ return;
+ }
+
+ s_mem.free_func(ptr);
+ (void)SDL_AtomicDecRef(&s_mem.num_allocations);
+}
+
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/stdlib/SDL_string.c b/src/stdlib/SDL_string.c
index 1b6c39304e..ae5fef214d 100644
--- a/src/stdlib/SDL_string.c
+++ b/src/stdlib/SDL_string.c
@@ -561,16 +561,12 @@ SDL_strlcat(SDL_INOUT_Z_CAP(maxlen) char *dst, const char *src, size_t maxlen)
char *
SDL_strdup(const char *string)
{
-#if defined(HAVE_STRDUP)
- return strdup(string);
-#else
size_t len = SDL_strlen(string) + 1;
char *newstr = SDL_malloc(len);
if (newstr) {
SDL_strlcpy(newstr, string, len);
}
return newstr;
-#endif /* HAVE_STRDUP */
}
char *
diff --git a/src/test/SDL_test_common.c b/src/test/SDL_test_common.c
index 5bade2a206..d3101ea704 100644
--- a/src/test/SDL_test_common.c
+++ b/src/test/SDL_test_common.c
@@ -47,7 +47,18 @@ static void SDL_snprintfcat(SDL_OUT_Z_CAP(maxlen) char *text, size_t maxlen, SDL
SDLTest_CommonState *
SDLTest_CommonCreateState(char **argv, Uint32 flags)
{
- SDLTest_CommonState *state = (SDLTest_CommonState *)SDL_calloc(1, sizeof(*state));
+ int i;
+ SDLTest_CommonState *state;
+
+ /* Do this first so we catch all allocations */
+ for (i = 1; argv[i]; ++i) {
+ if (SDL_strcasecmp(argv[i], "--trackmem") == 0) {
+ SDLTest_TrackAllocations();
+ break;
+ }
+ }
+
+ state = (SDLTest_CommonState *)SDL_calloc(1, sizeof(*state));
if (!state) {
SDL_OutOfMemory();
return NULL;
@@ -447,6 +458,10 @@ SDLTest_CommonArg(SDLTest_CommonState * state, int index)
state->audiospec.samples = (Uint16) SDL_atoi(argv[index]);
return 2;
}
+ if (SDL_strcasecmp(argv[index], "--trackmem") == 0) {
+ /* Already handled in SDLTest_CommonCreateState() */
+ return 1;
+ }
if ((SDL_strcasecmp(argv[index], "-h") == 0)
|| (SDL_strcasecmp(argv[index], "--help") == 0)) {
/* Print the usage message */
@@ -464,13 +479,13 @@ SDLTest_CommonUsage(SDLTest_CommonState * state)
{
switch (state->flags & (SDL_INIT_VIDEO | SDL_INIT_AUDIO)) {
case SDL_INIT_VIDEO:
- return VIDEO_USAGE;
+ return "[--trackmem] " VIDEO_USAGE;
case SDL_INIT_AUDIO:
- return AUDIO_USAGE;
+ return "[--trackmem] " AUDIO_USAGE;
case (SDL_INIT_VIDEO | SDL_INIT_AUDIO):
- return VIDEO_USAGE " " AUDIO_USAGE;
+ return "[--trackmem] " VIDEO_USAGE " " AUDIO_USAGE;
default:
- return "";
+ return "[--trackmem]";
}
}
@@ -661,6 +676,52 @@ SDLTest_LoadIcon(const char *file)
return (icon);
}
+static SDL_HitTestResult SDLCALL
+SDLTest_ExampleHitTestCallback(SDL_Window *win, const SDL_Point *area, void *data)
+{
+ int w, h;
+ const int RESIZE_BORDER = 8;
+ const int DRAGGABLE_TITLE = 32;
+
+ /*SDL_Log("Hit test point %d,%d\n", area->x, area->y);*/
+
+ SDL_GetWindowSize(win, &w, &h);
+
+ if (area->x < RESIZE_BORDER) {
+ if (area->y < RESIZE_BORDER) {
+ SDL_Log("SDL_HITTEST_RESIZE_TOPLEFT\n");
+ return SDL_HITTEST_RESIZE_TOPLEFT;
+ } else if (area->y >= (h-RESIZE_BORDER)) {
+ SDL_Log("SDL_HITTEST_RESIZE_BOTTOMLEFT\n");
+ return SDL_HITTEST_RESIZE_BOTTOMLEFT;
+ } else {
+ SDL_Log("SDL_HITTEST_RESIZE_LEFT\n");
+ return SDL_HITTEST_RESIZE_LEFT;
+ }
+ } else if (area->x >= (w-RESIZE_BORDER)) {
+ if (area->y < RESIZE_BORDER) {
+ SDL_Log("SDL_HITTEST_RESIZE_TOPRIGHT\n");
+ return SDL_HITTEST_RESIZE_TOPRIGHT;
+ } else if (area->y >= (h-RESIZE_BORDER)) {
+ SDL_Log("SDL_HITTEST_RESIZE_BOTTOMRIGHT\n");
+ return SDL_HITTEST_RESIZE_BOTTOMRIGHT;
+ } else {
+ SDL_Log("SDL_HITTEST_RESIZE_RIGHT\n");
+ return SDL_HITTEST_RESIZE_RIGHT;
+ }
+ } else if (area->y >= (h-RESIZE_BORDER)) {
+ SDL_Log("SDL_HITTEST_RESIZE_BOTTOM\n");
+ return SDL_HITTEST_RESIZE_BOTTOM;
+ } else if (area->y < RESIZE_BORDER) {
+ SDL_Log("SDL_HITTEST_RESIZE_TOP\n");
+ return SDL_HITTEST_RESIZE_TOP;
+ } else if (area->y < DRAGGABLE_TITLE) {
+ SDL_Log("SDL_HITTEST_DRAGGABLE\n");
+ return SDL_HITTEST_DRAGGABLE;
+ }
+ return SDL_HITTEST_NORMAL;
+}
+
SDL_bool
SDLTest_CommonInit(SDLTest_CommonState * state)
{
@@ -734,8 +795,8 @@ SDLTest_CommonInit(SDLTest_CommonState * state)
int bpp;
Uint32 Rmask, Gmask, Bmask, Amask;
#if SDL_VIDEO_DRIVER_WINDOWS
- int adapterIndex = 0;
- int outputIndex = 0;
+ int adapterIndex = 0;
+ int outputIndex = 0;
#endif
n = SDL_GetNumVideoDisplays();
SDL_Log("Number of displays: %d\n", n);
@@ -778,7 +839,7 @@ SDLTest_CommonInit(SDLTest_CommonState * state)
SDL_GetDisplayMode(i, j, &mode);
SDL_PixelFormatEnumToMasks(mode.format, &bpp, &Rmask,
&Gmask, &Bmask, &Amask);
- SDL_Log(" Mode %d: %dx%d@%dHz, %d bits-per-pixel (%s)\n",
+ SDL_Log(" Mode %d: %dx%d@%dHz, %d bits-per-pixel (%s)\n",
j, mode.w, mode.h, mode.refresh_rate, bpp,
SDL_GetPixelFormatName(mode.format));
if (Rmask || Gmask || Bmask) {
@@ -789,20 +850,20 @@ SDLTest_CommonInit(SDLTest_CommonState * state)
SDL_Log(" Blue Mask = 0x%.8x\n",
Bmask);
if (Amask)
- SDL_Log(" Alpha Mask = 0x%.8x\n",
+ SDL_Log(" Alpha Mask = 0x%.8x\n",
Amask);
}
}
}
#if SDL_VIDEO_DRIVER_WINDOWS
- /* Print the D3D9 adapter index */
- adapterIndex = SDL_Direct3D9GetAdapterIndex( i );
- SDL_Log("D3D9 Adapter Index: %d", adapterIndex);
+ /* Print the D3D9 adapter index */
+ adapterIndex = SDL_Direct3D9GetAdapterIndex( i );
+ SDL_Log("D3D9 Adapter Index: %d", adapterIndex);
- /* Print the DXGI adapter and output indices */
- SDL_DXGIGetOutputInfo(i, &adapterIndex, &outputIndex);
- SDL_Log("DXGI Adapter Index: %d Output Index: %d", adapterIndex, outputIndex);
+ /* Print the DXGI adapter and output indices */
+ SDL_DXGIGetOutputInfo(i, &adapterIndex, &outputIndex);
+ SDL_Log("DXGI Adapter Index: %d Output Index: %d", adapterIndex, outputIndex);
#endif
}
}
@@ -892,6 +953,12 @@ SDLTest_CommonInit(SDLTest_CommonState * state)
return SDL_FALSE;
}
+ /* Add resize/drag areas for windows that are borderless and resizable */
+ if ((state->window_flags & (SDL_WINDOW_RESIZABLE|SDL_WINDOW_BORDERLESS)) ==
+ (SDL_WINDOW_RESIZABLE|SDL_WINDOW_BORDERLESS)) {
+ SDL_SetWindowHitTest(state->windows[i], SDLTest_ExampleHitTestCallback, NULL);
+ }
+
if (state->window_icon) {
SDL_Surface *icon = SDLTest_LoadIcon(state->window_icon);
if (icon) {
@@ -918,7 +985,7 @@ SDLTest_CommonInit(SDLTest_CommonState * state)
}
}
if (m == -1) {
- SDL_Log("Couldn't find render driver named %s",
+ SDL_Log("Couldn't find render driver named %s",
state->renderdriver);
return SDL_FALSE;
}
@@ -1710,6 +1777,7 @@ SDLTest_CommonQuit(SDLTest_CommonState * state)
}
SDL_free(state);
SDL_Quit();
+ SDLTest_LogAllocations();
}
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/test/SDL_test_crc32.c b/src/test/SDL_test_crc32.c
index a8878eaa2a..867f7c611a 100644
--- a/src/test/SDL_test_crc32.c
+++ b/src/test/SDL_test_crc32.c
@@ -69,7 +69,6 @@ int SDLTest_Crc32Init(SDLTest_Crc32Context *crcContext)
}
/* Complete CRC32 calculation on a memory block */
-/* un-used
int SDLTest_Crc32Calc(SDLTest_Crc32Context * crcContext, CrcUint8 *inBuf, CrcUint32 inLen, CrcUint32 *crc32)
{
if (SDLTest_Crc32CalcStart(crcContext,crc32)) {
@@ -86,7 +85,6 @@ int SDLTest_Crc32Calc(SDLTest_Crc32Context * crcContext, CrcUint8 *inBuf, CrcUin
return 0;
}
-*/
/* Start crc calculation */
diff --git a/src/test/SDL_test_memory.c b/src/test/SDL_test_memory.c
new file mode 100644
index 0000000000..3a2dc71081
--- /dev/null
+++ b/src/test/SDL_test_memory.c
@@ -0,0 +1,274 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2017 Sam Lantinga
+
+ 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_config.h"
+#include "SDL_assert.h"
+#include "SDL_stdinc.h"
+#include "SDL_log.h"
+#include "SDL_test_crc32.h"
+#include "SDL_test_memory.h"
+
+#ifdef HAVE_LIBUNWIND_H
+#include
+#endif
+
+/* This is a simple tracking allocator to demonstrate the use of SDL's
+ memory allocation replacement functionality.
+
+ It gets slow with large numbers of allocations and shouldn't be used
+ for production code.
+*/
+
+typedef struct SDL_tracked_allocation
+{
+ void *mem;
+ size_t size;
+ Uint64 stack[10];
+ char stack_names[10][256];
+ struct SDL_tracked_allocation *next;
+} SDL_tracked_allocation;
+
+static SDLTest_Crc32Context s_crc32_context;
+static SDL_malloc_func SDL_malloc_orig = NULL;
+static SDL_calloc_func SDL_calloc_orig = NULL;
+static SDL_realloc_func SDL_realloc_orig = NULL;
+static SDL_free_func SDL_free_orig = NULL;
+static int s_previous_allocations = 0;
+static SDL_tracked_allocation *s_tracked_allocations[256];
+
+static unsigned int get_allocation_bucket(void *mem)
+{
+ CrcUint32 crc_value;
+ unsigned int index;
+ SDLTest_Crc32Calc(&s_crc32_context, (CrcUint8 *)&mem, sizeof(mem), &crc_value);
+ index = (crc_value & (SDL_arraysize(s_tracked_allocations) - 1));
+ return index;
+}
+
+static SDL_bool SDL_IsAllocationTracked(void *mem)
+{
+ SDL_tracked_allocation *entry;
+ int index = get_allocation_bucket(mem);
+ for (entry = s_tracked_allocations[index]; entry; entry = entry->next) {
+ if (mem == entry->mem) {
+ return SDL_TRUE;
+ }
+ }
+ return SDL_FALSE;
+}
+
+static void SDL_TrackAllocation(void *mem, size_t size)
+{
+ SDL_tracked_allocation *entry;
+ int index = get_allocation_bucket(mem);
+
+ if (SDL_IsAllocationTracked(mem)) {
+ return;
+ }
+ entry = (SDL_tracked_allocation *)SDL_malloc_orig(sizeof(*entry));
+ if (!entry) {
+ return;
+ }
+ entry->mem = mem;
+ entry->size = size;
+
+ /* Generate the stack trace for the allocation */
+ SDL_zero(entry->stack);
+#ifdef HAVE_LIBUNWIND_H
+ {
+ int stack_index;
+ unw_cursor_t cursor;
+ unw_context_t context;
+
+ unw_getcontext(&context);
+ unw_init_local(&cursor, &context);
+
+ stack_index = 0;
+ while (unw_step(&cursor) > 0) {
+ unw_word_t offset, pc;
+ char sym[256];
+
+ unw_get_reg(&cursor, UNW_REG_IP, &pc);
+ entry->stack[stack_index] = pc;
+
+ if (unw_get_proc_name(&cursor, sym, sizeof(sym), &offset) == 0) {
+ snprintf(entry->stack_names[stack_index], sizeof(entry->stack_names[stack_index]), "%s+0x%llx", sym, offset);
+ }
+ ++stack_index;
+
+ if (stack_index == SDL_arraysize(entry->stack)) {
+ break;
+ }
+ }
+ }
+#endif /* HAVE_LIBUNWIND_H */
+
+ entry->next = s_tracked_allocations[index];
+ s_tracked_allocations[index] = entry;
+}
+
+static void SDL_UntrackAllocation(void *mem)
+{
+ SDL_tracked_allocation *entry, *prev;
+ int index = get_allocation_bucket(mem);
+
+ prev = NULL;
+ for (entry = s_tracked_allocations[index]; entry; entry = entry->next) {
+ if (mem == entry->mem) {
+ if (prev) {
+ prev->next = entry->next;
+ } else {
+ s_tracked_allocations[index] = entry->next;
+ }
+ SDL_free_orig(entry);
+ return;
+ }
+ prev = entry;
+ }
+}
+
+static void * SDLCALL SDLTest_TrackedMalloc(size_t size)
+{
+ void *mem;
+
+ mem = SDL_malloc_orig(size);
+ if (mem) {
+ SDL_TrackAllocation(mem, size);
+ }
+ return mem;
+}
+
+static void * SDLCALL SDLTest_TrackedCalloc(size_t nmemb, size_t size)
+{
+ void *mem;
+
+ mem = SDL_calloc_orig(nmemb, size);
+ if (mem) {
+ SDL_TrackAllocation(mem, nmemb * size);
+ }
+ return mem;
+}
+
+static void * SDLCALL SDLTest_TrackedRealloc(void *ptr, size_t size)
+{
+ void *mem;
+
+ SDL_assert(!ptr || SDL_IsAllocationTracked(ptr));
+ mem = SDL_realloc_orig(ptr, size);
+ if (mem && mem != ptr) {
+ if (ptr) {
+ SDL_UntrackAllocation(ptr);
+ }
+ SDL_TrackAllocation(mem, size);
+ }
+ return mem;
+}
+
+static void SDLCALL SDLTest_TrackedFree(void *ptr)
+{
+ if (!ptr) {
+ return;
+ }
+
+ if (!s_previous_allocations) {
+ SDL_assert(SDL_IsAllocationTracked(ptr));
+ }
+ SDL_UntrackAllocation(ptr);
+ SDL_free_orig(ptr);
+}
+
+int SDLTest_TrackAllocations()
+{
+ if (SDL_malloc_orig) {
+ return 0;
+ }
+
+ SDLTest_Crc32Init(&s_crc32_context);
+
+ s_previous_allocations = SDL_GetNumAllocations();
+ if (s_previous_allocations != 0) {
+ SDL_Log("SDLTest_TrackAllocations(): There are %d previous allocations, disabling free() validation", s_previous_allocations);
+ }
+
+ SDL_GetMemoryFunctions(&SDL_malloc_orig,
+ &SDL_calloc_orig,
+ &SDL_realloc_orig,
+ &SDL_free_orig);
+
+ SDL_SetMemoryFunctions(SDLTest_TrackedMalloc,
+ SDLTest_TrackedCalloc,
+ SDLTest_TrackedRealloc,
+ SDLTest_TrackedFree);
+ return 0;
+}
+
+void SDLTest_LogAllocations()
+{
+ char *message = NULL;
+ size_t message_size = 0;
+ char line[128], *tmp;
+ SDL_tracked_allocation *entry;
+ int index, count, stack_index;
+ Uint64 total_allocated;
+
+ if (!SDL_malloc_orig) {
+ return;
+ }
+
+#define ADD_LINE() \
+ message_size += (SDL_strlen(line) + 1); \
+ tmp = (char *)SDL_realloc_orig(message, message_size); \
+ if (!tmp) { \
+ return; \
+ } \
+ message = tmp; \
+ SDL_strlcat(message, line, message_size)
+
+ SDL_strlcpy(line, "Memory allocations:\n", sizeof(line));
+ ADD_LINE();
+ SDL_strlcpy(line, "Expect 2 allocations from within SDL_GetErrBuf()\n", sizeof(line));
+ ADD_LINE();
+
+ count = 0;
+ total_allocated = 0;
+ for (index = 0; index < SDL_arraysize(s_tracked_allocations); ++index) {
+ for (entry = s_tracked_allocations[index]; entry; entry = entry->next) {
+ SDL_snprintf(line, sizeof(line), "Allocation %d: %d bytes\n", count, (int)entry->size);
+ ADD_LINE();
+ /* Start at stack index 1 to skip our tracking functions */
+ for (stack_index = 1; stack_index < SDL_arraysize(entry->stack); ++stack_index) {
+ if (!entry->stack[stack_index]) {
+ break;
+ }
+ SDL_snprintf(line, sizeof(line), "\t0x%"SDL_PRIx64": %s\n", entry->stack[stack_index], entry->stack_names[stack_index]);
+ ADD_LINE();
+ }
+ total_allocated += entry->size;
+ ++count;
+ }
+ }
+ SDL_snprintf(line, sizeof(line), "Total: %.2f Kb in %d allocations\n", (float)total_allocated / 1024, count);
+ ADD_LINE();
+#undef ADD_LINE
+
+ SDL_Log("%s", message);
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c
index 600056fe93..38addea004 100644
--- a/src/video/SDL_surface.c
+++ b/src/video/SDL_surface.c
@@ -26,6 +26,21 @@
#include "SDL_RLEaccel_c.h"
#include "SDL_pixels_c.h"
+/* Private routines */
+static int
+SDL_ConvertPixels_YUV_to_ARGB8888(int width, int height,
+ Uint32 src_format, const void *src,
+ void *dst, int dst_pitch);
+
+static int
+SDL_ConvertPixels_ARGB8888_to_YUV(int width, int height,
+ const void *src, int src_pitch,
+ Uint32 dst_format, void *dst);
+
+/* Check to make sure we can safely check multiplication of surface w and pitch and it won't overflow size_t */
+SDL_COMPILE_TIME_ASSERT(surface_size_assumptions,
+ sizeof(int) == sizeof(Sint32) && sizeof(size_t) >= sizeof(Sint32));
+
/* Public routines */
/*
@@ -80,7 +95,16 @@ SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth,
/* Get the pixels */
if (surface->w && surface->h) {
- surface->pixels = SDL_malloc(surface->h * surface->pitch);
+ /* Assumptions checked in surface_size_assumptions assert above */
+ Sint64 size = ((Sint64)surface->h * surface->pitch);
+ if (size < 0 || size > SDL_MAX_SINT32) {
+ /* Overflow... */
+ SDL_FreeSurface(surface);
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+ surface->pixels = SDL_malloc((size_t)size);
if (!surface->pixels) {
SDL_FreeSurface(surface);
SDL_OutOfMemory();
@@ -1116,56 +1140,131 @@ int SDL_ConvertPixels(int width, int height,
/* Fast path for same format copy */
if (src_format == dst_format) {
- int bpp, i;
+ int i;
if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
switch (src_format) {
case SDL_PIXELFORMAT_YUY2:
case SDL_PIXELFORMAT_UYVY:
case SDL_PIXELFORMAT_YVYU:
- bpp = 2;
+ /* Packed planes */
+ width = 4 * ((width + 1) / 2);
+ for (i = height; i--;) {
+ SDL_memcpy(dst, src, width);
+ src = (const Uint8*)src + src_pitch;
+ dst = (Uint8*)dst + dst_pitch;
+ }
break;
case SDL_PIXELFORMAT_YV12:
case SDL_PIXELFORMAT_IYUV:
case SDL_PIXELFORMAT_NV12:
case SDL_PIXELFORMAT_NV21:
- bpp = 1;
+ {
+ /* Y plane */
+ for (i = height; i--;) {
+ SDL_memcpy(dst, src, width);
+ src = (const Uint8*)src + src_pitch;
+ dst = (Uint8*)dst + dst_pitch;
+ }
+
+ /* not sure the pitch is relevant here.
+ this also works to add the size of two chroma planes */
+#if 0
+ SDL_memcpy(dst, src, 2 * ((width + 1)/2) * ((height+1)/2));
+#else
+
+ if (src_format == SDL_PIXELFORMAT_YV12 || src_format == SDL_PIXELFORMAT_IYUV) {
+ /* U and V planes are a quarter the size of the Y plane */
+ width = (width + 1) / 2;
+ height = (height + 1) / 2;
+ src_pitch = (src_pitch + 1) / 2;
+ dst_pitch = (dst_pitch + 1) / 2;
+ for (i = height * 2; i--;) {
+ SDL_memcpy(dst, src, width);
+ src = (const Uint8*)src + src_pitch;
+ dst = (Uint8*)dst + dst_pitch;
+ }
+ } else if (src_format == SDL_PIXELFORMAT_NV12 || src_format == SDL_PIXELFORMAT_NV21) {
+ /* U/V plane is half the height of the Y plane */
+ height = (height + 1) / 2;
+ width = (width + 1) / 2;
+ src_pitch = (src_pitch + 1) / 2;
+ dst_pitch = (dst_pitch + 1) / 2;
+ for (i = height; i--;) {
+ SDL_memcpy(dst, src, 2 * width);
+ src = (const Uint8*)src + 2 * src_pitch;
+ dst = (Uint8*)dst + 2 * dst_pitch;
+ }
+ }
+#endif
+ }
break;
default:
return SDL_SetError("Unknown FOURCC pixel format");
}
} else {
- bpp = SDL_BYTESPERPIXEL(src_format);
+ const int bpp = SDL_BYTESPERPIXEL(src_format);
+ width *= bpp;
+ for (i = height; i--;) {
+ SDL_memcpy(dst, src, width);
+ src = (const Uint8*)src + src_pitch;
+ dst = (Uint8*)dst + dst_pitch;
+ }
}
- width *= bpp;
+ return 0;
+ }
- for (i = height; i--;) {
- SDL_memcpy(dst, src, width);
- src = (Uint8*)src + src_pitch;
- dst = (Uint8*)dst + dst_pitch;
+ /* FOURCC to Any */
+ if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
+ /* FOURCC to ARGB8888 */
+ if (dst_format == SDL_PIXELFORMAT_ARGB8888) {
+ SDL_ConvertPixels_YUV_to_ARGB8888(width, height, src_format, src, dst, dst_pitch);
+ return 0;
}
+ else /* FOURCC to not(ARGB8888) : need an intermediate conversion */
+ {
+ int ret;
+ void *tmp = SDL_malloc(width * height * 4);
+ if (tmp == NULL) {
+ return -1;
+ }
- if (src_format == SDL_PIXELFORMAT_YV12 || src_format == SDL_PIXELFORMAT_IYUV) {
- /* U and V planes are a quarter the size of the Y plane */
- width /= 2;
- height /= 2;
- src_pitch /= 2;
- dst_pitch /= 2;
- for (i = height * 2; i--;) {
- SDL_memcpy(dst, src, width);
- src = (Uint8*)src + src_pitch;
- dst = (Uint8*)dst + dst_pitch;
+ /* convert src/FOURCC to tmp/ARGB8888 */
+ SDL_ConvertPixels_YUV_to_ARGB8888(width, height, src_format, src, tmp, width * 4);
+
+ /* convert tmp/ARGB8888 to dst/dst_format */
+ ret = SDL_ConvertPixels(width, height, SDL_PIXELFORMAT_ARGB8888, tmp, width * 4, dst_format, dst, dst_pitch);
+ SDL_free(tmp);
+ return ret;
+ }
+ }
+
+ /* Any to FOURCC */
+ if (SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
+ /* ARGB8888 to FOURCC */
+ if (src_format == SDL_PIXELFORMAT_ARGB8888) {
+ SDL_ConvertPixels_ARGB8888_to_YUV(width, height, src, src_pitch, dst_format, dst);
+ return 0;
+ }
+ else /* not(ARGB8888) to FOURCC : need an intermediate conversion */
+ {
+ int ret;
+ void *tmp = SDL_malloc(width * height * 4);
+ if (tmp == NULL) {
+ return -1;
}
- } else if (src_format == SDL_PIXELFORMAT_NV12 || src_format == SDL_PIXELFORMAT_NV21) {
- /* U/V plane is half the height of the Y plane */
- height /= 2;
- for (i = height; i--;) {
- SDL_memcpy(dst, src, width);
- src = (Uint8*)src + src_pitch;
- dst = (Uint8*)dst + dst_pitch;
+ /* convert src/src_format to tmp/ARGB8888 */
+ ret = SDL_ConvertPixels(width, height, src_format, src, src_pitch, SDL_PIXELFORMAT_ARGB8888, tmp, width * 4);
+ if (ret == -1) {
+ SDL_free(tmp);
+ return ret;
}
+ /* convert tmp/ARGB8888 to dst/FOURCC */
+ SDL_ConvertPixels_ARGB8888_to_YUV(width, height, tmp, width * 4, dst_format, dst);
+
+ SDL_free(tmp);
+ return 0;
}
- return 0;
}
if (!SDL_CreateSurfaceOnStack(width, height, src_format, nonconst_src,
@@ -1198,10 +1297,8 @@ SDL_FreeSurface(SDL_Surface * surface)
if (surface->flags & SDL_DONTFREE) {
return;
}
- if (surface->map != NULL) {
- SDL_FreeBlitMap(surface->map);
- surface->map = NULL;
- }
+ SDL_InvalidateMap(surface->map);
+
if (--surface->refcount > 0) {
return;
}
@@ -1219,7 +1316,497 @@ SDL_FreeSurface(SDL_Surface * surface)
if (!(surface->flags & SDL_PREALLOC)) {
SDL_free(surface->pixels);
}
+ if (surface->map) {
+ SDL_FreeBlitMap(surface->map);
+ }
SDL_free(surface);
}
+
+/* YUV-RGB conversion */
+#define CLAMP(val) ((val) > 0 ? ((val) < 255 ? (val) : 255) : 0)
+
+#if 1
+
+/* Coefficients from CCIR 601 */
+#define MAKE_Y(r, g, b) (int)( 0.29900f * (r) + 0.58700f * (g) + 0.11400f * (b))
+#define MAKE_U(r, g, b) (int)(-0.16874f * (r) - 0.33126f * (g) + 0.50000f * (b) + 128)
+#define MAKE_V(r, g, b) (int)( 0.50000f * (r) - 0.41869f * (g) - 0.08131f * (b) + 128)
+
+#define MAKE_R(y, u, v) CLAMP((int)((y) + 1.40200f * ((v) - 128)))
+#define MAKE_G(y, u, v) CLAMP((int)((y) - 0.34414f * ((u) - 128) - 0.71414f * ((v) - 128)))
+#define MAKE_B(y, u, v) CLAMP((int)((y) + 1.77200f * ((u) - 128) ))
+
+#else
+
+/* Coefficients from Video Demystified */
+#define MAKE_Y(r, g, b) ((( 66 * (r) + 129 * (g) + 25 * (b) + 128) >> 8) + 16)
+#define MAKE_U(r, g, b) ((( -38 * (r) - 74 * (g) + 112 * (b) + 128) >> 8) + 128)
+#define MAKE_V(r, g, b) ((( 112 * (r) - 94 * (g) - 18 * (b) + 128) >> 8) + 128)
+
+#define MAKE_R(y, u, v) CLAMP(( 298 * ((y) - 16) + 409 * ((v) - 128) + 128) >> 8)
+#define MAKE_G(y, u, v) CLAMP(( 298 * ((y) - 16) - 100 * ((u) - 128) - 208 * ((v) - 128) + 128) >> 8)
+#define MAKE_B(y, u, v) CLAMP(( 298 * ((y) - 16) + 516 * ((u) - 128) + 128) >> 8)
+
+#endif
+
+
+static int
+SDL_ConvertPixels_YUV_to_ARGB8888(int width, int height,
+ Uint32 src_format, const void *src,
+ void *dst, int dst_pitch)
+{
+ const int sz_plane = width * height;
+ const int sz_plane_chroma = ((width + 1) / 2) * ((height + 1) / 2);
+ const int width_remainder = (width & 0x1);
+ const int width_half = width / 2;
+ const int curr_row_padding = dst_pitch - 4 * width;
+ int i, j;
+ Uint8 *curr_row = (Uint8*)dst;
+
+ // SDL_Log("SDL_ConvertPixels_YUV_to_ARGB8888 (from %s)", SDL_GetPixelFormatName(src_format));
+
+#define WRITE_RGB_PIXEL(y, u, v) \
+ *((Uint32*)curr_row) = \
+ (MAKE_B((y), (u), (v)) \
+ | (MAKE_G((y), (u), (v)) << 8) \
+ | (MAKE_R((y), (u), (v)) << 16) \
+ | 0xff000000); \
+ curr_row += 4; \
+
+ switch (src_format)
+ {
+ case SDL_PIXELFORMAT_YV12:
+ case SDL_PIXELFORMAT_IYUV:
+ case SDL_PIXELFORMAT_NV12:
+ case SDL_PIXELFORMAT_NV21:
+ {
+ const Uint8 *plane_y = (const Uint8*)src;
+
+ if (src_format == SDL_PIXELFORMAT_YV12 || src_format == SDL_PIXELFORMAT_IYUV)
+ {
+ const Uint8 *plane_u = (src_format == SDL_PIXELFORMAT_YV12 ? plane_y + sz_plane + sz_plane_chroma : plane_y + sz_plane);
+ const Uint8 *plane_v = (src_format == SDL_PIXELFORMAT_YV12 ? plane_y + sz_plane : plane_y + sz_plane + sz_plane_chroma);
+
+ for (j = 0; j < height; j++) {
+ for (i = 0; i < width_half; i++) {
+ const Uint8 u = *plane_u++;
+ const Uint8 v = *plane_v++;
+ const Uint8 y = *plane_y++;
+ const Uint8 y1 = *plane_y++;
+ WRITE_RGB_PIXEL(y, u, v);
+ WRITE_RGB_PIXEL(y1, u, v);
+ }
+ if (width_remainder) {
+ const Uint8 u = *plane_u++;
+ const Uint8 v = *plane_v++;
+ const Uint8 y = *plane_y++;
+ WRITE_RGB_PIXEL(y, u, v);
+ }
+ /* Re-use the same line of chroma planes */
+ if ((j & 0x1) == 0x0) {
+ plane_u -= width_half + width_remainder;
+ plane_v -= width_half + width_remainder;
+ }
+ curr_row += curr_row_padding;
+ }
+ }
+ else if (src_format == SDL_PIXELFORMAT_NV12)
+ {
+ const Uint8 *plane_interleaved_uv = plane_y + sz_plane;
+ for (j = 0; j < height; j++) {
+ for (i = 0; i < width_half; i++) {
+ const Uint8 y = *plane_y++;
+ const Uint8 y1 = *plane_y++;
+ const Uint8 u = *plane_interleaved_uv++;
+ const Uint8 v = *plane_interleaved_uv++;
+ WRITE_RGB_PIXEL(y, u, v);
+ WRITE_RGB_PIXEL(y1, u, v);
+ }
+ if (width_remainder) {
+ const Uint8 y = *plane_y++;
+ const Uint8 u = *plane_interleaved_uv++;
+ const Uint8 v = *plane_interleaved_uv++;
+ WRITE_RGB_PIXEL(y, u, v);
+ }
+ /* Re-use the same line of chroma planes */
+ if ((j & 0x1) == 0x0) {
+ plane_interleaved_uv -= 2 * (width_half + width_remainder);
+ }
+ curr_row += curr_row_padding;
+ }
+ }
+ else /* src_format == SDL_PIXELFORMAT_NV21 */
+ {
+ const Uint8 *plane_interleaved_uv = plane_y + sz_plane;
+ for (j = 0; j < height; j++) {
+ for (i = 0; i < width_half; i++) {
+ const Uint8 y = *plane_y++;
+ const Uint8 y1 = *plane_y++;
+ const Uint8 v = *plane_interleaved_uv++;
+ const Uint8 u = *plane_interleaved_uv++;
+ WRITE_RGB_PIXEL(y, u, v);
+ WRITE_RGB_PIXEL(y1, u, v);
+ }
+ if (width_remainder) {
+ const Uint8 y = *plane_y++;
+ const Uint8 v = *plane_interleaved_uv++;
+ const Uint8 u = *plane_interleaved_uv++;
+ WRITE_RGB_PIXEL(y, u, v);
+ }
+ /* Re-use the same line of chroma planes */
+ if ((j & 0x1) == 0x0) {
+ plane_interleaved_uv -= 2 * (width_half + width_remainder);
+ }
+ curr_row += curr_row_padding;
+ }
+ }
+ }
+ break;
+
+ case SDL_PIXELFORMAT_YUY2:
+ case SDL_PIXELFORMAT_UYVY:
+ case SDL_PIXELFORMAT_YVYU:
+ {
+ const Uint8 *plane = (const Uint8 *)src;
+
+#define READ_PACKED_YUV(var1, var2, var3, var4) \
+ const Uint8 var1 = plane[0]; \
+ const Uint8 var2 = plane[1]; \
+ const Uint8 var3 = plane[2]; \
+ const Uint8 var4 = plane[3]; \
+ plane += 4; \
+
+ if (src_format == SDL_PIXELFORMAT_YUY2) /* Y U Y1 V */
+ {
+ for (j = 0; j < height; j++) {
+ for (i = 0; i < width_half; i++) {
+ READ_PACKED_YUV(y, u, y1, v);
+ WRITE_RGB_PIXEL(y, u, v);
+ WRITE_RGB_PIXEL(y1, u, v);
+ }
+ if (width_remainder) {
+ READ_PACKED_YUV(y, u, y1, v);
+ (void)y1; /* y1 unused */
+ WRITE_RGB_PIXEL(y, u, v);
+ }
+ curr_row += curr_row_padding;
+ }
+ }
+ else if (src_format == SDL_PIXELFORMAT_UYVY) /* U Y V Y1 */
+ {
+ for (j = 0; j < height; j++) {
+ for (i = 0; i < width_half; i++) {
+ READ_PACKED_YUV(u, y, v, y1);
+ WRITE_RGB_PIXEL(y, u, v);
+ WRITE_RGB_PIXEL(y1, u, v);
+ }
+ if (width_remainder) {
+ READ_PACKED_YUV(u, y, v, y1);
+ (void) y1; /* y1 unused */
+ WRITE_RGB_PIXEL(y, u, v);
+ }
+ curr_row += curr_row_padding;
+ }
+ }
+ else if (src_format == SDL_PIXELFORMAT_YVYU) /* Y V Y1 U */
+ {
+ for (j = 0; j < height; j++) {
+ for (i = 0; i < width_half; i++) {
+ READ_PACKED_YUV(y, v, y1, u);
+ WRITE_RGB_PIXEL(y, u, v);
+ WRITE_RGB_PIXEL(y1, u, v);
+ }
+ if (width_remainder) {
+ READ_PACKED_YUV(y, v, y1, u);
+ (void) y1; /* y1 unused */
+ WRITE_RGB_PIXEL(y, u, v);
+ }
+ curr_row += curr_row_padding;
+ }
+ }
+#undef READ_PACKED_YUV
+ }
+ break;
+ }
+#undef WRITE_RGB_PIXEL
+ return 0;
+}
+
+static int
+SDL_ConvertPixels_ARGB8888_to_YUV(int width, int height, const void *src, int src_pitch, Uint32 dst_format, void *dst)
+{
+ const int src_pitch_x_2 = src_pitch * 2;
+ const int sz_plane = width * height;
+ const int sz_plane_chroma = ((width + 1) / 2) * ((height + 1) / 2);
+ const int height_half = height / 2;
+ const int height_remainder = (height & 0x1);
+ const int width_half = width / 2;
+ const int width_remainder = (width & 0x1);
+ int i, j;
+
+ // SDL_Log("SDL_ConvertPixels_ARGB8888_to_YUV (to %s)", SDL_GetPixelFormatName(dst_format));
+
+ switch (dst_format)
+ {
+ case SDL_PIXELFORMAT_YV12:
+ case SDL_PIXELFORMAT_IYUV:
+ case SDL_PIXELFORMAT_NV12:
+ case SDL_PIXELFORMAT_NV21:
+ {
+ const Uint8 *curr_row, *next_row;
+
+ Uint8 *plane_y = (Uint8*) dst;
+ Uint8 *plane_u = (dst_format == SDL_PIXELFORMAT_YV12 ? plane_y + sz_plane + sz_plane_chroma : plane_y + sz_plane);
+ Uint8 *plane_v = (dst_format == SDL_PIXELFORMAT_YV12 ? plane_y + sz_plane : plane_y + sz_plane + sz_plane_chroma);
+ Uint8 *plane_interleaved_uv = plane_y + sz_plane;
+
+ curr_row = (const Uint8*)src;
+
+ /* Write Y plane */
+ for (j = 0; j < height; j++) {
+ for (i = 0; i < width; i++) {
+ const Uint8 b = curr_row[4 * i + 0];
+ const Uint8 g = curr_row[4 * i + 1];
+ const Uint8 r = curr_row[4 * i + 2];
+ *plane_y++ = MAKE_Y(r, g, b);
+ }
+ curr_row += src_pitch;
+ }
+
+ curr_row = (const Uint8*)src;
+ next_row = (const Uint8*)src;
+ next_row += src_pitch;
+
+#if 1
+/* slightly faster */
+#define READ_2x2_PIXELS \
+ const Uint32 p1 = ((const Uint32 *)curr_row)[2 * i]; \
+ const Uint32 p2 = ((const Uint32 *)curr_row)[2 * i + 1]; \
+ const Uint32 p3 = ((const Uint32 *)next_row)[2 * i]; \
+ const Uint32 p4 = ((const Uint32 *)next_row)[2 * i + 1]; \
+ const Uint32 b = ((p1 & 0x000000ff) + (p2 & 0x000000ff) + (p3 & 0x000000ff) + (p4 & 0x000000ff)) >> 2; \
+ const Uint32 g = ((p1 & 0x0000ff00) + (p2 & 0x0000ff00) + (p3 & 0x0000ff00) + (p4 & 0x0000ff00)) >> 10; \
+ const Uint32 r = ((p1 & 0x00ff0000) + (p2 & 0x00ff0000) + (p3 & 0x00ff0000) + (p4 & 0x00ff0000)) >> 18; \
+
+#else
+
+#define READ_2x2_PIXELS \
+ const Uint8 b = (curr_row[8 * i + 0] + curr_row[8 * i + 4] \
+ + next_row[8 * i + 0] + next_row[8 * i + 4] ) >> 2; \
+ const Uint8 g = (curr_row[8 * i + 1] + curr_row[8 * i + 5] \
+ + next_row[8 * i + 1] + next_row[8 * i + 5] ) >> 2; \
+ const Uint8 r = (curr_row[8 * i + 2] + curr_row[8 * i + 6] \
+ + next_row[8 * i + 2] + next_row[8 * i + 6] ) >> 2; \
+
+#endif
+
+#define READ_2x1_PIXELS \
+ const Uint8 b = (curr_row[8 * i + 0] + next_row[8 * i + 0]) >> 1; \
+ const Uint8 g = (curr_row[8 * i + 1] + next_row[8 * i + 1]) >> 1; \
+ const Uint8 r = (curr_row[8 * i + 2] + next_row[8 * i + 2]) >> 1; \
+
+#define READ_1x2_PIXELS \
+ const Uint8 b = (curr_row[8 * i + 0] + curr_row[8 * i + 4]) >> 1; \
+ const Uint8 g = (curr_row[8 * i + 1] + curr_row[8 * i + 5]) >> 1; \
+ const Uint8 r = (curr_row[8 * i + 2] + curr_row[8 * i + 6]) >> 1; \
+
+#define READ_1x1_PIXEL \
+ const Uint8 b = curr_row[8 * i + 0]; \
+ const Uint8 g = curr_row[8 * i + 1]; \
+ const Uint8 r = curr_row[8 * i + 2]; \
+
+ if (dst_format == SDL_PIXELFORMAT_YV12 || dst_format == SDL_PIXELFORMAT_IYUV)
+ {
+ /* Write UV planes, not interleaved */
+ for (j = 0; j < height_half; j++) {
+ for (i = 0; i < width_half; i++) {
+ READ_2x2_PIXELS;
+ *plane_u++ = MAKE_U(r, g, b);
+ *plane_v++ = MAKE_V(r, g, b);
+ }
+ if (width_remainder) {
+ READ_2x1_PIXELS;
+ *plane_u++ = MAKE_U(r, g, b);
+ *plane_v++ = MAKE_V(r, g, b);
+ }
+ curr_row += src_pitch_x_2;
+ next_row += src_pitch_x_2;
+ }
+ if (height_remainder) {
+ for (i = 0; i < width_half; i++) {
+ READ_1x2_PIXELS;
+ *plane_u++ = MAKE_U(r, g, b);
+ *plane_v++ = MAKE_V(r, g, b);
+ }
+ if (width_remainder) {
+ READ_1x1_PIXEL;
+ *plane_u++ = MAKE_U(r, g, b);
+ *plane_v++ = MAKE_V(r, g, b);
+ }
+ }
+ }
+ else if (dst_format == SDL_PIXELFORMAT_NV12)
+ {
+ for (j = 0; j < height_half; j++) {
+ for (i = 0; i < width_half; i++) {
+ READ_2x2_PIXELS;
+ *plane_interleaved_uv++ = MAKE_U(r, g, b);
+ *plane_interleaved_uv++ = MAKE_V(r, g, b);
+ }
+ if (width_remainder) {
+ READ_2x1_PIXELS;
+ *plane_interleaved_uv++ = MAKE_U(r, g, b);
+ *plane_interleaved_uv++ = MAKE_V(r, g, b);
+ }
+ curr_row += src_pitch_x_2;
+ next_row += src_pitch_x_2;
+ }
+ if (height_remainder) {
+ for (i = 0; i < width_half; i++) {
+ READ_1x2_PIXELS;
+ *plane_interleaved_uv++ = MAKE_U(r, g, b);
+ *plane_interleaved_uv++ = MAKE_V(r, g, b);
+ }
+ if (width_remainder) {
+ READ_1x1_PIXEL;
+ *plane_interleaved_uv++ = MAKE_U(r, g, b);
+ *plane_interleaved_uv++ = MAKE_V(r, g, b);
+ }
+ }
+ }
+ else /* dst_format == SDL_PIXELFORMAT_NV21 */
+ {
+ for (j = 0; j < height_half; j++) {
+ for (i = 0; i < width_half; i++) {
+ READ_2x2_PIXELS;
+ *plane_interleaved_uv++ = MAKE_V(r, g, b);
+ *plane_interleaved_uv++ = MAKE_U(r, g, b);
+ }
+ if (width_remainder) {
+ READ_2x1_PIXELS;
+ *plane_interleaved_uv++ = MAKE_V(r, g, b);
+ *plane_interleaved_uv++ = MAKE_U(r, g, b);
+ }
+ curr_row += src_pitch_x_2;
+ next_row += src_pitch_x_2;
+ }
+ if (height_remainder) {
+ for (i = 0; i < width_half; i++) {
+ READ_1x2_PIXELS;
+ *plane_interleaved_uv++ = MAKE_V(r, g, b);
+ *plane_interleaved_uv++ = MAKE_U(r, g, b);
+ }
+ if (width_remainder) {
+ READ_1x1_PIXEL;
+ *plane_interleaved_uv++ = MAKE_V(r, g, b);
+ *plane_interleaved_uv++ = MAKE_U(r, g, b);
+ }
+ }
+ }
+#undef READ_2x2_PIXELS
+#undef READ_2x1_PIXELS
+#undef READ_1x2_PIXELS
+#undef READ_1x1_PIXEL
+ }
+ break;
+
+ case SDL_PIXELFORMAT_YUY2:
+ case SDL_PIXELFORMAT_UYVY:
+ case SDL_PIXELFORMAT_YVYU:
+ {
+ const Uint8 *curr_row = (const Uint8*) src;
+ Uint8 *plane = (Uint8*) dst;
+
+#define READ_TWO_RGB_PIXELS \
+ const Uint8 b = curr_row[8 * i + 0]; \
+ const Uint8 g = curr_row[8 * i + 1]; \
+ const Uint8 r = curr_row[8 * i + 2]; \
+ const Uint8 b1 = curr_row[8 * i + 4]; \
+ const Uint8 g1 = curr_row[8 * i + 5]; \
+ const Uint8 r1 = curr_row[8 * i + 6]; \
+ const Uint8 B = (b + b1) >> 1; \
+ const Uint8 G = (g + g1) >> 1; \
+ const Uint8 R = (r + r1) >> 1; \
+
+#define READ_ONE_RGB_PIXEL \
+ const Uint8 b = curr_row[8 * i + 0]; \
+ const Uint8 g = curr_row[8 * i + 1]; \
+ const Uint8 r = curr_row[8 * i + 2]; \
+
+ /* Write YUV plane, packed */
+ if (dst_format == SDL_PIXELFORMAT_YUY2)
+ {
+ for (j = 0; j < height; j++) {
+ for (i = 0; i < width_half; i++) {
+ READ_TWO_RGB_PIXELS;
+ /* Y U Y1 V */
+ *plane++ = MAKE_Y(r, g, b);
+ *plane++ = MAKE_U(R, G, B);
+ *plane++ = MAKE_Y(r1, g1, b1);
+ *plane++ = MAKE_V(R, G, B);
+ }
+ if (width_remainder) {
+ READ_ONE_RGB_PIXEL;
+ /* Y U Y V */
+ *plane++ = MAKE_Y(r, g, b);
+ *plane++ = MAKE_U(r, g, b);
+ *plane++ = MAKE_Y(r, g, b);
+ *plane++ = MAKE_V(r, g, b);
+ }
+ curr_row += src_pitch;
+ }
+ }
+ else if (dst_format == SDL_PIXELFORMAT_UYVY)
+ {
+ for (j = 0; j < height; j++) {
+ for (i = 0; i < width_half; i++) {
+ READ_TWO_RGB_PIXELS;
+ /* U Y V Y1 */
+ *plane++ = MAKE_U(R, G, B);
+ *plane++ = MAKE_Y(r, g, b);
+ *plane++ = MAKE_V(R, G, B);
+ *plane++ = MAKE_Y(r1, g1, b1);
+ }
+ if (width_remainder) {
+ READ_ONE_RGB_PIXEL;
+ /* U Y V Y */
+ *plane++ = MAKE_U(r, g, b);
+ *plane++ = MAKE_Y(r, g, b);
+ *plane++ = MAKE_V(r, g, b);
+ *plane++ = MAKE_Y(r, g, b);
+ }
+ curr_row += src_pitch;
+ }
+ }
+ else if (dst_format == SDL_PIXELFORMAT_YVYU)
+ {
+ for (j = 0; j < height; j++) {
+ for (i = 0; i < width_half; i++) {
+ READ_TWO_RGB_PIXELS;
+ /* Y V Y1 U */
+ *plane++ = MAKE_Y(r, g, b);
+ *plane++ = MAKE_V(R, G, B);
+ *plane++ = MAKE_Y(r1, g1, b1);
+ *plane++ = MAKE_U(R, G, B);
+ }
+ if (width_remainder) {
+ READ_ONE_RGB_PIXEL;
+ /* Y V Y U */
+ *plane++ = MAKE_Y(r, g, b);
+ *plane++ = MAKE_V(r, g, b);
+ *plane++ = MAKE_Y(r, g, b);
+ *plane++ = MAKE_U(r, g, b);
+ }
+ curr_row += src_pitch;
+ }
+ }
+#undef READ_TWO_RGB_PIXELS
+#undef READ_ONE_RGB_PIXEL
+ }
+ break;
+ }
+ return 0;
+}
+
/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/cocoa/SDL_cocoaevents.m b/src/video/cocoa/SDL_cocoaevents.m
index e428e4374d..98bdf87546 100644
--- a/src/video/cocoa/SDL_cocoaevents.m
+++ b/src/video/cocoa/SDL_cocoaevents.m
@@ -216,6 +216,18 @@ - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filenam
{
return (BOOL)SDL_SendDropFile(NULL, [filename UTF8String]) && SDL_SendDropComplete(NULL);
}
+
+- (void)applicationDidFinishLaunching:(NSNotification *)notification
+{
+ /* The menu bar of SDL apps which don't have the typical .app bundle
+ * structure fails to work the first time a window is created (until it's
+ * de-focused and re-focused), if this call is in Cocoa_RegisterApp instead
+ * of here. https://bugzilla.libsdl.org/show_bug.cgi?id=3051
+ */
+ if (!SDL_GetHintBoolean(SDL_HINT_MAC_BACKGROUND_APP, SDL_FALSE)) {
+ [NSApp activateIgnoringOtherApps:YES];
+ }
+}
@end
static SDLAppDelegate *appDelegate = nil;
@@ -361,7 +373,6 @@ - (BOOL)application:(NSApplication *)theApplication openFile:(NSString *)filenam
if (!SDL_GetHintBoolean(SDL_HINT_MAC_BACKGROUND_APP, SDL_FALSE)) {
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];
- [NSApp activateIgnoringOtherApps:YES];
}
if ([NSApp mainMenu] == nil) {
diff --git a/src/video/cocoa/SDL_cocoakeyboard.m b/src/video/cocoa/SDL_cocoakeyboard.m
index b2ce5a31d1..e1d100a2bd 100644
--- a/src/video/cocoa/SDL_cocoakeyboard.m
+++ b/src/video/cocoa/SDL_cocoakeyboard.m
@@ -93,7 +93,7 @@ - (NSRange)selectedRange
return _selectedRange;
}
-- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange;
+- (void)setMarkedText:(id)aString selectedRange:(NSRange)selectedRange replacementRange:(NSRange)replacementRange
{
if ([aString isKindOfClass:[NSAttributedString class]]) {
aString = [aString string];
@@ -127,7 +127,7 @@ - (void)unmarkText
SDL_SendEditingText("", 0, 0);
}
-- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange;
+- (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
{
NSWindow *window = [self window];
NSRect contentRect = [window contentRectForFrameRect:[window frame]];
@@ -155,7 +155,7 @@ - (NSRect)firstRectForCharacterRange:(NSRange)aRange actualRange:(NSRangePointer
return rect;
}
-- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange;
+- (NSAttributedString *)attributedSubstringForProposedRange:(NSRange)aRange actualRange:(NSRangePointer)actualRange
{
DEBUG_IME(@"attributedSubstringFromRange: (%d, %d)", aRange.location, aRange.length);
return nil;
diff --git a/src/video/kmsdrm/SDL_kmsdrmopengles.c b/src/video/kmsdrm/SDL_kmsdrmopengles.c
index 7063e5f1a5..7ba663f14f 100644
--- a/src/video/kmsdrm/SDL_kmsdrmopengles.c
+++ b/src/video/kmsdrm/SDL_kmsdrmopengles.c
@@ -42,6 +42,40 @@ KMSDRM_GLES_LoadLibrary(_THIS, const char *path) {
SDL_EGL_CreateContext_impl(KMSDRM)
+SDL_bool
+KMSDRM_GLES_SetupCrtc(_THIS, SDL_Window * window) {
+ SDL_WindowData *wdata = ((SDL_WindowData *) window->driverdata);
+ SDL_DisplayData *displaydata = (SDL_DisplayData *) SDL_GetDisplayForWindow(window)->driverdata;
+ SDL_VideoData *vdata = ((SDL_VideoData *)_this->driverdata);
+ KMSDRM_FBInfo *fb_info;
+
+ if (!(_this->egl_data->eglSwapBuffers(_this->egl_data->egl_display, wdata->egl_surface))) {
+ SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "eglSwapBuffers failed on CRTC setup");
+ return SDL_FALSE;
+ }
+
+ wdata->next_bo = KMSDRM_gbm_surface_lock_front_buffer(wdata->gs);
+ if (wdata->next_bo == NULL) {
+ SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not lock GBM surface front buffer on CRTC setup");
+ return SDL_FALSE;
+ }
+
+ fb_info = KMSDRM_FBFromBO(_this, wdata->next_bo);
+ if (fb_info == NULL) {
+ return SDL_FALSE;
+ }
+
+ if(KMSDRM_drmModeSetCrtc(vdata->drm_fd, displaydata->crtc_id, fb_info->fb_id,
+ 0, 0, &vdata->saved_conn_id, 1, &displaydata->cur_mode) != 0) {
+ SDL_LogWarn(SDL_LOG_CATEGORY_VIDEO, "Could not set up CRTC to a GBM buffer");
+ return SDL_FALSE;
+
+ }
+
+ wdata->crtc_ready = SDL_TRUE;
+ return SDL_TRUE;
+}
+
int KMSDRM_GLES_SetSwapInterval(_THIS, int interval) {
if (!_this->egl_data) {
return SDL_SetError("EGL not initialized");
@@ -118,6 +152,16 @@ KMSDRM_GLES_SwapWindow(_THIS, SDL_Window * window) {
}
} else {
/* Queue page flip at vsync */
+
+ /* Have we already setup the CRTC to one of the GBM buffers? Do so if we have not,
+ or FlipPage won't work in some cases. */
+ if (!wdata->crtc_ready) {
+ if(!KMSDRM_GLES_SetupCrtc(_this, window)) {
+ SDL_LogError(SDL_LOG_CATEGORY_VIDEO, "Could not set up CRTC for doing vsync-ed pageflips");
+ return 0;
+ }
+ }
+
/* SDL_LogDebug(SDL_LOG_CATEGORY_VIDEO, "drmModePageFlip(%d, %u, %u, DRM_MODE_PAGE_FLIP_EVENT, &wdata->waiting_for_flip)",
vdata->drm_fd, displaydata->crtc_id, fb_info->fb_id); */
ret = KMSDRM_drmModePageFlip(vdata->drm_fd, displaydata->crtc_id, fb_info->fb_id,
diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.c b/src/video/kmsdrm/SDL_kmsdrmvideo.c
index 63376f213a..ee3ac0592a 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvideo.c
+++ b/src/video/kmsdrm/SDL_kmsdrmvideo.c
@@ -522,6 +522,12 @@ KMSDRM_CreateWindow(_THIS, SDL_Window * window)
}
#endif /* SDL_VIDEO_OPENGL_EGL */
+ /* Window is created, but we have yet to set up CRTC to one of the GBM buffers if we want
+ drmModePageFlip to work, and we can't do it until EGL is completely setup, because we
+ need to do eglSwapBuffers so we can get a valid GBM buffer object to call
+ drmModeSetCrtc on it. */
+ wdata->crtc_ready = SDL_FALSE;
+
/* Setup driver data for this window */
window->driverdata = wdata;
diff --git a/src/video/kmsdrm/SDL_kmsdrmvideo.h b/src/video/kmsdrm/SDL_kmsdrmvideo.h
index 307c475dce..71f0de722b 100644
--- a/src/video/kmsdrm/SDL_kmsdrmvideo.h
+++ b/src/video/kmsdrm/SDL_kmsdrmvideo.h
@@ -62,6 +62,7 @@ typedef struct SDL_WindowData
struct gbm_bo *current_bo;
struct gbm_bo *next_bo;
SDL_bool waiting_for_flip;
+ SDL_bool crtc_ready;
#if SDL_VIDEO_OPENGL_EGL
EGLSurface egl_surface;
#endif
diff --git a/src/video/vivante/SDL_vivanteplatform.c b/src/video/vivante/SDL_vivanteplatform.c
index d1b46a4949..694ed2614c 100644
--- a/src/video/vivante/SDL_vivanteplatform.c
+++ b/src/video/vivante/SDL_vivanteplatform.c
@@ -32,6 +32,16 @@ VIVANTE_SetupPlatform(_THIS)
return 0;
}
+char *VIVANTE_GetDisplayName(_THIS)
+{
+ return NULL;
+}
+
+void
+VIVANTE_UpdateDisplayScale(_THIS)
+{
+}
+
void
VIVANTE_CleanupPlatform(_THIS)
{
diff --git a/src/video/vivante/SDL_vivanteplatform.h b/src/video/vivante/SDL_vivanteplatform.h
index 23cb4062b5..9fa714b8d2 100644
--- a/src/video/vivante/SDL_vivanteplatform.h
+++ b/src/video/vivante/SDL_vivanteplatform.h
@@ -36,6 +36,8 @@
#endif
extern int VIVANTE_SetupPlatform(_THIS);
+extern char *VIVANTE_GetDisplayName(_THIS);
+extern void VIVANTE_UpdateDisplayScale(_THIS);
extern void VIVANTE_CleanupPlatform(_THIS);
#endif /* SDL_VIDEO_DRIVER_VIVANTE */
diff --git a/src/video/vivante/SDL_vivantevideo.c b/src/video/vivante/SDL_vivantevideo.c
index 79b36c258f..efa13c509c 100644
--- a/src/video/vivante/SDL_vivantevideo.c
+++ b/src/video/vivante/SDL_vivantevideo.c
@@ -97,6 +97,7 @@ VIVANTE_Create()
device->DestroyWindow = VIVANTE_DestroyWindow;
device->GetWindowWMInfo = VIVANTE_GetWindowWMInfo;
+#if SDL_VIDEO_OPENGL_EGL
device->GL_LoadLibrary = VIVANTE_GLES_LoadLibrary;
device->GL_GetProcAddress = VIVANTE_GLES_GetProcAddress;
device->GL_UnloadLibrary = VIVANTE_GLES_UnloadLibrary;
@@ -106,6 +107,7 @@ VIVANTE_Create()
device->GL_GetSwapInterval = VIVANTE_GLES_GetSwapInterval;
device->GL_SwapWindow = VIVANTE_GLES_SwapWindow;
device->GL_DeleteContext = VIVANTE_GLES_DeleteContext;
+#endif
device->PumpEvents = VIVANTE_PumpEvents;
@@ -152,6 +154,9 @@ VIVANTE_AddVideoDisplays(_THIS)
switch (bpp)
{
default: /* Is another format used? */
+ case 32:
+ current_mode.format = SDL_PIXELFORMAT_ARGB8888;
+ break;
case 16:
current_mode.format = SDL_PIXELFORMAT_RGB565;
break;
@@ -160,6 +165,7 @@ VIVANTE_AddVideoDisplays(_THIS)
current_mode.refresh_rate = 60;
SDL_zero(display);
+ display.name = VIVANTE_GetDisplayName(_this);
display.desktop_mode = current_mode;
display.current_mode = current_mode;
display.driverdata = data;
@@ -208,6 +214,8 @@ VIVANTE_VideoInit(_THIS)
return -1;
}
+ VIVANTE_UpdateDisplayScale(_this);
+
#ifdef SDL_INPUT_LINUXEV
if (SDL_EVDEV_Init() < 0) {
return -1;
@@ -281,6 +289,7 @@ VIVANTE_CreateWindow(_THIS, SDL_Window * window)
return SDL_SetError("VIVANTE: Can't create native window");
}
+#if SDL_VIDEO_OPENGL_EGL
if (window->flags & SDL_WINDOW_OPENGL) {
data->egl_surface = SDL_EGL_CreateSurface(_this, data->native_window);
if (data->egl_surface == EGL_NO_SURFACE) {
@@ -289,6 +298,7 @@ VIVANTE_CreateWindow(_THIS, SDL_Window * window)
} else {
data->egl_surface = EGL_NO_SURFACE;
}
+#endif
/* Window has been successfully created */
return 0;
@@ -302,9 +312,11 @@ VIVANTE_DestroyWindow(_THIS, SDL_Window * window)
data = window->driverdata;
if (data) {
+#if SDL_VIDEO_OPENGL_EGL
if (data->egl_surface != EGL_NO_SURFACE) {
SDL_EGL_DestroySurface(_this, data->egl_surface);
}
+#endif
if (data->native_window) {
#if SDL_VIDEO_DRIVER_VIVANTE_VDK
diff --git a/src/video/wayland/SDL_waylandevents.c b/src/video/wayland/SDL_waylandevents.c
index 961325fea7..32c7cdfdf2 100644
--- a/src/video/wayland/SDL_waylandevents.c
+++ b/src/video/wayland/SDL_waylandevents.c
@@ -366,6 +366,10 @@ static const struct wl_pointer_listener pointer_listener = {
pointer_handle_motion,
pointer_handle_button,
pointer_handle_axis,
+ NULL, /* frame */
+ NULL, /* axis_source */
+ NULL, /* axis_stop */
+ NULL, /* axis_discrete */
};
static void
@@ -428,7 +432,9 @@ static const struct wl_touch_listener touch_listener = {
touch_handler_up,
touch_handler_motion,
touch_handler_frame,
- touch_handler_cancel
+ touch_handler_cancel,
+ NULL, /* shape */
+ NULL, /* orientation */
};
static void
@@ -564,6 +570,7 @@ static const struct wl_keyboard_listener keyboard_listener = {
keyboard_handle_leave,
keyboard_handle_key,
keyboard_handle_modifiers,
+ NULL, /* repeat_info */
};
static void
@@ -608,6 +615,7 @@ seat_handle_capabilities(void *data, struct wl_seat *seat,
static const struct wl_seat_listener seat_listener = {
seat_handle_capabilities,
+ NULL, /* name */
};
static void
diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
index e3a73bd3d7..7390ad6f22 100644
--- a/src/video/wayland/SDL_waylandvideo.c
+++ b/src/video/wayland/SDL_waylandvideo.c
@@ -344,7 +344,8 @@ display_handle_global(void *data, struct wl_registry *registry, uint32_t id,
}
static const struct wl_registry_listener registry_listener = {
- display_handle_global
+ display_handle_global,
+ NULL, /* global_remove */
};
int
diff --git a/src/video/windows/SDL_windowsevents.c b/src/video/windows/SDL_windowsevents.c
index cc6ef7e4a0..b73e9df8bd 100644
--- a/src/video/windows/SDL_windowsevents.c
+++ b/src/video/windows/SDL_windowsevents.c
@@ -949,11 +949,19 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
}
break;
+ case WM_NCCALCSIZE:
+ {
+ // When borderless, need to tell windows that the size of the non-client area is 0
+ if ( wParam == TRUE && SDL_GetWindowFlags( data->window ) & SDL_WINDOW_BORDERLESS )
+ return 0;
+ }
+ break;
+
case WM_NCHITTEST:
{
SDL_Window *window = data->window;
if (window->hit_test) {
- POINT winpoint = { (int) LOWORD(lParam), (int) HIWORD(lParam) };
+ POINT winpoint = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
if (ScreenToClient(hwnd, &winpoint)) {
const SDL_Point point = { (int) winpoint.x, (int) winpoint.y };
const SDL_HitTestResult rc = window->hit_test(window, &point, window->hit_test_data);
@@ -976,7 +984,6 @@ WIN_WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
}
}
break;
-
}
/* If there's a window proc, assume it's going to handle messages */
diff --git a/src/video/windows/SDL_windowswindow.c b/src/video/windows/SDL_windowswindow.c
index 3bde2666fa..32849c4422 100644
--- a/src/video/windows/SDL_windowswindow.c
+++ b/src/video/windows/SDL_windowswindow.c
@@ -51,9 +51,14 @@ static WCHAR *SDL_HelperWindowClassName = TEXT("SDLHelperWindowInputCatcher");
static WCHAR *SDL_HelperWindowName = TEXT("SDLHelperWindowInputMsgWindow");
static ATOM SDL_HelperWindowClass = 0;
+// for borderless Windows, still want the following flags:
+// - WS_CAPTION: this seems to enable the Windows minimize animation
+// - WS_SYSMENU: enables system context menu on task bar
+// - WS_MINIMIZEBOX: window will respond to Windows minimize commands sent to all windows, such as windows key + m, shaking title bar, etc.
+
#define STYLE_BASIC (WS_CLIPSIBLINGS | WS_CLIPCHILDREN)
#define STYLE_FULLSCREEN (WS_POPUP)
-#define STYLE_BORDERLESS (WS_POPUP)
+#define STYLE_BORDERLESS (WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX)
#define STYLE_NORMAL (WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX)
#define STYLE_RESIZABLE (WS_THICKFRAME | WS_MAXIMIZEBOX)
#define STYLE_MASK (STYLE_FULLSCREEN | STYLE_BORDERLESS | STYLE_NORMAL | STYLE_RESIZABLE)
@@ -89,7 +94,11 @@ WIN_AdjustWindowRectWithStyle(SDL_Window *window, DWORD style, BOOL menu, int *x
rect.top = 0;
rect.right = (use_current ? window->w : window->windowed.w);
rect.bottom = (use_current ? window->h : window->windowed.h);
- AdjustWindowRectEx(&rect, style, menu, 0);
+
+ // borderless windows will have WM_NCCALCSIZE return 0 for the non-client area. When this happens, it looks like windows will send a resize message
+ // expanding the window client area to the previous window + chrome size, so shouldn't need to adjust the window size for the set styles.
+ if (!(window->flags & SDL_WINDOW_BORDERLESS))
+ AdjustWindowRectEx(&rect, style, menu, 0);
*x = (use_current ? window->x : window->windowed.x) + rect.left;
*y = (use_current ? window->y : window->windowed.y) + rect.top;
@@ -216,10 +225,10 @@ SetupWindowData(_THIS, SDL_Window * window, HWND hwnd, HWND parent, SDL_bool cre
} else {
window->flags &= ~SDL_WINDOW_SHOWN;
}
- if (style & (WS_BORDER | WS_THICKFRAME)) {
- window->flags &= ~SDL_WINDOW_BORDERLESS;
- } else {
+ if (style & WS_POPUP) {
window->flags |= SDL_WINDOW_BORDERLESS;
+ } else {
+ window->flags &= ~SDL_WINDOW_BORDERLESS;
}
if (style & WS_THICKFRAME) {
window->flags |= SDL_WINDOW_RESIZABLE;
@@ -306,6 +315,9 @@ WIN_CreateWindow(_THIS, SDL_Window * window)
return -1;
}
+ // Inform Windows of the frame change so we can respond to WM_NCCALCSIZE
+ SetWindowPos(hwnd, NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
+
if (!(window->flags & SDL_WINDOW_OPENGL)) {
return 0;
}
@@ -583,6 +595,8 @@ WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display,
style &= ~WS_MAXIMIZE;
}
} else {
+ BOOL menu;
+
/* Restore window-maximization state, as applicable.
Special care is taken to *not* do this if and when we're
alt-tab'ing away (to some other window; as indicated by
@@ -594,7 +608,8 @@ WIN_SetWindowFullscreen(_THIS, SDL_Window * window, SDL_VideoDisplay * display,
data->windowed_mode_was_maximized = SDL_FALSE;
}
- WIN_AdjustWindowRect(window, &x, &y, &w, &h, SDL_FALSE);
+ menu = (style & WS_CHILDWINDOW) ? FALSE : (GetMenu(hwnd) != NULL);
+ WIN_AdjustWindowRectWithStyle(window, style, menu, &x, &y, &w, &h, SDL_FALSE);
}
SetWindowLong(hwnd, GWL_STYLE, style);
data->expected_resize = SDL_TRUE;
diff --git a/src/video/x11/SDL_x11opengl.c b/src/video/x11/SDL_x11opengl.c
index ab1bf58ca1..922c096173 100644
--- a/src/video/x11/SDL_x11opengl.c
+++ b/src/video/x11/SDL_x11opengl.c
@@ -463,7 +463,9 @@ X11_GL_InitExtensions(_THIS)
}
}
- X11_XDestroyWindow(display, w);
+ if (w) {
+ X11_XDestroyWindow(display, w);
+ }
X11_PumpEvents(_this);
}
diff --git a/src/video/x11/SDL_x11xinput2.c b/src/video/x11/SDL_x11xinput2.c
index 654fb8445b..a602b2a63d 100644
--- a/src/video/x11/SDL_x11xinput2.c
+++ b/src/video/x11/SDL_x11xinput2.c
@@ -73,6 +73,35 @@ xinput2_version_atleast(const int version, const int wantmajor, const int wantmi
{
return ( version >= ((wantmajor * 1000) + wantminor) );
}
+
+#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
+static void
+xinput2_normalize_touch_coordinates(SDL_VideoData *videodata, Window window,
+ double in_x, double in_y, float *out_x, float *out_y)
+{
+ int i;
+ for (i = 0; i < videodata->numwindows; i++) {
+ SDL_WindowData *d = videodata->windowlist[i];
+ if (d->xwindow == window) {
+ if (d->window->w == 1) {
+ *out_x = 0.5f;
+ } else {
+ *out_x = in_x / (d->window->w - 1);
+ }
+ if (d->window->h == 1) {
+ *out_y = 0.5f;
+ } else {
+ *out_y = in_y / (d->window->h - 1);
+ }
+ return;
+ }
+ }
+ // couldn't find the window...
+ *out_x = in_x;
+ *out_y = in_y;
+}
+#endif /* SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH */
+
#endif /* SDL_VIDEO_DRIVER_X11_XINPUT2 */
void
@@ -171,22 +200,28 @@ X11_HandleXinput2Event(SDL_VideoData *videodata,XGenericEventCookie *cookie)
#if SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
case XI_TouchBegin: {
const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
- SDL_SendTouch(xev->sourceid,xev->detail,
- SDL_TRUE, xev->event_x, xev->event_y, 1.0);
+ float x, y;
+ xinput2_normalize_touch_coordinates(videodata, xev->event,
+ xev->event_x, xev->event_y, &x, &y);
+ SDL_SendTouch(xev->sourceid,xev->detail, SDL_TRUE, x, y, 1.0);
return 1;
}
break;
case XI_TouchEnd: {
const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
- SDL_SendTouch(xev->sourceid,xev->detail,
- SDL_FALSE, xev->event_x, xev->event_y, 1.0);
+ float x, y;
+ xinput2_normalize_touch_coordinates(videodata, xev->event,
+ xev->event_x, xev->event_y, &x, &y);
+ SDL_SendTouch(xev->sourceid,xev->detail, SDL_FALSE, x, y, 1.0);
return 1;
}
break;
case XI_TouchUpdate: {
const XIDeviceEvent *xev = (const XIDeviceEvent *) cookie->data;
- SDL_SendTouchMotion(xev->sourceid,xev->detail,
- xev->event_x, xev->event_y, 1.0);
+ float x, y;
+ xinput2_normalize_touch_coordinates(videodata, xev->event,
+ xev->event_x, xev->event_y, &x, &y);
+ SDL_SendTouchMotion(xev->sourceid,xev->detail, x, y, 1.0);
return 1;
}
break;
diff --git a/test/testplatform.c b/test/testplatform.c
index 001123b7d0..0cba8fe76c 100644
--- a/test/testplatform.c
+++ b/test/testplatform.c
@@ -30,6 +30,26 @@ TestTypes(SDL_bool verbose)
{
int error = 0;
+ SDL_COMPILE_TIME_ASSERT(SDL_MAX_SINT8, SDL_MAX_SINT8 == 127);
+ SDL_COMPILE_TIME_ASSERT(SDL_MIN_SINT8, SDL_MIN_SINT8 == -128);
+ SDL_COMPILE_TIME_ASSERT(SDL_MAX_UINT8, SDL_MAX_UINT8 == 255);
+ SDL_COMPILE_TIME_ASSERT(SDL_MIN_UINT8, SDL_MIN_UINT8 == 0);
+
+ SDL_COMPILE_TIME_ASSERT(SDL_MAX_SINT16, SDL_MAX_SINT16 == 32767);
+ SDL_COMPILE_TIME_ASSERT(SDL_MIN_SINT16, SDL_MIN_SINT16 == -32768);
+ SDL_COMPILE_TIME_ASSERT(SDL_MAX_UINT16, SDL_MAX_UINT16 == 65535);
+ SDL_COMPILE_TIME_ASSERT(SDL_MIN_UINT16, SDL_MIN_UINT16 == 0);
+
+ SDL_COMPILE_TIME_ASSERT(SDL_MAX_SINT32, SDL_MAX_SINT32 == 2147483647);
+ SDL_COMPILE_TIME_ASSERT(SDL_MIN_SINT32, SDL_MIN_SINT32 == ~0x7fffffff); /* Instead of -2147483648, which is treated as unsigned by some compilers */
+ SDL_COMPILE_TIME_ASSERT(SDL_MAX_UINT32, SDL_MAX_UINT32 == 4294967295u);
+ SDL_COMPILE_TIME_ASSERT(SDL_MIN_UINT32, SDL_MIN_UINT32 == 0);
+
+ SDL_COMPILE_TIME_ASSERT(SDL_MAX_SINT64, SDL_MAX_SINT64 == 9223372036854775807ll);
+ SDL_COMPILE_TIME_ASSERT(SDL_MIN_SINT64, SDL_MIN_SINT64 == ~0x7fffffffffffffffll); /* Instead of -9223372036854775808, which is treated as unsigned by compilers */
+ SDL_COMPILE_TIME_ASSERT(SDL_MAX_UINT64, SDL_MAX_UINT64 == 18446744073709551615ull);
+ SDL_COMPILE_TIME_ASSERT(SDL_MIN_UINT64, SDL_MIN_UINT64 == 0);
+
if (badsize(sizeof(Uint8), 1)) {
if (verbose)
SDL_Log("sizeof(Uint8) != 1, instead = %u\n",