diff --git a/VisualC-WinPhone/SDL/SDL_VS2012-WinPhone.vcxproj b/VisualC-WinPhone/SDL/SDL_VS2012-WinPhone.vcxproj
new file mode 100644
index 000000000..5c5951528
--- /dev/null
+++ b/VisualC-WinPhone/SDL/SDL_VS2012-WinPhone.vcxproj
@@ -0,0 +1,403 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ ARM
+
+
+ Release
+ Win32
+
+
+ Release
+ ARM
+
+
+
+ {33048af1-031a-4ce6-b61e-fad2db832e9e}
+ SDL
+ en-US
+ 11.0
+ SDL-WinPhone
+
+
+
+ DynamicLibrary
+ true
+ v110_wp80
+ false
+
+
+ DynamicLibrary
+ true
+ v110_wp80
+ false
+
+
+ DynamicLibrary
+ false
+ true
+ v110_wp80
+ false
+
+
+ DynamicLibrary
+ false
+ true
+ v110_wp80
+ false
+
+
+
+
+
+
+
+ false
+
+
+
+ _USRDLL;UNICODE;%(PreprocessorDefinitions)
+ NotUsing
+ pch.h
+ false
+ $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)
+ ..\..\include
+ false
+
+
+ Console
+ false
+ false
+ true
+ d3d11.lib;xaudio2.lib;WindowsPhoneCore.lib;RuntimeObject.lib;PhoneAppModelHost.lib;%(AdditionalDependencies)
+
+
+
+
+ _USRDLL;UNICODE;NDEBUG;%(PreprocessorDefinitions)
+ NotUsing
+ pch.h
+ false
+ $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)
+ ..\..\include
+
+
+ Console
+ false
+ false
+ true
+ d3d11.lib;xaudio2.lib;WindowsPhoneCore.lib;RuntimeObject.lib;PhoneAppModelHost.lib;%(AdditionalDependencies)
+
+
+
+
+ _USRDLL;UNICODE;%(PreprocessorDefinitions)
+ NotUsing
+ pch.h
+ false
+ $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)
+ ..\..\include
+ false
+
+
+ Console
+ false
+ false
+ true
+ d3d11.lib;xaudio2.lib;WindowsPhoneCore.lib;RuntimeObject.lib;PhoneAppModelHost.lib;%(AdditionalDependencies)
+
+
+
+
+ _USRDLL;UNICODE;NDEBUG;%(PreprocessorDefinitions)
+ NotUsing
+ pch.h
+ false
+ $(WindowsSDK_MetadataPath);$(AdditionalUsingDirectories)
+ ..\..\include
+
+
+ Console
+ false
+ false
+ true
+ d3d11.lib;xaudio2.lib;WindowsPhoneCore.lib;RuntimeObject.lib;PhoneAppModelHost.lib;%(AdditionalDependencies)
+
+
+
+
+ true
+
+
+ true
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CompileAsCpp
+ CompileAsCpp
+ CompileAsCpp
+ CompileAsCpp
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+
+
+ Pixel
+ Pixel
+ Pixel
+ Pixel
+
+
+ Pixel
+ Pixel
+ Pixel
+ Pixel
+
+
+ Vertex
+ Vertex
+ Vertex
+ Vertex
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/VisualC-WinPhone/SDL/SDL_VS2012-WinPhone.vcxproj.filters b/VisualC-WinPhone/SDL/SDL_VS2012-WinPhone.vcxproj.filters
new file mode 100644
index 000000000..4eb56ac03
--- /dev/null
+++ b/VisualC-WinPhone/SDL/SDL_VS2012-WinPhone.vcxproj.filters
@@ -0,0 +1,608 @@
+
+
+
+
+ {02b21b9a-45a7-41ee-a8a6-e45d14aa28da}
+
+
+ {abc3a7e6-f955-4cb5-8340-fae0f653e9c1}
+
+
+ {fd67993e-5155-488b-9313-d1eb06a1b67e}
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ GPU Shaders
+
+
+ GPU Shaders
+
+
+ GPU Shaders
+
+
+
\ No newline at end of file
diff --git a/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj b/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj
new file mode 100644
index 000000000..40a8ffd9e
--- /dev/null
+++ b/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj
@@ -0,0 +1,505 @@
+
+
+
+
+ Debug
+ ARM
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ ARM
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CompileAsCpp
+ CompileAsCpp
+ CompileAsCpp
+ CompileAsCpp
+ CompileAsCpp
+ CompileAsCpp
+
+
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Pixel
+ Pixel
+ Pixel
+ Pixel
+ Pixel
+ Pixel
+ 4.0_level_9_1
+ 4.0_level_9_1
+ 4.0_level_9_1
+ 4.0_level_9_1
+ 4.0_level_9_1
+ 4.0_level_9_1
+
+
+ Pixel
+ Pixel
+ Pixel
+ Pixel
+ Pixel
+ Pixel
+ 4.0_level_9_1
+ 4.0_level_9_1
+ 4.0_level_9_1
+ 4.0_level_9_1
+
+
+ Vertex
+ Vertex
+ Vertex
+ Vertex
+ Vertex
+ Vertex
+ 4.0_level_9_1
+ 4.0_level_9_1
+ 4.0_level_9_1
+ 4.0_level_9_1
+ 4.0_level_9_1
+ 4.0_level_9_1
+
+
+
+ {aeaea3a2-d4e6-45b1-8ec6-53d84287fc14}
+ Win32Proj
+ SDL-WinRT
+ SDL_VS2012_WinRT
+ en-US
+ 11.0
+ true
+
+
+
+ DynamicLibrary
+ true
+ v110
+
+
+ DynamicLibrary
+ true
+ v110
+
+
+ DynamicLibrary
+ true
+ v110
+
+
+ DynamicLibrary
+ false
+ true
+ v110
+
+
+ DynamicLibrary
+ false
+ true
+ v110
+
+
+ DynamicLibrary
+ false
+ true
+ v110
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ false
+ false
+ SDL
+
+
+ false
+ false
+ SDL
+
+
+ false
+ false
+ SDL
+
+
+ false
+ false
+ SDL
+
+
+ false
+ false
+ SDL
+
+
+ false
+ false
+ SDL
+
+
+
+ NotUsing
+ false
+ ..\..\include;%(AdditionalIncludeDirectories)
+ _WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+
+
+ Console
+ false
+ false
+ xinput.lib;xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)
+
+
+
+
+ NotUsing
+ false
+ ..\..\include;%(AdditionalIncludeDirectories)
+ _WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+
+
+ Console
+ false
+ false
+ xinput.lib;xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)
+
+
+
+
+ NotUsing
+ false
+ ..\..\include;%(AdditionalIncludeDirectories)
+ _WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+
+
+ Console
+ false
+ false
+ xinput.lib;xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)
+
+
+
+
+ NotUsing
+ false
+ ..\..\include;%(AdditionalIncludeDirectories)
+ _WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+
+
+ Console
+ false
+ false
+ xinput.lib;xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)
+
+
+
+
+ NotUsing
+ false
+ ..\..\include;%(AdditionalIncludeDirectories)
+ _WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+
+
+ Console
+ false
+ false
+ xinput.lib;xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)
+
+
+
+
+ NotUsing
+ false
+ ..\..\include;%(AdditionalIncludeDirectories)
+ _WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+
+
+ Console
+ false
+ false
+ xinput.lib;xaudio2.lib;d2d1.lib;d3d11.lib;dxgi.lib;ole32.lib;windowscodecs.lib;dwrite.lib;kernel32.lib;%(AdditionalDependencies)
+
+
+
+
+
+
\ No newline at end of file
diff --git a/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj.filters b/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj.filters
new file mode 100644
index 000000000..74dd2dc86
--- /dev/null
+++ b/VisualC-WinRT/SDL/SDL_VS2012-WinRT.vcxproj.filters
@@ -0,0 +1,608 @@
+
+
+
+
+ GPU Shaders
+
+
+ GPU Shaders
+
+
+ GPU Shaders
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Header Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Source Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Source Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Source Files
+
+
+ Header Files
+
+
+ Source Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Header Files
+
+
+ Source Files
+
+
+
+
+ {20773b57-7034-4c24-af5a-334844585f1b}
+
+
+ {ddf04d85-6a87-4c5a-bc52-869b38f45a61}
+
+
+ {83ed1283-8234-4c77-99a8-ffcfd8ce7381}
+
+
+
\ No newline at end of file
diff --git a/VisualC-WinRT/SDL_VS2012-WinRT.sln b/VisualC-WinRT/SDL_VS2012-WinRT.sln
new file mode 100644
index 000000000..046e6b7ba
--- /dev/null
+++ b/VisualC-WinRT/SDL_VS2012-WinRT.sln
@@ -0,0 +1,32 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Express 2012 for Windows 8
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDL_VS2012-WinRT", "SDL\SDL_VS2012-WinRT.vcxproj", "{AEAEA3A2-D4E6-45B1-8EC6-53D84287FC14}"
+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
+ {AEAEA3A2-D4E6-45B1-8EC6-53D84287FC14}.Debug|ARM.ActiveCfg = Debug|ARM
+ {AEAEA3A2-D4E6-45B1-8EC6-53D84287FC14}.Debug|ARM.Build.0 = Debug|ARM
+ {AEAEA3A2-D4E6-45B1-8EC6-53D84287FC14}.Debug|Win32.ActiveCfg = Debug|Win32
+ {AEAEA3A2-D4E6-45B1-8EC6-53D84287FC14}.Debug|Win32.Build.0 = Debug|Win32
+ {AEAEA3A2-D4E6-45B1-8EC6-53D84287FC14}.Debug|x64.ActiveCfg = Debug|x64
+ {AEAEA3A2-D4E6-45B1-8EC6-53D84287FC14}.Debug|x64.Build.0 = Debug|x64
+ {AEAEA3A2-D4E6-45B1-8EC6-53D84287FC14}.Release|ARM.ActiveCfg = Release|ARM
+ {AEAEA3A2-D4E6-45B1-8EC6-53D84287FC14}.Release|ARM.Build.0 = Release|ARM
+ {AEAEA3A2-D4E6-45B1-8EC6-53D84287FC14}.Release|Win32.ActiveCfg = Release|Win32
+ {AEAEA3A2-D4E6-45B1-8EC6-53D84287FC14}.Release|Win32.Build.0 = Release|Win32
+ {AEAEA3A2-D4E6-45B1-8EC6-53D84287FC14}.Release|x64.ActiveCfg = Release|x64
+ {AEAEA3A2-D4E6-45B1-8EC6-53D84287FC14}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/VisualC-WinRT/tests/loopwave/Assets/Logo.png b/VisualC-WinRT/tests/loopwave/Assets/Logo.png
new file mode 100644
index 000000000..e26771cb3
Binary files /dev/null and b/VisualC-WinRT/tests/loopwave/Assets/Logo.png differ
diff --git a/VisualC-WinRT/tests/loopwave/Assets/SmallLogo.png b/VisualC-WinRT/tests/loopwave/Assets/SmallLogo.png
new file mode 100644
index 000000000..1eb0d9d52
Binary files /dev/null and b/VisualC-WinRT/tests/loopwave/Assets/SmallLogo.png differ
diff --git a/VisualC-WinRT/tests/loopwave/Assets/SplashScreen.png b/VisualC-WinRT/tests/loopwave/Assets/SplashScreen.png
new file mode 100644
index 000000000..c951e031b
Binary files /dev/null and b/VisualC-WinRT/tests/loopwave/Assets/SplashScreen.png differ
diff --git a/VisualC-WinRT/tests/loopwave/Assets/StoreLogo.png b/VisualC-WinRT/tests/loopwave/Assets/StoreLogo.png
new file mode 100644
index 000000000..dcb672712
Binary files /dev/null and b/VisualC-WinRT/tests/loopwave/Assets/StoreLogo.png differ
diff --git a/VisualC-WinRT/tests/loopwave/Package.appxmanifest b/VisualC-WinRT/tests/loopwave/Package.appxmanifest
new file mode 100644
index 000000000..3b62bf1b1
--- /dev/null
+++ b/VisualC-WinRT/tests/loopwave/Package.appxmanifest
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+ loopwave_VS2012_WinRT
+ David
+ Assets\StoreLogo.png
+
+
+
+ 6.2.1
+ 6.2.1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/VisualC-WinRT/tests/loopwave/loopwave_VS2012.vcxproj b/VisualC-WinRT/tests/loopwave/loopwave_VS2012.vcxproj
new file mode 100644
index 000000000..14e57e5fd
--- /dev/null
+++ b/VisualC-WinRT/tests/loopwave/loopwave_VS2012.vcxproj
@@ -0,0 +1,157 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM
+
+
+ Release
+ ARM
+
+
+
+ {03fcc293-9406-49c2-acf6-6e7d460c3239}
+ loopwave_VS2012
+ en-US
+ 11.0
+ true
+ loopwave
+
+
+
+ Application
+ true
+ v110
+
+
+ Application
+ true
+ v110
+
+
+ Application
+ true
+ v110
+
+
+ Application
+ false
+ true
+ v110
+
+
+ Application
+ false
+ true
+ v110
+
+
+ Application
+ false
+ true
+ v110
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ loopwave_VS2012_TemporaryKey.pfx
+
+
+
+ d2d1.lib; d3d11.lib; dxgi.lib; ole32.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies)
+
+
+ pch.h
+ $(IntDir)pch.pch
+ $(ProjectDir);$(IntermediateOutputPath);$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories)
+ 4453
+
+
+
+
+ NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ NotUsing
+ NotUsing
+ NotUsing
+
+
+
+
+ _DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ NotUsing
+ NotUsing
+ NotUsing
+
+
+
+
+
+
+
+
+
+
+ Designer
+
+
+
+
+
+
+ false
+ false
+ false
+ false
+ false
+ false
+
+
+
+
+
+
+
+ {aeaea3a2-d4e6-45b1-8ec6-53d84287fc14}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/VisualC-WinRT/tests/loopwave/loopwave_VS2012_TemporaryKey.pfx b/VisualC-WinRT/tests/loopwave/loopwave_VS2012_TemporaryKey.pfx
new file mode 100644
index 000000000..3c07b779f
Binary files /dev/null and b/VisualC-WinRT/tests/loopwave/loopwave_VS2012_TemporaryKey.pfx differ
diff --git a/VisualC-WinRT/tests/testthread/Assets/Logo.png b/VisualC-WinRT/tests/testthread/Assets/Logo.png
new file mode 100644
index 000000000..e26771cb3
Binary files /dev/null and b/VisualC-WinRT/tests/testthread/Assets/Logo.png differ
diff --git a/VisualC-WinRT/tests/testthread/Assets/SmallLogo.png b/VisualC-WinRT/tests/testthread/Assets/SmallLogo.png
new file mode 100644
index 000000000..1eb0d9d52
Binary files /dev/null and b/VisualC-WinRT/tests/testthread/Assets/SmallLogo.png differ
diff --git a/VisualC-WinRT/tests/testthread/Assets/SplashScreen.png b/VisualC-WinRT/tests/testthread/Assets/SplashScreen.png
new file mode 100644
index 000000000..c951e031b
Binary files /dev/null and b/VisualC-WinRT/tests/testthread/Assets/SplashScreen.png differ
diff --git a/VisualC-WinRT/tests/testthread/Assets/StoreLogo.png b/VisualC-WinRT/tests/testthread/Assets/StoreLogo.png
new file mode 100644
index 000000000..dcb672712
Binary files /dev/null and b/VisualC-WinRT/tests/testthread/Assets/StoreLogo.png differ
diff --git a/VisualC-WinRT/tests/testthread/Package.appxmanifest b/VisualC-WinRT/tests/testthread/Package.appxmanifest
new file mode 100644
index 000000000..f02b3a173
--- /dev/null
+++ b/VisualC-WinRT/tests/testthread/Package.appxmanifest
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+ testthread_VS2012_WinRT
+ David
+ Assets\StoreLogo.png
+
+
+
+ 6.2.1
+ 6.2.1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/VisualC-WinRT/tests/testthread/testthread_VS2012.vcxproj b/VisualC-WinRT/tests/testthread/testthread_VS2012.vcxproj
new file mode 100644
index 000000000..1940fe315
--- /dev/null
+++ b/VisualC-WinRT/tests/testthread/testthread_VS2012.vcxproj
@@ -0,0 +1,160 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+ Debug
+ ARM
+
+
+ Release
+ ARM
+
+
+
+ {a8705bee-d01d-46a4-b2ab-feedfb5fdd11}
+ testthread_VS2012
+ en-US
+ 11.0
+ true
+ testthread
+
+
+
+ Application
+ true
+ v110
+
+
+ Application
+ true
+ v110
+
+
+ Application
+ true
+ v110
+
+
+ Application
+ false
+ true
+ v110
+
+
+ Application
+ false
+ true
+ v110
+
+
+ Application
+ false
+ true
+ v110
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ testthread_VS2012_TemporaryKey.pfx
+
+
+
+ d2d1.lib; d3d11.lib; dxgi.lib; ole32.lib; windowscodecs.lib; dwrite.lib; %(AdditionalDependencies)
+
+
+ pch.h
+ $(IntDir)pch.pch
+ $(ProjectDir);$(IntermediateOutputPath);$(ProjectDir)..\..\..\include;%(AdditionalIncludeDirectories)
+ 4453
+
+
+
+
+ NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ NotUsing
+ NotUsing
+ NotUsing
+ false
+ false
+ false
+
+
+
+
+ _DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)
+ NotUsing
+ NotUsing
+ NotUsing
+ false
+ false
+ false
+
+
+
+
+
+
+
+
+
+
+ Designer
+
+
+
+
+
+ true
+ true
+ true
+ true
+ true
+ true
+
+
+
+
+
+ {aeaea3a2-d4e6-45b1-8ec6-53d84287fc14}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/VisualC-WinRT/tests/testthread/testthread_VS2012_TemporaryKey.pfx b/VisualC-WinRT/tests/testthread/testthread_VS2012_TemporaryKey.pfx
new file mode 100644
index 000000000..97fd1e190
Binary files /dev/null and b/VisualC-WinRT/tests/testthread/testthread_VS2012_TemporaryKey.pfx differ
diff --git a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj
index f3122ecba..4d349d28a 100755
--- a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj
+++ b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj
@@ -547,6 +547,7 @@
);
name = CustomTemplate;
sourceTree = "";
+ usesTabs = 0;
};
56EA86F813E9EBF9002E47EB /* coreaudio */ = {
isa = PBXGroup;
diff --git a/include/SDL_config.h b/include/SDL_config.h
index 7440940ad..9022af81e 100644
--- a/include/SDL_config.h
+++ b/include/SDL_config.h
@@ -31,6 +31,8 @@
/* Add any platform that doesn't build using the configure system. */
#if defined(__WIN32__)
#include "SDL_config_windows.h"
+#elif defined(__WINRT__)
+#include "SDL_config_windowsrt.h"
#elif defined(__MACOSX__)
#include "SDL_config_macosx.h"
#elif defined(__IPHONEOS__)
diff --git a/include/SDL_config_windowsrt.h b/include/SDL_config_windowsrt.h
new file mode 100644
index 000000000..b6ecc00fe
--- /dev/null
+++ b/include/SDL_config_windowsrt.h
@@ -0,0 +1,180 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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.
+*/
+
+#ifndef _SDL_config_windows_h
+#define _SDL_config_windows_h
+
+#include "SDL_platform.h"
+
+/* This is a set of defines to configure the SDL features */
+
+#if !defined(_STDINT_H_) && (!defined(HAVE_STDINT_H) || !_HAVE_STDINT_H)
+#if defined(__GNUC__) || defined(__DMC__) || defined(__WATCOMC__)
+#define HAVE_STDINT_H 1
+#elif defined(_MSC_VER)
+typedef signed __int8 int8_t;
+typedef unsigned __int8 uint8_t;
+typedef signed __int16 int16_t;
+typedef unsigned __int16 uint16_t;
+typedef signed __int32 int32_t;
+typedef unsigned __int32 uint32_t;
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+#ifndef _UINTPTR_T_DEFINED
+#ifdef _WIN64
+typedef unsigned __int64 uintptr_t;
+#else
+typedef unsigned int uintptr_t;
+#endif
+#define _UINTPTR_T_DEFINED
+#endif
+/* Older Visual C++ headers don't have the Win64-compatible typedefs... */
+#if ((_MSC_VER <= 1200) && (!defined(DWORD_PTR)))
+#define DWORD_PTR DWORD
+#endif
+#if ((_MSC_VER <= 1200) && (!defined(LONG_PTR)))
+#define LONG_PTR LONG
+#endif
+#else /* !__GNUC__ && !_MSC_VER */
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef signed short int16_t;
+typedef unsigned short uint16_t;
+typedef signed int int32_t;
+typedef unsigned int uint32_t;
+typedef signed long long int64_t;
+typedef unsigned long long uint64_t;
+#ifndef _SIZE_T_DEFINED_
+#define _SIZE_T_DEFINED_
+typedef unsigned int size_t;
+#endif
+typedef unsigned int uintptr_t;
+#endif /* __GNUC__ || _MSC_VER */
+#endif /* !_STDINT_H_ && !HAVE_STDINT_H */
+
+#ifdef _WIN64
+# define SIZEOF_VOIDP 8
+#else
+# define SIZEOF_VOIDP 4
+#endif
+
+/* Useful headers */
+#define HAVE_LIBC 1
+#define HAVE_STDIO_H 1
+#define STDC_HEADERS 1
+#define HAVE_STRING_H 1
+#define HAVE_CTYPE_H 1
+#define HAVE_MATH_H 1
+#define HAVE_SIGNAL_H 1
+
+/* C library functions */
+#define HAVE_MALLOC 1
+#define HAVE_CALLOC 1
+#define HAVE_REALLOC 1
+#define HAVE_FREE 1
+#define HAVE_ALLOCA 1
+#define HAVE_QSORT 1
+#define HAVE_ABS 1
+#define HAVE_MEMSET 1
+#define HAVE_MEMCPY 1
+#define HAVE_MEMMOVE 1
+#define HAVE_MEMCMP 1
+#define HAVE_STRLEN 1
+#define HAVE__STRREV 1
+#define HAVE__STRUPR 1
+//#define HAVE__STRLWR 1 // TODO, WinRT: consider using _strlwr_s instead
+#define HAVE_STRCHR 1
+#define HAVE_STRRCHR 1
+#define HAVE_STRSTR 1
+//#define HAVE_ITOA 1 // TODO, WinRT: consider using _itoa_s instead
+//#define HAVE__LTOA 1 // TODO, WinRT: consider using _ltoa_s instead
+//#define HAVE__ULTOA 1 // TODO, WinRT: consider using _ultoa_s instead
+#define HAVE_STRTOL 1
+#define HAVE_STRTOUL 1
+//#define HAVE_STRTOLL 1
+#define HAVE_STRTOD 1
+#define HAVE_ATOI 1
+#define HAVE_ATOF 1
+#define HAVE_STRCMP 1
+#define HAVE_STRNCMP 1
+#define HAVE__STRICMP 1
+#define HAVE__STRNICMP 1
+#define HAVE_VSNPRINTF 1
+//#define HAVE_SSCANF 1 // TODO, WinRT: consider using sscanf_s instead
+#define HAVE_M_PI 1
+#define HAVE_ATAN 1
+#define HAVE_ATAN2 1
+#define HAVE_CEIL 1
+//#define HAVE_COPYSIGN 1 // TODO, WinRT: consider using _copysign instead
+#define HAVE_COS 1
+#define HAVE_COSF 1
+#define HAVE_FABS 1
+#define HAVE_FLOOR 1
+#define HAVE_LOG 1
+#define HAVE_POW 1
+//#define HAVE_SCALBN 1
+#define HAVE_SIN 1
+#define HAVE_SINF 1
+#define HAVE_SQRT 1
+#define HAVE__FSEEKI64 1
+
+/* Enable various audio drivers */
+#define SDL_AUDIO_DRIVER_XAUDIO2 1
+#define SDL_AUDIO_DRIVER_DISK 1
+#define SDL_AUDIO_DRIVER_DUMMY 1
+
+/* Enable various input drivers */
+// TODO, WinRT: Get haptic support working
+#define SDL_HAPTIC_DISABLED 1
+
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+#define SDL_JOYSTICK_DISABLED 1
+#else
+#define SDL_JOYSTICK_XINPUT 1
+#endif
+
+/* Enable various shared object loading systems */
+#define SDL_LOADSO_WINDOWS 1
+
+/* Enable various threading systems */
+#define SDL_THREAD_STDCPP 1
+
+/* Enable various timer systems */
+#define SDL_TIMER_WINDOWS 1
+
+/* Enable various video drivers */
+#define SDL_VIDEO_DRIVER_WINRT 1
+#define SDL_VIDEO_DRIVER_DUMMY 1
+
+// TODO, WinRT: Get a Direct3D 11 based renderer working in SDL.
+/* Enable appropriate renderer(s) */
+#define SDL_VIDEO_RENDER_D3D11 1
+
+/* Enable system power support */
+// TODO, WinRT: investigate system power support. The Win32-based APIs don't work on WinRT.
+#define SDL_POWER_DISABLED 1
+
+/* Enable assembly routines (Win64 doesn't have inline asm) */
+#ifndef _WIN64
+#define SDL_ASSEMBLY_ROUTINES 1
+#endif
+
+#endif /* _SDL_config_windows_h */
diff --git a/include/SDL_cpuinfo.h b/include/SDL_cpuinfo.h
index dde3074f0..a722ee4d5 100644
--- a/include/SDL_cpuinfo.h
+++ b/include/SDL_cpuinfo.h
@@ -32,7 +32,7 @@
/* Need to do this here because intrin.h has C++ code in it */
/* Visual Studio 2005 has a bug where intrin.h conflicts with winnt.h */
-#if defined(_MSC_VER) && (_MSC_VER >= 1500)
+#if defined(_MSC_VER) && (_MSC_VER >= 1500) && (defined(_M_IX86) || defined(_M_X64))
#include
#ifndef _WIN64
#define __MMX__
diff --git a/include/SDL_stdinc.h b/include/SDL_stdinc.h
index 7fa9c1049..bc39c2a90 100644
--- a/include/SDL_stdinc.h
+++ b/include/SDL_stdinc.h
@@ -71,6 +71,13 @@
# include
#endif
#ifdef HAVE_MATH_H
+# if defined(__WINRT__)
+/* Defining _USE_MATH_DEFINES is required to get M_PI to be defined on
+ Windows RT. See http://msdn.microsoft.com/en-us/library/4hwaceh6.aspx
+ for more information.
+*/
+# define _USE_MATH_DEFINES
+# endif
# include
#endif
#if defined(HAVE_ICONV) && defined(HAVE_ICONV_H)
diff --git a/include/SDL_system.h b/include/SDL_system.h
index 26e9eaa0a..cb7490664 100644
--- a/include/SDL_system.h
+++ b/include/SDL_system.h
@@ -94,6 +94,71 @@ extern DECLSPEC const char * SDLCALL SDL_AndroidGetExternalStoragePath();
#endif /* __ANDROID__ */
+/* Platform specific functions for Windows RT */
+#if defined(__WINRT__) && __WINRT__
+
+/**
+ * \brief Windows RT / Windows Phone path types
+ */
+typedef enum
+{
+ /** \brief The installed app's root directory.
+ Files here are likely to be read-only. */
+ SDL_WINRT_PATH_INSTALLED_LOCATION,
+
+ /** \brief The app's local data store. Files may be written here */
+ SDL_WINRT_PATH_LOCAL_FOLDER,
+
+ /** \brief The app's roaming data store. Unsupported on Windows Phone.
+ Files written here may be copied to other machines via a network
+ connection.
+ */
+ SDL_WINRT_PATH_ROAMING_FOLDER,
+
+ /** \brief The app's temporary data store. Unsupported on Windows Phone.
+ Files written here may be deleted at any time. */
+ SDL_WINRT_PATH_TEMP_FOLDER
+} SDL_WinRT_Path;
+
+
+/**
+ * \brief Retrieves a Windows RT defined path on the local file system
+ *
+ * \note Documentation on most app-specific path types on Windows RT
+ * can be found on MSDN, at the URL:
+ * http://msdn.microsoft.com/en-us/library/windows/apps/hh464917.aspx
+ *
+ * \param pathType The type of path to retrieve.
+ * \ret A UCS-2 string (16-bit, wide-char) containing the path, or NULL
+ * if the path is not available for any reason. Not all paths are
+ * available on all versions of Windows. This is especially true on
+ * Windows Phone. Check the documentation for the given
+ * SDL_WinRT_Path for more information on which path types are
+ * supported where.
+ */
+extern DECLSPEC const wchar_t * SDLCALL SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path pathType);
+
+/**
+ * \brief Retrieves a Windows RT defined path on the local file system
+ *
+ * \note Documentation on most app-specific path types on Windows RT
+ * can be found on MSDN, at the URL:
+ * http://msdn.microsoft.com/en-us/library/windows/apps/hh464917.aspx
+ *
+ * \param pathType The type of path to retrieve.
+ * \ret A UTF-8 string (8-bit, multi-byte) containing the path, or NULL
+ * if the path is not available for any reason. Not all paths are
+ * available on all versions of Windows. This is especially true on
+ * Windows Phone. Check the documentation for the given
+ * SDL_WinRT_Path for more information on which path types are
+ * supported where.
+ */
+extern DECLSPEC const char * SDLCALL SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType);
+
+
+#endif /* __WINRT__ */
+
+
/* Ends C function definitions when using C++ */
#ifdef __cplusplus
}
diff --git a/include/SDL_syswm.h b/include/SDL_syswm.h
index 5e4454f86..3b503ae74 100644
--- a/include/SDL_syswm.h
+++ b/include/SDL_syswm.h
@@ -56,6 +56,10 @@ struct SDL_SysWMinfo;
#include
#endif
+#if defined(SDL_VIDEO_DRIVER_WINRT)
+#include
+#endif
+
/* This is the structure for custom window manager events */
#if defined(SDL_VIDEO_DRIVER_X11)
#if defined(__APPLE__) && defined(__MACH__)
@@ -90,6 +94,7 @@ typedef struct _NSWindow NSWindow;
#include
#else
typedef struct _UIWindow UIWindow;
+typedef struct _UIViewController UIViewController;
#endif
#endif
@@ -100,6 +105,7 @@ typedef enum
{
SDL_SYSWM_UNKNOWN,
SDL_SYSWM_WINDOWS,
+ SDL_SYSWM_WINDOWSRT,
SDL_SYSWM_X11,
SDL_SYSWM_DIRECTFB,
SDL_SYSWM_COCOA,
@@ -168,6 +174,12 @@ struct SDL_SysWMinfo
HWND window; /**< The window handle */
} win;
#endif
+#if defined(SDL_VIDEO_DRIVER_WINRT)
+ struct
+ {
+ IUnknown * window; /**< The Windows RT CoreWindow */
+ } winrt;
+#endif
#if defined(SDL_VIDEO_DRIVER_X11)
struct
{
@@ -193,6 +205,7 @@ struct SDL_SysWMinfo
struct
{
UIWindow *window; /* The UIKit window */
+ UIViewController *viewcontroller; /* The UIKit view controller */
} uikit;
#endif
/* Can't have an empty union */
diff --git a/include/begin_code.h b/include/begin_code.h
index dd1f0616d..8997a7220 100644
--- a/include/begin_code.h
+++ b/include/begin_code.h
@@ -41,7 +41,7 @@
# else
# define DECLSPEC __declspec(export)
# endif
-# elif defined(__WIN32__)
+# elif defined(__WIN32__) || defined(__WINRT__)
# ifdef __BORLANDC__
# ifdef BUILD_SDL
# define DECLSPEC
@@ -62,7 +62,7 @@
/* By default SDL uses the C calling convention */
#ifndef SDLCALL
-#if defined(__WIN32__) && !defined(__GNUC__)
+#if (defined(__WIN32__) || defined(__WINRT__)) && !defined(__GNUC__)
#define SDLCALL __cdecl
#else
#define SDLCALL
diff --git a/src/SDL_assert.c b/src/SDL_assert.c
index a4cf6434f..73ebfe5fc 100644
--- a/src/SDL_assert.c
+++ b/src/SDL_assert.c
@@ -37,8 +37,10 @@
#else /* fprintf, _exit(), etc. */
#include
#include
+#if ! defined(__WINRT__)
#include
#endif
+#endif
static SDL_assert_state
SDL_PromptAssertion(const SDL_assert_data *data, void *userdata);
diff --git a/src/SDL_log.c b/src/SDL_log.c
index 2245946c6..a19a2c425 100644
--- a/src/SDL_log.c
+++ b/src/SDL_log.c
@@ -28,7 +28,7 @@
#include
#endif
-#if defined(__WIN32__)
+#if defined(__WIN32__) || defined(__WINRT__)
#include "core/windows/SDL_windows.h"
#elif defined(__ANDROID__)
#include
@@ -315,7 +315,7 @@ static void
SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority,
const char *message)
{
-#if defined(__WIN32__)
+#if defined(__WIN32__) || defined(__WINRT__)
/* Way too many allocations here, urgh */
/* Note: One can't call SDL_SetError here, since that function itself logs. */
{
diff --git a/src/atomic/SDL_spinlock.c b/src/atomic/SDL_spinlock.c
index f3aeea0e2..f90528c35 100644
--- a/src/atomic/SDL_spinlock.c
+++ b/src/atomic/SDL_spinlock.c
@@ -25,7 +25,7 @@
#include "SDL_timer.h"
/* Don't do the check for Visual Studio 2005, it's safe here */
-#ifdef __WIN32__
+#if defined(__WIN32__) || defined(__WINRT__)
#include "../core/windows/SDL_windows.h"
#endif
diff --git a/src/audio/xaudio2/SDL_xaudio2.c b/src/audio/xaudio2/SDL_xaudio2.c
index a2c45ba86..19f7cdc5c 100644
--- a/src/audio/xaudio2/SDL_xaudio2.c
+++ b/src/audio/xaudio2/SDL_xaudio2.c
@@ -1,437 +1,583 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2013 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"
-
-#if SDL_AUDIO_DRIVER_XAUDIO2
-
-#include "../../core/windows/SDL_windows.h"
-#include "SDL_audio.h"
-#include "../SDL_audio_c.h"
-#include "../SDL_sysaudio.h"
-#include "SDL_assert.h"
-
-#ifdef __GNUC__
-/* The configure script already did any necessary checking */
-# define SDL_XAUDIO2_HAS_SDK 1
-#else
-#include /* XAudio2 exists as of the March 2008 DirectX SDK */
-#if (!defined(_DXSDK_BUILD_MAJOR) || (_DXSDK_BUILD_MAJOR < 1284))
-# pragma message("Your DirectX SDK is too old. Disabling XAudio2 support.")
-#else
-# define SDL_XAUDIO2_HAS_SDK 1
-#endif
-#endif /* __GNUC__ */
-
-#ifdef SDL_XAUDIO2_HAS_SDK
-
-#define INITGUID 1
-#include
-
-/* Hidden "this" pointer for the audio functions */
-#define _THIS SDL_AudioDevice *this
-
-struct SDL_PrivateAudioData
-{
- IXAudio2 *ixa2;
- IXAudio2SourceVoice *source;
- IXAudio2MasteringVoice *mastering;
- HANDLE semaphore;
- Uint8 *mixbuf;
- int mixlen;
- Uint8 *nextbuf;
-};
-
-
-static __inline__ char *
-utf16_to_utf8(const WCHAR *S)
-{
- /* !!! FIXME: this should be UTF-16, not UCS-2! */
- return SDL_iconv_string("UTF-8", "UCS-2", (char *)(S),
- (SDL_wcslen(S)+1)*sizeof(WCHAR));
-}
-
-static void
-XAUDIO2_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
-{
- IXAudio2 *ixa2 = NULL;
- UINT32 devcount = 0;
- UINT32 i = 0;
-
- if (iscapture) {
- SDL_SetError("XAudio2: capture devices unsupported.");
- return;
- } else if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
- SDL_SetError("XAudio2: XAudio2Create() failed at detection.");
- return;
- } else if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) {
- SDL_SetError("XAudio2: IXAudio2::GetDeviceCount() failed.");
- IXAudio2_Release(ixa2);
- return;
- }
-
- for (i = 0; i < devcount; i++) {
- XAUDIO2_DEVICE_DETAILS details;
- if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) {
- char *str = utf16_to_utf8(details.DisplayName);
- if (str != NULL) {
- addfn(str);
- SDL_free(str); /* addfn() made a copy of the string. */
- }
- }
- }
-
- IXAudio2_Release(ixa2);
-}
-
-static void STDMETHODCALLTYPE
-VoiceCBOnBufferEnd(THIS_ void *data)
-{
- /* Just signal the SDL audio thread and get out of XAudio2's way. */
- SDL_AudioDevice *this = (SDL_AudioDevice *) data;
- ReleaseSemaphore(this->hidden->semaphore, 1, NULL);
-}
-
-static void STDMETHODCALLTYPE
-VoiceCBOnVoiceError(THIS_ void *data, HRESULT Error)
-{
- /* !!! FIXME: attempt to recover, or mark device disconnected. */
- SDL_assert(0 && "write me!");
-}
-
-/* no-op callbacks... */
-static void STDMETHODCALLTYPE VoiceCBOnStreamEnd(THIS) {}
-static void STDMETHODCALLTYPE VoiceCBOnVoiceProcessPassStart(THIS_ UINT32 b) {}
-static void STDMETHODCALLTYPE VoiceCBOnVoiceProcessPassEnd(THIS) {}
-static void STDMETHODCALLTYPE VoiceCBOnBufferStart(THIS_ void *data) {}
-static void STDMETHODCALLTYPE VoiceCBOnLoopEnd(THIS_ void *data) {}
-
-
-static Uint8 *
-XAUDIO2_GetDeviceBuf(_THIS)
-{
- return this->hidden->nextbuf;
-}
-
-static void
-XAUDIO2_PlayDevice(_THIS)
-{
- XAUDIO2_BUFFER buffer;
- Uint8 *mixbuf = this->hidden->mixbuf;
- Uint8 *nextbuf = this->hidden->nextbuf;
- const int mixlen = this->hidden->mixlen;
- IXAudio2SourceVoice *source = this->hidden->source;
- HRESULT result = S_OK;
-
- if (!this->enabled) { /* shutting down? */
- return;
- }
-
- /* Submit the next filled buffer */
- SDL_zero(buffer);
- buffer.AudioBytes = mixlen;
- buffer.pAudioData = nextbuf;
- buffer.pContext = this;
-
- if (nextbuf == mixbuf) {
- nextbuf += mixlen;
- } else {
- nextbuf = mixbuf;
- }
- this->hidden->nextbuf = nextbuf;
-
- result = IXAudio2SourceVoice_SubmitSourceBuffer(source, &buffer, NULL);
- if (result == XAUDIO2_E_DEVICE_INVALIDATED) {
- /* !!! FIXME: possibly disconnected or temporary lost. Recover? */
- }
-
- if (result != S_OK) { /* uhoh, panic! */
- IXAudio2SourceVoice_FlushSourceBuffers(source);
- this->enabled = 0;
- }
-}
-
-static void
-XAUDIO2_WaitDevice(_THIS)
-{
- if (this->enabled) {
- WaitForSingleObject(this->hidden->semaphore, INFINITE);
- }
-}
-
-static void
-XAUDIO2_WaitDone(_THIS)
-{
- IXAudio2SourceVoice *source = this->hidden->source;
- XAUDIO2_VOICE_STATE state;
- SDL_assert(!this->enabled); /* flag that stops playing. */
- IXAudio2SourceVoice_Discontinuity(source);
- IXAudio2SourceVoice_GetState(source, &state);
- while (state.BuffersQueued > 0) {
- WaitForSingleObject(this->hidden->semaphore, INFINITE);
- IXAudio2SourceVoice_GetState(source, &state);
- }
-}
-
-
-static void
-XAUDIO2_CloseDevice(_THIS)
-{
- if (this->hidden != NULL) {
- IXAudio2 *ixa2 = this->hidden->ixa2;
- IXAudio2SourceVoice *source = this->hidden->source;
- IXAudio2MasteringVoice *mastering = this->hidden->mastering;
-
- if (source != NULL) {
- IXAudio2SourceVoice_Stop(source, 0, XAUDIO2_COMMIT_NOW);
- IXAudio2SourceVoice_FlushSourceBuffers(source);
- IXAudio2SourceVoice_DestroyVoice(source);
- }
- if (ixa2 != NULL) {
- IXAudio2_StopEngine(ixa2);
- }
- if (mastering != NULL) {
- IXAudio2MasteringVoice_DestroyVoice(mastering);
- }
- if (ixa2 != NULL) {
- IXAudio2_Release(ixa2);
- }
- if (this->hidden->mixbuf != NULL) {
- SDL_free(this->hidden->mixbuf);
- }
- if (this->hidden->semaphore != NULL) {
- CloseHandle(this->hidden->semaphore);
- }
-
- SDL_free(this->hidden);
- this->hidden = NULL;
- }
-}
-
-static int
-XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture)
-{
- HRESULT result = S_OK;
- WAVEFORMATEX waveformat;
- int valid_format = 0;
- SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
- IXAudio2 *ixa2 = NULL;
- IXAudio2SourceVoice *source = NULL;
- UINT32 devId = 0; /* 0 == system default device. */
-
- static IXAudio2VoiceCallbackVtbl callbacks_vtable = {
- VoiceCBOnVoiceProcessPassStart,
- VoiceCBOnVoiceProcessPassEnd,
- VoiceCBOnStreamEnd,
- VoiceCBOnBufferStart,
- VoiceCBOnBufferEnd,
- VoiceCBOnLoopEnd,
- VoiceCBOnVoiceError
- };
-
- static IXAudio2VoiceCallback callbacks = { &callbacks_vtable };
-
- if (iscapture) {
- return SDL_SetError("XAudio2: capture devices unsupported.");
- } else if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
- return SDL_SetError("XAudio2: XAudio2Create() failed at open.");
- }
-
- if (devname != NULL) {
- UINT32 devcount = 0;
- UINT32 i = 0;
-
- if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) {
- IXAudio2_Release(ixa2);
- return SDL_SetError("XAudio2: IXAudio2_GetDeviceCount() failed.");
- }
- for (i = 0; i < devcount; i++) {
- XAUDIO2_DEVICE_DETAILS details;
- if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) {
- char *str = utf16_to_utf8(details.DisplayName);
- if (str != NULL) {
- const int match = (SDL_strcmp(str, devname) == 0);
- SDL_free(str);
- if (match) {
- devId = i;
- break;
- }
- }
- }
- }
-
- if (i == devcount) {
- IXAudio2_Release(ixa2);
- return SDL_SetError("XAudio2: Requested device not found.");
- }
- }
-
- /* Initialize all variables that we clean on shutdown */
- this->hidden = (struct SDL_PrivateAudioData *)
- SDL_malloc((sizeof *this->hidden));
- if (this->hidden == NULL) {
- IXAudio2_Release(ixa2);
- return SDL_OutOfMemory();
- }
- SDL_memset(this->hidden, 0, (sizeof *this->hidden));
-
- this->hidden->ixa2 = ixa2;
- this->hidden->semaphore = CreateSemaphore(NULL, 1, 2, NULL);
- if (this->hidden->semaphore == NULL) {
- XAUDIO2_CloseDevice(this);
- return SDL_SetError("XAudio2: CreateSemaphore() failed!");
- }
-
- while ((!valid_format) && (test_format)) {
- switch (test_format) {
- case AUDIO_U8:
- case AUDIO_S16:
- case AUDIO_S32:
- case AUDIO_F32:
- this->spec.format = test_format;
- valid_format = 1;
- break;
- }
- test_format = SDL_NextAudioFormat();
- }
-
- if (!valid_format) {
- XAUDIO2_CloseDevice(this);
- return SDL_SetError("XAudio2: Unsupported audio format");
- }
-
- /* Update the fragment size as size in bytes */
- SDL_CalculateAudioSpec(&this->spec);
-
- /* We feed a Source, it feeds the Mastering, which feeds the device. */
- this->hidden->mixlen = this->spec.size;
- this->hidden->mixbuf = (Uint8 *) SDL_malloc(2 * this->hidden->mixlen);
- if (this->hidden->mixbuf == NULL) {
- XAUDIO2_CloseDevice(this);
- return SDL_OutOfMemory();
- }
- this->hidden->nextbuf = this->hidden->mixbuf;
- SDL_memset(this->hidden->mixbuf, 0, 2 * this->hidden->mixlen);
-
- /* We use XAUDIO2_DEFAULT_CHANNELS instead of this->spec.channels. On
- Xbox360, this means 5.1 output, but on Windows, it means "figure out
- what the system has." It might be preferable to let XAudio2 blast
- stereo output to appropriate surround sound configurations
- instead of clamping to 2 channels, even though we'll configure the
- Source Voice for whatever number of channels you supply. */
- result = IXAudio2_CreateMasteringVoice(ixa2, &this->hidden->mastering,
- XAUDIO2_DEFAULT_CHANNELS,
- this->spec.freq, 0, devId, NULL);
- if (result != S_OK) {
- XAUDIO2_CloseDevice(this);
- return SDL_SetError("XAudio2: Couldn't create mastering voice");
- }
-
- SDL_zero(waveformat);
- if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
- waveformat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
- } else {
- waveformat.wFormatTag = WAVE_FORMAT_PCM;
- }
- waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
- waveformat.nChannels = this->spec.channels;
- waveformat.nSamplesPerSec = this->spec.freq;
- waveformat.nBlockAlign =
- waveformat.nChannels * (waveformat.wBitsPerSample / 8);
- waveformat.nAvgBytesPerSec =
- waveformat.nSamplesPerSec * waveformat.nBlockAlign;
-
- result = IXAudio2_CreateSourceVoice(ixa2, &source, &waveformat,
- XAUDIO2_VOICE_NOSRC |
- XAUDIO2_VOICE_NOPITCH,
- 1.0f, &callbacks, NULL, NULL);
- if (result != S_OK) {
- XAUDIO2_CloseDevice(this);
- return SDL_SetError("XAudio2: Couldn't create source voice");
- }
- this->hidden->source = source;
-
- /* Start everything playing! */
- result = IXAudio2_StartEngine(ixa2);
- if (result != S_OK) {
- XAUDIO2_CloseDevice(this);
- return SDL_SetError("XAudio2: Couldn't start engine");
- }
-
- result = IXAudio2SourceVoice_Start(source, 0, XAUDIO2_COMMIT_NOW);
- if (result != S_OK) {
- XAUDIO2_CloseDevice(this);
- return SDL_SetError("XAudio2: Couldn't start source voice");
- }
-
- return 0; /* good to go. */
-}
-
-static void
-XAUDIO2_Deinitialize(void)
-{
- WIN_CoUninitialize();
-}
-
-#endif /* SDL_XAUDIO2_HAS_SDK */
-
-
-static int
-XAUDIO2_Init(SDL_AudioDriverImpl * impl)
-{
-#ifndef SDL_XAUDIO2_HAS_SDK
- SDL_SetError("XAudio2: SDL was built without XAudio2 support (old DirectX SDK).");
- return 0; /* no XAudio2 support, ever. Update your SDK! */
-#else
- /* XAudio2Create() is a macro that uses COM; we don't load the .dll */
- IXAudio2 *ixa2 = NULL;
- if (FAILED(WIN_CoInitialize())) {
- SDL_SetError("XAudio2: CoInitialize() failed");
- return 0;
- }
-
- if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
- WIN_CoUninitialize();
- SDL_SetError("XAudio2: XAudio2Create() failed at initialization");
- return 0; /* not available. */
- }
- IXAudio2_Release(ixa2);
-
- /* Set the function pointers */
- impl->DetectDevices = XAUDIO2_DetectDevices;
- impl->OpenDevice = XAUDIO2_OpenDevice;
- impl->PlayDevice = XAUDIO2_PlayDevice;
- impl->WaitDevice = XAUDIO2_WaitDevice;
- impl->WaitDone = XAUDIO2_WaitDone;
- impl->GetDeviceBuf = XAUDIO2_GetDeviceBuf;
- impl->CloseDevice = XAUDIO2_CloseDevice;
- impl->Deinitialize = XAUDIO2_Deinitialize;
-
- return 1; /* this audio target is available. */
-#endif
-}
-
-AudioBootStrap XAUDIO2_bootstrap = {
- "xaudio2", "XAudio2", XAUDIO2_Init, 0
-};
-
-#endif /* SDL_AUDIO_DRIVER_XAUDIO2 */
-
-/* vi: set ts=4 sw=4 expandtab: */
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2013 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.
+*/
+
+/* WinRT NOTICE:
+
+ A number of changes were warranted to SDL's XAudio2 backend in order to
+ get it compiling for Windows RT.
+
+ When compiling for WinRT, XAudio2.h requires that it be compiled in a C++
+ file, and not a straight C file. Trying to compile it as C leads to lots
+ of errors, at least with MSVC 2012 and Windows SDK 8.0, as of Nov 22, 2012.
+ To address this specific issue, a few changes were made to SDL_xaudio2.c:
+
+ 1. SDL_xaudio2.c is compiled as a C++ file in WinRT builds. Exported
+ symbols, namely XAUDIO2_bootstrap, uses 'extern "C"' to make sure the
+ rest of SDL can access it. Non-WinRT builds continue to compile
+ SDL_xaudio2.c as a C file.
+ 2. A macro redefines variables named 'this' to '_this', to prevent compiler
+ errors (C2355 in Visual C++) related to 'this' being a reserverd keyword.
+ This hack may need to be altered in the future, particularly if C++'s
+ 'this' keyword needs to be used (within SDL_xaudio2.c). At the time
+ WinRT support was initially added to SDL's XAudio2 backend, this
+ capability was not needed.
+ 3. The C-style macros to invoke XAudio2's COM-based methods were
+ rewritten to be C++-friendly. These are provided in the file,
+ SDL_xaudio2_winrthelpers.h.
+ 4. IXAudio2::CreateSourceVoice, when used in C++, requires its callbacks to
+ be specified via a C++ class. SDL's XAudio2 backend was written with
+ C-style callbacks. A class to bridge these two interfaces,
+ SDL_XAudio2VoiceCallback, was written to make XAudio2 happy. Its methods
+ just call SDL's existing, C-style callbacks.
+ 5. Multiple checks for the __cplusplus macro were made, in appropriate
+ places.
+
+
+ A few additional changes to SDL's XAudio2 backend were warranted by API
+ changes to Windows. Many, but not all of these are documented by Microsoft
+ at:
+ http://blogs.msdn.com/b/chuckw/archive/2012/04/02/xaudio2-and-windows-8-consumer-preview.aspx
+
+ 1. Windows' thread synchronization function, CreateSemaphore, was removed
+ from Windows RT. SDL's semaphore API was substituted instead.
+ 2. The method calls, IXAudio2::GetDeviceCount and IXAudio2::GetDeviceDetails
+ were removed from the XAudio2 API. Microsoft is telling developers to
+ use APIs in Windows::Foundation instead.
+ For SDL, the missing methods were reimplemented using the APIs Microsoft
+ said to use.
+ 3. CoInitialize and CoUninitialize are not available in Windows RT.
+ These calls were removed, as COM will have been initialized earlier,
+ at least by the call to the WinRT app's main function
+ (aka 'int main(Platform::Array^)). (DLudwig:
+ This was my understanding of how WinRT: the 'main' function uses
+ a tag of [MTAThread], which should initialize COM. My understanding
+ of COM is somewhat limited, and I may be incorrect here.)
+ 4. IXAudio2::CreateMasteringVoice changed its integer-based 'DeviceIndex'
+ argument to a string-based one, 'szDeviceId'. In Windows RT, the
+ string-based argument will be used.
+*/
+
+#include "SDL_config.h"
+
+#if SDL_AUDIO_DRIVER_XAUDIO2
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include "../../core/windows/SDL_windows.h"
+#include "SDL_audio.h"
+#include "../SDL_audio_c.h"
+#include "../SDL_sysaudio.h"
+#include "SDL_assert.h"
+#ifdef __cplusplus
+}
+#endif
+
+#if defined(__WINRT__)
+# define SDL_XAUDIO2_HAS_SDK 1
+#endif
+#if defined(__WIN32__)
+#ifdef __GNUC__
+/* The configure script already did any necessary checking */
+# define SDL_XAUDIO2_HAS_SDK 1
+#elif defined(__WINRT__)
+/* WinRT always has access to the .the XAudio 2 SD
+# define SDL_XAUDIO2_HAS_SDK
+#else
+#include /* XAudio2 exists as of the March 2008 DirectX SDK */
+#if (!defined(_DXSDK_BUILD_MAJOR) || (_DXSDK_BUILD_MAJOR < 1284))
+# pragma message("Your DirectX SDK is too old. Disabling XAudio2 support.")
+#else
+# define SDL_XAUDIO2_HAS_SDK 1
+#endif
+#endif
+
+#ifdef SDL_XAUDIO2_HAS_SDK
+
+#define INITGUID 1
+#include
+
+/* Hidden "this" pointer for the audio functions */
+#define _THIS SDL_AudioDevice *this
+
+#ifdef __cplusplus
+#define this _this
+#include "SDL_xaudio2_winrthelpers.h"
+#endif
+
+struct SDL_PrivateAudioData
+{
+ IXAudio2 *ixa2;
+ IXAudio2SourceVoice *source;
+ IXAudio2MasteringVoice *mastering;
+ SDL_sem * semaphore;
+ Uint8 *mixbuf;
+ int mixlen;
+ Uint8 *nextbuf;
+};
+
+
+static void
+XAUDIO2_DetectDevices(int iscapture, SDL_AddAudioDevice addfn)
+{
+ IXAudio2 *ixa2 = NULL;
+ UINT32 devcount = 0;
+ UINT32 i = 0;
+
+ if (iscapture) {
+ SDL_SetError("XAudio2: capture devices unsupported.");
+ return;
+ } else if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
+ SDL_SetError("XAudio2: XAudio2Create() failed at detection.");
+ return;
+ } else if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) {
+ SDL_SetError("XAudio2: IXAudio2::GetDeviceCount() failed.");
+ IXAudio2_Release(ixa2);
+ return;
+ }
+
+ for (i = 0; i < devcount; i++) {
+ XAUDIO2_DEVICE_DETAILS details;
+ if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) {
+ char *str = WIN_StringToUTF8(details.DisplayName);
+ if (str != NULL) {
+ addfn(str);
+ SDL_free(str); /* addfn() made a copy of the string. */
+ }
+ }
+ }
+
+ IXAudio2_Release(ixa2);
+}
+
+static void STDMETHODCALLTYPE
+VoiceCBOnBufferEnd(THIS_ void *data)
+{
+ /* Just signal the SDL audio thread and get out of XAudio2's way. */
+ SDL_AudioDevice *this = (SDL_AudioDevice *) data;
+ SDL_SemPost(this->hidden->semaphore);
+}
+
+static void STDMETHODCALLTYPE
+VoiceCBOnVoiceError(THIS_ void *data, HRESULT Error)
+{
+ /* !!! FIXME: attempt to recover, or mark device disconnected. */
+ SDL_assert(0 && "write me!");
+}
+
+/* no-op callbacks... */
+static void STDMETHODCALLTYPE VoiceCBOnStreamEnd(THIS) {}
+static void STDMETHODCALLTYPE VoiceCBOnVoiceProcessPassStart(THIS_ UINT32 b) {}
+static void STDMETHODCALLTYPE VoiceCBOnVoiceProcessPassEnd(THIS) {}
+static void STDMETHODCALLTYPE VoiceCBOnBufferStart(THIS_ void *data) {}
+static void STDMETHODCALLTYPE VoiceCBOnLoopEnd(THIS_ void *data) {}
+
+#if defined(__cplusplus)
+class SDL_XAudio2VoiceCallback : public IXAudio2VoiceCallback
+{
+public:
+ STDMETHOD_(void, OnBufferEnd)(void *pBufferContext) {
+ VoiceCBOnBufferEnd(pBufferContext);
+ }
+ STDMETHOD_(void, OnBufferStart)(void *pBufferContext) {
+ VoiceCBOnBufferStart(pBufferContext);
+ }
+ STDMETHOD_(void, OnLoopEnd)(void *pBufferContext) {
+ VoiceCBOnLoopEnd(pBufferContext);
+ }
+ STDMETHOD_(void, OnStreamEnd)() {
+ VoiceCBOnStreamEnd();
+ }
+ STDMETHOD_(void, OnVoiceError)(void *pBufferContext, HRESULT Error) {
+ VoiceCBOnVoiceError(pBufferContext, Error);
+ }
+ STDMETHOD_(void, OnVoiceProcessingPassEnd)() {
+ VoiceCBOnVoiceProcessPassEnd();
+ }
+ STDMETHOD_(void, OnVoiceProcessingPassStart)(UINT32 BytesRequired) {
+ VoiceCBOnVoiceProcessPassStart(BytesRequired);
+ }
+};
+#endif
+
+static Uint8 *
+XAUDIO2_GetDeviceBuf(_THIS)
+{
+ return this->hidden->nextbuf;
+}
+
+static void
+XAUDIO2_PlayDevice(_THIS)
+{
+ XAUDIO2_BUFFER buffer;
+ Uint8 *mixbuf = this->hidden->mixbuf;
+ Uint8 *nextbuf = this->hidden->nextbuf;
+ const int mixlen = this->hidden->mixlen;
+ IXAudio2SourceVoice *source = this->hidden->source;
+ HRESULT result = S_OK;
+
+ if (!this->enabled) { /* shutting down? */
+ return;
+ }
+
+ /* Submit the next filled buffer */
+ SDL_zero(buffer);
+ buffer.AudioBytes = mixlen;
+ buffer.pAudioData = nextbuf;
+ buffer.pContext = this;
+
+ if (nextbuf == mixbuf) {
+ nextbuf += mixlen;
+ } else {
+ nextbuf = mixbuf;
+ }
+ this->hidden->nextbuf = nextbuf;
+
+ result = IXAudio2SourceVoice_SubmitSourceBuffer(source, &buffer, NULL);
+ if (result == XAUDIO2_E_DEVICE_INVALIDATED) {
+ /* !!! FIXME: possibly disconnected or temporary lost. Recover? */
+ }
+
+ if (result != S_OK) { /* uhoh, panic! */
+ IXAudio2SourceVoice_FlushSourceBuffers(source);
+ this->enabled = 0;
+ }
+}
+
+static void
+XAUDIO2_WaitDevice(_THIS)
+{
+ if (this->enabled) {
+ SDL_SemWait(this->hidden->semaphore);
+ }
+}
+
+static void
+XAUDIO2_WaitDone(_THIS)
+{
+ IXAudio2SourceVoice *source = this->hidden->source;
+ XAUDIO2_VOICE_STATE state;
+ SDL_assert(!this->enabled); /* flag that stops playing. */
+ IXAudio2SourceVoice_Discontinuity(source);
+ IXAudio2SourceVoice_GetState(source, &state);
+ while (state.BuffersQueued > 0) {
+ SDL_SemWait(this->hidden->semaphore);
+ IXAudio2SourceVoice_GetState(source, &state);
+ }
+}
+
+
+static void
+XAUDIO2_CloseDevice(_THIS)
+{
+ if (this->hidden != NULL) {
+ IXAudio2 *ixa2 = this->hidden->ixa2;
+ IXAudio2SourceVoice *source = this->hidden->source;
+ IXAudio2MasteringVoice *mastering = this->hidden->mastering;
+
+ if (source != NULL) {
+ IXAudio2SourceVoice_Stop(source, 0, XAUDIO2_COMMIT_NOW);
+ IXAudio2SourceVoice_FlushSourceBuffers(source);
+ IXAudio2SourceVoice_DestroyVoice(source);
+ }
+ if (ixa2 != NULL) {
+ IXAudio2_StopEngine(ixa2);
+ }
+ if (mastering != NULL) {
+ IXAudio2MasteringVoice_DestroyVoice(mastering);
+ }
+ if (ixa2 != NULL) {
+ IXAudio2_Release(ixa2);
+ }
+ if (this->hidden->mixbuf != NULL) {
+ SDL_free(this->hidden->mixbuf);
+ }
+ if (this->hidden->semaphore != NULL) {
+ SDL_DestroySemaphore(this->hidden->semaphore);
+ }
+
+ SDL_free(this->hidden);
+ this->hidden = NULL;
+ }
+}
+
+static int
+XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture)
+{
+ HRESULT result = S_OK;
+ WAVEFORMATEX waveformat;
+ int valid_format = 0;
+ SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format);
+ IXAudio2 *ixa2 = NULL;
+ IXAudio2SourceVoice *source = NULL;
+#if defined(__WINRT__)
+ WCHAR devIdBuffer[256];
+ LPCWSTR devId = 0;
+#else
+ UINT32 devId = 0; /* 0 == system default device. */
+#endif
+
+#if defined(__cplusplus)
+ static SDL_XAudio2VoiceCallback callbacks;
+#else
+ static IXAudio2VoiceCallbackVtbl callbacks_vtable = {
+ VoiceCBOnVoiceProcessPassStart,
+ VoiceCBOnVoiceProcessPassEnd,
+ VoiceCBOnStreamEnd,
+ VoiceCBOnBufferStart,
+ VoiceCBOnBufferEnd,
+ VoiceCBOnLoopEnd,
+ VoiceCBOnVoiceError
+ };
+
+ static IXAudio2VoiceCallback callbacks = { &callbacks_vtable };
+#endif // ! defined(__cplusplus)
+
+#if defined(__WINRT__)
+ SDL_zero(devIdBuffer);
+#endif
+
+ if (iscapture) {
+ return SDL_SetError("XAudio2: capture devices unsupported.");
+ } else if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
+ return SDL_SetError("XAudio2: XAudio2Create() failed at open.");
+ }
+ /*
+ XAUDIO2_DEBUG_CONFIGURATION debugConfig;
+ debugConfig.TraceMask = XAUDIO2_LOG_ERRORS; //XAUDIO2_LOG_WARNINGS | XAUDIO2_LOG_DETAIL | XAUDIO2_LOG_FUNC_CALLS | XAUDIO2_LOG_TIMING | XAUDIO2_LOG_LOCKS | XAUDIO2_LOG_MEMORY | XAUDIO2_LOG_STREAMING;
+ debugConfig.BreakMask = XAUDIO2_LOG_ERRORS; //XAUDIO2_LOG_WARNINGS;
+ debugConfig.LogThreadID = TRUE;
+ debugConfig.LogFileline = TRUE;
+ debugConfig.LogFunctionName = TRUE;
+ debugConfig.LogTiming = TRUE;
+ ixa2->SetDebugConfiguration(&debugConfig);
+ */
+
+#if ! defined(__WINRT__) || WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
+ if (devname != NULL) {
+ UINT32 devcount = 0;
+ UINT32 i = 0;
+
+ if (IXAudio2_GetDeviceCount(ixa2, &devcount) != S_OK) {
+ IXAudio2_Release(ixa2);
+ return SDL_SetError("XAudio2: IXAudio2_GetDeviceCount() failed.");
+ }
+ for (i = 0; i < devcount; i++) {
+ XAUDIO2_DEVICE_DETAILS details;
+ if (IXAudio2_GetDeviceDetails(ixa2, i, &details) == S_OK) {
+ char *str = WIN_StringToUTF8(details.DisplayName);
+ if (str != NULL) {
+ const int match = (SDL_strcmp(str, devname) == 0);
+ SDL_free(str);
+ if (match) {
+#if defined(__WINRT__)
+ wcsncpy_s(devIdBuffer, ARRAYSIZE(devIdBuffer), details.DeviceID, _TRUNCATE);
+ devId = (LPCWSTR) &devIdBuffer;
+#else
+ devId = i;
+#endif
+ break;
+ }
+ }
+ }
+ }
+
+ if (i == devcount) {
+ IXAudio2_Release(ixa2);
+ return SDL_SetError("XAudio2: Requested device not found.");
+ }
+ }
+#endif
+
+ /* Initialize all variables that we clean on shutdown */
+ this->hidden = (struct SDL_PrivateAudioData *)
+ SDL_malloc((sizeof *this->hidden));
+ if (this->hidden == NULL) {
+ IXAudio2_Release(ixa2);
+ return SDL_OutOfMemory();
+ }
+ SDL_memset(this->hidden, 0, (sizeof *this->hidden));
+
+ this->hidden->ixa2 = ixa2;
+ this->hidden->semaphore = SDL_CreateSemaphore(1);
+ if (this->hidden->semaphore == NULL) {
+ XAUDIO2_CloseDevice(this);
+ return SDL_SetError("XAudio2: CreateSemaphore() failed!");
+ }
+
+ while ((!valid_format) && (test_format)) {
+ switch (test_format) {
+ case AUDIO_U8:
+ case AUDIO_S16:
+ case AUDIO_S32:
+ case AUDIO_F32:
+ this->spec.format = test_format;
+ valid_format = 1;
+ break;
+ }
+ test_format = SDL_NextAudioFormat();
+ }
+
+ if (!valid_format) {
+ XAUDIO2_CloseDevice(this);
+ return SDL_SetError("XAudio2: Unsupported audio format");
+ }
+
+ /* Update the fragment size as size in bytes */
+ SDL_CalculateAudioSpec(&this->spec);
+
+ /* We feed a Source, it feeds the Mastering, which feeds the device. */
+ this->hidden->mixlen = this->spec.size;
+ this->hidden->mixbuf = (Uint8 *) SDL_malloc(2 * this->hidden->mixlen);
+ if (this->hidden->mixbuf == NULL) {
+ XAUDIO2_CloseDevice(this);
+ return SDL_OutOfMemory();
+ }
+ this->hidden->nextbuf = this->hidden->mixbuf;
+ SDL_memset(this->hidden->mixbuf, 0, 2 * this->hidden->mixlen);
+
+ /* We use XAUDIO2_DEFAULT_CHANNELS instead of this->spec.channels. On
+ Xbox360, this means 5.1 output, but on Windows, it means "figure out
+ what the system has." It might be preferable to let XAudio2 blast
+ stereo output to appropriate surround sound configurations
+ instead of clamping to 2 channels, even though we'll configure the
+ Source Voice for whatever number of channels you supply. */
+ result = IXAudio2_CreateMasteringVoice(ixa2, &this->hidden->mastering,
+ XAUDIO2_DEFAULT_CHANNELS,
+ this->spec.freq, 0, devId, NULL);
+ if (result != S_OK) {
+ XAUDIO2_CloseDevice(this);
+ return SDL_SetError("XAudio2: Couldn't create mastering voice");
+ }
+
+ SDL_zero(waveformat);
+ if (SDL_AUDIO_ISFLOAT(this->spec.format)) {
+ waveformat.wFormatTag = WAVE_FORMAT_IEEE_FLOAT;
+ } else {
+ waveformat.wFormatTag = WAVE_FORMAT_PCM;
+ }
+ waveformat.wBitsPerSample = SDL_AUDIO_BITSIZE(this->spec.format);
+ waveformat.nChannels = this->spec.channels;
+ waveformat.nSamplesPerSec = this->spec.freq;
+ waveformat.nBlockAlign =
+ waveformat.nChannels * (waveformat.wBitsPerSample / 8);
+ waveformat.nAvgBytesPerSec =
+ waveformat.nSamplesPerSec * waveformat.nBlockAlign;
+ waveformat.cbSize = sizeof(waveformat);
+
+#ifdef __WINRT__
+ // DLudwig: for now, make XAudio2 do sample rate conversion, just to
+ // get the loopwave test to work.
+ //
+ // TODO, WinRT: consider removing WinRT-specific source-voice creation code from SDL_xaudio2.c
+ result = IXAudio2_CreateSourceVoice(ixa2, &source, &waveformat,
+ 0,
+ 1.0f, &callbacks, NULL, NULL);
+#else
+ result = IXAudio2_CreateSourceVoice(ixa2, &source, &waveformat,
+ XAUDIO2_VOICE_NOSRC |
+ XAUDIO2_VOICE_NOPITCH,
+ 1.0f, &callbacks, NULL, NULL);
+
+#endif
+ if (result != S_OK) {
+ XAUDIO2_CloseDevice(this);
+ return SDL_SetError("XAudio2: Couldn't create source voice");
+ }
+ this->hidden->source = source;
+
+ /* Start everything playing! */
+ result = IXAudio2_StartEngine(ixa2);
+ if (result != S_OK) {
+ XAUDIO2_CloseDevice(this);
+ return SDL_SetError("XAudio2: Couldn't start engine");
+ }
+
+ result = IXAudio2SourceVoice_Start(source, 0, XAUDIO2_COMMIT_NOW);
+ if (result != S_OK) {
+ XAUDIO2_CloseDevice(this);
+ return SDL_SetError("XAudio2: Couldn't start source voice");
+ }
+
+ return 0; /* good to go. */
+}
+
+static void
+XAUDIO2_Deinitialize(void)
+{
+#if defined(__WIN32__)
+ WIN_CoUninitialize();
+#endif
+}
+
+#endif /* SDL_XAUDIO2_HAS_SDK */
+
+
+static int
+XAUDIO2_Init(SDL_AudioDriverImpl * impl)
+{
+#ifndef SDL_XAUDIO2_HAS_SDK
+ SDL_SetError("XAudio2: SDL was built without XAudio2 support (old DirectX SDK).");
+ return 0; /* no XAudio2 support, ever. Update your SDK! */
+#else
+ /* XAudio2Create() is a macro that uses COM; we don't load the .dll */
+ IXAudio2 *ixa2 = NULL;
+#if defined(__WIN32__)
+ // TODO, WinRT: Investigate using CoInitializeEx here
+ if (FAILED(WIN_CoInitialize())) {
+ SDL_SetError("XAudio2: CoInitialize() failed");
+ return 0;
+ }
+#endif
+
+ if (XAudio2Create(&ixa2, 0, XAUDIO2_DEFAULT_PROCESSOR) != S_OK) {
+#if defined(__WIN32__)
+ WIN_CoUninitialize();
+#endif
+ SDL_SetError("XAudio2: XAudio2Create() failed at initialization");
+ return 0; /* not available. */
+ }
+ IXAudio2_Release(ixa2);
+
+ /* Set the function pointers */
+ impl->DetectDevices = XAUDIO2_DetectDevices;
+ impl->OpenDevice = XAUDIO2_OpenDevice;
+ impl->PlayDevice = XAUDIO2_PlayDevice;
+ impl->WaitDevice = XAUDIO2_WaitDevice;
+ impl->WaitDone = XAUDIO2_WaitDone;
+ impl->GetDeviceBuf = XAUDIO2_GetDeviceBuf;
+ impl->CloseDevice = XAUDIO2_CloseDevice;
+ impl->Deinitialize = XAUDIO2_Deinitialize;
+
+ return 1; /* this audio target is available. */
+#endif
+}
+
+#if defined(__cplusplus)
+extern "C"
+#endif
+AudioBootStrap XAUDIO2_bootstrap = {
+ "xaudio2", "XAudio2", XAUDIO2_Init, 0
+};
+
+#endif /* SDL_AUDIO_DRIVER_XAUDIO2 */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp
new file mode 100644
index 000000000..aa88fd6c1
--- /dev/null
+++ b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp
@@ -0,0 +1,69 @@
+
+#include
+#include "SDL_xaudio2_winrthelpers.h"
+
+#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
+using Windows::Devices::Enumeration::DeviceClass;
+using Windows::Devices::Enumeration::DeviceInformation;
+using Windows::Devices::Enumeration::DeviceInformationCollection;
+#endif
+
+HRESULT IXAudio2_GetDeviceCount(IXAudio2 * ixa2, UINT32 * devcount)
+{
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+ // There doesn't seem to be any audio device enumeration on Windows Phone.
+ // In lieu of this, just treat things as if there is one and only one
+ // audio device.
+ *devcount = 1;
+ return S_OK;
+#else
+ // TODO, WinRT: make xaudio2 device enumeration only happen once, and in the background
+ auto operation = DeviceInformation::FindAllAsync(DeviceClass::AudioRender);
+ while (operation->Status != Windows::Foundation::AsyncStatus::Completed)
+ {
+ }
+
+ DeviceInformationCollection^ devices = operation->GetResults();
+ *devcount = devices->Size;
+ return S_OK;
+#endif
+}
+
+HRESULT IXAudio2_GetDeviceDetails(IXAudio2 * unused, UINT32 index, XAUDIO2_DEVICE_DETAILS * details)
+{
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+ // Windows Phone doesn't seem to have the same device enumeration APIs that
+ // Windows 8/RT has, or it doesn't have them at all. In lieu of this,
+ // just treat things as if there is one, and only one, default device.
+ if (index != 0)
+ {
+ return XAUDIO2_E_INVALID_CALL;
+ }
+
+ if (details)
+ {
+ wcsncpy_s(details->DeviceID, ARRAYSIZE(details->DeviceID), L"default", _TRUNCATE);
+ wcsncpy_s(details->DisplayName, ARRAYSIZE(details->DisplayName), L"default", _TRUNCATE);
+ }
+ return S_OK;
+#else
+ auto operation = DeviceInformation::FindAllAsync(DeviceClass::AudioRender);
+ while (operation->Status != Windows::Foundation::AsyncStatus::Completed)
+ {
+ }
+
+ DeviceInformationCollection^ devices = operation->GetResults();
+ if (index >= devices->Size)
+ {
+ return XAUDIO2_E_INVALID_CALL;
+ }
+
+ DeviceInformation^ d = devices->GetAt(index);
+ if (details)
+ {
+ wcsncpy_s(details->DeviceID, ARRAYSIZE(details->DeviceID), d->Id->Data(), _TRUNCATE);
+ wcsncpy_s(details->DisplayName, ARRAYSIZE(details->DisplayName), d->Name->Data(), _TRUNCATE);
+ }
+ return S_OK;
+#endif
+}
diff --git a/src/audio/xaudio2/SDL_xaudio2_winrthelpers.h b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.h
new file mode 100644
index 000000000..a72804faa
--- /dev/null
+++ b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.h
@@ -0,0 +1,40 @@
+
+#pragma once
+
+//
+// Re-implementation of methods removed from XAudio2 (in Windows RT):
+//
+
+typedef struct XAUDIO2_DEVICE_DETAILS
+{
+ WCHAR DeviceID[256];
+ WCHAR DisplayName[256];
+ /* Other fields exist in the pre-Windows 8 version of this struct, however
+ they weren't used by SDL, so they weren't added.
+ */
+} XAUDIO2_DEVICE_DETAILS;
+
+HRESULT IXAudio2_GetDeviceCount(IXAudio2 * unused, UINT32 * devcount);
+HRESULT IXAudio2_GetDeviceDetails(IXAudio2 * unused, UINT32 index, XAUDIO2_DEVICE_DETAILS * details);
+
+
+//
+// C-style macros to call XAudio2's methods in C++:
+//
+
+#define IXAudio2_CreateMasteringVoice(A, B, C, D, E, F, G) (A)->CreateMasteringVoice((B), (C), (D), (E), (F), (G))
+#define IXAudio2_CreateSourceVoice(A, B, C, D, E, F, G, H) (A)->CreateSourceVoice((B), (C), (D), (E), (F), (G), (H))
+#define IXAudio2_QueryInterface(A, B, C) (A)->QueryInterface((B), (C))
+#define IXAudio2_Release(A) (A)->Release()
+#define IXAudio2_StartEngine(A) (A)->StartEngine()
+#define IXAudio2_StopEngine(A) (A)->StopEngine()
+
+#define IXAudio2MasteringVoice_DestroyVoice(A) (A)->DestroyVoice()
+
+#define IXAudio2SourceVoice_DestroyVoice(A) (A)->DestroyVoice()
+#define IXAudio2SourceVoice_Discontinuity(A) (A)->Discontinuity()
+#define IXAudio2SourceVoice_FlushSourceBuffers(A) (A)->FlushSourceBuffers()
+#define IXAudio2SourceVoice_GetState(A, B) (A)->GetState((B))
+#define IXAudio2SourceVoice_Start(A, B, C) (A)->Start((B), (C))
+#define IXAudio2SourceVoice_Stop(A, B, C) (A)->Stop((B), (C))
+#define IXAudio2SourceVoice_SubmitSourceBuffer(A, B, C) (A)->SubmitSourceBuffer((B), (C))
diff --git a/src/core/windows/SDL_windows.c b/src/core/windows/SDL_windows.c
index e69d25793..2388f93fa 100644
--- a/src/core/windows/SDL_windows.c
+++ b/src/core/windows/SDL_windows.c
@@ -20,21 +20,21 @@
*/
#include "SDL_config.h"
-#ifdef __WIN32__
+#if defined(__WIN32__) || defined(__WINRT__)
#include "SDL_error.h"
#include "SDL_windows.h"
#include "SDL_assert.h"
-#include /* for CoInitialize/CoUninitialize */
+#include /* for CoInitialize/CoUninitialize (Win32 only) */
/* Sets an error message based on GetLastError() */
int
-WIN_SetError(const char *prefix)
+WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr)
{
TCHAR buffer[1024];
char *message;
- FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0,
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, hr, 0,
buffer, SDL_arraysize(buffer), NULL);
message = WIN_StringToUTF8(buffer);
SDL_SetError("%s%s%s", prefix ? prefix : "", prefix ? ": " : "", message);
@@ -42,9 +42,24 @@ WIN_SetError(const char *prefix)
return -1;
}
+/* Sets an error message based on GetLastError() */
+int
+WIN_SetError(const char *prefix)
+{
+ return WIN_SetErrorFromHRESULT(prefix, GetLastError());
+}
+
HRESULT
WIN_CoInitialize(void)
{
+#ifdef __WINRT__
+ /* DLudwig: On WinRT, it is assumed that COM was initialized in main().
+ CoInitializeEx is available (not CoInitialize though), however
+ on WinRT, main() is typically declared with the [MTAThread]
+ attribute, which, AFAIK, should initialize COM.
+ */
+ return S_OK;
+#else
const HRESULT hr = CoInitialize(NULL);
/* S_FALSE means success, but someone else already initialized. */
@@ -54,12 +69,15 @@ WIN_CoInitialize(void)
}
return hr;
+#endif
}
void
WIN_CoUninitialize(void)
{
+#ifndef __WINRT__
CoUninitialize();
+#endif
}
#endif /* __WIN32__ */
diff --git a/src/core/windows/SDL_windows.h b/src/core/windows/SDL_windows.h
index 440c387d3..ce614a998 100644
--- a/src/core/windows/SDL_windows.h
+++ b/src/core/windows/SDL_windows.h
@@ -24,6 +24,7 @@
#ifndef _INCLUDED_WINDOWS_H
#define _INCLUDED_WINDOWS_H
+#if defined(__WIN32__)
#define WIN32_LEAN_AND_MEAN
#define STRICT
#ifndef UNICODE
@@ -31,6 +32,7 @@
#endif
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x501 /* Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices(), 0x501 for raw input */
+#endif
#include
@@ -43,6 +45,9 @@
#define WIN_UTF8ToString(S) SDL_iconv_string("ASCII", "UTF-8", (char *)(S), SDL_strlen(S)+1)
#endif
+/* Sets an error message based on a given HRESULT */
+extern int WIN_SetErrorFromHRESULT(const char *prefix, HRESULT hr);
+
/* Sets an error message based on GetLastError(). Always return -1. */
extern int WIN_SetError(const char *prefix);
diff --git a/src/core/windowsrt/SDL_winrtpaths.cpp b/src/core/windowsrt/SDL_winrtpaths.cpp
new file mode 100644
index 000000000..4c10b78b7
--- /dev/null
+++ b/src/core/windowsrt/SDL_winrtpaths.cpp
@@ -0,0 +1,94 @@
+/* TODO, WinRT: include copyright info in SDL_winrtpaths.cpp
+ TODO, WinRT: add note to SDL_winrtpaths.cpp mentioning that /ZW must be used when compiling the file
+*/
+
+#include "SDL_config.h"
+
+#ifdef __WINRT__
+
+extern "C" {
+#include "SDL_error.h"
+#include "SDL_stdinc.h"
+#include "SDL_system.h"
+#include "../windows/SDL_windows.h"
+}
+
+#include
+#include
+
+using namespace std;
+using namespace Windows::Storage;
+
+extern "C" const wchar_t *
+SDL_WinRTGetFSPathUNICODE(SDL_WinRT_Path pathType)
+{
+ switch (pathType) {
+ case SDL_WINRT_PATH_INSTALLED_LOCATION:
+ {
+ static wstring path;
+ if (path.empty()) {
+ path = Windows::ApplicationModel::Package::Current->InstalledLocation->Path->Data();
+ }
+ return path.c_str();
+ }
+
+ case SDL_WINRT_PATH_LOCAL_FOLDER:
+ {
+ static wstring path;
+ if (path.empty()) {
+ path = ApplicationData::Current->LocalFolder->Path->Data();
+ }
+ return path.c_str();
+ }
+
+#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
+ case SDL_WINRT_PATH_ROAMING_FOLDER:
+ {
+ static wstring path;
+ if (path.empty()) {
+ path = ApplicationData::Current->RoamingFolder->Path->Data();
+ }
+ return path.c_str();
+ }
+
+ case SDL_WINRT_PATH_TEMP_FOLDER:
+ {
+ static wstring path;
+ if (path.empty()) {
+ path = ApplicationData::Current->TemporaryFolder->Path->Data();
+ }
+ return path.c_str();
+ }
+#endif
+
+ default:
+ break;
+ }
+
+ SDL_Unsupported();
+ return NULL;
+}
+
+extern "C" const char *
+SDL_WinRTGetFSPathUTF8(SDL_WinRT_Path pathType)
+{
+ typedef unordered_map UTF8PathMap;
+ static UTF8PathMap utf8Paths;
+
+ UTF8PathMap::iterator searchResult = utf8Paths.find(pathType);
+ if (searchResult != utf8Paths.end()) {
+ return searchResult->second.c_str();
+ }
+
+ const wchar_t * ucs2Path = SDL_WinRTGetFSPathUNICODE(pathType);
+ if (!ucs2Path) {
+ return NULL;
+ }
+
+ char * utf8Path = WIN_StringToUTF8(ucs2Path);
+ utf8Paths[pathType] = utf8Path;
+ SDL_free(utf8Path);
+ return utf8Paths[pathType].c_str();
+}
+
+#endif /* __WINRT__ */
diff --git a/src/file/SDL_rwops.c b/src/file/SDL_rwops.c
index afbc39aa0..3a6f7db66 100644
--- a/src/file/SDL_rwops.c
+++ b/src/file/SDL_rwops.c
@@ -1,757 +1,764 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2013 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.
-*/
-/* Need this so Linux systems define fseek64o, ftell64o and off64_t */
-#define _LARGEFILE64_SOURCE
-#include "SDL_config.h"
-
-/* This file provides a general interface for SDL to read and write
- data sources. It can easily be extended to files, memory, etc.
-*/
-
-#include "SDL_endian.h"
-#include "SDL_rwops.h"
-
-#ifdef __APPLE__
-#include "cocoa/SDL_rwopsbundlesupport.h"
-#endif /* __APPLE__ */
-
-#ifdef ANDROID
-#include "../core/android/SDL_android.h"
-#include "SDL_system.h"
-#endif
-
-#ifdef __WIN32__
-
-/* Functions to read/write Win32 API file pointers */
-
-#include "../core/windows/SDL_windows.h"
-
-#ifndef INVALID_SET_FILE_POINTER
-#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
-#endif
-
-#define READAHEAD_BUFFER_SIZE 1024
-
-static int SDLCALL
-windows_file_open(SDL_RWops * context, const char *filename, const char *mode)
-{
- UINT old_error_mode;
- HANDLE h;
- DWORD r_right, w_right;
- DWORD must_exist, truncate;
- int a_mode;
-
- if (!context)
- return -1; /* failed (invalid call) */
-
- context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* mark this as unusable */
- context->hidden.windowsio.buffer.data = NULL;
- context->hidden.windowsio.buffer.size = 0;
- context->hidden.windowsio.buffer.left = 0;
-
- /* "r" = reading, file must exist */
- /* "w" = writing, truncate existing, file may not exist */
- /* "r+"= reading or writing, file must exist */
- /* "a" = writing, append file may not exist */
- /* "a+"= append + read, file may not exist */
- /* "w+" = read, write, truncate. file may not exist */
-
- must_exist = (SDL_strchr(mode, 'r') != NULL) ? OPEN_EXISTING : 0;
- truncate = (SDL_strchr(mode, 'w') != NULL) ? CREATE_ALWAYS : 0;
- r_right = (SDL_strchr(mode, '+') != NULL
- || must_exist) ? GENERIC_READ : 0;
- a_mode = (SDL_strchr(mode, 'a') != NULL) ? OPEN_ALWAYS : 0;
- w_right = (a_mode || SDL_strchr(mode, '+')
- || truncate) ? GENERIC_WRITE : 0;
-
- if (!r_right && !w_right) /* inconsistent mode */
- return -1; /* failed (invalid call) */
-
- context->hidden.windowsio.buffer.data =
- (char *) SDL_malloc(READAHEAD_BUFFER_SIZE);
- if (!context->hidden.windowsio.buffer.data) {
- return SDL_OutOfMemory();
- }
- /* Do not open a dialog box if failure */
- old_error_mode =
- SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
-
- {
- LPTSTR tstr = WIN_UTF8ToString(filename);
- h = CreateFile(tstr, (w_right | r_right),
- (w_right) ? 0 : FILE_SHARE_READ, NULL,
- (must_exist | truncate | a_mode),
- FILE_ATTRIBUTE_NORMAL, NULL);
- SDL_free(tstr);
- }
-
- /* restore old behavior */
- SetErrorMode(old_error_mode);
-
- if (h == INVALID_HANDLE_VALUE) {
- SDL_free(context->hidden.windowsio.buffer.data);
- context->hidden.windowsio.buffer.data = NULL;
- SDL_SetError("Couldn't open %s", filename);
- return -2; /* failed (CreateFile) */
- }
- context->hidden.windowsio.h = h;
- context->hidden.windowsio.append = a_mode ? SDL_TRUE : SDL_FALSE;
-
- return 0; /* ok */
-}
-
-static Sint64 SDLCALL
-windows_file_size(SDL_RWops * context)
-{
- LARGE_INTEGER size;
-
- if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
- return SDL_SetError("windows_file_size: invalid context/file not opened");
- }
-
- if (!GetFileSizeEx(context->hidden.windowsio.h, &size)) {
- return WIN_SetError("windows_file_size");
- }
-
- return size.QuadPart;
-}
-
-static Sint64 SDLCALL
-windows_file_seek(SDL_RWops * context, Sint64 offset, int whence)
-{
- DWORD windowswhence;
- LARGE_INTEGER windowsoffset;
-
- if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
- return SDL_SetError("windows_file_seek: invalid context/file not opened");
- }
-
- /* FIXME: We may be able to satisfy the seek within buffered data */
- if (whence == RW_SEEK_CUR && context->hidden.windowsio.buffer.left) {
- offset -= (long)context->hidden.windowsio.buffer.left;
- }
- context->hidden.windowsio.buffer.left = 0;
-
- switch (whence) {
- case RW_SEEK_SET:
- windowswhence = FILE_BEGIN;
- break;
- case RW_SEEK_CUR:
- windowswhence = FILE_CURRENT;
- break;
- case RW_SEEK_END:
- windowswhence = FILE_END;
- break;
- default:
- return SDL_SetError("windows_file_seek: Unknown value for 'whence'");
- }
-
- windowsoffset.QuadPart = offset;
- if (!SetFilePointerEx(context->hidden.windowsio.h, windowsoffset, &windowsoffset, windowswhence)) {
- return WIN_SetError("windows_file_seek");
- }
- return windowsoffset.QuadPart;
-}
-
-static size_t SDLCALL
-windows_file_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
-{
- size_t total_need;
- size_t total_read = 0;
- size_t read_ahead;
- DWORD byte_read;
-
- total_need = size * maxnum;
-
- if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
- || !total_need)
- return 0;
-
- if (context->hidden.windowsio.buffer.left > 0) {
- void *data = (char *) context->hidden.windowsio.buffer.data +
- context->hidden.windowsio.buffer.size -
- context->hidden.windowsio.buffer.left;
- read_ahead =
- SDL_min(total_need, context->hidden.windowsio.buffer.left);
- SDL_memcpy(ptr, data, read_ahead);
- context->hidden.windowsio.buffer.left -= read_ahead;
-
- if (read_ahead == total_need) {
- return maxnum;
- }
- ptr = (char *) ptr + read_ahead;
- total_need -= read_ahead;
- total_read += read_ahead;
- }
-
- if (total_need < READAHEAD_BUFFER_SIZE) {
- if (!ReadFile
- (context->hidden.windowsio.h, context->hidden.windowsio.buffer.data,
- READAHEAD_BUFFER_SIZE, &byte_read, NULL)) {
- SDL_Error(SDL_EFREAD);
- return 0;
- }
- read_ahead = SDL_min(total_need, (int) byte_read);
- SDL_memcpy(ptr, context->hidden.windowsio.buffer.data, read_ahead);
- context->hidden.windowsio.buffer.size = byte_read;
- context->hidden.windowsio.buffer.left = byte_read - read_ahead;
- total_read += read_ahead;
- } else {
- if (!ReadFile
- (context->hidden.windowsio.h, ptr, (DWORD)total_need, &byte_read, NULL)) {
- SDL_Error(SDL_EFREAD);
- return 0;
- }
- total_read += byte_read;
- }
- return (total_read / size);
-}
-
-static size_t SDLCALL
-windows_file_write(SDL_RWops * context, const void *ptr, size_t size,
- size_t num)
-{
-
- size_t total_bytes;
- DWORD byte_written;
- size_t nwritten;
-
- total_bytes = size * num;
-
- if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
- || total_bytes <= 0 || !size)
- return 0;
-
- if (context->hidden.windowsio.buffer.left) {
- SetFilePointer(context->hidden.windowsio.h,
- -(LONG)context->hidden.windowsio.buffer.left, NULL,
- FILE_CURRENT);
- context->hidden.windowsio.buffer.left = 0;
- }
-
- /* if in append mode, we must go to the EOF before write */
- if (context->hidden.windowsio.append) {
- if (SetFilePointer(context->hidden.windowsio.h, 0L, NULL, FILE_END) ==
- INVALID_SET_FILE_POINTER) {
- SDL_Error(SDL_EFWRITE);
- return 0;
- }
- }
-
- if (!WriteFile
- (context->hidden.windowsio.h, ptr, (DWORD)total_bytes, &byte_written, NULL)) {
- SDL_Error(SDL_EFWRITE);
- return 0;
- }
-
- nwritten = byte_written / size;
- return nwritten;
-}
-
-static int SDLCALL
-windows_file_close(SDL_RWops * context)
-{
-
- if (context) {
- if (context->hidden.windowsio.h != INVALID_HANDLE_VALUE) {
- CloseHandle(context->hidden.windowsio.h);
- context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* to be sure */
- }
- if (context->hidden.windowsio.buffer.data) {
- SDL_free(context->hidden.windowsio.buffer.data);
- context->hidden.windowsio.buffer.data = NULL;
- }
- SDL_FreeRW(context);
- }
- return (0);
-}
-#endif /* __WIN32__ */
-
-#ifdef HAVE_STDIO_H
-
-/* Functions to read/write stdio file pointers */
-
-static Sint64 SDLCALL
-stdio_size(SDL_RWops * context)
-{
- Sint64 pos, size;
-
- pos = SDL_RWseek(context, 0, RW_SEEK_CUR);
- if (pos < 0) {
- return -1;
- }
- size = SDL_RWseek(context, 0, RW_SEEK_END);
-
- SDL_RWseek(context, pos, RW_SEEK_SET);
- return size;
-}
-
-static Sint64 SDLCALL
-stdio_seek(SDL_RWops * context, Sint64 offset, int whence)
-{
-#ifdef HAVE_FSEEKO64
- if (fseeko64(context->hidden.stdio.fp, (off64_t)offset, whence) == 0) {
- return ftello64(context->hidden.stdio.fp);
- }
-#elif defined(HAVE_FSEEKO)
- if (fseeko(context->hidden.stdio.fp, (off_t)offset, whence) == 0) {
- return ftello(context->hidden.stdio.fp);
- }
-#else
- if (fseek(context->hidden.stdio.fp, offset, whence) == 0) {
- return (ftell(context->hidden.stdio.fp));
- }
-#endif
- return SDL_Error(SDL_EFSEEK);
-}
-
-static size_t SDLCALL
-stdio_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
-{
- size_t nread;
-
- nread = fread(ptr, size, maxnum, context->hidden.stdio.fp);
- if (nread == 0 && ferror(context->hidden.stdio.fp)) {
- SDL_Error(SDL_EFREAD);
- }
- return (nread);
-}
-
-static size_t SDLCALL
-stdio_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
-{
- size_t nwrote;
-
- nwrote = fwrite(ptr, size, num, context->hidden.stdio.fp);
- if (nwrote == 0 && ferror(context->hidden.stdio.fp)) {
- SDL_Error(SDL_EFWRITE);
- }
- return (nwrote);
-}
-
-static int SDLCALL
-stdio_close(SDL_RWops * context)
-{
- int status = 0;
- if (context) {
- if (context->hidden.stdio.autoclose) {
- /* WARNING: Check the return value here! */
- if (fclose(context->hidden.stdio.fp) != 0) {
- status = SDL_Error(SDL_EFWRITE);
- }
- }
- SDL_FreeRW(context);
- }
- return status;
-}
-#endif /* !HAVE_STDIO_H */
-
-/* Functions to read/write memory pointers */
-
-static Sint64 SDLCALL
-mem_size(SDL_RWops * context)
-{
- return (Sint64)(context->hidden.mem.stop - context->hidden.mem.base);
-}
-
-static Sint64 SDLCALL
-mem_seek(SDL_RWops * context, Sint64 offset, int whence)
-{
- Uint8 *newpos;
-
- switch (whence) {
- case RW_SEEK_SET:
- newpos = context->hidden.mem.base + offset;
- break;
- case RW_SEEK_CUR:
- newpos = context->hidden.mem.here + offset;
- break;
- case RW_SEEK_END:
- newpos = context->hidden.mem.stop + offset;
- break;
- default:
- return SDL_SetError("Unknown value for 'whence'");
- }
- if (newpos < context->hidden.mem.base) {
- newpos = context->hidden.mem.base;
- }
- if (newpos > context->hidden.mem.stop) {
- newpos = context->hidden.mem.stop;
- }
- context->hidden.mem.here = newpos;
- return (Sint64)(context->hidden.mem.here - context->hidden.mem.base);
-}
-
-static size_t SDLCALL
-mem_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
-{
- size_t total_bytes;
- size_t mem_available;
-
- total_bytes = (maxnum * size);
- if ((maxnum <= 0) || (size <= 0)
- || ((total_bytes / maxnum) != (size_t) size)) {
- return 0;
- }
-
- mem_available = (context->hidden.mem.stop - context->hidden.mem.here);
- if (total_bytes > mem_available) {
- total_bytes = mem_available;
- }
-
- SDL_memcpy(ptr, context->hidden.mem.here, total_bytes);
- context->hidden.mem.here += total_bytes;
-
- return (total_bytes / size);
-}
-
-static size_t SDLCALL
-mem_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
-{
- if ((context->hidden.mem.here + (num * size)) > context->hidden.mem.stop) {
- num = (context->hidden.mem.stop - context->hidden.mem.here) / size;
- }
- SDL_memcpy(context->hidden.mem.here, ptr, num * size);
- context->hidden.mem.here += num * size;
- return (num);
-}
-
-static size_t SDLCALL
-mem_writeconst(SDL_RWops * context, const void *ptr, size_t size, size_t num)
-{
- SDL_SetError("Can't write to read-only memory");
- return (0);
-}
-
-static int SDLCALL
-mem_close(SDL_RWops * context)
-{
- if (context) {
- SDL_FreeRW(context);
- }
- return (0);
-}
-
-
-/* Functions to create SDL_RWops structures from various data sources */
-
-SDL_RWops *
-SDL_RWFromFile(const char *file, const char *mode)
-{
- SDL_RWops *rwops = NULL;
- if (!file || !*file || !mode || !*mode) {
- SDL_SetError("SDL_RWFromFile(): No file or no mode specified");
- return NULL;
- }
-#if defined(ANDROID)
-#ifdef HAVE_STDIO_H
- /* Try to open the file on the filesystem first */
- if (*file == '/') {
- FILE *fp = fopen(file, mode);
- if (fp) {
- return SDL_RWFromFP(fp, 1);
- }
- } else {
- /* Try opening it from internal storage if it's a relative path */
- char *path;
- FILE *fp;
-
- path = SDL_stack_alloc(char, PATH_MAX);
- if (path) {
- SDL_snprintf(path, PATH_MAX, "%s/%s",
- SDL_AndroidGetInternalStoragePath(), file);
- fp = fopen(path, mode);
- SDL_stack_free(path);
- if (fp) {
- return SDL_RWFromFP(fp, 1);
- }
- }
- }
-#endif /* HAVE_STDIO_H */
-
- /* Try to open the file from the asset system */
- rwops = SDL_AllocRW();
- if (!rwops)
- return NULL; /* SDL_SetError already setup by SDL_AllocRW() */
- if (Android_JNI_FileOpen(rwops, file, mode) < 0) {
- SDL_FreeRW(rwops);
- return NULL;
- }
- rwops->size = Android_JNI_FileSize;
- rwops->seek = Android_JNI_FileSeek;
- rwops->read = Android_JNI_FileRead;
- rwops->write = Android_JNI_FileWrite;
- rwops->close = Android_JNI_FileClose;
- rwops->type = SDL_RWOPS_JNIFILE;
-
-#elif defined(__WIN32__)
- rwops = SDL_AllocRW();
- if (!rwops)
- return NULL; /* SDL_SetError already setup by SDL_AllocRW() */
- if (windows_file_open(rwops, file, mode) < 0) {
- SDL_FreeRW(rwops);
- return NULL;
- }
- rwops->size = windows_file_size;
- rwops->seek = windows_file_seek;
- rwops->read = windows_file_read;
- rwops->write = windows_file_write;
- rwops->close = windows_file_close;
- rwops->type = SDL_RWOPS_WINFILE;
-
-#elif HAVE_STDIO_H
- {
- #ifdef __APPLE__
- FILE *fp = SDL_OpenFPFromBundleOrFallback(file, mode);
- #else
- FILE *fp = fopen(file, mode);
- #endif
- if (fp == NULL) {
- SDL_SetError("Couldn't open %s", file);
- } else {
- rwops = SDL_RWFromFP(fp, 1);
- }
- }
-#else
- SDL_SetError("SDL not compiled with stdio support");
-#endif /* !HAVE_STDIO_H */
-
- return (rwops);
-}
-
-#ifdef HAVE_STDIO_H
-SDL_RWops *
-SDL_RWFromFP(FILE * fp, SDL_bool autoclose)
-{
- SDL_RWops *rwops = NULL;
-
- rwops = SDL_AllocRW();
- if (rwops != NULL) {
- rwops->size = stdio_size;
- rwops->seek = stdio_seek;
- rwops->read = stdio_read;
- rwops->write = stdio_write;
- rwops->close = stdio_close;
- rwops->hidden.stdio.fp = fp;
- rwops->hidden.stdio.autoclose = autoclose;
- rwops->type = SDL_RWOPS_STDFILE;
- }
- return (rwops);
-}
-#else
-SDL_RWops *
-SDL_RWFromFP(void * fp, SDL_bool autoclose)
-{
- SDL_SetError("SDL not compiled with stdio support");
- return NULL;
-}
-#endif /* HAVE_STDIO_H */
-
-SDL_RWops *
-SDL_RWFromMem(void *mem, int size)
-{
- SDL_RWops *rwops = NULL;
- if (!mem) {
- SDL_InvalidParamError("mem");
- return (rwops);
- }
- if (!size) {
- SDL_InvalidParamError("size");
- return (rwops);
- }
-
- rwops = SDL_AllocRW();
- if (rwops != NULL) {
- rwops->size = mem_size;
- rwops->seek = mem_seek;
- rwops->read = mem_read;
- rwops->write = mem_write;
- rwops->close = mem_close;
- rwops->hidden.mem.base = (Uint8 *) mem;
- rwops->hidden.mem.here = rwops->hidden.mem.base;
- rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
- rwops->type = SDL_RWOPS_MEMORY;
- }
- return (rwops);
-}
-
-SDL_RWops *
-SDL_RWFromConstMem(const void *mem, int size)
-{
- SDL_RWops *rwops = NULL;
- if (!mem) {
- SDL_InvalidParamError("mem");
- return (rwops);
- }
- if (!size) {
- SDL_InvalidParamError("size");
- return (rwops);
- }
-
- rwops = SDL_AllocRW();
- if (rwops != NULL) {
- rwops->size = mem_size;
- rwops->seek = mem_seek;
- rwops->read = mem_read;
- rwops->write = mem_writeconst;
- rwops->close = mem_close;
- rwops->hidden.mem.base = (Uint8 *) mem;
- rwops->hidden.mem.here = rwops->hidden.mem.base;
- rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
- rwops->type = SDL_RWOPS_MEMORY_RO;
- }
- return (rwops);
-}
-
-SDL_RWops *
-SDL_AllocRW(void)
-{
- SDL_RWops *area;
-
- area = (SDL_RWops *) SDL_malloc(sizeof *area);
- if (area == NULL) {
- SDL_OutOfMemory();
- } else {
- area->type = SDL_RWOPS_UNKNOWN;
- }
- return (area);
-}
-
-void
-SDL_FreeRW(SDL_RWops * area)
-{
- SDL_free(area);
-}
-
-/* Functions for dynamically reading and writing endian-specific values */
-
-Uint8
-SDL_ReadU8(SDL_RWops * src)
-{
- Uint8 value = 0;
-
- SDL_RWread(src, &value, (sizeof value), 1);
- return value;
-}
-
-Uint16
-SDL_ReadLE16(SDL_RWops * src)
-{
- Uint16 value = 0;
-
- SDL_RWread(src, &value, (sizeof value), 1);
- return (SDL_SwapLE16(value));
-}
-
-Uint16
-SDL_ReadBE16(SDL_RWops * src)
-{
- Uint16 value = 0;
-
- SDL_RWread(src, &value, (sizeof value), 1);
- return (SDL_SwapBE16(value));
-}
-
-Uint32
-SDL_ReadLE32(SDL_RWops * src)
-{
- Uint32 value = 0;
-
- SDL_RWread(src, &value, (sizeof value), 1);
- return (SDL_SwapLE32(value));
-}
-
-Uint32
-SDL_ReadBE32(SDL_RWops * src)
-{
- Uint32 value = 0;
-
- SDL_RWread(src, &value, (sizeof value), 1);
- return (SDL_SwapBE32(value));
-}
-
-Uint64
-SDL_ReadLE64(SDL_RWops * src)
-{
- Uint64 value = 0;
-
- SDL_RWread(src, &value, (sizeof value), 1);
- return (SDL_SwapLE64(value));
-}
-
-Uint64
-SDL_ReadBE64(SDL_RWops * src)
-{
- Uint64 value = 0;
-
- SDL_RWread(src, &value, (sizeof value), 1);
- return (SDL_SwapBE64(value));
-}
-
-size_t
-SDL_WriteU8(SDL_RWops * dst, Uint8 value)
-{
- return (SDL_RWwrite(dst, &value, (sizeof value), 1));
-}
-
-size_t
-SDL_WriteLE16(SDL_RWops * dst, Uint16 value)
-{
- value = SDL_SwapLE16(value);
- return (SDL_RWwrite(dst, &value, (sizeof value), 1));
-}
-
-size_t
-SDL_WriteBE16(SDL_RWops * dst, Uint16 value)
-{
- value = SDL_SwapBE16(value);
- return (SDL_RWwrite(dst, &value, (sizeof value), 1));
-}
-
-size_t
-SDL_WriteLE32(SDL_RWops * dst, Uint32 value)
-{
- value = SDL_SwapLE32(value);
- return (SDL_RWwrite(dst, &value, (sizeof value), 1));
-}
-
-size_t
-SDL_WriteBE32(SDL_RWops * dst, Uint32 value)
-{
- value = SDL_SwapBE32(value);
- return (SDL_RWwrite(dst, &value, (sizeof value), 1));
-}
-
-size_t
-SDL_WriteLE64(SDL_RWops * dst, Uint64 value)
-{
- value = SDL_SwapLE64(value);
- return (SDL_RWwrite(dst, &value, (sizeof value), 1));
-}
-
-size_t
-SDL_WriteBE64(SDL_RWops * dst, Uint64 value)
-{
- value = SDL_SwapBE64(value);
- return (SDL_RWwrite(dst, &value, (sizeof value), 1));
-}
-
-/* vi: set ts=4 sw=4 expandtab: */
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2013 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.
+*/
+/* Need this so Linux systems define fseek64o, ftell64o and off64_t */
+#define _LARGEFILE64_SOURCE
+#include "SDL_config.h"
+
+/* This file provides a general interface for SDL to read and write
+ data sources. It can easily be extended to files, memory, etc.
+*/
+
+#include "SDL_endian.h"
+#include "SDL_rwops.h"
+
+#ifdef __APPLE__
+#include "cocoa/SDL_rwopsbundlesupport.h"
+#endif /* __APPLE__ */
+
+#ifdef ANDROID
+#include "../core/android/SDL_android.h"
+#include "SDL_system.h"
+#endif
+
+#ifdef __WIN32__
+
+/* Functions to read/write Win32 API file pointers */
+
+#include "../core/windows/SDL_windows.h"
+
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER 0xFFFFFFFF
+#endif
+
+#define READAHEAD_BUFFER_SIZE 1024
+
+static int SDLCALL
+windows_file_open(SDL_RWops * context, const char *filename, const char *mode)
+{
+ UINT old_error_mode;
+ HANDLE h;
+ DWORD r_right, w_right;
+ DWORD must_exist, truncate;
+ int a_mode;
+
+ if (!context)
+ return -1; /* failed (invalid call) */
+
+ context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* mark this as unusable */
+ context->hidden.windowsio.buffer.data = NULL;
+ context->hidden.windowsio.buffer.size = 0;
+ context->hidden.windowsio.buffer.left = 0;
+
+ /* "r" = reading, file must exist */
+ /* "w" = writing, truncate existing, file may not exist */
+ /* "r+"= reading or writing, file must exist */
+ /* "a" = writing, append file may not exist */
+ /* "a+"= append + read, file may not exist */
+ /* "w+" = read, write, truncate. file may not exist */
+
+ must_exist = (SDL_strchr(mode, 'r') != NULL) ? OPEN_EXISTING : 0;
+ truncate = (SDL_strchr(mode, 'w') != NULL) ? CREATE_ALWAYS : 0;
+ r_right = (SDL_strchr(mode, '+') != NULL
+ || must_exist) ? GENERIC_READ : 0;
+ a_mode = (SDL_strchr(mode, 'a') != NULL) ? OPEN_ALWAYS : 0;
+ w_right = (a_mode || SDL_strchr(mode, '+')
+ || truncate) ? GENERIC_WRITE : 0;
+
+ if (!r_right && !w_right) /* inconsistent mode */
+ return -1; /* failed (invalid call) */
+
+ context->hidden.windowsio.buffer.data =
+ (char *) SDL_malloc(READAHEAD_BUFFER_SIZE);
+ if (!context->hidden.windowsio.buffer.data) {
+ return SDL_OutOfMemory();
+ }
+ /* Do not open a dialog box if failure */
+ old_error_mode =
+ SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS);
+
+ {
+ LPTSTR tstr = WIN_UTF8ToString(filename);
+ h = CreateFile(tstr, (w_right | r_right),
+ (w_right) ? 0 : FILE_SHARE_READ, NULL,
+ (must_exist | truncate | a_mode),
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ SDL_free(tstr);
+ }
+
+ /* restore old behavior */
+ SetErrorMode(old_error_mode);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ SDL_free(context->hidden.windowsio.buffer.data);
+ context->hidden.windowsio.buffer.data = NULL;
+ SDL_SetError("Couldn't open %s", filename);
+ return -2; /* failed (CreateFile) */
+ }
+ context->hidden.windowsio.h = h;
+ context->hidden.windowsio.append = a_mode ? SDL_TRUE : SDL_FALSE;
+
+ return 0; /* ok */
+}
+
+static Sint64 SDLCALL
+windows_file_size(SDL_RWops * context)
+{
+ LARGE_INTEGER size;
+
+ if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
+ return SDL_SetError("windows_file_size: invalid context/file not opened");
+ }
+
+ if (!GetFileSizeEx(context->hidden.windowsio.h, &size)) {
+ return WIN_SetError("windows_file_size");
+ }
+
+ return size.QuadPart;
+}
+
+static Sint64 SDLCALL
+windows_file_seek(SDL_RWops * context, Sint64 offset, int whence)
+{
+ DWORD windowswhence;
+ LARGE_INTEGER windowsoffset;
+
+ if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE) {
+ return SDL_SetError("windows_file_seek: invalid context/file not opened");
+ }
+
+ /* FIXME: We may be able to satisfy the seek within buffered data */
+ if (whence == RW_SEEK_CUR && context->hidden.windowsio.buffer.left) {
+ offset -= (long)context->hidden.windowsio.buffer.left;
+ }
+ context->hidden.windowsio.buffer.left = 0;
+
+ switch (whence) {
+ case RW_SEEK_SET:
+ windowswhence = FILE_BEGIN;
+ break;
+ case RW_SEEK_CUR:
+ windowswhence = FILE_CURRENT;
+ break;
+ case RW_SEEK_END:
+ windowswhence = FILE_END;
+ break;
+ default:
+ return SDL_SetError("windows_file_seek: Unknown value for 'whence'");
+ }
+
+ windowsoffset.QuadPart = offset;
+ if (!SetFilePointerEx(context->hidden.windowsio.h, windowsoffset, &windowsoffset, windowswhence)) {
+ return WIN_SetError("windows_file_seek");
+ }
+ return windowsoffset.QuadPart;
+}
+
+static size_t SDLCALL
+windows_file_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
+{
+ size_t total_need;
+ size_t total_read = 0;
+ size_t read_ahead;
+ DWORD byte_read;
+
+ total_need = size * maxnum;
+
+ if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
+ || !total_need)
+ return 0;
+
+ if (context->hidden.windowsio.buffer.left > 0) {
+ void *data = (char *) context->hidden.windowsio.buffer.data +
+ context->hidden.windowsio.buffer.size -
+ context->hidden.windowsio.buffer.left;
+ read_ahead =
+ SDL_min(total_need, context->hidden.windowsio.buffer.left);
+ SDL_memcpy(ptr, data, read_ahead);
+ context->hidden.windowsio.buffer.left -= read_ahead;
+
+ if (read_ahead == total_need) {
+ return maxnum;
+ }
+ ptr = (char *) ptr + read_ahead;
+ total_need -= read_ahead;
+ total_read += read_ahead;
+ }
+
+ if (total_need < READAHEAD_BUFFER_SIZE) {
+ if (!ReadFile
+ (context->hidden.windowsio.h, context->hidden.windowsio.buffer.data,
+ READAHEAD_BUFFER_SIZE, &byte_read, NULL)) {
+ SDL_Error(SDL_EFREAD);
+ return 0;
+ }
+ read_ahead = SDL_min(total_need, (int) byte_read);
+ SDL_memcpy(ptr, context->hidden.windowsio.buffer.data, read_ahead);
+ context->hidden.windowsio.buffer.size = byte_read;
+ context->hidden.windowsio.buffer.left = byte_read - read_ahead;
+ total_read += read_ahead;
+ } else {
+ if (!ReadFile
+ (context->hidden.windowsio.h, ptr, (DWORD)total_need, &byte_read, NULL)) {
+ SDL_Error(SDL_EFREAD);
+ return 0;
+ }
+ total_read += byte_read;
+ }
+ return (total_read / size);
+}
+
+static size_t SDLCALL
+windows_file_write(SDL_RWops * context, const void *ptr, size_t size,
+ size_t num)
+{
+
+ size_t total_bytes;
+ DWORD byte_written;
+ size_t nwritten;
+
+ total_bytes = size * num;
+
+ if (!context || context->hidden.windowsio.h == INVALID_HANDLE_VALUE
+ || total_bytes <= 0 || !size)
+ return 0;
+
+ if (context->hidden.windowsio.buffer.left) {
+ SetFilePointer(context->hidden.windowsio.h,
+ -(LONG)context->hidden.windowsio.buffer.left, NULL,
+ FILE_CURRENT);
+ context->hidden.windowsio.buffer.left = 0;
+ }
+
+ /* if in append mode, we must go to the EOF before write */
+ if (context->hidden.windowsio.append) {
+ if (SetFilePointer(context->hidden.windowsio.h, 0L, NULL, FILE_END) ==
+ INVALID_SET_FILE_POINTER) {
+ SDL_Error(SDL_EFWRITE);
+ return 0;
+ }
+ }
+
+ if (!WriteFile
+ (context->hidden.windowsio.h, ptr, (DWORD)total_bytes, &byte_written, NULL)) {
+ SDL_Error(SDL_EFWRITE);
+ return 0;
+ }
+
+ nwritten = byte_written / size;
+ return nwritten;
+}
+
+static int SDLCALL
+windows_file_close(SDL_RWops * context)
+{
+
+ if (context) {
+ if (context->hidden.windowsio.h != INVALID_HANDLE_VALUE) {
+ CloseHandle(context->hidden.windowsio.h);
+ context->hidden.windowsio.h = INVALID_HANDLE_VALUE; /* to be sure */
+ }
+ if (context->hidden.windowsio.buffer.data) {
+ SDL_free(context->hidden.windowsio.buffer.data);
+ context->hidden.windowsio.buffer.data = NULL;
+ }
+ SDL_FreeRW(context);
+ }
+ return (0);
+}
+#endif /* __WIN32__ */
+
+#ifdef HAVE_STDIO_H
+
+/* Functions to read/write stdio file pointers */
+
+static Sint64 SDLCALL
+stdio_size(SDL_RWops * context)
+{
+ Sint64 pos, size;
+
+ pos = SDL_RWseek(context, 0, RW_SEEK_CUR);
+ if (pos < 0) {
+ return -1;
+ }
+ size = SDL_RWseek(context, 0, RW_SEEK_END);
+
+ SDL_RWseek(context, pos, RW_SEEK_SET);
+ return size;
+}
+
+static Sint64 SDLCALL
+stdio_seek(SDL_RWops * context, Sint64 offset, int whence)
+{
+#ifdef HAVE_FSEEKO64
+ if (fseeko64(context->hidden.stdio.fp, (off64_t)offset, whence) == 0) {
+ return ftello64(context->hidden.stdio.fp);
+ }
+#elif defined(HAVE_FSEEKO)
+ if (fseeko(context->hidden.stdio.fp, (off_t)offset, whence) == 0) {
+ return ftello(context->hidden.stdio.fp);
+ }
+#elif defined(HAVE__FSEEKI64)
+ if (_fseeki64(context->hidden.stdio.fp, offset, whence) == 0) {
+ return _ftelli64(context->hidden.stdio.fp);
+ }
+#else
+ if (fseek(context->hidden.stdio.fp, offset, whence) == 0) {
+ return (ftell(context->hidden.stdio.fp));
+ }
+#endif
+ return SDL_Error(SDL_EFSEEK);
+}
+
+static size_t SDLCALL
+stdio_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
+{
+ size_t nread;
+
+ nread = fread(ptr, size, maxnum, context->hidden.stdio.fp);
+ if (nread == 0 && ferror(context->hidden.stdio.fp)) {
+ SDL_Error(SDL_EFREAD);
+ }
+ return (nread);
+}
+
+static size_t SDLCALL
+stdio_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
+{
+ size_t nwrote;
+
+ nwrote = fwrite(ptr, size, num, context->hidden.stdio.fp);
+ if (nwrote == 0 && ferror(context->hidden.stdio.fp)) {
+ SDL_Error(SDL_EFWRITE);
+ }
+ return (nwrote);
+}
+
+static int SDLCALL
+stdio_close(SDL_RWops * context)
+{
+ int status = 0;
+ if (context) {
+ if (context->hidden.stdio.autoclose) {
+ /* WARNING: Check the return value here! */
+ if (fclose(context->hidden.stdio.fp) != 0) {
+ status = SDL_Error(SDL_EFWRITE);
+ }
+ }
+ SDL_FreeRW(context);
+ }
+ return status;
+}
+#endif /* !HAVE_STDIO_H */
+
+/* Functions to read/write memory pointers */
+
+static Sint64 SDLCALL
+mem_size(SDL_RWops * context)
+{
+ return (Sint64)(context->hidden.mem.stop - context->hidden.mem.base);
+}
+
+static Sint64 SDLCALL
+mem_seek(SDL_RWops * context, Sint64 offset, int whence)
+{
+ Uint8 *newpos;
+
+ switch (whence) {
+ case RW_SEEK_SET:
+ newpos = context->hidden.mem.base + offset;
+ break;
+ case RW_SEEK_CUR:
+ newpos = context->hidden.mem.here + offset;
+ break;
+ case RW_SEEK_END:
+ newpos = context->hidden.mem.stop + offset;
+ break;
+ default:
+ return SDL_SetError("Unknown value for 'whence'");
+ }
+ if (newpos < context->hidden.mem.base) {
+ newpos = context->hidden.mem.base;
+ }
+ if (newpos > context->hidden.mem.stop) {
+ newpos = context->hidden.mem.stop;
+ }
+ context->hidden.mem.here = newpos;
+ return (Sint64)(context->hidden.mem.here - context->hidden.mem.base);
+}
+
+static size_t SDLCALL
+mem_read(SDL_RWops * context, void *ptr, size_t size, size_t maxnum)
+{
+ size_t total_bytes;
+ size_t mem_available;
+
+ total_bytes = (maxnum * size);
+ if ((maxnum <= 0) || (size <= 0)
+ || ((total_bytes / maxnum) != (size_t) size)) {
+ return 0;
+ }
+
+ mem_available = (context->hidden.mem.stop - context->hidden.mem.here);
+ if (total_bytes > mem_available) {
+ total_bytes = mem_available;
+ }
+
+ SDL_memcpy(ptr, context->hidden.mem.here, total_bytes);
+ context->hidden.mem.here += total_bytes;
+
+ return (total_bytes / size);
+}
+
+static size_t SDLCALL
+mem_write(SDL_RWops * context, const void *ptr, size_t size, size_t num)
+{
+ if ((context->hidden.mem.here + (num * size)) > context->hidden.mem.stop) {
+ num = (context->hidden.mem.stop - context->hidden.mem.here) / size;
+ }
+ SDL_memcpy(context->hidden.mem.here, ptr, num * size);
+ context->hidden.mem.here += num * size;
+ return (num);
+}
+
+static size_t SDLCALL
+mem_writeconst(SDL_RWops * context, const void *ptr, size_t size, size_t num)
+{
+ SDL_SetError("Can't write to read-only memory");
+ return (0);
+}
+
+static int SDLCALL
+mem_close(SDL_RWops * context)
+{
+ if (context) {
+ SDL_FreeRW(context);
+ }
+ return (0);
+}
+
+
+/* Functions to create SDL_RWops structures from various data sources */
+
+SDL_RWops *
+SDL_RWFromFile(const char *file, const char *mode)
+{
+ SDL_RWops *rwops = NULL;
+ if (!file || !*file || !mode || !*mode) {
+ SDL_SetError("SDL_RWFromFile(): No file or no mode specified");
+ return NULL;
+ }
+#if defined(ANDROID)
+#ifdef HAVE_STDIO_H
+ /* Try to open the file on the filesystem first */
+ if (*file == '/') {
+ FILE *fp = fopen(file, mode);
+ if (fp) {
+ return SDL_RWFromFP(fp, 1);
+ }
+ } else {
+ /* Try opening it from internal storage if it's a relative path */
+ char *path;
+ FILE *fp;
+
+ path = SDL_stack_alloc(char, PATH_MAX);
+ if (path) {
+ SDL_snprintf(path, PATH_MAX, "%s/%s",
+ SDL_AndroidGetInternalStoragePath(), file);
+ fp = fopen(path, mode);
+ SDL_stack_free(path);
+ if (fp) {
+ return SDL_RWFromFP(fp, 1);
+ }
+ }
+ }
+#endif /* HAVE_STDIO_H */
+
+ /* Try to open the file from the asset system */
+ rwops = SDL_AllocRW();
+ if (!rwops)
+ return NULL; /* SDL_SetError already setup by SDL_AllocRW() */
+ if (Android_JNI_FileOpen(rwops, file, mode) < 0) {
+ SDL_FreeRW(rwops);
+ return NULL;
+ }
+ rwops->size = Android_JNI_FileSize;
+ rwops->seek = Android_JNI_FileSeek;
+ rwops->read = Android_JNI_FileRead;
+ rwops->write = Android_JNI_FileWrite;
+ rwops->close = Android_JNI_FileClose;
+ rwops->type = SDL_RWOPS_JNIFILE;
+
+#elif defined(__WIN32__)
+ rwops = SDL_AllocRW();
+ if (!rwops)
+ return NULL; /* SDL_SetError already setup by SDL_AllocRW() */
+ if (windows_file_open(rwops, file, mode) < 0) {
+ SDL_FreeRW(rwops);
+ return NULL;
+ }
+ rwops->size = windows_file_size;
+ rwops->seek = windows_file_seek;
+ rwops->read = windows_file_read;
+ rwops->write = windows_file_write;
+ rwops->close = windows_file_close;
+ rwops->type = SDL_RWOPS_WINFILE;
+
+#elif HAVE_STDIO_H
+ {
+ #ifdef __APPLE__
+ FILE *fp = SDL_OpenFPFromBundleOrFallback(file, mode);
+ #elif __WINRT__
+ FILE *fp = NULL;
+ fopen_s(&fp, file, mode);
+ #else
+ FILE *fp = fopen(file, mode);
+ #endif
+ if (fp == NULL) {
+ SDL_SetError("Couldn't open %s", file);
+ } else {
+ rwops = SDL_RWFromFP(fp, 1);
+ }
+ }
+#else
+ SDL_SetError("SDL not compiled with stdio support");
+#endif /* !HAVE_STDIO_H */
+
+ return (rwops);
+}
+
+#ifdef HAVE_STDIO_H
+SDL_RWops *
+SDL_RWFromFP(FILE * fp, SDL_bool autoclose)
+{
+ SDL_RWops *rwops = NULL;
+
+ rwops = SDL_AllocRW();
+ if (rwops != NULL) {
+ rwops->size = stdio_size;
+ rwops->seek = stdio_seek;
+ rwops->read = stdio_read;
+ rwops->write = stdio_write;
+ rwops->close = stdio_close;
+ rwops->hidden.stdio.fp = fp;
+ rwops->hidden.stdio.autoclose = autoclose;
+ rwops->type = SDL_RWOPS_STDFILE;
+ }
+ return (rwops);
+}
+#else
+SDL_RWops *
+SDL_RWFromFP(void * fp, SDL_bool autoclose)
+{
+ SDL_SetError("SDL not compiled with stdio support");
+ return NULL;
+}
+#endif /* HAVE_STDIO_H */
+
+SDL_RWops *
+SDL_RWFromMem(void *mem, int size)
+{
+ SDL_RWops *rwops = NULL;
+ if (!mem) {
+ SDL_InvalidParamError("mem");
+ return (rwops);
+ }
+ if (!size) {
+ SDL_InvalidParamError("size");
+ return (rwops);
+ }
+
+ rwops = SDL_AllocRW();
+ if (rwops != NULL) {
+ rwops->size = mem_size;
+ rwops->seek = mem_seek;
+ rwops->read = mem_read;
+ rwops->write = mem_write;
+ rwops->close = mem_close;
+ rwops->hidden.mem.base = (Uint8 *) mem;
+ rwops->hidden.mem.here = rwops->hidden.mem.base;
+ rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
+ rwops->type = SDL_RWOPS_MEMORY;
+ }
+ return (rwops);
+}
+
+SDL_RWops *
+SDL_RWFromConstMem(const void *mem, int size)
+{
+ SDL_RWops *rwops = NULL;
+ if (!mem) {
+ SDL_InvalidParamError("mem");
+ return (rwops);
+ }
+ if (!size) {
+ SDL_InvalidParamError("size");
+ return (rwops);
+ }
+
+ rwops = SDL_AllocRW();
+ if (rwops != NULL) {
+ rwops->size = mem_size;
+ rwops->seek = mem_seek;
+ rwops->read = mem_read;
+ rwops->write = mem_writeconst;
+ rwops->close = mem_close;
+ rwops->hidden.mem.base = (Uint8 *) mem;
+ rwops->hidden.mem.here = rwops->hidden.mem.base;
+ rwops->hidden.mem.stop = rwops->hidden.mem.base + size;
+ rwops->type = SDL_RWOPS_MEMORY_RO;
+ }
+ return (rwops);
+}
+
+SDL_RWops *
+SDL_AllocRW(void)
+{
+ SDL_RWops *area;
+
+ area = (SDL_RWops *) SDL_malloc(sizeof *area);
+ if (area == NULL) {
+ SDL_OutOfMemory();
+ } else {
+ area->type = SDL_RWOPS_UNKNOWN;
+ }
+ return (area);
+}
+
+void
+SDL_FreeRW(SDL_RWops * area)
+{
+ SDL_free(area);
+}
+
+/* Functions for dynamically reading and writing endian-specific values */
+
+Uint8
+SDL_ReadU8(SDL_RWops * src)
+{
+ Uint8 value = 0;
+
+ SDL_RWread(src, &value, (sizeof value), 1);
+ return value;
+}
+
+Uint16
+SDL_ReadLE16(SDL_RWops * src)
+{
+ Uint16 value = 0;
+
+ SDL_RWread(src, &value, (sizeof value), 1);
+ return (SDL_SwapLE16(value));
+}
+
+Uint16
+SDL_ReadBE16(SDL_RWops * src)
+{
+ Uint16 value = 0;
+
+ SDL_RWread(src, &value, (sizeof value), 1);
+ return (SDL_SwapBE16(value));
+}
+
+Uint32
+SDL_ReadLE32(SDL_RWops * src)
+{
+ Uint32 value = 0;
+
+ SDL_RWread(src, &value, (sizeof value), 1);
+ return (SDL_SwapLE32(value));
+}
+
+Uint32
+SDL_ReadBE32(SDL_RWops * src)
+{
+ Uint32 value = 0;
+
+ SDL_RWread(src, &value, (sizeof value), 1);
+ return (SDL_SwapBE32(value));
+}
+
+Uint64
+SDL_ReadLE64(SDL_RWops * src)
+{
+ Uint64 value = 0;
+
+ SDL_RWread(src, &value, (sizeof value), 1);
+ return (SDL_SwapLE64(value));
+}
+
+Uint64
+SDL_ReadBE64(SDL_RWops * src)
+{
+ Uint64 value = 0;
+
+ SDL_RWread(src, &value, (sizeof value), 1);
+ return (SDL_SwapBE64(value));
+}
+
+size_t
+SDL_WriteU8(SDL_RWops * dst, Uint8 value)
+{
+ return (SDL_RWwrite(dst, &value, (sizeof value), 1));
+}
+
+size_t
+SDL_WriteLE16(SDL_RWops * dst, Uint16 value)
+{
+ value = SDL_SwapLE16(value);
+ return (SDL_RWwrite(dst, &value, (sizeof value), 1));
+}
+
+size_t
+SDL_WriteBE16(SDL_RWops * dst, Uint16 value)
+{
+ value = SDL_SwapBE16(value);
+ return (SDL_RWwrite(dst, &value, (sizeof value), 1));
+}
+
+size_t
+SDL_WriteLE32(SDL_RWops * dst, Uint32 value)
+{
+ value = SDL_SwapLE32(value);
+ return (SDL_RWwrite(dst, &value, (sizeof value), 1));
+}
+
+size_t
+SDL_WriteBE32(SDL_RWops * dst, Uint32 value)
+{
+ value = SDL_SwapBE32(value);
+ return (SDL_RWwrite(dst, &value, (sizeof value), 1));
+}
+
+size_t
+SDL_WriteLE64(SDL_RWops * dst, Uint64 value)
+{
+ value = SDL_SwapLE64(value);
+ return (SDL_RWwrite(dst, &value, (sizeof value), 1));
+}
+
+size_t
+SDL_WriteBE64(SDL_RWops * dst, Uint64 value)
+{
+ value = SDL_SwapBE64(value);
+ return (SDL_RWwrite(dst, &value, (sizeof value), 1));
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c
index 912be0524..414e59135 100644
--- a/src/joystick/SDL_gamecontroller.c
+++ b/src/joystick/SDL_gamecontroller.c
@@ -1,1249 +1,1249 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2013 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"
-
-/* This is the game controller API for Simple DirectMedia Layer */
-
-#include "SDL_events.h"
-#include "SDL_assert.h"
-#include "SDL_sysjoystick.h"
-#include "SDL_hints.h"
-#include "SDL_gamecontrollerdb.h"
-
-#if !SDL_EVENTS_DISABLED
-#include "../events/SDL_events_c.h"
-#endif
-#define ABS(_x) ((_x) < 0 ? -(_x) : (_x))
-
-
-/* a list of currently opened game controllers */
-static SDL_GameController *SDL_gamecontrollers = NULL;
-
-/* keep track of the hat and mask value that transforms this hat movement into a button/axis press */
-struct _SDL_HatMapping
-{
- int hat;
- Uint8 mask;
-};
-
-#define k_nMaxReverseEntries 20
-
-/**
- * We are encoding the "HAT" as 0xhm. where h == hat ID and m == mask
- * MAX 4 hats supported
- */
-#define k_nMaxHatEntries 0x3f + 1
-
-/* our in memory mapping db between joystick objects and controller mappings*/
-struct _SDL_ControllerMapping
-{
- SDL_JoystickGUID guid;
- const char *name;
-
- /* mapping of axis/button id to controller version */
- int axes[SDL_CONTROLLER_AXIS_MAX];
- int buttonasaxis[SDL_CONTROLLER_AXIS_MAX];
-
- int buttons[SDL_CONTROLLER_BUTTON_MAX];
- int axesasbutton[SDL_CONTROLLER_BUTTON_MAX];
- struct _SDL_HatMapping hatasbutton[SDL_CONTROLLER_BUTTON_MAX];
-
- /* reverse mapping, joystick indices to buttons */
- SDL_GameControllerAxis raxes[k_nMaxReverseEntries];
- SDL_GameControllerAxis rbuttonasaxis[k_nMaxReverseEntries];
-
- SDL_GameControllerButton rbuttons[k_nMaxReverseEntries];
- SDL_GameControllerButton raxesasbutton[k_nMaxReverseEntries];
- SDL_GameControllerButton rhatasbutton[k_nMaxHatEntries];
-
-};
-
-
-/* our hard coded list of mapping support */
-typedef struct _ControllerMapping_t
-{
- SDL_JoystickGUID guid;
- char *name;
- char *mapping;
- struct _ControllerMapping_t *next;
-} ControllerMapping_t;
-
-static ControllerMapping_t *s_pSupportedControllers = NULL;
-#ifdef SDL_JOYSTICK_DINPUT
-static ControllerMapping_t *s_pXInputMapping = NULL;
-#endif
-
-/* The SDL game controller structure */
-struct _SDL_GameController
-{
- SDL_Joystick *joystick; /* underlying joystick device */
- int ref_count;
- Uint8 hatState[4]; /* the current hat state for this controller */
- struct _SDL_ControllerMapping mapping; /* the mapping object for this controller */
- struct _SDL_GameController *next; /* pointer to next game controller we have allocated */
-};
-
-
-int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value);
-int SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state);
-
-/*
- * Event filter to fire controller events from joystick ones
- */
-int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event)
-{
- switch( event->type )
- {
- case SDL_JOYAXISMOTION:
- {
- SDL_GameController *controllerlist;
-
- if ( event->jaxis.axis >= k_nMaxReverseEntries ) break;
-
- controllerlist = SDL_gamecontrollers;
- while ( controllerlist )
- {
- if ( controllerlist->joystick->instance_id == event->jaxis.which )
- {
- if ( controllerlist->mapping.raxes[event->jaxis.axis] >= 0 ) /* simple axis to axis, send it through */
- {
- SDL_GameControllerAxis axis = controllerlist->mapping.raxes[event->jaxis.axis];
- Sint16 value = event->jaxis.value;
- switch (axis)
- {
- case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
- case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
- /* Shift it to be 0 - 32767. */
- value = value / 2 + 16384;
- default:
- break;
- }
- SDL_PrivateGameControllerAxis( controllerlist, axis, value );
- }
- else if ( controllerlist->mapping.raxesasbutton[event->jaxis.axis] >= 0 ) /* simulate an axis as a button */
- {
- SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.raxesasbutton[event->jaxis.axis], ABS(event->jaxis.value) > 32768/2 ? SDL_PRESSED : SDL_RELEASED );
- }
- break;
- }
- controllerlist = controllerlist->next;
- }
- }
- break;
- case SDL_JOYBUTTONDOWN:
- case SDL_JOYBUTTONUP:
- {
- SDL_GameController *controllerlist;
-
- if ( event->jbutton.button >= k_nMaxReverseEntries ) break;
-
- controllerlist = SDL_gamecontrollers;
- while ( controllerlist )
- {
- if ( controllerlist->joystick->instance_id == event->jbutton.which )
- {
- if ( controllerlist->mapping.rbuttons[event->jbutton.button] >= 0 ) /* simple button as button */
- {
- SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rbuttons[event->jbutton.button], event->jbutton.state );
- }
- else if ( controllerlist->mapping.rbuttonasaxis[event->jbutton.button] >= 0 ) /* an button pretending to be an axis */
- {
- SDL_PrivateGameControllerAxis( controllerlist, controllerlist->mapping.rbuttonasaxis[event->jbutton.button], event->jbutton.state > 0 ? 32767 : 0 );
- }
- break;
- }
- controllerlist = controllerlist->next;
- }
- }
- break;
- case SDL_JOYHATMOTION:
- {
- SDL_GameController *controllerlist;
-
- if ( event->jhat.hat >= 4 ) break;
-
- controllerlist = SDL_gamecontrollers;
- while ( controllerlist )
- {
- if ( controllerlist->joystick->instance_id == event->jhat.which )
- {
- Uint8 bSame = controllerlist->hatState[event->jhat.hat] & event->jhat.value;
- /* Get list of removed bits (button release) */
- Uint8 bChanged = controllerlist->hatState[event->jhat.hat] ^ bSame;
- /* the hat idx in the high nibble */
- int bHighHat = event->jhat.hat << 4;
-
- if ( bChanged & SDL_HAT_DOWN )
- SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_RELEASED );
- if ( bChanged & SDL_HAT_UP )
- SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_RELEASED );
- if ( bChanged & SDL_HAT_LEFT )
- SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_RELEASED );
- if ( bChanged & SDL_HAT_RIGHT )
- SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_RELEASED );
-
- /* Get list of added bits (button press) */
- bChanged = event->jhat.value ^ bSame;
-
- if ( bChanged & SDL_HAT_DOWN )
- SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_PRESSED );
- if ( bChanged & SDL_HAT_UP )
- SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_PRESSED );
- if ( bChanged & SDL_HAT_LEFT )
- SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_PRESSED );
- if ( bChanged & SDL_HAT_RIGHT )
- SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_PRESSED );
-
- /* update our state cache */
- controllerlist->hatState[event->jhat.hat] = event->jhat.value;
-
- break;
- }
- controllerlist = controllerlist->next;
- }
- }
- break;
- case SDL_JOYDEVICEADDED:
- {
- if ( SDL_IsGameController(event->jdevice.which ) )
- {
- SDL_Event deviceevent;
- deviceevent.type = SDL_CONTROLLERDEVICEADDED;
- deviceevent.cdevice.which = event->jdevice.which;
- SDL_PushEvent(&deviceevent);
- }
- }
- break;
- case SDL_JOYDEVICEREMOVED:
- {
- SDL_GameController *controllerlist = SDL_gamecontrollers;
- while ( controllerlist )
- {
- if ( controllerlist->joystick->instance_id == event->jdevice.which )
- {
- SDL_Event deviceevent;
- deviceevent.type = SDL_CONTROLLERDEVICEREMOVED;
- deviceevent.cdevice.which = event->jdevice.which;
- SDL_PushEvent(&deviceevent);
- break;
- }
- controllerlist = controllerlist->next;
- }
- }
- break;
- default:
- break;
- }
-
- return 1;
-}
-
-/*
- * Helper function to scan the mappings database for a controller with the specified GUID
- */
-ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *guid)
-{
- ControllerMapping_t *pSupportedController = s_pSupportedControllers;
- while ( pSupportedController )
- {
- if ( !SDL_memcmp( guid, &pSupportedController->guid, sizeof(*guid) ) )
- {
- return pSupportedController;
- }
- pSupportedController = pSupportedController->next;
- }
- return NULL;
-}
-
-/*
- * Helper function to determine pre-calculated offset to certain joystick mappings
- */
-ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
-{
-#ifdef SDL_JOYSTICK_DINPUT
- if ( SDL_SYS_IsXInputDeviceIndex(device_index) && s_pXInputMapping )
- {
- return s_pXInputMapping;
- }
- else
-#endif
- {
- SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID( device_index );
- return SDL_PrivateGetControllerMappingForGUID(&jGUID);
- }
-
- return NULL;
-}
-
-static const char* map_StringForControllerAxis[] = {
- "leftx",
- "lefty",
- "rightx",
- "righty",
- "lefttrigger",
- "righttrigger",
- NULL
-};
-
-/*
- * convert a string to its enum equivalent
- */
-SDL_GameControllerAxis SDL_GameControllerGetAxisFromString( const char *pchString )
-{
- int entry;
- if ( !pchString || !pchString[0] )
- return SDL_CONTROLLER_AXIS_INVALID;
-
- for ( entry = 0; map_StringForControllerAxis[entry]; ++entry)
- {
- if ( !SDL_strcasecmp( pchString, map_StringForControllerAxis[entry] ) )
- return entry;
- }
- return SDL_CONTROLLER_AXIS_INVALID;
-}
-
-/*
- * convert an enum to its string equivalent
- */
-const char* SDL_GameControllerGetStringForAxis( SDL_GameControllerAxis axis )
-{
- if (axis > SDL_CONTROLLER_AXIS_INVALID && axis < SDL_CONTROLLER_AXIS_MAX)
- {
- return map_StringForControllerAxis[axis];
- }
- return NULL;
-}
-
-static const char* map_StringForControllerButton[] = {
- "a",
- "b",
- "x",
- "y",
- "back",
- "guide",
- "start",
- "leftstick",
- "rightstick",
- "leftshoulder",
- "rightshoulder",
- "dpup",
- "dpdown",
- "dpleft",
- "dpright",
- NULL
-};
-
-/*
- * convert a string to its enum equivalent
- */
-SDL_GameControllerButton SDL_GameControllerGetButtonFromString( const char *pchString )
-{
- int entry;
- if ( !pchString || !pchString[0] )
- return SDL_CONTROLLER_BUTTON_INVALID;
-
- for ( entry = 0; map_StringForControllerButton[entry]; ++entry)
- {
- if ( !SDL_strcasecmp( pchString, map_StringForControllerButton[entry] ) )
- return entry;
- }
- return SDL_CONTROLLER_BUTTON_INVALID;
-}
-
-/*
- * convert an enum to its string equivalent
- */
-const char* SDL_GameControllerGetStringForButton( SDL_GameControllerButton axis )
-{
- if (axis > SDL_CONTROLLER_BUTTON_INVALID && axis < SDL_CONTROLLER_BUTTON_MAX)
- {
- return map_StringForControllerButton[axis];
- }
- return NULL;
-}
-
-/*
- * given a controller button name and a joystick name update our mapping structure with it
- */
-void SDL_PrivateGameControllerParseButton( const char *szGameButton, const char *szJoystickButton, struct _SDL_ControllerMapping *pMapping )
-{
- int iSDLButton = 0;
- SDL_GameControllerButton button;
- SDL_GameControllerAxis axis;
- button = SDL_GameControllerGetButtonFromString( szGameButton );
- axis = SDL_GameControllerGetAxisFromString( szGameButton );
- iSDLButton = SDL_atoi( &szJoystickButton[1] );
-
- if ( szJoystickButton[0] == 'a' )
- {
- if ( iSDLButton >= k_nMaxReverseEntries )
- {
- SDL_SetError("Axis index too large: %d", iSDLButton );
- return;
- }
- if ( axis != SDL_CONTROLLER_AXIS_INVALID )
- {
- pMapping->axes[ axis ] = iSDLButton;
- pMapping->raxes[ iSDLButton ] = axis;
- }
- else if ( button != SDL_CONTROLLER_BUTTON_INVALID )
- {
- pMapping->axesasbutton[ button ] = iSDLButton;
- pMapping->raxesasbutton[ iSDLButton ] = button;
- }
- else
- {
- SDL_assert( !"How did we get here?" );
- }
-
- }
- else if ( szJoystickButton[0] == 'b' )
- {
- if ( iSDLButton >= k_nMaxReverseEntries )
- {
- SDL_SetError("Button index too large: %d", iSDLButton );
- return;
- }
- if ( button != SDL_CONTROLLER_BUTTON_INVALID )
- {
- pMapping->buttons[ button ] = iSDLButton;
- pMapping->rbuttons[ iSDLButton ] = button;
- }
- else if ( axis != SDL_CONTROLLER_AXIS_INVALID )
- {
- pMapping->buttonasaxis[ axis ] = iSDLButton;
- pMapping->rbuttonasaxis[ iSDLButton ] = axis;
- }
- else
- {
- SDL_assert( !"How did we get here?" );
- }
- }
- else if ( szJoystickButton[0] == 'h' )
- {
- int hat = SDL_atoi( &szJoystickButton[1] );
- int mask = SDL_atoi( &szJoystickButton[3] );
- if (hat >= 4) {
- SDL_SetError("Hat index too large: %d", iSDLButton );
- }
-
- if ( button != SDL_CONTROLLER_BUTTON_INVALID )
- {
- int ridx;
- pMapping->hatasbutton[ button ].hat = hat;
- pMapping->hatasbutton[ button ].mask = mask;
- ridx = (hat << 4) | mask;
- pMapping->rhatasbutton[ ridx ] = button;
- }
- else if ( axis != SDL_CONTROLLER_AXIS_INVALID )
- {
- SDL_assert( !"Support hat as axis" );
- }
- else
- {
- SDL_assert( !"How did we get here?" );
- }
- }
-}
-
-
-/*
- * given a controller mapping string update our mapping object
- */
-static void
-SDL_PrivateGameControllerParseControllerConfigString( struct _SDL_ControllerMapping *pMapping, const char *pchString )
-{
- char szGameButton[20];
- char szJoystickButton[20];
- SDL_bool bGameButton = SDL_TRUE;
- int i = 0;
- const char *pchPos = pchString;
-
- SDL_memset( szGameButton, 0x0, sizeof(szGameButton) );
- SDL_memset( szJoystickButton, 0x0, sizeof(szJoystickButton) );
-
- while ( pchPos && *pchPos )
- {
- if ( *pchPos == ':' )
- {
- i = 0;
- bGameButton = SDL_FALSE;
- }
- else if ( *pchPos == ' ' )
- {
-
- }
- else if ( *pchPos == ',' )
- {
- i = 0;
- bGameButton = SDL_TRUE;
- SDL_PrivateGameControllerParseButton( szGameButton, szJoystickButton, pMapping );
- SDL_memset( szGameButton, 0x0, sizeof(szGameButton) );
- SDL_memset( szJoystickButton, 0x0, sizeof(szJoystickButton) );
-
- }
- else if ( bGameButton )
- {
- if ( i >= sizeof(szGameButton))
- {
- SDL_SetError( "Button name too large: %s", szGameButton );
- return;
- }
- szGameButton[i] = *pchPos;
- i++;
- }
- else
- {
- if ( i >= sizeof(szJoystickButton))
- {
- SDL_SetError( "Joystick button name too large: %s", szJoystickButton );
- return;
- }
- szJoystickButton[i] = *pchPos;
- i++;
- }
- pchPos++;
- }
-
- SDL_PrivateGameControllerParseButton( szGameButton, szJoystickButton, pMapping );
-
-}
-
-/*
- * Make a new button mapping struct
- */
-void SDL_PrivateLoadButtonMapping( struct _SDL_ControllerMapping *pMapping, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping )
-{
- int j;
-
- pMapping->guid = guid;
- pMapping->name = pchName;
-
- /* set all the button mappings to non defaults */
- for ( j = 0; j < SDL_CONTROLLER_AXIS_MAX; j++ )
- {
- pMapping->axes[j] = -1;
- pMapping->buttonasaxis[j] = -1;
- }
- for ( j = 0; j < SDL_CONTROLLER_BUTTON_MAX; j++ )
- {
- pMapping->buttons[j] = -1;
- pMapping->axesasbutton[j] = -1;
- pMapping->hatasbutton[j].hat = -1;
- }
-
- for ( j = 0; j < k_nMaxReverseEntries; j++ )
- {
- pMapping->raxes[j] = SDL_CONTROLLER_AXIS_INVALID;
- pMapping->rbuttonasaxis[j] = SDL_CONTROLLER_AXIS_INVALID;
- pMapping->rbuttons[j] = SDL_CONTROLLER_BUTTON_INVALID;
- pMapping->raxesasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID;
- }
-
- for (j = 0; j < k_nMaxHatEntries; j++)
- {
- pMapping->rhatasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID;
- }
-
- SDL_PrivateGameControllerParseControllerConfigString( pMapping, pchMapping );
-}
-
-
-/*
- * grab the guid string from a mapping string
- */
-char *SDL_PrivateGetControllerGUIDFromMappingString( const char *pMapping )
-{
- const char *pFirstComma = SDL_strchr( pMapping, ',' );
- if ( pFirstComma )
- {
- char *pchGUID = SDL_malloc( pFirstComma - pMapping + 1 );
- if ( !pchGUID )
- {
- SDL_OutOfMemory();
- return NULL;
- }
- SDL_memcpy( pchGUID, pMapping, pFirstComma - pMapping );
- pchGUID[ pFirstComma - pMapping ] = 0;
- return pchGUID;
- }
- return NULL;
-}
-
-
-/*
- * grab the name string from a mapping string
- */
-char *SDL_PrivateGetControllerNameFromMappingString( const char *pMapping )
-{
- const char *pFirstComma, *pSecondComma;
- char *pchName;
-
- pFirstComma = SDL_strchr( pMapping, ',' );
- if ( !pFirstComma )
- return NULL;
-
- pSecondComma = SDL_strchr( pFirstComma + 1, ',' );
- if ( !pSecondComma )
- return NULL;
-
- pchName = SDL_malloc( pSecondComma - pFirstComma );
- if ( !pchName )
- {
- SDL_OutOfMemory();
- return NULL;
- }
- SDL_memcpy( pchName, pFirstComma + 1, pSecondComma - pFirstComma );
- pchName[ pSecondComma - pFirstComma - 1 ] = 0;
- return pchName;
-}
-
-
-/*
- * grab the button mapping string from a mapping string
- */
-char *SDL_PrivateGetControllerMappingFromMappingString( const char *pMapping )
-{
- const char *pFirstComma, *pSecondComma;
-
- pFirstComma = SDL_strchr( pMapping, ',' );
- if ( !pFirstComma )
- return NULL;
-
- pSecondComma = SDL_strchr( pFirstComma + 1, ',' );
- if ( !pSecondComma )
- return NULL;
-
- return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */
-}
-
-void SDL_PrivateGameControllerRefreshMapping( ControllerMapping_t *pControllerMapping )
-{
- SDL_GameController *gamecontrollerlist = SDL_gamecontrollers;
- while ( gamecontrollerlist )
- {
- if ( !SDL_memcmp( &gamecontrollerlist->mapping.guid, &pControllerMapping->guid, sizeof(pControllerMapping->guid) ) )
- {
- SDL_Event event;
- event.type = SDL_CONTROLLERDEVICEREMAPPED;
- event.cdevice.which = gamecontrollerlist->joystick->instance_id;
- SDL_PushEvent(&event);
-
- /* Not really threadsafe. Should this lock access within SDL_GameControllerEventWatcher? */
- SDL_PrivateLoadButtonMapping(&gamecontrollerlist->mapping, pControllerMapping->guid, pControllerMapping->name, pControllerMapping->mapping);
- }
-
- gamecontrollerlist = gamecontrollerlist->next;
- }
-}
-
-/*
- * Add or update an entry into the Mappings Database
- */
-int
-SDL_GameControllerAddMapping( const char *mappingString )
-{
- char *pchGUID;
- char *pchName;
- char *pchMapping;
- SDL_JoystickGUID jGUID;
- ControllerMapping_t *pControllerMapping;
-#ifdef SDL_JOYSTICK_DINPUT
- SDL_bool is_xinput_mapping = SDL_FALSE;
-#endif
-
- pchGUID = SDL_PrivateGetControllerGUIDFromMappingString( mappingString );
- if (!pchGUID) {
- return -1;
- }
-#ifdef SDL_JOYSTICK_DINPUT
- if ( !SDL_strcasecmp( pchGUID, "xinput" ) ) {
- is_xinput_mapping = SDL_TRUE;
- }
-#endif
- jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
- SDL_free(pchGUID);
-
- pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
-
- pchName = SDL_PrivateGetControllerNameFromMappingString( mappingString );
- if (!pchName) return -1;
-
- pchMapping = SDL_PrivateGetControllerMappingFromMappingString( mappingString );
- if (!pchMapping) {
- SDL_free( pchName );
- return -1;
- }
-
- if (pControllerMapping) {
- /* Update existing mapping */
- SDL_free( pControllerMapping->name );
- pControllerMapping->name = pchName;
- SDL_free( pControllerMapping->mapping );
- pControllerMapping->mapping = pchMapping;
- /* refresh open controllers */
- SDL_PrivateGameControllerRefreshMapping( pControllerMapping );
- return 0;
- } else {
- pControllerMapping = SDL_malloc( sizeof(*pControllerMapping) );
- if (!pControllerMapping) {
- SDL_free( pchName );
- SDL_free( pchMapping );
- return SDL_OutOfMemory();
- }
-#ifdef SDL_JOYSTICK_DINPUT
- if ( is_xinput_mapping )
- {
- s_pXInputMapping = pControllerMapping;
- }
-#endif
- pControllerMapping->guid = jGUID;
- pControllerMapping->name = pchName;
- pControllerMapping->mapping = pchMapping;
- pControllerMapping->next = s_pSupportedControllers;
- s_pSupportedControllers = pControllerMapping;
- return 1;
- }
-}
-
-/*
- * Get the mapping string for this GUID
- */
-char *
-SDL_GameControllerMappingForGUID( SDL_JoystickGUID guid )
-{
- char *pMappingString = NULL;
- ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForGUID(&guid);
- if (mapping) {
- char pchGUID[33];
- size_t needed;
- SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
- /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
- needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
- pMappingString = SDL_malloc( needed );
- SDL_snprintf( pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping );
- }
- return pMappingString;
-}
-
-/*
- * Get the mapping string for this device
- */
-char *
-SDL_GameControllerMapping( SDL_GameController * gamecontroller )
-{
- return SDL_GameControllerMappingForGUID( gamecontroller->mapping.guid );
-}
-
-static void
-SDL_GameControllerLoadHints()
-{
- const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG);
- if ( hint && hint[0] ) {
- int nchHints = SDL_strlen( hint );
- char *pUserMappings = SDL_malloc( nchHints + 1 );
- char *pTempMappings = pUserMappings;
- SDL_memcpy( pUserMappings, hint, nchHints );
- while ( pUserMappings ) {
- char *pchNewLine = NULL;
-
- pchNewLine = SDL_strchr( pUserMappings, '\n' );
- if ( pchNewLine )
- *pchNewLine = '\0';
-
- SDL_GameControllerAddMapping( pUserMappings );
-
- if ( pchNewLine )
- pUserMappings = pchNewLine + 1;
- else
- pUserMappings = NULL;
- }
- SDL_free(pTempMappings);
- }
-}
-
-/*
- * Initialize the game controller system, mostly load our DB of controller config mappings
- */
-int
-SDL_GameControllerInit(void)
-{
- int i = 0;
- const char *pMappingString = NULL;
- s_pSupportedControllers = NULL;
- pMappingString = s_ControllerMappings[i];
- while ( pMappingString )
- {
- SDL_GameControllerAddMapping( pMappingString );
-
- i++;
- pMappingString = s_ControllerMappings[i];
- }
-
- /* load in any user supplied config */
- SDL_GameControllerLoadHints();
-
- /* watch for joy events and fire controller ones if needed */
- SDL_AddEventWatch( SDL_GameControllerEventWatcher, NULL );
-
- return (0);
-}
-
-
-/*
- * Get the implementation dependent name of a controller
- */
-const char *
-SDL_GameControllerNameForIndex(int device_index)
-{
- ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
- if ( pSupportedController )
- {
- return pSupportedController->name;
- }
- return NULL;
-}
-
-
-/*
- * Return 1 if the joystick at this device index is a supported controller
- */
-SDL_bool
-SDL_IsGameController(int device_index)
-{
- ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
- if ( pSupportedController )
- {
- return SDL_TRUE;
- }
-
- return SDL_FALSE;
-}
-
-/*
- * Open a controller for use - the index passed as an argument refers to
- * the N'th controller on the system. This index is the value which will
- * identify this controller in future controller events.
- *
- * This function returns a controller identifier, or NULL if an error occurred.
- */
-SDL_GameController *
-SDL_GameControllerOpen(int device_index)
-{
- SDL_GameController *gamecontroller;
- SDL_GameController *gamecontrollerlist;
- ControllerMapping_t *pSupportedController = NULL;
-
- if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
- SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
- return (NULL);
- }
-
- gamecontrollerlist = SDL_gamecontrollers;
- /* If the controller is already open, return it */
- while ( gamecontrollerlist )
- {
- if ( SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id ) {
- gamecontroller = gamecontrollerlist;
- ++gamecontroller->ref_count;
- return (gamecontroller);
- }
- gamecontrollerlist = gamecontrollerlist->next;
- }
-
- /* Find a controller mapping */
- pSupportedController = SDL_PrivateGetControllerMapping(device_index);
- if ( !pSupportedController ) {
- SDL_SetError("Couldn't find mapping for device (%d)", device_index );
- return (NULL);
- }
-
- /* Create and initialize the joystick */
- gamecontroller = (SDL_GameController *) SDL_malloc((sizeof *gamecontroller));
- if (gamecontroller == NULL) {
- SDL_OutOfMemory();
- return NULL;
- }
-
- SDL_memset(gamecontroller, 0, (sizeof *gamecontroller));
- gamecontroller->joystick = SDL_JoystickOpen(device_index);
- if ( !gamecontroller->joystick ) {
- SDL_free(gamecontroller);
- return NULL;
- }
-
- SDL_PrivateLoadButtonMapping( &gamecontroller->mapping, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping );
-
- /* Add joystick to list */
- ++gamecontroller->ref_count;
- /* Link the joystick in the list */
- gamecontroller->next = SDL_gamecontrollers;
- SDL_gamecontrollers = gamecontroller;
-
- SDL_SYS_JoystickUpdate( gamecontroller->joystick );
-
- return (gamecontroller);
-}
-
-/*
- * Manually pump for controller updates.
- */
-void
-SDL_GameControllerUpdate(void)
-{
- /* Just for API completeness; the joystick API does all the work. */
- SDL_JoystickUpdate();
-}
-
-
-/*
- * Get the current state of an axis control on a controller
- */
-Sint16
-SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
-{
- if ( !gamecontroller )
- return 0;
-
- if (gamecontroller->mapping.axes[axis] >= 0 )
- {
- Sint16 value = ( SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axes[axis]) );
- switch (axis)
- {
- case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
- case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
- /* Shift it to be 0 - 32767. */
- value = value / 2 + 16384;
- default:
- break;
- }
- return value;
- }
- else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 )
- {
- Uint8 value;
- value = SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttonasaxis[axis] );
- if ( value > 0 )
- return 32767;
- return 0;
- }
- return 0;
-}
-
-
-/*
- * Get the current state of a button on a controller
- */
-Uint8
-SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button)
-{
- if ( !gamecontroller )
- return 0;
-
- if ( gamecontroller->mapping.buttons[button] >= 0 )
- {
- return ( SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttons[button] ) );
- }
- else if ( gamecontroller->mapping.axesasbutton[button] >= 0 )
- {
- Sint16 value;
- value = SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axesasbutton[button] );
- if ( ABS(value) > 32768/2 )
- return 1;
- return 0;
- }
- else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 )
- {
- Uint8 value;
- value = SDL_JoystickGetHat( gamecontroller->joystick, gamecontroller->mapping.hatasbutton[button].hat );
-
- if ( value & gamecontroller->mapping.hatasbutton[button].mask )
- return 1;
- return 0;
- }
-
- return 0;
-}
-
-/*
- * Return if the joystick in question is currently attached to the system,
- * \return 0 if not plugged in, 1 if still present.
- */
-SDL_bool
-SDL_GameControllerGetAttached( SDL_GameController * gamecontroller )
-{
- if ( !gamecontroller )
- return SDL_FALSE;
-
- return SDL_JoystickGetAttached(gamecontroller->joystick);
-}
-
-
-/*
- * Get the number of multi-dimensional axis controls on a joystick
- */
-const char *
-SDL_GameControllerName(SDL_GameController * gamecontroller)
-{
- if ( !gamecontroller )
- return NULL;
-
- return (gamecontroller->mapping.name);
-}
-
-
-/*
- * Get the joystick for this controller
- */
-SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller)
-{
- if ( !gamecontroller )
- return NULL;
-
- return gamecontroller->joystick;
-}
-
-/**
- * Get the SDL joystick layer binding for this controller axis mapping
- */
-SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
-{
- SDL_GameControllerButtonBind bind;
- SDL_memset( &bind, 0x0, sizeof(bind) );
-
- if ( !gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID )
- return bind;
-
- if (gamecontroller->mapping.axes[axis] >= 0 )
- {
- bind.bindType = SDL_CONTROLLER_BINDTYPE_AXIS;
- bind.value.button = gamecontroller->mapping.axes[axis];
- }
- else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 )
- {
- bind.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
- bind.value.button = gamecontroller->mapping.buttonasaxis[axis];
- }
-
- return bind;
-}
-
-
-/**
- * Get the SDL joystick layer binding for this controller button mapping
- */
-SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button)
-{
- SDL_GameControllerButtonBind bind;
- SDL_memset( &bind, 0x0, sizeof(bind) );
-
- if ( !gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID )
- return bind;
-
- if ( gamecontroller->mapping.buttons[button] >= 0 )
- {
- bind.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
- bind.value.button = gamecontroller->mapping.buttons[button];
- }
- else if ( gamecontroller->mapping.axesasbutton[button] >= 0 )
- {
- bind.bindType = SDL_CONTROLLER_BINDTYPE_AXIS;
- bind.value.axis = gamecontroller->mapping.axesasbutton[button];
- }
- else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 )
- {
- bind.bindType = SDL_CONTROLLER_BINDTYPE_HAT;
- bind.value.hat.hat = gamecontroller->mapping.hatasbutton[button].hat;
- bind.value.hat.hat_mask = gamecontroller->mapping.hatasbutton[button].mask;
- }
-
- return bind;
-}
-
-
-/*
- * Close a joystick previously opened with SDL_JoystickOpen()
- */
-void
-SDL_GameControllerClose(SDL_GameController * gamecontroller)
-{
- SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev;
-
- if ( !gamecontroller )
- return;
-
- /* First decrement ref count */
- if (--gamecontroller->ref_count > 0) {
- return;
- }
-
- SDL_JoystickClose( gamecontroller->joystick );
-
- gamecontrollerlist = SDL_gamecontrollers;
- gamecontrollerlistprev = NULL;
- while ( gamecontrollerlist )
- {
- if (gamecontroller == gamecontrollerlist)
- {
- if ( gamecontrollerlistprev )
- {
- /* unlink this entry */
- gamecontrollerlistprev->next = gamecontrollerlist->next;
- }
- else
- {
- SDL_gamecontrollers = gamecontroller->next;
- }
-
- break;
- }
- gamecontrollerlistprev = gamecontrollerlist;
- gamecontrollerlist = gamecontrollerlist->next;
- }
-
- SDL_free(gamecontroller);
-}
-
-
-/*
- * Quit the controller subsystem
- */
-void
-SDL_GameControllerQuit(void)
-{
- ControllerMapping_t *pControllerMap;
- while ( SDL_gamecontrollers )
- {
- SDL_gamecontrollers->ref_count = 1;
- SDL_GameControllerClose(SDL_gamecontrollers);
- }
-
- while ( s_pSupportedControllers )
- {
- pControllerMap = s_pSupportedControllers;
- s_pSupportedControllers = s_pSupportedControllers->next;
- SDL_free( pControllerMap->name );
- SDL_free( pControllerMap );
- }
-
- SDL_DelEventWatch( SDL_GameControllerEventWatcher, NULL );
-
-}
-
-/*
- * Event filter to transform joystick events into appropriate game controller ones
- */
-int
-SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value)
-{
- int posted;
-
- /* translate the event, if desired */
- posted = 0;
-#if !SDL_EVENTS_DISABLED
- if (SDL_GetEventState(SDL_CONTROLLERAXISMOTION) == SDL_ENABLE) {
- SDL_Event event;
- event.type = SDL_CONTROLLERAXISMOTION;
- event.caxis.which = gamecontroller->joystick->instance_id;
- event.caxis.axis = axis;
- event.caxis.value = value;
- posted = SDL_PushEvent(&event) == 1;
- }
-#endif /* !SDL_EVENTS_DISABLED */
- return (posted);
-}
-
-
-/*
- * Event filter to transform joystick events into appropriate game controller ones
- */
-int
-SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state)
-{
- int posted;
-#if !SDL_EVENTS_DISABLED
- SDL_Event event;
-
- if ( button == SDL_CONTROLLER_BUTTON_INVALID )
- return (0);
-
- switch (state) {
- case SDL_PRESSED:
- event.type = SDL_CONTROLLERBUTTONDOWN;
- break;
- case SDL_RELEASED:
- event.type = SDL_CONTROLLERBUTTONUP;
- break;
- default:
- /* Invalid state -- bail */
- return (0);
- }
-#endif /* !SDL_EVENTS_DISABLED */
-
- /* translate the event, if desired */
- posted = 0;
-#if !SDL_EVENTS_DISABLED
- if (SDL_GetEventState(event.type) == SDL_ENABLE) {
- event.cbutton.which = gamecontroller->joystick->instance_id;
- event.cbutton.button = button;
- event.cbutton.state = state;
- posted = SDL_PushEvent(&event) == 1;
- }
-#endif /* !SDL_EVENTS_DISABLED */
- return (posted);
-}
-
-/*
- * Turn off controller events
- */
-int
-SDL_GameControllerEventState(int state)
-{
-#if SDL_EVENTS_DISABLED
- return SDL_IGNORE;
-#else
- const Uint32 event_list[] = {
- SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP,
- SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED, SDL_CONTROLLERDEVICEREMAPPED,
- };
- unsigned int i;
-
- switch (state) {
- case SDL_QUERY:
- state = SDL_IGNORE;
- for (i = 0; i < SDL_arraysize(event_list); ++i) {
- state = SDL_EventState(event_list[i], SDL_QUERY);
- if (state == SDL_ENABLE) {
- break;
- }
- }
- break;
- default:
- for (i = 0; i < SDL_arraysize(event_list); ++i) {
- SDL_EventState(event_list[i], state);
- }
- break;
- }
- return (state);
-#endif /* SDL_EVENTS_DISABLED */
-}
-
-/* vi: set ts=4 sw=4 expandtab: */
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2013 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"
+
+/* This is the game controller API for Simple DirectMedia Layer */
+
+#include "SDL_events.h"
+#include "SDL_assert.h"
+#include "SDL_sysjoystick.h"
+#include "SDL_hints.h"
+#include "SDL_gamecontrollerdb.h"
+
+#if !SDL_EVENTS_DISABLED
+#include "../events/SDL_events_c.h"
+#endif
+#define ABS(_x) ((_x) < 0 ? -(_x) : (_x))
+
+
+/* a list of currently opened game controllers */
+static SDL_GameController *SDL_gamecontrollers = NULL;
+
+/* keep track of the hat and mask value that transforms this hat movement into a button/axis press */
+struct _SDL_HatMapping
+{
+ int hat;
+ Uint8 mask;
+};
+
+#define k_nMaxReverseEntries 20
+
+/**
+ * We are encoding the "HAT" as 0xhm. where h == hat ID and m == mask
+ * MAX 4 hats supported
+ */
+#define k_nMaxHatEntries 0x3f + 1
+
+/* our in memory mapping db between joystick objects and controller mappings*/
+struct _SDL_ControllerMapping
+{
+ SDL_JoystickGUID guid;
+ const char *name;
+
+ /* mapping of axis/button id to controller version */
+ int axes[SDL_CONTROLLER_AXIS_MAX];
+ int buttonasaxis[SDL_CONTROLLER_AXIS_MAX];
+
+ int buttons[SDL_CONTROLLER_BUTTON_MAX];
+ int axesasbutton[SDL_CONTROLLER_BUTTON_MAX];
+ struct _SDL_HatMapping hatasbutton[SDL_CONTROLLER_BUTTON_MAX];
+
+ /* reverse mapping, joystick indices to buttons */
+ SDL_GameControllerAxis raxes[k_nMaxReverseEntries];
+ SDL_GameControllerAxis rbuttonasaxis[k_nMaxReverseEntries];
+
+ SDL_GameControllerButton rbuttons[k_nMaxReverseEntries];
+ SDL_GameControllerButton raxesasbutton[k_nMaxReverseEntries];
+ SDL_GameControllerButton rhatasbutton[k_nMaxHatEntries];
+
+};
+
+
+/* our hard coded list of mapping support */
+typedef struct _ControllerMapping_t
+{
+ SDL_JoystickGUID guid;
+ char *name;
+ char *mapping;
+ struct _ControllerMapping_t *next;
+} ControllerMapping_t;
+
+static ControllerMapping_t *s_pSupportedControllers = NULL;
+#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT)
+static ControllerMapping_t *s_pXInputMapping = NULL;
+#endif
+
+/* The SDL game controller structure */
+struct _SDL_GameController
+{
+ SDL_Joystick *joystick; /* underlying joystick device */
+ int ref_count;
+ Uint8 hatState[4]; /* the current hat state for this controller */
+ struct _SDL_ControllerMapping mapping; /* the mapping object for this controller */
+ struct _SDL_GameController *next; /* pointer to next game controller we have allocated */
+};
+
+
+int SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value);
+int SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state);
+
+/*
+ * Event filter to fire controller events from joystick ones
+ */
+int SDL_GameControllerEventWatcher(void *userdata, SDL_Event * event)
+{
+ switch( event->type )
+ {
+ case SDL_JOYAXISMOTION:
+ {
+ SDL_GameController *controllerlist;
+
+ if ( event->jaxis.axis >= k_nMaxReverseEntries ) break;
+
+ controllerlist = SDL_gamecontrollers;
+ while ( controllerlist )
+ {
+ if ( controllerlist->joystick->instance_id == event->jaxis.which )
+ {
+ if ( controllerlist->mapping.raxes[event->jaxis.axis] >= 0 ) /* simple axis to axis, send it through */
+ {
+ SDL_GameControllerAxis axis = controllerlist->mapping.raxes[event->jaxis.axis];
+ Sint16 value = event->jaxis.value;
+ switch (axis)
+ {
+ case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
+ case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
+ /* Shift it to be 0 - 32767. */
+ value = value / 2 + 16384;
+ default:
+ break;
+ }
+ SDL_PrivateGameControllerAxis( controllerlist, axis, value );
+ }
+ else if ( controllerlist->mapping.raxesasbutton[event->jaxis.axis] >= 0 ) /* simulate an axis as a button */
+ {
+ SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.raxesasbutton[event->jaxis.axis], ABS(event->jaxis.value) > 32768/2 ? SDL_PRESSED : SDL_RELEASED );
+ }
+ break;
+ }
+ controllerlist = controllerlist->next;
+ }
+ }
+ break;
+ case SDL_JOYBUTTONDOWN:
+ case SDL_JOYBUTTONUP:
+ {
+ SDL_GameController *controllerlist;
+
+ if ( event->jbutton.button >= k_nMaxReverseEntries ) break;
+
+ controllerlist = SDL_gamecontrollers;
+ while ( controllerlist )
+ {
+ if ( controllerlist->joystick->instance_id == event->jbutton.which )
+ {
+ if ( controllerlist->mapping.rbuttons[event->jbutton.button] >= 0 ) /* simple button as button */
+ {
+ SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rbuttons[event->jbutton.button], event->jbutton.state );
+ }
+ else if ( controllerlist->mapping.rbuttonasaxis[event->jbutton.button] >= 0 ) /* an button pretending to be an axis */
+ {
+ SDL_PrivateGameControllerAxis( controllerlist, controllerlist->mapping.rbuttonasaxis[event->jbutton.button], event->jbutton.state > 0 ? 32767 : 0 );
+ }
+ break;
+ }
+ controllerlist = controllerlist->next;
+ }
+ }
+ break;
+ case SDL_JOYHATMOTION:
+ {
+ SDL_GameController *controllerlist;
+
+ if ( event->jhat.hat >= 4 ) break;
+
+ controllerlist = SDL_gamecontrollers;
+ while ( controllerlist )
+ {
+ if ( controllerlist->joystick->instance_id == event->jhat.which )
+ {
+ Uint8 bSame = controllerlist->hatState[event->jhat.hat] & event->jhat.value;
+ /* Get list of removed bits (button release) */
+ Uint8 bChanged = controllerlist->hatState[event->jhat.hat] ^ bSame;
+ /* the hat idx in the high nibble */
+ int bHighHat = event->jhat.hat << 4;
+
+ if ( bChanged & SDL_HAT_DOWN )
+ SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_RELEASED );
+ if ( bChanged & SDL_HAT_UP )
+ SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_RELEASED );
+ if ( bChanged & SDL_HAT_LEFT )
+ SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_RELEASED );
+ if ( bChanged & SDL_HAT_RIGHT )
+ SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_RELEASED );
+
+ /* Get list of added bits (button press) */
+ bChanged = event->jhat.value ^ bSame;
+
+ if ( bChanged & SDL_HAT_DOWN )
+ SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_DOWN], SDL_PRESSED );
+ if ( bChanged & SDL_HAT_UP )
+ SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_UP], SDL_PRESSED );
+ if ( bChanged & SDL_HAT_LEFT )
+ SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_LEFT], SDL_PRESSED );
+ if ( bChanged & SDL_HAT_RIGHT )
+ SDL_PrivateGameControllerButton( controllerlist, controllerlist->mapping.rhatasbutton[bHighHat | SDL_HAT_RIGHT], SDL_PRESSED );
+
+ /* update our state cache */
+ controllerlist->hatState[event->jhat.hat] = event->jhat.value;
+
+ break;
+ }
+ controllerlist = controllerlist->next;
+ }
+ }
+ break;
+ case SDL_JOYDEVICEADDED:
+ {
+ if ( SDL_IsGameController(event->jdevice.which ) )
+ {
+ SDL_Event deviceevent;
+ deviceevent.type = SDL_CONTROLLERDEVICEADDED;
+ deviceevent.cdevice.which = event->jdevice.which;
+ SDL_PushEvent(&deviceevent);
+ }
+ }
+ break;
+ case SDL_JOYDEVICEREMOVED:
+ {
+ SDL_GameController *controllerlist = SDL_gamecontrollers;
+ while ( controllerlist )
+ {
+ if ( controllerlist->joystick->instance_id == event->jdevice.which )
+ {
+ SDL_Event deviceevent;
+ deviceevent.type = SDL_CONTROLLERDEVICEREMOVED;
+ deviceevent.cdevice.which = event->jdevice.which;
+ SDL_PushEvent(&deviceevent);
+ break;
+ }
+ controllerlist = controllerlist->next;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ return 1;
+}
+
+/*
+ * Helper function to scan the mappings database for a controller with the specified GUID
+ */
+ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *guid)
+{
+ ControllerMapping_t *pSupportedController = s_pSupportedControllers;
+ while ( pSupportedController )
+ {
+ if ( !SDL_memcmp( guid, &pSupportedController->guid, sizeof(*guid) ) )
+ {
+ return pSupportedController;
+ }
+ pSupportedController = pSupportedController->next;
+ }
+ return NULL;
+}
+
+/*
+ * Helper function to determine pre-calculated offset to certain joystick mappings
+ */
+ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index)
+{
+#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT)
+ if ( SDL_SYS_IsXInputDeviceIndex(device_index) && s_pXInputMapping )
+ {
+ return s_pXInputMapping;
+ }
+ else
+#endif
+ {
+ SDL_JoystickGUID jGUID = SDL_JoystickGetDeviceGUID( device_index );
+ return SDL_PrivateGetControllerMappingForGUID(&jGUID);
+ }
+
+ return NULL;
+}
+
+static const char* map_StringForControllerAxis[] = {
+ "leftx",
+ "lefty",
+ "rightx",
+ "righty",
+ "lefttrigger",
+ "righttrigger",
+ NULL
+};
+
+/*
+ * convert a string to its enum equivalent
+ */
+SDL_GameControllerAxis SDL_GameControllerGetAxisFromString( const char *pchString )
+{
+ int entry;
+ if ( !pchString || !pchString[0] )
+ return SDL_CONTROLLER_AXIS_INVALID;
+
+ for ( entry = 0; map_StringForControllerAxis[entry]; ++entry)
+ {
+ if ( !SDL_strcasecmp( pchString, map_StringForControllerAxis[entry] ) )
+ return entry;
+ }
+ return SDL_CONTROLLER_AXIS_INVALID;
+}
+
+/*
+ * convert an enum to its string equivalent
+ */
+const char* SDL_GameControllerGetStringForAxis( SDL_GameControllerAxis axis )
+{
+ if (axis > SDL_CONTROLLER_AXIS_INVALID && axis < SDL_CONTROLLER_AXIS_MAX)
+ {
+ return map_StringForControllerAxis[axis];
+ }
+ return NULL;
+}
+
+static const char* map_StringForControllerButton[] = {
+ "a",
+ "b",
+ "x",
+ "y",
+ "back",
+ "guide",
+ "start",
+ "leftstick",
+ "rightstick",
+ "leftshoulder",
+ "rightshoulder",
+ "dpup",
+ "dpdown",
+ "dpleft",
+ "dpright",
+ NULL
+};
+
+/*
+ * convert a string to its enum equivalent
+ */
+SDL_GameControllerButton SDL_GameControllerGetButtonFromString( const char *pchString )
+{
+ int entry;
+ if ( !pchString || !pchString[0] )
+ return SDL_CONTROLLER_BUTTON_INVALID;
+
+ for ( entry = 0; map_StringForControllerButton[entry]; ++entry)
+ {
+ if ( !SDL_strcasecmp( pchString, map_StringForControllerButton[entry] ) )
+ return entry;
+ }
+ return SDL_CONTROLLER_BUTTON_INVALID;
+}
+
+/*
+ * convert an enum to its string equivalent
+ */
+const char* SDL_GameControllerGetStringForButton( SDL_GameControllerButton axis )
+{
+ if (axis > SDL_CONTROLLER_BUTTON_INVALID && axis < SDL_CONTROLLER_BUTTON_MAX)
+ {
+ return map_StringForControllerButton[axis];
+ }
+ return NULL;
+}
+
+/*
+ * given a controller button name and a joystick name update our mapping structure with it
+ */
+void SDL_PrivateGameControllerParseButton( const char *szGameButton, const char *szJoystickButton, struct _SDL_ControllerMapping *pMapping )
+{
+ int iSDLButton = 0;
+ SDL_GameControllerButton button;
+ SDL_GameControllerAxis axis;
+ button = SDL_GameControllerGetButtonFromString( szGameButton );
+ axis = SDL_GameControllerGetAxisFromString( szGameButton );
+ iSDLButton = SDL_atoi( &szJoystickButton[1] );
+
+ if ( szJoystickButton[0] == 'a' )
+ {
+ if ( iSDLButton >= k_nMaxReverseEntries )
+ {
+ SDL_SetError("Axis index too large: %d", iSDLButton );
+ return;
+ }
+ if ( axis != SDL_CONTROLLER_AXIS_INVALID )
+ {
+ pMapping->axes[ axis ] = iSDLButton;
+ pMapping->raxes[ iSDLButton ] = axis;
+ }
+ else if ( button != SDL_CONTROLLER_BUTTON_INVALID )
+ {
+ pMapping->axesasbutton[ button ] = iSDLButton;
+ pMapping->raxesasbutton[ iSDLButton ] = button;
+ }
+ else
+ {
+ SDL_assert( !"How did we get here?" );
+ }
+
+ }
+ else if ( szJoystickButton[0] == 'b' )
+ {
+ if ( iSDLButton >= k_nMaxReverseEntries )
+ {
+ SDL_SetError("Button index too large: %d", iSDLButton );
+ return;
+ }
+ if ( button != SDL_CONTROLLER_BUTTON_INVALID )
+ {
+ pMapping->buttons[ button ] = iSDLButton;
+ pMapping->rbuttons[ iSDLButton ] = button;
+ }
+ else if ( axis != SDL_CONTROLLER_AXIS_INVALID )
+ {
+ pMapping->buttonasaxis[ axis ] = iSDLButton;
+ pMapping->rbuttonasaxis[ iSDLButton ] = axis;
+ }
+ else
+ {
+ SDL_assert( !"How did we get here?" );
+ }
+ }
+ else if ( szJoystickButton[0] == 'h' )
+ {
+ int hat = SDL_atoi( &szJoystickButton[1] );
+ int mask = SDL_atoi( &szJoystickButton[3] );
+ if (hat >= 4) {
+ SDL_SetError("Hat index too large: %d", iSDLButton );
+ }
+
+ if ( button != SDL_CONTROLLER_BUTTON_INVALID )
+ {
+ int ridx;
+ pMapping->hatasbutton[ button ].hat = hat;
+ pMapping->hatasbutton[ button ].mask = mask;
+ ridx = (hat << 4) | mask;
+ pMapping->rhatasbutton[ ridx ] = button;
+ }
+ else if ( axis != SDL_CONTROLLER_AXIS_INVALID )
+ {
+ SDL_assert( !"Support hat as axis" );
+ }
+ else
+ {
+ SDL_assert( !"How did we get here?" );
+ }
+ }
+}
+
+
+/*
+ * given a controller mapping string update our mapping object
+ */
+static void
+SDL_PrivateGameControllerParseControllerConfigString( struct _SDL_ControllerMapping *pMapping, const char *pchString )
+{
+ char szGameButton[20];
+ char szJoystickButton[20];
+ SDL_bool bGameButton = SDL_TRUE;
+ int i = 0;
+ const char *pchPos = pchString;
+
+ SDL_memset( szGameButton, 0x0, sizeof(szGameButton) );
+ SDL_memset( szJoystickButton, 0x0, sizeof(szJoystickButton) );
+
+ while ( pchPos && *pchPos )
+ {
+ if ( *pchPos == ':' )
+ {
+ i = 0;
+ bGameButton = SDL_FALSE;
+ }
+ else if ( *pchPos == ' ' )
+ {
+
+ }
+ else if ( *pchPos == ',' )
+ {
+ i = 0;
+ bGameButton = SDL_TRUE;
+ SDL_PrivateGameControllerParseButton( szGameButton, szJoystickButton, pMapping );
+ SDL_memset( szGameButton, 0x0, sizeof(szGameButton) );
+ SDL_memset( szJoystickButton, 0x0, sizeof(szJoystickButton) );
+
+ }
+ else if ( bGameButton )
+ {
+ if ( i >= sizeof(szGameButton))
+ {
+ SDL_SetError( "Button name too large: %s", szGameButton );
+ return;
+ }
+ szGameButton[i] = *pchPos;
+ i++;
+ }
+ else
+ {
+ if ( i >= sizeof(szJoystickButton))
+ {
+ SDL_SetError( "Joystick button name too large: %s", szJoystickButton );
+ return;
+ }
+ szJoystickButton[i] = *pchPos;
+ i++;
+ }
+ pchPos++;
+ }
+
+ SDL_PrivateGameControllerParseButton( szGameButton, szJoystickButton, pMapping );
+
+}
+
+/*
+ * Make a new button mapping struct
+ */
+void SDL_PrivateLoadButtonMapping( struct _SDL_ControllerMapping *pMapping, SDL_JoystickGUID guid, const char *pchName, const char *pchMapping )
+{
+ int j;
+
+ pMapping->guid = guid;
+ pMapping->name = pchName;
+
+ /* set all the button mappings to non defaults */
+ for ( j = 0; j < SDL_CONTROLLER_AXIS_MAX; j++ )
+ {
+ pMapping->axes[j] = -1;
+ pMapping->buttonasaxis[j] = -1;
+ }
+ for ( j = 0; j < SDL_CONTROLLER_BUTTON_MAX; j++ )
+ {
+ pMapping->buttons[j] = -1;
+ pMapping->axesasbutton[j] = -1;
+ pMapping->hatasbutton[j].hat = -1;
+ }
+
+ for ( j = 0; j < k_nMaxReverseEntries; j++ )
+ {
+ pMapping->raxes[j] = SDL_CONTROLLER_AXIS_INVALID;
+ pMapping->rbuttonasaxis[j] = SDL_CONTROLLER_AXIS_INVALID;
+ pMapping->rbuttons[j] = SDL_CONTROLLER_BUTTON_INVALID;
+ pMapping->raxesasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID;
+ }
+
+ for (j = 0; j < k_nMaxHatEntries; j++)
+ {
+ pMapping->rhatasbutton[j] = SDL_CONTROLLER_BUTTON_INVALID;
+ }
+
+ SDL_PrivateGameControllerParseControllerConfigString( pMapping, pchMapping );
+}
+
+
+/*
+ * grab the guid string from a mapping string
+ */
+char *SDL_PrivateGetControllerGUIDFromMappingString( const char *pMapping )
+{
+ const char *pFirstComma = SDL_strchr( pMapping, ',' );
+ if ( pFirstComma )
+ {
+ char *pchGUID = SDL_malloc( pFirstComma - pMapping + 1 );
+ if ( !pchGUID )
+ {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+ SDL_memcpy( pchGUID, pMapping, pFirstComma - pMapping );
+ pchGUID[ pFirstComma - pMapping ] = 0;
+ return pchGUID;
+ }
+ return NULL;
+}
+
+
+/*
+ * grab the name string from a mapping string
+ */
+char *SDL_PrivateGetControllerNameFromMappingString( const char *pMapping )
+{
+ const char *pFirstComma, *pSecondComma;
+ char *pchName;
+
+ pFirstComma = SDL_strchr( pMapping, ',' );
+ if ( !pFirstComma )
+ return NULL;
+
+ pSecondComma = SDL_strchr( pFirstComma + 1, ',' );
+ if ( !pSecondComma )
+ return NULL;
+
+ pchName = SDL_malloc( pSecondComma - pFirstComma );
+ if ( !pchName )
+ {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+ SDL_memcpy( pchName, pFirstComma + 1, pSecondComma - pFirstComma );
+ pchName[ pSecondComma - pFirstComma - 1 ] = 0;
+ return pchName;
+}
+
+
+/*
+ * grab the button mapping string from a mapping string
+ */
+char *SDL_PrivateGetControllerMappingFromMappingString( const char *pMapping )
+{
+ const char *pFirstComma, *pSecondComma;
+
+ pFirstComma = SDL_strchr( pMapping, ',' );
+ if ( !pFirstComma )
+ return NULL;
+
+ pSecondComma = SDL_strchr( pFirstComma + 1, ',' );
+ if ( !pSecondComma )
+ return NULL;
+
+ return SDL_strdup(pSecondComma + 1); /* mapping is everything after the 3rd comma */
+}
+
+void SDL_PrivateGameControllerRefreshMapping( ControllerMapping_t *pControllerMapping )
+{
+ SDL_GameController *gamecontrollerlist = SDL_gamecontrollers;
+ while ( gamecontrollerlist )
+ {
+ if ( !SDL_memcmp( &gamecontrollerlist->mapping.guid, &pControllerMapping->guid, sizeof(pControllerMapping->guid) ) )
+ {
+ SDL_Event event;
+ event.type = SDL_CONTROLLERDEVICEREMAPPED;
+ event.cdevice.which = gamecontrollerlist->joystick->instance_id;
+ SDL_PushEvent(&event);
+
+ /* Not really threadsafe. Should this lock access within SDL_GameControllerEventWatcher? */
+ SDL_PrivateLoadButtonMapping(&gamecontrollerlist->mapping, pControllerMapping->guid, pControllerMapping->name, pControllerMapping->mapping);
+ }
+
+ gamecontrollerlist = gamecontrollerlist->next;
+ }
+}
+
+/*
+ * Add or update an entry into the Mappings Database
+ */
+int
+SDL_GameControllerAddMapping( const char *mappingString )
+{
+ char *pchGUID;
+ char *pchName;
+ char *pchMapping;
+ SDL_JoystickGUID jGUID;
+ ControllerMapping_t *pControllerMapping;
+#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT)
+ SDL_bool is_xinput_mapping = SDL_FALSE;
+#endif
+
+ pchGUID = SDL_PrivateGetControllerGUIDFromMappingString( mappingString );
+ if (!pchGUID) {
+ return -1;
+ }
+#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT)
+ if ( !SDL_strcasecmp( pchGUID, "xinput" ) ) {
+ is_xinput_mapping = SDL_TRUE;
+ }
+#endif
+ jGUID = SDL_JoystickGetGUIDFromString(pchGUID);
+ SDL_free(pchGUID);
+
+ pControllerMapping = SDL_PrivateGetControllerMappingForGUID(&jGUID);
+
+ pchName = SDL_PrivateGetControllerNameFromMappingString( mappingString );
+ if (!pchName) return -1;
+
+ pchMapping = SDL_PrivateGetControllerMappingFromMappingString( mappingString );
+ if (!pchMapping) {
+ SDL_free( pchName );
+ return -1;
+ }
+
+ if (pControllerMapping) {
+ /* Update existing mapping */
+ SDL_free( pControllerMapping->name );
+ pControllerMapping->name = pchName;
+ SDL_free( pControllerMapping->mapping );
+ pControllerMapping->mapping = pchMapping;
+ /* refresh open controllers */
+ SDL_PrivateGameControllerRefreshMapping( pControllerMapping );
+ return 0;
+ } else {
+ pControllerMapping = SDL_malloc( sizeof(*pControllerMapping) );
+ if (!pControllerMapping) {
+ SDL_free( pchName );
+ SDL_free( pchMapping );
+ return SDL_OutOfMemory();
+ }
+#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT)
+ if ( is_xinput_mapping )
+ {
+ s_pXInputMapping = pControllerMapping;
+ }
+#endif
+ pControllerMapping->guid = jGUID;
+ pControllerMapping->name = pchName;
+ pControllerMapping->mapping = pchMapping;
+ pControllerMapping->next = s_pSupportedControllers;
+ s_pSupportedControllers = pControllerMapping;
+ return 1;
+ }
+}
+
+/*
+ * Get the mapping string for this GUID
+ */
+char *
+SDL_GameControllerMappingForGUID( SDL_JoystickGUID guid )
+{
+ char *pMappingString = NULL;
+ ControllerMapping_t *mapping = SDL_PrivateGetControllerMappingForGUID(&guid);
+ if (mapping) {
+ char pchGUID[33];
+ size_t needed;
+ SDL_JoystickGetGUIDString(guid, pchGUID, sizeof(pchGUID));
+ /* allocate enough memory for GUID + ',' + name + ',' + mapping + \0 */
+ needed = SDL_strlen(pchGUID) + 1 + SDL_strlen(mapping->name) + 1 + SDL_strlen(mapping->mapping) + 1;
+ pMappingString = SDL_malloc( needed );
+ SDL_snprintf( pMappingString, needed, "%s,%s,%s", pchGUID, mapping->name, mapping->mapping );
+ }
+ return pMappingString;
+}
+
+/*
+ * Get the mapping string for this device
+ */
+char *
+SDL_GameControllerMapping( SDL_GameController * gamecontroller )
+{
+ return SDL_GameControllerMappingForGUID( gamecontroller->mapping.guid );
+}
+
+static void
+SDL_GameControllerLoadHints()
+{
+ const char *hint = SDL_GetHint(SDL_HINT_GAMECONTROLLERCONFIG);
+ if ( hint && hint[0] ) {
+ int nchHints = SDL_strlen( hint );
+ char *pUserMappings = SDL_malloc( nchHints + 1 );
+ char *pTempMappings = pUserMappings;
+ SDL_memcpy( pUserMappings, hint, nchHints );
+ while ( pUserMappings ) {
+ char *pchNewLine = NULL;
+
+ pchNewLine = SDL_strchr( pUserMappings, '\n' );
+ if ( pchNewLine )
+ *pchNewLine = '\0';
+
+ SDL_GameControllerAddMapping( pUserMappings );
+
+ if ( pchNewLine )
+ pUserMappings = pchNewLine + 1;
+ else
+ pUserMappings = NULL;
+ }
+ SDL_free(pTempMappings);
+ }
+}
+
+/*
+ * Initialize the game controller system, mostly load our DB of controller config mappings
+ */
+int
+SDL_GameControllerInit(void)
+{
+ int i = 0;
+ const char *pMappingString = NULL;
+ s_pSupportedControllers = NULL;
+ pMappingString = s_ControllerMappings[i];
+ while ( pMappingString )
+ {
+ SDL_GameControllerAddMapping( pMappingString );
+
+ i++;
+ pMappingString = s_ControllerMappings[i];
+ }
+
+ /* load in any user supplied config */
+ SDL_GameControllerLoadHints();
+
+ /* watch for joy events and fire controller ones if needed */
+ SDL_AddEventWatch( SDL_GameControllerEventWatcher, NULL );
+
+ return (0);
+}
+
+
+/*
+ * Get the implementation dependent name of a controller
+ */
+const char *
+SDL_GameControllerNameForIndex(int device_index)
+{
+ ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
+ if ( pSupportedController )
+ {
+ return pSupportedController->name;
+ }
+ return NULL;
+}
+
+
+/*
+ * Return 1 if the joystick at this device index is a supported controller
+ */
+SDL_bool
+SDL_IsGameController(int device_index)
+{
+ ControllerMapping_t *pSupportedController = SDL_PrivateGetControllerMapping(device_index);
+ if ( pSupportedController )
+ {
+ return SDL_TRUE;
+ }
+
+ return SDL_FALSE;
+}
+
+/*
+ * Open a controller for use - the index passed as an argument refers to
+ * the N'th controller on the system. This index is the value which will
+ * identify this controller in future controller events.
+ *
+ * This function returns a controller identifier, or NULL if an error occurred.
+ */
+SDL_GameController *
+SDL_GameControllerOpen(int device_index)
+{
+ SDL_GameController *gamecontroller;
+ SDL_GameController *gamecontrollerlist;
+ ControllerMapping_t *pSupportedController = NULL;
+
+ if ((device_index < 0) || (device_index >= SDL_NumJoysticks())) {
+ SDL_SetError("There are %d joysticks available", SDL_NumJoysticks());
+ return (NULL);
+ }
+
+ gamecontrollerlist = SDL_gamecontrollers;
+ /* If the controller is already open, return it */
+ while ( gamecontrollerlist )
+ {
+ if ( SDL_SYS_GetInstanceIdOfDeviceIndex(device_index) == gamecontrollerlist->joystick->instance_id ) {
+ gamecontroller = gamecontrollerlist;
+ ++gamecontroller->ref_count;
+ return (gamecontroller);
+ }
+ gamecontrollerlist = gamecontrollerlist->next;
+ }
+
+ /* Find a controller mapping */
+ pSupportedController = SDL_PrivateGetControllerMapping(device_index);
+ if ( !pSupportedController ) {
+ SDL_SetError("Couldn't find mapping for device (%d)", device_index );
+ return (NULL);
+ }
+
+ /* Create and initialize the joystick */
+ gamecontroller = (SDL_GameController *) SDL_malloc((sizeof *gamecontroller));
+ if (gamecontroller == NULL) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+
+ SDL_memset(gamecontroller, 0, (sizeof *gamecontroller));
+ gamecontroller->joystick = SDL_JoystickOpen(device_index);
+ if ( !gamecontroller->joystick ) {
+ SDL_free(gamecontroller);
+ return NULL;
+ }
+
+ SDL_PrivateLoadButtonMapping( &gamecontroller->mapping, pSupportedController->guid, pSupportedController->name, pSupportedController->mapping );
+
+ /* Add joystick to list */
+ ++gamecontroller->ref_count;
+ /* Link the joystick in the list */
+ gamecontroller->next = SDL_gamecontrollers;
+ SDL_gamecontrollers = gamecontroller;
+
+ SDL_SYS_JoystickUpdate( gamecontroller->joystick );
+
+ return (gamecontroller);
+}
+
+/*
+ * Manually pump for controller updates.
+ */
+void
+SDL_GameControllerUpdate(void)
+{
+ /* Just for API completeness; the joystick API does all the work. */
+ SDL_JoystickUpdate();
+}
+
+
+/*
+ * Get the current state of an axis control on a controller
+ */
+Sint16
+SDL_GameControllerGetAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
+{
+ if ( !gamecontroller )
+ return 0;
+
+ if (gamecontroller->mapping.axes[axis] >= 0 )
+ {
+ Sint16 value = ( SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axes[axis]) );
+ switch (axis)
+ {
+ case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
+ case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
+ /* Shift it to be 0 - 32767. */
+ value = value / 2 + 16384;
+ default:
+ break;
+ }
+ return value;
+ }
+ else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 )
+ {
+ Uint8 value;
+ value = SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttonasaxis[axis] );
+ if ( value > 0 )
+ return 32767;
+ return 0;
+ }
+ return 0;
+}
+
+
+/*
+ * Get the current state of a button on a controller
+ */
+Uint8
+SDL_GameControllerGetButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button)
+{
+ if ( !gamecontroller )
+ return 0;
+
+ if ( gamecontroller->mapping.buttons[button] >= 0 )
+ {
+ return ( SDL_JoystickGetButton( gamecontroller->joystick, gamecontroller->mapping.buttons[button] ) );
+ }
+ else if ( gamecontroller->mapping.axesasbutton[button] >= 0 )
+ {
+ Sint16 value;
+ value = SDL_JoystickGetAxis( gamecontroller->joystick, gamecontroller->mapping.axesasbutton[button] );
+ if ( ABS(value) > 32768/2 )
+ return 1;
+ return 0;
+ }
+ else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 )
+ {
+ Uint8 value;
+ value = SDL_JoystickGetHat( gamecontroller->joystick, gamecontroller->mapping.hatasbutton[button].hat );
+
+ if ( value & gamecontroller->mapping.hatasbutton[button].mask )
+ return 1;
+ return 0;
+ }
+
+ return 0;
+}
+
+/*
+ * Return if the joystick in question is currently attached to the system,
+ * \return 0 if not plugged in, 1 if still present.
+ */
+SDL_bool
+SDL_GameControllerGetAttached( SDL_GameController * gamecontroller )
+{
+ if ( !gamecontroller )
+ return SDL_FALSE;
+
+ return SDL_JoystickGetAttached(gamecontroller->joystick);
+}
+
+
+/*
+ * Get the number of multi-dimensional axis controls on a joystick
+ */
+const char *
+SDL_GameControllerName(SDL_GameController * gamecontroller)
+{
+ if ( !gamecontroller )
+ return NULL;
+
+ return (gamecontroller->mapping.name);
+}
+
+
+/*
+ * Get the joystick for this controller
+ */
+SDL_Joystick *SDL_GameControllerGetJoystick(SDL_GameController * gamecontroller)
+{
+ if ( !gamecontroller )
+ return NULL;
+
+ return gamecontroller->joystick;
+}
+
+/**
+ * Get the SDL joystick layer binding for this controller axis mapping
+ */
+SDL_GameControllerButtonBind SDL_GameControllerGetBindForAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis)
+{
+ SDL_GameControllerButtonBind bind;
+ SDL_memset( &bind, 0x0, sizeof(bind) );
+
+ if ( !gamecontroller || axis == SDL_CONTROLLER_AXIS_INVALID )
+ return bind;
+
+ if (gamecontroller->mapping.axes[axis] >= 0 )
+ {
+ bind.bindType = SDL_CONTROLLER_BINDTYPE_AXIS;
+ bind.value.button = gamecontroller->mapping.axes[axis];
+ }
+ else if (gamecontroller->mapping.buttonasaxis[axis] >= 0 )
+ {
+ bind.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
+ bind.value.button = gamecontroller->mapping.buttonasaxis[axis];
+ }
+
+ return bind;
+}
+
+
+/**
+ * Get the SDL joystick layer binding for this controller button mapping
+ */
+SDL_GameControllerButtonBind SDL_GameControllerGetBindForButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button)
+{
+ SDL_GameControllerButtonBind bind;
+ SDL_memset( &bind, 0x0, sizeof(bind) );
+
+ if ( !gamecontroller || button == SDL_CONTROLLER_BUTTON_INVALID )
+ return bind;
+
+ if ( gamecontroller->mapping.buttons[button] >= 0 )
+ {
+ bind.bindType = SDL_CONTROLLER_BINDTYPE_BUTTON;
+ bind.value.button = gamecontroller->mapping.buttons[button];
+ }
+ else if ( gamecontroller->mapping.axesasbutton[button] >= 0 )
+ {
+ bind.bindType = SDL_CONTROLLER_BINDTYPE_AXIS;
+ bind.value.axis = gamecontroller->mapping.axesasbutton[button];
+ }
+ else if ( gamecontroller->mapping.hatasbutton[button].hat >= 0 )
+ {
+ bind.bindType = SDL_CONTROLLER_BINDTYPE_HAT;
+ bind.value.hat.hat = gamecontroller->mapping.hatasbutton[button].hat;
+ bind.value.hat.hat_mask = gamecontroller->mapping.hatasbutton[button].mask;
+ }
+
+ return bind;
+}
+
+
+/*
+ * Close a joystick previously opened with SDL_JoystickOpen()
+ */
+void
+SDL_GameControllerClose(SDL_GameController * gamecontroller)
+{
+ SDL_GameController *gamecontrollerlist, *gamecontrollerlistprev;
+
+ if ( !gamecontroller )
+ return;
+
+ /* First decrement ref count */
+ if (--gamecontroller->ref_count > 0) {
+ return;
+ }
+
+ SDL_JoystickClose( gamecontroller->joystick );
+
+ gamecontrollerlist = SDL_gamecontrollers;
+ gamecontrollerlistprev = NULL;
+ while ( gamecontrollerlist )
+ {
+ if (gamecontroller == gamecontrollerlist)
+ {
+ if ( gamecontrollerlistprev )
+ {
+ /* unlink this entry */
+ gamecontrollerlistprev->next = gamecontrollerlist->next;
+ }
+ else
+ {
+ SDL_gamecontrollers = gamecontroller->next;
+ }
+
+ break;
+ }
+ gamecontrollerlistprev = gamecontrollerlist;
+ gamecontrollerlist = gamecontrollerlist->next;
+ }
+
+ SDL_free(gamecontroller);
+}
+
+
+/*
+ * Quit the controller subsystem
+ */
+void
+SDL_GameControllerQuit(void)
+{
+ ControllerMapping_t *pControllerMap;
+ while ( SDL_gamecontrollers )
+ {
+ SDL_gamecontrollers->ref_count = 1;
+ SDL_GameControllerClose(SDL_gamecontrollers);
+ }
+
+ while ( s_pSupportedControllers )
+ {
+ pControllerMap = s_pSupportedControllers;
+ s_pSupportedControllers = s_pSupportedControllers->next;
+ SDL_free( pControllerMap->name );
+ SDL_free( pControllerMap );
+ }
+
+ SDL_DelEventWatch( SDL_GameControllerEventWatcher, NULL );
+
+}
+
+/*
+ * Event filter to transform joystick events into appropriate game controller ones
+ */
+int
+SDL_PrivateGameControllerAxis(SDL_GameController * gamecontroller, SDL_GameControllerAxis axis, Sint16 value)
+{
+ int posted;
+
+ /* translate the event, if desired */
+ posted = 0;
+#if !SDL_EVENTS_DISABLED
+ if (SDL_GetEventState(SDL_CONTROLLERAXISMOTION) == SDL_ENABLE) {
+ SDL_Event event;
+ event.type = SDL_CONTROLLERAXISMOTION;
+ event.caxis.which = gamecontroller->joystick->instance_id;
+ event.caxis.axis = axis;
+ event.caxis.value = value;
+ posted = SDL_PushEvent(&event) == 1;
+ }
+#endif /* !SDL_EVENTS_DISABLED */
+ return (posted);
+}
+
+
+/*
+ * Event filter to transform joystick events into appropriate game controller ones
+ */
+int
+SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameControllerButton button, Uint8 state)
+{
+ int posted;
+#if !SDL_EVENTS_DISABLED
+ SDL_Event event;
+
+ if ( button == SDL_CONTROLLER_BUTTON_INVALID )
+ return (0);
+
+ switch (state) {
+ case SDL_PRESSED:
+ event.type = SDL_CONTROLLERBUTTONDOWN;
+ break;
+ case SDL_RELEASED:
+ event.type = SDL_CONTROLLERBUTTONUP;
+ break;
+ default:
+ /* Invalid state -- bail */
+ return (0);
+ }
+#endif /* !SDL_EVENTS_DISABLED */
+
+ /* translate the event, if desired */
+ posted = 0;
+#if !SDL_EVENTS_DISABLED
+ if (SDL_GetEventState(event.type) == SDL_ENABLE) {
+ event.cbutton.which = gamecontroller->joystick->instance_id;
+ event.cbutton.button = button;
+ event.cbutton.state = state;
+ posted = SDL_PushEvent(&event) == 1;
+ }
+#endif /* !SDL_EVENTS_DISABLED */
+ return (posted);
+}
+
+/*
+ * Turn off controller events
+ */
+int
+SDL_GameControllerEventState(int state)
+{
+#if SDL_EVENTS_DISABLED
+ return SDL_IGNORE;
+#else
+ const Uint32 event_list[] = {
+ SDL_CONTROLLERAXISMOTION, SDL_CONTROLLERBUTTONDOWN, SDL_CONTROLLERBUTTONUP,
+ SDL_CONTROLLERDEVICEADDED, SDL_CONTROLLERDEVICEREMOVED, SDL_CONTROLLERDEVICEREMAPPED,
+ };
+ unsigned int i;
+
+ switch (state) {
+ case SDL_QUERY:
+ state = SDL_IGNORE;
+ for (i = 0; i < SDL_arraysize(event_list); ++i) {
+ state = SDL_EventState(event_list[i], SDL_QUERY);
+ if (state == SDL_ENABLE) {
+ break;
+ }
+ }
+ break;
+ default:
+ for (i = 0; i < SDL_arraysize(event_list); ++i) {
+ SDL_EventState(event_list[i], state);
+ }
+ break;
+ }
+ return (state);
+#endif /* SDL_EVENTS_DISABLED */
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h
index 4a5019e73..f75aabc07 100644
--- a/src/joystick/SDL_sysjoystick.h
+++ b/src/joystick/SDL_sysjoystick.h
@@ -108,7 +108,7 @@ extern SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID(int device_index);
/* Function to return the stable GUID for a opened joystick */
extern SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick);
-#ifdef SDL_JOYSTICK_DINPUT
+#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT)
/* Function to get the current instance id of the joystick located at device_index */
extern SDL_bool SDL_SYS_IsXInputDeviceIndex( int device_index );
#endif
diff --git a/src/joystick/windowsrt/SDL_xinputjoystick.c b/src/joystick/windowsrt/SDL_xinputjoystick.c
new file mode 100644
index 000000000..6b3e59f0e
--- /dev/null
+++ b/src/joystick/windowsrt/SDL_xinputjoystick.c
@@ -0,0 +1,435 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2013 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"
+
+#if SDL_JOYSTICK_XINPUT
+
+/* SDL_xinputjoystick.c implements an XInput-only joystick and game controller
+ backend that is suitable for use on WinRT. SDL's DirectInput backend, also
+ XInput-capable, was not used as DirectInput is not available on WinRT (or,
+ at least, it isn't a public API). Some portions of this XInput backend
+ may copy parts of the XInput-using code from the DirectInput backend.
+ Refactoring the common parts into one location may be good to-do at some
+ point.
+
+ TODO, WinRT: add hotplug support for XInput based game controllers
+*/
+
+#include "SDL_joystick.h"
+#include "../SDL_sysjoystick.h"
+#include "../SDL_joystick_c.h"
+#include "SDL_events.h"
+#include "../../events/SDL_events_c.h"
+
+#include
+#include
+
+struct joystick_hwdata {
+ //Uint8 bXInputHaptic; // Supports force feedback via XInput.
+ DWORD userIndex; // The XInput device index, in the range [0, XUSER_MAX_COUNT-1] (probably [0,3]).
+ XINPUT_STATE XInputState; // the last-read in XInputState, kept around to compare old and new values
+ SDL_bool isDeviceConnected; // was the device connected (on the last polling, or during backend-initialization)?
+ SDL_bool isDeviceRemovalEventPending; // was the device removed, and is the associated removal event pending?
+};
+
+/* Keep track of data on all XInput devices, regardless of whether or not
+ they've been opened (via SDL_JoystickOpen).
+ */
+static struct joystick_hwdata g_XInputData[XUSER_MAX_COUNT];
+
+/* Function to scan the system for joysticks.
+ * It should return 0, or -1 on an unrecoverable fatal error.
+ */
+int
+SDL_SYS_JoystickInit(void)
+{
+ HRESULT result = S_OK;
+ XINPUT_STATE tempXInputState;
+ int i;
+
+ SDL_zero(g_XInputData);
+
+ /* Make initial notes on whether or not devices are connected (or not).
+ */
+ for (i = 0; i < XUSER_MAX_COUNT; ++i) {
+ result = XInputGetState(i, &tempXInputState);
+ if (result == ERROR_SUCCESS) {
+ g_XInputData[i].isDeviceConnected = SDL_TRUE;
+ }
+ }
+
+ return (0);
+}
+
+int SDL_SYS_NumJoysticks()
+{
+ int joystickCount = 0;
+ DWORD i;
+
+ /* Iterate through each possible XInput device and see if something
+ was connected (at joystick init, or during the last polling).
+ */
+ for (i = 0; i < XUSER_MAX_COUNT; ++i) {
+ if (g_XInputData[i].isDeviceConnected) {
+ ++joystickCount;
+ }
+ }
+
+ return joystickCount;
+}
+
+void SDL_SYS_JoystickDetect()
+{
+ DWORD i;
+ XINPUT_STATE tempXInputState;
+ HRESULT result;
+ SDL_Event event;
+
+ /* Iterate through each possible XInput device, seeing if any devices
+ have been connected, or if they were removed.
+ */
+ for (i = 0; i < XUSER_MAX_COUNT; ++i) {
+ /* See if any new devices are connected. */
+ if (!g_XInputData[i].isDeviceConnected && !g_XInputData[i].isDeviceRemovalEventPending) {
+ result = XInputGetState(i, &tempXInputState);
+ if (result == ERROR_SUCCESS) {
+ /* Yup, a device is connected. Mark the device as connected,
+ then tell others about it (via an SDL_JOYDEVICEADDED event.)
+ */
+ g_XInputData[i].isDeviceConnected = SDL_TRUE;
+
+#if !SDL_EVENTS_DISABLED
+ SDL_zero(event);
+ event.type = SDL_JOYDEVICEADDED;
+
+ if (SDL_GetEventState(event.type) == SDL_ENABLE) {
+ event.jdevice.which = i;
+ if ((SDL_EventOK == NULL)
+ || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
+ SDL_PushEvent(&event);
+ }
+ }
+#endif
+ }
+ } else if (g_XInputData[i].isDeviceRemovalEventPending) {
+ /* A device was previously marked as removed (by
+ SDL_SYS_JoystickUpdate). Tell others about the device removal.
+ */
+
+ g_XInputData[i].isDeviceRemovalEventPending = SDL_FALSE;
+
+#if !SDL_EVENTS_DISABLED
+ SDL_zero(event);
+ event.type = SDL_JOYDEVICEREMOVED;
+
+ if (SDL_GetEventState(event.type) == SDL_ENABLE) {
+ event.jdevice.which = i; //joystick->hwdata->userIndex;
+ if ((SDL_EventOK == NULL)
+ || (*SDL_EventOK) (SDL_EventOKParam, &event)) {
+ SDL_PushEvent(&event);
+ }
+ }
+#endif
+ }
+ }
+}
+
+SDL_bool SDL_SYS_JoystickNeedsPolling()
+{
+ /* Since XInput, or WinRT, provides any events to indicate when a game
+ controller gets connected, and instead indicates device availability
+ solely through polling, we'll poll (for new devices).
+ */
+ return SDL_TRUE;
+}
+
+/* Internal function to retreive device capabilities.
+ This function will return an SDL-standard value of 0 on success
+ (a device is connected, and data on it was retrieved), or -1
+ on failure (no device was connected, or some other error
+ occurred. SDL_SetError() will be invoked to set an appropriate
+ error message.
+ */
+static int
+SDL_XInput_GetDeviceCapabilities(int device_index, XINPUT_CAPABILITIES * pDeviceCaps)
+{
+ HRESULT dwResult;
+
+ /* Make sure that the device index is a valid one. If not, return to the
+ caller with an error.
+ */
+ if (device_index < 0 || device_index >= XUSER_MAX_COUNT) {
+ return SDL_SetError("invalid/unavailable device index");
+ }
+
+ /* See if a device exists, and if so, what its capabilities are. If a
+ device is not available, return to the caller with an error.
+ */
+ switch ((dwResult = XInputGetCapabilities(device_index, 0, pDeviceCaps))) {
+ case ERROR_SUCCESS:
+ /* A device is available, and its capabilities were retrieved! */
+ return 0;
+ case ERROR_DEVICE_NOT_CONNECTED:
+ return SDL_SetError("no device is connected at joystick index, %d", device_index);
+ default:
+ return SDL_SetError("an unknown error occurred when retrieving info on a device at joystick index, %d", device_index);
+ }
+}
+
+/* Function to get the device-dependent name of a joystick */
+const char *
+SDL_SYS_JoystickNameForDeviceIndex(int device_index)
+{
+ XINPUT_CAPABILITIES deviceCaps;
+
+ if (SDL_XInput_GetDeviceCapabilities(device_index, &deviceCaps) != 0) {
+ /* Uh oh. Device capabilities couldn't be retrieved. Return to the
+ caller. SDL_SetError() has already been invoked (with relevant
+ information).
+ */
+ return NULL;
+ }
+
+ switch (deviceCaps.SubType) {
+ default:
+ if (deviceCaps.Type == XINPUT_DEVTYPE_GAMEPAD) {
+ return "Undefined game controller";
+ } else {
+ return "Undefined controller";
+ }
+ case XINPUT_DEVSUBTYPE_UNKNOWN:
+ if (deviceCaps.Type == XINPUT_DEVTYPE_GAMEPAD) {
+ return "Unknown game controller";
+ } else {
+ return "Unknown controller";
+ }
+ case XINPUT_DEVSUBTYPE_GAMEPAD:
+ return "Gamepad controller";
+ case XINPUT_DEVSUBTYPE_WHEEL:
+ return "Racing wheel controller";
+ case XINPUT_DEVSUBTYPE_ARCADE_STICK:
+ return "Arcade stick controller";
+ case XINPUT_DEVSUBTYPE_FLIGHT_STICK:
+ return "Flight stick controller";
+ case XINPUT_DEVSUBTYPE_DANCE_PAD:
+ return "Dance pad controller";
+ case XINPUT_DEVSUBTYPE_GUITAR:
+ return "Guitar controller";
+ case XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE:
+ return "Guitar controller, Alternate";
+ case XINPUT_DEVSUBTYPE_GUITAR_BASS:
+ return "Guitar controller, Bass";
+ case XINPUT_DEVSUBTYPE_DRUM_KIT:
+ return "Drum controller";
+ case XINPUT_DEVSUBTYPE_ARCADE_PAD:
+ return "Arcade pad controller";
+ }
+}
+
+/* Function to perform the mapping from device index to the instance id for this index */
+SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
+{
+ return device_index;
+}
+
+/* Function to open a joystick for use.
+ The joystick to open is specified by the index field of the joystick.
+ This should fill the nbuttons and naxes fields of the joystick structure.
+ It returns 0, or -1 if there is an error.
+ */
+int
+SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
+{
+ XINPUT_CAPABILITIES deviceCaps;
+
+ if (SDL_XInput_GetDeviceCapabilities(device_index, &deviceCaps) != 0) {
+ /* Uh oh. Device capabilities couldn't be retrieved. Return to the
+ caller. SDL_SetError() has already been invoked (with relevant
+ information).
+ */
+ return -1;
+ }
+
+ /* For now, only game pads are supported. If the device is something other
+ than that, return an error to the caller.
+ */
+ if (deviceCaps.Type != XINPUT_DEVTYPE_GAMEPAD) {
+ return SDL_SetError("a device is connected (at joystick index, %d), but it is of an unknown device type (deviceCaps.Flags=%ul)",
+ device_index, (unsigned int)deviceCaps.Flags);
+ }
+
+ /* Create the joystick data structure */
+ joystick->instance_id = device_index;
+ joystick->hwdata = &g_XInputData[device_index];
+
+ // The XInput API has a hard coded button/axis mapping, so we just match it
+ joystick->naxes = 6;
+ joystick->nbuttons = 15;
+ joystick->nballs = 0;
+ joystick->nhats = 0;
+
+ /* We're done! */
+ return (0);
+}
+
+/* Function to determine is this joystick is attached to the system right now */
+SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
+{
+ return joystick->hwdata->isDeviceConnected;
+}
+
+/* Function to return > 0 if a bit array of buttons differs after applying a mask
+*/
+static int ButtonChanged( int ButtonsNow, int ButtonsPrev, int ButtonMask )
+{
+ return ( ButtonsNow & ButtonMask ) != ( ButtonsPrev & ButtonMask );
+}
+
+/* Function to update the state of a joystick - called as a device poll.
+ * This function shouldn't update the joystick structure directly,
+ * but instead should call SDL_PrivateJoystick*() to deliver events
+ * and update joystick device state.
+ */
+void
+SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
+{
+ HRESULT result;
+
+ /* Before polling for new data, make note of the old data */
+ XINPUT_STATE prevXInputState = joystick->hwdata->XInputState;
+
+ /* Poll for new data */
+ result = XInputGetState(joystick->hwdata->userIndex, &joystick->hwdata->XInputState);
+ if (result == ERROR_DEVICE_NOT_CONNECTED) {
+ if (joystick->hwdata->isDeviceConnected) {
+ joystick->hwdata->isDeviceConnected = SDL_FALSE;
+ joystick->hwdata->isDeviceRemovalEventPending = SDL_TRUE;
+ /* TODO, WinRT: make sure isDeviceRemovalEventPending gets cleared as appropriate, and that quick re-plugs don't cause trouble */
+ }
+ return;
+ }
+
+ /* Make sure the device is marked as connected */
+ joystick->hwdata->isDeviceConnected = SDL_TRUE;
+
+ // only fire events if the data changed from last time
+ if ( joystick->hwdata->XInputState.dwPacketNumber != 0
+ && joystick->hwdata->XInputState.dwPacketNumber != prevXInputState.dwPacketNumber )
+ {
+ XINPUT_STATE *pXInputState = &joystick->hwdata->XInputState;
+ XINPUT_STATE *pXInputStatePrev = &prevXInputState;
+
+ SDL_PrivateJoystickAxis(joystick, 0, (Sint16)pXInputState->Gamepad.sThumbLX );
+ SDL_PrivateJoystickAxis(joystick, 1, (Sint16)(-1*pXInputState->Gamepad.sThumbLY-1) );
+ SDL_PrivateJoystickAxis(joystick, 2, (Sint16)pXInputState->Gamepad.sThumbRX );
+ SDL_PrivateJoystickAxis(joystick, 3, (Sint16)(-1*pXInputState->Gamepad.sThumbRY-1) );
+ SDL_PrivateJoystickAxis(joystick, 4, (Sint16)((int)pXInputState->Gamepad.bLeftTrigger*32767/255) );
+ SDL_PrivateJoystickAxis(joystick, 5, (Sint16)((int)pXInputState->Gamepad.bRightTrigger*32767/255) );
+
+ if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_UP ) )
+ SDL_PrivateJoystickButton(joystick, 0, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_UP ? SDL_PRESSED : SDL_RELEASED );
+ if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_DOWN ) )
+ SDL_PrivateJoystickButton(joystick, 1, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_DOWN ? SDL_PRESSED : SDL_RELEASED );
+ if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_LEFT ) )
+ SDL_PrivateJoystickButton(joystick, 2, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_LEFT ? SDL_PRESSED : SDL_RELEASED );
+ if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_DPAD_RIGHT ) )
+ SDL_PrivateJoystickButton(joystick, 3, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_DPAD_RIGHT ? SDL_PRESSED : SDL_RELEASED );
+ if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_START ) )
+ SDL_PrivateJoystickButton(joystick, 4, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_START ? SDL_PRESSED : SDL_RELEASED );
+ if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_BACK ) )
+ SDL_PrivateJoystickButton(joystick, 5, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_BACK ? SDL_PRESSED : SDL_RELEASED );
+ if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_THUMB ) )
+ SDL_PrivateJoystickButton(joystick, 6, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_THUMB ? SDL_PRESSED : SDL_RELEASED );
+ if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_THUMB ) )
+ SDL_PrivateJoystickButton(joystick, 7, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_THUMB ? SDL_PRESSED : SDL_RELEASED );
+ if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_LEFT_SHOULDER ) )
+ SDL_PrivateJoystickButton(joystick, 8, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_LEFT_SHOULDER ? SDL_PRESSED : SDL_RELEASED );
+ if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_RIGHT_SHOULDER ) )
+ SDL_PrivateJoystickButton(joystick, 9, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_RIGHT_SHOULDER ? SDL_PRESSED : SDL_RELEASED );
+ if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_A ) )
+ SDL_PrivateJoystickButton(joystick, 10, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_A ? SDL_PRESSED : SDL_RELEASED );
+ if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_B ) )
+ SDL_PrivateJoystickButton(joystick, 11, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_B ? SDL_PRESSED : SDL_RELEASED );
+ if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_X ) )
+ SDL_PrivateJoystickButton(joystick, 12, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_X ? SDL_PRESSED : SDL_RELEASED );
+ if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, XINPUT_GAMEPAD_Y ) )
+ SDL_PrivateJoystickButton(joystick, 13, pXInputState->Gamepad.wButtons & XINPUT_GAMEPAD_Y ? SDL_PRESSED : SDL_RELEASED );
+ if ( ButtonChanged( pXInputState->Gamepad.wButtons, pXInputStatePrev->Gamepad.wButtons, 0x400 ) )
+ SDL_PrivateJoystickButton(joystick, 14, pXInputState->Gamepad.wButtons & 0x400 ? SDL_PRESSED : SDL_RELEASED ); // 0x400 is the undocumented code for the guide button
+ }
+}
+
+/* Function to close a joystick after use */
+void
+SDL_SYS_JoystickClose(SDL_Joystick * joystick)
+{
+ /* Clear cached button data on the joystick */
+ SDL_zero(joystick->hwdata->XInputState);
+
+ /* There's need to free 'hwdata', as it's a pointer to a global array.
+ The field will be cleared anyways, just to indicate that it's not
+ currently needed.
+ */
+ joystick->hwdata = NULL;
+}
+
+/* Function to perform any system-specific joystick related cleanup */
+void
+SDL_SYS_JoystickQuit(void)
+{
+ return;
+}
+
+SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
+{
+ SDL_JoystickGUID guid;
+ // the GUID is just the first 16 chars of the name for now
+ const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index );
+ SDL_zero( guid );
+ SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
+ return guid;
+}
+
+
+SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
+{
+ SDL_JoystickGUID guid;
+ // the GUID is just the first 16 chars of the name for now
+ const char *name = joystick->name;
+ SDL_zero( guid );
+ SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
+ return guid;
+}
+
+SDL_bool SDL_SYS_IsXInputDeviceIndex(int device_index)
+{
+ /* The XInput-capable DirectInput joystick backend implements the same
+ function (SDL_SYS_IsXInputDeviceIndex), however in that case, not all
+ joystick devices are XInput devices. In this case, with the
+ WinRT-enabled XInput-only backend, all "joystick" devices are XInput
+ devices.
+ */
+ return SDL_TRUE;
+}
+
+#endif /* SDL_JOYSTICK_XINPUT */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/loadso/windows/SDL_sysloadso.c b/src/loadso/windows/SDL_sysloadso.c
index 21e7a6c54..44506ecd0 100644
--- a/src/loadso/windows/SDL_sysloadso.c
+++ b/src/loadso/windows/SDL_sysloadso.c
@@ -33,7 +33,15 @@ void *
SDL_LoadObject(const char *sofile)
{
LPTSTR tstr = WIN_UTF8ToString(sofile);
+#ifdef __WINRT__
+ /* WinRT only publically supports LoadPackagedLibrary() for loading .dll
+ files. LoadLibrary() is a private API, and not available for apps
+ (that can be published to MS' Windows Store.)
+ */
+ void *handle = (void *) LoadPackagedLibrary(tstr, 0);
+#else
void *handle = (void *) LoadLibrary(tstr);
+#endif
SDL_free(tstr);
/* Generate an error message if all loads failed */
diff --git a/src/main/windowsrt/SDL_winrt_main.cpp b/src/main/windowsrt/SDL_winrt_main.cpp
new file mode 100644
index 000000000..9cc046de5
--- /dev/null
+++ b/src/main/windowsrt/SDL_winrt_main.cpp
@@ -0,0 +1,14 @@
+
+//#include "pch.h"
+
+// The app's C-style main will be passed into SDL.dll as a function
+// pointer, and called at the appropriate time.
+typedef int (*SDLmain_MainFunction)(int, char **);
+extern __declspec(dllimport) int SDL_WinRT_RunApplication(SDLmain_MainFunction mainFunction);
+extern "C" int SDL_main(int, char **);
+
+[Platform::MTAThread]
+int main(Platform::Array^)
+{
+ return SDL_WinRT_RunApplication(SDL_main);
+}
diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h
index f06ee1d80..10504654f 100644
--- a/src/render/SDL_sysrender.h
+++ b/src/render/SDL_sysrender.h
@@ -166,6 +166,9 @@ struct SDL_RenderDriver
#if SDL_VIDEO_RENDER_D3D
extern SDL_RenderDriver D3D_RenderDriver;
#endif
+#if SDL_VIDEO_RENDER_D3D11
+extern SDL_RenderDriver D3D11_RenderDriver;
+#endif
#if SDL_VIDEO_RENDER_OGL
extern SDL_RenderDriver GL_RenderDriver;
#endif
diff --git a/src/render/direct3d11/SDL_D3D11_PixelShader_FixedColor.hlsl b/src/render/direct3d11/SDL_D3D11_PixelShader_FixedColor.hlsl
new file mode 100644
index 000000000..84de709f5
--- /dev/null
+++ b/src/render/direct3d11/SDL_D3D11_PixelShader_FixedColor.hlsl
@@ -0,0 +1,12 @@
+
+struct PixelShaderInput
+{
+ float4 pos : SV_POSITION;
+ float2 tex : TEXCOORD0;
+ float4 color : COLOR0;
+};
+
+float4 main(PixelShaderInput input) : SV_TARGET
+{
+ return input.color;
+}
diff --git a/src/render/direct3d11/SDL_D3D11_PixelShader_TextureColored.hlsl b/src/render/direct3d11/SDL_D3D11_PixelShader_TextureColored.hlsl
new file mode 100644
index 000000000..503b4fdcb
--- /dev/null
+++ b/src/render/direct3d11/SDL_D3D11_PixelShader_TextureColored.hlsl
@@ -0,0 +1,14 @@
+Texture2D theTexture : register(t0);
+SamplerState theSampler : register(s0);
+
+struct PixelShaderInput
+{
+ float4 pos : SV_POSITION;
+ float2 tex : TEXCOORD0;
+ float4 color : COLOR0;
+};
+
+float4 main(PixelShaderInput input) : SV_TARGET
+{
+ return theTexture.Sample(theSampler, input.tex) * input.color;
+}
diff --git a/src/render/direct3d11/SDL_D3D11_VertexShader_Default.hlsl b/src/render/direct3d11/SDL_D3D11_VertexShader_Default.hlsl
new file mode 100644
index 000000000..b5cac4fa9
--- /dev/null
+++ b/src/render/direct3d11/SDL_D3D11_VertexShader_Default.hlsl
@@ -0,0 +1,41 @@
+
+#pragma pack_matrix( row_major )
+
+cbuffer SDL_VertexShaderConstants : register(b0)
+{
+ matrix model;
+ matrix view;
+ matrix projection;
+};
+
+struct VertexShaderInput
+{
+ float3 pos : POSITION;
+ float2 tex : TEXCOORD0;
+ float4 color : COLOR0;
+};
+
+struct VertexShaderOutput
+{
+ float4 pos : SV_POSITION;
+ float2 tex : TEXCOORD0;
+ float4 color : COLOR0;
+};
+
+VertexShaderOutput main(VertexShaderInput input)
+{
+ VertexShaderOutput output;
+ float4 pos = float4(input.pos, 1.0f);
+
+ // Transform the vertex position into projected space.
+ pos = mul(pos, model);
+ pos = mul(pos, view);
+ pos = mul(pos, projection);
+ output.pos = pos;
+
+ // Pass through texture coordinates and color values without transformation
+ output.tex = input.tex;
+ output.color = input.color;
+
+ return output;
+}
diff --git a/src/render/direct3d11/SDL_render_d3d11.cpp b/src/render/direct3d11/SDL_render_d3d11.cpp
new file mode 100644
index 000000000..ed741c278
--- /dev/null
+++ b/src/render/direct3d11/SDL_render_d3d11.cpp
@@ -0,0 +1,1807 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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"
+
+#if SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED
+
+#ifdef __WINRT__
+#include
+#include
+#endif
+
+extern "C" {
+#include "../../core/windows/SDL_windows.h"
+//#include "SDL_hints.h"
+//#include "SDL_loadso.h"
+#include "SDL_system.h"
+#include "SDL_syswm.h"
+#include "../SDL_sysrender.h"
+#include "SDL_log.h"
+#include "../../video/SDL_sysvideo.h"
+//#include "stdio.h"
+}
+
+#include
+#include
+#include
+
+#include "SDL_render_d3d11_cpp.h"
+
+using namespace DirectX;
+using namespace Microsoft::WRL;
+using namespace std;
+
+#ifdef __WINRT__
+using namespace Windows::Graphics::Display;
+using namespace Windows::UI::Core;
+#endif
+
+/* Direct3D 11.1 renderer implementation */
+
+static SDL_Renderer *D3D11_CreateRenderer(SDL_Window * window, Uint32 flags);
+static void D3D11_WindowEvent(SDL_Renderer * renderer,
+ const SDL_WindowEvent *event);
+static int D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
+static int D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
+ const SDL_Rect * rect, const void *srcPixels,
+ int srcPitch);
+static int D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
+ const SDL_Rect * rect, void **pixels, int *pitch);
+static void D3D11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
+static int D3D11_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
+static int D3D11_UpdateViewport(SDL_Renderer * renderer);
+static int D3D11_RenderClear(SDL_Renderer * renderer);
+static int D3D11_RenderDrawPoints(SDL_Renderer * renderer,
+ const SDL_FPoint * points, int count);
+static int D3D11_RenderDrawLines(SDL_Renderer * renderer,
+ const SDL_FPoint * points, int count);
+static int D3D11_RenderFillRects(SDL_Renderer * renderer,
+ const SDL_FRect * rects, int count);
+static int D3D11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect);
+static int D3D11_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect,
+ const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip);
+static int D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
+ Uint32 format, void * pixels, int pitch);
+static void D3D11_RenderPresent(SDL_Renderer * renderer);
+static void D3D11_DestroyTexture(SDL_Renderer * renderer,
+ SDL_Texture * texture);
+static void D3D11_DestroyRenderer(SDL_Renderer * renderer);
+
+/* Direct3D 11.1 Internal Functions */
+HRESULT D3D11_CreateDeviceResources(SDL_Renderer * renderer);
+HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer);
+HRESULT D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer);
+HRESULT D3D11_HandleDeviceLost(SDL_Renderer * renderer);
+
+extern "C" SDL_RenderDriver D3D11_RenderDriver = {
+ D3D11_CreateRenderer,
+ {
+ "direct3d 11.1",
+ (
+ SDL_RENDERER_ACCELERATED |
+ SDL_RENDERER_PRESENTVSYNC |
+ SDL_RENDERER_TARGETTEXTURE
+ ), // flags. see SDL_RendererFlags
+ 2, // num_texture_formats
+ { // texture_formats
+ SDL_PIXELFORMAT_RGB888,
+ SDL_PIXELFORMAT_ARGB8888
+ },
+ 0, // max_texture_width: will be filled in later
+ 0 // max_texture_height: will be filled in later
+ }
+};
+
+
+static Uint32
+DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat) {
+ switch (dxgiFormat) {
+ case DXGI_FORMAT_B8G8R8A8_UNORM:
+ return SDL_PIXELFORMAT_ARGB8888;
+ case DXGI_FORMAT_B8G8R8X8_UNORM:
+ return SDL_PIXELFORMAT_RGB888;
+ default:
+ return SDL_PIXELFORMAT_UNKNOWN;
+ }
+}
+
+static DXGI_FORMAT
+SDLPixelFormatToDXGIFormat(Uint32 sdlFormat)
+{
+ switch (sdlFormat) {
+ case SDL_PIXELFORMAT_ARGB8888:
+ return DXGI_FORMAT_B8G8R8A8_UNORM;
+ case SDL_PIXELFORMAT_RGB888:
+ return DXGI_FORMAT_B8G8R8X8_UNORM;
+ default:
+ return DXGI_FORMAT_UNKNOWN;
+ }
+}
+
+
+//typedef struct
+//{
+// float x, y, z;
+// DWORD color;
+// float u, v;
+//} Vertex;
+
+SDL_Renderer *
+D3D11_CreateRenderer(SDL_Window * window, Uint32 flags)
+{
+ SDL_Renderer *renderer;
+ D3D11_RenderData *data;
+
+ renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
+ if (!renderer) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+ SDL_zerop(renderer);
+
+ data = new D3D11_RenderData; // Use the C++ 'new' operator to make sure the struct's members initialize using C++ rules
+ if (!data) {
+ SDL_OutOfMemory();
+ return NULL;
+ }
+ data->featureLevel = (D3D_FEATURE_LEVEL) 0;
+ data->windowSizeInDIPs = XMFLOAT2(0, 0);
+ data->renderTargetSize = XMFLOAT2(0, 0);
+
+ renderer->WindowEvent = D3D11_WindowEvent;
+ renderer->CreateTexture = D3D11_CreateTexture;
+ renderer->UpdateTexture = D3D11_UpdateTexture;
+ renderer->LockTexture = D3D11_LockTexture;
+ renderer->UnlockTexture = D3D11_UnlockTexture;
+ renderer->SetRenderTarget = D3D11_SetRenderTarget;
+ renderer->UpdateViewport = D3D11_UpdateViewport;
+ renderer->RenderClear = D3D11_RenderClear;
+ renderer->RenderDrawPoints = D3D11_RenderDrawPoints;
+ renderer->RenderDrawLines = D3D11_RenderDrawLines;
+ renderer->RenderFillRects = D3D11_RenderFillRects;
+ renderer->RenderCopy = D3D11_RenderCopy;
+ renderer->RenderCopyEx = D3D11_RenderCopyEx;
+ renderer->RenderReadPixels = D3D11_RenderReadPixels;
+ renderer->RenderPresent = D3D11_RenderPresent;
+ renderer->DestroyTexture = D3D11_DestroyTexture;
+ renderer->DestroyRenderer = D3D11_DestroyRenderer;
+ renderer->info = D3D11_RenderDriver.info;
+ renderer->driverdata = data;
+
+ // HACK: make sure the SDL_Renderer references the SDL_Window data now, in
+ // order to give init functions access to the underlying window handle:
+ renderer->window = window;
+
+ /* Initialize Direct3D resources */
+ if (FAILED(D3D11_CreateDeviceResources(renderer))) {
+ D3D11_DestroyRenderer(renderer);
+ return NULL;
+ }
+ if (FAILED(D3D11_CreateWindowSizeDependentResources(renderer))) {
+ D3D11_DestroyRenderer(renderer);
+ return NULL;
+ }
+
+ // TODO, WinRT: fill in renderer->info.texture_formats where appropriate
+
+ return renderer;
+}
+
+static void
+D3D11_DestroyRenderer(SDL_Renderer * renderer)
+{
+ D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
+ if (data) {
+ delete data;
+ data = NULL;
+ }
+}
+
+static bool
+D3D11_ReadFileContents(const wstring & fileName, vector & out)
+{
+ ifstream in(fileName, ios::in | ios::binary);
+ if (!in) {
+ return false;
+ }
+
+ in.seekg(0, ios::end);
+ out.resize((size_t) in.tellg());
+ in.seekg(0, ios::beg);
+ in.read(&out[0], out.size());
+ return in.good();
+}
+
+static bool
+D3D11_ReadShaderContents(const wstring & shaderName, vector & out)
+{
+ wstring fileName;
+
+#if WINAPI_FAMILY == WINAPI_FAMILY_APP
+ fileName = SDL_WinRTGetFSPathUNICODE(SDL_WINRT_PATH_INSTALLED_LOCATION);
+ fileName += L"\\SDL_VS2012_WinRT\\";
+#elif WINAPI_FAMILY == WINAPI_PHONE_APP
+ fileName = SDL_WinRTGetFSPathUNICODE(SDL_WINRT_PATH_INSTALLED_LOCATION);
+ fileName += L"\\";
+#endif
+ // WinRT, TODO: test Direct3D 11.1 shader loading on Win32
+ fileName += shaderName;
+ return D3D11_ReadFileContents(fileName, out);
+}
+
+static HRESULT
+D3D11_LoadPixelShader(SDL_Renderer * renderer,
+ const wstring & shaderName,
+ ID3D11PixelShader ** shaderOutput)
+{
+ D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
+ HRESULT result = S_OK;
+ vector fileData;
+
+ if (!D3D11_ReadShaderContents(shaderName, fileData)) {
+ SDL_SetError("Unable to open SDL's pixel shader file.");
+ return E_FAIL;
+ }
+
+ result = data->d3dDevice->CreatePixelShader(
+ &fileData[0],
+ fileData.size(),
+ nullptr,
+ shaderOutput
+ );
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+
+ return S_OK;
+}
+
+static HRESULT
+D3D11_CreateBlendMode(SDL_Renderer * renderer,
+ BOOL enableBlending,
+ D3D11_BLEND srcBlend,
+ D3D11_BLEND destBlend,
+ ID3D11BlendState ** blendStateOutput)
+{
+ D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
+ HRESULT result = S_OK;
+
+ D3D11_BLEND_DESC blendDesc;
+ memset(&blendDesc, 0, sizeof(blendDesc));
+ blendDesc.AlphaToCoverageEnable = FALSE;
+ blendDesc.IndependentBlendEnable = FALSE;
+ blendDesc.RenderTarget[0].BlendEnable = enableBlending;
+ blendDesc.RenderTarget[0].SrcBlend = srcBlend;
+ blendDesc.RenderTarget[0].DestBlend = destBlend;
+ blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
+ blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
+ blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
+ blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
+ result = data->d3dDevice->CreateBlendState(&blendDesc, blendStateOutput);
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+
+ return S_OK;
+}
+
+// Create resources that depend on the device.
+HRESULT
+D3D11_CreateDeviceResources(SDL_Renderer * renderer)
+{
+ D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
+
+ // This flag adds support for surfaces with a different color channel ordering
+ // than the API default. It is required for compatibility with Direct2D.
+ UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
+
+#if defined(_DEBUG)
+ // If the project is in a debug build, enable debugging via SDK Layers with this flag.
+ creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
+#endif
+
+ // This array defines the set of DirectX hardware feature levels this app will support.
+ // Note the ordering should be preserved.
+ // Don't forget to declare your application's minimum required feature level in its
+ // description. All applications are assumed to support 9.1 unless otherwise stated.
+ D3D_FEATURE_LEVEL featureLevels[] =
+ {
+ D3D_FEATURE_LEVEL_11_1,
+ D3D_FEATURE_LEVEL_11_0,
+ D3D_FEATURE_LEVEL_10_1,
+ D3D_FEATURE_LEVEL_10_0,
+ D3D_FEATURE_LEVEL_9_3,
+ D3D_FEATURE_LEVEL_9_2,
+ D3D_FEATURE_LEVEL_9_1
+ };
+
+ // Create the Direct3D 11 API device object and a corresponding context.
+ ComPtr device;
+ ComPtr context;
+ HRESULT result = S_OK;
+ result = D3D11CreateDevice(
+ nullptr, // Specify nullptr to use the default adapter.
+ D3D_DRIVER_TYPE_HARDWARE,
+ nullptr,
+ creationFlags, // Set set debug and Direct2D compatibility flags.
+ featureLevels, // List of feature levels this app can support.
+ ARRAYSIZE(featureLevels),
+ D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps.
+ &device, // Returns the Direct3D device created.
+ &data->featureLevel, // Returns feature level of device created.
+ &context // Returns the device immediate context.
+ );
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+
+ // Get the Direct3D 11.1 API device and context interfaces.
+ Microsoft::WRL::ComPtr d3dDevice1;
+ result = device.As(&(data->d3dDevice));
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+
+ result = context.As(&data->d3dContext);
+ if (FAILED(result)) {
+ return result;
+ }
+
+ //
+ // Make note of the maximum texture size
+ // Max texture sizes are documented on MSDN, at:
+ // http://msdn.microsoft.com/en-us/library/windows/apps/ff476876.aspx
+ //
+ switch (data->d3dDevice->GetFeatureLevel()) {
+ case D3D_FEATURE_LEVEL_11_1:
+ case D3D_FEATURE_LEVEL_11_0:
+ renderer->info.max_texture_width = renderer->info.max_texture_height = 16384;
+ break;
+
+ case D3D_FEATURE_LEVEL_10_1:
+ case D3D_FEATURE_LEVEL_10_0:
+ renderer->info.max_texture_width = renderer->info.max_texture_height = 8192;
+ break;
+
+ case D3D_FEATURE_LEVEL_9_3:
+ renderer->info.max_texture_width = renderer->info.max_texture_height = 4096;
+ break;
+
+ case D3D_FEATURE_LEVEL_9_2:
+ case D3D_FEATURE_LEVEL_9_1:
+ renderer->info.max_texture_width = renderer->info.max_texture_height = 2048;
+ break;
+ }
+
+ //
+ // Load in SDL's one and only vertex shader:
+ //
+ vector fileData;
+ if (!D3D11_ReadShaderContents(L"SDL_D3D11_VertexShader_Default.cso", fileData)) {
+ SDL_SetError("Unable to open SDL's vertex shader file.");
+ return E_FAIL;
+ }
+
+ result = data->d3dDevice->CreateVertexShader(
+ &fileData[0],
+ fileData.size(),
+ nullptr,
+ &data->vertexShader
+ );
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+
+ //
+ // Create an input layout for SDL's vertex shader:
+ //
+ const D3D11_INPUT_ELEMENT_DESC vertexDesc[] =
+ {
+ { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ };
+
+ result = data->d3dDevice->CreateInputLayout(
+ vertexDesc,
+ ARRAYSIZE(vertexDesc),
+ &fileData[0],
+ fileData.size(),
+ &data->inputLayout
+ );
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+
+ //
+ // Load in SDL's pixel shaders
+ //
+ result = D3D11_LoadPixelShader(renderer, L"SDL_D3D11_PixelShader_TextureColored.cso", &data->texturePixelShader);
+ if (FAILED(result)) {
+ // D3D11_LoadPixelShader will have aleady set the SDL error
+ return result;
+ }
+
+ result = D3D11_LoadPixelShader(renderer, L"SDL_D3D11_PixelShader_FixedColor.cso", &data->colorPixelShader);
+ if (FAILED(result)) {
+ // D3D11_LoadPixelShader will have aleady set the SDL error
+ return result;
+ }
+
+ //
+ // Setup space to hold vertex shader constants:
+ //
+ CD3D11_BUFFER_DESC constantBufferDesc(sizeof(SDL_VertexShaderConstants), D3D11_BIND_CONSTANT_BUFFER);
+ result = data->d3dDevice->CreateBuffer(
+ &constantBufferDesc,
+ nullptr,
+ &data->vertexShaderConstants
+ );
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+
+ //
+ // Make sure that the vertex buffer, if already created, gets freed.
+ // It will be recreated later.
+ //
+ data->vertexBuffer = nullptr;
+
+ //
+ // Create a sampler to use when drawing textures:
+ //
+ D3D11_SAMPLER_DESC samplerDesc;
+ samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
+ samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
+ samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
+ samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
+ samplerDesc.MipLODBias = 0.0f;
+ samplerDesc.MaxAnisotropy = 1;
+ samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
+ samplerDesc.BorderColor[0] = 0.0f;
+ samplerDesc.BorderColor[1] = 0.0f;
+ samplerDesc.BorderColor[2] = 0.0f;
+ samplerDesc.BorderColor[3] = 0.0f;
+ samplerDesc.MinLOD = 0.0f;
+ samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
+ result = data->d3dDevice->CreateSamplerState(
+ &samplerDesc,
+ &data->mainSampler
+ );
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+
+ //
+ // Setup the Direct3D rasterizer
+ //
+ D3D11_RASTERIZER_DESC rasterDesc;
+ memset(&rasterDesc, 0, sizeof(rasterDesc));
+ rasterDesc.AntialiasedLineEnable = false;
+ rasterDesc.CullMode = D3D11_CULL_NONE;
+ rasterDesc.DepthBias = 0;
+ rasterDesc.DepthBiasClamp = 0.0f;
+ rasterDesc.DepthClipEnable = true;
+ rasterDesc.FillMode = D3D11_FILL_SOLID;
+ rasterDesc.FrontCounterClockwise = false;
+ rasterDesc.MultisampleEnable = false;
+ rasterDesc.ScissorEnable = false;
+ rasterDesc.SlopeScaledDepthBias = 0.0f;
+ result = data->d3dDevice->CreateRasterizerState(&rasterDesc, &data->mainRasterizer);
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+
+ //
+ // Create blending states:
+ //
+ result = D3D11_CreateBlendMode(
+ renderer,
+ TRUE,
+ D3D11_BLEND_SRC_ALPHA,
+ D3D11_BLEND_INV_SRC_ALPHA,
+ &data->blendModeBlend);
+ if (FAILED(result)) {
+ // D3D11_CreateBlendMode will set the SDL error, if it fails
+ return result;
+ }
+
+ result = D3D11_CreateBlendMode(
+ renderer,
+ TRUE,
+ D3D11_BLEND_SRC_ALPHA,
+ D3D11_BLEND_ONE,
+ &data->blendModeAdd);
+ if (FAILED(result)) {
+ // D3D11_CreateBlendMode will set the SDL error, if it fails
+ return result;
+ }
+
+ result = D3D11_CreateBlendMode(
+ renderer,
+ TRUE,
+ D3D11_BLEND_ZERO,
+ D3D11_BLEND_SRC_COLOR,
+ &data->blendModeMod);
+ if (FAILED(result)) {
+ // D3D11_CreateBlendMode will set the SDL error, if it fails
+ return result;
+ }
+
+ //
+ // All done!
+ //
+ return S_OK;
+}
+
+#ifdef __WINRT__
+
+static ABI::Windows::UI::Core::ICoreWindow *
+D3D11_GetCoreWindowFromSDLRenderer(SDL_Renderer * renderer)
+{
+ SDL_Window * sdlWindow = renderer->window;
+ if ( ! renderer->window ) {
+ return nullptr;
+ }
+
+ SDL_SysWMinfo sdlWindowInfo;
+ SDL_VERSION(&sdlWindowInfo.version);
+ if ( ! SDL_GetWindowWMInfo(sdlWindow, &sdlWindowInfo) ) {
+ return nullptr;
+ }
+
+ if (sdlWindowInfo.subsystem != SDL_SYSWM_WINDOWSRT) {
+ return nullptr;
+ }
+
+ if ( ! sdlWindowInfo.info.winrt.window ) {
+ return nullptr;
+ }
+
+ ABI::Windows::UI::Core::ICoreWindow * coreWindow = nullptr;
+ if (FAILED(sdlWindowInfo.info.winrt.window->QueryInterface(&coreWindow))) {
+ return nullptr;
+ }
+
+ return coreWindow;
+}
+
+// Method to convert a length in device-independent pixels (DIPs) to a length in physical pixels.
+static float
+D3D11_ConvertDipsToPixels(float dips)
+{
+ static const float dipsPerInch = 96.0f;
+ return floor(dips * DisplayProperties::LogicalDpi / dipsPerInch + 0.5f); // Round to nearest integer.
+}
+#endif
+
+// Initialize all resources that change when the window's size changes.
+// WinRT, TODO: get D3D11_CreateWindowSizeDependentResources working on Win32
+HRESULT
+D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer)
+{
+ D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
+ HRESULT result = S_OK;
+ ABI::Windows::UI::Core::ICoreWindow * coreWindow = D3D11_GetCoreWindowFromSDLRenderer(renderer);
+
+ // Store the window bounds so the next time we get a SizeChanged event we can
+ // avoid rebuilding everything if the size is identical.
+ ABI::Windows::Foundation::Rect coreWindowBounds;
+ result = coreWindow->get_Bounds(&coreWindowBounds);
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__", Get Window Bounds", result);
+ return result;
+ }
+
+ data->windowSizeInDIPs.x = coreWindowBounds.Width;
+ data->windowSizeInDIPs.y = coreWindowBounds.Height;
+
+ // Calculate the necessary swap chain and render target size in pixels.
+ float windowWidth = D3D11_ConvertDipsToPixels(data->windowSizeInDIPs.x);
+ float windowHeight = D3D11_ConvertDipsToPixels(data->windowSizeInDIPs.y);
+
+ // The width and height of the swap chain must be based on the window's
+ // landscape-oriented width and height. If the window is in a portrait
+ // orientation, the dimensions must be reversed.
+ data->orientation = DisplayProperties::CurrentOrientation;
+ const bool swapDimensions =
+ data->orientation == DisplayOrientations::Portrait ||
+ data->orientation == DisplayOrientations::PortraitFlipped;
+ data->renderTargetSize.x = swapDimensions ? windowHeight : windowWidth;
+ data->renderTargetSize.y = swapDimensions ? windowWidth : windowHeight;
+
+ if(data->swapChain != nullptr)
+ {
+ // If the swap chain already exists, resize it.
+ result = data->swapChain->ResizeBuffers(
+ 2, // Double-buffered swap chain.
+ static_cast(data->renderTargetSize.x),
+ static_cast(data->renderTargetSize.y),
+ DXGI_FORMAT_B8G8R8A8_UNORM,
+ 0
+ );
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+ }
+ else
+ {
+ // Otherwise, create a new one using the same adapter as the existing Direct3D device.
+ DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
+ swapChainDesc.Width = static_cast(data->renderTargetSize.x); // Match the size of the window.
+ swapChainDesc.Height = static_cast(data->renderTargetSize.y);
+ swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format.
+ swapChainDesc.Stereo = false;
+ swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling.
+ swapChainDesc.SampleDesc.Quality = 0;
+ swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
+ swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency.
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+ swapChainDesc.Scaling = DXGI_SCALING_STRETCH; // On phone, only stretch and aspect-ratio stretch scaling are allowed.
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // On phone, no swap effects are supported.
+#else
+ swapChainDesc.Scaling = DXGI_SCALING_NONE;
+ swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this SwapEffect.
+#endif
+ swapChainDesc.Flags = 0;
+
+ ComPtr dxgiDevice;
+ result = data->d3dDevice.As(&dxgiDevice);
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+
+ ComPtr dxgiAdapter;
+ result = dxgiDevice->GetAdapter(&dxgiAdapter);
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+
+ ComPtr dxgiFactory;
+ result = dxgiAdapter->GetParent(
+ __uuidof(IDXGIFactory2),
+ &dxgiFactory
+ );
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+
+ IUnknown * coreWindowAsIUnknown = nullptr;
+ result = coreWindow->QueryInterface(&coreWindowAsIUnknown);
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__ ", CoreWindow to IUnknown", result);
+ return result;
+ }
+
+ result = dxgiFactory->CreateSwapChainForCoreWindow(
+ data->d3dDevice.Get(),
+ coreWindowAsIUnknown,
+ &swapChainDesc,
+ nullptr, // Allow on all displays.
+ &data->swapChain
+ );
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+
+ // Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and
+ // ensures that the application will only render after each VSync, minimizing power consumption.
+ result = dxgiDevice->SetMaximumFrameLatency(1);
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+ }
+
+ // Set the proper orientation for the swap chain, and generate the
+ // 3D matrix transformation for rendering to the rotated swap chain.
+ DXGI_MODE_ROTATION rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
+ switch (data->orientation)
+ {
+ case DisplayOrientations::Landscape:
+ rotation = DXGI_MODE_ROTATION_IDENTITY;
+ break;
+
+ case DisplayOrientations::Portrait:
+ rotation = DXGI_MODE_ROTATION_ROTATE270;
+ break;
+
+ case DisplayOrientations::LandscapeFlipped:
+ rotation = DXGI_MODE_ROTATION_ROTATE180;
+ break;
+
+ case DisplayOrientations::PortraitFlipped:
+ rotation = DXGI_MODE_ROTATION_ROTATE90;
+ break;
+
+ default:
+ throw ref new Platform::FailureException();
+ }
+
+#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
+ // TODO, WinRT: Windows Phone does not have the IDXGISwapChain1::SetRotation method. Check if an alternative is available, or needed.
+ result = data->swapChain->SetRotation(rotation);
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+#endif
+
+ // Create a render target view of the swap chain back buffer.
+ ComPtr backBuffer;
+ result = data->swapChain->GetBuffer(
+ 0,
+ __uuidof(ID3D11Texture2D),
+ &backBuffer
+ );
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+
+ result = data->d3dDevice->CreateRenderTargetView(
+ backBuffer.Get(),
+ nullptr,
+ &data->mainRenderTargetView
+ );
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+
+ if (D3D11_UpdateViewport(renderer) != 0) {
+ // D3D11_UpdateViewport will set the SDL error if it fails.
+ return E_FAIL;
+ }
+
+ return S_OK;
+}
+
+// This method is called when the window's size changes.
+HRESULT
+D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer)
+{
+ D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
+ HRESULT result = S_OK;
+ ABI::Windows::UI::Core::ICoreWindow * coreWindow = D3D11_GetCoreWindowFromSDLRenderer(renderer);
+ ABI::Windows::Foundation::Rect coreWindowBounds;
+
+ result = coreWindow->get_Bounds(&coreWindowBounds);
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__ ", Get Window Bounds", result);
+ return result;
+ }
+
+ if (coreWindowBounds.Width != data->windowSizeInDIPs.x ||
+ coreWindowBounds.Height != data->windowSizeInDIPs.y ||
+ data->orientation != DisplayProperties::CurrentOrientation)
+ {
+ ID3D11RenderTargetView* nullViews[] = {nullptr};
+ data->d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
+ data->mainRenderTargetView = nullptr;
+ data->d3dContext->Flush();
+ result = D3D11_CreateWindowSizeDependentResources(renderer);
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT
+D3D11_HandleDeviceLost(SDL_Renderer * renderer)
+{
+ D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
+ HRESULT result = S_OK;
+
+ // Reset these member variables to ensure that D3D11_UpdateForWindowSizeChange recreates all resources.
+ data->windowSizeInDIPs.x = 0;
+ data->windowSizeInDIPs.y = 0;
+ data->swapChain = nullptr;
+
+ result = D3D11_CreateDeviceResources(renderer);
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+
+ result = D3D11_UpdateForWindowSizeChange(renderer);
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return result;
+ }
+
+ return S_OK;
+}
+
+static void
+D3D11_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
+{
+ //D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
+
+ if (event->event == SDL_WINDOWEVENT_RESIZED) {
+ D3D11_UpdateForWindowSizeChange(renderer);
+ }
+}
+
+static int
+D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
+{
+ D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
+ D3D11_TextureData *textureData;
+ HRESULT result;
+ DXGI_FORMAT textureFormat = SDLPixelFormatToDXGIFormat(texture->format);
+ if (textureFormat == SDL_PIXELFORMAT_UNKNOWN) {
+ SDL_SetError("%s, An unsupported SDL pixel format (0x%x) was specified",
+ __FUNCTION__, texture->format);
+ return -1;
+ }
+
+ textureData = new D3D11_TextureData;
+ if (!textureData) {
+ SDL_OutOfMemory();
+ return -1;
+ }
+ textureData->pixelFormat = SDL_AllocFormat(texture->format);
+ textureData->lockedTexturePosition = XMINT2(0, 0);
+
+ texture->driverdata = textureData;
+
+ D3D11_TEXTURE2D_DESC textureDesc = {0};
+ textureDesc.Width = texture->w;
+ textureDesc.Height = texture->h;
+ textureDesc.MipLevels = 1;
+ textureDesc.ArraySize = 1;
+ textureDesc.Format = textureFormat;
+ textureDesc.SampleDesc.Count = 1;
+ textureDesc.SampleDesc.Quality = 0;
+ textureDesc.MiscFlags = 0;
+
+ if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
+ textureDesc.Usage = D3D11_USAGE_DYNAMIC;
+ textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ } else {
+ textureDesc.Usage = D3D11_USAGE_DEFAULT;
+ textureDesc.CPUAccessFlags = 0;
+ }
+
+ if (texture->access == SDL_TEXTUREACCESS_TARGET) {
+ textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
+ } else {
+ textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ }
+
+#if 0
+ // Fill the texture with a non-black color, for debugging purposes:
+ const int numPixels = textureDesc.Width * textureDesc.Height;
+ const int pixelSizeInBytes = textureData->pixelFormat->BytesPerPixel;
+ std::vector initialTexturePixels(numPixels * pixelSizeInBytes, 0x00);
+ for (int i = 0; i < (numPixels * pixelSizeInBytes); i += pixelSizeInBytes) {
+ initialTexturePixels[i+0] = 0xff;
+ initialTexturePixels[i+1] = 0xff;
+ initialTexturePixels[i+2] = 0x00;
+ initialTexturePixels[i+3] = 0xff;
+ }
+ D3D11_SUBRESOURCE_DATA initialTextureData = {0};
+ initialTextureData.pSysMem = (void *)&(initialTexturePixels[0]);
+ initialTextureData.SysMemPitch = textureDesc.Width * pixelSizeInBytes;
+ initialTextureData.SysMemSlicePitch = numPixels * pixelSizeInBytes;
+#endif
+
+ result = rendererData->d3dDevice->CreateTexture2D(
+ &textureDesc,
+ NULL, // &initialTextureData,
+ &textureData->mainTexture
+ );
+ if (FAILED(result)) {
+ D3D11_DestroyTexture(renderer, texture);
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return -1;
+ }
+
+ if (texture->access & SDL_TEXTUREACCESS_TARGET) {
+ D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;
+ renderTargetViewDesc.Format = textureDesc.Format;
+ renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
+ renderTargetViewDesc.Texture2D.MipSlice = 0;
+
+ result = rendererData->d3dDevice->CreateRenderTargetView(
+ textureData->mainTexture.Get(),
+ &renderTargetViewDesc,
+ &textureData->mainTextureRenderTargetView);
+ if (FAILED(result)) {
+ D3D11_DestroyTexture(renderer, texture);
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return -1;
+ }
+ }
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
+ resourceViewDesc.Format = textureDesc.Format;
+ resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ resourceViewDesc.Texture2D.MostDetailedMip = 0;
+ resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels;
+ result = rendererData->d3dDevice->CreateShaderResourceView(
+ textureData->mainTexture.Get(),
+ &resourceViewDesc,
+ &textureData->mainTextureResourceView
+ );
+ if (FAILED(result)) {
+ D3D11_DestroyTexture(renderer, texture);
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+D3D11_DestroyTexture(SDL_Renderer * renderer,
+ SDL_Texture * texture)
+{
+ D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata;
+
+ if (textureData) {
+ if (textureData->pixelFormat) {
+ SDL_FreeFormat(textureData->pixelFormat);
+ textureData->pixelFormat = NULL;
+ }
+
+ delete textureData;
+ texture->driverdata = NULL;
+ }
+}
+
+static int
+D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
+ const SDL_Rect * rect, const void * srcPixels,
+ int srcPitch)
+{
+ // Lock the texture, retrieving a buffer to write pixel data to:
+ void * destPixels = NULL;
+ int destPitch = 0;
+ if (D3D11_LockTexture(renderer, texture, rect, &destPixels, &destPitch) != 0) {
+ // An error is already set. Attach some info to it, then return to
+ // the caller.
+ std::string errorMessage = string(__FUNCTION__ ", Lock Texture Failed: ") + SDL_GetError();
+ SDL_SetError(errorMessage.c_str());
+ return -1;
+ }
+
+ // Copy pixel data to the locked texture's memory:
+ for (int y = 0; y < rect->h; ++y) {
+ memcpy(
+ ((Uint8 *)destPixels) + (destPitch * y),
+ ((Uint8 *)srcPixels) + (srcPitch * y),
+ srcPitch
+ );
+ }
+
+ // Commit the texture's memory back to Direct3D:
+ D3D11_UnlockTexture(renderer, texture);
+
+ // Return to the caller:
+ return 0;
+}
+
+static int
+D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
+ const SDL_Rect * rect, void **pixels, int *pitch)
+{
+ D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
+ D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata;
+ HRESULT result = S_OK;
+
+ if (textureData->stagingTexture) {
+ SDL_SetError("texture is already locked");
+ return -1;
+ }
+
+ // Create a 'staging' texture, which will be used to write to a portion
+ // of the main texture. This is necessary, as Direct3D 11.1 does not
+ // have the ability to write a CPU-bound pixel buffer to a rectangular
+ // subrect of a texture. Direct3D 11.1 can, however, write a pixel
+ // buffer to an entire texture, hence the use of a staging texture.
+ D3D11_TEXTURE2D_DESC stagingTextureDesc;
+ textureData->mainTexture->GetDesc(&stagingTextureDesc);
+ stagingTextureDesc.Width = rect->w;
+ stagingTextureDesc.Height = rect->h;
+ stagingTextureDesc.BindFlags = 0;
+ stagingTextureDesc.MiscFlags = 0;
+ stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ stagingTextureDesc.Usage = D3D11_USAGE_STAGING;
+ result = rendererData->d3dDevice->CreateTexture2D(
+ &stagingTextureDesc,
+ NULL,
+ &textureData->stagingTexture);
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__ ", Create Staging Texture", result);
+ return -1;
+ }
+
+ // Get a write-only pointer to data in the staging texture:
+ D3D11_MAPPED_SUBRESOURCE textureMemory = {0};
+ result = rendererData->d3dContext->Map(
+ textureData->stagingTexture.Get(),
+ D3D11CalcSubresource(0, 0, 0),
+ D3D11_MAP_WRITE,
+ 0,
+ &textureMemory
+ );
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__ ", Map Staging Texture", result);
+ textureData->stagingTexture = nullptr;
+ return -1;
+ }
+
+ // Make note of where the staging texture will be written to (on a
+ // call to SDL_UnlockTexture):
+ textureData->lockedTexturePosition = XMINT2(rect->x, rect->y);
+
+ // Make sure the caller has information on the texture's pixel buffer,
+ // then return:
+ *pixels = textureMemory.pData;
+ *pitch = textureMemory.RowPitch;
+ return 0;
+}
+
+static void
+D3D11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
+{
+ D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
+ D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata;
+
+ // Commit the pixel buffer's changes back to the staging texture:
+ rendererData->d3dContext->Unmap(
+ textureData->stagingTexture.Get(),
+ 0);
+
+ // Copy the staging texture's contents back to the main texture:
+ rendererData->d3dContext->CopySubresourceRegion(
+ textureData->mainTexture.Get(),
+ D3D11CalcSubresource(0, 0, 0),
+ textureData->lockedTexturePosition.x,
+ textureData->lockedTexturePosition.y,
+ 0,
+ textureData->stagingTexture.Get(),
+ D3D11CalcSubresource(0, 0, 0),
+ NULL);
+
+ // Clean up and return:
+ textureData->stagingTexture = nullptr;
+ textureData->lockedTexturePosition = XMINT2(0, 0);
+}
+
+static int
+D3D11_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
+{
+ D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
+
+ if (texture == NULL) {
+ rendererData->currentOffscreenRenderTargetView = nullptr;
+ return 0;
+ }
+
+ D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata;
+
+ if (!textureData->mainTextureRenderTargetView) {
+ std::string errorMessage = string(__FUNCTION__) + ": specified texture is not a render target";
+ SDL_SetError(errorMessage.c_str());
+ return -1;
+ }
+
+ rendererData->currentOffscreenRenderTargetView = textureData->mainTextureRenderTargetView;
+
+ return 0;
+}
+
+static int
+D3D11_UpdateViewport(SDL_Renderer * renderer)
+{
+ D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
+
+ if (renderer->viewport.w == 0 || renderer->viewport.h == 0) {
+ // If the viewport is empty, assume that it is because
+ // SDL_CreateRenderer is calling it, and will call it again later
+ // with a non-empty viewport.
+ return 0;
+ }
+
+ switch (data->orientation)
+ {
+ case DisplayOrientations::Landscape:
+ data->vertexShaderConstantsData.projection = XMFLOAT4X4( // 0-degree Z-rotation
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ );
+ break;
+
+ case DisplayOrientations::Portrait:
+ data->vertexShaderConstantsData.projection = XMFLOAT4X4( // 90-degree Z-rotation
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ -1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ );
+ break;
+
+ case DisplayOrientations::LandscapeFlipped:
+ data->vertexShaderConstantsData.projection = XMFLOAT4X4( // 180-degree Z-rotation
+ -1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, -1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ );
+ break;
+
+ case DisplayOrientations::PortraitFlipped:
+ data->vertexShaderConstantsData.projection = XMFLOAT4X4( // 270-degree Z-rotation
+ 0.0f, -1.0f, 0.0f, 0.0f,
+ 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f
+ );
+ break;
+
+ default:
+ SDL_SetError("An unknown DisplayOrientation is being used");
+ return -1;
+ }
+
+ //
+ // Update the view matrix
+ //
+ float viewportWidth = (float) renderer->viewport.w;
+ float viewportHeight = (float) renderer->viewport.h;
+ XMStoreFloat4x4(&data->vertexShaderConstantsData.view,
+ XMMatrixMultiply(
+ XMMatrixScaling(2.0f / viewportWidth, 2.0f / viewportHeight, 1.0f),
+ XMMatrixMultiply(
+ XMMatrixTranslation(-1, -1, 0),
+ XMMatrixRotationX(XM_PI)
+ )));
+#if 0
+ data->vertexShaderConstantsData.view = XMMatrixIdentity();
+#endif
+
+ //
+ // Reset the model matrix
+ //
+ XMStoreFloat4x4(&data->vertexShaderConstantsData.model, XMMatrixIdentity());
+
+ //
+ // Update the Direct3D viewport, which seems to be aligned to the
+ // swap buffer's coordinate space, which is always in landscape:
+ //
+ SDL_FRect orientationAlignedViewport;
+ const bool swapDimensions =
+ data->orientation == DisplayOrientations::Portrait ||
+ data->orientation == DisplayOrientations::PortraitFlipped;
+ if (swapDimensions) {
+ orientationAlignedViewport.x = (float) renderer->viewport.y;
+ orientationAlignedViewport.y = (float) renderer->viewport.x;
+ orientationAlignedViewport.w = (float) renderer->viewport.h;
+ orientationAlignedViewport.h = (float) renderer->viewport.w;
+ } else {
+ orientationAlignedViewport.x = (float) renderer->viewport.x;
+ orientationAlignedViewport.y = (float) renderer->viewport.y;
+ orientationAlignedViewport.w = (float) renderer->viewport.w;
+ orientationAlignedViewport.h = (float) renderer->viewport.h;
+ }
+ // WinRT, TODO: get custom viewports working with non-Landscape modes (Portrait, PortraitFlipped, and LandscapeFlipped)
+
+ D3D11_VIEWPORT viewport;
+ memset(&viewport, 0, sizeof(viewport));
+ viewport.TopLeftX = orientationAlignedViewport.x;
+ viewport.TopLeftY = orientationAlignedViewport.y;
+ viewport.Width = orientationAlignedViewport.w;
+ viewport.Height = orientationAlignedViewport.h;
+ viewport.MinDepth = 0.0f;
+ viewport.MaxDepth = 1.0f;
+ data->d3dContext->RSSetViewports(1, &viewport);
+
+#if 0
+ SDL_Log("%s, oav={%.0f,%.0f,%.0f,%.0f}, rend={%.0f,%.0f}\n",
+ __FUNCTION__,
+ orientationAlignedViewport.x,
+ orientationAlignedViewport.y,
+ orientationAlignedViewport.w,
+ orientationAlignedViewport.h,
+ data->renderTargetSize.x,
+ data->renderTargetSize.y);
+#endif
+
+ return 0;
+}
+
+static ComPtr &
+D3D11_GetCurrentRenderTargetView(SDL_Renderer * renderer)
+{
+ D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
+ if (data->currentOffscreenRenderTargetView) {
+ return data->currentOffscreenRenderTargetView;
+ } else {
+ return data->mainRenderTargetView;
+ }
+}
+
+static int
+D3D11_RenderClear(SDL_Renderer * renderer)
+{
+ D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
+ const float colorRGBA[] = {
+ (renderer->r / 255.0f),
+ (renderer->g / 255.0f),
+ (renderer->b / 255.0f),
+ (renderer->a / 255.0f)
+ };
+ data->d3dContext->ClearRenderTargetView(
+ D3D11_GetCurrentRenderTargetView(renderer).Get(),
+ colorRGBA
+ );
+ return 0;
+}
+
+static int
+D3D11_UpdateVertexBuffer(SDL_Renderer *renderer,
+ const void * vertexData, unsigned int dataSizeInBytes)
+{
+ D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
+ HRESULT result = S_OK;
+ D3D11_BUFFER_DESC vertexBufferDesc;
+
+ if (rendererData->vertexBuffer) {
+ rendererData->vertexBuffer->GetDesc(&vertexBufferDesc);
+ } else {
+ memset(&vertexBufferDesc, 0, sizeof(vertexBufferDesc));
+ }
+
+ if (vertexBufferDesc.ByteWidth >= dataSizeInBytes) {
+ rendererData->d3dContext->UpdateSubresource(rendererData->vertexBuffer.Get(), 0, NULL, vertexData, dataSizeInBytes, 0);
+ } else {
+ vertexBufferDesc.ByteWidth = dataSizeInBytes;
+ vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+
+ D3D11_SUBRESOURCE_DATA vertexBufferData = {0};
+ vertexBufferData.pSysMem = vertexData;
+ vertexBufferData.SysMemPitch = 0;
+ vertexBufferData.SysMemSlicePitch = 0;
+
+ result = rendererData->d3dDevice->CreateBuffer(
+ &vertexBufferDesc,
+ &vertexBufferData,
+ &rendererData->vertexBuffer
+ );
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, result);
+ return -1;
+ }
+ }
+
+ UINT stride = sizeof(VertexPositionColor);
+ UINT offset = 0;
+ rendererData->d3dContext->IASetVertexBuffers(
+ 0,
+ 1,
+ rendererData->vertexBuffer.GetAddressOf(),
+ &stride,
+ &offset
+ );
+
+ return 0;
+}
+
+static void
+D3D11_RenderStartDrawOp(SDL_Renderer * renderer)
+{
+ D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
+
+ rendererData->d3dContext->OMSetRenderTargets(
+ 1,
+ D3D11_GetCurrentRenderTargetView(renderer).GetAddressOf(),
+ nullptr
+ );
+}
+
+static void
+D3D11_RenderSetBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
+{
+ D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
+ switch (blendMode) {
+ case SDL_BLENDMODE_BLEND:
+ rendererData->d3dContext->OMSetBlendState(rendererData->blendModeBlend.Get(), 0, 0xFFFFFFFF);
+ break;
+ case SDL_BLENDMODE_ADD:
+ rendererData->d3dContext->OMSetBlendState(rendererData->blendModeAdd.Get(), 0, 0xFFFFFFFF);
+ break;
+ case SDL_BLENDMODE_MOD:
+ rendererData->d3dContext->OMSetBlendState(rendererData->blendModeMod.Get(), 0, 0xFFFFFFFF);
+ break;
+ case SDL_BLENDMODE_NONE:
+ rendererData->d3dContext->OMSetBlendState(NULL, 0, 0xFFFFFFFF);
+ break;
+ }
+}
+
+static void
+D3D11_SetPixelShader(SDL_Renderer * renderer,
+ ID3D11PixelShader * shader,
+ ID3D11ShaderResourceView * shaderResource,
+ ID3D11SamplerState * sampler)
+{
+ D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
+ rendererData->d3dContext->PSSetShader(shader, nullptr, 0);
+ rendererData->d3dContext->PSSetShaderResources(0, 1, &shaderResource);
+ rendererData->d3dContext->PSSetSamplers(0, 1, &sampler);
+}
+
+static void
+D3D11_RenderFinishDrawOp(SDL_Renderer * renderer,
+ D3D11_PRIMITIVE_TOPOLOGY primitiveTopology,
+ UINT vertexCount)
+{
+ D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
+
+ rendererData->d3dContext->UpdateSubresource(
+ rendererData->vertexShaderConstants.Get(),
+ 0,
+ NULL,
+ &rendererData->vertexShaderConstantsData,
+ 0,
+ 0
+ );
+
+ rendererData->d3dContext->IASetPrimitiveTopology(primitiveTopology);
+ rendererData->d3dContext->IASetInputLayout(rendererData->inputLayout.Get());
+ rendererData->d3dContext->VSSetShader(rendererData->vertexShader.Get(), nullptr, 0);
+ rendererData->d3dContext->VSSetConstantBuffers(0, 1, rendererData->vertexShaderConstants.GetAddressOf());
+ rendererData->d3dContext->RSSetState(rendererData->mainRasterizer.Get());
+ rendererData->d3dContext->Draw(vertexCount, 0);
+}
+
+static int
+D3D11_RenderDrawPoints(SDL_Renderer * renderer,
+ const SDL_FPoint * points, int count)
+{
+ D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
+ float r, g, b, a;
+
+ r = (float)(renderer->r / 255.0f);
+ g = (float)(renderer->g / 255.0f);
+ b = (float)(renderer->b / 255.0f);
+ a = (float)(renderer->a / 255.0f);
+
+ vector vertices;
+ vertices.reserve(count);
+ for (int i = 0; i < count; ++i) {
+ VertexPositionColor v = {XMFLOAT3(points[i].x, points[i].y, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)};
+ vertices.push_back(v);
+ }
+
+ D3D11_RenderStartDrawOp(renderer);
+ D3D11_RenderSetBlendMode(renderer, renderer->blendMode);
+ if (D3D11_UpdateVertexBuffer(renderer, &vertices[0], vertices.size() * sizeof(VertexPositionColor)) != 0) {
+ return -1;
+ }
+
+ D3D11_SetPixelShader(
+ renderer,
+ rendererData->colorPixelShader.Get(),
+ nullptr,
+ nullptr);
+
+ D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, vertices.size());
+
+ return 0;
+}
+
+static int
+D3D11_RenderDrawLines(SDL_Renderer * renderer,
+ const SDL_FPoint * points, int count)
+{
+ D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
+ float r, g, b, a;
+
+ r = (float)(renderer->r / 255.0f);
+ g = (float)(renderer->g / 255.0f);
+ b = (float)(renderer->b / 255.0f);
+ a = (float)(renderer->a / 255.0f);
+
+ vector vertices;
+ vertices.reserve(count);
+ for (int i = 0; i < count; ++i) {
+ VertexPositionColor v = {XMFLOAT3(points[i].x, points[i].y, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)};
+ vertices.push_back(v);
+ }
+
+ D3D11_RenderStartDrawOp(renderer);
+ D3D11_RenderSetBlendMode(renderer, renderer->blendMode);
+ if (D3D11_UpdateVertexBuffer(renderer, &vertices[0], vertices.size() * sizeof(VertexPositionColor)) != 0) {
+ return -1;
+ }
+
+ D3D11_SetPixelShader(
+ renderer,
+ rendererData->colorPixelShader.Get(),
+ nullptr,
+ nullptr);
+
+ D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, vertices.size());
+
+ return 0;
+}
+
+static int
+D3D11_RenderFillRects(SDL_Renderer * renderer,
+ const SDL_FRect * rects, int count)
+{
+ D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
+ float r, g, b, a;
+
+ r = (float)(renderer->r / 255.0f);
+ g = (float)(renderer->g / 255.0f);
+ b = (float)(renderer->b / 255.0f);
+ a = (float)(renderer->a / 255.0f);
+
+#if 0
+ // Set up a test pattern:
+ SDL_FRect _rects[] = {
+ {-1.1f, 1.1f, 1.1f, -1.1f},
+ {-1.0f, 1.0f, 1.0f, -1.0f}, // red
+ {0.0f, 1.0f, 1.0f, -1.0f}, // green
+ {-1.0f, 0.0f, 1.0f, -1.0f}, // blue
+ {0.0f, 0.0f, 1.0f, -1.0f} // white
+ };
+ count = sizeof(_rects) / sizeof(SDL_FRect);
+#define rects _rects
+#endif
+
+ for (int i = 0; i < count; ++i) {
+ D3D11_RenderStartDrawOp(renderer);
+ D3D11_RenderSetBlendMode(renderer, renderer->blendMode);
+
+#if 0
+ // Set colors for the test pattern:
+ a = 1.0f;
+ switch (i) {
+ case 0: r = 1.0f; g = 1.0f; b = 0.0f; break;
+ case 1: r = 1.0f; g = 0.0f; b = 0.0f; break;
+ case 2: r = 0.0f; g = 1.0f; b = 0.0f; break;
+ case 3: r = 0.0f; g = 0.0f; b = 1.0f; break;
+ case 4: r = 1.0f; g = 1.0f; b = 1.0f; break;
+ }
+#endif
+
+ VertexPositionColor vertices[] = {
+ {XMFLOAT3(rects[i].x, rects[i].y, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)},
+ {XMFLOAT3(rects[i].x, rects[i].y + rects[i].h, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)},
+ {XMFLOAT3(rects[i].x + rects[i].w, rects[i].y, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)},
+ {XMFLOAT3(rects[i].x + rects[i].w, rects[i].y + rects[i].h, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)},
+ };
+ if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) {
+ return -1;
+ }
+
+ D3D11_SetPixelShader(
+ renderer,
+ rendererData->colorPixelShader.Get(),
+ nullptr,
+ nullptr);
+
+ D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, sizeof(vertices) / sizeof(VertexPositionColor));
+ }
+
+ return 0;
+}
+
+static int
+D3D11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect)
+{
+ D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
+ D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata;
+
+ D3D11_RenderStartDrawOp(renderer);
+ D3D11_RenderSetBlendMode(renderer, texture->blendMode);
+
+ float minu = (float) srcrect->x / texture->w;
+ float maxu = (float) (srcrect->x + srcrect->w) / texture->w;
+ float minv = (float) srcrect->y / texture->h;
+ float maxv = (float) (srcrect->y + srcrect->h) / texture->h;
+
+ float r = 1.0f;
+ float g = 1.0f;
+ float b = 1.0f;
+ float a = 1.0f;
+ if (texture->modMode & SDL_TEXTUREMODULATE_COLOR) {
+ r = (float)(texture->r / 255.0f);
+ g = (float)(texture->g / 255.0f);
+ b = (float)(texture->b / 255.0f);
+ }
+ if (texture->modMode & SDL_TEXTUREMODULATE_ALPHA) {
+ a = (float)(texture->a / 255.0f);
+ }
+
+ VertexPositionColor vertices[] = {
+ {XMFLOAT3(dstrect->x, dstrect->y, 0.0f), XMFLOAT2(minu, minv), XMFLOAT4(r, g, b, a)},
+ {XMFLOAT3(dstrect->x, dstrect->y + dstrect->h, 0.0f), XMFLOAT2(minu, maxv), XMFLOAT4(r, g, b, a)},
+ {XMFLOAT3(dstrect->x + dstrect->w, dstrect->y, 0.0f), XMFLOAT2(maxu, minv), XMFLOAT4(r, g, b, a)},
+ {XMFLOAT3(dstrect->x + dstrect->w, dstrect->y + dstrect->h, 0.0f), XMFLOAT2(maxu, maxv), XMFLOAT4(r, g, b, a)},
+ };
+ if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) {
+ return -1;
+ }
+
+ D3D11_SetPixelShader(
+ renderer,
+ rendererData->texturePixelShader.Get(),
+ textureData->mainTextureResourceView.Get(),
+ rendererData->mainSampler.Get());
+
+ D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, sizeof(vertices) / sizeof(VertexPositionColor));
+
+ return 0;
+}
+
+static int
+D3D11_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
+ const SDL_Rect * srcrect, const SDL_FRect * dstrect,
+ const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
+{
+ D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
+ D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata;
+
+ D3D11_RenderStartDrawOp(renderer);
+ D3D11_RenderSetBlendMode(renderer, texture->blendMode);
+
+ float minu = (float) srcrect->x / texture->w;
+ float maxu = (float) (srcrect->x + srcrect->w) / texture->w;
+ float minv = (float) srcrect->y / texture->h;
+ float maxv = (float) (srcrect->y + srcrect->h) / texture->h;
+
+ float r = 1.0f;
+ float g = 1.0f;
+ float b = 1.0f;
+ float a = 1.0f;
+ if (texture->modMode & SDL_TEXTUREMODULATE_COLOR) {
+ r = (float)(texture->r / 255.0f);
+ g = (float)(texture->g / 255.0f);
+ b = (float)(texture->b / 255.0f);
+ }
+ if (texture->modMode & SDL_TEXTUREMODULATE_ALPHA) {
+ a = (float)(texture->a / 255.0f);
+ }
+
+ if (flip & SDL_FLIP_HORIZONTAL) {
+ float tmp = maxu;
+ maxu = minu;
+ minu = tmp;
+ }
+ if (flip & SDL_FLIP_VERTICAL) {
+ float tmp = maxv;
+ maxv = minv;
+ minv = tmp;
+ }
+
+ XMFLOAT4X4 oldModelMatrix = rendererData->vertexShaderConstantsData.model;
+ XMStoreFloat4x4(
+ &rendererData->vertexShaderConstantsData.model,
+ XMMatrixMultiply(
+ XMMatrixRotationZ((float)(XM_PI * (float) angle / 180.0f)),
+ XMMatrixTranslation(dstrect->x + center->x, dstrect->y + center->y, 0)
+ ));
+
+ const float minx = -center->x;
+ const float maxx = dstrect->w - center->x;
+ const float miny = -center->y;
+ const float maxy = dstrect->h - center->y;
+
+ VertexPositionColor vertices[] = {
+ {XMFLOAT3(minx, miny, 0.0f), XMFLOAT2(minu, minv), XMFLOAT4(r, g, b, a)},
+ {XMFLOAT3(minx, maxy, 0.0f), XMFLOAT2(minu, maxv), XMFLOAT4(r, g, b, a)},
+ {XMFLOAT3(maxx, miny, 0.0f), XMFLOAT2(maxu, minv), XMFLOAT4(r, g, b, a)},
+ {XMFLOAT3(maxx, maxy, 0.0f), XMFLOAT2(maxu, maxv), XMFLOAT4(r, g, b, a)},
+ };
+ if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) {
+ return -1;
+ }
+
+ D3D11_SetPixelShader(
+ renderer,
+ rendererData->texturePixelShader.Get(),
+ textureData->mainTextureResourceView.Get(),
+ rendererData->mainSampler.Get());
+
+ D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, sizeof(vertices) / sizeof(VertexPositionColor));
+
+ rendererData->vertexShaderConstantsData.model = oldModelMatrix;
+
+ return 0;
+}
+
+static int
+D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
+ Uint32 format, void * pixels, int pitch)
+{
+ D3D11_RenderData * data = (D3D11_RenderData *) renderer->driverdata;
+ HRESULT result = S_OK;
+
+ // Retrieve a pointer to the back buffer:
+ ComPtr backBuffer;
+ result = data->swapChain->GetBuffer(
+ 0,
+ __uuidof(ID3D11Texture2D),
+ &backBuffer
+ );
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__ ", Get Back Buffer", result);
+ return -1;
+ }
+
+ // Create a staging texture to copy the screen's data to:
+ ComPtr stagingTexture;
+ D3D11_TEXTURE2D_DESC stagingTextureDesc;
+ backBuffer->GetDesc(&stagingTextureDesc);
+ stagingTextureDesc.Width = rect->w;
+ stagingTextureDesc.Height = rect->h;
+ stagingTextureDesc.BindFlags = 0;
+ stagingTextureDesc.MiscFlags = 0;
+ stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
+ stagingTextureDesc.Usage = D3D11_USAGE_STAGING;
+ result = data->d3dDevice->CreateTexture2D(
+ &stagingTextureDesc,
+ NULL,
+ &stagingTexture);
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__ ", Create Staging Texture", result);
+ return -1;
+ }
+
+ // Copy the desired portion of the back buffer to the staging texture:
+ D3D11_BOX srcBox;
+ srcBox.left = rect->x;
+ srcBox.right = rect->x + rect->w;
+ srcBox.top = rect->y;
+ srcBox.bottom = rect->y + rect->h;
+ srcBox.front = 0;
+ srcBox.back = 1;
+ data->d3dContext->CopySubresourceRegion(
+ stagingTexture.Get(),
+ D3D11CalcSubresource(0, 0, 0),
+ 0, 0, 0,
+ backBuffer.Get(),
+ D3D11CalcSubresource(0, 0, 0),
+ &srcBox);
+
+ // Map the staging texture's data to CPU-accessible memory:
+ D3D11_MAPPED_SUBRESOURCE textureMemory = {0};
+ result = data->d3dContext->Map(
+ stagingTexture.Get(),
+ D3D11CalcSubresource(0, 0, 0),
+ D3D11_MAP_READ,
+ 0,
+ &textureMemory);
+ if (FAILED(result)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__ ", Map Staging Texture to CPU Memory", result);
+ return -1;
+ }
+
+ // Copy the data into the desired buffer, converting pixels to the
+ // desired format at the same time:
+ if (SDL_ConvertPixels(
+ rect->w, rect->h,
+ DXGIFormatToSDLPixelFormat(stagingTextureDesc.Format),
+ textureMemory.pData,
+ textureMemory.RowPitch,
+ format,
+ pixels,
+ pitch) != 0)
+ {
+ // When SDL_ConvertPixels fails, it'll have already set the format.
+ // Get the error message, and attach some extra data to it.
+ std::string errorMessage = string(__FUNCTION__ ", Convert Pixels failed: ") + SDL_GetError();
+ SDL_SetError(errorMessage.c_str());
+ return -1;
+ }
+
+ // Unmap the texture:
+ data->d3dContext->Unmap(
+ stagingTexture.Get(),
+ D3D11CalcSubresource(0, 0, 0));
+
+ // All done. The staging texture will be cleaned up in it's container
+ // ComPtr<>'s destructor.
+ return 0;
+}
+
+static void
+D3D11_RenderPresent(SDL_Renderer * renderer)
+{
+ D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
+
+#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
+ // The first argument instructs DXGI to block until VSync, putting the application
+ // to sleep until the next VSync. This ensures we don't waste any cycles rendering
+ // frames that will never be displayed to the screen.
+ HRESULT hr = data->swapChain->Present(1, 0);
+#else
+ // The application may optionally specify "dirty" or "scroll"
+ // rects to improve efficiency in certain scenarios.
+ // This option is not available on Windows Phone 8, to note.
+ DXGI_PRESENT_PARAMETERS parameters = {0};
+ parameters.DirtyRectsCount = 0;
+ parameters.pDirtyRects = nullptr;
+ parameters.pScrollRect = nullptr;
+ parameters.pScrollOffset = nullptr;
+
+ // The first argument instructs DXGI to block until VSync, putting the application
+ // to sleep until the next VSync. This ensures we don't waste any cycles rendering
+ // frames that will never be displayed to the screen.
+ HRESULT hr = data->swapChain->Present1(1, 0, ¶meters);
+#endif
+
+ // Discard the contents of the render target.
+ // This is a valid operation only when the existing contents will be entirely
+ // overwritten. If dirty or scroll rects are used, this call should be removed.
+ data->d3dContext->DiscardView(data->mainRenderTargetView.Get());
+
+ // If the device was removed either by a disconnect or a driver upgrade, we
+ // must recreate all device resources.
+ //
+ // TODO, WinRT: consider throwing an exception if D3D11_RenderPresent fails, especially if there is a way to salvedge debug info from users' machines
+ if (hr == DXGI_ERROR_DEVICE_REMOVED)
+ {
+ hr = D3D11_HandleDeviceLost(renderer);
+ if (FAILED(hr)) {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, hr);
+ }
+ }
+ else
+ {
+ WIN_SetErrorFromHRESULT(__FUNCTION__, hr);
+ }
+}
+
+#endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/render/direct3d11/SDL_render_d3d11_cpp.h b/src/render/direct3d11/SDL_render_d3d11_cpp.h
new file mode 100644
index 000000000..14fc61270
--- /dev/null
+++ b/src/render/direct3d11/SDL_render_d3d11_cpp.h
@@ -0,0 +1,84 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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
+#include
+#include
+#include
+
+struct SDL_VertexShaderConstants
+{
+ DirectX::XMFLOAT4X4 model;
+ DirectX::XMFLOAT4X4 view;
+ DirectX::XMFLOAT4X4 projection;
+};
+
+typedef struct
+{
+ Microsoft::WRL::ComPtr d3dDevice;
+ Microsoft::WRL::ComPtr d3dContext;
+ Microsoft::WRL::ComPtr swapChain;
+ Microsoft::WRL::ComPtr mainRenderTargetView;
+ Microsoft::WRL::ComPtr currentOffscreenRenderTargetView;
+ Microsoft::WRL::ComPtr inputLayout;
+ Microsoft::WRL::ComPtr vertexBuffer;
+ Microsoft::WRL::ComPtr vertexShader;
+ Microsoft::WRL::ComPtr texturePixelShader;
+ Microsoft::WRL::ComPtr colorPixelShader;
+ Microsoft::WRL::ComPtr blendModeBlend;
+ Microsoft::WRL::ComPtr blendModeAdd;
+ Microsoft::WRL::ComPtr blendModeMod;
+ Microsoft::WRL::ComPtr mainSampler;
+ Microsoft::WRL::ComPtr mainRasterizer;
+ D3D_FEATURE_LEVEL featureLevel;
+
+ // Vertex buffer constants:
+ SDL_VertexShaderConstants vertexShaderConstantsData;
+ Microsoft::WRL::ComPtr vertexShaderConstants;
+
+ // Cached renderer properties.
+ DirectX::XMFLOAT2 windowSizeInDIPs;
+ DirectX::XMFLOAT2 renderTargetSize;
+ Windows::Graphics::Display::DisplayOrientations orientation;
+
+ // Transform used for display orientation.
+ DirectX::XMFLOAT4X4 orientationTransform3D;
+} D3D11_RenderData;
+
+typedef struct
+{
+ Microsoft::WRL::ComPtr mainTexture;
+ Microsoft::WRL::ComPtr mainTextureResourceView;
+ Microsoft::WRL::ComPtr mainTextureRenderTargetView;
+ SDL_PixelFormat * pixelFormat;
+ Microsoft::WRL::ComPtr stagingTexture;
+ DirectX::XMINT2 lockedTexturePosition;
+} D3D11_TextureData;
+
+struct VertexPositionColor
+{
+ DirectX::XMFLOAT3 pos;
+ DirectX::XMFLOAT2 tex;
+ DirectX::XMFLOAT4 color;
+};
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/thread/SDL_thread_c.h b/src/thread/SDL_thread_c.h
index 1971ded24..90d9b57ca 100644
--- a/src/thread/SDL_thread_c.h
+++ b/src/thread/SDL_thread_c.h
@@ -36,6 +36,8 @@
#include "windows/SDL_systhread_c.h"
#elif SDL_THREAD_PSP
#include "psp/SDL_systhread_c.h"
+#elif SDL_THREAD_STDCPP
+#include "stdcpp/SDL_systhread_c.h"
#else
#error Need thread implementation for this platform
#include "generic/SDL_systhread_c.h"
diff --git a/src/thread/stdcpp/SDL_syscond.cpp b/src/thread/stdcpp/SDL_syscond.cpp
new file mode 100644
index 000000000..4ca1d96f7
--- /dev/null
+++ b/src/thread/stdcpp/SDL_syscond.cpp
@@ -0,0 +1,183 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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"
+
+extern "C" {
+#include "SDL_thread.h"
+}
+
+#include
+#include
+#include
+#include
+
+#include "SDL_sysmutex_c.h"
+
+struct SDL_cond
+{
+ std::condition_variable_any cpp_cond;
+};
+
+/* Create a condition variable */
+extern "C"
+SDL_cond *
+SDL_CreateCond(void)
+{
+ /* Allocate and initialize the condition variable */
+ try {
+ SDL_cond * cond = new SDL_cond;
+ return cond;
+ } catch (std::exception & ex) {
+ SDL_SetError("unable to create C++ condition variable: %s", ex.what());
+ return NULL;
+ } catch (...) {
+ SDL_SetError("unable to create C++ condition variable due to an unknown exception");
+ return NULL;
+ }
+}
+
+/* Destroy a condition variable */
+extern "C"
+void
+SDL_DestroyCond(SDL_cond * cond)
+{
+ if (cond) {
+ try {
+ delete cond;
+ } catch (...) {
+ // catch any and all exceptions, just in case something happens
+ }
+ }
+}
+
+/* Restart one of the threads that are waiting on the condition variable */
+extern "C"
+int
+SDL_CondSignal(SDL_cond * cond)
+{
+ if (!cond) {
+ SDL_SetError("Passed a NULL condition variable");
+ return -1;
+ }
+
+ try {
+ cond->cpp_cond.notify_one();
+ return 0;
+ } catch (...) {
+ // catch any and all exceptions, just in case something happens
+ SDL_SetError("unable to signal C++ condition variable due to an unknown exception");
+ return -1;
+ }
+}
+
+/* Restart all threads that are waiting on the condition variable */
+extern "C"
+int
+SDL_CondBroadcast(SDL_cond * cond)
+{
+ if (!cond) {
+ SDL_SetError("Passed a NULL condition variable");
+ return -1;
+ }
+
+ try {
+ cond->cpp_cond.notify_all();
+ return 0;
+ } catch (...) {
+ // catch any and all exceptions, just in case something happens
+ SDL_SetError("unable to broadcast C++ condition variable due to an unknown exception");
+ return -1;
+ }
+}
+
+/* Wait on the condition variable for at most 'ms' milliseconds.
+ The mutex must be locked before entering this function!
+ The mutex is unlocked during the wait, and locked again after the wait.
+
+Typical use:
+
+Thread A:
+ SDL_LockMutex(lock);
+ while ( ! condition ) {
+ SDL_CondWait(cond, lock);
+ }
+ SDL_UnlockMutex(lock);
+
+Thread B:
+ SDL_LockMutex(lock);
+ ...
+ condition = true;
+ ...
+ SDL_CondSignal(cond);
+ SDL_UnlockMutex(lock);
+ */
+extern "C"
+int
+SDL_CondWaitTimeout(SDL_cond * cond, SDL_mutex * mutex, Uint32 ms)
+{
+ if (!cond) {
+ SDL_SetError("Passed a NULL condition variable");
+ return -1;
+ }
+
+ if (!mutex) {
+ SDL_SetError("Passed a NULL mutex variable");
+ return -1;
+ }
+
+ try {
+ std::unique_lock cpp_lock(mutex->cpp_mutex, std::defer_lock_t());
+ if (ms == SDL_MUTEX_MAXWAIT) {
+ cond->cpp_cond.wait(
+ cpp_lock
+ );
+ cpp_lock.release();
+ return 0;
+ } else {
+ auto wait_result = cond->cpp_cond.wait_for(
+ cpp_lock,
+ std::chrono::duration(ms)
+ );
+ cpp_lock.release();
+ if (wait_result == std::cv_status::timeout) {
+ return SDL_MUTEX_TIMEDOUT;
+ } else {
+ return 0;
+ }
+ }
+ } catch (std::exception & ex) {
+ SDL_SetError("unable to wait on C++ condition variable: %s", ex.what());
+ return -1;
+ } catch (...) {
+ SDL_SetError("unable to lock wait on C++ condition variable due to an unknown exception");
+ return -1;
+ }
+}
+
+/* Wait on the condition variable forever */
+extern "C"
+int
+SDL_CondWait(SDL_cond * cond, SDL_mutex * mutex)
+{
+ return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT);
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/thread/stdcpp/SDL_sysmutex.cpp b/src/thread/stdcpp/SDL_sysmutex.cpp
new file mode 100644
index 000000000..e43b255e8
--- /dev/null
+++ b/src/thread/stdcpp/SDL_sysmutex.cpp
@@ -0,0 +1,113 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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"
+
+extern "C" {
+#include "SDL_thread.h"
+#include "SDL_systhread_c.h"
+#include "SDL_log.h"
+}
+
+#include
+
+#include "SDL_sysmutex_c.h"
+#include
+
+
+/* Create a mutex */
+extern "C"
+SDL_mutex *
+SDL_CreateMutex(void)
+{
+ /* Allocate and initialize the mutex */
+ try {
+ SDL_mutex * mutex = new SDL_mutex;
+ return mutex;
+ } catch (std::exception & ex) {
+ SDL_SetError("unable to create C++ mutex: %s", ex.what());
+ return NULL;
+ } catch (...) {
+ SDL_SetError("unable to create C++ mutex due to an unknown exception");
+ return NULL;
+ }
+}
+
+/* Free the mutex */
+extern "C"
+void
+SDL_DestroyMutex(SDL_mutex * mutex)
+{
+ if (mutex) {
+ try {
+ delete mutex;
+ } catch (...) {
+ // catch any and all exceptions, just in case something happens
+ }
+ }
+}
+
+/* Lock the semaphore */
+extern "C"
+int
+SDL_mutexP(SDL_mutex * mutex)
+{
+ SDL_threadID threadID = SDL_ThreadID();
+ DWORD realThreadID = GetCurrentThreadId();
+ if (mutex == NULL) {
+ SDL_SetError("Passed a NULL mutex");
+ return -1;
+ }
+
+ try {
+ mutex->cpp_mutex.lock();
+ return 0;
+ } catch (std::exception & ex) {
+ SDL_SetError("unable to lock C++ mutex: %s", ex.what());
+ return -1;
+ } catch (...) {
+ SDL_SetError("unable to lock C++ mutex due to an unknown exception");
+ return -1;
+ }
+}
+
+/* Unlock the mutex */
+extern "C"
+int
+SDL_mutexV(SDL_mutex * mutex)
+{
+ SDL_threadID threadID = SDL_ThreadID();
+ DWORD realThreadID = GetCurrentThreadId();
+ if (mutex == NULL) {
+ SDL_SetError("Passed a NULL mutex");
+ return -1;
+ }
+
+ try {
+ mutex->cpp_mutex.unlock();
+ return 0;
+ } catch (...) {
+ // catch any and all exceptions, just in case something happens.
+ SDL_SetError("unable to unlock C++ mutex due to an unknown exception");
+ return -1;
+ }
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/thread/stdcpp/SDL_sysmutex_c.h b/src/thread/stdcpp/SDL_sysmutex_c.h
new file mode 100644
index 000000000..500e57d40
--- /dev/null
+++ b/src/thread/stdcpp/SDL_sysmutex_c.h
@@ -0,0 +1,30 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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
+
+struct SDL_mutex
+{
+ std::recursive_mutex cpp_mutex;
+};
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/thread/stdcpp/SDL_systhread.cpp b/src/thread/stdcpp/SDL_systhread.cpp
new file mode 100644
index 000000000..fd4cdafb3
--- /dev/null
+++ b/src/thread/stdcpp/SDL_systhread.cpp
@@ -0,0 +1,124 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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"
+
+/* Thread management routines for SDL */
+
+extern "C" {
+#include "SDL_thread.h"
+#include "../SDL_systhread.h"
+#include "../SDL_thread_c.h"
+#include "SDL_log.h"
+}
+
+#include
+#include
+
+// HACK: Mimic C++11's thread_local keyword on Visual C++ 2012 (aka. VC++ 11)
+// TODO: make sure this hack doesn't get used if and when Visual C++ supports
+// the official, 'thread_local' keyword.
+#ifdef _MSC_VER
+#define thread_local __declspec(thread)
+// Documentation for __declspec(thread) can be found online at:
+// http://msdn.microsoft.com/en-us/library/2s9wt68x.aspx
+#endif
+
+static void
+RunThread(void *args)
+{
+ SDL_RunThread(args);
+}
+
+extern "C"
+int
+SDL_SYS_CreateThread(SDL_Thread * thread, void *args)
+{
+ try {
+ std::thread cpp_thread(RunThread, args);
+ thread->handle = (void *) new std::thread(std::move(cpp_thread));
+ return 0;
+ } catch (std::exception & ex) {
+ SDL_SetError("unable to create a C++ thread: %s", ex.what());
+ return -1;
+ } catch (...) {
+ SDL_SetError("unable to create a C++ thread due to an unknown exception");
+ return -1;
+ }
+}
+
+extern "C"
+void
+SDL_SYS_SetupThread(const char *name)
+{
+ // Make sure a thread ID gets assigned ASAP, for debugging purposes:
+ SDL_ThreadID();
+ return;
+}
+
+extern "C"
+SDL_threadID
+SDL_ThreadID(void)
+{
+ static thread_local SDL_threadID current_thread_id = 0;
+ static SDL_threadID next_thread_id = 1;
+ static std::mutex next_thread_id_mutex;
+
+ if (current_thread_id == 0) {
+ std::lock_guard lock(next_thread_id_mutex);
+ current_thread_id = next_thread_id;
+ ++next_thread_id;
+ }
+
+ return current_thread_id;
+}
+
+extern "C"
+int
+SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority)
+{
+ // Thread priorities do not look to be settable via C++11's thread
+ // interface, at least as of this writing (Nov 2012). std::thread does
+ // provide access to the OS' native handle, however, and some form of
+ // priority-setting could, in theory, be done through this interface.
+ return (0);
+}
+
+extern "C"
+void
+SDL_SYS_WaitThread(SDL_Thread * thread)
+{
+ if ( ! thread) {
+ return;
+ }
+
+ try {
+ std::thread * cpp_thread = (std::thread *) thread->handle;
+ if (cpp_thread->joinable()) {
+ cpp_thread->join();
+ }
+ } catch (...) {
+ // Catch any exceptions, just in case.
+ // Report nothing, as SDL_WaitThread does not seem to offer a means
+ // to report errors to its callers.
+ }
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/thread/stdcpp/SDL_systhread_c.h b/src/thread/stdcpp/SDL_systhread_c.h
new file mode 100644
index 000000000..4a060c98a
--- /dev/null
+++ b/src/thread/stdcpp/SDL_systhread_c.h
@@ -0,0 +1,26 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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"
+
+/* For a thread handle, use a void pointer to a std::thread */
+typedef void * SYS_ThreadHandle;
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h
index 4973648c7..e149b8a18 100644
--- a/src/video/SDL_sysvideo.h
+++ b/src/video/SDL_sysvideo.h
@@ -343,6 +343,9 @@ extern VideoBootStrap DirectFB_bootstrap;
#if SDL_VIDEO_DRIVER_WINDOWS
extern VideoBootStrap WINDOWS_bootstrap;
#endif
+#if SDL_VIDEO_DRIVER_WINRT
+extern VideoBootStrap WINRT_bootstrap;
+#endif
#if SDL_VIDEO_DRIVER_BWINDOW
extern VideoBootStrap BWINDOW_bootstrap;
#endif
diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c
index bab6c6cb9..1404ba0e8 100644
--- a/src/video/SDL_video.c
+++ b/src/video/SDL_video.c
@@ -64,6 +64,9 @@ static VideoBootStrap *bootstrap[] = {
#if SDL_VIDEO_DRIVER_WINDOWS
&WINDOWS_bootstrap,
#endif
+#if SDL_VIDEO_DRIVER_WINRT
+ &WINRT_bootstrap,
+#endif
#if SDL_VIDEO_DRIVER_BWINDOW
&BWINDOW_bootstrap,
#endif
diff --git a/src/video/uikit/SDL_uikitwindow.m b/src/video/uikit/SDL_uikitwindow.m
index b3f7ac9f4..0285b6bcc 100644
--- a/src/video/uikit/SDL_uikitwindow.m
+++ b/src/video/uikit/SDL_uikitwindow.m
@@ -202,7 +202,7 @@ UIKit_CreateWindow(_THIS, SDL_Window *window)
if (external) {
[uiwindow setScreen:data->uiscreen];
}
-
+
if (SetupWindowData(_this, window, uiwindow, SDL_TRUE) < 0) {
[uiwindow release];
return -1;
@@ -301,10 +301,12 @@ SDL_bool
UIKit_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
{
UIWindow *uiwindow = ((SDL_WindowData *) window->driverdata)->uiwindow;
+ UIViewController *uiviewcontroller = ((SDL_WindowData *) window->driverdata)->viewcontroller;
if (info->version.major <= SDL_MAJOR_VERSION) {
info->subsystem = SDL_SYSWM_UIKIT;
info->info.uikit.window = uiwindow;
+ info->info.uikit.viewcontroller = uiviewcontroller;
return SDL_TRUE;
} else {
SDL_SetError("Application not compiled with SDL %d.%d\n",
diff --git a/src/video/windowsrt/SDL_WinRTApp.cpp b/src/video/windowsrt/SDL_WinRTApp.cpp
new file mode 100644
index 000000000..a807bda7f
--- /dev/null
+++ b/src/video/windowsrt/SDL_WinRTApp.cpp
@@ -0,0 +1,978 @@
+
+#include
+#include
+#include
+
+#include "ppltasks.h"
+
+extern "C" {
+#include "SDL_assert.h"
+#include "SDL_events.h"
+#include "SDL_hints.h"
+#include "SDL_log.h"
+#include "SDL_stdinc.h"
+#include "SDL_render.h"
+#include "../SDL_sysvideo.h"
+#include "../../SDL_hints_c.h"
+#include "../../events/scancodes_windows.h"
+#include "../../events/SDL_mouse_c.h"
+#include "../../events/SDL_keyboard_c.h"
+#include "../../events/SDL_windowevents_c.h"
+#include "../../render/SDL_sysrender.h"
+}
+
+#include "SDL_winrtvideo.h"
+#include "SDL_WinRTApp.h"
+
+using namespace concurrency;
+using namespace std;
+using namespace Windows::ApplicationModel;
+using namespace Windows::ApplicationModel::Core;
+using namespace Windows::ApplicationModel::Activation;
+using namespace Windows::Devices::Input;
+using namespace Windows::Graphics::Display;
+using namespace Windows::Foundation;
+using namespace Windows::System;
+using namespace Windows::UI::Core;
+using namespace Windows::UI::Input;
+
+// Compile-time debugging options:
+// To enable, uncomment; to disable, comment them out.
+//#define LOG_POINTER_EVENTS 1
+//#define LOG_WINDOW_EVENTS 1
+//#define LOG_ORIENTATION_EVENTS 1
+
+
+// HACK, DLudwig: The C-style main() will get loaded via the app's
+// WinRT-styled main(), which is part of SDLmain_for_WinRT.cpp.
+// This seems wrong on some level, but does seem to work.
+typedef int (*SDL_WinRT_MainFunction)(int, char **);
+static SDL_WinRT_MainFunction SDL_WinRT_main = nullptr;
+
+// HACK, DLudwig: record a reference to the global, Windows RT 'app'/view.
+// SDL/WinRT will use this throughout its code.
+//
+// TODO, WinRT: consider replacing SDL_WinRTGlobalApp with something
+// non-global, such as something created inside
+// SDL_InitSubSystem(SDL_INIT_VIDEO), or something inside
+// SDL_CreateWindow().
+SDL_WinRTApp ^ SDL_WinRTGlobalApp = nullptr;
+
+ref class SDLApplicationSource sealed : Windows::ApplicationModel::Core::IFrameworkViewSource
+{
+public:
+ virtual Windows::ApplicationModel::Core::IFrameworkView^ CreateView();
+};
+
+IFrameworkView^ SDLApplicationSource::CreateView()
+{
+ // TODO, WinRT: see if this function (CreateView) can ever get called
+ // more than once. For now, just prevent it from ever assigning
+ // SDL_WinRTGlobalApp more than once.
+ SDL_assert(!SDL_WinRTGlobalApp);
+ SDL_WinRTApp ^ app = ref new SDL_WinRTApp();
+ if (!SDL_WinRTGlobalApp)
+ {
+ SDL_WinRTGlobalApp = app;
+ }
+ return app;
+}
+
+__declspec(dllexport) int SDL_WinRT_RunApplication(SDL_WinRT_MainFunction mainFunction)
+{
+ SDL_WinRT_main = mainFunction;
+ auto direct3DApplicationSource = ref new SDLApplicationSource();
+ CoreApplication::Run(direct3DApplicationSource);
+ return 0;
+}
+
+static void WINRT_SetDisplayOrientationsPreference(const char *name, const char *oldValue, const char *newValue)
+{
+ SDL_assert(SDL_strcmp(name, SDL_HINT_ORIENTATIONS) == 0);
+
+ // Start with no orientation flags, then add each in as they're parsed
+ // from newValue.
+ unsigned int orientationFlags = 0;
+ std::istringstream tokenizer(newValue);
+ while (!tokenizer.eof()) {
+ std::string orientationName;
+ std::getline(tokenizer, orientationName, ' ');
+ if (orientationName == "LandscapeLeft") {
+ orientationFlags |= (unsigned int) DisplayOrientations::LandscapeFlipped;
+ } else if (orientationName == "LandscapeRight") {
+ orientationFlags |= (unsigned int) DisplayOrientations::Landscape;
+ } else if (orientationName == "Portrait") {
+ orientationFlags |= (unsigned int) DisplayOrientations::Portrait;
+ } else if (orientationName == "PortraitUpsideDown") {
+ orientationFlags |= (unsigned int) DisplayOrientations::PortraitFlipped;
+ }
+ }
+
+ // If no valid orientation flags were specified, use a reasonable set of defaults:
+ if (!orientationFlags) {
+ // TODO, WinRT: consider seeing if an app's default orientation flags can be found out via some API call(s).
+ orientationFlags = (unsigned int) ( \
+ DisplayOrientations::Landscape |
+ DisplayOrientations::LandscapeFlipped |
+ DisplayOrientations::Portrait |
+ DisplayOrientations::PortraitFlipped);
+ }
+
+ // Set the orientation/rotation preferences. Please note that this does
+ // not constitute a 100%-certain lock of a given set of possible
+ // orientations. According to Microsoft's documentation on Windows RT [1]
+ // when a device is not capable of being rotated, Windows may ignore
+ // the orientation preferences, and stick to what the device is capable of
+ // displaying.
+ //
+ // [1] Documentation on the 'InitialRotationPreference' setting for a
+ // Windows app's manifest file describes how some orientation/rotation
+ // preferences may be ignored. See
+ // http://msdn.microsoft.com/en-us/library/windows/apps/hh700343.aspx
+ // for details. Microsoft's "Display orientation sample" also gives an
+ // outline of how Windows treats device rotation
+ // (http://code.msdn.microsoft.com/Display-Orientation-Sample-19a58e93).
+ DisplayProperties::AutoRotationPreferences = (DisplayOrientations) orientationFlags;
+}
+
+SDL_WinRTApp::SDL_WinRTApp() :
+ m_windowClosed(false),
+ m_windowVisible(true),
+ m_sdlWindowData(NULL),
+ m_sdlVideoDevice(NULL),
+ m_useRelativeMouseMode(false)
+{
+}
+
+void SDL_WinRTApp::Initialize(CoreApplicationView^ applicationView)
+{
+ applicationView->Activated +=
+ ref new TypedEventHandler(this, &SDL_WinRTApp::OnActivated);
+
+ CoreApplication::Suspending +=
+ ref new EventHandler(this, &SDL_WinRTApp::OnSuspending);
+
+ CoreApplication::Resuming +=
+ ref new EventHandler(this, &SDL_WinRTApp::OnResuming);
+
+ DisplayProperties::OrientationChanged +=
+ ref new DisplayPropertiesEventHandler(this, &SDL_WinRTApp::OnOrientationChanged);
+
+ // Register the hint, SDL_HINT_ORIENTATIONS, with SDL. This needs to be
+ // done before the hint's callback is registered (as of Feb 22, 2013),
+ // otherwise the hint callback won't get registered.
+ //
+ // WinRT, TODO: see if an app's default orientation can be found out via WinRT API(s), then set the initial value of SDL_HINT_ORIENTATIONS accordingly.
+ SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft LandscapeRight Portrait PortraitUpsideDown");
+ SDL_RegisterHintChangedCb(SDL_HINT_ORIENTATIONS, WINRT_SetDisplayOrientationsPreference);
+}
+
+void SDL_WinRTApp::OnOrientationChanged(Object^ sender)
+{
+#if LOG_ORIENTATION_EVENTS==1
+ CoreWindow^ window = CoreWindow::GetForCurrentThread();
+ if (window) {
+ SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, CoreWindow Size={%f,%f}\n",
+ __FUNCTION__,
+ (int)DisplayProperties::CurrentOrientation,
+ (int)DisplayProperties::NativeOrientation,
+ (int)DisplayProperties::AutoRotationPreferences,
+ window->Bounds.Width,
+ window->Bounds.Height);
+ } else {
+ SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d\n",
+ __FUNCTION__,
+ (int)DisplayProperties::CurrentOrientation,
+ (int)DisplayProperties::NativeOrientation,
+ (int)DisplayProperties::AutoRotationPreferences);
+ }
+#endif
+}
+
+void SDL_WinRTApp::SetWindow(CoreWindow^ window)
+{
+#if LOG_WINDOW_EVENTS==1
+ SDL_Log("%s, current orientation=%d, native orientation=%d, auto rot. pref=%d, window Size={%f,%f}\n",
+ __FUNCTION__,
+ (int)DisplayProperties::CurrentOrientation,
+ (int)DisplayProperties::NativeOrientation,
+ (int)DisplayProperties::AutoRotationPreferences,
+ window->Bounds.Width,
+ window->Bounds.Height);
+#endif
+
+ window->SizeChanged +=
+ ref new TypedEventHandler(this, &SDL_WinRTApp::OnWindowSizeChanged);
+
+ window->VisibilityChanged +=
+ ref new TypedEventHandler(this, &SDL_WinRTApp::OnVisibilityChanged);
+
+ window->Closed +=
+ ref new TypedEventHandler(this, &SDL_WinRTApp::OnWindowClosed);
+
+#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
+ window->PointerCursor = ref new CoreCursor(CoreCursorType::Arrow, 0);
+#endif
+
+ window->PointerPressed +=
+ ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerPressed);
+
+ window->PointerReleased +=
+ ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerReleased);
+
+ window->PointerWheelChanged +=
+ ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerWheelChanged);
+
+ window->PointerMoved +=
+ ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerMoved);
+
+#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
+ // Retrieves relative-only mouse movements:
+ Windows::Devices::Input::MouseDevice::GetForCurrentView()->MouseMoved +=
+ ref new TypedEventHandler(this, &SDL_WinRTApp::OnMouseMoved);
+#endif
+
+ window->KeyDown +=
+ ref new TypedEventHandler(this, &SDL_WinRTApp::OnKeyDown);
+
+ window->KeyUp +=
+ ref new TypedEventHandler(this, &SDL_WinRTApp::OnKeyUp);
+}
+
+void SDL_WinRTApp::Load(Platform::String^ entryPoint)
+{
+}
+
+void SDL_WinRTApp::Run()
+{
+ if (SDL_WinRT_main)
+ {
+ // TODO, WinRT: pass the C-style main() a reasonably realistic
+ // representation of command line arguments.
+ int argc = 0;
+ char **argv = NULL;
+ SDL_WinRT_main(argc, argv);
+ }
+}
+
+void SDL_WinRTApp::PumpEvents()
+{
+ if (!m_windowClosed)
+ {
+ if (m_windowVisible)
+ {
+ CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);
+ }
+ else
+ {
+ CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessOneAndAllPending);
+ }
+ }
+}
+
+void SDL_WinRTApp::Uninitialize()
+{
+}
+
+void SDL_WinRTApp::OnWindowSizeChanged(CoreWindow^ sender, WindowSizeChangedEventArgs^ args)
+{
+#if LOG_WINDOW_EVENTS==1
+ SDL_Log("%s, size={%f,%f}, current orientation=%d, native orientation=%d, auto rot. pref=%d, m_sdlWindowData?=%s\n",
+ __FUNCTION__,
+ args->Size.Width, args->Size.Height,
+ (int)DisplayProperties::CurrentOrientation,
+ (int)DisplayProperties::NativeOrientation,
+ (int)DisplayProperties::AutoRotationPreferences,
+ (m_sdlWindowData ? "yes" : "no"));
+#endif
+
+ if (m_sdlWindowData) {
+ // Make the new window size be the one true fullscreen mode.
+ // This change was done, in part, to allow the Direct3D 11.1 renderer
+ // to receive window-resize events as a device rotates.
+ // Before, rotating a device from landscape, to portrait, and then
+ // back to landscape would cause the Direct3D 11.1 swap buffer to
+ // not get resized appropriately. SDL would, on the rotation from
+ // landscape to portrait, re-resize the SDL window to it's initial
+ // size (landscape). On the subsequent rotation, SDL would drop the
+ // window-resize event as it appeared the SDL window didn't change
+ // size, and the Direct3D 11.1 renderer wouldn't resize its swap
+ // chain.
+ //
+ // TODO, WinRT: consider dropping old display modes after the fullscreen window changes size (from rotations, etc.)
+ m_sdlWindowData->sdlWindow->fullscreen_mode = SDL_WinRTGlobalApp->GetMainDisplayMode();
+ SDL_AddDisplayMode(&m_sdlVideoDevice->displays[0], &m_sdlWindowData->sdlWindow->fullscreen_mode);
+
+ // HACK, Feb 19, 2013: SDL_WINDOWEVENT_RESIZED events, when sent,
+ // will attempt to fix the values of the main window's renderer's
+ // viewport. While this can be good, it does appear to be buggy,
+ // and can cause a fullscreen viewport to become corrupted. This
+ // behavior was noticed on a Surface RT while rotating the device
+ // from landscape to portrait. Oddly enough, this did not occur
+ // in the Windows Simulator.
+ //
+ // Backing up, then restoring, the main renderer's 'resized' flag
+ // seems to fix fullscreen viewport problems when rotating a
+ // Windows device.
+ //
+ // Commencing hack in 3... 2... 1...
+ SDL_Renderer * rendererForMainWindow = SDL_GetRenderer(m_sdlWindowData->sdlWindow);
+ // For now, limit the hack to when the Direct3D 11.1 is getting used:
+ const bool usingD3D11Renderer = \
+ (rendererForMainWindow != NULL) &&
+ (SDL_strcmp(rendererForMainWindow->info.name, "direct3d 11.1") == 0);
+ SDL_bool wasD3D11RendererResized = SDL_FALSE;
+ if (usingD3D11Renderer) {
+ wasD3D11RendererResized = rendererForMainWindow->resized;
+ }
+
+ // Send the window-resize event to the rest of SDL, and to apps:
+ const int windowWidth = (int) ceil(args->Size.Width);
+ const int windowHeight = (int) ceil(args->Size.Height);
+ SDL_SendWindowEvent(
+ m_sdlWindowData->sdlWindow,
+ SDL_WINDOWEVENT_RESIZED,
+ windowWidth,
+ windowHeight);
+
+ // Viewport hack, part two:
+ if (usingD3D11Renderer) {
+ rendererForMainWindow->resized = wasD3D11RendererResized;
+ }
+ }
+}
+
+void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args)
+{
+#if LOG_WINDOW_EVENTS==1
+ SDL_Log("%s, visible?=%s, m_sdlWindowData?=%s\n",
+ __FUNCTION__,
+ (args->Visible ? "yes" : "no"),
+ (m_sdlWindowData ? "yes" : "no"));
+#endif
+
+ m_windowVisible = args->Visible;
+ if (m_sdlWindowData) {
+ SDL_bool wasSDLWindowSurfaceValid = m_sdlWindowData->sdlWindow->surface_valid;
+
+ if (args->Visible) {
+ SDL_SendWindowEvent(m_sdlWindowData->sdlWindow, SDL_WINDOWEVENT_SHOWN, 0, 0);
+ } else {
+ SDL_SendWindowEvent(m_sdlWindowData->sdlWindow, SDL_WINDOWEVENT_HIDDEN, 0, 0);
+ }
+
+ // HACK: Prevent SDL's window-hide handling code, which currently
+ // triggers a fake window resize (possibly erronously), from
+ // marking the SDL window's surface as invalid.
+ //
+ // A better solution to this probably involves figuring out if the
+ // fake window resize can be prevented.
+ m_sdlWindowData->sdlWindow->surface_valid = wasSDLWindowSurfaceValid;
+ }
+}
+
+void SDL_WinRTApp::OnWindowClosed(CoreWindow^ sender, CoreWindowEventArgs^ args)
+{
+#if LOG_WINDOW_EVENTS==1
+ SDL_Log("%s\n", __FUNCTION__);
+#endif
+ m_windowClosed = true;
+}
+
+static Uint8
+WINRT_GetSDLButtonForPointerPoint(PointerPoint ^ pt)
+{
+ switch (pt->Properties->PointerUpdateKind)
+ {
+ case PointerUpdateKind::LeftButtonPressed:
+ case PointerUpdateKind::LeftButtonReleased:
+ return SDL_BUTTON_LEFT;
+
+ case PointerUpdateKind::RightButtonPressed:
+ case PointerUpdateKind::RightButtonReleased:
+ return SDL_BUTTON_RIGHT;
+
+ case PointerUpdateKind::MiddleButtonPressed:
+ case PointerUpdateKind::MiddleButtonReleased:
+ return SDL_BUTTON_MIDDLE;
+
+ case PointerUpdateKind::XButton1Pressed:
+ case PointerUpdateKind::XButton1Released:
+ return SDL_BUTTON_X1;
+
+ case PointerUpdateKind::XButton2Pressed:
+ case PointerUpdateKind::XButton2Released:
+ return SDL_BUTTON_X2;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static const char *
+WINRT_ConvertPointerUpdateKindToString(PointerUpdateKind kind)
+{
+ switch (kind)
+ {
+ case PointerUpdateKind::Other:
+ return "Other";
+ case PointerUpdateKind::LeftButtonPressed:
+ return "LeftButtonPressed";
+ case PointerUpdateKind::LeftButtonReleased:
+ return "LeftButtonReleased";
+ case PointerUpdateKind::RightButtonPressed:
+ return "RightButtonPressed";
+ case PointerUpdateKind::RightButtonReleased:
+ return "RightButtonReleased";
+ case PointerUpdateKind::MiddleButtonPressed:
+ return "MiddleButtonPressed";
+ case PointerUpdateKind::MiddleButtonReleased:
+ return "MiddleButtonReleased";
+ case PointerUpdateKind::XButton1Pressed:
+ return "XButton1Pressed";
+ case PointerUpdateKind::XButton1Released:
+ return "XButton1Released";
+ case PointerUpdateKind::XButton2Pressed:
+ return "XButton2Pressed";
+ case PointerUpdateKind::XButton2Released:
+ return "XButton2Released";
+ }
+
+ return "";
+}
+
+static void
+WINRT_LogPointerEvent(const string & header, PointerEventArgs ^ args, Point transformedPoint)
+{
+ PointerPoint ^ pt = args->CurrentPoint;
+ SDL_Log("%s: Position={%f,%f}, Transformed Pos={%f, %f}, MouseWheelDelta=%d, FrameId=%d, PointerId=%d, PointerUpdateKind=%s\n",
+ header.c_str(),
+ pt->Position.X, pt->Position.Y,
+ transformedPoint.X, transformedPoint.Y,
+ pt->Properties->MouseWheelDelta,
+ pt->FrameId,
+ pt->PointerId,
+ WINRT_ConvertPointerUpdateKindToString(args->CurrentPoint->Properties->PointerUpdateKind));
+}
+
+void SDL_WinRTApp::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args)
+{
+#if LOG_POINTER_EVENTS
+ WINRT_LogPointerEvent("mouse down", args, TransformCursor(args->CurrentPoint->Position));
+#endif
+
+ if (m_sdlWindowData) {
+ Uint8 button = WINRT_GetSDLButtonForPointerPoint(args->CurrentPoint);
+ if (button) {
+ SDL_SendMouseButton(m_sdlWindowData->sdlWindow, 0, SDL_PRESSED, button);
+ }
+ }
+}
+
+void SDL_WinRTApp::OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args)
+{
+#if LOG_POINTER_EVENTS
+ WINRT_LogPointerEvent("mouse up", args, TransformCursor(args->CurrentPoint->Position));
+#endif
+
+ if (m_sdlWindowData) {
+ Uint8 button = WINRT_GetSDLButtonForPointerPoint(args->CurrentPoint);
+ if (button) {
+ SDL_SendMouseButton(m_sdlWindowData->sdlWindow, 0, SDL_RELEASED, button);
+ }
+ }
+}
+
+void SDL_WinRTApp::OnPointerWheelChanged(CoreWindow^ sender, PointerEventArgs^ args)
+{
+#if LOG_POINTER_EVENTS
+ WINRT_LogPointerEvent("wheel changed", args, TransformCursor(args->CurrentPoint->Position));
+#endif
+
+ if (m_sdlWindowData) {
+ // FIXME: This may need to accumulate deltas up to WHEEL_DELTA
+ short motion = args->CurrentPoint->Properties->MouseWheelDelta / WHEEL_DELTA;
+ SDL_SendMouseWheel(m_sdlWindowData->sdlWindow, 0, 0, motion);
+ }
+}
+
+static inline int _lround(float arg) {
+ if (arg >= 0.0f) {
+ return (int)floor(arg + 0.5f);
+ } else {
+ return (int)ceil(arg - 0.5f);
+ }
+}
+
+void SDL_WinRTApp::OnMouseMoved(MouseDevice^ mouseDevice, MouseEventArgs^ args)
+{
+ if (m_sdlWindowData && m_useRelativeMouseMode) {
+ // DLudwig, 2012-12-28: On some systems, namely Visual Studio's Windows
+ // Simulator, as well as Windows 8 in a Parallels 8 VM, MouseEventArgs'
+ // MouseDelta field often reports very large values. More information
+ // on this can be found at the following pages on MSDN:
+ // - http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/a3c789fa-f1c5-49c4-9c0a-7db88d0f90f8
+ // - https://connect.microsoft.com/VisualStudio/Feedback/details/756515
+ //
+ // The values do not appear to be as large when running on some systems,
+ // most notably a Surface RT. Furthermore, the values returned by
+ // CoreWindow's PointerMoved event, and sent to this class' OnPointerMoved
+ // method, do not ever appear to be large, even when MouseEventArgs'
+ // MouseDelta is reporting to the contrary.
+ //
+ // On systems with the large-values behavior, it appears that the values
+ // get reported as if the screen's size is 65536 units in both the X and Y
+ // dimensions. This can be viewed by using Windows' now-private, "Raw Input"
+ // APIs. (GetRawInputData, RegisterRawInputDevices, WM_INPUT, etc.)
+ //
+ // MSDN's documentation on MouseEventArgs' MouseDelta field (at
+ // http://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.input.mouseeventargs.mousedelta ),
+ // does not seem to indicate (to me) that its values should be so large. It
+ // says that its values should be a "change in screen location". I could
+ // be misinterpreting this, however a post on MSDN from a Microsoft engineer (see:
+ // http://social.msdn.microsoft.com/Forums/en-US/winappswithnativecode/thread/09a9868e-95bb-4858-ba1a-cb4d2c298d62 ),
+ // indicates that these values are in DIPs, which is the same unit used
+ // by CoreWindow's PointerMoved events (via the Position field in its CurrentPoint
+ // property. See http://msdn.microsoft.com/en-us/library/windows/apps/windows.ui.input.pointerpoint.position.aspx
+ // for details.)
+ //
+ // To note, PointerMoved events are sent a 'RawPosition' value (via the
+ // CurrentPoint property in MouseEventArgs), however these do not seem
+ // to exhibit the same large-value behavior.
+ //
+ // The values passed via PointerMoved events can't always be used for relative
+ // mouse motion, unfortunately. Its values are bound to the cursor's position,
+ // which stops when it hits one of the screen's edges. This can be a problem in
+ // first person shooters, whereby it is normal for mouse motion to travel far
+ // along any one axis for a period of time. MouseMoved events do not have the
+ // screen-bounding limitation, and can be used regardless of where the system's
+ // cursor is.
+ //
+ // One possible workaround would be to programmatically set the cursor's
+ // position to the screen's center (when SDL's relative mouse mode is enabled),
+ // however Windows RT does not yet seem to have the ability to set the cursor's
+ // position via a public API. Win32 did this via an API call, SetCursorPos,
+ // however WinRT makes this function be private. Apps that use it won't get
+ // approved for distribution in the Windows Store. I've yet to be able to find
+ // a suitable, store-friendly counterpart for WinRT.
+ //
+ // There may be some room for a workaround whereby OnPointerMoved's values
+ // are compared to the values from OnMouseMoved in order to detect
+ // when this bug is active. A suitable transformation could then be made to
+ // OnMouseMoved's values. For now, however, the system-reported values are sent
+ // to SDL with minimal transformation: from native screen coordinates (in DIPs)
+ // to SDL window coordinates.
+ //
+ const Point mouseDeltaInDIPs((float)args->MouseDelta.X, (float)args->MouseDelta.Y);
+ const Point mouseDeltaInSDLWindowCoords = TransformCursor(mouseDeltaInDIPs);
+ SDL_SendMouseMotion(
+ m_sdlWindowData->sdlWindow,
+ 0,
+ 1,
+ _lround(mouseDeltaInSDLWindowCoords.X),
+ _lround(mouseDeltaInSDLWindowCoords.Y));
+ }
+}
+
+// Applies necessary geometric transformations to raw cursor positions:
+Point SDL_WinRTApp::TransformCursor(Point rawPosition)
+{
+ if ( ! m_sdlWindowData || ! m_sdlWindowData->sdlWindow ) {
+ return rawPosition;
+ }
+ CoreWindow ^ nativeWindow = CoreWindow::GetForCurrentThread();
+ Point outputPosition;
+ outputPosition.X = rawPosition.X * (((float32)m_sdlWindowData->sdlWindow->w) / nativeWindow->Bounds.Width);
+ outputPosition.Y = rawPosition.Y * (((float32)m_sdlWindowData->sdlWindow->h) / nativeWindow->Bounds.Height);
+ return outputPosition;
+}
+
+void SDL_WinRTApp::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args)
+{
+#if LOG_POINTER_EVENTS
+ WINRT_LogPointerEvent("pointer moved", args, TransformCursor(args->CurrentPoint->Position));
+#endif
+
+ if (m_sdlWindowData && ! m_useRelativeMouseMode)
+ {
+ Point transformedPoint = TransformCursor(args->CurrentPoint->Position);
+ SDL_SendMouseMotion(m_sdlWindowData->sdlWindow, 0, 0, (int)transformedPoint.X, (int)transformedPoint.Y);
+ }
+}
+
+static SDL_Scancode WinRT_Official_Keycodes[] = {
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.None -- 0
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.LeftButton -- 1
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.RightButton -- 2
+ SDL_SCANCODE_CANCEL, // VirtualKey.Cancel -- 3
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.MiddleButton -- 4
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.XButton1 -- 5
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.XButton2 -- 6
+ SDL_SCANCODE_UNKNOWN, // -- 7
+ SDL_SCANCODE_BACKSPACE, // VirtualKey.Back -- 8
+ SDL_SCANCODE_TAB, // VirtualKey.Tab -- 9
+ SDL_SCANCODE_UNKNOWN, // -- 10
+ SDL_SCANCODE_UNKNOWN, // -- 11
+ SDL_SCANCODE_CLEAR, // VirtualKey.Clear -- 12
+ SDL_SCANCODE_RETURN, // VirtualKey.Enter -- 13
+ SDL_SCANCODE_UNKNOWN, // -- 14
+ SDL_SCANCODE_UNKNOWN, // -- 15
+ SDL_SCANCODE_LSHIFT, // VirtualKey.Shift -- 16
+ SDL_SCANCODE_LCTRL, // VirtualKey.Control -- 17
+ SDL_SCANCODE_MENU, // VirtualKey.Menu -- 18
+ SDL_SCANCODE_PAUSE, // VirtualKey.Pause -- 19
+ SDL_SCANCODE_CAPSLOCK, // VirtualKey.CapitalLock -- 20
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.Kana or VirtualKey.Hangul -- 21
+ SDL_SCANCODE_UNKNOWN, // -- 22
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.Junja -- 23
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.Final -- 24
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.Hanja or VirtualKey.Kanji -- 25
+ SDL_SCANCODE_UNKNOWN, // -- 26
+ SDL_SCANCODE_ESCAPE, // VirtualKey.Escape -- 27
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.Convert -- 28
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.NonConvert -- 29
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.Accept -- 30
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.ModeChange -- 31 (maybe SDL_SCANCODE_MODE ?)
+ SDL_SCANCODE_SPACE, // VirtualKey.Space -- 32
+ SDL_SCANCODE_PAGEUP, // VirtualKey.PageUp -- 33
+ SDL_SCANCODE_PAGEDOWN, // VirtualKey.PageDown -- 34
+ SDL_SCANCODE_END, // VirtualKey.End -- 35
+ SDL_SCANCODE_HOME, // VirtualKey.Home -- 36
+ SDL_SCANCODE_LEFT, // VirtualKey.Left -- 37
+ SDL_SCANCODE_UP, // VirtualKey.Up -- 38
+ SDL_SCANCODE_RIGHT, // VirtualKey.Right -- 39
+ SDL_SCANCODE_DOWN, // VirtualKey.Down -- 40
+ SDL_SCANCODE_SELECT, // VirtualKey.Select -- 41
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.Print -- 42 (maybe SDL_SCANCODE_PRINTSCREEN ?)
+ SDL_SCANCODE_EXECUTE, // VirtualKey.Execute -- 43
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.Snapshot -- 44
+ SDL_SCANCODE_INSERT, // VirtualKey.Insert -- 45
+ SDL_SCANCODE_DELETE, // VirtualKey.Delete -- 46
+ SDL_SCANCODE_HELP, // VirtualKey.Help -- 47
+ SDL_SCANCODE_0, // VirtualKey.Number0 -- 48
+ SDL_SCANCODE_1, // VirtualKey.Number1 -- 49
+ SDL_SCANCODE_2, // VirtualKey.Number2 -- 50
+ SDL_SCANCODE_3, // VirtualKey.Number3 -- 51
+ SDL_SCANCODE_4, // VirtualKey.Number4 -- 52
+ SDL_SCANCODE_5, // VirtualKey.Number5 -- 53
+ SDL_SCANCODE_6, // VirtualKey.Number6 -- 54
+ SDL_SCANCODE_7, // VirtualKey.Number7 -- 55
+ SDL_SCANCODE_8, // VirtualKey.Number8 -- 56
+ SDL_SCANCODE_9, // VirtualKey.Number9 -- 57
+ SDL_SCANCODE_UNKNOWN, // -- 58
+ SDL_SCANCODE_UNKNOWN, // -- 59
+ SDL_SCANCODE_UNKNOWN, // -- 60
+ SDL_SCANCODE_UNKNOWN, // -- 61
+ SDL_SCANCODE_UNKNOWN, // -- 62
+ SDL_SCANCODE_UNKNOWN, // -- 63
+ SDL_SCANCODE_UNKNOWN, // -- 64
+ SDL_SCANCODE_A, // VirtualKey.A -- 65
+ SDL_SCANCODE_B, // VirtualKey.B -- 66
+ SDL_SCANCODE_C, // VirtualKey.C -- 67
+ SDL_SCANCODE_D, // VirtualKey.D -- 68
+ SDL_SCANCODE_E, // VirtualKey.E -- 69
+ SDL_SCANCODE_F, // VirtualKey.F -- 70
+ SDL_SCANCODE_G, // VirtualKey.G -- 71
+ SDL_SCANCODE_H, // VirtualKey.H -- 72
+ SDL_SCANCODE_I, // VirtualKey.I -- 73
+ SDL_SCANCODE_J, // VirtualKey.J -- 74
+ SDL_SCANCODE_K, // VirtualKey.K -- 75
+ SDL_SCANCODE_L, // VirtualKey.L -- 76
+ SDL_SCANCODE_M, // VirtualKey.M -- 77
+ SDL_SCANCODE_N, // VirtualKey.N -- 78
+ SDL_SCANCODE_O, // VirtualKey.O -- 79
+ SDL_SCANCODE_P, // VirtualKey.P -- 80
+ SDL_SCANCODE_Q, // VirtualKey.Q -- 81
+ SDL_SCANCODE_R, // VirtualKey.R -- 82
+ SDL_SCANCODE_S, // VirtualKey.S -- 83
+ SDL_SCANCODE_T, // VirtualKey.T -- 84
+ SDL_SCANCODE_U, // VirtualKey.U -- 85
+ SDL_SCANCODE_V, // VirtualKey.V -- 86
+ SDL_SCANCODE_W, // VirtualKey.W -- 87
+ SDL_SCANCODE_X, // VirtualKey.X -- 88
+ SDL_SCANCODE_Y, // VirtualKey.Y -- 89
+ SDL_SCANCODE_Z, // VirtualKey.Z -- 90
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.LeftWindows -- 91 (maybe SDL_SCANCODE_APPLICATION or SDL_SCANCODE_LGUI ?)
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.RightWindows -- 92 (maybe SDL_SCANCODE_APPLICATION or SDL_SCANCODE_RGUI ?)
+ SDL_SCANCODE_APPLICATION, // VirtualKey.Application -- 93
+ SDL_SCANCODE_UNKNOWN, // -- 94
+ SDL_SCANCODE_SLEEP, // VirtualKey.Sleep -- 95
+ SDL_SCANCODE_KP_0, // VirtualKey.NumberPad0 -- 96
+ SDL_SCANCODE_KP_1, // VirtualKey.NumberPad1 -- 97
+ SDL_SCANCODE_KP_2, // VirtualKey.NumberPad2 -- 98
+ SDL_SCANCODE_KP_3, // VirtualKey.NumberPad3 -- 99
+ SDL_SCANCODE_KP_4, // VirtualKey.NumberPad4 -- 100
+ SDL_SCANCODE_KP_5, // VirtualKey.NumberPad5 -- 101
+ SDL_SCANCODE_KP_6, // VirtualKey.NumberPad6 -- 102
+ SDL_SCANCODE_KP_7, // VirtualKey.NumberPad7 -- 103
+ SDL_SCANCODE_KP_8, // VirtualKey.NumberPad8 -- 104
+ SDL_SCANCODE_KP_9, // VirtualKey.NumberPad9 -- 105
+ SDL_SCANCODE_KP_MULTIPLY, // VirtualKey.Multiply -- 106
+ SDL_SCANCODE_KP_PLUS, // VirtualKey.Add -- 107
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.Separator -- 108
+ SDL_SCANCODE_KP_MINUS, // VirtualKey.Subtract -- 109
+ SDL_SCANCODE_UNKNOWN, // VirtualKey.Decimal -- 110 (maybe SDL_SCANCODE_DECIMALSEPARATOR, SDL_SCANCODE_KP_DECIMAL, or SDL_SCANCODE_KP_PERIOD ?)
+ SDL_SCANCODE_KP_DIVIDE, // VirtualKey.Divide -- 111
+ SDL_SCANCODE_F1, // VirtualKey.F1 -- 112
+ SDL_SCANCODE_F2, // VirtualKey.F2 -- 113
+ SDL_SCANCODE_F3, // VirtualKey.F3 -- 114
+ SDL_SCANCODE_F4, // VirtualKey.F4 -- 115
+ SDL_SCANCODE_F5, // VirtualKey.F5 -- 116
+ SDL_SCANCODE_F6, // VirtualKey.F6 -- 117
+ SDL_SCANCODE_F7, // VirtualKey.F7 -- 118
+ SDL_SCANCODE_F8, // VirtualKey.F8 -- 119
+ SDL_SCANCODE_F9, // VirtualKey.F9 -- 120
+ SDL_SCANCODE_F10, // VirtualKey.F10 -- 121
+ SDL_SCANCODE_F11, // VirtualKey.F11 -- 122
+ SDL_SCANCODE_F12, // VirtualKey.F12 -- 123
+ SDL_SCANCODE_F13, // VirtualKey.F13 -- 124
+ SDL_SCANCODE_F14, // VirtualKey.F14 -- 125
+ SDL_SCANCODE_F15, // VirtualKey.F15 -- 126
+ SDL_SCANCODE_F16, // VirtualKey.F16 -- 127
+ SDL_SCANCODE_F17, // VirtualKey.F17 -- 128
+ SDL_SCANCODE_F18, // VirtualKey.F18 -- 129
+ SDL_SCANCODE_F19, // VirtualKey.F19 -- 130
+ SDL_SCANCODE_F20, // VirtualKey.F20 -- 131
+ SDL_SCANCODE_F21, // VirtualKey.F21 -- 132
+ SDL_SCANCODE_F22, // VirtualKey.F22 -- 133
+ SDL_SCANCODE_F23, // VirtualKey.F23 -- 134
+ SDL_SCANCODE_F24, // VirtualKey.F24 -- 135
+ SDL_SCANCODE_UNKNOWN, // -- 136
+ SDL_SCANCODE_UNKNOWN, // -- 137
+ SDL_SCANCODE_UNKNOWN, // -- 138
+ SDL_SCANCODE_UNKNOWN, // -- 139
+ SDL_SCANCODE_UNKNOWN, // -- 140
+ SDL_SCANCODE_UNKNOWN, // -- 141
+ SDL_SCANCODE_UNKNOWN, // -- 142
+ SDL_SCANCODE_UNKNOWN, // -- 143
+ SDL_SCANCODE_NUMLOCKCLEAR, // VirtualKey.NumberKeyLock -- 144
+ SDL_SCANCODE_SCROLLLOCK, // VirtualKey.Scroll -- 145
+ SDL_SCANCODE_UNKNOWN, // -- 146
+ SDL_SCANCODE_UNKNOWN, // -- 147
+ SDL_SCANCODE_UNKNOWN, // -- 148
+ SDL_SCANCODE_UNKNOWN, // -- 149
+ SDL_SCANCODE_UNKNOWN, // -- 150
+ SDL_SCANCODE_UNKNOWN, // -- 151
+ SDL_SCANCODE_UNKNOWN, // -- 152
+ SDL_SCANCODE_UNKNOWN, // -- 153
+ SDL_SCANCODE_UNKNOWN, // -- 154
+ SDL_SCANCODE_UNKNOWN, // -- 155
+ SDL_SCANCODE_UNKNOWN, // -- 156
+ SDL_SCANCODE_UNKNOWN, // -- 157
+ SDL_SCANCODE_UNKNOWN, // -- 158
+ SDL_SCANCODE_UNKNOWN, // -- 159
+ SDL_SCANCODE_LSHIFT, // VirtualKey.LeftShift -- 160
+ SDL_SCANCODE_RSHIFT, // VirtualKey.RightShift -- 161
+ SDL_SCANCODE_LCTRL, // VirtualKey.LeftControl -- 162
+ SDL_SCANCODE_RCTRL, // VirtualKey.RightControl -- 163
+ SDL_SCANCODE_MENU, // VirtualKey.LeftMenu -- 164
+ SDL_SCANCODE_MENU, // VirtualKey.RightMenu -- 165
+};
+
+static std::unordered_map WinRT_Unofficial_Keycodes;
+
+static SDL_Scancode
+TranslateKeycode(int keycode)
+{
+ if (WinRT_Unofficial_Keycodes.empty()) {
+ /* Set up a table of undocumented (by Microsoft), WinRT-specific,
+ key codes: */
+ // TODO, WinRT: move content declarations of WinRT_Unofficial_Keycodes into a C++11 initializer list, when possible
+ WinRT_Unofficial_Keycodes[220] = SDL_SCANCODE_GRAVE;
+ WinRT_Unofficial_Keycodes[222] = SDL_SCANCODE_BACKSLASH;
+ }
+
+ /* Try to get a documented, WinRT, 'VirtualKey' first (as documented at
+ http://msdn.microsoft.com/en-us/library/windows/apps/windows.system.virtualkey.aspx ).
+ If that fails, fall back to a Win32 virtual key.
+ */
+ // TODO, WinRT: try filling out the WinRT keycode table as much as possible, using the Win32 table for interpretation hints
+ //SDL_Log("WinRT TranslateKeycode, keycode=%d\n", (int)keycode);
+ SDL_Scancode scancode = SDL_SCANCODE_UNKNOWN;
+ if (keycode < SDL_arraysize(WinRT_Official_Keycodes)) {
+ scancode = WinRT_Official_Keycodes[keycode];
+ }
+ if (scancode == SDL_SCANCODE_UNKNOWN) {
+ if (WinRT_Unofficial_Keycodes.find(keycode) != WinRT_Unofficial_Keycodes.end()) {
+ scancode = WinRT_Unofficial_Keycodes[keycode];
+ }
+ }
+ if (scancode == SDL_SCANCODE_UNKNOWN) {
+ if (keycode < SDL_arraysize(windows_scancode_table)) {
+ scancode = windows_scancode_table[keycode];
+ }
+ }
+ if (scancode == SDL_SCANCODE_UNKNOWN) {
+ SDL_Log("WinRT TranslateKeycode, unknown keycode=%d\n", (int)keycode);
+ }
+ return scancode;
+}
+
+void SDL_WinRTApp::OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
+{
+ SDL_Scancode sdlScancode = TranslateKeycode((int)args->VirtualKey);
+#if 0
+ SDL_Keycode keycode = SDL_GetKeyFromScancode(sdlScancode);
+ SDL_Log("key down, handled=%s, ext?=%s, released?=%s, menu key down?=%s, repeat count=%d, native scan code=%d, was down?=%s, vkey=%d, sdl scan code=%d (%s), sdl key code=%d (%s)\n",
+ (args->Handled ? "1" : "0"),
+ (args->KeyStatus.IsExtendedKey ? "1" : "0"),
+ (args->KeyStatus.IsKeyReleased ? "1" : "0"),
+ (args->KeyStatus.IsMenuKeyDown ? "1" : "0"),
+ args->KeyStatus.RepeatCount,
+ args->KeyStatus.ScanCode,
+ (args->KeyStatus.WasKeyDown ? "1" : "0"),
+ args->VirtualKey,
+ sdlScancode,
+ SDL_GetScancodeName(sdlScancode),
+ keycode,
+ SDL_GetKeyName(keycode));
+ //args->Handled = true;
+ //VirtualKey vkey = args->VirtualKey;
+#endif
+ SDL_SendKeyboardKey(SDL_PRESSED, sdlScancode);
+}
+
+void SDL_WinRTApp::OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args)
+{
+ SDL_Scancode sdlScancode = TranslateKeycode((int)args->VirtualKey);
+#if 0
+ SDL_Keycode keycode = SDL_GetKeyFromScancode(sdlScancode);
+ SDL_Log("key up, handled=%s, ext?=%s, released?=%s, menu key down?=%s, repeat count=%d, native scan code=%d, was down?=%s, vkey=%d, sdl scan code=%d (%s), sdl key code=%d (%s)\n",
+ (args->Handled ? "1" : "0"),
+ (args->KeyStatus.IsExtendedKey ? "1" : "0"),
+ (args->KeyStatus.IsKeyReleased ? "1" : "0"),
+ (args->KeyStatus.IsMenuKeyDown ? "1" : "0"),
+ args->KeyStatus.RepeatCount,
+ args->KeyStatus.ScanCode,
+ (args->KeyStatus.WasKeyDown ? "1" : "0"),
+ args->VirtualKey,
+ sdlScancode,
+ SDL_GetScancodeName(sdlScancode),
+ keycode,
+ SDL_GetKeyName(keycode));
+ //args->Handled = true;
+#endif
+ SDL_SendKeyboardKey(SDL_RELEASED, sdlScancode);
+}
+
+void SDL_WinRTApp::OnActivated(CoreApplicationView^ applicationView, IActivatedEventArgs^ args)
+{
+ CoreWindow::GetForCurrentThread()->Activate();
+}
+
+static int SDLCALL RemoveAppSuspendAndResumeEvents(void * userdata, SDL_Event * event)
+{
+ if (event->type == SDL_WINDOWEVENT)
+ {
+ switch (event->window.event)
+ {
+ case SDL_WINDOWEVENT_MINIMIZED:
+ case SDL_WINDOWEVENT_RESTORED:
+ // Return 0 to indicate that the event should be removed from the
+ // event queue:
+ return 0;
+ default:
+ break;
+ }
+ }
+
+ // Return 1 to indicate that the event should stay in the event queue:
+ return 1;
+}
+
+void SDL_WinRTApp::OnSuspending(Platform::Object^ sender, SuspendingEventArgs^ args)
+{
+ // Save app state asynchronously after requesting a deferral. Holding a deferral
+ // indicates that the application is busy performing suspending operations. Be
+ // aware that a deferral may not be held indefinitely. After about five seconds,
+ // the app will be forced to exit.
+ SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();
+ create_task([this, deferral]()
+ {
+ // Send a window-minimized event immediately to observers.
+ // CoreDispatcher::ProcessEvents, which is the backbone on which
+ // SDL_WinRTApp::PumpEvents is built, will not return to its caller
+ // once it sends out a suspend event. Any events posted to SDL's
+ // event queue won't get received until the WinRT app is resumed.
+ // SDL_AddEventWatch() may be used to receive app-suspend events on
+ // WinRT.
+ //
+ // In order to prevent app-suspend events from being received twice:
+ // first via a callback passed to SDL_AddEventWatch, and second via
+ // SDL's event queue, the event will be sent to SDL, then immediately
+ // removed from the queue.
+ if (m_sdlWindowData)
+ {
+ SDL_SendWindowEvent(m_sdlWindowData->sdlWindow, SDL_WINDOWEVENT_MINIMIZED, 0, 0); // TODO: see if SDL_WINDOWEVENT_SIZE_CHANGED should be getting triggered here (it is, currently)
+ SDL_FilterEvents(RemoveAppSuspendAndResumeEvents, 0);
+ }
+ deferral->Complete();
+ });
+}
+
+void SDL_WinRTApp::OnResuming(Platform::Object^ sender, Platform::Object^ args)
+{
+ // Restore any data or state that was unloaded on suspend. By default, data
+ // and state are persisted when resuming from suspend. Note that this event
+ // does not occur if the app was previously terminated.
+ if (m_sdlWindowData)
+ {
+ SDL_SendWindowEvent(m_sdlWindowData->sdlWindow, SDL_WINDOWEVENT_RESTORED, 0, 0); // TODO: see if SDL_WINDOWEVENT_SIZE_CHANGED should be getting triggered here (it is, currently)
+
+ // Remove the app-resume event from the queue, as is done with the
+ // app-suspend event.
+ //
+ // TODO, WinRT: consider posting this event to the queue even though
+ // its counterpart, the app-suspend event, effectively has to be
+ // processed immediately.
+ SDL_FilterEvents(RemoveAppSuspendAndResumeEvents, 0);
+ }
+}
+
+SDL_DisplayMode SDL_WinRTApp::GetMainDisplayMode()
+{
+ // Create an empty, zeroed-out display mode:
+ SDL_DisplayMode mode;
+ SDL_zero(mode);
+
+ // Fill in most fields:
+ mode.format = SDL_PIXELFORMAT_RGB888;
+ mode.refresh_rate = 0; // TODO, WinRT: see if refresh rate data is available, or relevant (for WinRT apps)
+ mode.driverdata = NULL;
+
+ // Calculate the display size given the window size, taking into account
+ // the current display's DPI:
+ const float currentDPI = Windows::Graphics::Display::DisplayProperties::LogicalDpi;
+ const float dipsPerInch = 96.0f;
+ mode.w = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Width * currentDPI) / dipsPerInch);
+ mode.h = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Height * currentDPI) / dipsPerInch);
+
+ return mode;
+}
+
+const SDL_WindowData * SDL_WinRTApp::GetSDLWindowData() const
+{
+ return m_sdlWindowData;
+}
+
+bool SDL_WinRTApp::HasSDLWindowData() const
+{
+ return (m_sdlWindowData != NULL);
+}
+
+void SDL_WinRTApp::SetRelativeMouseMode(bool enable)
+{
+ m_useRelativeMouseMode = enable;
+}
+
+void SDL_WinRTApp::SetSDLWindowData(const SDL_WindowData * windowData)
+{
+ m_sdlWindowData = windowData;
+}
+
+void SDL_WinRTApp::SetSDLVideoDevice(const SDL_VideoDevice * videoDevice)
+{
+ m_sdlVideoDevice = videoDevice;
+}
diff --git a/src/video/windowsrt/SDL_WinRTApp.h b/src/video/windowsrt/SDL_WinRTApp.h
new file mode 100644
index 000000000..cd0c379fc
--- /dev/null
+++ b/src/video/windowsrt/SDL_WinRTApp.h
@@ -0,0 +1,52 @@
+#pragma once
+
+struct SDL_WindowData;
+
+ref class SDL_WinRTApp sealed : public Windows::ApplicationModel::Core::IFrameworkView
+{
+public:
+ SDL_WinRTApp();
+
+ // IFrameworkView Methods.
+ virtual void Initialize(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView);
+ virtual void SetWindow(Windows::UI::Core::CoreWindow^ window);
+ virtual void Load(Platform::String^ entryPoint);
+ virtual void Run();
+ virtual void Uninitialize();
+
+internal:
+ // SDL-specific methods
+ SDL_DisplayMode GetMainDisplayMode();
+ void PumpEvents();
+ const SDL_WindowData * GetSDLWindowData() const;
+ bool HasSDLWindowData() const;
+ void SetRelativeMouseMode(bool enable);
+ void SetSDLWindowData(const SDL_WindowData * windowData);
+ void SetSDLVideoDevice(const SDL_VideoDevice * videoDevice);
+ Windows::Foundation::Point TransformCursor(Windows::Foundation::Point rawPosition);
+
+protected:
+ // Event Handlers.
+ void OnOrientationChanged(Platform::Object^ sender);
+ void OnWindowSizeChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::WindowSizeChangedEventArgs^ args);
+ void OnLogicalDpiChanged(Platform::Object^ sender);
+ void OnActivated(Windows::ApplicationModel::Core::CoreApplicationView^ applicationView, Windows::ApplicationModel::Activation::IActivatedEventArgs^ args);
+ void OnSuspending(Platform::Object^ sender, Windows::ApplicationModel::SuspendingEventArgs^ args);
+ void OnResuming(Platform::Object^ sender, Platform::Object^ args);
+ void OnWindowClosed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::CoreWindowEventArgs^ args);
+ void OnVisibilityChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::VisibilityChangedEventArgs^ args);
+ void OnPointerPressed(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+ void OnPointerReleased(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+ void OnPointerWheelChanged(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+ void OnPointerMoved(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::PointerEventArgs^ args);
+ void OnMouseMoved(Windows::Devices::Input::MouseDevice^ mouseDevice, Windows::Devices::Input::MouseEventArgs^ args);
+ void OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args);
+ void OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args);
+
+private:
+ bool m_windowClosed;
+ bool m_windowVisible;
+ const SDL_WindowData* m_sdlWindowData;
+ const SDL_VideoDevice* m_sdlVideoDevice;
+ bool m_useRelativeMouseMode;
+};
diff --git a/src/video/windowsrt/SDL_winrtevents.cpp b/src/video/windowsrt/SDL_winrtevents.cpp
new file mode 100644
index 000000000..f445b8b65
--- /dev/null
+++ b/src/video/windowsrt/SDL_winrtevents.cpp
@@ -0,0 +1,41 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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"
+
+#if SDL_VIDEO_DRIVER_WINRT
+
+#include "../../events/SDL_events_c.h"
+
+#include "SDL_winrtvideo.h"
+#include "SDL_winrtevents_c.h"
+#include "SDL_WinRTApp.h"
+
+extern SDL_WinRTApp ^ SDL_WinRTGlobalApp;
+
+void
+WINRT_PumpEvents(_THIS)
+{
+ SDL_WinRTGlobalApp->PumpEvents();
+}
+
+#endif /* SDL_VIDEO_DRIVER_WINRT */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/windowsrt/SDL_winrtevents_c.h b/src/video/windowsrt/SDL_winrtevents_c.h
new file mode 100644
index 000000000..afbd6862c
--- /dev/null
+++ b/src/video/windowsrt/SDL_winrtevents_c.h
@@ -0,0 +1,27 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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_winrtvideo.h"
+
+extern void WINRT_PumpEvents(_THIS);
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/windowsrt/SDL_winrtmouse.cpp b/src/video/windowsrt/SDL_winrtmouse.cpp
new file mode 100644
index 000000000..e0450c655
--- /dev/null
+++ b/src/video/windowsrt/SDL_winrtmouse.cpp
@@ -0,0 +1,149 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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"
+
+#if SDL_VIDEO_DRIVER_WINRT
+
+extern "C" {
+#include "SDL_assert.h"
+#include "../../events/SDL_mouse_c.h"
+#include "../SDL_sysvideo.h"
+}
+
+#include "SDL_WinRTApp.h"
+#include "SDL_winrtmouse.h"
+
+using namespace Windows::UI::Core;
+using Windows::UI::Core::CoreCursor;
+
+extern SDL_WinRTApp ^ SDL_WinRTGlobalApp;
+
+
+static SDL_Cursor *
+WINRT_CreateSystemCursor(SDL_SystemCursor id)
+{
+ SDL_Cursor *cursor;
+ CoreCursorType cursorType = CoreCursorType::Arrow;
+
+ switch(id)
+ {
+ default:
+ SDL_assert(0);
+ return NULL;
+ case SDL_SYSTEM_CURSOR_ARROW: cursorType = CoreCursorType::Arrow; break;
+ case SDL_SYSTEM_CURSOR_IBEAM: cursorType = CoreCursorType::IBeam; break;
+ case SDL_SYSTEM_CURSOR_WAIT: cursorType = CoreCursorType::Wait; break;
+ case SDL_SYSTEM_CURSOR_CROSSHAIR: cursorType = CoreCursorType::Cross; break;
+ case SDL_SYSTEM_CURSOR_WAITARROW: cursorType = CoreCursorType::Wait; break;
+ case SDL_SYSTEM_CURSOR_SIZENWSE: cursorType = CoreCursorType::SizeNorthwestSoutheast; break;
+ case SDL_SYSTEM_CURSOR_SIZENESW: cursorType = CoreCursorType::SizeNortheastSouthwest; break;
+ case SDL_SYSTEM_CURSOR_SIZEWE: cursorType = CoreCursorType::SizeWestEast; break;
+ case SDL_SYSTEM_CURSOR_SIZENS: cursorType = CoreCursorType::SizeNorthSouth; break;
+ case SDL_SYSTEM_CURSOR_SIZEALL: cursorType = CoreCursorType::SizeAll; break;
+ case SDL_SYSTEM_CURSOR_NO: cursorType = CoreCursorType::UniversalNo; break;
+ case SDL_SYSTEM_CURSOR_HAND: cursorType = CoreCursorType::Hand; break;
+ }
+
+ cursor = (SDL_Cursor *) SDL_calloc(1, sizeof(*cursor));
+ if (cursor) {
+ /* Create a pointer to a COM reference to a cursor. The extra
+ pointer is used (on top of the COM reference) to allow the cursor
+ to be referenced by the SDL_cursor's driverdata field, which is
+ a void pointer.
+ */
+ CoreCursor ^* theCursor = new CoreCursor^(nullptr);
+ *theCursor = ref new CoreCursor(cursorType, 0);
+ cursor->driverdata = (void *) theCursor;
+ } else {
+ SDL_OutOfMemory();
+ }
+
+ return cursor;
+}
+
+static SDL_Cursor *
+WINRT_CreateDefaultCursor()
+{
+ return WINRT_CreateSystemCursor(SDL_SYSTEM_CURSOR_ARROW);
+}
+
+static void
+WINRT_FreeCursor(SDL_Cursor * cursor)
+{
+ if (cursor->driverdata) {
+ CoreCursor ^* theCursor = (CoreCursor ^*) cursor->driverdata;
+ *theCursor = nullptr; // Release the COM reference to the CoreCursor
+ delete theCursor; // Delete the pointer to the COM reference
+ }
+ SDL_free(cursor);
+}
+
+static int
+WINRT_ShowCursor(SDL_Cursor * cursor)
+{
+ if (cursor) {
+ CoreCursor ^* theCursor = (CoreCursor ^*) cursor->driverdata;
+ CoreWindow::GetForCurrentThread()->PointerCursor = *theCursor;
+ } else {
+ CoreWindow::GetForCurrentThread()->PointerCursor = nullptr;
+ }
+ return 0;
+}
+
+static int
+WINRT_SetRelativeMouseMode(SDL_bool enabled)
+{
+ SDL_WinRTGlobalApp->SetRelativeMouseMode(enabled ? true : false);
+ return 0;
+}
+
+void
+WINRT_InitMouse(_THIS)
+{
+ SDL_Mouse *mouse = SDL_GetMouse();
+
+ /* DLudwig, Dec 3, 2012: Windows RT does not currently provide APIs for
+ the following features, AFAIK:
+ - custom cursors (multiple system cursors are, however, available)
+ - programmatically moveable cursors
+ */
+
+#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
+ //mouse->CreateCursor = WINRT_CreateCursor;
+ mouse->CreateSystemCursor = WINRT_CreateSystemCursor;
+ mouse->ShowCursor = WINRT_ShowCursor;
+ mouse->FreeCursor = WINRT_FreeCursor;
+ //mouse->WarpMouse = WINRT_WarpMouse;
+ mouse->SetRelativeMouseMode = WINRT_SetRelativeMouseMode;
+
+ SDL_SetDefaultCursor(WINRT_CreateDefaultCursor());
+#endif
+}
+
+void
+WINRT_QuitMouse(_THIS)
+{
+}
+
+#endif /* SDL_VIDEO_DRIVER_WINRT */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/windowsrt/SDL_winrtmouse.h b/src/video/windowsrt/SDL_winrtmouse.h
new file mode 100644
index 000000000..50bdbe24d
--- /dev/null
+++ b/src/video/windowsrt/SDL_winrtmouse.h
@@ -0,0 +1,31 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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"
+
+#ifndef _SDL_windowsmouse_h
+#define _SDL_windowsmouse_h
+
+extern void WINRT_InitMouse(_THIS);
+extern void WINRT_QuitMouse(_THIS);
+
+#endif /* _SDL_windowsmouse_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/windowsrt/SDL_winrtvideo.cpp b/src/video/windowsrt/SDL_winrtvideo.cpp
new file mode 100644
index 000000000..7a459fb95
--- /dev/null
+++ b/src/video/windowsrt/SDL_winrtvideo.cpp
@@ -0,0 +1,262 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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"
+
+#if SDL_VIDEO_DRIVER_WINRT
+
+/* WinRT SDL video driver implementation
+
+ Initial work on this was done by David Ludwig (dludwig@pobox.com), and
+ was based off of SDL's "dummy" video driver.
+ */
+
+extern "C" {
+#include "SDL_video.h"
+#include "SDL_mouse.h"
+#include "../SDL_sysvideo.h"
+#include "../SDL_pixels_c.h"
+#include "../../events/SDL_events_c.h"
+#include "../../render/SDL_sysrender.h"
+#include "SDL_syswm.h"
+}
+
+#include "SDL_WinRTApp.h"
+#include "SDL_winrtvideo.h"
+#include "SDL_winrtevents_c.h"
+#include "SDL_winrtmouse.h"
+
+using namespace Windows::UI::Core;
+
+/* On Windows, windows.h defines CreateWindow */
+#ifdef CreateWindow
+#undef CreateWindow
+#endif
+
+extern SDL_WinRTApp ^ SDL_WinRTGlobalApp;
+
+#define WINRTVID_DRIVER_NAME "winrt"
+
+/* Initialization/Query functions */
+static int WINRT_VideoInit(_THIS);
+static int WINRT_InitModes(_THIS);
+static int WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode);
+static void WINRT_VideoQuit(_THIS);
+
+/* Window functions */
+static int WINRT_CreateWindow(_THIS, SDL_Window * window);
+static void WINRT_DestroyWindow(_THIS, SDL_Window * window);
+static SDL_bool WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info);
+
+/* WinRT driver bootstrap functions */
+
+static int
+WINRT_Available(void)
+{
+ return (1);
+}
+
+static void
+WINRT_DeleteDevice(SDL_VideoDevice * device)
+{
+ SDL_WinRTGlobalApp->SetSDLVideoDevice(NULL);
+ SDL_free(device);
+}
+
+static SDL_VideoDevice *
+WINRT_CreateDevice(int devindex)
+{
+ SDL_VideoDevice *device;
+
+ /* Initialize all variables that we clean on shutdown */
+ device = (SDL_VideoDevice *) SDL_calloc(1, sizeof(SDL_VideoDevice));
+ if (!device) {
+ SDL_OutOfMemory();
+ if (device) {
+ SDL_free(device);
+ }
+ return (0);
+ }
+
+ /* Set the function pointers */
+ device->VideoInit = WINRT_VideoInit;
+ device->VideoQuit = WINRT_VideoQuit;
+ device->CreateWindow = WINRT_CreateWindow;
+ device->DestroyWindow = WINRT_DestroyWindow;
+ device->SetDisplayMode = WINRT_SetDisplayMode;
+ device->PumpEvents = WINRT_PumpEvents;
+ //device->CreateWindowFramebuffer = SDL_WINRT_CreateWindowFramebuffer;
+ //device->UpdateWindowFramebuffer = SDL_WINRT_UpdateWindowFramebuffer;
+ //device->DestroyWindowFramebuffer = SDL_WINRT_DestroyWindowFramebuffer;
+ device->GetWindowWMInfo = WINRT_GetWindowWMInfo;
+ device->free = WINRT_DeleteDevice;
+
+ SDL_WinRTGlobalApp->SetSDLVideoDevice(device);
+
+ return device;
+}
+
+VideoBootStrap WINRT_bootstrap = {
+ WINRTVID_DRIVER_NAME, "SDL Windows RT video driver",
+ WINRT_Available, WINRT_CreateDevice
+};
+
+int
+WINRT_VideoInit(_THIS)
+{
+ // TODO, WinRT: consider adding a hack to wait (here) for the app's orientation to finish getting set (before the initial display mode is set up)
+
+ if (WINRT_InitModes(_this) < 0) {
+ return -1;
+ }
+ WINRT_InitMouse(_this);
+
+ return 0;
+}
+
+static int
+WINRT_InitModes(_THIS)
+{
+ SDL_DisplayMode mode = SDL_WinRTGlobalApp->GetMainDisplayMode();
+ if (SDL_AddBasicVideoDisplay(&mode) < 0) {
+ return -1;
+ }
+
+ SDL_AddDisplayMode(&_this->displays[0], &mode);
+ return 0;
+}
+
+static int
+WINRT_SetDisplayMode(_THIS, SDL_VideoDisplay * display, SDL_DisplayMode * mode)
+{
+ return 0;
+}
+
+void
+WINRT_VideoQuit(_THIS)
+{
+ WINRT_QuitMouse(_this);
+}
+
+int
+WINRT_CreateWindow(_THIS, SDL_Window * window)
+{
+ // Make sure that only one window gets created, at least until multimonitor
+ // support is added.
+ if (SDL_WinRTGlobalApp->HasSDLWindowData())
+ {
+ SDL_SetError("WinRT only supports one window");
+ return -1;
+ }
+
+ SDL_WindowData *data = new SDL_WindowData;
+ if (!data) {
+ SDL_OutOfMemory();
+ return -1;
+ }
+ window->driverdata = data;
+ data->sdlWindow = window;
+ data->coreWindow = CoreWindow::GetForCurrentThread();
+
+ /* Make sure the window is considered to be positioned at {0,0},
+ and is considered fullscreen, shown, and the like.
+ */
+ window->x = 0;
+ window->y = 0;
+ window->flags =
+ SDL_WINDOW_FULLSCREEN |
+ SDL_WINDOW_SHOWN |
+ SDL_WINDOW_BORDERLESS |
+ SDL_WINDOW_MAXIMIZED |
+ SDL_WINDOW_INPUT_GRABBED;
+
+ /* HACK from DLudwig: The following line of code prevents
+ SDL_CreateWindow and SDL_UpdateFullscreenMode from trying to resize
+ the window after the call to WINRT_CreateWindow returns.
+
+ This hack should allow a window to be created in virtually any size,
+ and more importantly, it allows a window's framebuffer, as created and
+ retrieved via SDL_GetWindowSurface, to be in any size. This can be
+ utilized by apps centered around software rendering, such as ports
+ of older apps. The app can have SDL create a framebuffer in any size
+ it chooses. SDL will scale the framebuffer to the native
+ screen size on the GPU (via SDL_UpdateWindowSurface).
+ */
+ _this->displays[0].fullscreen_window = window;
+
+ /* Further prevent any display resizing, and make sure SDL_GetWindowDisplayMode
+ can report the correct size of windows, by creating a new display
+ mode in the requested size. To note, if the window is being created in
+ the device's native screen size, SDL_AddDisplayMode will do nothing.
+ */
+ window->fullscreen_mode = SDL_WinRTGlobalApp->GetMainDisplayMode();
+ window->fullscreen_mode.w = window->w;
+ window->fullscreen_mode.h = window->h;
+ SDL_AddDisplayMode(&_this->displays[0], &window->fullscreen_mode);
+
+ /* TODO: Consider removing custom display modes in WINRT_DestroyWindow. */
+
+ /* Make sure the WinRT app's IFramworkView can post events on
+ behalf of SDL:
+ */
+ SDL_WinRTGlobalApp->SetSDLWindowData(data);
+
+ /* All done! */
+ return 0;
+}
+
+void
+WINRT_DestroyWindow(_THIS, SDL_Window * window)
+{
+ SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
+
+ if (SDL_WinRTGlobalApp->HasSDLWindowData() &&
+ SDL_WinRTGlobalApp->GetSDLWindowData()->sdlWindow == window)
+ {
+ SDL_WinRTGlobalApp->SetSDLWindowData(NULL);
+ }
+
+ if (data) {
+ // Delete the internal window data:
+ delete data;
+ data = NULL;
+ }
+}
+
+SDL_bool
+WINRT_GetWindowWMInfo(_THIS, SDL_Window * window, SDL_SysWMinfo * info)
+{
+ SDL_WindowData * data = (SDL_WindowData *) window->driverdata;
+
+ if (info->version.major <= SDL_MAJOR_VERSION) {
+ info->subsystem = SDL_SYSWM_WINDOWSRT;
+ info->info.winrt.window = reinterpret_cast(data->coreWindow.Get());
+ return SDL_TRUE;
+ } else {
+ SDL_SetError("Application not compiled with SDL %d.%d\n",
+ SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
+ return SDL_FALSE;
+ }
+ return SDL_FALSE;
+}
+
+#endif /* SDL_VIDEO_DRIVER_WINRT */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/src/video/windowsrt/SDL_winrtvideo.h b/src/video/windowsrt/SDL_winrtvideo.h
new file mode 100644
index 000000000..4418754c2
--- /dev/null
+++ b/src/video/windowsrt/SDL_winrtvideo.h
@@ -0,0 +1,40 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2012 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"
+
+#ifndef _SDL_winrtvideo_h
+#define _SDL_winrtvideo_h
+
+extern "C" {
+#include "../SDL_sysvideo.h"
+}
+
+#include
+
+struct SDL_WindowData
+{
+ SDL_Window *sdlWindow;
+ Platform::Agile coreWindow;
+};
+
+#endif /* _SDL_winrtvideo_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
diff --git a/test/loopwave.c b/test/loopwave.c
index 22b0559de..de8329af1 100644
--- a/test/loopwave.c
+++ b/test/loopwave.c
@@ -79,6 +79,7 @@ int
main(int argc, char *argv[])
{
int i;
+ char filename[4096];
/* Load the SDL library */
if (SDL_Init(SDL_INIT_AUDIO) < 0) {
@@ -86,12 +87,14 @@ main(int argc, char *argv[])
return (1);
}
- if (argv[1] == NULL) {
- argv[1] = "sample.wav";
+ if (argc >= 1) {
+ SDL_strlcpy(filename, argv[1], sizeof(filename));
+ } else {
+ SDL_strlcpy(filename, "sample.wav", sizeof(filename));
}
/* Load the wave file into memory */
- if (SDL_LoadWAV(argv[1], &wave.spec, &wave.sound, &wave.soundlen) == NULL) {
- fprintf(stderr, "Couldn't load %s: %s\n", argv[1], SDL_GetError());
+ if (SDL_LoadWAV(filename, &wave.spec, &wave.sound, &wave.soundlen) == NULL) {
+ fprintf(stderr, "Couldn't load %s: %s\n", filename, SDL_GetError());
quit(1);
}