diff --git a/VisualC-WinPhone/SDL/SDL-WinPhone_VS2012.vcxproj b/VisualC-WinPhone/SDL/SDL-WinPhone_VS2012.vcxproj new file mode 100644 index 000000000..4eaeca36b --- /dev/null +++ b/VisualC-WinPhone/SDL/SDL-WinPhone_VS2012.vcxproj @@ -0,0 +1,404 @@ + + + + + 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 + true + true + + + + + + + \ No newline at end of file diff --git a/VisualC-WinPhone/SDL/SDL-WinPhone_VS2012.vcxproj.filters b/VisualC-WinPhone/SDL/SDL-WinPhone_VS2012.vcxproj.filters new file mode 100644 index 000000000..9535fe759 --- /dev/null +++ b/VisualC-WinPhone/SDL/SDL-WinPhone_VS2012.vcxproj.filters @@ -0,0 +1,612 @@ + + + + + {02b21b9a-45a7-41ee-a8a6-e45d14aa28da} + + + {abc3a7e6-f955-4cb5-8340-fae0f653e9c1} + + + + + 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 + + + Header 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 + + + 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 + + + \ No newline at end of file diff --git a/VisualC-WinRT/SDL-WinRT_VS2012.sln b/VisualC-WinRT/SDL-WinRT_VS2012.sln new file mode 100644 index 000000000..921cebd6d --- /dev/null +++ b/VisualC-WinRT/SDL-WinRT_VS2012.sln @@ -0,0 +1,32 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2012 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDL-WinRT", "SDL\SDL-WinRT_VS2012.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/SDL/SDL-WinRT_VS2012.vcxproj b/VisualC-WinRT/SDL/SDL-WinRT_VS2012.vcxproj new file mode 100644 index 000000000..a63bbc8cd --- /dev/null +++ b/VisualC-WinRT/SDL/SDL-WinRT_VS2012.vcxproj @@ -0,0 +1,508 @@ + + + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + + + + + + + + + + + + + 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 + + + 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {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-WinRT_VS2012.vcxproj.filters b/VisualC-WinRT/SDL/SDL-WinRT_VS2012.vcxproj.filters new file mode 100644 index 000000000..21ec9bb9d --- /dev/null +++ b/VisualC-WinRT/SDL/SDL-WinRT_VS2012.vcxproj.filters @@ -0,0 +1,645 @@ + + + + + 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 + + + + + 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 + + + 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 + + + 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 + + + Header Files + + + Header Files + + + Source Files + + + Source Files + + + Source Files + + + Header Files + + + Source Files + + + Source Files + + + Source Files + + + Header Files + + + Source Files + + + Source Files + + + Header Files + + + Header Files + + + Source Files + + + Source Files + + + + + {20773b57-7034-4c24-af5a-334844585f1b} + + + {ddf04d85-6a87-4c5a-bc52-869b38f45a61} + + + \ No newline at end of file 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..bd1750942 --- /dev/null +++ b/VisualC-WinRT/tests/loopwave/loopwave_VS2012.vcxproj @@ -0,0 +1,170 @@ + + + + + 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 + false + false + false + + + + + _DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + NotUsing + NotUsing + NotUsing + false + false + false + + + + + + + + + + + Designer + + + + + + true + true + true + true + true + true + + + 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..eb2558fa4 --- /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 8541fa343..c4b95a36c 100755 --- a/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj +++ b/Xcode-iOS/SDL/SDL.xcodeproj/project.pbxproj @@ -561,6 +561,7 @@ ); name = CustomTemplate; sourceTree = ""; + usesTabs = 0; }; 56A6702F18565E4F0007D20F /* dynapi */ = { isa = PBXGroup; diff --git a/include/SDL_config.h b/include/SDL_config.h index d46573ba4..9a2e51c55 100644 --- a/include/SDL_config.h +++ b/include/SDL_config.h @@ -33,6 +33,8 @@ #include "SDL_config_premake.h" #elif defined(__WIN32__) #include "SDL_config_windows.h" +#elif defined(__WINRT__) +#include "SDL_config_winrt.h" #elif defined(__MACOSX__) #include "SDL_config_macosx.h" #elif defined(__IPHONEOS__) diff --git a/include/SDL_config_winrt.h b/include/SDL_config_winrt.h new file mode 100644 index 000000000..2d9258132 --- /dev/null +++ b/include/SDL_config_winrt.h @@ -0,0 +1,191 @@ +/* + 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_FLOAT_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 +#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__SCALB 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 + +/* Enable OpenGL ES 2.0 (via a modified ANGLE library) */ +#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP /* TODO, WinRT: try adding OpenGL ES 2 support for Windows Phone 8 */ +#define SDL_VIDEO_OPENGL_ES2 1 +#define SDL_VIDEO_OPENGL_EGL 1 +#endif + +/* Enable appropriate renderer(s) */ +#define SDL_VIDEO_RENDER_D3D11 1 + +#if SDL_VIDEO_OPENGL_ES2 +#define SDL_VIDEO_RENDER_OGL_ES2 1 +#endif + +/* 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 b8eb27855..1f6efd384 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_egl.h b/include/SDL_egl.h index bda7c5046..d312f0425 100644 --- a/include/SDL_egl.h +++ b/include/SDL_egl.h @@ -391,9 +391,16 @@ typedef enum { #endif #include +#if __WINRT__ +#include +typedef IUnknown * EGLNativeWindowType; +typedef int EGLNativeDisplayType; +typedef HBITMAP EGLNativePixmapType; +#else typedef HDC EGLNativeDisplayType; typedef HBITMAP EGLNativePixmapType; typedef HWND EGLNativeWindowType; +#endif #elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */ diff --git a/include/SDL_hints.h b/include/SDL_hints.h index a7c016208..b98ce6834 100644 --- a/include/SDL_hints.h +++ b/include/SDL_hints.h @@ -105,6 +105,19 @@ extern "C" { */ #define SDL_HINT_RENDER_DIRECT3D_THREADSAFE "SDL_RENDER_DIRECT3D_THREADSAFE" +/** + * \brief A variable controlling whether to enable Direct3D 11+'s Debug Layer. + * + * This variable does not have any effect on the Direct3D 9 based renderer. + * + * This variable can be set to the following values: + * "0" - Disable Debug Layer use + * "1" - Enable Debug Layer use + * + * By default, SDL does not use Direct3D Debug Layer. + */ +#define SDL_HINT_RENDER_DIRECT3D11_DEBUG "SDL_HINT_RENDER_DIRECT3D11_DEBUG" + /** * \brief A variable controlling the scaling quality * @@ -334,7 +347,7 @@ extern "C" { * If this hint is set before SDL_CreateWindowFrom() and the SDL_Window* it is set to has * SDL_WINDOW_OPENGL set (and running on WGL only, currently), then two things will occur on the newly * created SDL_Window: - +* * 1. Its pixel format will be set to the same pixel format as this SDL_Window. This is * needed for example when sharing an OpenGL context across multiple windows. * @@ -347,6 +360,62 @@ extern "C" { */ #define SDL_HINT_VIDEO_WINDOW_SHARE_PIXEL_FORMAT "SDL_VIDEO_WINDOW_SHARE_PIXEL_FORMAT" +/* + * \brief A URL to a WinRT app's privacy policy + * + * All network-enabled WinRT apps must make a privacy policy available to its + * users. On Windows 8, 8.1, and RT, Microsoft mandates that this policy be + * be available in the Windows Settings charm, as accessed from within the app. + * SDL provides code to add a URL-based link there, which can point to the app's + * privacy policy. + * + * To setup a URL to an app's privacy policy, set SDL_HINT_WINRT_PRIVACY_POLICY_URL + * before calling any SDL_Init functions. The contents of the hint should + * be a valid URL. For example, "http://www.example.com". + * + * The default value is "", which will prevent SDL from adding a privacy policy + * link to the Settings charm. This hint should only be set during app init. + * + * The label text of an app's "Privacy Policy" link may be customized via another + * hint, SDL_HINT_WINRT_PRIVACY_POLICY_LABEL. + * + * Please note that on Windows Phone, Microsoft does not provide standard UI + * for displaying a privacy policy link, and as such, SDL_HINT_WINRT_PRIVACY_POLICY_URL + * will not get used on that platform. Network-enabled phone apps should display + * their privacy policy through some other, in-app means. + */ +#define SDL_HINT_WINRT_PRIVACY_POLICY_URL "SDL_HINT_WINRT_PRIVACY_POLICY_URL" + +/** \brief Label text for a WinRT app's privacy policy link + * + * Network-enabled WinRT apps must include a privacy policy. On Windows 8, 8.1, and RT, + * Microsoft mandates that this policy be available via the Windows Settings charm. + * SDL provides code to add a link there, with it's label text being set via the + * optional hint, SDL_HINT_WINRT_PRIVACY_POLICY_LABEL. + * + * Please note that a privacy policy's contents are not set via this hint. A separate + * hint, SDL_HINT_WINRT_PRIVACY_POLICY_URL, is used to link to the actual text of the + * policy. + * + * The contents of this hint should be encoded as a UTF8 string. + * + * The default value is "Privacy Policy". This hint should only be set during app + * initialization, preferably before any calls to SDL_Init. + * + * For additional information on linking to a privacy policy, see the documentation for + * SDL_HINT_WINRT_PRIVACY_POLICY_URL. + */ +#define SDL_HINT_WINRT_PRIVACY_POLICY_LABEL "SDL_HINT_WINRT_PRIVACY_POLICY_LABEL" + +/** \brief If set to 1, back button press events on Windows Phone 8+ will be marked as handled. + * + * TODO, WinRT: document SDL_HINT_WINRT_HANDLE_BACK_BUTTON need and use + * For now, more details on why this is needed can be found at the + * beginning of the following web page: + * http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj247550(v=vs.105).aspx + */ +#define SDL_HINT_WINRT_HANDLE_BACK_BUTTON "SDL_HINT_WINRT_HANDLE_BACK_BUTTON" + /** * \brief A variable that dictates policy for fullscreen Spaces on Mac OS X. * diff --git a/include/SDL_main.h b/include/SDL_main.h index 1f2bad3fb..2e8fae95e 100644 --- a/include/SDL_main.h +++ b/include/SDL_main.h @@ -39,6 +39,18 @@ */ #define SDL_MAIN_AVAILABLE +#elif defined(__WINRT__) +/* On WinRT, SDL provides a main function that initializes CoreApplication, + creating an instance of IFrameworkView in the process. + + Please note that #include'ing SDL_main.h is not enough to get a main() + function working. In non-XAML apps, the file, + src/main/winrt/SDL_WinRT_main_NonXAML.cpp, or a copy of it, must be compiled + into the app itself. In XAML apps, the function, SDL_WinRTRunApp must be + called, with a pointer to the Direct3D-hosted XAML control passed in. +*/ +#define SDL_MAIN_NEEDED + #elif defined(__IPHONEOS__) /* On iOS SDL provides a main function that creates an application delegate and starts the iOS application run loop. @@ -115,6 +127,24 @@ extern DECLSPEC void SDLCALL SDL_UnregisterApp(void); #endif /* __WIN32__ */ +#ifdef __WINRT__ + +/** + * \brief Initializes and launches an SDL/WinRT application. + * + * \param mainFunction The SDL app's C-style main(). + * \param xamlBackgroundPanel An optional, XAML-based, background panel. + * For Non-XAML apps, this value must be set to NULL. For XAML apps, + * pass in a pointer to a SwapChainBackgroundPanel, casted to an + * IInspectable (via reinterpret_cast). + * \ret 0 on success, -1 on failure. On failure, use SDL_GetError to retrieve more + * information on the failure. + */ +extern DECLSPEC int SDLCALL SDL_WinRTRunApp(int (*mainFunction)(int, char **), void * xamlBackgroundPanel); + +#endif /* __WINRT__ */ + + #ifdef __cplusplus } #endif diff --git a/include/SDL_platform.h b/include/SDL_platform.h index afe338913..ace93a427 100644 --- a/include/SDL_platform.h +++ b/include/SDL_platform.h @@ -113,10 +113,27 @@ #undef __SOLARIS__ #define __SOLARIS__ 1 #endif + #if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) +/* Try to find out if we're compiling for WinRT or non-WinRT */ +#if defined(_MSC_VER) && (_MSC_VER >= 1700) /* _MSC_VER==1700 for MSVC 2012 */ +#include +#endif /* _MSC_VER >= 1700 */ +/* Default to classic, Win32/Win64/Desktop compilation either if: + 1. the version of Windows is explicity set to a 'Desktop' (non-Metro) app + 2. the version of Windows cannot be determined via winapifamily.h + If neither is true, then see if we're compiling for WinRT. + */ +#if ! defined(WINAPI_FAMILY_PARTITION) || WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) #undef __WINDOWS__ #define __WINDOWS__ 1 -#endif +/* See if we're compiling for WinRT: */ +#elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) +#undef __WINRT__ +#define __WINRT__ 1 +#endif /* ! defined(WINAPI_FAMILY_PARTITION) */ +#endif /* defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) */ + #if defined(__WINDOWS__) #undef __WIN32__ #define __WIN32__ 1 diff --git a/include/SDL_stdinc.h b/include/SDL_stdinc.h index 6de724e9a..31b343d30 100644 --- a/include/SDL_stdinc.h +++ b/include/SDL_stdinc.h @@ -71,8 +71,18 @@ # include #endif #ifdef HAVE_MATH_H +# if defined(__WINRT__) +/* Defining _USE_MATH_DEFINES is required to get M_PI to be defined on + WinRT. See http://msdn.microsoft.com/en-us/library/4hwaceh6.aspx + for more information. +*/ +# define _USE_MATH_DEFINES +# endif # include #endif +#ifdef HAVE_FLOAT_H +# include +#endif #if defined(HAVE_ICONV) && defined(HAVE_ICONV_H) # include #endif diff --git a/include/SDL_system.h b/include/SDL_system.h index 99ef8223e..fd929f7f9 100644 --- a/include/SDL_system.h +++ b/include/SDL_system.h @@ -116,6 +116,70 @@ extern DECLSPEC const char * SDLCALL SDL_AndroidGetExternalStoragePath(); #endif /* __ANDROID__ */ +/* Platform specific functions for WinRT */ +#if defined(__WINRT__) && __WINRT__ + +/** + * \brief WinRT / 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 WinRT defined path on the local file system + * + * \note Documentation on most app-specific path types on WinRT + * 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 WinRT defined path on the local file system + * + * \note Documentation on most app-specific path types on WinRT + * 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 40e8ca7c6..857fc75a4 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 @@ -105,6 +110,7 @@ typedef enum { SDL_SYSWM_UNKNOWN, SDL_SYSWM_WINDOWS, + SDL_SYSWM_WINRT, SDL_SYSWM_X11, SDL_SYSWM_DIRECTFB, SDL_SYSWM_COCOA, @@ -175,6 +181,12 @@ struct SDL_SysWMinfo HWND window; /**< The window handle */ } win; #endif +#if defined(SDL_VIDEO_DRIVER_WINRT) + struct + { + IInspectable * window; /**< The WinRT CoreWindow */ + } winrt; +#endif #if defined(SDL_VIDEO_DRIVER_X11) struct { diff --git a/include/begin_code.h b/include/begin_code.h index fbed7d4a5..f37ee3696 100644 --- a/include/begin_code.h +++ b/include/begin_code.h @@ -43,7 +43,7 @@ /* Some compilers use a special export keyword */ #ifndef DECLSPEC -# if defined(__WIN32__) +# if defined(__WIN32__) || defined(__WINRT__) # ifdef __BORLANDC__ # ifdef BUILD_SDL # define DECLSPEC @@ -66,7 +66,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 6a6bf8361..98e758447 100644 --- a/src/SDL_assert.c +++ b/src/SDL_assert.c @@ -39,8 +39,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 8cd2483cf..39aa3e4bf 100644 --- a/src/SDL_log.c +++ b/src/SDL_log.c @@ -20,7 +20,7 @@ */ #include "./SDL_internal.h" -#if defined(__WIN32__) +#if defined(__WIN32__) || defined(__WINRT__) #include "core/windows/SDL_windows.h" #endif @@ -318,13 +318,15 @@ 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. */ { char *output; size_t length; LPTSTR tstr; + +#ifndef __WINRT__ BOOL attachResult; DWORD attachError; unsigned long charsWritten; @@ -356,6 +358,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority, stderrHandle = GetStdHandle(STD_ERROR_HANDLE); } } +#endif /* ifndef __WINRT__ */ length = SDL_strlen(SDL_priority_prefixes[priority]) + 2 + SDL_strlen(message) + 1 + 1 + 1; output = SDL_stack_alloc(char, length); @@ -365,6 +368,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority, /* Output to debugger */ OutputDebugString(tstr); +#ifndef __WINRT__ /* Screen output to stderr, if console was attached. */ if (consoleAttached == 1) { if (!WriteConsole(stderrHandle, tstr, lstrlen(tstr), &charsWritten, NULL)) { @@ -374,6 +378,7 @@ SDL_LogOutput(void *userdata, int category, SDL_LogPriority priority, OutputDebugString(TEXT("Insufficient heap memory to write message\r\n")); } } +#endif /* ifndef __WINRT__ */ SDL_free(tstr); SDL_stack_free(output); diff --git a/src/atomic/SDL_spinlock.c b/src/atomic/SDL_spinlock.c index 5edeb1d73..2d8446dc5 100644 --- a/src/atomic/SDL_spinlock.c +++ b/src/atomic/SDL_spinlock.c @@ -20,7 +20,7 @@ */ #include "../SDL_internal.h" -#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 a2ac16db2..a1a18df6d 100644 --- a/src/audio/xaudio2/SDL_xaudio2.c +++ b/src/audio/xaudio2/SDL_xaudio2.c @@ -18,6 +18,32 @@ misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. */ + +/* WinRT NOTICE: + + A few 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 WinRT. 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 WinRT. + 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 WinRT, the + string-based argument will be used. +*/ #include "../../SDL_internal.h" #if SDL_AUDIO_DRIVER_XAUDIO2 @@ -31,6 +57,9 @@ #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 SDK */ +# define SDL_XAUDIO2_HAS_SDK #else /* XAudio2 exists as of the March 2008 DirectX SDK The XAudio2 implementation available in the Windows 8 SDK targets Windows 8 and newer. @@ -42,16 +71,36 @@ #else # define SDL_XAUDIO2_HAS_SDK 1 #endif -#endif /* __GNUC__ */ +#endif #ifdef SDL_XAUDIO2_HAS_SDK +/* Check to see if we're compiling for XAudio 2.8, or higher. */ +#ifdef WINVER +#if WINVER >= 0x0602 /* Windows 8 SDK or higher? */ +#define SDL_XAUDIO2_WIN8 1 +#endif +#endif + +/* The XAudio header file, when #include'd on WinRT, will only compile in C++ + files, but not C. A few preprocessor-based hacks are defined below in order + to get xaudio2.h to compile in the C/non-C++ file, SDL_xaudio2.c. + */ +#ifdef __WINRT__ +#define uuid(x) +#define DX_BUILD +#endif + #define INITGUID 1 #include /* Hidden "this" pointer for the audio functions */ #define _THIS SDL_AudioDevice *this +#ifdef __WINRT__ +#include "SDL_xaudio2_winrthelpers.h" +#endif + /* Fixes bug 1210 where some versions of gcc need named parameters */ #ifdef __GNUC__ #ifdef THIS @@ -69,7 +118,7 @@ struct SDL_PrivateAudioData IXAudio2 *ixa2; IXAudio2SourceVoice *source; IXAudio2MasteringVoice *mastering; - HANDLE semaphore; + SDL_sem * semaphore; Uint8 *mixbuf; int mixlen; Uint8 *nextbuf; @@ -114,7 +163,7 @@ 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); + SDL_SemPost(this->hidden->semaphore); } static void STDMETHODCALLTYPE @@ -180,7 +229,7 @@ static void XAUDIO2_WaitDevice(_THIS) { if (this->enabled) { - WaitForSingleObject(this->hidden->semaphore, INFINITE); + SDL_SemWait(this->hidden->semaphore); } } @@ -191,10 +240,18 @@ XAUDIO2_WaitDone(_THIS) XAUDIO2_VOICE_STATE state; SDL_assert(!this->enabled); /* flag that stops playing. */ IXAudio2SourceVoice_Discontinuity(source); +#if SDL_XAUDIO2_WIN8 + IXAudio2SourceVoice_GetState(source, &state, 0); +#else IXAudio2SourceVoice_GetState(source, &state); +#endif while (state.BuffersQueued > 0) { - WaitForSingleObject(this->hidden->semaphore, INFINITE); + SDL_SemWait(this->hidden->semaphore); +#if SDL_XAUDIO2_WIN8 + IXAudio2SourceVoice_GetState(source, &state, 0); +#else IXAudio2SourceVoice_GetState(source, &state); +#endif } } @@ -223,7 +280,7 @@ XAUDIO2_CloseDevice(_THIS) } SDL_free(this->hidden->mixbuf); if (this->hidden->semaphore != NULL) { - CloseHandle(this->hidden->semaphore); + SDL_DestroySemaphore(this->hidden->semaphore); } SDL_free(this->hidden); @@ -240,7 +297,11 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture) SDL_AudioFormat test_format = SDL_FirstAudioFormat(this->spec.format); IXAudio2 *ixa2 = NULL; IXAudio2SourceVoice *source = NULL; +#if defined(SDL_XAUDIO2_WIN8) + LPCWSTR devId = NULL; +#else UINT32 devId = 0; /* 0 == system default device. */ +#endif static IXAudio2VoiceCallbackVtbl callbacks_vtable = { VoiceCBOnVoiceProcessPassStart, @@ -260,6 +321,18 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture) 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__) if (devname != NULL) { UINT32 devcount = 0; UINT32 i = 0; @@ -288,6 +361,7 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture) return SDL_SetError("XAudio2: Requested device not found."); } } +#endif /* Initialize all variables that we clean on shutdown */ this->hidden = (struct SDL_PrivateAudioData *) @@ -299,7 +373,7 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture) SDL_memset(this->hidden, 0, (sizeof *this->hidden)); this->hidden->ixa2 = ixa2; - this->hidden->semaphore = CreateSemaphore(NULL, 1, 2, NULL); + this->hidden->semaphore = SDL_CreateSemaphore(1); if (this->hidden->semaphore == NULL) { XAUDIO2_CloseDevice(this); return SDL_SetError("XAudio2: CreateSemaphore() failed!"); @@ -342,9 +416,15 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture) 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. */ +#if SDL_XAUDIO2_WIN8 + result = IXAudio2_CreateMasteringVoice(ixa2, &this->hidden->mastering, + XAUDIO2_DEFAULT_CHANNELS, + this->spec.freq, 0, devId, NULL, AudioCategory_GameEffects); +#else result = IXAudio2_CreateMasteringVoice(ixa2, &this->hidden->mastering, XAUDIO2_DEFAULT_CHANNELS, this->spec.freq, 0, devId, NULL); +#endif if (result != S_OK) { XAUDIO2_CloseDevice(this); return SDL_SetError("XAudio2: Couldn't create mastering voice"); @@ -363,11 +443,23 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture) 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"); @@ -393,7 +485,9 @@ XAUDIO2_OpenDevice(_THIS, const char *devname, int iscapture) static void XAUDIO2_Deinitialize(void) { +#if defined(__WIN32__) WIN_CoUninitialize(); +#endif } #endif /* SDL_XAUDIO2_HAS_SDK */ @@ -408,13 +502,18 @@ XAUDIO2_Init(SDL_AudioDriverImpl * impl) #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. */ } diff --git a/src/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.cpp new file mode 100644 index 000000000..b27ee59b6 --- /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 + +extern "C" HRESULT __cdecl 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 +} + +extern "C" 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..0beaf8d1f --- /dev/null +++ b/src/audio/xaudio2/SDL_xaudio2_winrthelpers.h @@ -0,0 +1,52 @@ + +#pragma once + +// +// Re-implementation of methods removed from XAudio2 (in WinRT): +// + +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; + + +#ifdef __cplusplus +extern "C" { +#endif + +HRESULT IXAudio2_GetDeviceCount(IXAudio2 * unused, UINT32 * devcount); +HRESULT IXAudio2_GetDeviceDetails(IXAudio2 * unused, UINT32 index, XAUDIO2_DEVICE_DETAILS * details); + +#ifdef __cplusplus +} +#endif + + +// +// C-style macros to call XAudio2's methods in C++: +// +#ifdef __cplusplus +/* +#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)) +*/ +#endif // ifdef __cplusplus diff --git a/src/core/windows/SDL_windows.c b/src/core/windows/SDL_windows.c index 25a1c4f25..16934d5e1 100644 --- a/src/core/windows/SDL_windows.c +++ b/src/core/windows/SDL_windows.c @@ -20,21 +20,21 @@ */ #include "../../SDL_internal.h" -#ifdef __WIN32__ +#if defined(__WIN32__) || defined(__WINRT__) #include "SDL_windows.h" #include "SDL_error.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,6 +42,13 @@ 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) { @@ -50,6 +57,14 @@ WIN_CoInitialize(void) If you need multi-threaded mode, call CoInitializeEx() before SDL_Init() */ +#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 HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); if (hr == RPC_E_CHANGED_MODE) { hr = CoInitializeEx(NULL, COINIT_MULTITHREADED); @@ -62,12 +77,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 4a24111a4..45c9d7347 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 @@ -44,6 +46,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/winrt/SDL_winrtapp_common.cpp b/src/core/winrt/SDL_winrtapp_common.cpp new file mode 100644 index 000000000..fb151f229 --- /dev/null +++ b/src/core/winrt/SDL_winrtapp_common.cpp @@ -0,0 +1,16 @@ + +#include +#include "SDL_winrtapp_direct3d.h" +#include "SDL_winrtapp_xaml.h" + +int (*WINRT_SDLAppEntryPoint)(int, char **) = NULL; + +extern "C" DECLSPEC int +SDL_WinRTRunApp(int (*mainFunction)(int, char **), void * xamlBackgroundPanel) +{ + if (xamlBackgroundPanel) { + return SDL_WinRTInitXAMLApp(mainFunction, xamlBackgroundPanel); + } else { + return SDL_WinRTInitNonXAMLApp(mainFunction); + } +} diff --git a/src/core/winrt/SDL_winrtapp_common.h b/src/core/winrt/SDL_winrtapp_common.h new file mode 100644 index 000000000..d54a8ccdc --- /dev/null +++ b/src/core/winrt/SDL_winrtapp_common.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_winrtapp_common_h +#define _SDL_winrtapp_common_h + +/* A pointer to the app's C-style main() function (which is a different + function than the WinRT app's actual entry point). + */ +extern int (*WINRT_SDLAppEntryPoint)(int, char **); + +#endif // ifndef _SDL_winrtapp_common_h diff --git a/src/core/winrt/SDL_winrtapp_direct3d.cpp b/src/core/winrt/SDL_winrtapp_direct3d.cpp new file mode 100644 index 000000000..53c72bc4e --- /dev/null +++ b/src/core/winrt/SDL_winrtapp_direct3d.cpp @@ -0,0 +1,668 @@ + +/* Standard C++11 includes */ +#include +#include +#include +using namespace std; + + +/* Windows includes */ +#include "ppltasks.h" +using namespace concurrency; +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; + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP +using namespace Windows::Phone::UI::Input; +#endif + + +/* SDL includes */ +extern "C" { +#include "SDL_assert.h" +#include "SDL_events.h" +#include "SDL_hints.h" +#include "SDL_log.h" +#include "SDL_main.h" +#include "SDL_stdinc.h" +#include "SDL_render.h" +#include "../../video/SDL_sysvideo.h" +//#include "../../SDL_hints_c.h" +#include "../../events/SDL_events_c.h" +#include "../../events/SDL_keyboard_c.h" +#include "../../events/SDL_mouse_c.h" +#include "../../events/SDL_windowevents_c.h" +#include "../../render/SDL_sysrender.h" +#include "../windows/SDL_windows.h" +} + +#include "../../video/winrt/SDL_winrtevents_c.h" +#include "../../video/winrt/SDL_winrtvideo_cpp.h" +#include "SDL_winrtapp_common.h" +#include "SDL_winrtapp_direct3d.h" + + +// 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: record a reference to the global, WinRT '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; +} + +int SDL_WinRTInitNonXAMLApp(int (*mainFunction)(int, char **)) +{ + WINRT_SDLAppEntryPoint = mainFunction; + auto direct3DApplicationSource = ref new SDLApplicationSource(); + CoreApplication::Run(direct3DApplicationSource); + return 0; +} + +static void WINRT_SetDisplayOrientationsPreference(void *userdata, 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; + if (newValue) { + 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 WinRT [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; +} + +static void +WINRT_ProcessWindowSizeChange() +{ + // Make the new window size be the one true fullscreen mode. + // This change was initially 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. + SDL_DisplayMode newDisplayMode; + if (WINRT_CalcDisplayModeUsingNativeWindow(&newDisplayMode) != 0) { + return; + } + + // Make note of the old display mode, and it's old driverdata. + SDL_DisplayMode oldDisplayMode; + SDL_zero(oldDisplayMode); + if (WINRT_GlobalSDLVideoDevice) { + oldDisplayMode = WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode; + } + + // Setup the new display mode in the appropriate spots. + if (WINRT_GlobalSDLVideoDevice) { + // Make a full copy of the display mode for display_modes[0], + // one with with a separately malloced 'driverdata' field. + // SDL_VideoQuit(), if called, will attempt to free the driverdata + // fields in 'desktop_mode' and each entry in the 'display_modes' + // array. + if (WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0].driverdata) { + // Free the previous mode's memory + SDL_free(WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0].driverdata); + WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0].driverdata = NULL; + } + if (WINRT_DuplicateDisplayMode(&(WINRT_GlobalSDLVideoDevice->displays[0].display_modes[0]), &newDisplayMode) != 0) { + // Uh oh, something went wrong. A malloc call probably failed. + SDL_free(newDisplayMode.driverdata); + return; + } + + // Install 'newDisplayMode' into 'current_mode' and 'desktop_mode'. + WINRT_GlobalSDLVideoDevice->displays[0].current_mode = newDisplayMode; + WINRT_GlobalSDLVideoDevice->displays[0].desktop_mode = newDisplayMode; + } + + if (WINRT_GlobalSDLWindow) { + // Send a window-resize event to the rest of SDL, and to apps: + SDL_SendWindowEvent( + WINRT_GlobalSDLWindow, + SDL_WINDOWEVENT_RESIZED, + newDisplayMode.w, + newDisplayMode.h); + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + // HACK: On Windows Phone, make sure that orientation changes from + // Landscape to LandscapeFlipped, Portrait to PortraitFlipped, + // or vice-versa on either of those two, lead to the Direct3D renderer + // getting updated. + const DisplayOrientations oldOrientation = ((SDL_DisplayModeData *)oldDisplayMode.driverdata)->currentOrientation; + const DisplayOrientations newOrientation = ((SDL_DisplayModeData *)newDisplayMode.driverdata)->currentOrientation; + + if ((oldOrientation == DisplayOrientations::Landscape && newOrientation == DisplayOrientations::LandscapeFlipped) || + (oldOrientation == DisplayOrientations::LandscapeFlipped && newOrientation == DisplayOrientations::Landscape) || + (oldOrientation == DisplayOrientations::Portrait && newOrientation == DisplayOrientations::PortraitFlipped) || + (oldOrientation == DisplayOrientations::PortraitFlipped && newOrientation == DisplayOrientations::Portrait)) + { + // One of the reasons this event is getting sent out is because SDL + // will ignore requests to send out SDL_WINDOWEVENT_RESIZED events + // if and when the event size doesn't change (and the Direct3D 11.1 + // renderer doesn't get the memo). + // + // Make sure that the display/window size really didn't change. If + // it did, then a SDL_WINDOWEVENT_SIZE_CHANGED event got sent, and + // the Direct3D 11.1 renderer picked it up, presumably. + if (oldDisplayMode.w == newDisplayMode.w && + oldDisplayMode.h == newDisplayMode.h) + { + SDL_SendWindowEvent( + WINRT_GlobalSDLWindow, + SDL_WINDOWEVENT_SIZE_CHANGED, + newDisplayMode.w, + newDisplayMode.h); + } + } +#endif + } + + // Finally, free the 'driverdata' field of the old 'desktop_mode'. + if (oldDisplayMode.driverdata) { + SDL_free(oldDisplayMode.driverdata); + oldDisplayMode.driverdata = NULL; + } +} + +SDL_WinRTApp::SDL_WinRTApp() : + m_windowClosed(false), + m_windowVisible(true) +{ +} + +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); + + CoreApplication::Exiting += + ref new EventHandler(this, &SDL_WinRTApp::OnExiting); + + 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. + // + // TODO, WinRT: 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"); // DavidL: this is no longer needed (for SDL_AddHintCallback) + SDL_AddHintCallback(SDL_HINT_ORIENTATIONS, WINRT_SetDisplayOrientationsPreference, NULL); +} + +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 + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + // On Windows Phone, treat an orientation change as a change in window size. + // The native window's size doesn't seem to change, however SDL will simulate + // a window size change. + WINRT_ProcessWindowSizeChange(); +#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->PointerMoved += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerMoved); + + window->PointerReleased += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerReleased); + + window->PointerWheelChanged += + ref new TypedEventHandler(this, &SDL_WinRTApp::OnPointerWheelChanged); + +#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); + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + HardwareButtons::BackPressed += + ref new EventHandler(this, &SDL_WinRTApp::OnBackButtonPressed); +#endif + +#if WINAPI_FAMILY == WINAPI_FAMILY_APP // for Windows 8/8.1/RT apps... (and not Phone apps) + // Make sure we know when a user has opened the app's settings pane. + // This is needed in order to display a privacy policy, which needs + // to be done for network-enabled apps, as per Windows Store requirements. + using namespace Windows::UI::ApplicationSettings; + SettingsPane::GetForCurrentView()->CommandsRequested += + ref new TypedEventHandler + (this, &SDL_WinRTApp::OnSettingsPaneCommandsRequested); +#endif +} + +void SDL_WinRTApp::Load(Platform::String^ entryPoint) +{ +} + +void SDL_WinRTApp::Run() +{ + SDL_SetMainReady(); + if (WINRT_SDLAppEntryPoint) + { + // TODO, WinRT: pass the C-style main() a reasonably realistic + // representation of command line arguments. + int argc = 0; + char **argv = NULL; + WINRT_SDLAppEntryPoint(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() +{ +} + +#if WINAPI_FAMILY == WINAPI_FAMILY_APP +void SDL_WinRTApp::OnSettingsPaneCommandsRequested( + Windows::UI::ApplicationSettings::SettingsPane ^p, + Windows::UI::ApplicationSettings::SettingsPaneCommandsRequestedEventArgs ^args) +{ + using namespace Platform; + using namespace Windows::UI::ApplicationSettings; + using namespace Windows::UI::Popups; + + String ^privacyPolicyURL = nullptr; // a URL to an app's Privacy Policy + String ^privacyPolicyLabel = nullptr; // label/link text + const char *tmpHintValue = NULL; // SDL_GetHint-retrieved value, used immediately + wchar_t *tmpStr = NULL; // used for UTF8 to UCS2 conversion + + // Setup a 'Privacy Policy' link, if one is available (via SDL_GetHint): + tmpHintValue = SDL_GetHint(SDL_HINT_WINRT_PRIVACY_POLICY_URL); + if (tmpHintValue && tmpHintValue[0] != '\0') { + // Convert the privacy policy's URL to UCS2: + tmpStr = WIN_UTF8ToString(tmpHintValue); + privacyPolicyURL = ref new String(tmpStr); + SDL_free(tmpStr); + + // Optionally retrieve custom label-text for the link. If this isn't + // available, a default value will be used instead. + tmpHintValue = SDL_GetHint(SDL_HINT_WINRT_PRIVACY_POLICY_LABEL); + if (tmpHintValue && tmpHintValue[0] != '\0') { + tmpStr = WIN_UTF8ToString(tmpHintValue); + privacyPolicyLabel = ref new String(tmpStr); + SDL_free(tmpStr); + } else { + privacyPolicyLabel = ref new String(L"Privacy Policy"); + } + + // Register the link, along with a handler to be called if and when it is + // clicked: + auto cmd = ref new SettingsCommand(L"privacyPolicy", privacyPolicyLabel, + ref new UICommandInvokedHandler([=](IUICommand ^) { + Windows::System::Launcher::LaunchUriAsync(ref new Uri(privacyPolicyURL)); + })); + args->Request->ApplicationCommands->Append(cmd); + } +} +#endif // if WINAPI_FAMILY == WINAPI_FAMILY_APP + +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, WINRT_GlobalSDLWindow?=%s\n", + __FUNCTION__, + args->Size.Width, args->Size.Height, + (int)DisplayProperties::CurrentOrientation, + (int)DisplayProperties::NativeOrientation, + (int)DisplayProperties::AutoRotationPreferences, + (WINRT_GlobalSDLWindow ? "yes" : "no")); +#endif + + WINRT_ProcessWindowSizeChange(); +} + +void SDL_WinRTApp::OnVisibilityChanged(CoreWindow^ sender, VisibilityChangedEventArgs^ args) +{ +#if LOG_WINDOW_EVENTS==1 + SDL_Log("%s, visible?=%s, WINRT_GlobalSDLWindow?=%s\n", + __FUNCTION__, + (args->Visible ? "yes" : "no"), + (WINRT_GlobalSDLWindow ? "yes" : "no")); +#endif + + m_windowVisible = args->Visible; + if (WINRT_GlobalSDLWindow) { + SDL_bool wasSDLWindowSurfaceValid = WINRT_GlobalSDLWindow->surface_valid; + + if (args->Visible) { + SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_SHOWN, 0, 0); + } else { + SDL_SendWindowEvent(WINRT_GlobalSDLWindow, 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. + WINRT_GlobalSDLWindow->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; +} + +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 (WINRT_GlobalSDLWindow) + { + SDL_SendWindowEvent(WINRT_GlobalSDLWindow, SDL_WINDOWEVENT_MINIMIZED, 0, 0); // TODO: see if SDL_WINDOWEVENT_SIZE_CHANGED should be getting triggered here (it is, currently) + SDL_FilterEvents(RemoveAppSuspendAndResumeEvents, 0); + } + + SDL_SendAppEvent(SDL_APP_WILLENTERBACKGROUND); + SDL_SendAppEvent(SDL_APP_DIDENTERBACKGROUND); + + deferral->Complete(); + }); +} + +void SDL_WinRTApp::OnResuming(Platform::Object^ sender, Platform::Object^ args) +{ + SDL_SendAppEvent(SDL_APP_WILLENTERFOREGROUND); + SDL_SendAppEvent(SDL_APP_DIDENTERFOREGROUND); + + // 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 (WINRT_GlobalSDLWindow) + { + SDL_SendWindowEvent(WINRT_GlobalSDLWindow, 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); + } +} + +void SDL_WinRTApp::OnExiting(Platform::Object^ sender, Platform::Object^ args) +{ + SDL_SendAppEvent(SDL_APP_TERMINATING); +} + +static void +WINRT_LogPointerEvent(const char * header, Windows::UI::Core::PointerEventArgs ^ args, Windows::Foundation::Point transformedPoint) +{ + Windows::UI::Input::PointerPoint ^ pt = args->CurrentPoint; + SDL_Log("%s: Position={%f,%f}, Transformed Pos={%f, %f}, MouseWheelDelta=%d, FrameId=%d, PointerId=%d, SDL button=%d\n", + header, + pt->Position.X, pt->Position.Y, + transformedPoint.X, transformedPoint.Y, + pt->Properties->MouseWheelDelta, + pt->FrameId, + pt->PointerId, + WINRT_GetSDLButtonForPointerPoint(pt)); +} + +void SDL_WinRTApp::OnPointerPressed(CoreWindow^ sender, PointerEventArgs^ args) +{ +#if LOG_POINTER_EVENTS + WINRT_LogPointerEvent("pointer pressed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); +#endif + + WINRT_ProcessPointerPressedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); +} + +void SDL_WinRTApp::OnPointerMoved(CoreWindow^ sender, PointerEventArgs^ args) +{ +#if LOG_POINTER_EVENTS + WINRT_LogPointerEvent("pointer moved", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); +#endif + + WINRT_ProcessPointerMovedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); +} + +void SDL_WinRTApp::OnPointerReleased(CoreWindow^ sender, PointerEventArgs^ args) +{ +#if LOG_POINTER_EVENTS + WINRT_LogPointerEvent("pointer released", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); +#endif + + WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); +} + +void SDL_WinRTApp::OnPointerWheelChanged(CoreWindow^ sender, PointerEventArgs^ args) +{ +#if LOG_POINTER_EVENTS + WINRT_LogPointerEvent("pointer wheel changed", args, WINRT_TransformCursorPosition(WINRT_GlobalSDLWindow, args->CurrentPoint->Position, TransformToSDLWindowSize)); +#endif + + WINRT_ProcessPointerWheelChangedEvent(WINRT_GlobalSDLWindow, args->CurrentPoint); +} + +void SDL_WinRTApp::OnMouseMoved(MouseDevice^ mouseDevice, MouseEventArgs^ args) +{ + WINRT_ProcessMouseMovedEvent(WINRT_GlobalSDLWindow, args); +} + +void SDL_WinRTApp::OnKeyDown(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args) +{ + WINRT_ProcessKeyDownEvent(args); +} + +void SDL_WinRTApp::OnKeyUp(Windows::UI::Core::CoreWindow^ sender, Windows::UI::Core::KeyEventArgs^ args) +{ + WINRT_ProcessKeyUpEvent(args); +} + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP +void SDL_WinRTApp::OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args) +{ + SDL_SendKeyboardKey(SDL_PRESSED, SDL_SCANCODE_AC_BACK); + SDL_SendKeyboardKey(SDL_RELEASED, SDL_SCANCODE_AC_BACK); + + const char *hint = SDL_GetHint(SDL_HINT_WINRT_HANDLE_BACK_BUTTON); + if (hint) { + if (*hint == '1') { + args->Handled = true; + } + } +} +#endif + diff --git a/src/core/winrt/SDL_winrtapp_direct3d.h b/src/core/winrt/SDL_winrtapp_direct3d.h new file mode 100644 index 000000000..07e4a8048 --- /dev/null +++ b/src/core/winrt/SDL_winrtapp_direct3d.h @@ -0,0 +1,58 @@ +#pragma once + +#include + +extern int SDL_WinRTInitNonXAMLApp(int (*mainFunction)(int, char **)); + +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 + void PumpEvents(); + +protected: + // Event Handlers. + +#if WINAPI_FAMILY == WINAPI_FAMILY_APP // for Windows 8/8.1/RT apps... (and not Phone apps) + void OnSettingsPaneCommandsRequested( + Windows::UI::ApplicationSettings::SettingsPane ^p, + Windows::UI::ApplicationSettings::SettingsPaneCommandsRequestedEventArgs ^args); +#endif // if WINAPI_FAMILY == WINAPI_FAMILY_APP + + 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 OnExiting(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); + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + void OnBackButtonPressed(Platform::Object^ sender, Windows::Phone::UI::Input::BackPressedEventArgs^ args); +#endif + +private: + bool m_windowClosed; + bool m_windowVisible; +}; + +extern SDL_WinRTApp ^ SDL_WinRTGlobalApp; diff --git a/src/core/winrt/SDL_winrtapp_xaml.cpp b/src/core/winrt/SDL_winrtapp_xaml.cpp new file mode 100644 index 000000000..8b8a8ee63 --- /dev/null +++ b/src/core/winrt/SDL_winrtapp_xaml.cpp @@ -0,0 +1,158 @@ +/* + 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. +*/ + +/* Windows includes */ +#include +#include + +#if WINAPI_FAMILY == WINAPI_FAMILY_APP +#include +#endif + + +/* SDL includes */ +#include "SDL.h" +#include "../../video/winrt/SDL_winrtevents_c.h" +#include "../../video/winrt/SDL_winrtvideo_cpp.h" +#include "SDL_winrtapp_common.h" +#include "SDL_winrtapp_xaml.h" + + + +/* SDL-internal globals: */ +SDL_bool WINRT_XAMLWasEnabled = SDL_FALSE; + +#if WINAPI_FAMILY == WINAPI_FAMILY_APP +ISwapChainBackgroundPanelNative * WINRT_GlobalSwapChainBackgroundPanelNative = NULL; +static Windows::Foundation::EventRegistrationToken WINRT_XAMLAppEventToken; +#endif + + +/* + * Input event handlers (XAML) + */ +#if WINAPI_FAMILY == WINAPI_FAMILY_APP + +static void +WINRT_OnPointerPressedViaXAML(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ args) +{ + WINRT_ProcessPointerPressedEvent(WINRT_GlobalSDLWindow, args->GetCurrentPoint(nullptr)); +} + +static void +WINRT_OnPointerMovedViaXAML(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ args) +{ + WINRT_ProcessPointerMovedEvent(WINRT_GlobalSDLWindow, args->GetCurrentPoint(nullptr)); +} + +static void +WINRT_OnPointerReleasedViaXAML(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ args) +{ + WINRT_ProcessPointerReleasedEvent(WINRT_GlobalSDLWindow, args->GetCurrentPoint(nullptr)); +} + +static void +WINRT_OnPointerWheelChangedViaXAML(Platform::Object^ sender, Windows::UI::Xaml::Input::PointerRoutedEventArgs^ args) +{ + WINRT_ProcessPointerWheelChangedEvent(WINRT_GlobalSDLWindow, args->GetCurrentPoint(nullptr)); +} + +#endif // WINAPI_FAMILY == WINAPI_FAMILY_APP + + +/* + * XAML-to-SDL Rendering Callback + */ +#if WINAPI_FAMILY == WINAPI_FAMILY_APP + +static void +WINRT_OnRenderViaXAML(_In_ Platform::Object^ sender, _In_ Platform::Object^ args) +{ + WINRT_CycleXAMLThread(); +} + +#endif // WINAPI_FAMILY == WINAPI_FAMILY_APP + + +/* + * SDL + XAML Initialization + */ + +int +SDL_WinRTInitXAMLApp(int (*mainFunction)(int, char **), void * backgroundPanelAsIInspectable) +{ +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + return SDL_SetError("XAML support is not yet available in Windows Phone."); +#else + // Declare C++/CX namespaces: + using namespace Platform; + using namespace Windows::Foundation; + using namespace Windows::UI::Core; + using namespace Windows::UI::Xaml; + using namespace Windows::UI::Xaml::Controls; + using namespace Windows::UI::Xaml::Input; + using namespace Windows::UI::Xaml::Media; + + // Make sure we have a valid XAML element (to draw onto): + if ( ! backgroundPanelAsIInspectable) { + return SDL_SetError("'backgroundPanelAsIInspectable' can't be NULL"); + } + + Platform::Object ^ backgroundPanel = reinterpret_cast((IInspectable *) backgroundPanelAsIInspectable); + SwapChainBackgroundPanel ^swapChainBackgroundPanel = dynamic_cast(backgroundPanel); + if ( ! swapChainBackgroundPanel) { + return SDL_SetError("An unknown or unsupported type of XAML control was specified."); + } + + // Setup event handlers: + swapChainBackgroundPanel->PointerPressed += ref new PointerEventHandler(WINRT_OnPointerPressedViaXAML); + swapChainBackgroundPanel->PointerReleased += ref new PointerEventHandler(WINRT_OnPointerReleasedViaXAML); + swapChainBackgroundPanel->PointerWheelChanged += ref new PointerEventHandler(WINRT_OnPointerWheelChangedViaXAML); + swapChainBackgroundPanel->PointerMoved += ref new PointerEventHandler(WINRT_OnPointerMovedViaXAML); + + // Setup for rendering: + IInspectable *panelInspectable = (IInspectable*) reinterpret_cast(swapChainBackgroundPanel); + panelInspectable->QueryInterface(__uuidof(ISwapChainBackgroundPanelNative), (void **)&WINRT_GlobalSwapChainBackgroundPanelNative); + + WINRT_XAMLAppEventToken = CompositionTarget::Rendering::add(ref new EventHandler(WINRT_OnRenderViaXAML)); + + // Make sure the app is ready to call the SDL-centric main() function: + WINRT_SDLAppEntryPoint = mainFunction; + SDL_SetMainReady(); + + // Make sure video-init knows that we're initializing XAML: + SDL_bool oldXAMLWasEnabledValue = WINRT_XAMLWasEnabled; + WINRT_XAMLWasEnabled = SDL_TRUE; + + // Make sure video modes are detected now, while we still have access to the WinRT + // CoreWindow. WinRT will not allow the app's CoreWindow to be accessed via the + // SDL/WinRT thread. + if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { + // SDL_InitSubSystem will, on error, set the SDL error. Let that propogate to + // the caller to here: + WINRT_XAMLWasEnabled = oldXAMLWasEnabledValue; + return -1; + } + + // All done, for now. + return 0; +#endif // WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP / else +} diff --git a/src/core/winrt/SDL_winrtapp_xaml.h b/src/core/winrt/SDL_winrtapp_xaml.h new file mode 100644 index 000000000..875b768aa --- /dev/null +++ b/src/core/winrt/SDL_winrtapp_xaml.h @@ -0,0 +1,33 @@ +/* + 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_winrtapp_xaml_h +#define _SDL_winrtapp_xaml_h + +#include "SDL_types.h" + +#ifdef __cplusplus +extern SDL_bool WINRT_XAMLWasEnabled; +extern int SDL_WinRTInitXAMLApp(int (*mainFunction)(int, char **), void * backgroundPanelAsIInspectable); +#endif // ifdef __cplusplus + +#endif // ifndef _SDL_winrtapp_xaml_h diff --git a/src/file/SDL_rwops.c b/src/file/SDL_rwops.c index b372c3e4b..afa35d062 100644 --- a/src/file/SDL_rwops.c +++ b/src/file/SDL_rwops.c @@ -316,6 +316,10 @@ stdio_seek(SDL_RWops * context, Sint64 offset, int whence) 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); @@ -522,6 +526,9 @@ SDL_RWFromFile(const char *file, const char *mode) { #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 diff --git a/src/filesystem/winrt/SDL_sysfilesystem.cpp b/src/filesystem/winrt/SDL_sysfilesystem.cpp new file mode 100644 index 000000000..53dbaebe8 --- /dev/null +++ b/src/filesystem/winrt/SDL_sysfilesystem.cpp @@ -0,0 +1,154 @@ +/* TODO, WinRT: include copyright info in SDL_winrtpaths.cpp + TODO, WinRT: remove the need to compile this with C++/CX (/ZW) extensions, and if possible, without C++ at all +*/ + +#include "SDL_config.h" + +#ifdef __WINRT__ + +extern "C" { +#include "SDL_filesystem.h" +#include "SDL_error.h" +#include "SDL_stdinc.h" +#include "SDL_system.h" +#include "../../core/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(); +} + +extern "C" char * +SDL_GetBasePath(void) +{ + const char * srcPath = SDL_WinRTGetFSPathUTF8(SDL_WINRT_PATH_INSTALLED_LOCATION); + size_t destPathLen; + char * destPath = NULL; + + if (!srcPath) { + SDL_SetError("Couldn't locate our basepath: %s", SDL_GetError()); + return NULL; + } + + destPathLen = SDL_strlen(srcPath) + 2; + destPath = (char *) SDL_malloc(destPathLen); + if (!destPath) { + SDL_OutOfMemory(); + return NULL; + } + + SDL_snprintf(destPath, destPathLen, "%s\\", srcPath); + return destPath; +} + +extern "C" char * +SDL_GetPrefPath(const char *org, const char *app) +{ + /* WinRT note: The 'SHGetFolderPath' API that is used in Windows 7 and + * earlier is not available on WinRT or Windows Phone. WinRT provides + * a similar API, but SHGetFolderPath can't be called, at least not + * without violating Microsoft's app-store requirements. + */ + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + /* A 'Roaming' folder is not available in Windows Phone 8, however a 'Local' folder is. */ + const char * srcPath = SDL_WinRTGetFSPathUTF8(SDL_WINRT_PATH_LOCAL_FOLDER); +#else + /* A 'Roaming' folder is available on Windows 8 and 8.1. Use that. */ + const char * srcPath = SDL_WinRTGetFSPathUTF8(SDL_WINRT_PATH_ROAMING_FOLDER); +#endif + + size_t destPathLen; + char * destPath = NULL; + + if (!srcPath) { + SDL_SetError("Couldn't locate our basepath: %s", SDL_GetError()); + return NULL; + } + + destPathLen = SDL_strlen(srcPath) + SDL_strlen(org) + SDL_strlen(app) + 4; + destPath = (char *) SDL_malloc(destPathLen); + if (!destPath) { + SDL_OutOfMemory(); + return NULL; + } + + SDL_snprintf(destPath, destPathLen, "%s\\%s\\%s\\", srcPath, org, app); + return destPath; +} + +#endif /* __WINRT__ */ diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c index fc44bdb93..8361b29fb 100644 --- a/src/joystick/SDL_gamecontroller.c +++ b/src/joystick/SDL_gamecontroller.c @@ -88,7 +88,7 @@ typedef struct _ControllerMapping_t } ControllerMapping_t; static ControllerMapping_t *s_pSupportedControllers = NULL; -#ifdef SDL_JOYSTICK_DINPUT +#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) static ControllerMapping_t *s_pXInputMapping = NULL; #endif @@ -279,7 +279,7 @@ ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickGUID *gu */ ControllerMapping_t *SDL_PrivateGetControllerMapping(int device_index) { -#ifdef SDL_JOYSTICK_DINPUT +#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) if ( SDL_SYS_IsXInputDeviceIndex(device_index) && s_pXInputMapping ) { return s_pXInputMapping; @@ -737,7 +737,7 @@ SDL_GameControllerAddMapping( const char *mappingString ) char *pchMapping; SDL_JoystickGUID jGUID; ControllerMapping_t *pControllerMapping; -#ifdef SDL_JOYSTICK_DINPUT +#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) SDL_bool is_xinput_mapping = SDL_FALSE; #endif @@ -745,7 +745,7 @@ SDL_GameControllerAddMapping( const char *mappingString ) if (!pchGUID) { return SDL_SetError("Couldn't parse GUID from %s", mappingString); } -#ifdef SDL_JOYSTICK_DINPUT +#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) if ( !SDL_strcasecmp( pchGUID, "xinput" ) ) { is_xinput_mapping = SDL_TRUE; } @@ -782,7 +782,7 @@ SDL_GameControllerAddMapping( const char *mappingString ) SDL_free( pchMapping ); return SDL_OutOfMemory(); } -#ifdef SDL_JOYSTICK_DINPUT +#if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT) if ( is_xinput_mapping ) { s_pXInputMapping = pControllerMapping; diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h index 886d0180d..34630ca6b 100644 --- a/src/joystick/SDL_gamecontrollerdb.h +++ b/src/joystick/SDL_gamecontrollerdb.h @@ -42,6 +42,8 @@ static const char *s_ControllerMappings [] = "25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,", "4c05c405000000000000504944564944,PS4 Controller,a:a3,a:b1,b:b2,back:b8,dpdown:h0.0,dpdown:h0.4,dpleft:h0.8,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,guide:b12,leftshoulder:b4,leftshoulder:h0.0,leftstick:b10,leftstick:b7,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightshoulder:b6,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:a4,x:b0,y:b3,", "xinput,X360 Controller,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,guide:b14,leftshoulder:b8,leftstick:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b4,x:b12,y:b13,", +#elif defined(SDL_JOYSTICK_XINPUT) + "xinput,X360 Controller,a:b10,b:b11,back:b5,dpdown:b1,dpleft:b2,dpright:b3,dpup:b0,guide:b14,leftshoulder:b8,leftstick:b6,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b9,rightstick:b7,righttrigger:a5,rightx:a2,righty:a3,start:b4,x:b12,y:b13,", #elif defined(__MACOSX__) "0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,", "6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", /* Guide button doesn't seem to be sent in DInput mode. */ diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h index 6c7a4af95..818509d67 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 ); extern SDL_bool SDL_SYS_IsXInputJoystick(SDL_Joystick * joystick); diff --git a/src/joystick/winrt/SDL_xinputjoystick.c b/src/joystick/winrt/SDL_xinputjoystick.c new file mode 100644 index 000000000..1bb91b272 --- /dev/null +++ b/src/joystick/winrt/SDL_xinputjoystick.c @@ -0,0 +1,537 @@ +/* + 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 "SDL_timer.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 detection-polling, or during backend-initialization)? + SDL_bool isDeviceConnectionEventPending; // was a device added, and is the associated add-event pending? + SDL_bool isDeviceRemovalEventPending; // was the device removed, and is the associated remove-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]; + +/* Device detection can be extremely costly performance-wise, in some cases. + In particular, if no devices are connected, calls to detect a single device, + via either XInputGetState() or XInputGetCapabilities(), can take upwards of + 20 ms on a 1st generation Surface RT, more if devices are detected across + all of of XInput's four device slots. WinRT and XInput do not appear to + have callback-based APIs to notify an app when a device is connected, at + least as of Windows 8.1. The synchronous XInput calls must be used. + + Once a device is connected, calling XInputGetState() is a much less costly + operation, with individual calls costing well under 1 ms, and often under + 0.1 ms [on a 1st gen Surface RT]. + + With XInput's performance limitations in mind, a separate device-detection + thread will be utilized (by SDL) to try to move costly XInput calls off the + main thread. Polling of active devices still, however, occurs on the main + thread. + */ +static SDL_Thread * g_DeviceDetectionThread = NULL; +static SDL_mutex * g_DeviceInfoLock = NULL; +static SDL_bool g_DeviceDetectionQuit = SDL_FALSE; + +/* Main function for the device-detection thread. + */ +static int +DeviceDetectionThreadMain(void * _data) +{ + DWORD result; + XINPUT_CAPABILITIES tempXInputCaps; + int i; + + while (1) { + /* See if the device-detection thread is being asked to shutdown. + */ + SDL_LockMutex(g_DeviceInfoLock); + if (g_DeviceDetectionQuit) { + SDL_UnlockMutex(g_DeviceInfoLock); + break; + } + SDL_UnlockMutex(g_DeviceInfoLock); + + /* Add a short delay to prevent the device-detection thread from eating + up too much CPU time: + */ + SDL_Delay(300); + + /* TODO, WinRT: try making the device-detection thread wakeup sooner from its CPU-preserving SDL_Delay, if the thread was asked to quit. + */ + + /* See if any new devices are connected. */ + SDL_LockMutex(g_DeviceInfoLock); + for (i = 0; i < XUSER_MAX_COUNT; ++i) { + if (!g_XInputData[i].isDeviceConnected && + !g_XInputData[i].isDeviceConnectionEventPending && + !g_XInputData[i].isDeviceRemovalEventPending) + { + SDL_UnlockMutex(g_DeviceInfoLock); + result = XInputGetCapabilities(i, 0, &tempXInputCaps); + SDL_LockMutex(g_DeviceInfoLock); + if (result == ERROR_SUCCESS) { + /* Yes, a device is connected. Mark it as such. + Others will be told about this (via an + SDL_JOYDEVICEADDED event) in the next call to + SDL_SYS_JoystickDetect. + */ + g_XInputData[i].isDeviceConnected = SDL_TRUE; + g_XInputData[i].isDeviceConnectionEventPending = SDL_TRUE; + } + } + } + SDL_UnlockMutex(g_DeviceInfoLock); + } + + return 0; +} + +/* 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; + } + } + + /* Start up the device-detection thread. + */ + g_DeviceDetectionQuit = SDL_FALSE; + g_DeviceInfoLock = SDL_CreateMutex(); + g_DeviceDetectionThread = SDL_CreateThread(DeviceDetectionThreadMain, "SDL_joystick", NULL); + + 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). + */ + SDL_LockMutex(g_DeviceInfoLock); + for (i = 0; i < XUSER_MAX_COUNT; ++i) { + if (g_XInputData[i].isDeviceConnected) { + ++joystickCount; + } + } + SDL_UnlockMutex(g_DeviceInfoLock); + + return joystickCount; +} + +void SDL_SYS_JoystickDetect() +{ + DWORD i; + SDL_Event event; + + /* Iterate through each possible XInput device, seeing if any devices + have been connected, or if they were removed. + */ + SDL_LockMutex(g_DeviceInfoLock); + for (i = 0; i < XUSER_MAX_COUNT; ++i) { + /* See if any new devices are connected. */ + if (g_XInputData[i].isDeviceConnectionEventPending) { +#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 + g_XInputData[i].isDeviceConnectionEventPending = SDL_FALSE; + } 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_UnlockMutex(g_DeviceInfoLock); +} + +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) +{ + SDL_bool isDeviceConnected; + SDL_LockMutex(g_DeviceInfoLock); + isDeviceConnected = joystick->hwdata->isDeviceConnected; + SDL_UnlockMutex(g_DeviceInfoLock); + return 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; + XINPUT_STATE prevXInputState; + + SDL_LockMutex(g_DeviceInfoLock); + + /* Before polling for new data, make note of the old data */ + 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 */ + } + SDL_UnlockMutex(g_DeviceInfoLock); + 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 + } + + SDL_UnlockMutex(g_DeviceInfoLock); +} + +/* Function to close a joystick after use */ +void +SDL_SYS_JoystickClose(SDL_Joystick * joystick) +{ + /* Clear cached button data on the joystick */ + SDL_LockMutex(g_DeviceInfoLock); + SDL_zero(joystick->hwdata->XInputState); + SDL_UnlockMutex(g_DeviceInfoLock); + + /* 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) +{ + /* Tell the joystick detection thread to stop, then wait for it to finish */ + SDL_LockMutex(g_DeviceInfoLock); + g_DeviceDetectionQuit = SDL_TRUE; + SDL_UnlockMutex(g_DeviceInfoLock); + SDL_WaitThread(g_DeviceDetectionThread, NULL); + + /* Clean up device-detection stuff */ + SDL_DestroyMutex(g_DeviceInfoLock); + g_DeviceInfoLock = NULL; + g_DeviceDetectionThread = NULL; + g_DeviceDetectionQuit = SDL_FALSE; + + 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 cbbd92978..4d32b0985 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/winrt/SDL_winrt_main_NonXAML.cpp b/src/main/winrt/SDL_winrt_main_NonXAML.cpp new file mode 100644 index 000000000..088cd6c32 --- /dev/null +++ b/src/main/winrt/SDL_winrt_main_NonXAML.cpp @@ -0,0 +1,56 @@ + +#include +#include + +/* At least one file in any SDL/WinRT app appears to require compilation + with C++/CX, otherwise a Windows Metadata file won't get created, and + an APPX0702 build error can appear shortly after linking. + + The following set of preprocessor code forces this file to be compiled + as C++/CX, which appears to cause Visual C++ 2012's build tools to + create this .winmd file, and will help allow builds of SDL/WinRT apps + to proceed without error. + + If other files in an app's project enable C++/CX compilation, then it might + be possible for SDL_winrt_main_NonXAML.cpp to be compiled without /ZW, + for Visual C++'s build tools to create a winmd file, and for the app to + build without APPX0702 errors. In this case, if + SDL_WINRT_METADATA_FILE_AVAILABLE is defined as a C/C++ macro, then + the #error (to force C++/CX compilation) will be disabled. + + Please note that /ZW can be specified on a file-by-file basis. To do this, + right click on the file in Visual C++, click Properties, then change the + setting through the dialog that comes up. +*/ +#ifndef SDL_WINRT_METADATA_FILE_AVAILABLE +#ifndef __cplusplus_winrt +#error SDL_winrt_main_NonXAML.cpp must be compiled with /ZW, otherwise build errors due to missing .winmd files can occur. +#endif +#endif + +/* Prevent MSVC++ from warning about threading models when defining our + custom WinMain. The threading model will instead be set via a direct + call to Windows::Foundation::Initialize (rather than via an attributed + function). + + To note, this warning (C4447) does not seem to come up unless this file + is compiled with C++/CX enabled (via the /ZW compiler flag). +*/ +#ifdef _MSC_VER +#pragma warning(disable:4447) +#endif + +/* Make sure the function to initialize the Windows Runtime gets linked in. */ +#ifdef _MSC_VER +#pragma comment(lib, "runtimeobject.lib") +#endif + +int CALLBACK WinMain(HINSTANCE, HINSTANCE, LPSTR, int) +{ + if (FAILED(Windows::Foundation::Initialize(RO_INIT_MULTITHREADED))) { + return 1; + } + + SDL_WinRTRunApp(SDL_main, NULL); + return 0; +} diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c index 703594aea..1547668f3 100644 --- a/src/render/SDL_render.c +++ b/src/render/SDL_render.c @@ -50,6 +50,9 @@ static const SDL_RenderDriver *render_drivers[] = { #if SDL_VIDEO_RENDER_D3D &D3D_RenderDriver, #endif +#if SDL_VIDEO_RENDER_D3D11 + &D3D11_RenderDriver, +#endif #if SDL_VIDEO_RENDER_OGL &GL_RenderDriver, #endif diff --git a/src/render/SDL_sysrender.h b/src/render/SDL_sysrender.h index 511cd9ad7..5098d34fa 100644 --- a/src/render/SDL_sysrender.h +++ b/src/render/SDL_sysrender.h @@ -171,6 +171,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_render_d3d11.cpp b/src/render/direct3d11/SDL_render_d3d11.cpp new file mode 100644 index 000000000..58a7ede22 --- /dev/null +++ b/src/render/direct3d11/SDL_render_d3d11.cpp @@ -0,0 +1,2386 @@ +/* + 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 + +#if WINAPI_FAMILY == WINAPI_FAMILY_APP +#include +#endif + +#endif + +extern "C" { +#include "../../core/windows/SDL_windows.h" +#include "SDL_hints.h" +#include "SDL_system.h" +#include "SDL_syswm.h" +#include "../SDL_sysrender.h" +#include "../../video/SDL_sysvideo.h" +} + +#include +#include + +#include +#include +#include + + +using namespace DirectX; +using namespace Microsoft::WRL; +using namespace std; + +#ifdef __WINRT__ +using namespace Windows::Graphics::Display; +using namespace Windows::UI::Core; +#endif + +/* Texture sampling types */ +static const D3D11_FILTER SDL_D3D11_NEAREST_PIXEL_FILTER = D3D11_FILTER_MIN_MAG_MIP_POINT; +static const D3D11_FILTER SDL_D3D11_LINEAR_FILTER = D3D11_FILTER_MIN_MAG_MIP_LINEAR; + +/* Vertex shader, common values */ +struct VertexShaderConstants +{ + DirectX::XMFLOAT4X4 model; + DirectX::XMFLOAT4X4 projectionAndView; +}; + +/* Per-vertex data */ +struct VertexPositionColor +{ + DirectX::XMFLOAT3 pos; + DirectX::XMFLOAT2 tex; + DirectX::XMFLOAT4 color; +}; + +/* Per-texture data */ +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_FILTER scaleMode; +} D3D11_TextureData; + +/* Private renderer data */ +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 nearestPixelSampler; + Microsoft::WRL::ComPtr linearSampler; + D3D_FEATURE_LEVEL featureLevel; + + // Rasterizers: + // If this list starts to get unwieldy, then consider using a map<> of them. + Microsoft::WRL::ComPtr mainRasterizer; + Microsoft::WRL::ComPtr clippedRasterizer; + + // Vertex buffer constants: + 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; + + +/* Direct3D 11.x shaders + + SDL's shaders are compiled into SDL itself, to simplify distribution. + + All Direct3D 11.x shaders were compiled with the following: + + fxc /E"main" /T "" /Fo"" "" + + Variables: + - : the type of shader. A table of utilized shader types is + listed below. + - : where to store compiled output + - : where to read shader source code from + + Shader types: + - ps_4_0_level_9_1: Pixel shader for Windows 8+, including Windows RT + - vs_4_0_level_9_1: Vertex shader for Windows 8+, including Windows RT + - ps_4_0_level_9_3: Pixel shader for Windows Phone 8 + - vs_4_0_level_9_3: Vertex shader for Windows Phone 8 + + + Shader object code was converted to a list of DWORDs via the following + *nix style command (available separately from Windows + MSVC): + + hexdump -v -e '6/4 "0x%08.8x, " "\n"' + */ +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP +#define D3D11_USE_SHADER_MODEL_4_0_level_9_3 +#else +#define D3D11_USE_SHADER_MODEL_4_0_level_9_1 +#endif + +/* The texture-rendering pixel shader: + + --- D3D11_PixelShader_Textures.hlsl --- + 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; + } +*/ +#if defined(D3D11_USE_SHADER_MODEL_4_0_level_9_1) +static const DWORD D3D11_PixelShader_Textures[] = { + 0x43425844, 0x6299b59f, 0x155258f2, 0x873ab86a, 0xfcbb6dcd, 0x00000001, + 0x00000330, 0x00000006, 0x00000038, 0x000000c0, 0x0000015c, 0x000001d8, + 0x00000288, 0x000002fc, 0x396e6f41, 0x00000080, 0x00000080, 0xffff0200, + 0x00000058, 0x00000028, 0x00280000, 0x00280000, 0x00280000, 0x00240001, + 0x00280000, 0x00000000, 0xffff0200, 0x0200001f, 0x80000000, 0xb0030000, + 0x0200001f, 0x80000000, 0xb00f0001, 0x0200001f, 0x90000000, 0xa00f0800, + 0x03000042, 0x800f0000, 0xb0e40000, 0xa0e40800, 0x03000005, 0x800f0000, + 0x80e40000, 0xb0e40001, 0x02000001, 0x800f0800, 0x80e40000, 0x0000ffff, + 0x52444853, 0x00000094, 0x00000040, 0x00000025, 0x0300005a, 0x00106000, + 0x00000000, 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x03001062, + 0x00101032, 0x00000001, 0x03001062, 0x001010f2, 0x00000002, 0x03000065, + 0x001020f2, 0x00000000, 0x02000068, 0x00000001, 0x09000045, 0x001000f2, + 0x00000000, 0x00101046, 0x00000001, 0x00107e46, 0x00000000, 0x00106000, + 0x00000000, 0x07000038, 0x001020f2, 0x00000000, 0x00100e46, 0x00000000, + 0x00101e46, 0x00000002, 0x0100003e, 0x54415453, 0x00000074, 0x00000003, + 0x00000001, 0x00000000, 0x00000003, 0x00000001, 0x00000000, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x46454452, 0x000000a8, + 0x00000000, 0x00000000, 0x00000002, 0x0000001c, 0xffff0400, 0x00000100, + 0x00000072, 0x0000005c, 0x00000003, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000001, 0x00000067, 0x00000002, 0x00000005, + 0x00000004, 0xffffffff, 0x00000000, 0x00000001, 0x0000000d, 0x53656874, + 0x6c706d61, 0x74007265, 0x65546568, 0x72757478, 0x694d0065, 0x736f7263, + 0x2074666f, 0x20295228, 0x4c534c48, 0x61685320, 0x20726564, 0x706d6f43, + 0x72656c69, 0x332e3920, 0x32392e30, 0x312e3030, 0x34383336, 0xababab00, + 0x4e475349, 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, + 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, + 0x00000000, 0x00000003, 0x00000001, 0x00000303, 0x00000065, 0x00000000, + 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x505f5653, 0x5449534f, + 0x004e4f49, 0x43584554, 0x44524f4f, 0x4c4f4300, 0xab00524f, 0x4e47534f, + 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, + 0x00000003, 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054 +}; +#elif defined(D3D11_USE_SHADER_MODEL_4_0_level_9_3) +static const DWORD D3D11_PixelShader_Textures[] = { + 0x43425844, 0x5876569a, 0x01b6c87e, 0x8447454f, 0xc7f3ef10, 0x00000001, + 0x00000330, 0x00000006, 0x00000038, 0x000000c0, 0x0000015c, 0x000001d8, + 0x00000288, 0x000002fc, 0x396e6f41, 0x00000080, 0x00000080, 0xffff0200, + 0x00000058, 0x00000028, 0x00280000, 0x00280000, 0x00280000, 0x00240001, + 0x00280000, 0x00000000, 0xffff0201, 0x0200001f, 0x80000000, 0xb0030000, + 0x0200001f, 0x80000000, 0xb00f0001, 0x0200001f, 0x90000000, 0xa00f0800, + 0x03000042, 0x800f0000, 0xb0e40000, 0xa0e40800, 0x03000005, 0x800f0000, + 0x80e40000, 0xb0e40001, 0x02000001, 0x800f0800, 0x80e40000, 0x0000ffff, + 0x52444853, 0x00000094, 0x00000040, 0x00000025, 0x0300005a, 0x00106000, + 0x00000000, 0x04001858, 0x00107000, 0x00000000, 0x00005555, 0x03001062, + 0x00101032, 0x00000001, 0x03001062, 0x001010f2, 0x00000002, 0x03000065, + 0x001020f2, 0x00000000, 0x02000068, 0x00000001, 0x09000045, 0x001000f2, + 0x00000000, 0x00101046, 0x00000001, 0x00107e46, 0x00000000, 0x00106000, + 0x00000000, 0x07000038, 0x001020f2, 0x00000000, 0x00100e46, 0x00000000, + 0x00101e46, 0x00000002, 0x0100003e, 0x54415453, 0x00000074, 0x00000003, + 0x00000001, 0x00000000, 0x00000003, 0x00000001, 0x00000000, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x46454452, 0x000000a8, + 0x00000000, 0x00000000, 0x00000002, 0x0000001c, 0xffff0400, 0x00000100, + 0x00000072, 0x0000005c, 0x00000003, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000001, 0x00000001, 0x00000067, 0x00000002, 0x00000005, + 0x00000004, 0xffffffff, 0x00000000, 0x00000001, 0x0000000d, 0x53656874, + 0x6c706d61, 0x74007265, 0x65546568, 0x72757478, 0x694d0065, 0x736f7263, + 0x2074666f, 0x20295228, 0x4c534c48, 0x61685320, 0x20726564, 0x706d6f43, + 0x72656c69, 0x332e3920, 0x32392e30, 0x312e3030, 0x34383336, 0xababab00, + 0x4e475349, 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, + 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, + 0x00000000, 0x00000003, 0x00000001, 0x00000303, 0x00000065, 0x00000000, + 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x505f5653, 0x5449534f, + 0x004e4f49, 0x43584554, 0x44524f4f, 0x4c4f4300, 0xab00524f, 0x4e47534f, + 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, + 0x00000003, 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054 +}; +#else +#error "An appropriate 'textures' pixel shader is not defined" +#endif + +/* The color-only-rendering pixel shader: + + --- D3D11_PixelShader_Colors.hlsl --- + struct PixelShaderInput + { + float4 pos : SV_POSITION; + float2 tex : TEXCOORD0; + float4 color : COLOR0; + }; + + float4 main(PixelShaderInput input) : SV_TARGET + { + return input.color; + } +*/ +#if defined(D3D11_USE_SHADER_MODEL_4_0_level_9_1) +static const DWORD D3D11_PixelShader_Colors[] = { + 0x43425844, 0xd74c28fe, 0xa1eb8804, 0x269d512a, 0x7699723d, 0x00000001, + 0x00000240, 0x00000006, 0x00000038, 0x00000084, 0x000000c4, 0x00000140, + 0x00000198, 0x0000020c, 0x396e6f41, 0x00000044, 0x00000044, 0xffff0200, + 0x00000020, 0x00000024, 0x00240000, 0x00240000, 0x00240000, 0x00240000, + 0x00240000, 0xffff0200, 0x0200001f, 0x80000000, 0xb00f0001, 0x02000001, + 0x800f0800, 0xb0e40001, 0x0000ffff, 0x52444853, 0x00000038, 0x00000040, + 0x0000000e, 0x03001062, 0x001010f2, 0x00000002, 0x03000065, 0x001020f2, + 0x00000000, 0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000002, + 0x0100003e, 0x54415453, 0x00000074, 0x00000002, 0x00000000, 0x00000000, + 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x46454452, 0x00000050, 0x00000000, 0x00000000, + 0x00000000, 0x0000001c, 0xffff0400, 0x00000100, 0x0000001c, 0x7263694d, + 0x666f736f, 0x52282074, 0x4c482029, 0x53204c53, 0x65646168, 0x6f432072, + 0x6c69706d, 0x39207265, 0x2e30332e, 0x30303239, 0x3336312e, 0xab003438, + 0x4e475349, 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, + 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, + 0x00000000, 0x00000003, 0x00000001, 0x00000003, 0x00000065, 0x00000000, + 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x505f5653, 0x5449534f, + 0x004e4f49, 0x43584554, 0x44524f4f, 0x4c4f4300, 0xab00524f, 0x4e47534f, + 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, + 0x00000003, 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054 +}; +#elif defined(D3D11_USE_SHADER_MODEL_4_0_level_9_3) +static const DWORD D3D11_PixelShader_Colors[] = { + 0x43425844, 0x93f6ccfc, 0x5f919270, 0x7a11aa4f, 0x9148e931, 0x00000001, + 0x00000240, 0x00000006, 0x00000038, 0x00000084, 0x000000c4, 0x00000140, + 0x00000198, 0x0000020c, 0x396e6f41, 0x00000044, 0x00000044, 0xffff0200, + 0x00000020, 0x00000024, 0x00240000, 0x00240000, 0x00240000, 0x00240000, + 0x00240000, 0xffff0201, 0x0200001f, 0x80000000, 0xb00f0001, 0x02000001, + 0x800f0800, 0xb0e40001, 0x0000ffff, 0x52444853, 0x00000038, 0x00000040, + 0x0000000e, 0x03001062, 0x001010f2, 0x00000002, 0x03000065, 0x001020f2, + 0x00000000, 0x05000036, 0x001020f2, 0x00000000, 0x00101e46, 0x00000002, + 0x0100003e, 0x54415453, 0x00000074, 0x00000002, 0x00000000, 0x00000000, + 0x00000002, 0x00000000, 0x00000000, 0x00000000, 0x00000001, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000002, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x46454452, 0x00000050, 0x00000000, 0x00000000, + 0x00000000, 0x0000001c, 0xffff0400, 0x00000100, 0x0000001c, 0x7263694d, + 0x666f736f, 0x52282074, 0x4c482029, 0x53204c53, 0x65646168, 0x6f432072, + 0x6c69706d, 0x39207265, 0x2e30332e, 0x30303239, 0x3336312e, 0xab003438, + 0x4e475349, 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, + 0x00000001, 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, + 0x00000000, 0x00000003, 0x00000001, 0x00000003, 0x00000065, 0x00000000, + 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x505f5653, 0x5449534f, + 0x004e4f49, 0x43584554, 0x44524f4f, 0x4c4f4300, 0xab00524f, 0x4e47534f, + 0x0000002c, 0x00000001, 0x00000008, 0x00000020, 0x00000000, 0x00000000, + 0x00000003, 0x00000000, 0x0000000f, 0x545f5653, 0x45475241, 0xabab0054 +}; +#else +#error "An appropriate 'colors' pixel shader is not defined." +#endif + +/* The sole vertex shader: + + --- D3D11_VertexShader.hlsl --- + #pragma pack_matrix( row_major ) + + cbuffer VertexShaderConstants : register(b0) + { + matrix model; + matrix projectionAndView; + }; + + 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, projectionAndView); + output.pos = pos; + + // Pass through texture coordinates and color values without transformation + output.tex = input.tex; + output.color = input.color; + + return output; + } +*/ +#if defined(D3D11_USE_SHADER_MODEL_4_0_level_9_1) +static const DWORD D3D11_VertexShader[] = { + 0x43425844, 0x62dfae5f, 0x3e8bd8df, 0x9ec97127, 0x5044eefb, 0x00000001, + 0x00000598, 0x00000006, 0x00000038, 0x0000016c, 0x00000334, 0x000003b0, + 0x000004b4, 0x00000524, 0x396e6f41, 0x0000012c, 0x0000012c, 0xfffe0200, + 0x000000f8, 0x00000034, 0x00240001, 0x00300000, 0x00300000, 0x00240000, + 0x00300001, 0x00000000, 0x00010008, 0x00000000, 0x00000000, 0xfffe0200, + 0x0200001f, 0x80000005, 0x900f0000, 0x0200001f, 0x80010005, 0x900f0001, + 0x0200001f, 0x80020005, 0x900f0002, 0x03000005, 0x800f0000, 0x90550000, + 0xa0e40002, 0x04000004, 0x800f0000, 0x90000000, 0xa0e40001, 0x80e40000, + 0x04000004, 0x800f0000, 0x90aa0000, 0xa0e40003, 0x80e40000, 0x03000002, + 0x800f0000, 0x80e40000, 0xa0e40004, 0x03000005, 0x800f0001, 0x80550000, + 0xa0e40006, 0x04000004, 0x800f0001, 0x80000000, 0xa0e40005, 0x80e40001, + 0x04000004, 0x800f0001, 0x80aa0000, 0xa0e40007, 0x80e40001, 0x04000004, + 0x800f0000, 0x80ff0000, 0xa0e40008, 0x80e40001, 0x04000004, 0xc0030000, + 0x80ff0000, 0xa0e40000, 0x80e40000, 0x02000001, 0xc00c0000, 0x80e40000, + 0x02000001, 0xe0030000, 0x90e40001, 0x02000001, 0xe00f0001, 0x90e40002, + 0x0000ffff, 0x52444853, 0x000001c0, 0x00010040, 0x00000070, 0x04000059, + 0x00208e46, 0x00000000, 0x00000008, 0x0300005f, 0x00101072, 0x00000000, + 0x0300005f, 0x00101032, 0x00000001, 0x0300005f, 0x001010f2, 0x00000002, + 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x03000065, 0x00102032, + 0x00000001, 0x03000065, 0x001020f2, 0x00000002, 0x02000068, 0x00000002, + 0x08000038, 0x001000f2, 0x00000000, 0x00101556, 0x00000000, 0x00208e46, + 0x00000000, 0x00000001, 0x0a000032, 0x001000f2, 0x00000000, 0x00101006, + 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x00100e46, 0x00000000, + 0x0a000032, 0x001000f2, 0x00000000, 0x00101aa6, 0x00000000, 0x00208e46, + 0x00000000, 0x00000002, 0x00100e46, 0x00000000, 0x08000000, 0x001000f2, + 0x00000000, 0x00100e46, 0x00000000, 0x00208e46, 0x00000000, 0x00000003, + 0x08000038, 0x001000f2, 0x00000001, 0x00100556, 0x00000000, 0x00208e46, + 0x00000000, 0x00000005, 0x0a000032, 0x001000f2, 0x00000001, 0x00100006, + 0x00000000, 0x00208e46, 0x00000000, 0x00000004, 0x00100e46, 0x00000001, + 0x0a000032, 0x001000f2, 0x00000001, 0x00100aa6, 0x00000000, 0x00208e46, + 0x00000000, 0x00000006, 0x00100e46, 0x00000001, 0x0a000032, 0x001020f2, + 0x00000000, 0x00100ff6, 0x00000000, 0x00208e46, 0x00000000, 0x00000007, + 0x00100e46, 0x00000001, 0x05000036, 0x00102032, 0x00000001, 0x00101046, + 0x00000001, 0x05000036, 0x001020f2, 0x00000002, 0x00101e46, 0x00000002, + 0x0100003e, 0x54415453, 0x00000074, 0x0000000b, 0x00000002, 0x00000000, + 0x00000006, 0x00000003, 0x00000000, 0x00000000, 0x00000001, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x46454452, 0x000000fc, 0x00000001, 0x00000054, + 0x00000001, 0x0000001c, 0xfffe0400, 0x00000100, 0x000000c6, 0x0000003c, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, + 0x00000001, 0x74726556, 0x68537865, 0x72656461, 0x736e6f43, 0x746e6174, + 0xabab0073, 0x0000003c, 0x00000002, 0x0000006c, 0x00000080, 0x00000000, + 0x00000000, 0x0000009c, 0x00000000, 0x00000040, 0x00000002, 0x000000a4, + 0x00000000, 0x000000b4, 0x00000040, 0x00000040, 0x00000002, 0x000000a4, + 0x00000000, 0x65646f6d, 0xabab006c, 0x00030002, 0x00040004, 0x00000000, + 0x00000000, 0x6a6f7270, 0x69746365, 0x6e416e6f, 0x65695664, 0x694d0077, + 0x736f7263, 0x2074666f, 0x20295228, 0x4c534c48, 0x61685320, 0x20726564, + 0x706d6f43, 0x72656c69, 0x332e3920, 0x32392e30, 0x312e3030, 0x34383336, + 0xababab00, 0x4e475349, 0x00000068, 0x00000003, 0x00000008, 0x00000050, + 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000707, 0x00000059, + 0x00000000, 0x00000000, 0x00000003, 0x00000001, 0x00000303, 0x00000062, + 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x49534f50, + 0x4e4f4954, 0x58455400, 0x524f4f43, 0x4f430044, 0x00524f4c, 0x4e47534f, + 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, 0x00000001, + 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, 0x00000000, + 0x00000003, 0x00000001, 0x00000c03, 0x00000065, 0x00000000, 0x00000000, + 0x00000003, 0x00000002, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, + 0x43584554, 0x44524f4f, 0x4c4f4300, 0xab00524f +}; +#elif defined(D3D11_USE_SHADER_MODEL_4_0_level_9_3) +static const DWORD D3D11_VertexShader[] = { + 0x43425844, 0x01a24e41, 0x696af551, 0x4b2a87d1, 0x82ea03f6, 0x00000001, + 0x00000598, 0x00000006, 0x00000038, 0x0000016c, 0x00000334, 0x000003b0, + 0x000004b4, 0x00000524, 0x396e6f41, 0x0000012c, 0x0000012c, 0xfffe0200, + 0x000000f8, 0x00000034, 0x00240001, 0x00300000, 0x00300000, 0x00240000, + 0x00300001, 0x00000000, 0x00010008, 0x00000000, 0x00000000, 0xfffe0201, + 0x0200001f, 0x80000005, 0x900f0000, 0x0200001f, 0x80010005, 0x900f0001, + 0x0200001f, 0x80020005, 0x900f0002, 0x03000005, 0x800f0000, 0x90550000, + 0xa0e40002, 0x04000004, 0x800f0000, 0x90000000, 0xa0e40001, 0x80e40000, + 0x04000004, 0x800f0000, 0x90aa0000, 0xa0e40003, 0x80e40000, 0x03000002, + 0x800f0000, 0x80e40000, 0xa0e40004, 0x03000005, 0x800f0001, 0x80550000, + 0xa0e40006, 0x04000004, 0x800f0001, 0x80000000, 0xa0e40005, 0x80e40001, + 0x04000004, 0x800f0001, 0x80aa0000, 0xa0e40007, 0x80e40001, 0x04000004, + 0x800f0000, 0x80ff0000, 0xa0e40008, 0x80e40001, 0x04000004, 0xc0030000, + 0x80ff0000, 0xa0e40000, 0x80e40000, 0x02000001, 0xc00c0000, 0x80e40000, + 0x02000001, 0xe0030000, 0x90e40001, 0x02000001, 0xe00f0001, 0x90e40002, + 0x0000ffff, 0x52444853, 0x000001c0, 0x00010040, 0x00000070, 0x04000059, + 0x00208e46, 0x00000000, 0x00000008, 0x0300005f, 0x00101072, 0x00000000, + 0x0300005f, 0x00101032, 0x00000001, 0x0300005f, 0x001010f2, 0x00000002, + 0x04000067, 0x001020f2, 0x00000000, 0x00000001, 0x03000065, 0x00102032, + 0x00000001, 0x03000065, 0x001020f2, 0x00000002, 0x02000068, 0x00000002, + 0x08000038, 0x001000f2, 0x00000000, 0x00101556, 0x00000000, 0x00208e46, + 0x00000000, 0x00000001, 0x0a000032, 0x001000f2, 0x00000000, 0x00101006, + 0x00000000, 0x00208e46, 0x00000000, 0x00000000, 0x00100e46, 0x00000000, + 0x0a000032, 0x001000f2, 0x00000000, 0x00101aa6, 0x00000000, 0x00208e46, + 0x00000000, 0x00000002, 0x00100e46, 0x00000000, 0x08000000, 0x001000f2, + 0x00000000, 0x00100e46, 0x00000000, 0x00208e46, 0x00000000, 0x00000003, + 0x08000038, 0x001000f2, 0x00000001, 0x00100556, 0x00000000, 0x00208e46, + 0x00000000, 0x00000005, 0x0a000032, 0x001000f2, 0x00000001, 0x00100006, + 0x00000000, 0x00208e46, 0x00000000, 0x00000004, 0x00100e46, 0x00000001, + 0x0a000032, 0x001000f2, 0x00000001, 0x00100aa6, 0x00000000, 0x00208e46, + 0x00000000, 0x00000006, 0x00100e46, 0x00000001, 0x0a000032, 0x001020f2, + 0x00000000, 0x00100ff6, 0x00000000, 0x00208e46, 0x00000000, 0x00000007, + 0x00100e46, 0x00000001, 0x05000036, 0x00102032, 0x00000001, 0x00101046, + 0x00000001, 0x05000036, 0x001020f2, 0x00000002, 0x00101e46, 0x00000002, + 0x0100003e, 0x54415453, 0x00000074, 0x0000000b, 0x00000002, 0x00000000, + 0x00000006, 0x00000003, 0x00000000, 0x00000000, 0x00000001, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000003, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x46454452, 0x000000fc, 0x00000001, 0x00000054, + 0x00000001, 0x0000001c, 0xfffe0400, 0x00000100, 0x000000c6, 0x0000003c, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000001, + 0x00000001, 0x74726556, 0x68537865, 0x72656461, 0x736e6f43, 0x746e6174, + 0xabab0073, 0x0000003c, 0x00000002, 0x0000006c, 0x00000080, 0x00000000, + 0x00000000, 0x0000009c, 0x00000000, 0x00000040, 0x00000002, 0x000000a4, + 0x00000000, 0x000000b4, 0x00000040, 0x00000040, 0x00000002, 0x000000a4, + 0x00000000, 0x65646f6d, 0xabab006c, 0x00030002, 0x00040004, 0x00000000, + 0x00000000, 0x6a6f7270, 0x69746365, 0x6e416e6f, 0x65695664, 0x694d0077, + 0x736f7263, 0x2074666f, 0x20295228, 0x4c534c48, 0x61685320, 0x20726564, + 0x706d6f43, 0x72656c69, 0x332e3920, 0x32392e30, 0x312e3030, 0x34383336, + 0xababab00, 0x4e475349, 0x00000068, 0x00000003, 0x00000008, 0x00000050, + 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000707, 0x00000059, + 0x00000000, 0x00000000, 0x00000003, 0x00000001, 0x00000303, 0x00000062, + 0x00000000, 0x00000000, 0x00000003, 0x00000002, 0x00000f0f, 0x49534f50, + 0x4e4f4954, 0x58455400, 0x524f4f43, 0x4f430044, 0x00524f4c, 0x4e47534f, + 0x0000006c, 0x00000003, 0x00000008, 0x00000050, 0x00000000, 0x00000001, + 0x00000003, 0x00000000, 0x0000000f, 0x0000005c, 0x00000000, 0x00000000, + 0x00000003, 0x00000001, 0x00000c03, 0x00000065, 0x00000000, 0x00000000, + 0x00000003, 0x00000002, 0x0000000f, 0x505f5653, 0x5449534f, 0x004e4f49, + 0x43584554, 0x44524f4f, 0x4c4f4300, 0xab00524f +}; +#else +#error "An appropriate vertex shader is not defined." +#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_UpdateClipRect(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; + } +} + +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->UpdateClipRect = D3D11_UpdateClipRect; + 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 HRESULT +D3D11_CreateBlendMode(SDL_Renderer * renderer, + BOOL enableBlending, + D3D11_BLEND srcBlend, + D3D11_BLEND destBlend, + D3D11_BLEND srcBlendAlpha, + D3D11_BLEND destBlendAlpha, + 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 = srcBlendAlpha; + blendDesc.RenderTarget[0].DestBlendAlpha = destBlendAlpha; + 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__ ", ID3D11Device1::CreateBlendState", 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; + + // Make sure Direct3D's debugging feature gets used, if the app requests it. + const char *hint = SDL_GetHint(SDL_HINT_RENDER_DIRECT3D11_DEBUG); + if (hint) { + if (*hint == '1') { + creationFlags |= D3D11_CREATE_DEVICE_DEBUG; + } + } + + // 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__ ", D3D11CreateDevice", result); + return result; + } + + // Get the Direct3D 11.1 API device and context interfaces. + result = device.As(&(data->d3dDevice)); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device to ID3D11Device1", result); + return result; + } + + result = context.As(&data->d3dContext); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11DeviceContext to ID3D11DeviceContext1", 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: + // + result = data->d3dDevice->CreateVertexShader( + D3D11_VertexShader, + sizeof(D3D11_VertexShader), + nullptr, + &data->vertexShader + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateVertexShader", 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), + D3D11_VertexShader, + sizeof(D3D11_VertexShader), + &data->inputLayout + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateInputLayout", result); + return result; + } + + // + // Load in SDL's pixel shaders + // + + result = data->d3dDevice->CreatePixelShader( + D3D11_PixelShader_Textures, + sizeof(D3D11_PixelShader_Textures), + nullptr, + &data->texturePixelShader + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreatePixelShader ['textures' shader]", result); + return result; + } + + result = data->d3dDevice->CreatePixelShader( + D3D11_PixelShader_Colors, + sizeof(D3D11_PixelShader_Colors), + nullptr, + &data->colorPixelShader + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreatePixelShader ['color' shader]", result); + return result; + } + + // + // Setup space to hold vertex shader constants: + // + CD3D11_BUFFER_DESC constantBufferDesc(sizeof(VertexShaderConstants), D3D11_BIND_CONSTANT_BUFFER); + result = data->d3dDevice->CreateBuffer( + &constantBufferDesc, + nullptr, + &data->vertexShaderConstants + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateBuffer [vertex shader constants]", result); + return result; + } + + // + // Make sure that the vertex buffer, if already created, gets freed. + // It will be recreated later. + // + data->vertexBuffer = nullptr; + + // + // Create samplers to use when drawing textures: + // + D3D11_SAMPLER_DESC samplerDesc; + samplerDesc.Filter = SDL_D3D11_NEAREST_PIXEL_FILTER; + 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->nearestPixelSampler + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateSamplerState [nearest-pixel filter]", result); + return result; + } + + samplerDesc.Filter = SDL_D3D11_LINEAR_FILTER; + result = data->d3dDevice->CreateSamplerState( + &samplerDesc, + &data->linearSampler + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateSamplerState [linear filter]", result); + return result; + } + + // + // Setup Direct3D rasterizer states + // + 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__ ", ID3D11Device1::CreateRasterizerState [main rasterizer]", result); + return result; + } + + rasterDesc.ScissorEnable = true; + result = data->d3dDevice->CreateRasterizerState(&rasterDesc, &data->clippedRasterizer); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateRasterizerState [clipped rasterizer]", result); + return result; + } + + // + // Create blending states: + // + result = D3D11_CreateBlendMode( + renderer, + TRUE, + D3D11_BLEND_SRC_ALPHA, /* srcBlend */ + D3D11_BLEND_INV_SRC_ALPHA, /* destBlend */ + D3D11_BLEND_ONE, /* srcBlendAlpha */ + D3D11_BLEND_INV_SRC_ALPHA, /* destBlendAlpha */ + &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, /* srcBlend */ + D3D11_BLEND_ONE, /* destBlend */ + D3D11_BLEND_ZERO, /* srcBlendAlpha */ + D3D11_BLEND_ONE, /* destBlendAlpha */ + &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, /* srcBlend */ + D3D11_BLEND_SRC_COLOR, /* destBlend */ + D3D11_BLEND_ZERO, /* srcBlendAlpha */ + D3D11_BLEND_ONE, /* destBlendAlpha */ + &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_WINRT) { + 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 + +#if WINAPI_FAMILY == WINAPI_FAMILY_APP +// TODO, WinRT, XAML: get the ISwapChainBackgroundPanelNative from something other than a global var +extern ISwapChainBackgroundPanelNative * WINRT_GlobalSwapChainBackgroundPanelNative; +#endif + +static DXGI_MODE_ROTATION +D3D11_GetRotationForOrientation(Windows::Graphics::Display::DisplayOrientations orientation) +{ + switch (orientation) + { +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + // + // Windows Phone rotations + // + case DisplayOrientations::Landscape: + return DXGI_MODE_ROTATION_ROTATE90; + case DisplayOrientations::Portrait: + return DXGI_MODE_ROTATION_IDENTITY; + case DisplayOrientations::LandscapeFlipped: + return DXGI_MODE_ROTATION_ROTATE270; + case DisplayOrientations::PortraitFlipped: + return DXGI_MODE_ROTATION_ROTATE180; +#else + // + // Non-Windows-Phone rotations (ex: Windows 8, Windows RT) + // + case DisplayOrientations::Landscape: + return DXGI_MODE_ROTATION_IDENTITY; + case DisplayOrientations::Portrait: + return DXGI_MODE_ROTATION_ROTATE270; + case DisplayOrientations::LandscapeFlipped: + return DXGI_MODE_ROTATION_ROTATE180; + case DisplayOrientations::PortraitFlipped: + return DXGI_MODE_ROTATION_ROTATE90; +#endif // WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + + default: + return DXGI_MODE_ROTATION_UNSPECIFIED; + } +} + +static bool +D3D11_IsDisplayRotated90Degrees(Windows::Graphics::Display::DisplayOrientations orientation) +{ + switch (D3D11_GetRotationForOrientation(orientation)) { + case DXGI_MODE_ROTATION_ROTATE90: + case DXGI_MODE_ROTATION_ROTATE270: + return true; + default: + return false; + } +} + +static int +D3D11_GetViewportAlignedD3DRect(SDL_Renderer * renderer, const SDL_Rect * sdlRect, D3D11_RECT * outRect) +{ + D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; + switch (D3D11_GetRotationForOrientation(data-> orientation)) { + case DXGI_MODE_ROTATION_IDENTITY: + outRect->left = sdlRect->x; + outRect->right = sdlRect->x + sdlRect->w; + outRect->top = sdlRect->y; + outRect->bottom = sdlRect->y + sdlRect->h; + break; + case DXGI_MODE_ROTATION_ROTATE270: + outRect->left = sdlRect->y; + outRect->right = sdlRect->y + sdlRect->h; + outRect->top = renderer->viewport.w - sdlRect->x - sdlRect->w; + outRect->bottom = renderer->viewport.w - sdlRect->x; + break; + case DXGI_MODE_ROTATION_ROTATE180: + outRect->left = renderer->viewport.w - sdlRect->x - sdlRect->w; + outRect->right = renderer->viewport.w - sdlRect->x; + outRect->top = renderer->viewport.h - sdlRect->y - sdlRect->h; + outRect->bottom = renderer->viewport.h - sdlRect->y; + break; + case DXGI_MODE_ROTATION_ROTATE90: + outRect->left = renderer->viewport.h - sdlRect->y - sdlRect->h; + outRect->right = renderer->viewport.h - sdlRect->y; + outRect->top = sdlRect->x; + outRect->bottom = sdlRect->x + sdlRect->h; + break; + default: + return SDL_SetError("The physical display is in an unknown or unsupported orientation"); + } + return 0; +} + + +// Initialize all resources that change when the window's size changes. +// TODO, WinRT: 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 nativeWindowBounds; + if (coreWindow) { + result = coreWindow->get_Bounds(&nativeWindowBounds); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__", ICoreWindow::get_Bounds [get native-window bounds]", result); + return result; + } + } else { + // TODO, WinRT, XAML: clean up window-bounds code in D3D11_CreateWindowSizeDependentResources + SDL_DisplayMode displayMode; + if (SDL_GetDesktopDisplayMode(0, &displayMode) < 0) { + SDL_SetError(__FUNCTION__", Get Window Bounds (XAML): Unable to retrieve the native window's size"); + return E_FAIL; + } + + nativeWindowBounds.Width = (FLOAT) displayMode.w; + nativeWindowBounds.Height = (FLOAT) displayMode.h; + } + + // TODO, WinRT, XAML: see if window/control sizes are in DIPs, or something else. If something else, then adjust renderer size tracking accordingly. + data->windowSizeInDIPs.x = nativeWindowBounds.Width; + data->windowSizeInDIPs.y = nativeWindowBounds.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; + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + const bool swapDimensions = false; +#else + const bool swapDimensions = D3D11_IsDisplayRotated90Degrees(data->orientation); +#endif + 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__ ", IDXGISwapChain1::ResizeBuffers", result); + return result; + } + } + else + { + const bool usingXAML = (coreWindow == nullptr); + + // 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 + if (usingXAML) { + swapChainDesc.Scaling = DXGI_SCALING_STRETCH; + } 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__ ", ID3D11Device1 to IDXGIDevice1", result); + return result; + } + + ComPtr dxgiAdapter; + result = dxgiDevice->GetAdapter(&dxgiAdapter); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIDevice1::GetAdapter", result); + return result; + } + + ComPtr dxgiFactory; + result = dxgiAdapter->GetParent( + __uuidof(IDXGIFactory2), + &dxgiFactory + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIAdapter::GetParent", result); + return result; + } + + if (usingXAML) { + result = dxgiFactory->CreateSwapChainForComposition( + data->d3dDevice.Get(), + &swapChainDesc, + nullptr, + &data->swapChain); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGIFactory2::CreateSwapChainForComposition", result); + return result; + } + +#if WINAPI_FAMILY == WINAPI_FAMILY_APP + result = WINRT_GlobalSwapChainBackgroundPanelNative->SetSwapChain(data->swapChain.Get()); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ISwapChainBackgroundPanelNative::SetSwapChain", result); + return result; + } +#else + SDL_SetError(__FUNCTION__ ", XAML support is not yet available for Windows Phone"); + return E_FAIL; +#endif + } else { + IUnknown * coreWindowAsIUnknown = nullptr; + result = coreWindow->QueryInterface(&coreWindowAsIUnknown); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ICoreWindow 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__ ", IDXGIFactory2::CreateSwapChainForCoreWindow", 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__ ", IDXGIDevice1::SetMaximumFrameLatency", result); + return result; + } + } + +#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP + // Set the proper orientation for the swap chain, and generate the + // 3D matrix transformation for rendering to the rotated swap chain. + // + // To note, the call for this, IDXGISwapChain1::SetRotation, is not necessary + // on Windows Phone, nor is it supported there. It's only needed in Windows 8/RT. + DXGI_MODE_ROTATION rotation = D3D11_GetRotationForOrientation(data->orientation); + result = data->swapChain->SetRotation(rotation); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", IDXGISwapChain1::SetRotation" , 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__ ", IDXGISwapChain1::GetBuffer [back-buffer]", result); + return result; + } + + result = data->d3dDevice->CreateRenderTargetView( + backBuffer.Get(), + nullptr, + &data->mainRenderTargetView + ); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device1::CreateRenderTargetView", 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__ ", ICoreWindow::get_Bounds [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)) { + /* D3D11_CreateWindowSizeDependentResources will set the SDL error */ + 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)) { + /* D3D11_CreateDeviceResources will set the SDL error */ + return result; + } + + result = D3D11_UpdateForWindowSizeChange(renderer); + if (FAILED(result)) { + /* D3D11_UpdateForWindowSizeChange will set the SDL error */ + 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_SIZE_CHANGED) { + D3D11_UpdateForWindowSizeChange(renderer); + } +} + +static D3D11_FILTER +GetScaleQuality(void) +{ + const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY); + if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) { + return SDL_D3D11_NEAREST_PIXEL_FILTER; + } else /* if (*hint == '1' || SDL_strcasecmp(hint, "linear") == 0) */ { + return SDL_D3D11_LINEAR_FILTER; + } +} + +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) { + return SDL_SetError("%s, An unsupported SDL pixel format (0x%x) was specified", + __FUNCTION__, texture->format); + } + + textureData = new D3D11_TextureData; + if (!textureData) { + SDL_OutOfMemory(); + return -1; + } + textureData->pixelFormat = SDL_AllocFormat(texture->format); + textureData->lockedTexturePosition = XMINT2(0, 0); + textureData->scaleMode = GetScaleQuality(); + + 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__ ", ID3D11Device1::CreateTexture2D", 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__ ", ID3D11Device1::CreateRenderTargetView", 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__ "ID3D11Device1::CreateShaderResourceView", 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(); + return SDL_SetError(errorMessage.c_str()); + } + + // 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) { + return SDL_SetError("texture is already locked"); + } + + // 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. + // + // TODO, WinRT: consider avoiding the use of a staging texture in D3D11_LockTexture if/when the entire texture is being updated + 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__ ", ID3D11Device1::CreateTexture2D [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__ ", ID3D11DeviceContext1::Map [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) { + return SDL_SetError("specified texture is not a render target"); + } + + 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; + } + + // Make sure the SDL viewport gets rotated to that of the physical display's orientation. + // Keep in mind here that the Y-axis will be been inverted (from Direct3D's + // default coordinate system) so rotations will be done in the opposite + // direction of the DXGI_MODE_ROTATION enumeration. + DirectX::XMMATRIX projection; + switch (D3D11_GetRotationForOrientation(data->orientation)) + { + case DXGI_MODE_ROTATION_IDENTITY: + projection = XMMatrixIdentity(); + break; + case DXGI_MODE_ROTATION_ROTATE270: + projection = XMMatrixRotationZ(XM_PIDIV2); + break; + case DXGI_MODE_ROTATION_ROTATE180: + projection = XMMatrixRotationZ(XM_PI); + break; + case DXGI_MODE_ROTATION_ROTATE90: + projection = XMMatrixRotationZ(-XM_PIDIV2); + break; + default: + return SDL_SetError("An unknown DisplayOrientation is being used"); + } + + // + // Update the view matrix + // + float viewportWidth = (float) renderer->viewport.w; + float viewportHeight = (float) renderer->viewport.h; + DirectX::XMMATRIX view = XMMatrixMultiply( + XMMatrixScaling(2.0f / viewportWidth, 2.0f / viewportHeight, 1.0f), + XMMatrixMultiply( + XMMatrixTranslation(-1, -1, 0), + XMMatrixRotationX(XM_PI) + )); + + // + // Combine the projection + view matrix together now, as both only get + // set here (as of this writing, on Dec 26, 2013). When done, store it + // for eventual transfer to the GPU. + // + XMStoreFloat4x4(&data->vertexShaderConstantsData.projectionAndView, + XMMatrixMultiply( + view, + projection)); + + // + // 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 either + // a landscape mode, for all Windows 8/RT devices, or a portrait mode, + // for Windows Phone devices. + // + SDL_FRect orientationAlignedViewport; + const bool swapDimensions = D3D11_IsDisplayRotated90Degrees(data->orientation); + 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; + } + // TODO, WinRT: 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 int +D3D11_UpdateClipRect(SDL_Renderer * renderer) +{ + D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; + const SDL_Rect *rect = &renderer->clip_rect; + + if (SDL_RectEmpty(rect)) { + data->d3dContext->RSSetScissorRects(0, 0); + } else { + D3D11_RECT scissorRect; + if (D3D11_GetViewportAlignedD3DRect(renderer, rect, &scissorRect) != 0) { + /* D3D11_GetViewportAlignedD3DRect will have set the SDL error */ + return -1; + } + data->d3dContext->RSSetScissorRects(1, &scissorRect); + } + + 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, size_t 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) { + D3D11_MAPPED_SUBRESOURCE mappedResource; + ZeroMemory(&mappedResource, sizeof(D3D11_MAPPED_SUBRESOURCE)); + result = rendererData->d3dContext->Map(rendererData->vertexBuffer.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource); + if (FAILED(result)) { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11DeviceContext1::Map [vertex buffer]", result); + return -1; + } + memcpy(mappedResource.pData, vertexData, dataSizeInBytes); + rendererData->d3dContext->Unmap(rendererData->vertexBuffer.Get(), 0); + } else { + vertexBufferDesc.ByteWidth = dataSizeInBytes; + vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC; + vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; + vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; + + 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__ ", ID3D11Device1::CreateBuffer [vertex buffer]", 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()); + if (SDL_RectEmpty(&(renderer->clip_rect))) { + rendererData->d3dContext->RSSetState(rendererData->mainRasterizer.Get()); + } else { + rendererData->d3dContext->RSSetState(rendererData->clippedRasterizer.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); + + VertexPositionColor * vertices = SDL_stack_alloc(VertexPositionColor, count); + for (int i = 0; i < min(count, 128); ++i) { + const VertexPositionColor v = {XMFLOAT3(points[i].x, points[i].y, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)}; + vertices[i] = v; + } + + D3D11_RenderStartDrawOp(renderer); + D3D11_RenderSetBlendMode(renderer, renderer->blendMode); + if (D3D11_UpdateVertexBuffer(renderer, vertices, (unsigned int)count * sizeof(VertexPositionColor)) != 0) { + SDL_stack_free(vertices); + return -1; + } + + D3D11_SetPixelShader( + renderer, + rendererData->colorPixelShader.Get(), + nullptr, + nullptr); + + D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, count); + SDL_stack_free(vertices); + 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); + + VertexPositionColor * vertices = SDL_stack_alloc(VertexPositionColor, count); + for (int i = 0; i < count; ++i) { + const VertexPositionColor v = {XMFLOAT3(points[i].x, points[i].y, 0.0f), XMFLOAT2(0.0f, 0.0f), XMFLOAT4(r, g, b, a)}; + vertices[i] = v; + } + + D3D11_RenderStartDrawOp(renderer); + D3D11_RenderSetBlendMode(renderer, renderer->blendMode); + if (D3D11_UpdateVertexBuffer(renderer, vertices, (unsigned int)count * sizeof(VertexPositionColor)) != 0) { + SDL_stack_free(vertices); + return -1; + } + + D3D11_SetPixelShader( + renderer, + rendererData->colorPixelShader.Get(), + nullptr, + nullptr); + + D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, count); + SDL_stack_free(vertices); + 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 ID3D11SamplerState * +D3D11_RenderGetSampler(SDL_Renderer * renderer, SDL_Texture * texture) +{ + D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; + D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata; + + switch (textureData->scaleMode) { + case SDL_D3D11_NEAREST_PIXEL_FILTER: + return rendererData->nearestPixelSampler.Get(); + case SDL_D3D11_LINEAR_FILTER: + return rendererData->linearSampler.Get(); + default: + return NULL; + } +} + +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; + } + + ID3D11SamplerState *textureSampler = D3D11_RenderGetSampler(renderer, texture); + D3D11_SetPixelShader( + renderer, + rendererData->texturePixelShader.Get(), + textureData->mainTextureResourceView.Get(), + textureSampler); + + 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; + } + + ID3D11SamplerState *textureSampler = D3D11_RenderGetSampler(renderer, texture); + D3D11_SetPixelShader( + renderer, + rendererData->texturePixelShader.Get(), + textureData->mainTextureResourceView.Get(), + textureSampler); + + 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__ ", IDXGISwapChain1::GetBuffer [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__ ", ID3D11Device1::CreateTexture2D [create staging texture]", result); + return -1; + } + + // Copy the desired portion of the back buffer to the staging texture: + D3D11_RECT srcRect; + if (D3D11_GetViewportAlignedD3DRect(renderer, rect, &srcRect) != 0) { + /* D3D11_GetViewportAlignedD3DRect will have set the SDL error */ + return -1; + } + + D3D11_BOX srcBox; + srcBox.left = srcRect.left; + srcBox.right = srcRect.right; + srcBox.top = srcRect.top; + srcBox.bottom = srcRect.bottom; + 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__ ", ID3D11DeviceContext1::Map [map staging texture]", 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(); + return SDL_SetError(errorMessage.c_str()); + } + + // 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)) { + /* D3D11_HandleDeviceLost will set the SDL error */ + } + } + else + { + WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11DeviceContext1::DiscardView", hr); + } +} + +#endif /* SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/render/opengles2/SDL_render_gles2.c b/src/render/opengles2/SDL_render_gles2.c index f2fa8fa9f..60a8fe73b 100644 --- a/src/render/opengles2/SDL_render_gles2.c +++ b/src/render/opengles2/SDL_render_gles2.c @@ -1805,6 +1805,14 @@ GLES2_CreateRenderer(SDL_Window *window, Uint32 flags) return NULL; } +#if __WINRT__ + /* DLudwig, 2013-11-29: ANGLE for WinRT doesn't seem to work unless VSync + * is turned on. Not doing so will freeze the screen's contents to that + * of the first drawn frame. + */ + flags |= SDL_RENDERER_PRESENTVSYNC; +#endif + if (flags & SDL_RENDERER_PRESENTVSYNC) { SDL_GL_SetSwapInterval(1); } else { diff --git a/src/stdlib/SDL_stdlib.c b/src/stdlib/SDL_stdlib.c index 7c2e0d57a..11f778a37 100644 --- a/src/stdlib/SDL_stdlib.c +++ b/src/stdlib/SDL_stdlib.c @@ -102,6 +102,8 @@ SDL_copysign(double x, double y) { #if defined(HAVE_COPYSIGN) return copysign(x, y); +#elif defined(HAVE__COPYSIGN) + return _copysign(x, y); #else return SDL_uclibc_copysign(x, y); #endif /* HAVE_COPYSIGN */ @@ -172,6 +174,8 @@ SDL_scalbn(double x, int n) { #if defined(HAVE_SCALBN) return scalbn(x, n); +#elif defined(HAVE__SCALB) + return _scalb(x, n); #else return SDL_uclibc_scalbn(x, n); #endif /* HAVE_SCALBN */ diff --git a/src/thread/SDL_thread_c.h b/src/thread/SDL_thread_c.h index 011d9ba07..85ef5cce2 100644 --- a/src/thread/SDL_thread_c.h +++ b/src/thread/SDL_thread_c.h @@ -34,6 +34,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..a355607a1 --- /dev/null +++ b/src/thread/stdcpp/SDL_syscond.cpp @@ -0,0 +1,164 @@ +/* + 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::system_error & ex) { + SDL_SetError("unable to create a C++ condition variable: code=%d; %s", ex.code(), ex.what()); + return NULL; + } catch (std::bad_alloc &) { + SDL_OutOfMemory(); + return NULL; + } +} + +/* Destroy a condition variable */ +extern "C" +void +SDL_DestroyCond(SDL_cond * cond) +{ + if (cond) { + delete cond; + } +} + +/* 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; + } + + cond->cpp_cond.notify_one(); + return 0; +} + +/* 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; + } + + cond->cpp_cond.notify_all(); + return 0; +} + +/* 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::system_error & ex) { + SDL_SetError("unable to wait on a C++ condition variable: code=%d; %s", ex.code(), ex.what()); + 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..f5283e4a5 --- /dev/null +++ b/src/thread/stdcpp/SDL_sysmutex.cpp @@ -0,0 +1,96 @@ +/* + 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::system_error & ex) { + SDL_SetError("unable to create a C++ mutex: code=%d; %s", ex.code(), ex.what()); + return NULL; + } catch (std::bad_alloc &) { + SDL_OutOfMemory(); + return NULL; + } +} + +/* Free the mutex */ +extern "C" +void +SDL_DestroyMutex(SDL_mutex * mutex) +{ + if (mutex) { + delete mutex; + } +} + +/* Lock the semaphore */ +extern "C" +int +SDL_mutexP(SDL_mutex * mutex) +{ + if (mutex == NULL) { + SDL_SetError("Passed a NULL mutex"); + return -1; + } + + try { + mutex->cpp_mutex.lock(); + return 0; + } catch (std::system_error & ex) { + SDL_SetError("unable to lock a C++ mutex: code=%d; %s", ex.code(), ex.what()); + return -1; + } +} + +/* Unlock the mutex */ +extern "C" +int +SDL_mutexV(SDL_mutex * mutex) +{ + if (mutex == NULL) { + SDL_SetError("Passed a NULL mutex"); + return -1; + } + + mutex->cpp_mutex.unlock(); + return 0; +} + +/* 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..24df914c7 --- /dev/null +++ b/src/thread/stdcpp/SDL_systhread.cpp @@ -0,0 +1,167 @@ +/* + 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_thread_c.h" +#include "../SDL_systhread.h" +#include "SDL_log.h" +} + +#include +#include +#include + +#ifdef __WINRT__ +#include +#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::system_error & ex) { + SDL_SetError("unable to start a C++ thread: code=%d; %s", ex.code(), ex.what()); + return -1; + } catch (std::bad_alloc &) { + SDL_OutOfMemory(); + 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) +{ +#ifdef __WINRT__ + return GetCurrentThreadId(); +#else + // HACK: Mimick a thread ID, if one isn't otherwise available. + 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; +#endif +} + +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. + // + // WinRT: UPDATE (Aug 20, 2013): thread priorities cannot be changed + // on WinRT, at least not for any thread that's already been created. + // WinRT threads appear to be based off of the WinRT class, + // ThreadPool, more info on which can be found at: + // http://msdn.microsoft.com/en-us/library/windows/apps/windows.system.threading.threadpool.aspx + // + // For compatibility sake, 0 will be returned here. + 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 (std::system_error &) { + // An error occurred when joining the thread. SDL_WaitThread does not, + // however, seem to provide a means to report errors to its callers + // though! + } +} + +extern "C" +void +SDL_SYS_DetachThread(SDL_Thread * thread) +{ + if ( ! thread) { + return; + } + + try { + std::thread * cpp_thread = (std::thread *) thread->handle; + if (cpp_thread->joinable()) { + cpp_thread->detach(); + } + } catch (std::system_error &) { + // An error occurred when detaching the thread. SDL_DetachThread does not, + // however, seem to provide a means to report errors to its callers + // though! + } +} + +extern "C" +SDL_TLSData * +SDL_SYS_GetTLSData() +{ + return SDL_Generic_GetTLSData(); +} + +extern "C" +int +SDL_SYS_SetTLSData(SDL_TLSData *data) +{ + return SDL_Generic_SetTLSData(data); +} + +/* 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/timer/windows/SDL_systimer.c b/src/timer/windows/SDL_systimer.c index 186233a8e..07561636a 100644 --- a/src/timer/windows/SDL_systimer.c +++ b/src/timer/windows/SDL_systimer.c @@ -41,6 +41,7 @@ static LARGE_INTEGER hires_start_ticks; /* The number of ticks per second of the high-resolution performance counter */ static LARGE_INTEGER hires_ticks_per_second; +#ifndef __WINRT__ static void timeSetPeriod(UINT uPeriod) { @@ -74,6 +75,7 @@ SDL_TimerResolutionChanged(void *userdata, const char *name, const char *oldValu timeSetPeriod(uPeriod); } } +#endif /* ifndef __WINRT__ */ #endif /* !USE_GETTICKCOUNT */ @@ -97,13 +99,17 @@ SDL_TicksInit(void) QueryPerformanceCounter(&hires_start_ticks); } else { hires_timer_available = FALSE; +#ifdef __WINRT__ + start = 0; /* the timer failed to start! */ +#else timeSetPeriod(1); /* use 1 ms timer precision */ start = timeGetTime(); SDL_AddHintCallback(SDL_HINT_TIMER_RESOLUTION, SDL_TimerResolutionChanged, NULL); +#endif /* __WINRT__ */ } -#endif +#endif /* USE_GETTICKCOUNT */ } void @@ -111,12 +117,14 @@ SDL_TicksQuit(void) { #ifndef USE_GETTICKCOUNT if (!hires_timer_available) { +#ifndef __WINRT__ SDL_DelHintCallback(SDL_HINT_TIMER_RESOLUTION, SDL_TimerResolutionChanged, NULL); timeSetPeriod(0); +#endif /* __WINRT__ */ } -#endif +#endif /* USE_GETTICKCOUNT */ ticks_started = SDL_FALSE; } @@ -145,7 +153,11 @@ SDL_GetTicks(void) return (DWORD) hires_now.QuadPart; } else { +#ifdef __WINRT__ + now = 0; +#else now = timeGetTime(); +#endif /* __WINRT__ */ } #endif @@ -174,6 +186,19 @@ SDL_GetPerformanceFrequency(void) return frequency.QuadPart; } +#ifdef __WINRT__ +static void +Sleep(DWORD timeout) +{ + static HANDLE mutex = 0; + if ( ! mutex ) + { + mutex = CreateEventEx(0, 0, 0, EVENT_ALL_ACCESS); + } + WaitForSingleObjectEx(mutex, timeout, FALSE); +} +#endif + void SDL_Delay(Uint32 ms) { diff --git a/src/video/SDL_egl.c b/src/video/SDL_egl.c index 93e7fd5af..cfba20071 100644 --- a/src/video/SDL_egl.c +++ b/src/video/SDL_egl.c @@ -41,7 +41,7 @@ #define DEFAULT_OGL_ES_PVR "libGLES_CM.so" #define DEFAULT_OGL_ES "libGLESv1_CM.so" -#elif SDL_VIDEO_DRIVER_WINDOWS +#elif SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT /* EGL AND OpenGL ES support via ANGLE */ #define DEFAULT_EGL "libEGL.dll" #define DEFAULT_OGL_ES2 "libGLESv2.dll" @@ -119,7 +119,7 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa { void *dll_handle = NULL, *egl_dll_handle = NULL; /* The naming is counter intuitive, but hey, I just work here -- Gabriel */ char *path = NULL; -#if SDL_VIDEO_DRIVER_WINDOWS +#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT const char *d3dcompiler; #endif @@ -132,7 +132,7 @@ SDL_EGL_LoadLibrary(_THIS, const char *egl_path, NativeDisplayType native_displa return SDL_OutOfMemory(); } -#if SDL_VIDEO_DRIVER_WINDOWS +#if SDL_VIDEO_DRIVER_WINDOWS || SDL_VIDEO_DRIVER_WINRT d3dcompiler = SDL_GetHint(SDL_HINT_VIDEO_WIN_D3DCOMPILER); if (!d3dcompiler) { /* By default we load the Vista+ compatible compiler */ diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index 3ff352a1a..32b5d77a2 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -354,6 +354,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_HAIKU extern VideoBootStrap HAIKU_bootstrap; #endif diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 7426e2f49..722fdf4f8 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -68,6 +68,9 @@ static VideoBootStrap *bootstrap[] = { #if SDL_VIDEO_DRIVER_WINDOWS &WINDOWS_bootstrap, #endif +#if SDL_VIDEO_DRIVER_WINRT + &WINRT_bootstrap, +#endif #if SDL_VIDEO_DRIVER_HAIKU &HAIKU_bootstrap, #endif diff --git a/src/video/winrt/SDL_winrtevents.cpp b/src/video/winrt/SDL_winrtevents.cpp new file mode 100644 index 000000000..112c3d494 --- /dev/null +++ b/src/video/winrt/SDL_winrtevents.cpp @@ -0,0 +1,153 @@ +/* + 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 + +/* + * Windows includes: + */ +#include +using namespace Windows::UI::Core; +using Windows::UI::Core::CoreCursor; + +/* + * SDL includes: + */ +#include "SDL_winrtevents_c.h" +#include "../../core/winrt/SDL_winrtapp_common.h" +#include "../../core/winrt/SDL_winrtapp_direct3d.h" +#include "../../core/winrt/SDL_winrtapp_xaml.h" +#include "SDL_assert.h" +#include "SDL_system.h" + +extern "C" { +#include "../SDL_sysvideo.h" +#include "../../events/SDL_events_c.h" +} + + +/* Forward declarations */ +static void WINRT_YieldXAMLThread(); + + +/* Global event management */ + +void +WINRT_PumpEvents(_THIS) +{ + if (SDL_WinRTGlobalApp) { + SDL_WinRTGlobalApp->PumpEvents(); + } else if (WINRT_XAMLWasEnabled) { + WINRT_YieldXAMLThread(); + } +} + + +/* XAML Thread management */ + +enum SDL_XAMLAppThreadState +{ + ThreadState_NotLaunched = 0, + ThreadState_Running, + ThreadState_Yielding +}; + +static SDL_XAMLAppThreadState _threadState = ThreadState_NotLaunched; +static SDL_Thread * _XAMLThread = nullptr; +static SDL_mutex * _mutex = nullptr; +static SDL_cond * _cond = nullptr; + +static void +WINRT_YieldXAMLThread() +{ + SDL_LockMutex(_mutex); + SDL_assert(_threadState == ThreadState_Running); + _threadState = ThreadState_Yielding; + SDL_UnlockMutex(_mutex); + + SDL_CondSignal(_cond); + + SDL_LockMutex(_mutex); + while (_threadState != ThreadState_Running) { + SDL_CondWait(_cond, _mutex); + } + SDL_UnlockMutex(_mutex); +} + +static int +WINRT_XAMLThreadMain(void * userdata) +{ + // TODO, WinRT: pass the C-style main() a reasonably realistic + // representation of command line arguments. + int argc = 0; + char **argv = NULL; + return WINRT_SDLAppEntryPoint(argc, argv); +} + +void +WINRT_CycleXAMLThread() +{ + switch (_threadState) { + case ThreadState_NotLaunched: + { + _cond = SDL_CreateCond(); + + _mutex = SDL_CreateMutex(); + _threadState = ThreadState_Running; + _XAMLThread = SDL_CreateThread(WINRT_XAMLThreadMain, "SDL/XAML App Thread", nullptr); + + SDL_LockMutex(_mutex); + while (_threadState != ThreadState_Yielding) { + SDL_CondWait(_cond, _mutex); + } + SDL_UnlockMutex(_mutex); + + break; + } + + case ThreadState_Running: + { + SDL_assert(false); + break; + } + + case ThreadState_Yielding: + { + SDL_LockMutex(_mutex); + SDL_assert(_threadState == ThreadState_Yielding); + _threadState = ThreadState_Running; + SDL_UnlockMutex(_mutex); + + SDL_CondSignal(_cond); + + SDL_LockMutex(_mutex); + while (_threadState != ThreadState_Yielding) { + SDL_CondWait(_cond, _mutex); + } + SDL_UnlockMutex(_mutex); + } + } +} + +#endif /* SDL_VIDEO_DRIVER_WINRT */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/winrt/SDL_winrtevents_c.h b/src/video/winrt/SDL_winrtevents_c.h new file mode 100644 index 000000000..ba5105f3f --- /dev/null +++ b/src/video/winrt/SDL_winrtevents_c.h @@ -0,0 +1,72 @@ +/* + 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_sysvideo.h" +} + +/* + * Internal-use, C-style functions: + */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern void WINRT_InitTouch(_THIS); +extern void WINRT_PumpEvents(_THIS); + +#ifdef __cplusplus +} +#endif + + +/* + * Internal-use, C++/CX functions: + */ +#ifdef __cplusplus_winrt + +/* Pointers (Mice, Touch, etc.) */ +typedef enum { + NormalizeZeroToOne, + TransformToSDLWindowSize +} WINRT_CursorNormalizationType; +extern Windows::Foundation::Point WINRT_TransformCursorPosition(SDL_Window * window, + Windows::Foundation::Point rawPosition, + WINRT_CursorNormalizationType normalization); +extern Uint8 WINRT_GetSDLButtonForPointerPoint(Windows::UI::Input::PointerPoint ^pt); +extern void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint); +extern void WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint); +extern void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint); +extern void WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint); +extern void WINRT_ProcessMouseMovedEvent(SDL_Window * window, Windows::Devices::Input::MouseEventArgs ^args); + +/* Keyboard */ +extern void WINRT_ProcessKeyDownEvent(Windows::UI::Core::KeyEventArgs ^args); +extern void WINRT_ProcessKeyUpEvent(Windows::UI::Core::KeyEventArgs ^args); + +/* XAML Thread Management */ +extern void WINRT_CycleXAMLThread(); + +#endif // ifdef __cplusplus_winrt + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/winrt/SDL_winrtkeyboard.cpp b/src/video/winrt/SDL_winrtkeyboard.cpp new file mode 100644 index 000000000..cb5f57dd7 --- /dev/null +++ b/src/video/winrt/SDL_winrtkeyboard.cpp @@ -0,0 +1,301 @@ +/* + 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_VIDEO_DRIVER_WINRT + +/* Standard C++11 includes */ +#include + + +/* Windows-specific includes */ +#include +#include + + +/* SDL-specific includes */ +#include +#include "SDL_winrtevents_c.h" + +extern "C" { +#include "../../events/scancodes_windows.h" +#include "../../events/SDL_keyboard_c.h" +} + + +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 +WINRT_ProcessKeyDownEvent(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 +WINRT_ProcessKeyUpEvent(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); +} + +#endif // SDL_VIDEO_DRIVER_WINRT diff --git a/src/video/winrt/SDL_winrtmouse.cpp b/src/video/winrt/SDL_winrtmouse.cpp new file mode 100644 index 000000000..3e896f7f0 --- /dev/null +++ b/src/video/winrt/SDL_winrtmouse.cpp @@ -0,0 +1,166 @@ +/* + 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 + +/* + * Windows includes: + */ +#include +using namespace Windows::UI::Core; +using Windows::UI::Core::CoreCursor; + +/* + * SDL includes: + */ +extern "C" { +#include "SDL_assert.h" +#include "../../events/SDL_mouse_c.h" +#include "../../events/SDL_touch_c.h" +#include "../SDL_sysvideo.h" +#include "SDL_events.h" +#include "SDL_log.h" +} + +#include "../../core/winrt/SDL_winrtapp_direct3d.h" +#include "SDL_winrtvideo_cpp.h" +#include "SDL_winrtmouse_c.h" + + +extern "C" SDL_bool WINRT_UsingRelativeMouseMode = SDL_FALSE; + + +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) +{ + // TODO, WinRT, XAML: make WINRT_ShowCursor work when XAML support is enabled. + if ( ! CoreWindow::GetForCurrentThread()) { + return 0; + } + + 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) +{ + WINRT_UsingRelativeMouseMode = enabled; + return 0; +} + +void +WINRT_InitMouse(_THIS) +{ + SDL_Mouse *mouse = SDL_GetMouse(); + + /* DLudwig, Dec 3, 2012: WinRT 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/winrt/SDL_winrtmouse_c.h b/src/video/winrt/SDL_winrtmouse_c.h new file mode 100644 index 000000000..24c6e015e --- /dev/null +++ b/src/video/winrt/SDL_winrtmouse_c.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_winrtmouse_h +#define _SDL_winrtmouse_h + +#ifdef __cplusplus +extern "C" { +#endif + +extern void WINRT_InitMouse(_THIS); +extern void WINRT_QuitMouse(_THIS); +extern SDL_bool WINRT_UsingRelativeMouseMode; + +#ifdef __cplusplus +} +#endif + +#endif /* _SDL_windowsmouse_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/winrt/SDL_winrtopengles.cpp b/src/video/winrt/SDL_winrtopengles.cpp new file mode 100644 index 000000000..1229eb9bf --- /dev/null +++ b/src/video/winrt/SDL_winrtopengles.cpp @@ -0,0 +1,50 @@ +/* + 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" + +// TODO: WinRT, make this file compile via C code + +#if SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL + +/* EGL implementation of SDL OpenGL support */ + +#include "SDL_winrtvideo_cpp.h" +extern "C" { +#include "SDL_winrtopengles.h" +} + +#define EGL_D3D11_ONLY_DISPLAY_ANGLE ((NativeDisplayType) -3) + +extern "C" int +WINRT_GLES_LoadLibrary(_THIS, const char *path) { + return SDL_EGL_LoadLibrary(_this, path, EGL_D3D11_ONLY_DISPLAY_ANGLE); +} + +extern "C" { +SDL_EGL_CreateContext_impl(WINRT) +SDL_EGL_SwapWindow_impl(WINRT) +SDL_EGL_MakeCurrent_impl(WINRT) +} + +#endif /* SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL */ + +/* vi: set ts=4 sw=4 expandtab: */ + diff --git a/src/video/winrt/SDL_winrtopengles.h b/src/video/winrt/SDL_winrtopengles.h new file mode 100644 index 000000000..193e0333f --- /dev/null +++ b/src/video/winrt/SDL_winrtopengles.h @@ -0,0 +1,48 @@ +/* + 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" + +#ifndef _SDL_winrtopengles_h +#define _SDL_winrtopengles_h + +#if SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL + +#include "../SDL_sysvideo.h" +#include "../SDL_egl_c.h" + +/* OpenGLES functions */ +#define WINRT_GLES_GetAttribute SDL_EGL_GetAttribute +#define WINRT_GLES_GetProcAddress SDL_EGL_GetProcAddress +#define WINRT_GLES_UnloadLibrary SDL_EGL_UnloadLibrary +#define WINRT_GLES_SetSwapInterval SDL_EGL_SetSwapInterval +#define WINRT_GLES_GetSwapInterval SDL_EGL_GetSwapInterval +#define WINRT_GLES_DeleteContext SDL_EGL_DeleteContext + +extern int WINRT_GLES_LoadLibrary(_THIS, const char *path); +extern SDL_GLContext WINRT_GLES_CreateContext(_THIS, SDL_Window * window); +extern void WINRT_GLES_SwapWindow(_THIS, SDL_Window * window); +extern int WINRT_GLES_MakeCurrent(_THIS, SDL_Window * window, SDL_GLContext context); + +#endif /* SDL_VIDEO_DRIVER_WINRT && SDL_VIDEO_OPENGL_EGL */ + +#endif /* _SDL_winrtopengles_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/winrt/SDL_winrtpointerinput.cpp b/src/video/winrt/SDL_winrtpointerinput.cpp new file mode 100644 index 000000000..13dd5b621 --- /dev/null +++ b/src/video/winrt/SDL_winrtpointerinput.cpp @@ -0,0 +1,394 @@ +/* + 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 + +/* SDL includes */ +#include "SDL_winrtevents_c.h" +#include "SDL_winrtmouse_c.h" +#include "SDL_winrtvideo_cpp.h" +#include "SDL_assert.h" +#include "SDL_system.h" + +extern "C" { +#include "../SDL_sysvideo.h" +#include "../../events/SDL_events_c.h" +#include "../../events/SDL_mouse_c.h" +#include "../../events/SDL_touch_c.h" +} + +/* File-specific globals: */ +static SDL_TouchID WINRT_TouchID = 1; +static unsigned int WINRT_LeftFingerDown = 0; + + +void +WINRT_InitTouch(_THIS) +{ + SDL_AddTouch(WINRT_TouchID, ""); +} + + +// +// Applies necessary geometric transformations to raw cursor positions: +// +Windows::Foundation::Point +WINRT_TransformCursorPosition(SDL_Window * window, + Windows::Foundation::Point rawPosition, + WINRT_CursorNormalizationType normalization) +{ + using namespace Windows::UI::Core; + using namespace Windows::Graphics::Display; + + if (!window) { + return rawPosition; + } + + SDL_WindowData * windowData = (SDL_WindowData *) window->driverdata; + if (windowData->coreWindow == nullptr) { + // For some reason, the window isn't associated with a CoreWindow. + // This might end up being the case as XAML support is extended. + // For now, if there's no CoreWindow attached to the SDL_Window, + // don't do any transforms. + + // TODO, WinRT: make sure touch input coordinate ranges are correct when using XAML support + return rawPosition; + } + + // The CoreWindow can only be accessed on certain thread(s). + SDL_assert(CoreWindow::GetForCurrentThread() != nullptr); + + CoreWindow ^ nativeWindow = windowData->coreWindow.Get(); + Windows::Foundation::Point outputPosition; + + // Compute coordinates normalized from 0..1. + // If the coordinates need to be sized to the SDL window, + // we'll do that after. +#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP + outputPosition.X = rawPosition.X / nativeWindow->Bounds.Width; + outputPosition.Y = rawPosition.Y / nativeWindow->Bounds.Height; +#else + switch (DisplayProperties::CurrentOrientation) + { + case DisplayOrientations::Portrait: + outputPosition.X = rawPosition.X / nativeWindow->Bounds.Width; + outputPosition.Y = rawPosition.Y / nativeWindow->Bounds.Height; + break; + case DisplayOrientations::PortraitFlipped: + outputPosition.X = 1.0f - (rawPosition.X / nativeWindow->Bounds.Width); + outputPosition.Y = 1.0f - (rawPosition.Y / nativeWindow->Bounds.Height); + break; + case DisplayOrientations::Landscape: + outputPosition.X = rawPosition.Y / nativeWindow->Bounds.Height; + outputPosition.Y = 1.0f - (rawPosition.X / nativeWindow->Bounds.Width); + break; + case DisplayOrientations::LandscapeFlipped: + outputPosition.X = 1.0f - (rawPosition.Y / nativeWindow->Bounds.Height); + outputPosition.Y = rawPosition.X / nativeWindow->Bounds.Width; + break; + default: + break; + } +#endif + + if (normalization == TransformToSDLWindowSize) { + outputPosition.X *= ((float32) window->w); + outputPosition.Y *= ((float32) window->h); + } + + return outputPosition; +} + +static inline int +_lround(float arg) +{ + if (arg >= 0.0f) { + return (int)floor(arg + 0.5f); + } else { + return (int)ceil(arg - 0.5f); + } +} + +Uint8 +WINRT_GetSDLButtonForPointerPoint(Windows::UI::Input::PointerPoint ^pt) +{ + using namespace Windows::UI::Input; + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + return SDL_BUTTON_LEFT; +#else + 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; + } +#endif + + return 0; +} + +//const char * +//WINRT_ConvertPointerUpdateKindToString(Windows::UI::Input::PointerUpdateKind kind) +//{ +// using namespace Windows::UI::Input; +// +// 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 bool +WINRT_IsTouchEvent(Windows::UI::Input::PointerPoint ^pointerPoint) +{ +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + return true; +#else + using namespace Windows::Devices::Input; + switch (pointerPoint->PointerDevice->PointerDeviceType) { + case PointerDeviceType::Touch: + case PointerDeviceType::Pen: + return true; + default: + return false; + } +#endif +} + +void WINRT_ProcessPointerPressedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) +{ + if (!window) { + return; + } + + Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint); + + if ( ! WINRT_IsTouchEvent(pointerPoint)) { + SDL_SendMouseButton(window, 0, SDL_PRESSED, button); + } else { + Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne); + Windows::Foundation::Point windowPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, TransformToSDLWindowSize); + + if (!WINRT_LeftFingerDown) { + if (button) { + SDL_SendMouseMotion(window, 0, 0, (int)windowPoint.X, (int)windowPoint.Y); + SDL_SendMouseButton(window, 0, SDL_PRESSED, button); + } + + WINRT_LeftFingerDown = pointerPoint->PointerId; + } + + SDL_SendTouch( + WINRT_TouchID, + (SDL_FingerID) pointerPoint->PointerId, + SDL_TRUE, + normalizedPoint.X, + normalizedPoint.Y, + pointerPoint->Properties->Pressure); + } +} + +void +WINRT_ProcessPointerMovedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) +{ + if (!window || WINRT_UsingRelativeMouseMode) { + return; + } + + Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne); + Windows::Foundation::Point windowPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, TransformToSDLWindowSize); + + if ( ! WINRT_IsTouchEvent(pointerPoint)) { + SDL_SendMouseMotion(window, 0, 0, (int)windowPoint.X, (int)windowPoint.Y); + } else if (pointerPoint->PointerId == WINRT_LeftFingerDown) { + if (pointerPoint->PointerId == WINRT_LeftFingerDown) { + SDL_SendMouseMotion(window, 0, 0, (int)windowPoint.X, (int)windowPoint.Y); + } + + SDL_SendTouchMotion( + WINRT_TouchID, + (SDL_FingerID) pointerPoint->PointerId, + normalizedPoint.X, + normalizedPoint.Y, + pointerPoint->Properties->Pressure); + } +} + +void WINRT_ProcessPointerReleasedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) +{ + if (!window) { + return; + } + + Uint8 button = WINRT_GetSDLButtonForPointerPoint(pointerPoint); + + if (!WINRT_IsTouchEvent(pointerPoint)) { + SDL_SendMouseButton(window, 0, SDL_RELEASED, button); + } else { + Windows::Foundation::Point normalizedPoint = WINRT_TransformCursorPosition(window, pointerPoint->Position, NormalizeZeroToOne); + + if (WINRT_LeftFingerDown == pointerPoint->PointerId) { + if (button) { + SDL_SendMouseButton(window, 0, SDL_RELEASED, button); + } + WINRT_LeftFingerDown = 0; + } + + SDL_SendTouch( + WINRT_TouchID, + (SDL_FingerID) pointerPoint->PointerId, + SDL_FALSE, + normalizedPoint.X, + normalizedPoint.Y, + pointerPoint->Properties->Pressure); + } +} + +void +WINRT_ProcessPointerWheelChangedEvent(SDL_Window *window, Windows::UI::Input::PointerPoint ^pointerPoint) +{ + if (!window) { + return; + } + + // FIXME: This may need to accumulate deltas up to WHEEL_DELTA + short motion = pointerPoint->Properties->MouseWheelDelta / WHEEL_DELTA; + SDL_SendMouseWheel(window, 0, 0, motion); +} + +void +WINRT_ProcessMouseMovedEvent(SDL_Window * window, Windows::Devices::Input::MouseEventArgs ^args) +{ + if (!window || !WINRT_UsingRelativeMouseMode) { + return; + } + + // 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 WinRT 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 Windows::Foundation::Point mouseDeltaInDIPs((float)args->MouseDelta.X, (float)args->MouseDelta.Y); + const Windows::Foundation::Point mouseDeltaInSDLWindowCoords = WINRT_TransformCursorPosition(window, mouseDeltaInDIPs, TransformToSDLWindowSize); + SDL_SendMouseMotion( + window, + 0, + 1, + _lround(mouseDeltaInSDLWindowCoords.X), + _lround(mouseDeltaInSDLWindowCoords.Y)); +} + +#endif // SDL_VIDEO_DRIVER_WINRT diff --git a/src/video/winrt/SDL_winrtvideo.cpp b/src/video/winrt/SDL_winrtvideo.cpp new file mode 100644 index 000000000..30dffcf08 --- /dev/null +++ b/src/video/winrt/SDL_winrtvideo.cpp @@ -0,0 +1,401 @@ +/* + 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. + */ + +/* Windows includes */ +#include +using namespace Windows::UI::Core; + + +/* SDL includes */ +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_winrtopengles.h" +} + +#include "../../core/winrt/SDL_winrtapp_direct3d.h" +#include "../../core/winrt/SDL_winrtapp_xaml.h" +#include "SDL_winrtvideo_cpp.h" +#include "SDL_winrtevents_c.h" +#include "SDL_winrtmouse_c.h" +#include "SDL_main.h" +#include "SDL_system.h" + + +/* 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); + + +/* SDL-internal globals: */ +SDL_Window * WINRT_GlobalSDLWindow = NULL; +SDL_VideoDevice * WINRT_GlobalSDLVideoDevice = NULL; + + +/* WinRT driver bootstrap functions */ + +static int +WINRT_Available(void) +{ + return (1); +} + +static void +WINRT_DeleteDevice(SDL_VideoDevice * device) +{ + if (device == WINRT_GlobalSDLVideoDevice) { + WINRT_GlobalSDLVideoDevice = 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->GetWindowWMInfo = WINRT_GetWindowWMInfo; +#ifdef SDL_VIDEO_OPENGL_EGL + device->GL_LoadLibrary = WINRT_GLES_LoadLibrary; + device->GL_GetProcAddress = WINRT_GLES_GetProcAddress; + device->GL_UnloadLibrary = WINRT_GLES_UnloadLibrary; + device->GL_CreateContext = WINRT_GLES_CreateContext; + device->GL_MakeCurrent = WINRT_GLES_MakeCurrent; + device->GL_SetSwapInterval = WINRT_GLES_SetSwapInterval; + device->GL_GetSwapInterval = WINRT_GLES_GetSwapInterval; + device->GL_SwapWindow = WINRT_GLES_SwapWindow; + device->GL_DeleteContext = WINRT_GLES_DeleteContext; +#endif + device->free = WINRT_DeleteDevice; + WINRT_GlobalSDLVideoDevice = device; + + return device; +} + +#define WINRTVID_DRIVER_NAME "winrt" +VideoBootStrap WINRT_bootstrap = { + WINRTVID_DRIVER_NAME, "SDL WinRT video driver", + WINRT_Available, WINRT_CreateDevice +}; + +int +WINRT_VideoInit(_THIS) +{ + if (WINRT_InitModes(_this) < 0) { + return -1; + } + WINRT_InitMouse(_this); + WINRT_InitTouch(_this); + + return 0; +} + +int +WINRT_CalcDisplayModeUsingNativeWindow(SDL_DisplayMode * mode) +{ + SDL_DisplayModeData * driverdata; + + using namespace Windows::Graphics::Display; + + // Go no further if a native window cannot be accessed. This can happen, + // for example, if this function is called from certain threads, such as + // the SDL/XAML thread. + if (!CoreWindow::GetForCurrentThread()) { + return SDL_SetError("SDL/WinRT display modes cannot be calculated outside of the main thread, such as in SDL's XAML thread"); + } + + // 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; + const int w = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Width * currentDPI) / dipsPerInch); + const int h = (int) ((CoreWindow::GetForCurrentThread()->Bounds.Height * currentDPI) / dipsPerInch); + if (w == 0 || w == h) { + return SDL_SetError("Unable to calculate the WinRT window/display's size"); + } + + // Create a driverdata field: + driverdata = (SDL_DisplayModeData *) SDL_malloc(sizeof(*driverdata)); + if (!driverdata) { + return SDL_OutOfMemory(); + } + SDL_zerop(driverdata); + + // Fill in most fields: + SDL_zerop(mode); + mode->format = SDL_PIXELFORMAT_RGB888; + mode->refresh_rate = 0; // TODO, WinRT: see if refresh rate data is available, or relevant (for WinRT apps) + mode->w = w; + mode->h = h; + mode->driverdata = driverdata; + driverdata->currentOrientation = DisplayProperties::CurrentOrientation; + +#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP + // On Windows Phone, the native window's size is always in portrait, + // regardless of the device's orientation. This is in contrast to + // Windows 8/RT, which will resize the native window as the device's + // orientation changes. In order to compensate for this behavior, + // on Windows Phone, the mode's width and height will be swapped when + // the device is in a landscape (non-portrait) mode. + switch (DisplayProperties::CurrentOrientation) { + case DisplayOrientations::Landscape: + case DisplayOrientations::LandscapeFlipped: + { + const int tmp = mode->h; + mode->h = mode->w; + mode->w = tmp; + break; + } + + default: + break; + } +#endif + + return 0; +} + +int +WINRT_DuplicateDisplayMode(SDL_DisplayMode * dest, const SDL_DisplayMode * src) +{ + SDL_DisplayModeData * driverdata; + driverdata = (SDL_DisplayModeData *) SDL_malloc(sizeof(*driverdata)); + if (!driverdata) { + return SDL_OutOfMemory(); + } + SDL_memcpy(driverdata, src->driverdata, sizeof(SDL_DisplayModeData)); + SDL_memcpy(dest, src, sizeof(SDL_DisplayMode)); + dest->driverdata = driverdata; + return 0; +} + +int +WINRT_InitModes(_THIS) +{ + // Retrieve the display mode: + SDL_DisplayMode mode, desktop_mode; + if (WINRT_CalcDisplayModeUsingNativeWindow(&mode) != 0) { + return -1; // If WINRT_CalcDisplayModeUsingNativeWindow fails, it'll already have set the SDL error + } + + if (WINRT_DuplicateDisplayMode(&desktop_mode, &mode) != 0) { + return -1; + } + if (SDL_AddBasicVideoDisplay(&desktop_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 (WINRT_GlobalSDLWindow != NULL) { + 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; + + /* To note, when XAML support is enabled, access to the CoreWindow will not + be possible, at least not via the SDL/XAML thread. Attempts to access it + from there will throw exceptions. As such, the SDL_WindowData's + 'coreWindow' field will only be set (to a non-null value) if XAML isn't + enabled. + */ + if (!WINRT_XAMLWasEnabled) { + data->coreWindow = CoreWindow::GetForCurrentThread(); + } + +#if SDL_VIDEO_OPENGL_EGL + /* Setup the EGL surface, but only if OpenGL ES 2 was requested. */ + if (!(window->flags & SDL_WINDOW_OPENGL)) { + /* OpenGL ES 2 wasn't requested. Don't set up an EGL surface. */ + data->egl_surface = EGL_NO_SURFACE; + } else { + /* OpenGL ES 2 was reuqested. Set up an EGL surface. */ + + /* HACK: ANGLE/WinRT currently uses non-pointer, C++ objects to represent + native windows. The object only contains a single pointer to a COM + interface pointer, which on x86 appears to be castable to the object + without apparant problems. On other platforms, notable ARM and x64, + doing so will cause a crash. To avoid this crash, we'll bypass + SDL's normal call to eglCreateWindowSurface, which is invoked from C + code, and call it here, where an appropriate C++ object may be + passed in. + */ + typedef EGLSurface (*eglCreateWindowSurfaceFunction)(EGLDisplay dpy, EGLConfig config, + Microsoft::WRL::ComPtr win, + const EGLint *attrib_list); + eglCreateWindowSurfaceFunction WINRT_eglCreateWindowSurface = + (eglCreateWindowSurfaceFunction) _this->egl_data->eglCreateWindowSurface; + + Microsoft::WRL::ComPtr nativeWindow = reinterpret_cast(data->coreWindow.Get()); + data->egl_surface = WINRT_eglCreateWindowSurface( + _this->egl_data->egl_display, + _this->egl_data->egl_config, + nativeWindow, NULL); + if (data->egl_surface == NULL) { + // TODO, WinRT: see if eglCreateWindowSurface, or its callee(s), sets an error message. If so, attach it to the SDL error. + return SDL_SetError("eglCreateWindowSurface failed"); + } + } +#endif + + /* 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; + +#if SDL_VIDEO_OPENGL_EGL + if (data->egl_surface) { + window->flags |= SDL_WINDOW_OPENGL; + } +#endif + + /* WinRT does not, as of this writing, appear to support app-adjustable + window sizes. Set the window size to whatever the native WinRT + CoreWindow is set at. + + TODO, WinRT: if and when non-fullscreen XAML control support is added to SDL, consider making those resizable via SDL_Window's interfaces. + */ + window->w = _this->displays[0].current_mode.w; + window->h = _this->displays[0].current_mode.h; + + /* For now, treat WinRT apps as if they always have focus. + TODO, WinRT: try tracking keyboard and mouse focus state with respect to snapped apps + */ + SDL_SetMouseFocus(window); + SDL_SetKeyboardFocus(window); + + /* Make sure the WinRT app's IFramworkView can post events on + behalf of SDL: + */ + WINRT_GlobalSDLWindow = window; + + /* All done! */ + return 0; +} + +void +WINRT_DestroyWindow(_THIS, SDL_Window * window) +{ + SDL_WindowData * data = (SDL_WindowData *) window->driverdata; + + if (WINRT_GlobalSDLWindow == window) { + WINRT_GlobalSDLWindow = 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_WINRT; + 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/winrt/SDL_winrtvideo_cpp.h b/src/video/winrt/SDL_winrtvideo_cpp.h new file mode 100644 index 000000000..0a8de6455 --- /dev/null +++ b/src/video/winrt/SDL_winrtvideo_cpp.h @@ -0,0 +1,79 @@ +/* + 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. +*/ + +/* Windows includes: */ +#include +#ifdef __cplusplus_winrt +#include +#endif + +/* SDL includes: */ +#include "SDL_video.h" +#include "SDL_events.h" + +extern "C" { +#include "../SDL_sysvideo.h" +#include "../SDL_egl_c.h" +} + + +/* The global, WinRT, SDL Window. + For now, SDL/WinRT only supports one window (due to platform limitations of + WinRT. +*/ +extern SDL_Window * WINRT_GlobalSDLWindow; + +/* The global, WinRT, video device. */ +extern SDL_VideoDevice * WINRT_GlobalSDLVideoDevice; + +/* Creates a display mode for Plain Direct3D (non-XAML) apps, using the lone, native window's settings. + + Pass in an allocated SDL_DisplayMode field to store the data in. + + This function will return 0 on success, -1 on failure. + + If this function succeeds, be sure to call SDL_free on the + SDL_DisplayMode's driverdata field. +*/ +extern int WINRT_CalcDisplayModeUsingNativeWindow(SDL_DisplayMode * mode); + +/* Duplicates a display mode, copying over driverdata as necessary */ +extern int WINRT_DuplicateDisplayMode(SDL_DisplayMode * dest, const SDL_DisplayMode * src); + +/* Display mode internals */ +typedef struct +{ + Windows::Graphics::Display::DisplayOrientations currentOrientation; +} SDL_DisplayModeData; + +#ifdef __cplusplus_winrt + +/* Internal window data */ +struct SDL_WindowData +{ + SDL_Window *sdlWindow; + Platform::Agile coreWindow; +#ifdef SDL_VIDEO_OPENGL_EGL + EGLSurface egl_surface; +#endif +}; + +#endif // ifdef __cplusplus_winrt diff --git a/test/loopwave.c b/test/loopwave.c index dc3482c02..ab94da43b 100644 --- a/test/loopwave.c +++ b/test/loopwave.c @@ -79,6 +79,7 @@ int main(int argc, char *argv[]) { int i; + char filename[4096]; /* Enable standard application logging */ SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO); @@ -89,11 +90,13 @@ 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) { + if (SDL_LoadWAV(filename, &wave.spec, &wave.sound, &wave.soundlen) == NULL) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Couldn't load %s: %s\n", argv[1], SDL_GetError()); quit(1); }