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",