Compare commits

..

1 Commits

Author SHA1 Message Date
elasota
8a2b31fdb1 Add missing QT movie metadata 2020-02-18 20:58:00 -05:00
3474 changed files with 841 additions and 1218281 deletions

View File

@@ -1,10 +0,0 @@
root=true
[*.{h,c,cpp}]
indent_style=tab
indent_size=4
tab_width=4
end_of_line=lf
charset=latin1
trim_trailing_whitespace=true
insert_final_newline=true

38
.gitignore vendored
View File

@@ -1,38 +0,0 @@
*.suo
*.db
*.opendb
*.ipch
*.iobj
*.ipdb
*.pch
*.user
*.mcp
*.obj
*.log
*.tlog
*.lastbuildstate
*.dll
*.exe
*.exp
*.ilk
*.lib
*.pdb
*.idb
*.aps
*.res
.vs/*
Packaged/*
DebugData/*
ReleasePkg/*
InstallerPackages/*
*.msi
*.wixpdb
*.wixobj
*.CopyComplete
*.lnk
ReleasePackageInstaller/obj/*
ReleasePackageInstaller/bin/*
ReleasePackageInstaller/AerofoilPackageDefs.wxi
ReleasePackageInstaller/AerofoilPackageVersion.wxi
packages/*
!SDL2-2.0.12/lib/x64/*

View File

@@ -1,176 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.27130.2020
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hqx2bin", "hqx2bin\hqx2bin.vcxproj", "{45B1B18C-C846-4044-9206-74F58DFC5E88}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PortabilityLayer", "PortabilityLayer\PortabilityLayer.vcxproj", "{6EC62B0F-9353-40A4-A510-3788F1368B33}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MiniRez", "MiniRez\MiniRez.vcxproj", "{2FF15659-5C72-48B8-B55B-3C658E4125B5}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GpApp", "GpApp\GpApp.vcxproj", "{6233C3F2-5781-488E-B190-4FA8836F5A77}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "hqx2gp", "hqx2gp\hqx2gp.vcxproj", "{5FDE4822-C771-46A5-B6B2-FD12BACE86BF}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GpAudioDriver_XAudio2", "GpAudioDriver_XAudio2\GpAudioDriver_XAudio2.vcxproj", "{E3BDC783-8646-433E-ADF0-8B6390D36669}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FTagData", "FTagData\FTagData.vcxproj", "{A8FCDC5E-729C-4A80-BF9F-B669C52B2AE3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FreeType", "FreeType\FreeType.vcxproj", "{487216D8-16BA-4B4C-B5BF-43FEEDFEE03A}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CompileShadersD3D11", "CompileShadersD3D11\CompileShadersD3D11.vcxproj", "{ED2F91E1-673A-4590-82B2-EB157927D3E3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ConvertColorCursors", "ConvertColorCursors\ConvertColorCursors.vcxproj", "{B852D549-4020-4477-8BFB-E199FF78B047}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GpDisplayDriver_D3D11", "GpDisplayDriver_D3D11\GpDisplayDriver_D3D11.vcxproj", "{FFC961AC-55B4-4A38-A83E-06AE98F59ACC}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GpInputDriver_XInput", "GpInputDriver_XInput\GpInputDriver_XInput.vcxproj", "{17B96F07-EF92-47CD-95A5-8E6EE38AB564}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Aerofoil", "Aerofoil\Aerofoil.vcxproj", "{0E383EF0-CEF7-4733-87C6-5AC9844AA1EF}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MacRomanConversion", "MacRomanConversion\MacRomanConversion.vcxproj", "{07351A8E-1F79-42C9-BBAB-31F071EAA99E}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gpr2gpa", "gpr2gpa\gpr2gpa.vcxproj", "{27B7CA46-ED23-45C2-BF5F-0C126D81AEBF}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "zlib", "zlib\zlib.vcxproj", "{6AE5C85E-6631-4A12-97A0-A05F812FE9CA}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bin2gp", "bin2gp\bin2gp.vcxproj", "{D7BFE702-0667-4155-9B0B-2A54DF9AE60B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MakeTimestamp", "MakeTimestamp\MakeTimestamp.vcxproj", "{9023DF2F-A33D-485A-B13D-0973348B2F9B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "flattenmov", "flattenmov\flattenmov.vcxproj", "{89F8D13E-F216-4B67-8DE9-7F842D349E94}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "unpacktool", "unpacktool\unpacktool.vcxproj", "{A778D062-DE76-49F6-8D05-EB26852DD605}"
EndProject
Project("{930C7802-8A8C-48F9-8165-68863BCCD9DD}") = "ReleasePackageInstaller", "ReleasePackageInstaller\ReleasePackageInstaller.wixproj", "{D26BD501-28A7-4849-8130-FB5EA0A2B82F}"
ProjectSection(ProjectDependencies) = postProject
{7EFF1E21-C375-45EA-A069-4E2232C8A72B} = {7EFF1E21-C375-45EA-A069-4E2232C8A72B}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WindowsUnicodeToolShim", "WindowsUnicodeToolShim\WindowsUnicodeToolShim.vcxproj", "{15009625-1120-405E-8BBA-69A16CD6713D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "EmitWiXVersion", "EmitWiXVersion\EmitWiXVersion.vcxproj", "{7EFF1E21-C375-45EA-A069-4E2232C8A72B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GpShell", "GpShell\GpShell.vcxproj", "{10CF9B5F-61D0-4B5B-89F4-810B58FC053D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GpFontHandler_FreeType2", "GpFontHandler_FreeType2\GpFontHandler_FreeType2.vcxproj", "{4B564030-8985-4975-91E1-E1B2C16AE2A1}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AerofoilSDL", "AerofoilSDL\AerofoilSDL.vcxproj", "{33542FF0-0473-4802-BC79-3B8261790F65}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Release|x64 = Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{45B1B18C-C846-4044-9206-74F58DFC5E88}.Debug|x64.ActiveCfg = Debug|x64
{45B1B18C-C846-4044-9206-74F58DFC5E88}.Debug|x64.Build.0 = Debug|x64
{45B1B18C-C846-4044-9206-74F58DFC5E88}.Release|x64.ActiveCfg = Release|x64
{45B1B18C-C846-4044-9206-74F58DFC5E88}.Release|x64.Build.0 = Release|x64
{6EC62B0F-9353-40A4-A510-3788F1368B33}.Debug|x64.ActiveCfg = Debug|x64
{6EC62B0F-9353-40A4-A510-3788F1368B33}.Debug|x64.Build.0 = Debug|x64
{6EC62B0F-9353-40A4-A510-3788F1368B33}.Release|x64.ActiveCfg = Release|x64
{6EC62B0F-9353-40A4-A510-3788F1368B33}.Release|x64.Build.0 = Release|x64
{2FF15659-5C72-48B8-B55B-3C658E4125B5}.Debug|x64.ActiveCfg = Debug|x64
{2FF15659-5C72-48B8-B55B-3C658E4125B5}.Debug|x64.Build.0 = Debug|x64
{2FF15659-5C72-48B8-B55B-3C658E4125B5}.Release|x64.ActiveCfg = Release|x64
{2FF15659-5C72-48B8-B55B-3C658E4125B5}.Release|x64.Build.0 = Release|x64
{6233C3F2-5781-488E-B190-4FA8836F5A77}.Debug|x64.ActiveCfg = Debug|x64
{6233C3F2-5781-488E-B190-4FA8836F5A77}.Debug|x64.Build.0 = Debug|x64
{6233C3F2-5781-488E-B190-4FA8836F5A77}.Release|x64.ActiveCfg = Release|x64
{6233C3F2-5781-488E-B190-4FA8836F5A77}.Release|x64.Build.0 = Release|x64
{5FDE4822-C771-46A5-B6B2-FD12BACE86BF}.Debug|x64.ActiveCfg = Debug|x64
{5FDE4822-C771-46A5-B6B2-FD12BACE86BF}.Debug|x64.Build.0 = Debug|x64
{5FDE4822-C771-46A5-B6B2-FD12BACE86BF}.Release|x64.ActiveCfg = Release|x64
{5FDE4822-C771-46A5-B6B2-FD12BACE86BF}.Release|x64.Build.0 = Release|x64
{E3BDC783-8646-433E-ADF0-8B6390D36669}.Debug|x64.ActiveCfg = Debug|x64
{E3BDC783-8646-433E-ADF0-8B6390D36669}.Debug|x64.Build.0 = Debug|x64
{E3BDC783-8646-433E-ADF0-8B6390D36669}.Release|x64.ActiveCfg = Release|x64
{E3BDC783-8646-433E-ADF0-8B6390D36669}.Release|x64.Build.0 = Release|x64
{A8FCDC5E-729C-4A80-BF9F-B669C52B2AE3}.Debug|x64.ActiveCfg = Debug|x64
{A8FCDC5E-729C-4A80-BF9F-B669C52B2AE3}.Debug|x64.Build.0 = Debug|x64
{A8FCDC5E-729C-4A80-BF9F-B669C52B2AE3}.Release|x64.ActiveCfg = Release|x64
{A8FCDC5E-729C-4A80-BF9F-B669C52B2AE3}.Release|x64.Build.0 = Release|x64
{487216D8-16BA-4B4C-B5BF-43FEEDFEE03A}.Debug|x64.ActiveCfg = Debug|x64
{487216D8-16BA-4B4C-B5BF-43FEEDFEE03A}.Debug|x64.Build.0 = Debug|x64
{487216D8-16BA-4B4C-B5BF-43FEEDFEE03A}.Release|x64.ActiveCfg = Release|x64
{487216D8-16BA-4B4C-B5BF-43FEEDFEE03A}.Release|x64.Build.0 = Release|x64
{ED2F91E1-673A-4590-82B2-EB157927D3E3}.Debug|x64.ActiveCfg = Debug|x64
{ED2F91E1-673A-4590-82B2-EB157927D3E3}.Debug|x64.Build.0 = Debug|x64
{ED2F91E1-673A-4590-82B2-EB157927D3E3}.Release|x64.ActiveCfg = Release|x64
{ED2F91E1-673A-4590-82B2-EB157927D3E3}.Release|x64.Build.0 = Release|x64
{B852D549-4020-4477-8BFB-E199FF78B047}.Debug|x64.ActiveCfg = Debug|x64
{B852D549-4020-4477-8BFB-E199FF78B047}.Debug|x64.Build.0 = Debug|x64
{B852D549-4020-4477-8BFB-E199FF78B047}.Release|x64.ActiveCfg = Release|x64
{B852D549-4020-4477-8BFB-E199FF78B047}.Release|x64.Build.0 = Release|x64
{FFC961AC-55B4-4A38-A83E-06AE98F59ACC}.Debug|x64.ActiveCfg = Debug|x64
{FFC961AC-55B4-4A38-A83E-06AE98F59ACC}.Debug|x64.Build.0 = Debug|x64
{FFC961AC-55B4-4A38-A83E-06AE98F59ACC}.Release|x64.ActiveCfg = Release|x64
{FFC961AC-55B4-4A38-A83E-06AE98F59ACC}.Release|x64.Build.0 = Release|x64
{17B96F07-EF92-47CD-95A5-8E6EE38AB564}.Debug|x64.ActiveCfg = Debug|x64
{17B96F07-EF92-47CD-95A5-8E6EE38AB564}.Debug|x64.Build.0 = Debug|x64
{17B96F07-EF92-47CD-95A5-8E6EE38AB564}.Release|x64.ActiveCfg = Release|x64
{17B96F07-EF92-47CD-95A5-8E6EE38AB564}.Release|x64.Build.0 = Release|x64
{0E383EF0-CEF7-4733-87C6-5AC9844AA1EF}.Debug|x64.ActiveCfg = Debug|x64
{0E383EF0-CEF7-4733-87C6-5AC9844AA1EF}.Debug|x64.Build.0 = Debug|x64
{0E383EF0-CEF7-4733-87C6-5AC9844AA1EF}.Release|x64.ActiveCfg = Release|x64
{0E383EF0-CEF7-4733-87C6-5AC9844AA1EF}.Release|x64.Build.0 = Release|x64
{07351A8E-1F79-42C9-BBAB-31F071EAA99E}.Debug|x64.ActiveCfg = Debug|x64
{07351A8E-1F79-42C9-BBAB-31F071EAA99E}.Debug|x64.Build.0 = Debug|x64
{07351A8E-1F79-42C9-BBAB-31F071EAA99E}.Release|x64.ActiveCfg = Release|x64
{07351A8E-1F79-42C9-BBAB-31F071EAA99E}.Release|x64.Build.0 = Release|x64
{27B7CA46-ED23-45C2-BF5F-0C126D81AEBF}.Debug|x64.ActiveCfg = Debug|x64
{27B7CA46-ED23-45C2-BF5F-0C126D81AEBF}.Debug|x64.Build.0 = Debug|x64
{27B7CA46-ED23-45C2-BF5F-0C126D81AEBF}.Release|x64.ActiveCfg = Release|x64
{27B7CA46-ED23-45C2-BF5F-0C126D81AEBF}.Release|x64.Build.0 = Release|x64
{6AE5C85E-6631-4A12-97A0-A05F812FE9CA}.Debug|x64.ActiveCfg = Debug|x64
{6AE5C85E-6631-4A12-97A0-A05F812FE9CA}.Debug|x64.Build.0 = Debug|x64
{6AE5C85E-6631-4A12-97A0-A05F812FE9CA}.Release|x64.ActiveCfg = Release|x64
{6AE5C85E-6631-4A12-97A0-A05F812FE9CA}.Release|x64.Build.0 = Release|x64
{D7BFE702-0667-4155-9B0B-2A54DF9AE60B}.Debug|x64.ActiveCfg = Debug|x64
{D7BFE702-0667-4155-9B0B-2A54DF9AE60B}.Debug|x64.Build.0 = Debug|x64
{D7BFE702-0667-4155-9B0B-2A54DF9AE60B}.Release|x64.ActiveCfg = Release|x64
{D7BFE702-0667-4155-9B0B-2A54DF9AE60B}.Release|x64.Build.0 = Release|x64
{9023DF2F-A33D-485A-B13D-0973348B2F9B}.Debug|x64.ActiveCfg = Debug|x64
{9023DF2F-A33D-485A-B13D-0973348B2F9B}.Debug|x64.Build.0 = Debug|x64
{9023DF2F-A33D-485A-B13D-0973348B2F9B}.Release|x64.ActiveCfg = Release|x64
{9023DF2F-A33D-485A-B13D-0973348B2F9B}.Release|x64.Build.0 = Release|x64
{89F8D13E-F216-4B67-8DE9-7F842D349E94}.Debug|x64.ActiveCfg = Debug|x64
{89F8D13E-F216-4B67-8DE9-7F842D349E94}.Debug|x64.Build.0 = Debug|x64
{89F8D13E-F216-4B67-8DE9-7F842D349E94}.Release|x64.ActiveCfg = Release|x64
{89F8D13E-F216-4B67-8DE9-7F842D349E94}.Release|x64.Build.0 = Release|x64
{A778D062-DE76-49F6-8D05-EB26852DD605}.Debug|x64.ActiveCfg = Debug|x64
{A778D062-DE76-49F6-8D05-EB26852DD605}.Debug|x64.Build.0 = Debug|x64
{A778D062-DE76-49F6-8D05-EB26852DD605}.Release|x64.ActiveCfg = Release|x64
{A778D062-DE76-49F6-8D05-EB26852DD605}.Release|x64.Build.0 = Release|x64
{D26BD501-28A7-4849-8130-FB5EA0A2B82F}.Debug|x64.ActiveCfg = Debug|x64
{D26BD501-28A7-4849-8130-FB5EA0A2B82F}.Release|x64.ActiveCfg = Release|x64
{15009625-1120-405E-8BBA-69A16CD6713D}.Debug|x64.ActiveCfg = Debug|x64
{15009625-1120-405E-8BBA-69A16CD6713D}.Debug|x64.Build.0 = Debug|x64
{15009625-1120-405E-8BBA-69A16CD6713D}.Release|x64.ActiveCfg = Release|x64
{15009625-1120-405E-8BBA-69A16CD6713D}.Release|x64.Build.0 = Release|x64
{7EFF1E21-C375-45EA-A069-4E2232C8A72B}.Debug|x64.ActiveCfg = Debug|x64
{7EFF1E21-C375-45EA-A069-4E2232C8A72B}.Debug|x64.Build.0 = Debug|x64
{7EFF1E21-C375-45EA-A069-4E2232C8A72B}.Release|x64.ActiveCfg = Release|x64
{7EFF1E21-C375-45EA-A069-4E2232C8A72B}.Release|x64.Build.0 = Release|x64
{10CF9B5F-61D0-4B5B-89F4-810B58FC053D}.Debug|x64.ActiveCfg = Debug|x64
{10CF9B5F-61D0-4B5B-89F4-810B58FC053D}.Debug|x64.Build.0 = Debug|x64
{10CF9B5F-61D0-4B5B-89F4-810B58FC053D}.Release|x64.ActiveCfg = Release|x64
{10CF9B5F-61D0-4B5B-89F4-810B58FC053D}.Release|x64.Build.0 = Release|x64
{4B564030-8985-4975-91E1-E1B2C16AE2A1}.Debug|x64.ActiveCfg = Debug|x64
{4B564030-8985-4975-91E1-E1B2C16AE2A1}.Debug|x64.Build.0 = Debug|x64
{4B564030-8985-4975-91E1-E1B2C16AE2A1}.Release|x64.ActiveCfg = Release|x64
{4B564030-8985-4975-91E1-E1B2C16AE2A1}.Release|x64.Build.0 = Release|x64
{33542FF0-0473-4802-BC79-3B8261790F65}.Debug|x64.ActiveCfg = Debug|x64
{33542FF0-0473-4802-BC79-3B8261790F65}.Debug|x64.Build.0 = Debug|x64
{33542FF0-0473-4802-BC79-3B8261790F65}.Release|x64.ActiveCfg = Release|x64
{33542FF0-0473-4802-BC79-3B8261790F65}.Release|x64.Build.0 = Release|x64
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {0D6869A7-07EB-400F-B2AD-48531564555A}
EndGlobalSection
EndGlobal

View File

@@ -1,217 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="GpMain_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpMain.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpDisplayDriverFactory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpGlobalConfig.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpAppEnvironment.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpFileSystem_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpMemoryBuffer.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpPLGlueDisplayDriver.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpFileStream_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpSystemServices_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpFiberStarter_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpFiber_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpPLGlueAudioDriver.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpAudioDriverFactory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpPLGlueAudioChannel.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpMutex_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpThreadEvent_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpFontHandlerFactory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpFontHandler_FreeType2.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpVOSEventQueue.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpColorCursor_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpInputDriverFactory.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="GpWindows.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpDisplayDriverFactory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IGpDisplayDriver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpMain.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpGlobalConfig.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpAppEnvironment.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpCoreDefs.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpRingBuffer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpFileSystem_Win32.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpMemoryBuffer.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpPLGlueDisplayDriver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpFileStream_Win32.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpSystemServices_Win32.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpFiberStarter.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpFiber_Win32.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpFiber.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IGpAudioDriver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpAudioDriverFactory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpPLGlueAudioDriver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpPLGlueAudioChannel.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="IGpAudioChannel.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpMutex_Win32.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpThreadEvent_Win32.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\IGpAudioChannelCallbacks.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpFontHandlerFactory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpFontHandler_FreeType2.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpVOSEventQueue.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\IGpDisplayDriverSurface.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpComPtr.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\IGpColorCursor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\GpColorCursor_Win32.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\EGpStandardCursor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpInputDriverFactory.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\EGpInputDriverType.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\GpInputDriverProperties.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\GpDisplayDriverTickStatus.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\GpFileCreationDisposition.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\GpApplicationName.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Aerofoil.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<Image Include="ConvertedResources\Large128.ico">
<Filter>Resource Files</Filter>
</Image>
<Image Include="ConvertedResources\Small128.ico">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
</Project>

Binary file not shown.

View File

@@ -1,150 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{0E383EF0-CEF7-4733-87C6-5AC9844AA1EF}</ProjectGuid>
<RootNamespace>Aerofoil</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\PortabilityLayer.props" />
<Import Project="..\Common.props" />
<Import Project="..\GpCommon.props" />
<Import Project="..\GpMainApp.props" />
<Import Project="..\GpShell.props" />
<Import Project="..\Debug.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="..\PortabilityLayer.props" />
<Import Project="..\Common.props" />
<Import Project="..\GpCommon.props" />
<Import Project="..\GpMainApp.props" />
<Import Project="..\Release.props" />
<Import Project="..\GpShell.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="GpBWCursor_Win32.cpp" />
<ClCompile Include="GpColorCursor_Win32.cpp" />
<ClCompile Include="GpFiber_Win32.cpp" />
<ClCompile Include="GpFileStream_Win32.cpp" />
<ClCompile Include="GpFileSystem_Win32.cpp" />
<ClCompile Include="GpLogDriver_Win32.cpp" />
<ClCompile Include="GpMain_Win32.cpp" />
<ClCompile Include="GpMutex_Win32.cpp" />
<ClCompile Include="GpSystemServices_Win32.cpp" />
<ClCompile Include="GpFiberStarter_Win32.cpp" />
<ClCompile Include="GpThreadEvent_Win32.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\GpCommon\EGpInputDriverType.h" />
<ClInclude Include="..\GpCommon\EGpStandardCursor.h" />
<ClInclude Include="..\GpCommon\GpApplicationName.h" />
<ClInclude Include="..\GpCommon\GpBuildVersion.h" />
<ClInclude Include="..\GpCommon\GpDisplayDriverTickStatus.h" />
<ClInclude Include="..\GpCommon\GpFileCreationDisposition.h" />
<ClInclude Include="..\GpCommon\GpInputDriverProperties.h" />
<ClInclude Include="..\GpCommon\IGpCursor.h" />
<ClInclude Include="..\GpCommon\IGpAudioChannelCallbacks.h" />
<ClInclude Include="..\GpCommon\IGpDisplayDriverSurface.h" />
<ClInclude Include="..\GpCommon\IGpLogDriver.h" />
<ClInclude Include="..\GpCommon\IGpPrefsHandler.h" />
<ClInclude Include="GpBWCursor_Win32.h" />
<ClInclude Include="GpFiber_Win32.h" />
<ClInclude Include="GpFileStream_Win32.h" />
<ClInclude Include="GpFileSystem_Win32.h" />
<ClInclude Include="GpLogDriver_Win32.h" />
<ClInclude Include="GpMutex_Win32.h" />
<ClInclude Include="GpSystemServices_Win32.h" />
<ClInclude Include="GpThreadEvent_Win32.h" />
<ClInclude Include="resource.h" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GpApp\GpApp.vcxproj">
<Project>{6233c3f2-5781-488e-b190-4fa8836f5a77}</Project>
</ProjectReference>
<ProjectReference Include="..\GpAudioDriver_XAudio2\GpAudioDriver_XAudio2.vcxproj">
<Project>{e3bdc783-8646-433e-adf0-8b6390d36669}</Project>
</ProjectReference>
<ProjectReference Include="..\GpDisplayDriver_D3D11\GpDisplayDriver_D3D11.vcxproj">
<Project>{ffc961ac-55b4-4a38-a83e-06ae98f59acc}</Project>
</ProjectReference>
<ProjectReference Include="..\GpFontHandler_FreeType2\GpFontHandler_FreeType2.vcxproj">
<Project>{4b564030-8985-4975-91e1-e1b2c16ae2a1}</Project>
</ProjectReference>
<ProjectReference Include="..\GpInputDriver_XInput\GpInputDriver_XInput.vcxproj">
<Project>{17b96f07-ef92-47cd-95a5-8e6ee38ab564}</Project>
</ProjectReference>
<ProjectReference Include="..\GpShell\GpShell.vcxproj">
<Project>{10cf9b5f-61d0-4b5b-89f4-810b58fc053d}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Aerofoil.rc" />
</ItemGroup>
<ItemGroup>
<Image Include="ConvertedResources\Large128.ico" />
<Image Include="ConvertedResources\Small128.ico" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -1,127 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="GpColorCursor_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpFiber_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpFiberStarter_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpFileStream_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpFileSystem_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpMain_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpMutex_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpSystemServices_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpThreadEvent_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpLogDriver_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpBWCursor_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\GpCommon\EGpInputDriverType.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\EGpStandardCursor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\GpApplicationName.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\GpDisplayDriverTickStatus.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpFiber_Win32.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\GpFileCreationDisposition.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpFileStream_Win32.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpFileSystem_Win32.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\GpInputDriverProperties.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpMutex_Win32.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpSystemServices_Win32.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpThreadEvent_Win32.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\IGpAudioChannelCallbacks.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\IGpCursor.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\IGpDisplayDriverSurface.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="resource.h">
<Filter>Resource Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\IGpLogDriver.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpLogDriver_Win32.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\IGpPrefsHandler.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\GpCommon\GpBuildVersion.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpBWCursor_Win32.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="ConvertedResources\Large128.ico">
<Filter>Resource Files</Filter>
</Image>
<Image Include="ConvertedResources\Small128.ico">
<Filter>Resource Files</Filter>
</Image>
</ItemGroup>
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{0db467fa-83af-4c89-b36b-2478899f4f9e}</UniqueIdentifier>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{bdb8c57b-c9f7-443a-be30-89718b8ca3e5}</UniqueIdentifier>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{8ed8ebed-2aea-4f6d-8f2f-c18a64eb6e20}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="Aerofoil.rc">
<Filter>Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
</Project>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 597 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 670 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 765 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 826 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 339 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 342 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 345 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 356 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 205 B

View File

@@ -1,110 +0,0 @@
/*
Portions of this file based on Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
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 "GpBWCursor_Win32.h"
#include "GpWindows.h"
#include <stdint.h>
#include <stdlib.h>
#include <new>
#include <algorithm>
extern GpWindowsGlobals g_gpWindowsGlobals;
void GpBWCursor_Win32::Destroy()
{
this->DecRef();
}
IGpCursor_Win32 *GpBWCursor_Win32::Create(size_t width, size_t height, const void *pixelData, const void *maskData, size_t hotSpotX, size_t hotSpotY)
{
size_t numBits = width * height;
size_t numBytes = (width * height + 7) / 8;
uint8_t *convertedAndData = static_cast<uint8_t*>(malloc(numBytes));
uint8_t *convertedXorData = static_cast<uint8_t*>(malloc(numBytes));
if (!convertedAndData || !convertedXorData)
{
if (convertedAndData)
free(convertedAndData);
if (convertedXorData)
free(convertedXorData);
return nullptr;
}
for (size_t i = 0; i < numBytes; i++)
{
// MacPx0 MacPx1
// MacMask0 1a 0x 1a 1x
// MacMask1 0a 1x 0a 0x
convertedAndData[i] = static_cast<const uint8_t*>(maskData)[i] ^ 0xff;
convertedXorData[i] = static_cast<const uint8_t*>(maskData)[i] ^ static_cast<const uint8_t*>(pixelData)[i];
}
HCURSOR hcursor = CreateCursor(g_gpWindowsGlobals.m_hInstance, static_cast<int>(hotSpotX), static_cast<int>(hotSpotY), static_cast<int>(width), static_cast<int>(height), convertedAndData, convertedXorData);
free(convertedAndData);
free(convertedXorData);
if (!hcursor)
return nullptr;
void *storage = malloc(sizeof(GpBWCursor_Win32));
if (!storage)
{
DestroyCursor(hcursor);
return nullptr;
}
return new (storage) GpBWCursor_Win32(hcursor);
}
GpBWCursor_Win32::GpBWCursor_Win32(HCURSOR cursor)
: m_cursor(cursor)
, m_refCount(1)
{
}
GpBWCursor_Win32::~GpBWCursor_Win32()
{
DestroyCursor(m_cursor);
}
const HCURSOR &GpBWCursor_Win32::GetHCursor() const
{
return m_cursor;
}
void GpBWCursor_Win32::IncRef()
{
m_refCount++;
}
void GpBWCursor_Win32::DecRef()
{
m_refCount--;
if (m_refCount == 0)
{
this->~GpBWCursor_Win32();
free(this);
}
}

View File

@@ -1,24 +0,0 @@
#pragma once
#include "IGpCursor_Win32.h"
#include "GpWindows.h"
class GpBWCursor_Win32 final : public IGpCursor_Win32
{
public:
void Destroy() override;
const HCURSOR &GetHCursor() const override;
void IncRef() override;
void DecRef() override;
static IGpCursor_Win32 *Create(size_t width, size_t height, const void *pixelData, const void *maskData, size_t hotSpotX, size_t hotSpotY);
private:
GpBWCursor_Win32(HCURSOR cursor);
~GpBWCursor_Win32();
HCURSOR m_cursor;
int m_refCount;
};

View File

@@ -1,132 +0,0 @@
/*
Portions of this file based on Simple DirectMedia Layer
Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
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 "GpColorCursor_Win32.h"
#include <stdint.h>
#include <stdlib.h>
#include <new>
#include <algorithm>
void GpColorCursor_Win32::Destroy()
{
this->DecRef();
}
IGpCursor_Win32 *GpColorCursor_Win32::Create(size_t width, size_t height, const void *pixelDataRGBA, size_t hotSpotX, size_t hotSpotY)
{
const size_t paddingBits = (sizeof(void*) * 8);
BITMAPV4HEADER bmp;
memset(&bmp, 0, sizeof(bmp));
bmp.bV4Size = sizeof(bmp);
bmp.bV4Width = width;
bmp.bV4Height = -static_cast<LONG>(height);
bmp.bV4Planes = 1;
bmp.bV4BitCount = 32;
bmp.bV4V4Compression = BI_BITFIELDS;
bmp.bV4AlphaMask = 0xFF000000;
bmp.bV4RedMask = 0x00FF0000;
bmp.bV4GreenMask = 0x0000FF00;
bmp.bV4BlueMask = 0x000000FF;
size_t maskPitch = width + paddingBits - 1;
maskPitch -= maskPitch % paddingBits;
LPVOID maskBits = malloc(maskPitch * height);
if (!maskBits)
return nullptr;
memset(maskBits, 0xff, maskPitch * height);
HDC hdc = GetDC(NULL);
LPVOID pixels;
ICONINFO ii;
memset(&ii, 0, sizeof(ii));
ii.fIcon = FALSE;
ii.xHotspot = (DWORD)hotSpotX;
ii.yHotspot = (DWORD)hotSpotY;
ii.hbmColor = CreateDIBSection(hdc, (BITMAPINFO*)&bmp, DIB_RGB_COLORS, &pixels, NULL, 0);
ii.hbmMask = CreateBitmap(width, height, 1, 1, maskBits);
ReleaseDC(NULL, hdc);
size_t cursorPitch = width * 4;
size_t numPixels = width * height;
memcpy(pixels, pixelDataRGBA, numPixels * 4);
for (size_t i = 0; i < numPixels; i++)
{
uint8_t *pixel = static_cast<uint8_t*>(pixels) + i * 4;
std::swap(pixel[0], pixel[2]);
}
HICON hicon = CreateIconIndirect(&ii);
DeleteObject(ii.hbmColor);
DeleteObject(ii.hbmMask);
if (!hicon)
return nullptr;
void *storage = malloc(sizeof(GpColorCursor_Win32));
if (!storage)
{
DestroyIcon(hicon);
return nullptr;
}
return new (storage) GpColorCursor_Win32(reinterpret_cast<HCURSOR>(hicon));
}
GpColorCursor_Win32::GpColorCursor_Win32(HCURSOR cursor)
: m_cursor(cursor)
, m_refCount(1)
{
}
GpColorCursor_Win32::~GpColorCursor_Win32()
{
DestroyIcon(m_cursor);
}
const HCURSOR &GpColorCursor_Win32::GetHCursor() const
{
return m_cursor;
}
void GpColorCursor_Win32::IncRef()
{
m_refCount++;
}
void GpColorCursor_Win32::DecRef()
{
m_refCount--;
if (m_refCount == 0)
{
this->~GpColorCursor_Win32();
free(this);
}
}

View File

@@ -1,25 +0,0 @@
#pragma once
#include "IGpCursor_Win32.h"
#include "GpWindows.h"
class GpColorCursor_Win32 final : public IGpCursor_Win32
{
public:
void Destroy() override;
const HCURSOR &GetHCursor() const override;
void IncRef() override;
void DecRef() override;
static IGpCursor_Win32 *Create(size_t width, size_t height, const void *pixelDataRGBA, size_t hotSpotX, size_t hotSpotY);
private:
GpColorCursor_Win32(HCURSOR cursor);
~GpColorCursor_Win32();
HCURSOR m_cursor;
int m_refCount;
};

View File

@@ -1,56 +0,0 @@
#include "GpFiberStarter.h"
#include "GpFiber_Win32.h"
#include "GpWindows.h"
#include <assert.h>
namespace GpFiberStarter_Win32
{
struct FiberStartState
{
GpFiberStarter::ThreadFunc_t m_threadFunc;
IGpFiber *m_creatingFiber;
void *m_context;
};
static VOID WINAPI FiberStartRoutine(LPVOID lpThreadParameter)
{
const FiberStartState *tss = static_cast<const FiberStartState*>(lpThreadParameter);
GpFiberStarter::ThreadFunc_t threadFunc = tss->m_threadFunc;
IGpFiber *creatingFiber = tss->m_creatingFiber;
void *context = tss->m_context;
SwitchToFiber(static_cast<GpFiber_Win32*>(creatingFiber)->GetFiber());
threadFunc(context);
assert(!"Fiber function exited");
}
}
IGpFiber *GpFiberStarter::StartFiber(PortabilityLayer::HostSystemServices *systemServices, ThreadFunc_t threadFunc, void *context, IGpFiber *creatingFiber)
{
ULONG_PTR lowLimit;
ULONG_PTR highLimit;
#if 0
GetCurrentThreadStackLimits(&lowLimit, &highLimit);
ULONG_PTR stackSize = highLimit - lowLimit;
#else
ULONG_PTR stackSize = 1024 * 1024;
#endif
GpFiberStarter_Win32::FiberStartState startState;
startState.m_context = context;
startState.m_creatingFiber = creatingFiber;
startState.m_threadFunc = threadFunc;
void *fiber = CreateFiber(static_cast<SIZE_T>(stackSize), GpFiberStarter_Win32::FiberStartRoutine, &startState);
if (!fiber)
return nullptr;
SwitchToFiber(fiber);
return GpFiber_Win32::Create(fiber);
}

View File

@@ -1,37 +0,0 @@
#include "GpFiber_Win32.h"
#include <new>
GpFiber_Win32::GpFiber_Win32(LPVOID fiber)
: m_fiber(fiber)
{
}
void GpFiber_Win32::YieldTo(IGpFiber *toFiber)
{
SwitchToFiber(static_cast<GpFiber_Win32*>(toFiber)->m_fiber);
}
void GpFiber_Win32::YieldToTerminal(IGpFiber *toFiber)
{
YieldTo(toFiber);
}
void GpFiber_Win32::Destroy()
{
this->~GpFiber_Win32();
free(this);
}
GpFiber_Win32::~GpFiber_Win32()
{
DeleteFiber(m_fiber);
}
IGpFiber *GpFiber_Win32::Create(LPVOID fiber)
{
void *storage = malloc(sizeof(GpFiber_Win32));
if (!storage)
return nullptr;
return new (storage) GpFiber_Win32(fiber);
}

View File

@@ -1,26 +0,0 @@
#pragma once
#include "GpWindows.h"
#include "IGpFiber.h"
class GpFiber_Win32 final : public IGpFiber
{
public:
void YieldTo(IGpFiber *toFiber) override;
void YieldToTerminal(IGpFiber *toFiber) override;
void Destroy() override;
static IGpFiber *Create(LPVOID fiber);
LPVOID GetFiber() const;
private:
explicit GpFiber_Win32(LPVOID fiber);
~GpFiber_Win32();
LPVOID m_fiber;
};
inline LPVOID GpFiber_Win32::GetFiber() const
{
return m_fiber;
}

View File

@@ -1,149 +0,0 @@
#include "GpFileStream_Win32.h"
GpFileStream_Win32::GpFileStream_Win32(HANDLE handle, bool readable, bool writeable, bool seekable)
: m_handle(handle)
, m_readable(readable)
, m_writeable(writeable)
, m_seekable(seekable)
{
}
size_t GpFileStream_Win32::Read(void *bytesOut, size_t size)
{
if (!m_readable)
return 0;
size_t totalRead = 0;
while (size)
{
const DWORD chunkSizeToRead = (size > MAXDWORD) ? MAXDWORD : size;
DWORD numRead = 0;
BOOL readSucceeded = ReadFile(m_handle, bytesOut, chunkSizeToRead, &numRead, nullptr);
if (!readSucceeded)
return totalRead;
totalRead += static_cast<size_t>(numRead);
size -= static_cast<size_t>(numRead);
bytesOut = static_cast<void*>(static_cast<uint8_t*>(bytesOut) + numRead);
if (numRead != chunkSizeToRead)
return totalRead;
}
return totalRead;
}
size_t GpFileStream_Win32::Write(const void *bytes, size_t size)
{
if (!m_writeable)
return 0;
size_t totalWritten = 0;
while (size)
{
const DWORD chunkSizeToWrite = (size > MAXDWORD) ? MAXDWORD : size;
DWORD numWritten = 0;
BOOL writeSucceeded = WriteFile(m_handle, bytes, chunkSizeToWrite, &numWritten, nullptr);
if (!writeSucceeded)
{
DWORD lastError = GetLastError();
return totalWritten;
}
totalWritten += static_cast<size_t>(numWritten);
size -= static_cast<size_t>(numWritten);
bytes = static_cast<const void*>(static_cast<const uint8_t*>(bytes) + numWritten);
if (numWritten != chunkSizeToWrite)
return totalWritten;
}
return totalWritten;
}
bool GpFileStream_Win32::IsSeekable() const
{
return m_seekable;
}
bool GpFileStream_Win32::IsReadOnly() const
{
return !m_writeable;
}
bool GpFileStream_Win32::IsWriteOnly() const
{
return !m_readable;
}
bool GpFileStream_Win32::SeekStart(GpUFilePos_t loc)
{
LARGE_INTEGER li;
li.QuadPart = static_cast<LONGLONG>(loc);
return SetFilePointerEx(m_handle, li, nullptr, FILE_BEGIN) != 0;
}
bool GpFileStream_Win32::SeekCurrent(GpFilePos_t loc)
{
LARGE_INTEGER li;
li.QuadPart = static_cast<LONGLONG>(loc);
return SetFilePointerEx(m_handle, li, nullptr, FILE_CURRENT) != 0;
}
bool GpFileStream_Win32::SeekEnd(GpUFilePos_t loc)
{
LARGE_INTEGER li;
li.QuadPart = -static_cast<LONGLONG>(loc);
return SetFilePointerEx(m_handle, li, nullptr, FILE_END) != 0;
}
bool GpFileStream_Win32::Truncate(GpUFilePos_t loc)
{
if (!m_writeable)
return false;
GpUFilePos_t oldPos = Tell();
if (!SeekStart(loc))
return false;
if (!SetEndOfFile(m_handle))
return false;
if (!SeekStart(oldPos))
return false;
return true;
}
GpUFilePos_t GpFileStream_Win32::Size() const
{
LARGE_INTEGER fsize;
if (!GetFileSizeEx(m_handle, &fsize))
return 0;
return static_cast<GpUFilePos_t>(fsize.QuadPart);
}
GpUFilePos_t GpFileStream_Win32::Tell() const
{
LARGE_INTEGER zero;
zero.QuadPart = 0;
LARGE_INTEGER fpos;
if (!SetFilePointerEx(m_handle, zero, &fpos, FILE_CURRENT))
return 0;
return static_cast<GpUFilePos_t>(fpos.QuadPart);
}
void GpFileStream_Win32::Close()
{
CloseHandle(m_handle);
}
void GpFileStream_Win32::Flush()
{
FlushFileBuffers(m_handle);
}

View File

@@ -1,31 +0,0 @@
#pragma once
#include "GpCoreDefs.h"
#include "GpWindows.h"
#include "GpIOStream.h"
class GpFileStream_Win32 final : public GpIOStream
{
public:
explicit GpFileStream_Win32(HANDLE handle, bool readable, bool writeable, bool seekable);
size_t Read(void *bytesOut, size_t size) override;
size_t Write(const void *bytes, size_t size) override;
bool IsSeekable() const override;
bool IsReadOnly() const override;
bool IsWriteOnly() const override;
bool SeekStart(GpUFilePos_t loc) override;
bool SeekCurrent(GpFilePos_t loc) override;
bool SeekEnd(GpUFilePos_t loc) override;
bool Truncate(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
void Flush() override;
private:
HANDLE m_handle;
bool m_readable;
bool m_writeable;
bool m_seekable;
};

View File

@@ -1,515 +0,0 @@
#include "GpFileSystem_Win32.h"
#include "GpApplicationName.h"
#include "GpFileStream_Win32.h"
#include "GpWindows.h"
#include "GpMemoryBuffer.h"
#include "HostDirectoryCursor.h"
#include <string>
#include <Shlwapi.h>
#include <ShlObj.h>
#include <commdlg.h>
#include <assert.h>
extern GpWindowsGlobals g_gpWindowsGlobals;
class GpDirectoryCursor_Win32 final : public PortabilityLayer::HostDirectoryCursor
{
public:
static GpDirectoryCursor_Win32 *Create(const HANDLE &handle, const WIN32_FIND_DATAW &findData);
bool GetNext(const char *&outFileName) override;
void Destroy() override;
private:
GpDirectoryCursor_Win32(const HANDLE &handle, const WIN32_FIND_DATAW &findData);
~GpDirectoryCursor_Win32();
HANDLE m_handle;
WIN32_FIND_DATAW m_findData;
char m_chars[MAX_PATH + 1];
bool m_haveNext;
};
GpDirectoryCursor_Win32 *GpDirectoryCursor_Win32::Create(const HANDLE &handle, const WIN32_FIND_DATAW &findData)
{
void *storage = malloc(sizeof(GpDirectoryCursor_Win32));
if (!storage)
return nullptr;
return new (storage) GpDirectoryCursor_Win32(handle, findData);
}
bool GpDirectoryCursor_Win32::GetNext(const char *&outFileName)
{
while (m_haveNext)
{
bool haveResult = false;
bool hasInvalidChars = false;
for (const wchar_t *fnameScan = m_findData.cFileName; *fnameScan; fnameScan++)
{
const int32_t asInt = static_cast<int32_t>(*fnameScan);
if (asInt < 1 || asInt >= 128)
{
hasInvalidChars = true;
break;
}
}
if (!hasInvalidChars && wcscmp(m_findData.cFileName, L".") && wcscmp(m_findData.cFileName, L".."))
{
const size_t len = wcslen(m_findData.cFileName);
haveResult = true;
for (size_t i = 0; i <= len; i++)
m_chars[i] = static_cast<char>(m_findData.cFileName[i]);
}
m_haveNext = (FindNextFileW(m_handle, &m_findData) != FALSE);
if (haveResult)
{
outFileName = m_chars;
return true;
}
}
return false;
}
void GpDirectoryCursor_Win32::Destroy()
{
this->~GpDirectoryCursor_Win32();
free(this);
}
GpDirectoryCursor_Win32::GpDirectoryCursor_Win32(const HANDLE &handle, const WIN32_FIND_DATAW &findData)
: m_handle(handle)
, m_findData(findData)
, m_haveNext(true)
{
}
GpDirectoryCursor_Win32::~GpDirectoryCursor_Win32()
{
FindClose(m_handle);
}
GpFileSystem_Win32::GpFileSystem_Win32()
{
// GP TODO: This shouldn't be static init since it allocates memory
m_executablePath[0] = 0;
PWSTR docsPath;
if (!FAILED(SHGetKnownFolderPath(FOLDERID_Documents, KF_FLAG_DEFAULT, nullptr, &docsPath)))
{
try
{
m_prefsDir = docsPath;
}
catch(...)
{
CoTaskMemFree(docsPath);
throw;
}
m_prefsDir.append(L"\\" GP_APPLICATION_NAME_W);
m_userHousesDir = m_prefsDir + L"\\Houses";
m_userSavesDir = m_prefsDir + L"\\SavedGames";
m_scoresDir = m_prefsDir + L"\\Scores";
m_logsDir = m_prefsDir + L"\\Logs";
m_fontCacheDir = m_prefsDir + L"\\FontCache";
CreateDirectoryW(m_prefsDir.c_str(), nullptr);
CreateDirectoryW(m_scoresDir.c_str(), nullptr);
CreateDirectoryW(m_userHousesDir.c_str(), nullptr);
CreateDirectoryW(m_userSavesDir.c_str(), nullptr);
CreateDirectoryW(m_logsDir.c_str(), nullptr);
CreateDirectoryW(m_fontCacheDir.c_str(), nullptr);
m_prefsDir.append(L"\\");
m_scoresDir.append(L"\\");
m_userHousesDir.append(L"\\");
m_userSavesDir.append(L"\\");
m_logsDir.append(L"\\");
m_fontCacheDir.append(L"\\");
}
DWORD modulePathSize = GetModuleFileNameW(nullptr, m_executablePath, MAX_PATH);
if (modulePathSize == MAX_PATH || modulePathSize == 0)
m_executablePath[0] = 0;
size_t currentPathLength = wcslen(m_executablePath);
for (;;)
{
while (currentPathLength > 0 && m_executablePath[currentPathLength - 1] != '\\')
currentPathLength--;
m_executablePath[currentPathLength] = 0;
if (currentPathLength + 11 > MAX_PATH)
{
// "Resources" append is a longer path than the executable
continue;
}
if (wcscat_s(m_executablePath, L"Resources"))
{
currentPathLength = 0;
break;
}
if (PathFileExistsW(m_executablePath) && PathIsDirectoryW(m_executablePath))
{
m_executablePath[currentPathLength] = 0;
break;
}
else
currentPathLength--;
}
if (currentPathLength > 0)
{
m_packagedDir = std::wstring(m_executablePath) + L"Packaged\\";
m_housesDir = std::wstring(m_executablePath) + L"Packaged\\Houses\\";
m_resourcesDir = std::wstring(m_executablePath) + L"Resources\\";
}
}
bool GpFileSystem_Win32::FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path)
{
wchar_t winPath[MAX_PATH + 1];
if (!ResolvePath(virtualDirectory, &path, 1, winPath))
return false;
return PathFileExistsW(winPath) != 0;
}
bool GpFileSystem_Win32::FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool *exists)
{
wchar_t winPath[MAX_PATH + 1];
if (!ResolvePath(virtualDirectory, &path, 1, winPath))
{
*exists = false;
return false;
}
DWORD attribs = GetFileAttributesW(winPath);
if (attribs == INVALID_FILE_ATTRIBUTES)
{
*exists = false;
return false;
}
*exists = true;
return (attribs & FILE_ATTRIBUTE_READONLY) != 0;
}
GpIOStream *GpFileSystem_Win32::OpenFileNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, bool writeAccess, GpFileCreationDisposition_t createDisposition)
{
wchar_t winPath[MAX_PATH + 1];
if (!ResolvePath(virtualDirectory, paths, numPaths, winPath))
return false;
const DWORD desiredAccess = writeAccess ? (GENERIC_WRITE | GENERIC_READ) : GENERIC_READ;
DWORD winCreationDisposition = 0;
switch (createDisposition)
{
case GpFileCreationDispositions::kCreateOrOverwrite:
winCreationDisposition = CREATE_ALWAYS;
break;
case GpFileCreationDispositions::kCreateNew:
winCreationDisposition = CREATE_NEW;
break;
case GpFileCreationDispositions::kCreateOrOpen:
winCreationDisposition = OPEN_ALWAYS;
break;
case GpFileCreationDispositions::kOpenExisting:
winCreationDisposition = OPEN_EXISTING;
break;
case GpFileCreationDispositions::kOverwriteExisting:
winCreationDisposition = TRUNCATE_EXISTING;
break;
default:
return false;
}
HANDLE h = CreateFileW(winPath, desiredAccess, FILE_SHARE_READ, nullptr, winCreationDisposition, FILE_ATTRIBUTE_NORMAL, nullptr);
if (h == INVALID_HANDLE_VALUE)
return false;
return new GpFileStream_Win32(h, true, writeAccess, true);
}
bool GpFileSystem_Win32::DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed)
{
wchar_t winPath[MAX_PATH + 1];
if (!ResolvePath(virtualDirectory, &path, 1, winPath))
return false;
if (DeleteFileW(winPath))
{
existed = true;
return true;
}
DWORD err = GetLastError();
if (err == ERROR_FILE_NOT_FOUND)
existed = false;
else
existed = true;
return false;
}
PortabilityLayer::HostDirectoryCursor *GpFileSystem_Win32::ScanDirectoryNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths)
{
wchar_t winPath[MAX_PATH + 2];
const char **expandedPaths = static_cast<const char**>(malloc(sizeof(const char*) * (numPaths + 1)));
if (!expandedPaths)
return nullptr;
for (size_t i = 0; i < numPaths; i++)
expandedPaths[i] = paths[i];
expandedPaths[numPaths] = "*";
const bool isPathResolved = ResolvePath(virtualDirectory, expandedPaths, numPaths + 1, winPath);
free(expandedPaths);
if (!isPathResolved)
return nullptr;
WIN32_FIND_DATAW findData;
HANDLE ff = FindFirstFileW(winPath, &findData);
if (ff == INVALID_HANDLE_VALUE)
return nullptr;
return GpDirectoryCursor_Win32::Create(ff, findData);
}
bool GpFileSystem_Win32::ValidateFilePathUnicodeChar(uint32_t c) const
{
if (c >= '0' && c <= '9')
return true;
if (c == '_' || c == '\'')
return true;
if (c == ' ')
return true;
if (c >= 'a' && c <= 'z')
return true;
if (c >= 'A' && c <= 'Z')
return true;
return false;
}
bool GpFileSystem_Win32::IsVirtualDirectoryLooseResources(PortabilityLayer::VirtualDirectory_t virtualDir) const
{
return false;
}
void GpFileSystem_Win32::SetMainThreadRelay(IGpThreadRelay *relay)
{
(void)relay;
}
void GpFileSystem_Win32::SetDelayCallback(GpFileSystem_Win32::DelayCallback_t delayCallback)
{
}
bool GpFileSystem_Win32::ValidateFilePath(const char *str, size_t length) const
{
for (size_t i = 0; i < length; i++)
{
const char c = str[i];
if (c >= '0' && c <= '9')
continue;
if (c == '_' || c == '.' || c == '\'')
continue;
if (c == ' ' && i != 0 && i != length - 1)
continue;
if (c >= 'a' && c <= 'z')
continue;
if (c >= 'A' && c <= 'Z')
continue;
return false;
}
const char *bannedNames[] =
{
"CON",
"PRN",
"AUX",
"NUL",
"COM1",
"COM2",
"COM3",
"COM4",
"COM5",
"COM6",
"COM7",
"COM8",
"COM9",
"LPT1",
"LPT2",
"LPT3",
"LPT4",
"LPT5",
"LPT6",
"LPT7",
"LPT8",
"LPT9"
};
size_t nameLengthWithoutExt = length;
for (size_t i = 0; i < length; i++)
{
if (str[i] == '.')
{
nameLengthWithoutExt = i;
break;
}
}
const size_t numBannedNames = sizeof(bannedNames) / sizeof(bannedNames[0]);
for (size_t i = 0; i < numBannedNames; i++)
{
const char *bannedName = bannedNames[i];
const size_t banLength = strlen(bannedName);
if (banLength == nameLengthWithoutExt)
{
bool isBanned = true;
for (size_t j = 0; j < banLength; j++)
{
char checkCH = str[j];
if (checkCH >= 'a' && checkCH <= 'z')
checkCH += ('A' - 'a');
if (bannedName[j] != checkCH)
{
isBanned = false;
break;
}
}
if (isBanned)
return false;
}
}
return true;
}
const wchar_t *GpFileSystem_Win32::GetBasePath() const
{
return m_executablePath;
}
GpFileSystem_Win32 *GpFileSystem_Win32::GetInstance()
{
return &ms_instance;
}
bool GpFileSystem_Win32::ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, wchar_t *outPath)
{
const wchar_t *baseDir = nullptr;
switch (virtualDirectory)
{
case PortabilityLayer::VirtualDirectories::kApplicationData:
baseDir = m_packagedDir.c_str();
break;
case PortabilityLayer::VirtualDirectories::kGameData:
baseDir = m_housesDir.c_str();
break;
case PortabilityLayer::VirtualDirectories::kUserData:
baseDir = m_userHousesDir.c_str();
break;
case PortabilityLayer::VirtualDirectories::kUserSaves:
baseDir = m_userSavesDir.c_str();
break;
case PortabilityLayer::VirtualDirectories::kPrefs:
baseDir = m_prefsDir.c_str();
break;
case PortabilityLayer::VirtualDirectories::kFonts:
baseDir = m_resourcesDir.c_str();
break;
case PortabilityLayer::VirtualDirectories::kHighScores:
baseDir = m_scoresDir.c_str();
break;
case PortabilityLayer::VirtualDirectories::kLogs:
baseDir = m_logsDir.c_str();
break;
case PortabilityLayer::VirtualDirectories::kFontCache:
baseDir = m_fontCacheDir.c_str();
break;
default:
return false;
}
if (baseDir == nullptr)
return false;
const size_t baseDirLen = wcslen(baseDir);
memcpy(outPath, baseDir, sizeof(wchar_t) * baseDirLen);
outPath[baseDirLen] = static_cast<wchar_t>(0);
for (size_t i = 0; i < numPaths; i++)
{
size_t outDirLen = wcslen(outPath);
if (i != 0)
{
if (baseDirLen >= MAX_PATH || MAX_PATH - baseDirLen < 1)
return false;
outPath[outDirLen++] = '\\';
}
const char *path = paths[i];
const size_t pathLen = strlen(path);
if (baseDirLen >= MAX_PATH || MAX_PATH - baseDirLen < pathLen)
return false;
for (size_t j = 0; j < pathLen; j++)
{
char c = path[j];
if (c == '/')
c = '\\';
outPath[outDirLen + j] = static_cast<wchar_t>(c);
}
outPath[outDirLen + pathLen] = static_cast<wchar_t>(0);
}
return true;
}
GpFileSystem_Win32 GpFileSystem_Win32::ms_instance;

View File

@@ -1,48 +0,0 @@
#pragma once
#include "HostFileSystem.h"
#include "GpCoreDefs.h"
#include "GpWindows.h"
#include <string>
class GpFileSystem_Win32 final : public PortabilityLayer::HostFileSystem
{
public:
GpFileSystem_Win32();
bool FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path) override;
bool FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool *exists) override;
GpIOStream *OpenFileNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, bool writeAccess, GpFileCreationDisposition_t createDisposition) override;
bool DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed) override;
PortabilityLayer::HostDirectoryCursor *ScanDirectoryNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths) override;
bool ValidateFilePath(const char *path, size_t sz) const override;
bool ValidateFilePathUnicodeChar(uint32_t ch) const override;
bool IsVirtualDirectoryLooseResources(PortabilityLayer::VirtualDirectory_t virtualDir) const override;
void SetMainThreadRelay(IGpThreadRelay *relay) override;
void SetDelayCallback(DelayCallback_t delayCallback) override;
const wchar_t *GetBasePath() const;
static GpFileSystem_Win32 *GetInstance();
private:
bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, wchar_t *outPath);
std::wstring m_prefsDir;
std::wstring m_scoresDir;
std::wstring m_packagedDir;
std::wstring m_housesDir;
std::wstring m_logsDir;
std::wstring m_userHousesDir;
std::wstring m_userSavesDir;
std::wstring m_resourcesDir;
std::wstring m_fontCacheDir;
wchar_t m_executablePath[MAX_PATH];
static GpFileSystem_Win32 ms_instance;
};

View File

@@ -1,113 +0,0 @@
#include "GpLogDriver_Win32.h"
#include "GpFileSystem_Win32.h"
#include "GpApplicationName.h"
#include "GpIOStream.h"
GpLogDriver_Win32::GpLogDriver_Win32()
: m_stream(nullptr)
, m_isInitialized(false)
{
}
void GpLogDriver_Win32::Init()
{
ms_instance.InitInternal();
}
void GpLogDriver_Win32::VPrintf(Category category, const char *fmt, va_list args)
{
size_t fmtSize = 0;
bool hasFormatting = false;
for (const char *fmtCheck = fmt; *fmtCheck; fmtCheck++)
{
if (*fmtCheck == '%')
hasFormatting = true;
fmtSize++;
}
SYSTEMTIME sysTime;
GetSystemTime(&sysTime);
char timestampBuffer[64];
sprintf(timestampBuffer, "[%02d:%02d:%02d:%03d] ", sysTime.wHour, sysTime.wMinute, sysTime.wSecond, sysTime.wMilliseconds);
m_stream->Write(timestampBuffer, strlen(timestampBuffer));
const char *debugTag = "";
switch (category)
{
case Category_Warning:
debugTag = "[WARNING] ";
break;
case Category_Error:
debugTag = "[ERROR] ";
break;
};
if (debugTag[0])
m_stream->Write(debugTag, strlen(debugTag));
if (!hasFormatting)
m_stream->Write(fmt, fmtSize);
else
{
int formattedSize = vsnprintf(nullptr, 0, fmt, args);
if (formattedSize <= 0)
return;
char *charBuff = static_cast<char*>(malloc(formattedSize + 1));
if (!charBuff)
return;
vsnprintf(charBuff, formattedSize + 1, fmt, args);
m_stream->Write(charBuff, formattedSize);
free(charBuff);
}
m_stream->Write("\n", 1);
m_stream->Flush();
}
void GpLogDriver_Win32::Shutdown()
{
if (m_stream)
m_stream->Close();
}
GpLogDriver_Win32 *GpLogDriver_Win32::GetInstance()
{
if (ms_instance.m_isInitialized)
return &ms_instance;
else
return nullptr;
}
void GpLogDriver_Win32::InitInternal()
{
SYSTEMTIME utcTime;
GetSystemTime(&utcTime);
char logFileName[256];
sprintf(logFileName, GP_APPLICATION_NAME "-%04d-%02d-%02d_%02d-%02d_%02d.txt", utcTime.wYear, utcTime.wMonth, utcTime.wDay, utcTime.wHour, utcTime.wMinute, utcTime.wSecond);
m_stream = GpFileSystem_Win32::GetInstance()->OpenFile(PortabilityLayer::VirtualDirectories::kLogs, logFileName, true, GpFileCreationDispositions::kCreateOrOverwrite);
if (m_stream)
{
this->Printf(IGpLogDriver::Category_Information, GP_APPLICATION_NAME " build " __TIMESTAMP__);
#if !GP_DEBUG_CONFIG
this->Printf(IGpLogDriver::Category_Information, "Configuration: Release");
#else
this->Printf(IGpLogDriver::Category_Information, "Configuration: Debug");
#endif
m_isInitialized = true;
}
}
GpLogDriver_Win32 GpLogDriver_Win32::ms_instance;

View File

@@ -1,26 +0,0 @@
#pragma once
#include "IGpLogDriver.h"
class GpIOStream;
class GpLogDriver_Win32 : public IGpLogDriver
{
public:
GpLogDriver_Win32();
static void Init();
void VPrintf(Category category, const char *fmt, va_list args) override;
void Shutdown() override;
static GpLogDriver_Win32 *GetInstance();
private:
void InitInternal();
GpIOStream *m_stream;
bool m_isInitialized;
static GpLogDriver_Win32 ms_instance;
};

View File

@@ -1,471 +0,0 @@
#include "GpMain.h"
#include "GpAudioDriverFactory.h"
#include "GpBWCursor_Win32.h"
#include "GpColorCursor_Win32.h"
#include "GpDisplayDriverFactory.h"
#include "GpGlobalConfig.h"
#include "GpFiber_Win32.h"
#include "GpFileSystem_Win32.h"
#include "GpLogDriver_Win32.h"
#include "GpFontHandlerFactory.h"
#include "GpInputDriverFactory.h"
#include "GpAppInterface.h"
#include "GpSystemServices_Win32.h"
#include "GpVOSEvent.h"
#include "IGpVOSEventQueue.h"
#include "HostFileSystem.h"
#include "GpWindows.h"
#include "resource.h"
#include <shellapi.h>
#include <stdio.h>
#include <windowsx.h>
GpWindowsGlobals g_gpWindowsGlobals;
extern "C" __declspec(dllimport) IGpAudioDriver *GpDriver_CreateAudioDriver_XAudio2(const GpAudioDriverProperties &properties);
extern "C" __declspec(dllimport) IGpDisplayDriver *GpDriver_CreateDisplayDriver_D3D11(const GpDisplayDriverProperties &properties);
extern "C" __declspec(dllimport) IGpInputDriver *GpDriver_CreateInputDriver_XInput(const GpInputDriverProperties &properties);
extern "C" __declspec(dllimport) IGpFontHandler *GpDriver_CreateFontHandler_FreeType2(const GpFontHandlerProperties &properties);
static void PostMouseEvent(IGpVOSEventQueue *eventQueue, GpMouseEventType_t eventType, GpMouseButton_t button, int32_t x, int32_t y, float pixelScaleX, float pixelScaleY)
{
if (GpVOSEvent *evt = eventQueue->QueueEvent())
{
evt->m_eventType = GpVOSEventTypes::kMouseInput;
GpMouseInputEvent &mEvent = evt->m_event.m_mouseInputEvent;
mEvent.m_button = button;
mEvent.m_x = x;
mEvent.m_y = y;
mEvent.m_eventType = eventType;
if (pixelScaleX != 1.0f)
mEvent.m_x = static_cast<int32_t>(static_cast<float>(x) / pixelScaleX);
if (pixelScaleY != 1.0f)
mEvent.m_y = static_cast<int32_t>(static_cast<float>(y) / pixelScaleX);
}
}
static bool IdentifyVKey(const WPARAM &wparam, const LPARAM &lparam, GpKeyIDSubset_t &outSubset, GpKeyboardInputEvent::KeyUnion &outKey)
{
switch (wparam)
{
case VK_ESCAPE:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kEscape;
break;
case VK_PRINT:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kPrintScreen;
break;
case VK_SCROLL:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kScrollLock;
break;
case VK_PAUSE:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kPause;
break;
case VK_INSERT:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kInsert;
break;
case VK_HOME:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kHome;
break;
case VK_PRIOR:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kPageUp;
break;
case VK_NEXT:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kPageDown;
break;
case VK_DELETE:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kDelete;
break;
case VK_TAB:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kTab;
break;
case VK_END:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kEnd;
break;
case VK_BACK:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kBackspace;
break;
case VK_CAPITAL:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kCapsLock;
break;
case VK_RETURN:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kEnter;
break;
case VK_SHIFT:
{
UINT vkey = MapVirtualKeyW((lparam >> 16) & 0xff, MAPVK_VSC_TO_VK_EX);
if (vkey == VK_LSHIFT || vkey == VK_SHIFT)
{
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kLeftShift;
}
else if (vkey == VK_RSHIFT)
{
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kRightShift;
}
else
return false;
}
break;
case VK_RSHIFT:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kRightShift;
break;
case VK_CONTROL:
outSubset = GpKeyIDSubsets::kSpecial;
if (lparam & 0x01000000)
outKey.m_specialKey = GpKeySpecials::kRightCtrl;
else
outKey.m_specialKey = GpKeySpecials::kLeftCtrl;
break;
case VK_MENU:
outSubset = GpKeyIDSubsets::kSpecial;
if (lparam & 0x01000000)
outKey.m_specialKey = GpKeySpecials::kRightAlt;
else
outKey.m_specialKey = GpKeySpecials::kLeftAlt;
break;
case VK_NUMLOCK:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kNumLock;
break;
case VK_NUMPAD0:
case VK_NUMPAD1:
case VK_NUMPAD2:
case VK_NUMPAD3:
case VK_NUMPAD4:
case VK_NUMPAD5:
case VK_NUMPAD6:
case VK_NUMPAD7:
case VK_NUMPAD8:
case VK_NUMPAD9:
outSubset = GpKeyIDSubsets::kNumPadNumber;
outKey.m_numPadNumber = static_cast<uint8_t>(wparam - VK_NUMPAD0);
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
case 'A':
case 'B':
case 'C':
case 'D':
case 'E':
case 'F':
case 'G':
case 'H':
case 'I':
case 'J':
case 'K':
case 'L':
case 'M':
case 'N':
case 'O':
case 'P':
case 'Q':
case 'R':
case 'S':
case 'T':
case 'U':
case 'V':
case 'W':
case 'X':
case 'Y':
case 'Z':
outSubset = GpKeyIDSubsets::kASCII;
outKey.m_asciiChar = static_cast<char>(wparam);
break;
case VK_F1:
case VK_F2:
case VK_F3:
case VK_F4:
case VK_F5:
case VK_F6:
case VK_F7:
case VK_F8:
case VK_F9:
case VK_F10:
case VK_F11:
case VK_F12:
case VK_F13:
case VK_F14:
case VK_F15:
case VK_F16:
case VK_F17:
case VK_F18:
case VK_F19:
case VK_F20:
case VK_F21:
case VK_F22:
case VK_F23:
case VK_F24:
outSubset = GpKeyIDSubsets::kFKey;
outKey.m_fKey = static_cast<uint8_t>(wparam - VK_F1 + 1);
break;
case VK_OEM_COMMA:
outSubset = GpKeyIDSubsets::kASCII;
outKey.m_asciiChar = ',';
break;
case VK_OEM_MINUS:
outSubset = GpKeyIDSubsets::kASCII;
outKey.m_asciiChar = '-';
break;
case VK_OEM_PERIOD:
outSubset = GpKeyIDSubsets::kASCII;
outKey.m_asciiChar = '.';
break;
case VK_OEM_PLUS:
outSubset = GpKeyIDSubsets::kASCII;
outKey.m_asciiChar = '+';
break;
case VK_UP:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kUpArrow;
break;
case VK_DOWN:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kDownArrow;
break;
case VK_LEFT:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kLeftArrow;
break;
case VK_RIGHT:
outSubset = GpKeyIDSubsets::kSpecial;
outKey.m_specialKey = GpKeySpecials::kRightArrow;
break;
default:
{
if (wparam >= VK_OEM_1 && wparam <= VK_OEM_102)
{
UINT charCode = MapVirtualKeyW(static_cast<UINT>(wparam), MAPVK_VK_TO_CHAR);
if (charCode == 0)
return false;
if (charCode < 128)
{
outSubset = GpKeyIDSubsets::kASCII;
outKey.m_asciiChar = static_cast<char>(charCode);
break;
}
else
{
outSubset = GpKeyIDSubsets::kUnicode;
outKey.m_unicodeChar = charCode;;
break;
}
}
}
return false;
}
return true;
}
static void PostKeyboardEvent(IGpVOSEventQueue *eventQueue, GpKeyboardInputEventType_t eventType, GpKeyIDSubset_t subset, const GpKeyboardInputEvent::KeyUnion &key, uint32_t repeatCount)
{
if (GpVOSEvent *evt = eventQueue->QueueEvent())
{
evt->m_eventType = GpVOSEventTypes::kKeyboardInput;
GpKeyboardInputEvent &mEvent = evt->m_event.m_keyboardInputEvent;
mEvent.m_key = key;
mEvent.m_eventType = eventType;
mEvent.m_keyIDSubset = subset;
mEvent.m_repeatCount = repeatCount;
}
}
static void TranslateWindowsMessage(const MSG *msg, IGpVOSEventQueue *eventQueue, float pixelScaleX, float pixelScaleY)
{
WPARAM wParam = msg->wParam;
LPARAM lParam = msg->lParam;
switch (msg->message)
{
case WM_LBUTTONDOWN:
PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kLeft, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY);
break;
case WM_LBUTTONUP:
PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kLeft, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY);
break;
case WM_MBUTTONDOWN:
PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kMiddle, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY);
break;
case WM_MBUTTONUP:
PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kMiddle, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY);
break;
case WM_RBUTTONDOWN:
PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kRight, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY);
break;
case WM_RBUTTONUP:
PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kRight, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY);
break;
case WM_XBUTTONDOWN:
if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kX1, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY);
else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON2)
PostMouseEvent(eventQueue, GpMouseEventTypes::kDown, GpMouseButtons::kX2, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY);
break;
case WM_XBUTTONUP:
if (GET_XBUTTON_WPARAM(wParam) == XBUTTON1)
PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kX1, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY);
else if (GET_XBUTTON_WPARAM(wParam) == XBUTTON2)
PostMouseEvent(eventQueue, GpMouseEventTypes::kUp, GpMouseButtons::kX2, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY);
break;
case WM_MOUSEMOVE:
PostMouseEvent(eventQueue, GpMouseEventTypes::kMove, GpMouseButtons::kNone, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pixelScaleX, pixelScaleY);
break;
case WM_MOUSELEAVE:
PostMouseEvent(eventQueue, GpMouseEventTypes::kLeave, GpMouseButtons::kNone, 0, 0, pixelScaleX, pixelScaleY);
break;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
{
GpKeyIDSubset_t subset;
GpKeyboardInputEvent::KeyUnion key;
bool isRepeat = ((lParam & 0x40000000) != 0);
const GpKeyboardInputEventType_t keyEventType = isRepeat ? GpKeyboardInputEventTypes::kAuto : GpKeyboardInputEventTypes::kDown;
if (IdentifyVKey(wParam, lParam, subset, key))
PostKeyboardEvent(eventQueue, keyEventType, subset, key, static_cast<uint32_t>(lParam & 0xffff));
(void)TranslateMessage(msg);
}
break;
case WM_KEYUP:
case WM_SYSKEYUP:
{
GpKeyIDSubset_t subset;
GpKeyboardInputEvent::KeyUnion key;
if (IdentifyVKey(wParam, lParam, subset, key))
PostKeyboardEvent(eventQueue, GpKeyboardInputEventTypes::kUp, subset, key, (lParam & 0xffff));
}
break;
case WM_CHAR:
case WM_UNICHAR:
{
bool isRepeat = ((lParam & 0x4000000) != 0);
const GpKeyboardInputEventType_t keyEventType = isRepeat ? GpKeyboardInputEventTypes::kAutoChar : GpKeyboardInputEventTypes::kDownChar;
GpKeyboardInputEvent::KeyUnion key;
GpKeyIDSubset_t subset = GpKeyIDSubsets::kASCII;
if (wParam <= 128)
key.m_asciiChar = static_cast<char>(wParam);
else
{
subset = GpKeyIDSubsets::kUnicode;
key.m_unicodeChar = static_cast<uint32_t>(wParam);
}
PostKeyboardEvent(eventQueue, keyEventType, subset, key, (lParam & 0xffff));
}
break;
case WM_QUIT:
{
if (GpVOSEvent *evt = eventQueue->QueueEvent())
evt->m_eventType = GpVOSEventTypes::kQuit;
}
break;
default:
break;
}
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
(void)lpCmdLine;
LPWSTR cmdLine = GetCommandLineW();
int nArgs;
LPWSTR *cmdLineArgs = CommandLineToArgvW(cmdLine, &nArgs);
for (int i = 1; i < nArgs; i++)
{
if (!wcscmp(cmdLineArgs[i], L"-diagnostics"))
GpLogDriver_Win32::Init();
}
IGpLogDriver *logger = GpLogDriver_Win32::GetInstance();
GpAppInterface_Get()->PL_HostFileSystem_SetInstance(GpFileSystem_Win32::GetInstance());
GpAppInterface_Get()->PL_HostSystemServices_SetInstance(GpSystemServices_Win32::GetInstance());
GpAppInterface_Get()->PL_HostLogDriver_SetInstance(GpLogDriver_Win32::GetInstance());
g_gpWindowsGlobals.m_hInstance = hInstance;
g_gpWindowsGlobals.m_hPrevInstance = hPrevInstance;
g_gpWindowsGlobals.m_cmdLine = cmdLine;
g_gpWindowsGlobals.m_cmdLineArgc = nArgs;
g_gpWindowsGlobals.m_cmdLineArgv = cmdLineArgs;
g_gpWindowsGlobals.m_nCmdShow = nCmdShow;
g_gpWindowsGlobals.m_baseDir = GpFileSystem_Win32::GetInstance()->GetBasePath();
g_gpWindowsGlobals.m_hwnd = nullptr;
g_gpWindowsGlobals.m_hIcon = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_ICON1));
g_gpWindowsGlobals.m_hIconSm = LoadIconW(hInstance, MAKEINTRESOURCEW(IDI_ICON2));
g_gpWindowsGlobals.m_createFiberFunc = GpFiber_Win32::Create;
g_gpWindowsGlobals.m_createBWCursorFunc = GpBWCursor_Win32::Create;
g_gpWindowsGlobals.m_createColorCursorFunc = GpColorCursor_Win32::Create;
g_gpWindowsGlobals.m_translateWindowsMessageFunc = TranslateWindowsMessage;
g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_D3D11;
g_gpGlobalConfig.m_audioDriverType = EGpAudioDriverType_XAudio2;
g_gpGlobalConfig.m_fontHandlerType = EGpFontHandlerType_FreeType2;
EGpInputDriverType inputDrivers[] =
{
EGpInputDriverType_XInput
};
g_gpGlobalConfig.m_inputDriverTypes = inputDrivers;
g_gpGlobalConfig.m_numInputDrivers = sizeof(inputDrivers) / sizeof(inputDrivers[0]);
g_gpGlobalConfig.m_osGlobals = &g_gpWindowsGlobals;
g_gpGlobalConfig.m_logger = logger;
g_gpGlobalConfig.m_systemServices = GpSystemServices_Win32::GetInstance();
GpDisplayDriverFactory::RegisterDisplayDriverFactory(EGpDisplayDriverType_D3D11, GpDriver_CreateDisplayDriver_D3D11);
GpAudioDriverFactory::RegisterAudioDriverFactory(EGpAudioDriverType_XAudio2, GpDriver_CreateAudioDriver_XAudio2);
GpInputDriverFactory::RegisterInputDriverFactory(EGpInputDriverType_XInput, GpDriver_CreateInputDriver_XInput);
GpFontHandlerFactory::RegisterFontHandlerFactory(EGpFontHandlerType_FreeType2, GpDriver_CreateFontHandler_FreeType2);
if (logger)
logger->Printf(IGpLogDriver::Category_Information, "Windows environment configured, starting up");
int returnCode = GpMain::Run();
if (logger)
logger->Printf(IGpLogDriver::Category_Information, "Windows environment exited with code %i, cleaning up", returnCode);
LocalFree(cmdLineArgs);
return returnCode;
}

View File

@@ -1,42 +0,0 @@
#include "GpMutex_Win32.h"
#include "GpWindows.h"
#include <stdlib.h>
#include <new>
void GpMutex_Win32::Destroy()
{
this->~GpMutex_Win32();
free(this);
}
void GpMutex_Win32::Lock()
{
EnterCriticalSection(&m_critSection);
}
void GpMutex_Win32::Unlock()
{
LeaveCriticalSection(&m_critSection);
}
GpMutex_Win32 *GpMutex_Win32::Create()
{
void *storage = malloc(sizeof(GpMutex_Win32));
if (!storage)
return nullptr;
return new (storage) GpMutex_Win32();
}
GpMutex_Win32::GpMutex_Win32()
{
InitializeCriticalSection(&m_critSection);
}
GpMutex_Win32::~GpMutex_Win32()
{
DeleteCriticalSection(&m_critSection);
}

View File

@@ -1,21 +0,0 @@
#pragma once
#include "HostMutex.h"
#include "GpWindows.h"
class GpMutex_Win32 final : public PortabilityLayer::HostMutex
{
public:
void Destroy() override;
void Lock() override;
void Unlock() override;
static GpMutex_Win32 *Create();
private:
const GpMutex_Win32();
~GpMutex_Win32();
CRITICAL_SECTION m_critSection;
};

View File

@@ -1,177 +0,0 @@
#include "GpSystemServices_Win32.h"
#include "GpMutex_Win32.h"
#include "GpThreadEvent_Win32.h"
#include <assert.h>
#pragma push_macro("CreateMutex")
#ifdef CreateMutex
#undef CreateMutex
#endif
struct GpSystemServices_Win32_ThreadStartParams
{
GpSystemServices_Win32::ThreadFunc_t m_threadFunc;
void *m_threadContext;
PortabilityLayer::HostThreadEvent *m_threadStartEvent;
};
static DWORD WINAPI StaticStartThread(LPVOID lpThreadParameter)
{
const GpSystemServices_Win32_ThreadStartParams *threadParams = static_cast<const GpSystemServices_Win32_ThreadStartParams*>(lpThreadParameter);
GpSystemServices_Win32::ThreadFunc_t threadFunc = threadParams->m_threadFunc;
void *threadContext = threadParams->m_threadContext;
PortabilityLayer::HostThreadEvent *threadStartEvent = threadParams->m_threadStartEvent;
threadStartEvent->Signal();
return threadFunc(threadContext);
}
GpSystemServices_Win32::GpSystemServices_Win32()
: m_isTouchscreenSimulation(false)
{
}
int64_t GpSystemServices_Win32::GetTime() const
{
SYSTEMTIME epochStart;
epochStart.wYear = 1904;
epochStart.wMonth = 1;
epochStart.wDayOfWeek = 5;
epochStart.wDay = 1;
epochStart.wHour = 0;
epochStart.wMinute = 0;
epochStart.wSecond = 0;
epochStart.wMilliseconds = 0;
FILETIME epochStartFT;
if (!SystemTimeToFileTime(&epochStart, &epochStartFT))
return 0;
FILETIME currentTime;
GetSystemTimeAsFileTime(&currentTime);
int64_t epochStart64 = (static_cast<int64_t>(epochStartFT.dwLowDateTime) & 0xffffffff) | (static_cast<int64_t>(epochStartFT.dwHighDateTime) << 32);
int64_t currentTime64 = (static_cast<int64_t>(currentTime.dwLowDateTime) & 0xffffffff) | (static_cast<int64_t>(currentTime.dwHighDateTime) << 32);
return (currentTime64 - epochStart64) / 10000000;
}
void GpSystemServices_Win32::GetLocalDateTime(unsigned int &year, unsigned int &month, unsigned int &day, unsigned int &hour, unsigned int &minute, unsigned int &second) const
{
SYSTEMTIME localTime;
GetLocalTime(&localTime);
year = localTime.wYear;
month = localTime.wMonth;
day = localTime.wDay;
hour = localTime.wHour;
minute = localTime.wMinute;
second = localTime.wSecond;
}
PortabilityLayer::HostMutex *GpSystemServices_Win32::CreateMutex()
{
return GpMutex_Win32::Create();
}
PortabilityLayer::HostMutex *GpSystemServices_Win32::CreateRecursiveMutex()
{
return GpMutex_Win32::Create();
}
PortabilityLayer::HostThreadEvent *GpSystemServices_Win32::CreateThreadEvent(bool autoReset, bool startSignaled)
{
return GpThreadEvent_Win32::Create(autoReset, startSignaled);
}
void *GpSystemServices_Win32::CreateThread(ThreadFunc_t threadFunc, void *context)
{
PortabilityLayer::HostThreadEvent *evt = CreateThreadEvent(true, false);
if (!evt)
return nullptr;
GpSystemServices_Win32_ThreadStartParams startParams;
startParams.m_threadContext = context;
startParams.m_threadFunc = threadFunc;
startParams.m_threadStartEvent = evt;
HANDLE threadHdl = ::CreateThread(nullptr, 0, StaticStartThread, &startParams, 0, nullptr);
if (threadHdl == nullptr)
{
evt->Destroy();
return nullptr;
}
evt->Wait();
evt->Destroy();
return threadHdl;
}
uint64_t GpSystemServices_Win32::GetFreeMemoryCosmetic() const
{
MEMORYSTATUSEX memStatus;
memset(&memStatus, 0, sizeof(memStatus));
memStatus.dwLength = sizeof(memStatus);
if (!GlobalMemoryStatusEx(&memStatus))
return 0;
return memStatus.ullAvailPhys;
}
void GpSystemServices_Win32::Beep() const
{
MessageBeep(MB_OK);
}
bool GpSystemServices_Win32::IsTouchscreen() const
{
return m_isTouchscreenSimulation;
}
bool GpSystemServices_Win32::IsUsingMouseAsTouch() const
{
return m_isTouchscreenSimulation;
}
bool GpSystemServices_Win32::IsTextInputObstructive() const
{
return false;
}
unsigned int GpSystemServices_Win32::GetCPUCount() const
{
SYSTEM_INFO sysInfo;
GetSystemInfo(&sysInfo);
return sysInfo.dwNumberOfProcessors;
}
void GpSystemServices_Win32::SetTextInputEnabled(bool isEnabled)
{
(void)isEnabled;
}
bool GpSystemServices_Win32::IsTextInputEnabled() const
{
return true;
}
void GpSystemServices_Win32::SetTouchscreenSimulation(bool isTouchscreenSimulation)
{
m_isTouchscreenSimulation = isTouchscreenSimulation;
}
GpSystemServices_Win32 *GpSystemServices_Win32::GetInstance()
{
return &ms_instance;
}
GpSystemServices_Win32 GpSystemServices_Win32::ms_instance;
#pragma pop_macro("CreateMutex")

View File

@@ -1,49 +0,0 @@
#pragma once
#include "HostSystemServices.h"
#include "GpCoreDefs.h"
#include "GpWindows.h"
#pragma push_macro("CreateMutex")
#ifdef CreateMutex
#undef CreateMutex
#endif
#pragma push_macro("CreateThread")
#ifdef CreateThread
#undef CreateThread
#endif
class GpSystemServices_Win32 final : public PortabilityLayer::HostSystemServices
{
public:
GpSystemServices_Win32();
int64_t GetTime() const override;
void GetLocalDateTime(unsigned int &year, unsigned int &month, unsigned int &day, unsigned int &hour, unsigned int &minute, unsigned int &second) const override;
PortabilityLayer::HostMutex *CreateMutex() override;
PortabilityLayer::HostMutex *CreateRecursiveMutex() override;
void *CreateThread(ThreadFunc_t threadFunc, void *context) override;
PortabilityLayer::HostThreadEvent *CreateThreadEvent(bool autoReset, bool startSignaled) override;
uint64_t GetFreeMemoryCosmetic() const override;
void Beep() const override;
bool IsTouchscreen() const override;
bool IsUsingMouseAsTouch() const override;
bool IsTextInputObstructive() const override;
unsigned int GetCPUCount() const override;
void SetTextInputEnabled(bool isEnabled) override;
bool IsTextInputEnabled() const override;
void SetTouchscreenSimulation(bool isTouchscreenSimulation);
static GpSystemServices_Win32 *GetInstance();
private:
bool m_isTouchscreenSimulation;
static GpSystemServices_Win32 ms_instance;
};
#pragma pop_macro("CreateMutex")
#pragma pop_macro("CreateThread")

View File

@@ -1,51 +0,0 @@
#include "GpThreadEvent_Win32.h"
#include <stdlib.h>
#include <new>
void GpThreadEvent_Win32::Wait()
{
WaitForSingleObject(m_event, INFINITE);
}
bool GpThreadEvent_Win32::WaitTimed(uint32_t msec)
{
return WaitForSingleObject(m_event, static_cast<DWORD>(msec)) == WAIT_OBJECT_0;
}
void GpThreadEvent_Win32::Signal()
{
SetEvent(m_event);
}
void GpThreadEvent_Win32::Destroy()
{
this->~GpThreadEvent_Win32();
free(this);
}
GpThreadEvent_Win32 *GpThreadEvent_Win32::Create(bool autoReset, bool startSignaled)
{
HANDLE handle = CreateEventA(nullptr, autoReset ? FALSE : TRUE, startSignaled ? TRUE : FALSE, nullptr);
if (handle == nullptr)
return nullptr;
void *storage = malloc(sizeof(GpThreadEvent_Win32));
if (!storage)
{
CloseHandle(handle);
return nullptr;
}
return new (storage) GpThreadEvent_Win32(handle);
}
GpThreadEvent_Win32::GpThreadEvent_Win32(const HANDLE &handle)
: m_event(handle)
{
}
GpThreadEvent_Win32::~GpThreadEvent_Win32()
{
CloseHandle(m_event);
}

View File

@@ -1,22 +0,0 @@
#pragma once
#include "HostThreadEvent.h"
#include "GpWindows.h"
class GpThreadEvent_Win32 final : public PortabilityLayer::HostThreadEvent
{
public:
void Wait() override;
bool WaitTimed(uint32_t msec) override;
void Signal() override;
void Destroy() override;
static GpThreadEvent_Win32 *Create(bool autoReset, bool startSignaled);
private:
explicit GpThreadEvent_Win32(const HANDLE &handle);
~GpThreadEvent_Win32();
HANDLE m_event;
};

View File

@@ -1,17 +0,0 @@
//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by GpD3D.rc
//
#define IDI_ICON1 101
#define IDI_ICON2 102
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 103
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1001
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View File

@@ -1,5 +0,0 @@
.idea
.gradle
gradle
local.properties
build

View File

@@ -1,5 +0,0 @@
Aerofoil - Google Play Store Distribution - Privacy Policy
------------------------------------------------------------------------------
The Aerofoil app does not collect or transmit any personal information,
sensitive information, or any other form of user data.

View File

@@ -1,4 +0,0 @@
.cxx
.externalNativeBuild
build
release

View File

@@ -1,77 +0,0 @@
def buildAsLibrary = project.hasProperty('BUILD_AS_LIBRARY');
def buildAsApplication = !buildAsLibrary
if (buildAsApplication) {
apply plugin: 'com.android.application'
}
else {
apply plugin: 'com.android.library'
}
android {
compileSdkVersion 29
defaultConfig {
if (buildAsApplication) {
applicationId "org.thecodedeposit.aerofoil"
}
minSdkVersion 16
targetSdkVersion 29
versionCode 4
versionName "1.0.9b2"
externalNativeBuild {
ndkBuild {
arguments "APP_PLATFORM=android-16"
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
// cmake {
// arguments "-DANDROID_APP_PLATFORM=android-16", "-DANDROID_STL=c++_static"
// // abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
// abiFilters 'arm64-v8a'
// }
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
if (!project.hasProperty('EXCLUDE_NATIVE_LIBS')) {
sourceSets.main {
jniLibs.srcDir 'libs'
}
externalNativeBuild {
ndkBuild {
path 'jni/Android.mk'
}
// cmake {
// path 'jni/CMakeLists.txt'
// }
}
}
lintOptions {
abortOnError false
}
if (buildAsLibrary) {
libraryVariants.all { variant ->
variant.outputs.each { output ->
def outputFile = output.outputFile
if (outputFile != null && outputFile.name.endsWith(".aar")) {
def fileName = "org.thecodedeposit.aerofoil.aar";
output.outputFile = new File(outputFile.parent, fileName);
}
}
}
}
aaptOptions {
noCompress 'gpa'
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
}
android.buildTypes.release.ndk.debugSymbolLevel = 'FULL'

View File

@@ -1,13 +0,0 @@
AerofoilSDL
Common
FreeType
GpApp
GpCommon
GpFontHandler_FreeType2
GpShell
MacRomanConversion
PortabilityLayer
rapidjson
SDL2
stb
zlib

View File

@@ -1 +0,0 @@
include $(call all-subdir-makefiles)

View File

@@ -1,10 +0,0 @@
# Uncomment this if you're using STL in your project
# You can find more information here:
# https://developer.android.com/ndk/guides/cpp-support
APP_STL := c++_shared
APP_ABI := armeabi-v7a arm64-v8a x86 x86_64
# Min runtime API level
APP_PLATFORM=android-16

View File

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

View File

@@ -1,30 +0,0 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := main
SDL_PATH := ../SDL
LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include \
$(LOCAL_PATH)/../GpShell \
$(LOCAL_PATH)/../GpCommon \
$(LOCAL_PATH)/../AerofoilSDL \
$(LOCAL_PATH)/../Common \
$(LOCAL_PATH)/../PortabilityLayer
LOCAL_CFLAGS := -DGP_DEBUG_CONFIG=0
# Add your application source files here...
LOCAL_SRC_FILES := \
GpMain_SDL_Android.cpp \
GpSystemServices_Android.cpp \
GpFileSystem_Android.cpp
LOCAL_SHARED_LIBRARIES := SDL2
LOCAL_STATIC_LIBRARIES := GpShell GpFontHandler_FreeType2 AerofoilSDL GpApp
LOCAL_LDLIBS := -lGLESv1_CM -lGLESv2 -llog
include $(BUILD_SHARED_LIBRARY)

View File

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

View File

@@ -1,5 +0,0 @@
#pragma once
struct GpAndroidGlobals
{
};

View File

@@ -1,942 +0,0 @@
#define _LARGEFILE64_SOURCE
#include "GpFileSystem_Android.h"
#include "GpIOStream.h"
#include "HostDirectoryCursor.h"
#include "HostSystemServices.h"
#include "HostMutex.h"
#include "IGpThreadRelay.h"
#include "VirtualDirectory.h"
#include "SDL.h"
#include "SDL_rwops.h"
#include <string>
#include <vector>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
#include <dirent.h>
#include <jni.h>
#include "UTF8.h"
JNIEXPORT void JNICALL nativePostSourceExportRequest(JNIEnv *env, jclass cls, jboolean cancelled, jint fd, jobject pfd);
static JNINativeMethod GpFileSystemAPI_tab[] =
{
{ "nativePostSourceExportRequest", "(ZILjava/lang/Object;)V", reinterpret_cast<void*>(nativePostSourceExportRequest) },
};
class GpFileStream_PFD final : public GpIOStream
{
public:
GpFileStream_PFD(GpFileSystem_Android *fs, int fd, jobject pfd, bool readOnly, bool writeOnly);
~GpFileStream_PFD();
size_t Read(void *bytesOut, size_t size) override;
size_t Write(const void *bytes, size_t size) override;
bool IsSeekable() const override;
bool IsReadOnly() const override;
bool IsWriteOnly() const override;
bool SeekStart(GpUFilePos_t loc) override;
bool SeekCurrent(GpFilePos_t loc) override;
bool SeekEnd(GpUFilePos_t loc) override;
bool Truncate(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
void Flush() override;
private:
GpFileSystem_Android *m_fs;
int m_fd;
jobject m_pfd;
bool m_readOnly;
bool m_writeOnly;
};
class GpFileStream_SDLRWops final : public GpIOStream
{
public:
GpFileStream_SDLRWops(SDL_RWops *f, bool readOnly, bool writeOnly);
~GpFileStream_SDLRWops();
size_t Read(void *bytesOut, size_t size) override;
size_t Write(const void *bytes, size_t size) override;
bool IsSeekable() const override;
bool IsReadOnly() const override;
bool IsWriteOnly() const override;
bool SeekStart(GpUFilePos_t loc) override;
bool SeekCurrent(GpFilePos_t loc) override;
bool SeekEnd(GpUFilePos_t loc) override;
bool Truncate(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
void Flush() override;
private:
SDL_RWops *m_rw;
bool m_isReadOnly;
bool m_isWriteOnly;
};
class GpFileStream_Android_File final : public GpIOStream
{
public:
GpFileStream_Android_File(FILE *f, int fd, bool readOnly, bool writeOnly);
~GpFileStream_Android_File();
size_t Read(void *bytesOut, size_t size) override;
size_t Write(const void *bytes, size_t size) override;
bool IsSeekable() const override;
bool IsReadOnly() const override;
bool IsWriteOnly() const override;
bool SeekStart(GpUFilePos_t loc) override;
bool SeekCurrent(GpFilePos_t loc) override;
bool SeekEnd(GpUFilePos_t loc) override;
bool Truncate(GpUFilePos_t loc) override;
GpUFilePos_t Size() const override;
GpUFilePos_t Tell() const override;
void Close() override;
void Flush() override;
private:
FILE *m_f;
int m_fd;
bool m_seekable;
bool m_isReadOnly;
bool m_isWriteOnly;
};
GpFileStream_PFD::GpFileStream_PFD(GpFileSystem_Android *fs, int fd, jobject pfd, bool readOnly, bool writeOnly)
: m_fs(fs)
, m_fd(fd)
, m_readOnly(readOnly)
, m_writeOnly(writeOnly)
, m_pfd(pfd)
{
}
GpFileStream_PFD::~GpFileStream_PFD()
{
m_fs->ClosePFD(m_pfd);
}
size_t GpFileStream_PFD::Read(void *bytesOut, size_t size)
{
if (m_writeOnly)
return 0;
return read(m_fd, bytesOut, size);
}
size_t GpFileStream_PFD::Write(const void *bytes, size_t size)
{
if (m_readOnly)
return 0;
return write(m_fd, bytes, size);
}
bool GpFileStream_PFD::IsSeekable() const
{
return true;
}
bool GpFileStream_PFD::IsReadOnly() const
{
return m_readOnly;
}
bool GpFileStream_PFD::IsWriteOnly() const
{
return m_writeOnly;
}
bool GpFileStream_PFD::SeekStart(GpUFilePos_t loc)
{
return lseek64(m_fd, loc, SEEK_SET) >= 0;
}
bool GpFileStream_PFD::SeekCurrent(GpFilePos_t loc)
{
return lseek64(m_fd, loc, SEEK_CUR) >= 0;
}
bool GpFileStream_PFD::SeekEnd(GpUFilePos_t loc)
{
return lseek64(m_fd, loc, SEEK_END) >= 0;
}
bool GpFileStream_PFD::Truncate(GpUFilePos_t loc)
{
return ftruncate64(m_fd, static_cast<off64_t>(loc)) >= 0;
}
GpUFilePos_t GpFileStream_PFD::Size() const
{
struct stat64 s;
if (fstat64(m_fd, &s) < 0)
return 0;
return static_cast<GpUFilePos_t>(s.st_size);
}
GpUFilePos_t GpFileStream_PFD::Tell() const
{
return lseek64(m_fd, 0, SEEK_CUR);
}
void GpFileStream_PFD::Close()
{
this->~GpFileStream_PFD();
free(this);
}
void GpFileStream_PFD::Flush()
{
}
GpFileStream_SDLRWops::GpFileStream_SDLRWops(SDL_RWops *f, bool readOnly, bool writeOnly)
: m_rw(f)
, m_isReadOnly(readOnly)
, m_isWriteOnly(writeOnly)
{
}
GpFileStream_SDLRWops::~GpFileStream_SDLRWops()
{
m_rw->close(m_rw);
}
size_t GpFileStream_SDLRWops::Read(void *bytesOut, size_t size)
{
return m_rw->read(m_rw, bytesOut, 1, size);
}
size_t GpFileStream_SDLRWops::Write(const void *bytes, size_t size)
{
return m_rw->write(m_rw, bytes, 1, size);
}
bool GpFileStream_SDLRWops::IsSeekable() const
{
return true;
}
bool GpFileStream_SDLRWops::IsReadOnly() const
{
return m_isReadOnly;
}
bool GpFileStream_SDLRWops::IsWriteOnly() const
{
return m_isWriteOnly;
}
bool GpFileStream_SDLRWops::SeekStart(GpUFilePos_t loc)
{
return m_rw->seek(m_rw, static_cast<Sint64>(loc), RW_SEEK_SET) >= 0;
}
bool GpFileStream_SDLRWops::SeekCurrent(GpFilePos_t loc)
{
return m_rw->seek(m_rw, static_cast<Sint64>(loc), RW_SEEK_CUR) >= 0;
}
bool GpFileStream_SDLRWops::SeekEnd(GpUFilePos_t loc)
{
return m_rw->seek(m_rw, -static_cast<Sint64>(loc), RW_SEEK_END) >= 0;
}
bool GpFileStream_SDLRWops::Truncate(GpUFilePos_t loc)
{
return false;
}
GpUFilePos_t GpFileStream_SDLRWops::Size() const
{
return m_rw->size(m_rw);
}
GpUFilePos_t GpFileStream_SDLRWops::GpFileStream_SDLRWops::Tell() const
{
return SDL_RWtell(m_rw);
}
void GpFileStream_SDLRWops::Close()
{
this->~GpFileStream_SDLRWops();
free(this);
}
void GpFileStream_SDLRWops::Flush()
{
}
GpFileStream_Android_File::GpFileStream_Android_File(FILE *f, int fd, bool readOnly, bool writeOnly)
: m_f(f)
, m_fd(fd)
, m_isReadOnly(readOnly)
, m_isWriteOnly(writeOnly)
{
m_seekable = (fseek(m_f, 0, SEEK_CUR) == 0);
}
GpFileStream_Android_File::~GpFileStream_Android_File()
{
fclose(m_f);
}
size_t GpFileStream_Android_File::Read(void *bytesOut, size_t size)
{
if (m_isWriteOnly)
return 0;
return fread(bytesOut, 1, size, m_f);
}
size_t GpFileStream_Android_File::Write(const void *bytes, size_t size)
{
if (m_isReadOnly)
return 0;
return fwrite(bytes, 1, size, m_f);
}
bool GpFileStream_Android_File::IsSeekable() const
{
return m_seekable;
}
bool GpFileStream_Android_File::IsReadOnly() const
{
return m_isReadOnly;
}
bool GpFileStream_Android_File::IsWriteOnly() const
{
return m_isWriteOnly;
}
bool GpFileStream_Android_File::SeekStart(GpUFilePos_t loc)
{
if (!m_seekable)
return false;
fflush(m_f);
return lseek64(m_fd, static_cast<off64_t>(loc), SEEK_SET) >= 0;
}
bool GpFileStream_Android_File::SeekCurrent(GpFilePos_t loc)
{
if (!m_seekable)
return false;
fflush(m_f);
return lseek64(m_fd, static_cast<off64_t>(loc), SEEK_CUR) >= 0;
}
bool GpFileStream_Android_File::SeekEnd(GpUFilePos_t loc)
{
if (!m_seekable)
return false;
fflush(m_f);
return lseek64(m_fd, -static_cast<off64_t>(loc), SEEK_END) >= 0;
}
bool GpFileStream_Android_File::Truncate(GpUFilePos_t loc)
{
fflush(m_f);
return ftruncate64(m_fd, static_cast<off64_t>(loc)) >= 0;
}
GpUFilePos_t GpFileStream_Android_File::Size() const
{
fflush(m_f);
struct stat64 s;
if (fstat64(m_fd, &s) < 0)
return 0;
return static_cast<GpUFilePos_t>(s.st_size);
}
GpUFilePos_t GpFileStream_Android_File::Tell() const
{
return static_cast<GpUFilePos_t>(ftell(m_f));
}
void GpFileStream_Android_File::Close()
{
this->~GpFileStream_Android_File();
free(this);
}
void GpFileStream_Android_File::Flush()
{
fflush(m_f);
}
bool GpFileSystem_Android::OpenSourceExportFD(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *const *paths, size_t numPaths, int &fd, jobject &pfd)
{
if (!m_sourceExportMutex)
m_sourceExportMutex = PortabilityLayer::HostSystemServices::GetInstance()->CreateMutex();
m_sourceExportWaiting = true;
m_sourceExportCancelled = false;
JNIEnv *jni = static_cast<JNIEnv *>(SDL_AndroidGetJNIEnv());
jstring fname = jni->NewStringUTF(paths[0]);
jni->CallVoidMethod(m_activity, this->m_selectSourceExportPathMID, fname);
jni->DeleteLocalRef(fname);
for (;;)
{
m_sourceExportMutex->Lock();
const bool isWaiting = m_sourceExportWaiting;
m_sourceExportMutex->Unlock();
if (!isWaiting)
break;
m_delayCallback(5);
}
fd = m_sourceExportFD;
pfd = m_sourceExportPFD;
return !m_sourceExportCancelled;
}
bool GpFileSystem_Android::ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, std::string &resolution, bool &isAsset)
{
const char *prefsAppend = nullptr;
isAsset = false;
switch (virtualDirectory)
{
case PortabilityLayer::VirtualDirectories::kApplicationData:
resolution = std::string("Packaged") ;
isAsset = true;
break;
case PortabilityLayer::VirtualDirectories::kGameData:
resolution = std::string("Packaged/Houses");
isAsset = true;
break;
case PortabilityLayer::VirtualDirectories::kFonts:
resolution = std::string("Resources");
isAsset = true;
break;
case PortabilityLayer::VirtualDirectories::kHighScores:
prefsAppend = "HighScores";
break;
case PortabilityLayer::VirtualDirectories::kUserData:
prefsAppend = "Houses";
break;
case PortabilityLayer::VirtualDirectories::kUserSaves:
prefsAppend = "SavedGames";
break;
case PortabilityLayer::VirtualDirectories::kPrefs:
prefsAppend = "Prefs";
break;
case PortabilityLayer::VirtualDirectories::kFontCache:
prefsAppend = "FontCache";
break;
default:
return false;
};
if (prefsAppend)
{
char *prefsDir = SDL_GetPrefPath("aerofoil", "aerofoil");
resolution = prefsDir;
SDL_free(prefsDir);
resolution += prefsAppend;
}
for (size_t i = 0; i < numPaths; i++)
{
resolution += "/";
resolution += paths[i];
}
return true;
}
GpFileSystem_Android::GpFileSystem_Android()
: m_activity(nullptr)
, m_relay(nullptr)
, m_delayCallback(nullptr)
, m_sourceExportMutex(nullptr)
, m_sourceExportFD(0)
, m_sourceExportWaiting(false)
, m_sourceExportCancelled(false)
, m_sourceExportPFD(nullptr)
{
}
GpFileSystem_Android::~GpFileSystem_Android()
{
}
void GpFileSystem_Android::InitJNI()
{
JNIEnv *jni = static_cast<JNIEnv *>(SDL_AndroidGetJNIEnv());
jclass fileSystemAPIClass = jni->FindClass("org/thecodedeposit/aerofoil/GpFileSystemAPI");
int registerStatus = jni->RegisterNatives(fileSystemAPIClass, GpFileSystemAPI_tab, sizeof(GpFileSystemAPI_tab) / sizeof(GpFileSystemAPI_tab[0]));
jni->DeleteLocalRef(fileSystemAPIClass);
jobject activityLR = static_cast<jobject>(SDL_AndroidGetActivity());
jclass activityClassLR = static_cast<jclass>(jni->GetObjectClass(activityLR));
m_scanAssetDirectoryMID = jni->GetMethodID(activityClassLR, "scanAssetDirectory", "(Ljava/lang/String;)[Ljava/lang/String;");
m_selectSourceExportPathMID = jni->GetMethodID(activityClassLR, "selectSourceExportPath", "(Ljava/lang/String;)V");
m_closeSourceExportPFDMID = jni->GetMethodID(activityClassLR, "closeSourceExportPFD", "(Ljava/lang/Object;)V");
m_activity = jni->NewGlobalRef(activityLR);
jni->DeleteLocalRef(activityLR);
jni->DeleteLocalRef(activityClassLR);
char *prefsDir = SDL_GetPrefPath("aerofoil", "aerofoil");
size_t prefsDirLen = strlen(prefsDir);
for (size_t i = 0; i < prefsDirLen; i++)
{
if (prefsDir[i] == '/')
{
prefsDir[i] = '\0';
int created = mkdir(prefsDir, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
prefsDir[i] = '/';
}
}
const char *extensions[] = { "HighScores", "Houses", "SavedGames", "Prefs", "FontCache" };
for (size_t i = 0; i < sizeof(extensions) / sizeof(extensions[0]); i++)
{
std::string prefsPath = std::string(prefsDir) + extensions[i];
int created = mkdir(prefsPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
int n = 0;
}
SDL_free(prefsDir);
}
void GpFileSystem_Android::ShutdownJNI()
{
JNIEnv *jni = static_cast<JNIEnv *>(SDL_AndroidGetJNIEnv());
jni->DeleteGlobalRef(m_activity);
m_activity = nullptr;
}
bool GpFileSystem_Android::FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path)
{
std::string resolvedPath;
bool isAsset;
if (!ResolvePath(virtualDirectory, &path, 1, resolvedPath, isAsset))
return false;
if (isAsset)
{
SDL_RWops *rw = SDL_RWFromFile(resolvedPath.c_str(), "rb");
if (!rw)
return false;
SDL_RWclose(rw);
return true;
}
struct stat s;
return stat(resolvedPath.c_str(), &s) == 0;
}
bool GpFileSystem_Android::FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool *exists)
{
std::string resolvedPath;
bool isAsset;
if (!ResolvePath(virtualDirectory, &path, 1, resolvedPath, isAsset))
{
if (exists)
*exists = false;
return false;
}
if (isAsset)
{
if (exists)
*exists = this->FileExists(virtualDirectory, path);
return true;
}
int permissions = access(resolvedPath.c_str(), W_OK | F_OK);
*exists = ((permissions & F_OK) != 0);
return ((permissions & W_OK) != 0);
}
GpIOStream *GpFileSystem_Android::OpenFileNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* subPaths, size_t numSubPaths, bool writeAccess, GpFileCreationDisposition_t createDisposition)
{
const char *mode = nullptr;
bool canWrite = false;
bool needResetPosition = false;
switch (createDisposition)
{
case GpFileCreationDispositions::kCreateOrOverwrite:
mode = "w+b";
break;
case GpFileCreationDispositions::kCreateNew:
mode = "x+b";
break;
case GpFileCreationDispositions::kCreateOrOpen:
mode = "a+b";
needResetPosition = true;
break;
case GpFileCreationDispositions::kOpenExisting:
mode = writeAccess ? "r+b" : "rb";
break;
case GpFileCreationDispositions::kOverwriteExisting:
mode = "r+b";
break;
default:
return nullptr;
};
if (virtualDirectory == PortabilityLayer::VirtualDirectories::kSourceExport)
{
void *objStorage = malloc(sizeof(GpFileStream_PFD));
if (!objStorage)
return nullptr;
int fd = 0;
jobject pfd = nullptr;
const bool resolved = OpenSourceExportFD(virtualDirectory, subPaths, numSubPaths, fd, pfd);
if (!resolved)
{
free(objStorage);
return nullptr;
}
return new (objStorage) GpFileStream_PFD(this, fd, pfd, false, true);
}
std::string resolvedPath;
bool isAsset;
if (!ResolvePath(virtualDirectory, subPaths, numSubPaths, resolvedPath, isAsset))
return nullptr;
if (isAsset)
{
if (createDisposition == GpFileCreationDispositions::kOverwriteExisting || writeAccess)
return nullptr;
void *objStorage = malloc(sizeof(GpFileStream_SDLRWops));
if (!objStorage)
return nullptr;
SDL_RWops *rw = SDL_RWFromFile(resolvedPath.c_str(), mode);
if (!rw)
{
free(objStorage);
return nullptr;
}
return new (objStorage) GpFileStream_SDLRWops(rw, true, false);
}
else
{
void *objStorage = malloc(sizeof(GpFileStream_Android_File));
if (!objStorage)
return nullptr;
FILE *f = fopen(resolvedPath.c_str(), mode);
if (!f)
{
free(objStorage);
return nullptr;
}
if (needResetPosition)
fseek(f, 0, SEEK_SET);
int fd = fileno(f);
if (createDisposition == GpFileCreationDispositions::kOverwriteExisting)
{
if (ftruncate64(fd, 0) < 0)
{
free(objStorage);
fclose(f);
return nullptr;
}
}
return new (objStorage) GpFileStream_Android_File(f, fd, !writeAccess, false);
}
}
bool GpFileSystem_Android::DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed)
{
std::string resolvedPath;
bool isAsset;
if (!ResolvePath(virtualDirectory, &path, 1, resolvedPath, isAsset))
{
existed = false;
return false;
}
if (isAsset)
return false;
if (unlink(resolvedPath.c_str()) < 0)
{
existed = (errno != ENOENT);
return false;
}
existed = true;
return true;
}
PortabilityLayer::HostDirectoryCursor *GpFileSystem_Android::ScanDirectoryNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *const *paths, size_t numPaths)
{
ScanDirectoryNestedContext ctx;
ctx.m_this = this;
ctx.m_returnValue = nullptr;
ctx.m_virtualDirectory = virtualDirectory;
ctx.m_paths = paths;
ctx.m_numPaths = numPaths;
m_relay->Invoke(ScanDirectoryNestedThunk, &ctx);
return ctx.m_returnValue;
}
void GpFileSystem_Android::ScanDirectoryNestedThunk(void *context)
{
ScanDirectoryNestedContext *ctx = static_cast<ScanDirectoryNestedContext*>(context);
ctx->m_returnValue = ctx->m_this->ScanDirectoryNestedInternal(ctx->m_virtualDirectory, ctx->m_paths, ctx->m_numPaths);
}
PortabilityLayer::HostDirectoryCursor *GpFileSystem_Android::ScanDirectoryNestedInternal(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *const *paths, size_t numPaths)
{
if (virtualDirectory == PortabilityLayer::VirtualDirectories::kGameData || virtualDirectory == PortabilityLayer::VirtualDirectories::kApplicationData)
return ScanAssetDirectory(virtualDirectory, paths, numPaths);
return ScanStorageDirectory(virtualDirectory, paths, numPaths);
}
bool GpFileSystem_Android::ValidateFilePath(const char *path, size_t length) const
{
for (size_t i = 0; i < length; i++)
{
const char c = path[i];
if (c >= '0' && c <= '9')
continue;
if (c == '_' || c == '.' || c == '\'')
continue;
if (c == ' ' && i != 0 && i != length - 1)
continue;
if (c >= 'a' && c <= 'z')
continue;
if (c >= 'A' && c <= 'Z')
continue;
return false;
}
return true;
}
bool GpFileSystem_Android::ValidateFilePathUnicodeChar(uint32_t c) const
{
if (c >= '0' && c <= '9')
return true;
if (c == '_' || c == '\'')
return true;
if (c == ' ')
return true;
if (c >= 'a' && c <= 'z')
return true;
if (c >= 'A' && c <= 'Z')
return true;
return false;
}
bool GpFileSystem_Android::IsVirtualDirectoryLooseResources(PortabilityLayer::VirtualDirectory_t virtualDir) const
{
return false;
}
void GpFileSystem_Android::SetMainThreadRelay(IGpThreadRelay *relay)
{
m_relay = relay;
}
void GpFileSystem_Android::SetDelayCallback(DelayCallback_t delayCallback)
{
m_delayCallback = delayCallback;
}
void GpFileSystem_Android::PostSourceExportRequest(bool cancelled, int fd, jobject pfd)
{
JNIEnv *jni = static_cast<JNIEnv *>(SDL_AndroidGetJNIEnv());
jobject globalRef = jni->NewGlobalRef(pfd);
m_sourceExportMutex->Lock();
m_sourceExportWaiting = false;
m_sourceExportCancelled = cancelled;
m_sourceExportFD = fd;
m_sourceExportPFD = globalRef;
m_sourceExportMutex->Unlock();
}
void GpFileSystem_Android::ClosePFD(jobject pfd)
{
JNIEnv *jni = static_cast<JNIEnv *>(SDL_AndroidGetJNIEnv());
jni->CallVoidMethod(m_activity, m_closeSourceExportPFDMID, pfd);
jni->DeleteGlobalRef(pfd);
}
GpFileSystem_Android *GpFileSystem_Android::GetInstance()
{
return &ms_instance;
}
class GpDirectoryCursor_StringList final : public PortabilityLayer::HostDirectoryCursor
{
public:
explicit GpDirectoryCursor_StringList(std::vector<std::string> &paths);
~GpDirectoryCursor_StringList();
bool GetNext(const char *&outFileName) override;
void Destroy() override;
private:
std::vector<std::string> m_paths;
size_t m_index;
};
GpDirectoryCursor_StringList::GpDirectoryCursor_StringList(std::vector<std::string> &paths)
: m_index(0)
{
std::swap(paths, m_paths);
}
GpDirectoryCursor_StringList::~GpDirectoryCursor_StringList()
{
}
bool GpDirectoryCursor_StringList::GetNext(const char *&outFileName)
{
if (m_index == m_paths.size())
return false;
outFileName = m_paths[m_index].c_str();
m_index++;
return true;
}
void GpDirectoryCursor_StringList::Destroy()
{
delete this;
}
class GpDirectoryCursor_POSIX final : public PortabilityLayer::HostDirectoryCursor
{
public:
explicit GpDirectoryCursor_POSIX(DIR *dir);
~GpDirectoryCursor_POSIX();
bool GetNext(const char *&outFileName) override;
void Destroy() override;
private:
DIR *m_dir;
};
GpDirectoryCursor_POSIX::GpDirectoryCursor_POSIX(DIR *dir)
: m_dir(dir)
{
}
GpDirectoryCursor_POSIX::~GpDirectoryCursor_POSIX()
{
closedir(m_dir);
}
bool GpDirectoryCursor_POSIX::GetNext(const char *&outFileName)
{
struct dirent *dir = readdir(m_dir);
if (!dir)
return false;
outFileName = dir->d_name;
return true;
}
void GpDirectoryCursor_POSIX::Destroy()
{
delete this;
}
PortabilityLayer::HostDirectoryCursor *GpFileSystem_Android::ScanAssetDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths)
{
std::string resolvedPath;
std::vector<std::string> subPaths;
bool isAsset = true;
if (!ResolvePath(virtualDirectory, paths, numPaths, resolvedPath, isAsset))
return nullptr;
JNIEnv *jni = static_cast<JNIEnv *>(SDL_AndroidGetJNIEnv());
jstring directory = jni->NewStringUTF(resolvedPath.c_str());
jobjectArray resultArray = static_cast<jobjectArray>(jni->CallObjectMethod(m_activity, m_scanAssetDirectoryMID, directory));
jni->DeleteLocalRef(directory);
size_t arrayLength = jni->GetArrayLength(resultArray);
subPaths.reserve(arrayLength);
for (size_t i = 0; i < arrayLength; i++)
{
jstring pathJStr = static_cast<jstring>(jni->GetObjectArrayElement(resultArray, i));
const char *pathStrChars = jni->GetStringUTFChars(pathJStr, nullptr);
subPaths.push_back(std::string(pathStrChars, static_cast<size_t>(jni->GetStringUTFLength(pathJStr))));
jni->ReleaseStringUTFChars(pathJStr, pathStrChars);
jni->DeleteLocalRef(pathJStr);
}
jni->DeleteLocalRef(resultArray);
return new GpDirectoryCursor_StringList(subPaths);
}
PortabilityLayer::HostDirectoryCursor *GpFileSystem_Android::ScanStorageDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths)
{
std::string resolvedPath;
std::vector<std::string> subPaths;
bool isAsset = true;
if (!ResolvePath(virtualDirectory, paths, numPaths, resolvedPath, isAsset))
return nullptr;
DIR *d = opendir(resolvedPath.c_str());
if (!d)
return nullptr;
return new GpDirectoryCursor_POSIX(d);
}
JNIEXPORT void JNICALL nativePostSourceExportRequest(JNIEnv *env, jclass cls, jboolean cancelled, jint fd, jobject pfd)
{
GpFileSystem_Android::GetInstance()->PostSourceExportRequest(cancelled != JNI_FALSE, fd, pfd);
}
GpFileSystem_Android GpFileSystem_Android::ms_instance;

View File

@@ -1,78 +0,0 @@
#pragma once
#include "HostFileSystem.h"
#include "GpCoreDefs.h"
#include <jni.h>
#include <string>
namespace PortabilityLayer
{
class HostMutex;
}
class GpFileSystem_Android final : public PortabilityLayer::HostFileSystem
{
public:
GpFileSystem_Android();
~GpFileSystem_Android();
void InitJNI();
void ShutdownJNI();
bool FileExists(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path) override;
bool FileLocked(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool *exists) override;
GpIOStream *OpenFileNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* subPaths, size_t numSubPaths, bool writeAccess, GpFileCreationDisposition_t createDisposition) override;
bool DeleteFile(PortabilityLayer::VirtualDirectory_t virtualDirectory, const char *path, bool &existed) override;
PortabilityLayer::HostDirectoryCursor *ScanDirectoryNested(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths) override;
bool ValidateFilePath(const char *path, size_t pathLen) const override;
bool ValidateFilePathUnicodeChar(uint32_t ch) const override;
bool IsVirtualDirectoryLooseResources(PortabilityLayer::VirtualDirectory_t virtualDir) const override;
void SetMainThreadRelay(IGpThreadRelay *relay) override;
void SetDelayCallback(DelayCallback_t delayCallback) override;
void PostSourceExportRequest(bool cancelled, int fd, jobject pfd);
void ClosePFD(jobject pfd);
static GpFileSystem_Android *GetInstance();
private:
struct ScanDirectoryNestedContext
{
GpFileSystem_Android *m_this;
PortabilityLayer::HostDirectoryCursor *m_returnValue;
PortabilityLayer::VirtualDirectory_t m_virtualDirectory;
char const *const *m_paths;
size_t m_numPaths;
};
static void ScanDirectoryNestedThunk(void *context);
PortabilityLayer::HostDirectoryCursor *ScanDirectoryNestedInternal(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths);
PortabilityLayer::HostDirectoryCursor *ScanAssetDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths);
PortabilityLayer::HostDirectoryCursor *ScanStorageDirectory(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths);
bool OpenSourceExportFD(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, int &fd, jobject &pfd);
bool ResolvePath(PortabilityLayer::VirtualDirectory_t virtualDirectory, char const* const* paths, size_t numPaths, std::string &resolution, bool &isAsset);
IGpThreadRelay *m_relay;
DelayCallback_t m_delayCallback;
jobject m_activity;
jmethodID m_scanAssetDirectoryMID;
jmethodID m_selectSourceExportPathMID;
jmethodID m_closeSourceExportPFDMID;
PortabilityLayer::HostMutex *m_sourceExportMutex;
int m_sourceExportFD;
bool m_sourceExportWaiting;
bool m_sourceExportCancelled;
jobject m_sourceExportPFD;
static GpFileSystem_Android ms_instance;
};

View File

@@ -1,117 +0,0 @@
#include "SDL.h"
#include "GpMain.h"
#include "GpAudioDriverFactory.h"
#include "GpDisplayDriverFactory.h"
#include "GpGlobalConfig.h"
#include "GpFiber_SDL.h"
#include "GpFileSystem_Android.h"
#include "GpFontHandlerFactory.h"
#include "GpInputDriverFactory.h"
#include "GpAppInterface.h"
#include "GpSystemServices_Android.h"
#include "GpVOSEvent.h"
#include "IGpVOSEventQueue.h"
#include "IGpLogDriver.h"
#include "HostFileSystem.h"
#include "HostThreadEvent.h"
#include "GpAndroid.h"
#include <exception>
GpAndroidGlobals g_gpAndroidGlobals;
extern "C" IGpFontHandler *GpDriver_CreateFontHandler_FreeType2(const GpFontHandlerProperties &properties);
IGpDisplayDriver *GpDriver_CreateDisplayDriver_SDL_GL2(const GpDisplayDriverProperties &properties);
IGpAudioDriver *GpDriver_CreateAudioDriver_SDL(const GpAudioDriverProperties &properties);
class GpLogDriver_Android final : public IGpLogDriver
{
public:
void VPrintf(Category category, const char *fmt, va_list args) override;
void Shutdown() override;
static GpLogDriver_Android *GetInstance();
private:
static GpLogDriver_Android ms_instance;
};
void GpLogDriver_Android::VPrintf(IGpLogDriver::Category category, const char *fmt, va_list args)
{
switch (category)
{
case IGpLogDriver::Category_Error:
SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, fmt, args);
break;
case IGpLogDriver::Category_Warning:
SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, fmt, args);
break;
case IGpLogDriver::Category_Information:
SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, fmt, args);
break;
default:
SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_VERBOSE, fmt, args);
break;
};
}
void GpLogDriver_Android::Shutdown()
{
}
GpLogDriver_Android *GpLogDriver_Android::GetInstance()
{
return &ms_instance;
}
GpLogDriver_Android GpLogDriver_Android::ms_instance;
int main(int argc, char* argv[])
{
SDL_LogSetAllPriority(SDL_LOG_PRIORITY_INFO);
if (SDL_Init(SDL_INIT_VIDEO) < 0)
return -1;
SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft LandscapeRight");
GpFileSystem_Android::GetInstance()->InitJNI();
GpAppInterface_Get()->PL_HostFileSystem_SetInstance(GpFileSystem_Android::GetInstance());
GpAppInterface_Get()->PL_HostSystemServices_SetInstance(GpSystemServices_Android::GetInstance());
GpAppInterface_Get()->PL_HostLogDriver_SetInstance(GpLogDriver_Android::GetInstance());
g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_SDL_GL2;
g_gpGlobalConfig.m_audioDriverType = EGpAudioDriverType_SDL2;
g_gpGlobalConfig.m_fontHandlerType = EGpFontHandlerType_FreeType2;
g_gpGlobalConfig.m_inputDriverTypes = nullptr;
g_gpGlobalConfig.m_numInputDrivers = 0;
g_gpGlobalConfig.m_osGlobals = &g_gpAndroidGlobals;
g_gpGlobalConfig.m_logger = GpLogDriver_Android::GetInstance();
g_gpGlobalConfig.m_systemServices = GpSystemServices_Android::GetInstance();
GpDisplayDriverFactory::RegisterDisplayDriverFactory(EGpDisplayDriverType_SDL_GL2, GpDriver_CreateDisplayDriver_SDL_GL2);
GpAudioDriverFactory::RegisterAudioDriverFactory(EGpAudioDriverType_SDL2, GpDriver_CreateAudioDriver_SDL);
GpFontHandlerFactory::RegisterFontHandlerFactory(EGpFontHandlerType_FreeType2, GpDriver_CreateFontHandler_FreeType2);
int returnCode = GpMain::Run();
GpFileSystem_Android::GetInstance()->ShutdownJNI();
SDL_Quit();
// This doesn't even actually exit, but it does stop this stupid brain-damaged OS from
// just calling "main" again with no cleanup...
// That'll have to do until proper cleanup code is added to everything.
exit(returnCode);
return returnCode;
}

View File

@@ -1,288 +0,0 @@
#include "GpSystemServices_Android.h"
#include "HostMutex.h"
#include "HostThreadEvent.h"
#include "SDL.h"
#include <time.h>
#include <mutex>
#include <condition_variable>
#include <unistd.h>
struct GpSystemServices_Android_ThreadStartParams
{
GpSystemServices_Android::ThreadFunc_t m_threadFunc;
void *m_threadContext;
PortabilityLayer::HostThreadEvent *m_threadStartEvent;
};
static int SDLCALL StaticStartThread(void *lpThreadParameter)
{
const GpSystemServices_Android_ThreadStartParams *threadParams = static_cast<const GpSystemServices_Android_ThreadStartParams*>(lpThreadParameter);
GpSystemServices_Android::ThreadFunc_t threadFunc = threadParams->m_threadFunc;
void *threadContext = threadParams->m_threadContext;
PortabilityLayer::HostThreadEvent *threadStartEvent = threadParams->m_threadStartEvent;
threadStartEvent->Signal();
return threadFunc(threadContext);
}
template<class TMutex>
class GpMutex_Cpp11 final : public PortabilityLayer::HostMutex
{
public:
GpMutex_Cpp11();
~GpMutex_Cpp11();
void Destroy() override;
void Lock() override;
void Unlock() override;
private:
TMutex m_mutex;
};
template<class TMutex>
GpMutex_Cpp11<TMutex>::GpMutex_Cpp11()
{
}
template<class TMutex>
GpMutex_Cpp11<TMutex>::~GpMutex_Cpp11()
{
}
template<class TMutex>
void GpMutex_Cpp11<TMutex>::Destroy()
{
this->~GpMutex_Cpp11();
free(this);
}
template<class TMutex>
void GpMutex_Cpp11<TMutex>::Lock()
{
m_mutex.lock();
}
template<class TMutex>
void GpMutex_Cpp11<TMutex>::Unlock()
{
m_mutex.unlock();
}
typedef GpMutex_Cpp11<std::mutex> GpMutex_Cpp11_Vanilla;
typedef GpMutex_Cpp11<std::recursive_mutex> GpMutex_Cpp11_Recursive;
class GpThreadEvent_Cpp11 final : public PortabilityLayer::HostThreadEvent
{
public:
GpThreadEvent_Cpp11(bool autoReset, bool startSignaled);
~GpThreadEvent_Cpp11();
void Wait() override;
bool WaitTimed(uint32_t msec) override;
void Signal() override;
void Destroy() override;
private:
std::mutex m_mutex;
std::condition_variable m_cvar;
bool m_flag;
bool m_autoReset;
};
GpThreadEvent_Cpp11::GpThreadEvent_Cpp11(bool autoReset, bool startSignaled)
: m_flag(startSignaled)
, m_autoReset(autoReset)
{
}
GpThreadEvent_Cpp11::~GpThreadEvent_Cpp11()
{
}
void GpThreadEvent_Cpp11::Wait()
{
std::unique_lock<std::mutex> lock(m_mutex);
if (m_autoReset)
{
m_cvar.wait(lock,[&]()->bool{
if (m_flag)
{
m_flag = false;
return true;
}
else
return false;
});
}
else
m_cvar.wait(lock,[&]()->bool{ return m_flag; });
}
bool GpThreadEvent_Cpp11::WaitTimed(uint32_t msec)
{
std::unique_lock<std::mutex> lock(m_mutex);
if (m_autoReset)
{
if (!m_cvar.wait_for(lock, std::chrono::milliseconds(msec), [&]()->bool{
if (m_flag)
{
m_flag = false;
return true;
}
else
return false;
}))
return false;
}
else
{
if (!m_cvar.wait_for(lock, std::chrono::milliseconds(msec), [&]()->bool{ return m_flag; }))
return false;
}
return true;
}
void GpThreadEvent_Cpp11::Signal()
{
m_mutex.lock();
m_flag = true;
m_mutex.unlock();
if (m_autoReset)
m_cvar.notify_one();
else
m_cvar.notify_all();
}
void GpThreadEvent_Cpp11::Destroy()
{
this->~GpThreadEvent_Cpp11();
free(this);
}
GpSystemServices_Android::GpSystemServices_Android()
: m_textInputEnabled(false)
{
}
int64_t GpSystemServices_Android::GetTime() const
{
time_t t = time(nullptr);
return static_cast<int64_t>(t) - 2082844800;
}
void GpSystemServices_Android::GetLocalDateTime(unsigned int &year, unsigned int &month, unsigned int &day, unsigned int &hour, unsigned int &minute, unsigned int &second) const
{
time_t t = time(nullptr);
tm *tmObject = localtime(&t);
year = static_cast<unsigned int>(tmObject->tm_year);
month = static_cast<unsigned int>(tmObject->tm_mon + 1);
hour = static_cast<unsigned int>(tmObject->tm_hour);
minute = static_cast<unsigned int>(tmObject->tm_min);
second = static_cast<unsigned int>(tmObject->tm_sec);
}
PortabilityLayer::HostMutex *GpSystemServices_Android::CreateMutex()
{
GpMutex_Cpp11_Vanilla *mutex = static_cast<GpMutex_Cpp11_Vanilla*>(malloc(sizeof(GpMutex_Cpp11_Vanilla)));
if (!mutex)
return nullptr;
return new (mutex) GpMutex_Cpp11_Vanilla();
}
void *GpSystemServices_Android::CreateThread(ThreadFunc_t threadFunc, void *context)
{
PortabilityLayer::HostThreadEvent *evt = CreateThreadEvent(true, false);
if (!evt)
return nullptr;
GpSystemServices_Android_ThreadStartParams startParams;
startParams.m_threadContext = context;
startParams.m_threadFunc = threadFunc;
startParams.m_threadStartEvent = evt;
SDL_Thread *thread = SDL_CreateThread(StaticStartThread, "WorkerThread", &startParams);
if (thread == nullptr)
{
evt->Destroy();
return nullptr;
}
evt->Wait();
evt->Destroy();
return thread;
}
PortabilityLayer::HostMutex *GpSystemServices_Android::CreateRecursiveMutex()
{
GpMutex_Cpp11_Recursive *mutex = static_cast<GpMutex_Cpp11_Recursive*>(malloc(sizeof(GpMutex_Cpp11_Recursive)));
if (!mutex)
return nullptr;
return new (mutex) GpMutex_Cpp11_Recursive();
}
PortabilityLayer::HostThreadEvent *GpSystemServices_Android::CreateThreadEvent(bool autoReset, bool startSignaled)
{
GpThreadEvent_Cpp11 *evt = static_cast<GpThreadEvent_Cpp11*>(malloc(sizeof(GpThreadEvent_Cpp11)));
if (!evt)
return nullptr;
return new (evt) GpThreadEvent_Cpp11(autoReset, startSignaled);
}
uint64_t GpSystemServices_Android::GetFreeMemoryCosmetic() const
{
long pages = sysconf(_SC_AVPHYS_PAGES);
long pageSize = sysconf(_SC_PAGE_SIZE);
return pages * pageSize;
}
void GpSystemServices_Android::Beep() const
{
}
bool GpSystemServices_Android::IsTouchscreen() const
{
return true;
}
bool GpSystemServices_Android::IsUsingMouseAsTouch() const
{
return false;
}
bool GpSystemServices_Android::IsTextInputObstructive() const
{
return true;
}
unsigned int GpSystemServices_Android::GetCPUCount() const
{
return SDL_GetCPUCount();
}
void GpSystemServices_Android::SetTextInputEnabled(bool isEnabled)
{
m_textInputEnabled = isEnabled;
}
bool GpSystemServices_Android::IsTextInputEnabled() const
{
return m_textInputEnabled;
}
GpSystemServices_Android *GpSystemServices_Android::GetInstance()
{
return &ms_instance;
}
GpSystemServices_Android GpSystemServices_Android::ms_instance;

View File

@@ -1,34 +0,0 @@
#pragma once
#include "HostSystemServices.h"
#include "GpCoreDefs.h"
class GpSystemServices_Android final : public PortabilityLayer::HostSystemServices
{
public:
GpSystemServices_Android();
int64_t GetTime() const override;
void GetLocalDateTime(unsigned int &year, unsigned int &month, unsigned int &day, unsigned int &hour, unsigned int &minute, unsigned int &second) const override;
PortabilityLayer::HostMutex *CreateMutex() override;
PortabilityLayer::HostMutex *CreateRecursiveMutex() override;
void *CreateThread(ThreadFunc_t threadFunc, void *context) override;
PortabilityLayer::HostThreadEvent *CreateThreadEvent(bool autoReset, bool startSignaled) override;
uint64_t GetFreeMemoryCosmetic() const override;
void Beep() const override;
bool IsTouchscreen() const override;
bool IsUsingMouseAsTouch() const override;
bool IsTextInputObstructive() const override;
unsigned int GetCPUCount() const override;
void SetTextInputEnabled(bool isEnabled) override;
bool IsTextInputEnabled() const override;
void FlushTextInputEnabled();
static GpSystemServices_Android *GetInstance();
private:
static GpSystemServices_Android ms_instance;
bool m_textInputEnabled;
};

View File

@@ -1,17 +0,0 @@
# Add project specific ProGuard rules here.
# By default, the flags in this file are appended to flags specified
# in [sdk]/tools/proguard/proguard-android.txt
# You can edit the include path and order by changing the proguardFiles
# directive in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# Add any project specific keep options here:
# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

View File

@@ -1,90 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Replace com.test.game with the identifier of your game below, e.g.
com.gamemaker.game
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.thecodedeposit.aerofoil"
android:versionCode="1"
android:versionName="1.0"
android:installLocation="auto">
<!-- OpenGL ES 2.0 -->
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
<!-- Touchscreen support -->
<uses-feature
android:name="android.hardware.touchscreen"
android:required="false" />
<!-- Game controller support -->
<uses-feature
android:name="android.hardware.bluetooth"
android:required="false" />
<uses-feature
android:name="android.hardware.gamepad"
android:required="false" />
<uses-feature
android:name="android.hardware.usb.host"
android:required="false" />
<!-- External mouse input events -->
<uses-feature
android:name="android.hardware.type.pc"
android:required="false" />
<!-- Audio recording support -->
<!-- if you want to capture audio, uncomment this. -->
<!-- <uses-feature
android:name="android.hardware.microphone"
android:required="false" /> -->
<!-- Allow writing to external storage -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Allow access to Bluetooth devices -->
<uses-permission android:name="android.permission.BLUETOOTH" />
<!-- Allow access to the vibrator -->
<uses-permission android:name="android.permission.VIBRATE" />
<!-- if you want to capture audio, uncomment this. -->
<!-- <uses-permission android:name="android.permission.RECORD_AUDIO" /> -->
<!-- Create a Java class extending SDLActivity and place it in a
directory under app/src/main/java matching the package, e.g. app/src/main/java/com/gamemaker/game/MyGame.java
then replace "SDLActivity" with the name of your class (e.g. "MyGame")
in the XML below.
An example Java class can be found in README-android.md
-->
<application android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:allowBackup="true"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:hardwareAccelerated="true" >
<!-- Example of setting SDL hints from AndroidManifest.xml:
<meta-data android:name="SDL_ENV.SDL_ACCELEROMETER_AS_JOYSTICK" android:value="0"/>
-->
<activity android:name="GpActivity"
android:label="@string/app_name"
android:alwaysRetainTaskState="true"
android:launchMode="singleInstance"
android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- Drop file event -->
<!--
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="*/*" />
</intent-filter>
-->
</activity>
</application>
</manifest>

View File

@@ -1,3 +0,0 @@
Packaged
Resources
SourceCode.pkg

View File

@@ -1,22 +0,0 @@
package org.libsdl.app;
import android.hardware.usb.UsbDevice;
interface HIDDevice
{
public int getId();
public int getVendorId();
public int getProductId();
public String getSerialNumber();
public int getVersion();
public String getManufacturerName();
public String getProductName();
public UsbDevice getDevice();
public boolean open();
public int sendFeatureReport(byte[] report);
public int sendOutputReport(byte[] report);
public boolean getFeatureReport(byte[] report);
public void setFrozen(boolean frozen);
public void close();
public void shutdown();
}

View File

@@ -1,650 +0,0 @@
package org.libsdl.app;
import android.content.Context;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothGattService;
import android.hardware.usb.UsbDevice;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.os.*;
//import com.android.internal.util.HexDump;
import java.lang.Runnable;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.UUID;
class HIDDeviceBLESteamController extends BluetoothGattCallback implements HIDDevice {
private static final String TAG = "hidapi";
private HIDDeviceManager mManager;
private BluetoothDevice mDevice;
private int mDeviceId;
private BluetoothGatt mGatt;
private boolean mIsRegistered = false;
private boolean mIsConnected = false;
private boolean mIsChromebook = false;
private boolean mIsReconnecting = false;
private boolean mFrozen = false;
private LinkedList<GattOperation> mOperations;
GattOperation mCurrentOperation = null;
private Handler mHandler;
private static final int TRANSPORT_AUTO = 0;
private static final int TRANSPORT_BREDR = 1;
private static final int TRANSPORT_LE = 2;
private static final int CHROMEBOOK_CONNECTION_CHECK_INTERVAL = 10000;
static public final UUID steamControllerService = UUID.fromString("100F6C32-1735-4313-B402-38567131E5F3");
static public final UUID inputCharacteristic = UUID.fromString("100F6C33-1735-4313-B402-38567131E5F3");
static public final UUID reportCharacteristic = UUID.fromString("100F6C34-1735-4313-B402-38567131E5F3");
static private final byte[] enterValveMode = new byte[] { (byte)0xC0, (byte)0x87, 0x03, 0x08, 0x07, 0x00 };
static class GattOperation {
private enum Operation {
CHR_READ,
CHR_WRITE,
ENABLE_NOTIFICATION
}
Operation mOp;
UUID mUuid;
byte[] mValue;
BluetoothGatt mGatt;
boolean mResult = true;
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid) {
mGatt = gatt;
mOp = operation;
mUuid = uuid;
}
private GattOperation(BluetoothGatt gatt, GattOperation.Operation operation, UUID uuid, byte[] value) {
mGatt = gatt;
mOp = operation;
mUuid = uuid;
mValue = value;
}
public void run() {
// This is executed in main thread
BluetoothGattCharacteristic chr;
switch (mOp) {
case CHR_READ:
chr = getCharacteristic(mUuid);
//Log.v(TAG, "Reading characteristic " + chr.getUuid());
if (!mGatt.readCharacteristic(chr)) {
Log.e(TAG, "Unable to read characteristic " + mUuid.toString());
mResult = false;
break;
}
mResult = true;
break;
case CHR_WRITE:
chr = getCharacteristic(mUuid);
//Log.v(TAG, "Writing characteristic " + chr.getUuid() + " value=" + HexDump.toHexString(value));
chr.setValue(mValue);
if (!mGatt.writeCharacteristic(chr)) {
Log.e(TAG, "Unable to write characteristic " + mUuid.toString());
mResult = false;
break;
}
mResult = true;
break;
case ENABLE_NOTIFICATION:
chr = getCharacteristic(mUuid);
//Log.v(TAG, "Writing descriptor of " + chr.getUuid());
if (chr != null) {
BluetoothGattDescriptor cccd = chr.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
if (cccd != null) {
int properties = chr.getProperties();
byte[] value;
if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) == BluetoothGattCharacteristic.PROPERTY_NOTIFY) {
value = BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE;
} else if ((properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) == BluetoothGattCharacteristic.PROPERTY_INDICATE) {
value = BluetoothGattDescriptor.ENABLE_INDICATION_VALUE;
} else {
Log.e(TAG, "Unable to start notifications on input characteristic");
mResult = false;
return;
}
mGatt.setCharacteristicNotification(chr, true);
cccd.setValue(value);
if (!mGatt.writeDescriptor(cccd)) {
Log.e(TAG, "Unable to write descriptor " + mUuid.toString());
mResult = false;
return;
}
mResult = true;
}
}
}
}
public boolean finish() {
return mResult;
}
private BluetoothGattCharacteristic getCharacteristic(UUID uuid) {
BluetoothGattService valveService = mGatt.getService(steamControllerService);
if (valveService == null)
return null;
return valveService.getCharacteristic(uuid);
}
static public GattOperation readCharacteristic(BluetoothGatt gatt, UUID uuid) {
return new GattOperation(gatt, Operation.CHR_READ, uuid);
}
static public GattOperation writeCharacteristic(BluetoothGatt gatt, UUID uuid, byte[] value) {
return new GattOperation(gatt, Operation.CHR_WRITE, uuid, value);
}
static public GattOperation enableNotification(BluetoothGatt gatt, UUID uuid) {
return new GattOperation(gatt, Operation.ENABLE_NOTIFICATION, uuid);
}
}
public HIDDeviceBLESteamController(HIDDeviceManager manager, BluetoothDevice device) {
mManager = manager;
mDevice = device;
mDeviceId = mManager.getDeviceIDForIdentifier(getIdentifier());
mIsRegistered = false;
mIsChromebook = mManager.getContext().getPackageManager().hasSystemFeature("org.chromium.arc.device_management");
mOperations = new LinkedList<GattOperation>();
mHandler = new Handler(Looper.getMainLooper());
mGatt = connectGatt();
// final HIDDeviceBLESteamController finalThis = this;
// mHandler.postDelayed(new Runnable() {
// @Override
// public void run() {
// finalThis.checkConnectionForChromebookIssue();
// }
// }, CHROMEBOOK_CONNECTION_CHECK_INTERVAL);
}
public String getIdentifier() {
return String.format("SteamController.%s", mDevice.getAddress());
}
public BluetoothGatt getGatt() {
return mGatt;
}
// Because on Chromebooks we show up as a dual-mode device, it will attempt to connect TRANSPORT_AUTO, which will use TRANSPORT_BREDR instead
// of TRANSPORT_LE. Let's force ourselves to connect low energy.
private BluetoothGatt connectGatt(boolean managed) {
if (Build.VERSION.SDK_INT >= 23) {
try {
return mDevice.connectGatt(mManager.getContext(), managed, this, TRANSPORT_LE);
} catch (Exception e) {
return mDevice.connectGatt(mManager.getContext(), managed, this);
}
} else {
return mDevice.connectGatt(mManager.getContext(), managed, this);
}
}
private BluetoothGatt connectGatt() {
return connectGatt(false);
}
protected int getConnectionState() {
Context context = mManager.getContext();
if (context == null) {
// We are lacking any context to get our Bluetooth information. We'll just assume disconnected.
return BluetoothProfile.STATE_DISCONNECTED;
}
BluetoothManager btManager = (BluetoothManager)context.getSystemService(Context.BLUETOOTH_SERVICE);
if (btManager == null) {
// This device doesn't support Bluetooth. We should never be here, because how did
// we instantiate a device to start with?
return BluetoothProfile.STATE_DISCONNECTED;
}
return btManager.getConnectionState(mDevice, BluetoothProfile.GATT);
}
public void reconnect() {
if (getConnectionState() != BluetoothProfile.STATE_CONNECTED) {
mGatt.disconnect();
mGatt = connectGatt();
}
}
protected void checkConnectionForChromebookIssue() {
if (!mIsChromebook) {
// We only do this on Chromebooks, because otherwise it's really annoying to just attempt
// over and over.
return;
}
int connectionState = getConnectionState();
switch (connectionState) {
case BluetoothProfile.STATE_CONNECTED:
if (!mIsConnected) {
// We are in the Bad Chromebook Place. We can force a disconnect
// to try to recover.
Log.v(TAG, "Chromebook: We are in a very bad state; the controller shows as connected in the underlying Bluetooth layer, but we never received a callback. Forcing a reconnect.");
mIsReconnecting = true;
mGatt.disconnect();
mGatt = connectGatt(false);
break;
}
else if (!isRegistered()) {
if (mGatt.getServices().size() > 0) {
Log.v(TAG, "Chromebook: We are connected to a controller, but never got our registration. Trying to recover.");
probeService(this);
}
else {
Log.v(TAG, "Chromebook: We are connected to a controller, but never discovered services. Trying to recover.");
mIsReconnecting = true;
mGatt.disconnect();
mGatt = connectGatt(false);
break;
}
}
else {
Log.v(TAG, "Chromebook: We are connected, and registered. Everything's good!");
return;
}
break;
case BluetoothProfile.STATE_DISCONNECTED:
Log.v(TAG, "Chromebook: We have either been disconnected, or the Chromebook BtGatt.ContextMap bug has bitten us. Attempting a disconnect/reconnect, but we may not be able to recover.");
mIsReconnecting = true;
mGatt.disconnect();
mGatt = connectGatt(false);
break;
case BluetoothProfile.STATE_CONNECTING:
Log.v(TAG, "Chromebook: We're still trying to connect. Waiting a bit longer.");
break;
}
final HIDDeviceBLESteamController finalThis = this;
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
finalThis.checkConnectionForChromebookIssue();
}
}, CHROMEBOOK_CONNECTION_CHECK_INTERVAL);
}
private boolean isRegistered() {
return mIsRegistered;
}
private void setRegistered() {
mIsRegistered = true;
}
private boolean probeService(HIDDeviceBLESteamController controller) {
if (isRegistered()) {
return true;
}
if (!mIsConnected) {
return false;
}
Log.v(TAG, "probeService controller=" + controller);
for (BluetoothGattService service : mGatt.getServices()) {
if (service.getUuid().equals(steamControllerService)) {
Log.v(TAG, "Found Valve steam controller service " + service.getUuid());
for (BluetoothGattCharacteristic chr : service.getCharacteristics()) {
if (chr.getUuid().equals(inputCharacteristic)) {
Log.v(TAG, "Found input characteristic");
// Start notifications
BluetoothGattDescriptor cccd = chr.getDescriptor(UUID.fromString("00002902-0000-1000-8000-00805f9b34fb"));
if (cccd != null) {
enableNotification(chr.getUuid());
}
}
}
return true;
}
}
if ((mGatt.getServices().size() == 0) && mIsChromebook && !mIsReconnecting) {
Log.e(TAG, "Chromebook: Discovered services were empty; this almost certainly means the BtGatt.ContextMap bug has bitten us.");
mIsConnected = false;
mIsReconnecting = true;
mGatt.disconnect();
mGatt = connectGatt(false);
}
return false;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
private void finishCurrentGattOperation() {
GattOperation op = null;
synchronized (mOperations) {
if (mCurrentOperation != null) {
op = mCurrentOperation;
mCurrentOperation = null;
}
}
if (op != null) {
boolean result = op.finish(); // TODO: Maybe in main thread as well?
// Our operation failed, let's add it back to the beginning of our queue.
if (!result) {
mOperations.addFirst(op);
}
}
executeNextGattOperation();
}
private void executeNextGattOperation() {
synchronized (mOperations) {
if (mCurrentOperation != null)
return;
if (mOperations.isEmpty())
return;
mCurrentOperation = mOperations.removeFirst();
}
// Run in main thread
mHandler.post(new Runnable() {
@Override
public void run() {
synchronized (mOperations) {
if (mCurrentOperation == null) {
Log.e(TAG, "Current operation null in executor?");
return;
}
mCurrentOperation.run();
// now wait for the GATT callback and when it comes, finish this operation
}
}
});
}
private void queueGattOperation(GattOperation op) {
synchronized (mOperations) {
mOperations.add(op);
}
executeNextGattOperation();
}
private void enableNotification(UUID chrUuid) {
GattOperation op = HIDDeviceBLESteamController.GattOperation.enableNotification(mGatt, chrUuid);
queueGattOperation(op);
}
public void writeCharacteristic(UUID uuid, byte[] value) {
GattOperation op = HIDDeviceBLESteamController.GattOperation.writeCharacteristic(mGatt, uuid, value);
queueGattOperation(op);
}
public void readCharacteristic(UUID uuid) {
GattOperation op = HIDDeviceBLESteamController.GattOperation.readCharacteristic(mGatt, uuid);
queueGattOperation(op);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
////////////// BluetoothGattCallback overridden methods
//////////////////////////////////////////////////////////////////////////////////////////////////////
public void onConnectionStateChange(BluetoothGatt g, int status, int newState) {
//Log.v(TAG, "onConnectionStateChange status=" + status + " newState=" + newState);
mIsReconnecting = false;
if (newState == 2) {
mIsConnected = true;
// Run directly, without GattOperation
if (!isRegistered()) {
mHandler.post(new Runnable() {
@Override
public void run() {
mGatt.discoverServices();
}
});
}
}
else if (newState == 0) {
mIsConnected = false;
}
// Disconnection is handled in SteamLink using the ACTION_ACL_DISCONNECTED Intent.
}
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
//Log.v(TAG, "onServicesDiscovered status=" + status);
if (status == 0) {
if (gatt.getServices().size() == 0) {
Log.v(TAG, "onServicesDiscovered returned zero services; something has gone horribly wrong down in Android's Bluetooth stack.");
mIsReconnecting = true;
mIsConnected = false;
gatt.disconnect();
mGatt = connectGatt(false);
}
else {
probeService(this);
}
}
}
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
//Log.v(TAG, "onCharacteristicRead status=" + status + " uuid=" + characteristic.getUuid());
if (characteristic.getUuid().equals(reportCharacteristic) && !mFrozen) {
mManager.HIDDeviceFeatureReport(getId(), characteristic.getValue());
}
finishCurrentGattOperation();
}
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
//Log.v(TAG, "onCharacteristicWrite status=" + status + " uuid=" + characteristic.getUuid());
if (characteristic.getUuid().equals(reportCharacteristic)) {
// Only register controller with the native side once it has been fully configured
if (!isRegistered()) {
Log.v(TAG, "Registering Steam Controller with ID: " + getId());
mManager.HIDDeviceConnected(getId(), getIdentifier(), getVendorId(), getProductId(), getSerialNumber(), getVersion(), getManufacturerName(), getProductName(), 0, 0, 0, 0);
setRegistered();
}
}
finishCurrentGattOperation();
}
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
// Enable this for verbose logging of controller input reports
//Log.v(TAG, "onCharacteristicChanged uuid=" + characteristic.getUuid() + " data=" + HexDump.dumpHexString(characteristic.getValue()));
if (characteristic.getUuid().equals(inputCharacteristic) && !mFrozen) {
mManager.HIDDeviceInputReport(getId(), characteristic.getValue());
}
}
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
//Log.v(TAG, "onDescriptorRead status=" + status);
}
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
BluetoothGattCharacteristic chr = descriptor.getCharacteristic();
//Log.v(TAG, "onDescriptorWrite status=" + status + " uuid=" + chr.getUuid() + " descriptor=" + descriptor.getUuid());
if (chr.getUuid().equals(inputCharacteristic)) {
boolean hasWrittenInputDescriptor = true;
BluetoothGattCharacteristic reportChr = chr.getService().getCharacteristic(reportCharacteristic);
if (reportChr != null) {
Log.v(TAG, "Writing report characteristic to enter valve mode");
reportChr.setValue(enterValveMode);
gatt.writeCharacteristic(reportChr);
}
}
finishCurrentGattOperation();
}
public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
//Log.v(TAG, "onReliableWriteCompleted status=" + status);
}
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
//Log.v(TAG, "onReadRemoteRssi status=" + status);
}
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
//Log.v(TAG, "onMtuChanged status=" + status);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////// Public API
//////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
public int getId() {
return mDeviceId;
}
@Override
public int getVendorId() {
// Valve Corporation
final int VALVE_USB_VID = 0x28DE;
return VALVE_USB_VID;
}
@Override
public int getProductId() {
// We don't have an easy way to query from the Bluetooth device, but we know what it is
final int D0G_BLE2_PID = 0x1106;
return D0G_BLE2_PID;
}
@Override
public String getSerialNumber() {
// This will be read later via feature report by Steam
return "12345";
}
@Override
public int getVersion() {
return 0;
}
@Override
public String getManufacturerName() {
return "Valve Corporation";
}
@Override
public String getProductName() {
return "Steam Controller";
}
@Override
public UsbDevice getDevice() {
return null;
}
@Override
public boolean open() {
return true;
}
@Override
public int sendFeatureReport(byte[] report) {
if (!isRegistered()) {
Log.e(TAG, "Attempted sendFeatureReport before Steam Controller is registered!");
if (mIsConnected) {
probeService(this);
}
return -1;
}
// We need to skip the first byte, as that doesn't go over the air
byte[] actual_report = Arrays.copyOfRange(report, 1, report.length - 1);
//Log.v(TAG, "sendFeatureReport " + HexDump.dumpHexString(actual_report));
writeCharacteristic(reportCharacteristic, actual_report);
return report.length;
}
@Override
public int sendOutputReport(byte[] report) {
if (!isRegistered()) {
Log.e(TAG, "Attempted sendOutputReport before Steam Controller is registered!");
if (mIsConnected) {
probeService(this);
}
return -1;
}
//Log.v(TAG, "sendFeatureReport " + HexDump.dumpHexString(report));
writeCharacteristic(reportCharacteristic, report);
return report.length;
}
@Override
public boolean getFeatureReport(byte[] report) {
if (!isRegistered()) {
Log.e(TAG, "Attempted getFeatureReport before Steam Controller is registered!");
if (mIsConnected) {
probeService(this);
}
return false;
}
//Log.v(TAG, "getFeatureReport");
readCharacteristic(reportCharacteristic);
return true;
}
@Override
public void close() {
}
@Override
public void setFrozen(boolean frozen) {
mFrozen = frozen;
}
@Override
public void shutdown() {
close();
BluetoothGatt g = mGatt;
if (g != null) {
g.disconnect();
g.close();
mGatt = null;
}
mManager = null;
mIsRegistered = false;
mIsConnected = false;
mOperations.clear();
}
}

View File

@@ -1,669 +0,0 @@
package org.libsdl.app;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.util.Log;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.hardware.usb.*;
import android.os.Handler;
import android.os.Looper;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
public class HIDDeviceManager {
private static final String TAG = "hidapi";
private static final String ACTION_USB_PERMISSION = "org.libsdl.app.USB_PERMISSION";
private static HIDDeviceManager sManager;
private static int sManagerRefCount = 0;
public static HIDDeviceManager acquire(Context context) {
if (sManagerRefCount == 0) {
sManager = new HIDDeviceManager(context);
}
++sManagerRefCount;
return sManager;
}
public static void release(HIDDeviceManager manager) {
if (manager == sManager) {
--sManagerRefCount;
if (sManagerRefCount == 0) {
sManager.close();
sManager = null;
}
}
}
private Context mContext;
private HashMap<Integer, HIDDevice> mDevicesById = new HashMap<Integer, HIDDevice>();
private HashMap<BluetoothDevice, HIDDeviceBLESteamController> mBluetoothDevices = new HashMap<BluetoothDevice, HIDDeviceBLESteamController>();
private int mNextDeviceId = 0;
private SharedPreferences mSharedPreferences = null;
private boolean mIsChromebook = false;
private UsbManager mUsbManager;
private Handler mHandler;
private BluetoothManager mBluetoothManager;
private List<BluetoothDevice> mLastBluetoothDevices;
private final BroadcastReceiver mUsbBroadcast = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(UsbManager.ACTION_USB_DEVICE_ATTACHED)) {
UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
handleUsbDeviceAttached(usbDevice);
} else if (action.equals(UsbManager.ACTION_USB_DEVICE_DETACHED)) {
UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
handleUsbDeviceDetached(usbDevice);
} else if (action.equals(HIDDeviceManager.ACTION_USB_PERMISSION)) {
UsbDevice usbDevice = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
handleUsbDevicePermission(usbDevice, intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false));
}
}
};
private final BroadcastReceiver mBluetoothBroadcast = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// Bluetooth device was connected. If it was a Steam Controller, handle it
if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.d(TAG, "Bluetooth device connected: " + device);
if (isSteamController(device)) {
connectBluetoothDevice(device);
}
}
// Bluetooth device was disconnected, remove from controller manager (if any)
if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
Log.d(TAG, "Bluetooth device disconnected: " + device);
disconnectBluetoothDevice(device);
}
}
};
private HIDDeviceManager(final Context context) {
mContext = context;
// Make sure we have the HIDAPI library loaded with the native functions
try {
SDL.loadLibrary("hidapi");
} catch (Throwable e) {
Log.w(TAG, "Couldn't load hidapi: " + e.toString());
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setCancelable(false);
builder.setTitle("SDL HIDAPI Error");
builder.setMessage("Please report the following error to the SDL maintainers: " + e.getMessage());
builder.setNegativeButton("Quit", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
try {
// If our context is an activity, exit rather than crashing when we can't
// call our native functions.
Activity activity = (Activity)context;
activity.finish();
}
catch (ClassCastException cce) {
// Context wasn't an activity, there's nothing we can do. Give up and return.
}
}
});
builder.show();
return;
}
HIDDeviceRegisterCallback();
mSharedPreferences = mContext.getSharedPreferences("hidapi", Context.MODE_PRIVATE);
mIsChromebook = mContext.getPackageManager().hasSystemFeature("org.chromium.arc.device_management");
// if (shouldClear) {
// SharedPreferences.Editor spedit = mSharedPreferences.edit();
// spedit.clear();
// spedit.commit();
// }
// else
{
mNextDeviceId = mSharedPreferences.getInt("next_device_id", 0);
}
initializeUSB();
initializeBluetooth();
}
public Context getContext() {
return mContext;
}
public int getDeviceIDForIdentifier(String identifier) {
SharedPreferences.Editor spedit = mSharedPreferences.edit();
int result = mSharedPreferences.getInt(identifier, 0);
if (result == 0) {
result = mNextDeviceId++;
spedit.putInt("next_device_id", mNextDeviceId);
}
spedit.putInt(identifier, result);
spedit.commit();
return result;
}
private void initializeUSB() {
mUsbManager = (UsbManager)mContext.getSystemService(Context.USB_SERVICE);
/*
// Logging
for (UsbDevice device : mUsbManager.getDeviceList().values()) {
Log.i(TAG,"Path: " + device.getDeviceName());
Log.i(TAG,"Manufacturer: " + device.getManufacturerName());
Log.i(TAG,"Product: " + device.getProductName());
Log.i(TAG,"ID: " + device.getDeviceId());
Log.i(TAG,"Class: " + device.getDeviceClass());
Log.i(TAG,"Protocol: " + device.getDeviceProtocol());
Log.i(TAG,"Vendor ID " + device.getVendorId());
Log.i(TAG,"Product ID: " + device.getProductId());
Log.i(TAG,"Interface count: " + device.getInterfaceCount());
Log.i(TAG,"---------------------------------------");
// Get interface details
for (int index = 0; index < device.getInterfaceCount(); index++) {
UsbInterface mUsbInterface = device.getInterface(index);
Log.i(TAG," ***** *****");
Log.i(TAG," Interface index: " + index);
Log.i(TAG," Interface ID: " + mUsbInterface.getId());
Log.i(TAG," Interface class: " + mUsbInterface.getInterfaceClass());
Log.i(TAG," Interface subclass: " + mUsbInterface.getInterfaceSubclass());
Log.i(TAG," Interface protocol: " + mUsbInterface.getInterfaceProtocol());
Log.i(TAG," Endpoint count: " + mUsbInterface.getEndpointCount());
// Get endpoint details
for (int epi = 0; epi < mUsbInterface.getEndpointCount(); epi++)
{
UsbEndpoint mEndpoint = mUsbInterface.getEndpoint(epi);
Log.i(TAG," ++++ ++++ ++++");
Log.i(TAG," Endpoint index: " + epi);
Log.i(TAG," Attributes: " + mEndpoint.getAttributes());
Log.i(TAG," Direction: " + mEndpoint.getDirection());
Log.i(TAG," Number: " + mEndpoint.getEndpointNumber());
Log.i(TAG," Interval: " + mEndpoint.getInterval());
Log.i(TAG," Packet size: " + mEndpoint.getMaxPacketSize());
Log.i(TAG," Type: " + mEndpoint.getType());
}
}
}
Log.i(TAG," No more devices connected.");
*/
// Register for USB broadcasts and permission completions
IntentFilter filter = new IntentFilter();
filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
filter.addAction(HIDDeviceManager.ACTION_USB_PERMISSION);
mContext.registerReceiver(mUsbBroadcast, filter);
for (UsbDevice usbDevice : mUsbManager.getDeviceList().values()) {
handleUsbDeviceAttached(usbDevice);
}
}
UsbManager getUSBManager() {
return mUsbManager;
}
private void shutdownUSB() {
try {
mContext.unregisterReceiver(mUsbBroadcast);
} catch (Exception e) {
// We may not have registered, that's okay
}
}
private boolean isHIDDeviceInterface(UsbDevice usbDevice, UsbInterface usbInterface) {
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_HID) {
return true;
}
if (isXbox360Controller(usbDevice, usbInterface) || isXboxOneController(usbDevice, usbInterface)) {
return true;
}
return false;
}
private boolean isXbox360Controller(UsbDevice usbDevice, UsbInterface usbInterface) {
final int XB360_IFACE_SUBCLASS = 93;
final int XB360_IFACE_PROTOCOL = 1; // Wired
final int XB360W_IFACE_PROTOCOL = 129; // Wireless
final int[] SUPPORTED_VENDORS = {
0x0079, // GPD Win 2
0x044f, // Thrustmaster
0x045e, // Microsoft
0x046d, // Logitech
0x056e, // Elecom
0x06a3, // Saitek
0x0738, // Mad Catz
0x07ff, // Mad Catz
0x0e6f, // PDP
0x0f0d, // Hori
0x1038, // SteelSeries
0x11c9, // Nacon
0x12ab, // Unknown
0x1430, // RedOctane
0x146b, // BigBen
0x1532, // Razer Sabertooth
0x15e4, // Numark
0x162e, // Joytech
0x1689, // Razer Onza
0x1bad, // Harmonix
0x24c6, // PowerA
};
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC &&
usbInterface.getInterfaceSubclass() == XB360_IFACE_SUBCLASS &&
(usbInterface.getInterfaceProtocol() == XB360_IFACE_PROTOCOL ||
usbInterface.getInterfaceProtocol() == XB360W_IFACE_PROTOCOL)) {
int vendor_id = usbDevice.getVendorId();
for (int supportedVid : SUPPORTED_VENDORS) {
if (vendor_id == supportedVid) {
return true;
}
}
}
return false;
}
private boolean isXboxOneController(UsbDevice usbDevice, UsbInterface usbInterface) {
final int XB1_IFACE_SUBCLASS = 71;
final int XB1_IFACE_PROTOCOL = 208;
final int[] SUPPORTED_VENDORS = {
0x045e, // Microsoft
0x0738, // Mad Catz
0x0e6f, // PDP
0x0f0d, // Hori
0x1532, // Razer Wildcat
0x24c6, // PowerA
0x2e24, // Hyperkin
};
if (usbInterface.getId() == 0 &&
usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_VENDOR_SPEC &&
usbInterface.getInterfaceSubclass() == XB1_IFACE_SUBCLASS &&
usbInterface.getInterfaceProtocol() == XB1_IFACE_PROTOCOL) {
int vendor_id = usbDevice.getVendorId();
for (int supportedVid : SUPPORTED_VENDORS) {
if (vendor_id == supportedVid) {
return true;
}
}
}
return false;
}
private void handleUsbDeviceAttached(UsbDevice usbDevice) {
connectHIDDeviceUSB(usbDevice);
}
private void handleUsbDeviceDetached(UsbDevice usbDevice) {
List<Integer> devices = new ArrayList<Integer>();
for (HIDDevice device : mDevicesById.values()) {
if (usbDevice.equals(device.getDevice())) {
devices.add(device.getId());
}
}
for (int id : devices) {
HIDDevice device = mDevicesById.get(id);
mDevicesById.remove(id);
device.shutdown();
HIDDeviceDisconnected(id);
}
}
private void handleUsbDevicePermission(UsbDevice usbDevice, boolean permission_granted) {
for (HIDDevice device : mDevicesById.values()) {
if (usbDevice.equals(device.getDevice())) {
boolean opened = false;
if (permission_granted) {
opened = device.open();
}
HIDDeviceOpenResult(device.getId(), opened);
}
}
}
private void connectHIDDeviceUSB(UsbDevice usbDevice) {
synchronized (this) {
for (int interface_index = 0; interface_index < usbDevice.getInterfaceCount(); interface_index++) {
UsbInterface usbInterface = usbDevice.getInterface(interface_index);
if (isHIDDeviceInterface(usbDevice, usbInterface)) {
HIDDeviceUSB device = new HIDDeviceUSB(this, usbDevice, interface_index);
int id = device.getId();
mDevicesById.put(id, device);
HIDDeviceConnected(id, device.getIdentifier(), device.getVendorId(), device.getProductId(), device.getSerialNumber(), device.getVersion(), device.getManufacturerName(), device.getProductName(), usbInterface.getId(), usbInterface.getInterfaceClass(), usbInterface.getInterfaceSubclass(), usbInterface.getInterfaceProtocol());
}
}
}
}
private void initializeBluetooth() {
Log.d(TAG, "Initializing Bluetooth");
if (mContext.getPackageManager().checkPermission(android.Manifest.permission.BLUETOOTH, mContext.getPackageName()) != PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, "Couldn't initialize Bluetooth, missing android.permission.BLUETOOTH");
return;
}
// Find bonded bluetooth controllers and create SteamControllers for them
mBluetoothManager = (BluetoothManager)mContext.getSystemService(Context.BLUETOOTH_SERVICE);
if (mBluetoothManager == null) {
// This device doesn't support Bluetooth.
return;
}
BluetoothAdapter btAdapter = mBluetoothManager.getAdapter();
if (btAdapter == null) {
// This device has Bluetooth support in the codebase, but has no available adapters.
return;
}
// Get our bonded devices.
for (BluetoothDevice device : btAdapter.getBondedDevices()) {
Log.d(TAG, "Bluetooth device available: " + device);
if (isSteamController(device)) {
connectBluetoothDevice(device);
}
}
// NOTE: These don't work on Chromebooks, to my undying dismay.
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
filter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
mContext.registerReceiver(mBluetoothBroadcast, filter);
if (mIsChromebook) {
mHandler = new Handler(Looper.getMainLooper());
mLastBluetoothDevices = new ArrayList<BluetoothDevice>();
// final HIDDeviceManager finalThis = this;
// mHandler.postDelayed(new Runnable() {
// @Override
// public void run() {
// finalThis.chromebookConnectionHandler();
// }
// }, 5000);
}
}
private void shutdownBluetooth() {
try {
mContext.unregisterReceiver(mBluetoothBroadcast);
} catch (Exception e) {
// We may not have registered, that's okay
}
}
// Chromebooks do not pass along ACTION_ACL_CONNECTED / ACTION_ACL_DISCONNECTED properly.
// This function provides a sort of dummy version of that, watching for changes in the
// connected devices and attempting to add controllers as things change.
public void chromebookConnectionHandler() {
if (!mIsChromebook) {
return;
}
ArrayList<BluetoothDevice> disconnected = new ArrayList<BluetoothDevice>();
ArrayList<BluetoothDevice> connected = new ArrayList<BluetoothDevice>();
List<BluetoothDevice> currentConnected = mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT);
for (BluetoothDevice bluetoothDevice : currentConnected) {
if (!mLastBluetoothDevices.contains(bluetoothDevice)) {
connected.add(bluetoothDevice);
}
}
for (BluetoothDevice bluetoothDevice : mLastBluetoothDevices) {
if (!currentConnected.contains(bluetoothDevice)) {
disconnected.add(bluetoothDevice);
}
}
mLastBluetoothDevices = currentConnected;
for (BluetoothDevice bluetoothDevice : disconnected) {
disconnectBluetoothDevice(bluetoothDevice);
}
for (BluetoothDevice bluetoothDevice : connected) {
connectBluetoothDevice(bluetoothDevice);
}
final HIDDeviceManager finalThis = this;
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
finalThis.chromebookConnectionHandler();
}
}, 10000);
}
public boolean connectBluetoothDevice(BluetoothDevice bluetoothDevice) {
Log.v(TAG, "connectBluetoothDevice device=" + bluetoothDevice);
synchronized (this) {
if (mBluetoothDevices.containsKey(bluetoothDevice)) {
Log.v(TAG, "Steam controller with address " + bluetoothDevice + " already exists, attempting reconnect");
HIDDeviceBLESteamController device = mBluetoothDevices.get(bluetoothDevice);
device.reconnect();
return false;
}
HIDDeviceBLESteamController device = new HIDDeviceBLESteamController(this, bluetoothDevice);
int id = device.getId();
mBluetoothDevices.put(bluetoothDevice, device);
mDevicesById.put(id, device);
// The Steam Controller will mark itself connected once initialization is complete
}
return true;
}
public void disconnectBluetoothDevice(BluetoothDevice bluetoothDevice) {
synchronized (this) {
HIDDeviceBLESteamController device = mBluetoothDevices.get(bluetoothDevice);
if (device == null)
return;
int id = device.getId();
mBluetoothDevices.remove(bluetoothDevice);
mDevicesById.remove(id);
device.shutdown();
HIDDeviceDisconnected(id);
}
}
public boolean isSteamController(BluetoothDevice bluetoothDevice) {
// Sanity check. If you pass in a null device, by definition it is never a Steam Controller.
if (bluetoothDevice == null) {
return false;
}
// If the device has no local name, we really don't want to try an equality check against it.
if (bluetoothDevice.getName() == null) {
return false;
}
return bluetoothDevice.getName().equals("SteamController") && ((bluetoothDevice.getType() & BluetoothDevice.DEVICE_TYPE_LE) != 0);
}
private void close() {
shutdownUSB();
shutdownBluetooth();
synchronized (this) {
for (HIDDevice device : mDevicesById.values()) {
device.shutdown();
}
mDevicesById.clear();
mBluetoothDevices.clear();
HIDDeviceReleaseCallback();
}
}
public void setFrozen(boolean frozen) {
synchronized (this) {
for (HIDDevice device : mDevicesById.values()) {
device.setFrozen(frozen);
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////////////
private HIDDevice getDevice(int id) {
synchronized (this) {
HIDDevice result = mDevicesById.get(id);
if (result == null) {
Log.v(TAG, "No device for id: " + id);
Log.v(TAG, "Available devices: " + mDevicesById.keySet());
}
return result;
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
////////// JNI interface functions
//////////////////////////////////////////////////////////////////////////////////////////////////////
public boolean openDevice(int deviceID) {
Log.v(TAG, "openDevice deviceID=" + deviceID);
HIDDevice device = getDevice(deviceID);
if (device == null) {
HIDDeviceDisconnected(deviceID);
return false;
}
// Look to see if this is a USB device and we have permission to access it
UsbDevice usbDevice = device.getDevice();
if (usbDevice != null && !mUsbManager.hasPermission(usbDevice)) {
HIDDeviceOpenPending(deviceID);
try {
mUsbManager.requestPermission(usbDevice, PendingIntent.getBroadcast(mContext, 0, new Intent(HIDDeviceManager.ACTION_USB_PERMISSION), 0));
} catch (Exception e) {
Log.v(TAG, "Couldn't request permission for USB device " + usbDevice);
HIDDeviceOpenResult(deviceID, false);
}
return false;
}
try {
return device.open();
} catch (Exception e) {
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
}
return false;
}
public int sendOutputReport(int deviceID, byte[] report) {
try {
//Log.v(TAG, "sendOutputReport deviceID=" + deviceID + " length=" + report.length);
HIDDevice device;
device = getDevice(deviceID);
if (device == null) {
HIDDeviceDisconnected(deviceID);
return -1;
}
return device.sendOutputReport(report);
} catch (Exception e) {
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
}
return -1;
}
public int sendFeatureReport(int deviceID, byte[] report) {
try {
//Log.v(TAG, "sendFeatureReport deviceID=" + deviceID + " length=" + report.length);
HIDDevice device;
device = getDevice(deviceID);
if (device == null) {
HIDDeviceDisconnected(deviceID);
return -1;
}
return device.sendFeatureReport(report);
} catch (Exception e) {
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
}
return -1;
}
public boolean getFeatureReport(int deviceID, byte[] report) {
try {
//Log.v(TAG, "getFeatureReport deviceID=" + deviceID);
HIDDevice device;
device = getDevice(deviceID);
if (device == null) {
HIDDeviceDisconnected(deviceID);
return false;
}
return device.getFeatureReport(report);
} catch (Exception e) {
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
}
return false;
}
public void closeDevice(int deviceID) {
try {
Log.v(TAG, "closeDevice deviceID=" + deviceID);
HIDDevice device;
device = getDevice(deviceID);
if (device == null) {
HIDDeviceDisconnected(deviceID);
return;
}
device.close();
} catch (Exception e) {
Log.e(TAG, "Got exception: " + Log.getStackTraceString(e));
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
/////////////// Native methods
//////////////////////////////////////////////////////////////////////////////////////////////////////
private native void HIDDeviceRegisterCallback();
private native void HIDDeviceReleaseCallback();
native void HIDDeviceConnected(int deviceID, String identifier, int vendorId, int productId, String serial_number, int release_number, String manufacturer_string, String product_string, int interface_number, int interface_class, int interface_subclass, int interface_protocol);
native void HIDDeviceOpenPending(int deviceID);
native void HIDDeviceOpenResult(int deviceID, boolean opened);
native void HIDDeviceDisconnected(int deviceID);
native void HIDDeviceInputReport(int deviceID, byte[] report);
native void HIDDeviceFeatureReport(int deviceID, byte[] report);
}

View File

@@ -1,304 +0,0 @@
package org.libsdl.app;
import android.hardware.usb.*;
import android.os.Build;
import android.util.Log;
import java.util.Arrays;
class HIDDeviceUSB implements HIDDevice {
private static final String TAG = "hidapi";
protected HIDDeviceManager mManager;
protected UsbDevice mDevice;
protected int mInterfaceIndex;
protected int mInterface;
protected int mDeviceId;
protected UsbDeviceConnection mConnection;
protected UsbEndpoint mInputEndpoint;
protected UsbEndpoint mOutputEndpoint;
protected InputThread mInputThread;
protected boolean mRunning;
protected boolean mFrozen;
public HIDDeviceUSB(HIDDeviceManager manager, UsbDevice usbDevice, int interface_index) {
mManager = manager;
mDevice = usbDevice;
mInterfaceIndex = interface_index;
mInterface = mDevice.getInterface(mInterfaceIndex).getId();
mDeviceId = manager.getDeviceIDForIdentifier(getIdentifier());
mRunning = false;
}
public String getIdentifier() {
return String.format("%s/%x/%x/%d", mDevice.getDeviceName(), mDevice.getVendorId(), mDevice.getProductId(), mInterfaceIndex);
}
@Override
public int getId() {
return mDeviceId;
}
@Override
public int getVendorId() {
return mDevice.getVendorId();
}
@Override
public int getProductId() {
return mDevice.getProductId();
}
@Override
public String getSerialNumber() {
String result = null;
if (Build.VERSION.SDK_INT >= 21) {
result = mDevice.getSerialNumber();
}
if (result == null) {
result = "";
}
return result;
}
@Override
public int getVersion() {
return 0;
}
@Override
public String getManufacturerName() {
String result = null;
if (Build.VERSION.SDK_INT >= 21) {
result = mDevice.getManufacturerName();
}
if (result == null) {
result = String.format("%x", getVendorId());
}
return result;
}
@Override
public String getProductName() {
String result = null;
if (Build.VERSION.SDK_INT >= 21) {
result = mDevice.getProductName();
}
if (result == null) {
result = String.format("%x", getProductId());
}
return result;
}
@Override
public UsbDevice getDevice() {
return mDevice;
}
public String getDeviceName() {
return getManufacturerName() + " " + getProductName() + "(0x" + String.format("%x", getVendorId()) + "/0x" + String.format("%x", getProductId()) + ")";
}
@Override
public boolean open() {
mConnection = mManager.getUSBManager().openDevice(mDevice);
if (mConnection == null) {
Log.w(TAG, "Unable to open USB device " + getDeviceName());
return false;
}
// Force claim our interface
UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
if (!mConnection.claimInterface(iface, true)) {
Log.w(TAG, "Failed to claim interfaces on USB device " + getDeviceName());
close();
return false;
}
// Find the endpoints
for (int j = 0; j < iface.getEndpointCount(); j++) {
UsbEndpoint endpt = iface.getEndpoint(j);
switch (endpt.getDirection()) {
case UsbConstants.USB_DIR_IN:
if (mInputEndpoint == null) {
mInputEndpoint = endpt;
}
break;
case UsbConstants.USB_DIR_OUT:
if (mOutputEndpoint == null) {
mOutputEndpoint = endpt;
}
break;
}
}
// Make sure the required endpoints were present
if (mInputEndpoint == null || mOutputEndpoint == null) {
Log.w(TAG, "Missing required endpoint on USB device " + getDeviceName());
close();
return false;
}
// Start listening for input
mRunning = true;
mInputThread = new InputThread();
mInputThread.start();
return true;
}
@Override
public int sendFeatureReport(byte[] report) {
int res = -1;
int offset = 0;
int length = report.length;
boolean skipped_report_id = false;
byte report_number = report[0];
if (report_number == 0x0) {
++offset;
--length;
skipped_report_id = true;
}
res = mConnection.controlTransfer(
UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_OUT,
0x09/*HID set_report*/,
(3/*HID feature*/ << 8) | report_number,
mInterface,
report, offset, length,
1000/*timeout millis*/);
if (res < 0) {
Log.w(TAG, "sendFeatureReport() returned " + res + " on device " + getDeviceName());
return -1;
}
if (skipped_report_id) {
++length;
}
return length;
}
@Override
public int sendOutputReport(byte[] report) {
int r = mConnection.bulkTransfer(mOutputEndpoint, report, report.length, 1000);
if (r != report.length) {
Log.w(TAG, "sendOutputReport() returned " + r + " on device " + getDeviceName());
}
return r;
}
@Override
public boolean getFeatureReport(byte[] report) {
int res = -1;
int offset = 0;
int length = report.length;
boolean skipped_report_id = false;
byte report_number = report[0];
if (report_number == 0x0) {
/* Offset the return buffer by 1, so that the report ID
will remain in byte 0. */
++offset;
--length;
skipped_report_id = true;
}
res = mConnection.controlTransfer(
UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_IN,
0x01/*HID get_report*/,
(3/*HID feature*/ << 8) | report_number,
mInterface,
report, offset, length,
1000/*timeout millis*/);
if (res < 0) {
Log.w(TAG, "getFeatureReport() returned " + res + " on device " + getDeviceName());
return false;
}
if (skipped_report_id) {
++res;
++length;
}
byte[] data;
if (res == length) {
data = report;
} else {
data = Arrays.copyOfRange(report, 0, res);
}
mManager.HIDDeviceFeatureReport(mDeviceId, data);
return true;
}
@Override
public void close() {
mRunning = false;
if (mInputThread != null) {
while (mInputThread.isAlive()) {
mInputThread.interrupt();
try {
mInputThread.join();
} catch (InterruptedException e) {
// Keep trying until we're done
}
}
mInputThread = null;
}
if (mConnection != null) {
UsbInterface iface = mDevice.getInterface(mInterfaceIndex);
mConnection.releaseInterface(iface);
mConnection.close();
mConnection = null;
}
}
@Override
public void shutdown() {
close();
mManager = null;
}
@Override
public void setFrozen(boolean frozen) {
mFrozen = frozen;
}
protected class InputThread extends Thread {
@Override
public void run() {
int packetSize = mInputEndpoint.getMaxPacketSize();
byte[] packet = new byte[packetSize];
while (mRunning) {
int r;
try
{
r = mConnection.bulkTransfer(mInputEndpoint, packet, packetSize, 1000);
}
catch (Exception e)
{
Log.v(TAG, "Exception in UsbDeviceConnection bulktransfer: " + e);
break;
}
if (r < 0) {
// Could be a timeout or an I/O error
}
if (r > 0) {
byte[] data;
if (r == packetSize) {
data = packet;
} else {
data = Arrays.copyOfRange(packet, 0, r);
}
if (!mFrozen) {
mManager.HIDDeviceInputReport(mDeviceId, data);
}
}
}
}
}
}

View File

@@ -1,84 +0,0 @@
package org.libsdl.app;
import android.content.Context;
import java.lang.reflect.*;
/**
SDL library initialization
*/
public class SDL {
// This function should be called first and sets up the native code
// so it can call into the Java classes
public static void setupJNI() {
SDLActivity.nativeSetupJNI();
SDLAudioManager.nativeSetupJNI();
SDLControllerManager.nativeSetupJNI();
}
// This function should be called each time the activity is started
public static void initialize() {
setContext(null);
SDLActivity.initialize();
SDLAudioManager.initialize();
SDLControllerManager.initialize();
}
// This function stores the current activity (SDL or not)
public static void setContext(Context context) {
mContext = context;
}
public static Context getContext() {
return mContext;
}
public static void loadLibrary(String libraryName) throws UnsatisfiedLinkError, SecurityException, NullPointerException {
if (libraryName == null) {
throw new NullPointerException("No library name provided.");
}
try {
// Let's see if we have ReLinker available in the project. This is necessary for
// some projects that have huge numbers of local libraries bundled, and thus may
// trip a bug in Android's native library loader which ReLinker works around. (If
// loadLibrary works properly, ReLinker will simply use the normal Android method
// internally.)
//
// To use ReLinker, just add it as a dependency. For more information, see
// https://github.com/KeepSafe/ReLinker for ReLinker's repository.
//
Class relinkClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker");
Class relinkListenerClass = mContext.getClassLoader().loadClass("com.getkeepsafe.relinker.ReLinker$LoadListener");
Class contextClass = mContext.getClassLoader().loadClass("android.content.Context");
Class stringClass = mContext.getClassLoader().loadClass("java.lang.String");
// Get a 'force' instance of the ReLinker, so we can ensure libraries are reinstalled if
// they've changed during updates.
Method forceMethod = relinkClass.getDeclaredMethod("force");
Object relinkInstance = forceMethod.invoke(null);
Class relinkInstanceClass = relinkInstance.getClass();
// Actually load the library!
Method loadMethod = relinkInstanceClass.getDeclaredMethod("loadLibrary", contextClass, stringClass, stringClass, relinkListenerClass);
loadMethod.invoke(relinkInstance, mContext, libraryName, null, null);
}
catch (final Throwable e) {
// Fall back
try {
System.loadLibrary(libraryName);
}
catch (final UnsatisfiedLinkError ule) {
throw ule;
}
catch (final SecurityException se) {
throw se;
}
}
}
protected static Context mContext;
}

View File

@@ -1,387 +0,0 @@
package org.libsdl.app;
import android.media.*;
import android.os.Build;
import android.util.Log;
public class SDLAudioManager
{
protected static final String TAG = "SDLAudio";
protected static AudioTrack mAudioTrack;
protected static AudioRecord mAudioRecord;
public static void initialize() {
mAudioTrack = null;
mAudioRecord = null;
}
// Audio
protected static String getAudioFormatString(int audioFormat) {
switch (audioFormat) {
case AudioFormat.ENCODING_PCM_8BIT:
return "8-bit";
case AudioFormat.ENCODING_PCM_16BIT:
return "16-bit";
case AudioFormat.ENCODING_PCM_FLOAT:
return "float";
default:
return Integer.toString(audioFormat);
}
}
protected static int[] open(boolean isCapture, int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
int channelConfig;
int sampleSize;
int frameSize;
Log.v(TAG, "Opening " + (isCapture ? "capture" : "playback") + ", requested " + desiredFrames + " frames of " + desiredChannels + " channel " + getAudioFormatString(audioFormat) + " audio at " + sampleRate + " Hz");
/* On older devices let's use known good settings */
if (Build.VERSION.SDK_INT < 21) {
if (desiredChannels > 2) {
desiredChannels = 2;
}
if (sampleRate < 8000) {
sampleRate = 8000;
} else if (sampleRate > 48000) {
sampleRate = 48000;
}
}
if (audioFormat == AudioFormat.ENCODING_PCM_FLOAT) {
int minSDKVersion = (isCapture ? 23 : 21);
if (Build.VERSION.SDK_INT < minSDKVersion) {
audioFormat = AudioFormat.ENCODING_PCM_16BIT;
}
}
switch (audioFormat)
{
case AudioFormat.ENCODING_PCM_8BIT:
sampleSize = 1;
break;
case AudioFormat.ENCODING_PCM_16BIT:
sampleSize = 2;
break;
case AudioFormat.ENCODING_PCM_FLOAT:
sampleSize = 4;
break;
default:
Log.v(TAG, "Requested format " + audioFormat + ", getting ENCODING_PCM_16BIT");
audioFormat = AudioFormat.ENCODING_PCM_16BIT;
sampleSize = 2;
break;
}
if (isCapture) {
switch (desiredChannels) {
case 1:
channelConfig = AudioFormat.CHANNEL_IN_MONO;
break;
case 2:
channelConfig = AudioFormat.CHANNEL_IN_STEREO;
break;
default:
Log.v(TAG, "Requested " + desiredChannels + " channels, getting stereo");
desiredChannels = 2;
channelConfig = AudioFormat.CHANNEL_IN_STEREO;
break;
}
} else {
switch (desiredChannels) {
case 1:
channelConfig = AudioFormat.CHANNEL_OUT_MONO;
break;
case 2:
channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
break;
case 3:
channelConfig = AudioFormat.CHANNEL_OUT_STEREO | AudioFormat.CHANNEL_OUT_FRONT_CENTER;
break;
case 4:
channelConfig = AudioFormat.CHANNEL_OUT_QUAD;
break;
case 5:
channelConfig = AudioFormat.CHANNEL_OUT_QUAD | AudioFormat.CHANNEL_OUT_FRONT_CENTER;
break;
case 6:
channelConfig = AudioFormat.CHANNEL_OUT_5POINT1;
break;
case 7:
channelConfig = AudioFormat.CHANNEL_OUT_5POINT1 | AudioFormat.CHANNEL_OUT_BACK_CENTER;
break;
case 8:
if (Build.VERSION.SDK_INT >= 23) {
channelConfig = AudioFormat.CHANNEL_OUT_7POINT1_SURROUND;
} else {
Log.v(TAG, "Requested " + desiredChannels + " channels, getting 5.1 surround");
desiredChannels = 6;
channelConfig = AudioFormat.CHANNEL_OUT_5POINT1;
}
break;
default:
Log.v(TAG, "Requested " + desiredChannels + " channels, getting stereo");
desiredChannels = 2;
channelConfig = AudioFormat.CHANNEL_OUT_STEREO;
break;
}
/*
Log.v(TAG, "Speaker configuration (and order of channels):");
if ((channelConfig & 0x00000004) != 0) {
Log.v(TAG, " CHANNEL_OUT_FRONT_LEFT");
}
if ((channelConfig & 0x00000008) != 0) {
Log.v(TAG, " CHANNEL_OUT_FRONT_RIGHT");
}
if ((channelConfig & 0x00000010) != 0) {
Log.v(TAG, " CHANNEL_OUT_FRONT_CENTER");
}
if ((channelConfig & 0x00000020) != 0) {
Log.v(TAG, " CHANNEL_OUT_LOW_FREQUENCY");
}
if ((channelConfig & 0x00000040) != 0) {
Log.v(TAG, " CHANNEL_OUT_BACK_LEFT");
}
if ((channelConfig & 0x00000080) != 0) {
Log.v(TAG, " CHANNEL_OUT_BACK_RIGHT");
}
if ((channelConfig & 0x00000100) != 0) {
Log.v(TAG, " CHANNEL_OUT_FRONT_LEFT_OF_CENTER");
}
if ((channelConfig & 0x00000200) != 0) {
Log.v(TAG, " CHANNEL_OUT_FRONT_RIGHT_OF_CENTER");
}
if ((channelConfig & 0x00000400) != 0) {
Log.v(TAG, " CHANNEL_OUT_BACK_CENTER");
}
if ((channelConfig & 0x00000800) != 0) {
Log.v(TAG, " CHANNEL_OUT_SIDE_LEFT");
}
if ((channelConfig & 0x00001000) != 0) {
Log.v(TAG, " CHANNEL_OUT_SIDE_RIGHT");
}
*/
}
frameSize = (sampleSize * desiredChannels);
// Let the user pick a larger buffer if they really want -- but ye
// gods they probably shouldn't, the minimums are horrifyingly high
// latency already
int minBufferSize;
if (isCapture) {
minBufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioFormat);
} else {
minBufferSize = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat);
}
desiredFrames = Math.max(desiredFrames, (minBufferSize + frameSize - 1) / frameSize);
int[] results = new int[4];
if (isCapture) {
if (mAudioRecord == null) {
mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.DEFAULT, sampleRate,
channelConfig, audioFormat, desiredFrames * frameSize);
// see notes about AudioTrack state in audioOpen(), above. Probably also applies here.
if (mAudioRecord.getState() != AudioRecord.STATE_INITIALIZED) {
Log.e(TAG, "Failed during initialization of AudioRecord");
mAudioRecord.release();
mAudioRecord = null;
return null;
}
mAudioRecord.startRecording();
}
results[0] = mAudioRecord.getSampleRate();
results[1] = mAudioRecord.getAudioFormat();
results[2] = mAudioRecord.getChannelCount();
results[3] = desiredFrames;
} else {
if (mAudioTrack == null) {
mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
// Instantiating AudioTrack can "succeed" without an exception and the track may still be invalid
// Ref: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/media/java/android/media/AudioTrack.java
// Ref: http://developer.android.com/reference/android/media/AudioTrack.html#getState()
if (mAudioTrack.getState() != AudioTrack.STATE_INITIALIZED) {
/* Try again, with safer values */
Log.e(TAG, "Failed during initialization of Audio Track");
mAudioTrack.release();
mAudioTrack = null;
return null;
}
mAudioTrack.play();
}
results[0] = mAudioTrack.getSampleRate();
results[1] = mAudioTrack.getAudioFormat();
results[2] = mAudioTrack.getChannelCount();
results[3] = desiredFrames;
}
Log.v(TAG, "Opening " + (isCapture ? "capture" : "playback") + ", got " + results[3] + " frames of " + results[2] + " channel " + getAudioFormatString(results[1]) + " audio at " + results[0] + " Hz");
return results;
}
/**
* This method is called by SDL using JNI.
*/
public static int[] audioOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
return open(false, sampleRate, audioFormat, desiredChannels, desiredFrames);
}
/**
* This method is called by SDL using JNI.
*/
public static void audioWriteFloatBuffer(float[] buffer) {
if (mAudioTrack == null) {
Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
return;
}
for (int i = 0; i < buffer.length;) {
int result = mAudioTrack.write(buffer, i, buffer.length - i, AudioTrack.WRITE_BLOCKING);
if (result > 0) {
i += result;
} else if (result == 0) {
try {
Thread.sleep(1);
} catch(InterruptedException e) {
// Nom nom
}
} else {
Log.w(TAG, "SDL audio: error return from write(float)");
return;
}
}
}
/**
* This method is called by SDL using JNI.
*/
public static void audioWriteShortBuffer(short[] buffer) {
if (mAudioTrack == null) {
Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
return;
}
for (int i = 0; i < buffer.length;) {
int result = mAudioTrack.write(buffer, i, buffer.length - i);
if (result > 0) {
i += result;
} else if (result == 0) {
try {
Thread.sleep(1);
} catch(InterruptedException e) {
// Nom nom
}
} else {
Log.w(TAG, "SDL audio: error return from write(short)");
return;
}
}
}
/**
* This method is called by SDL using JNI.
*/
public static void audioWriteByteBuffer(byte[] buffer) {
if (mAudioTrack == null) {
Log.e(TAG, "Attempted to make audio call with uninitialized audio!");
return;
}
for (int i = 0; i < buffer.length; ) {
int result = mAudioTrack.write(buffer, i, buffer.length - i);
if (result > 0) {
i += result;
} else if (result == 0) {
try {
Thread.sleep(1);
} catch(InterruptedException e) {
// Nom nom
}
} else {
Log.w(TAG, "SDL audio: error return from write(byte)");
return;
}
}
}
/**
* This method is called by SDL using JNI.
*/
public static int[] captureOpen(int sampleRate, int audioFormat, int desiredChannels, int desiredFrames) {
return open(true, sampleRate, audioFormat, desiredChannels, desiredFrames);
}
/** This method is called by SDL using JNI. */
public static int captureReadFloatBuffer(float[] buffer, boolean blocking) {
return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
}
/** This method is called by SDL using JNI. */
public static int captureReadShortBuffer(short[] buffer, boolean blocking) {
if (Build.VERSION.SDK_INT < 23) {
return mAudioRecord.read(buffer, 0, buffer.length);
} else {
return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
}
}
/** This method is called by SDL using JNI. */
public static int captureReadByteBuffer(byte[] buffer, boolean blocking) {
if (Build.VERSION.SDK_INT < 23) {
return mAudioRecord.read(buffer, 0, buffer.length);
} else {
return mAudioRecord.read(buffer, 0, buffer.length, blocking ? AudioRecord.READ_BLOCKING : AudioRecord.READ_NON_BLOCKING);
}
}
/** This method is called by SDL using JNI. */
public static void audioClose() {
if (mAudioTrack != null) {
mAudioTrack.stop();
mAudioTrack.release();
mAudioTrack = null;
}
}
/** This method is called by SDL using JNI. */
public static void captureClose() {
if (mAudioRecord != null) {
mAudioRecord.stop();
mAudioRecord.release();
mAudioRecord = null;
}
}
/** This method is called by SDL using JNI. */
public static void audioSetThreadPriority(boolean iscapture, int device_id) {
try {
/* Set thread name */
if (iscapture) {
Thread.currentThread().setName("SDLAudioC" + device_id);
} else {
Thread.currentThread().setName("SDLAudioP" + device_id);
}
/* Set thread priority */
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_AUDIO);
} catch (Exception e) {
Log.v(TAG, "modify thread properties failed " + e.toString());
}
}
public static native int nativeSetupJNI();
}

View File

@@ -1,788 +0,0 @@
package org.libsdl.app;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import android.content.Context;
import android.os.*;
import android.view.*;
import android.util.Log;
public class SDLControllerManager
{
public static native int nativeSetupJNI();
public static native int nativeAddJoystick(int device_id, String name, String desc,
int vendor_id, int product_id,
boolean is_accelerometer, int button_mask,
int naxes, int nhats, int nballs);
public static native int nativeRemoveJoystick(int device_id);
public static native int nativeAddHaptic(int device_id, String name);
public static native int nativeRemoveHaptic(int device_id);
public static native int onNativePadDown(int device_id, int keycode);
public static native int onNativePadUp(int device_id, int keycode);
public static native void onNativeJoy(int device_id, int axis,
float value);
public static native void onNativeHat(int device_id, int hat_id,
int x, int y);
protected static SDLJoystickHandler mJoystickHandler;
protected static SDLHapticHandler mHapticHandler;
private static final String TAG = "SDLControllerManager";
public static void initialize() {
if (mJoystickHandler == null) {
if (Build.VERSION.SDK_INT >= 19) {
mJoystickHandler = new SDLJoystickHandler_API19();
} else {
mJoystickHandler = new SDLJoystickHandler_API16();
}
}
if (mHapticHandler == null) {
if (Build.VERSION.SDK_INT >= 26) {
mHapticHandler = new SDLHapticHandler_API26();
} else {
mHapticHandler = new SDLHapticHandler();
}
}
}
// Joystick glue code, just a series of stubs that redirect to the SDLJoystickHandler instance
public static boolean handleJoystickMotionEvent(MotionEvent event) {
return mJoystickHandler.handleMotionEvent(event);
}
/**
* This method is called by SDL using JNI.
*/
public static void pollInputDevices() {
mJoystickHandler.pollInputDevices();
}
/**
* This method is called by SDL using JNI.
*/
public static void pollHapticDevices() {
mHapticHandler.pollHapticDevices();
}
/**
* This method is called by SDL using JNI.
*/
public static void hapticRun(int device_id, float intensity, int length) {
mHapticHandler.run(device_id, intensity, length);
}
/**
* This method is called by SDL using JNI.
*/
public static void hapticStop(int device_id)
{
mHapticHandler.stop(device_id);
}
// Check if a given device is considered a possible SDL joystick
public static boolean isDeviceSDLJoystick(int deviceId) {
InputDevice device = InputDevice.getDevice(deviceId);
// We cannot use InputDevice.isVirtual before API 16, so let's accept
// only nonnegative device ids (VIRTUAL_KEYBOARD equals -1)
if ((device == null) || (deviceId < 0)) {
return false;
}
int sources = device.getSources();
/* This is called for every button press, so let's not spam the logs */
/**
if ((sources & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
Log.v(TAG, "Input device " + device.getName() + " has class joystick.");
}
if ((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) {
Log.v(TAG, "Input device " + device.getName() + " is a dpad.");
}
if ((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) {
Log.v(TAG, "Input device " + device.getName() + " is a gamepad.");
}
**/
return ((sources & InputDevice.SOURCE_CLASS_JOYSTICK) != 0 ||
((sources & InputDevice.SOURCE_DPAD) == InputDevice.SOURCE_DPAD) ||
((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD)
);
}
}
class SDLJoystickHandler {
/**
* Handles given MotionEvent.
* @param event the event to be handled.
* @return if given event was processed.
*/
public boolean handleMotionEvent(MotionEvent event) {
return false;
}
/**
* Handles adding and removing of input devices.
*/
public void pollInputDevices() {
}
}
/* Actual joystick functionality available for API >= 12 devices */
class SDLJoystickHandler_API16 extends SDLJoystickHandler {
static class SDLJoystick {
public int device_id;
public String name;
public String desc;
public ArrayList<InputDevice.MotionRange> axes;
public ArrayList<InputDevice.MotionRange> hats;
}
static class RangeComparator implements Comparator<InputDevice.MotionRange> {
@Override
public int compare(InputDevice.MotionRange arg0, InputDevice.MotionRange arg1) {
// Some controllers, like the Moga Pro 2, return AXIS_GAS (22) for right trigger and AXIS_BRAKE (23) for left trigger - swap them so they're sorted in the right order for SDL
int arg0Axis = arg0.getAxis();
int arg1Axis = arg1.getAxis();
if (arg0Axis == MotionEvent.AXIS_GAS) {
arg0Axis = MotionEvent.AXIS_BRAKE;
} else if (arg0Axis == MotionEvent.AXIS_BRAKE) {
arg0Axis = MotionEvent.AXIS_GAS;
}
if (arg1Axis == MotionEvent.AXIS_GAS) {
arg1Axis = MotionEvent.AXIS_BRAKE;
} else if (arg1Axis == MotionEvent.AXIS_BRAKE) {
arg1Axis = MotionEvent.AXIS_GAS;
}
return arg0Axis - arg1Axis;
}
}
private ArrayList<SDLJoystick> mJoysticks;
public SDLJoystickHandler_API16() {
mJoysticks = new ArrayList<SDLJoystick>();
}
@Override
public void pollInputDevices() {
int[] deviceIds = InputDevice.getDeviceIds();
for(int i=0; i < deviceIds.length; ++i) {
SDLJoystick joystick = getJoystick(deviceIds[i]);
if (joystick == null) {
joystick = new SDLJoystick();
InputDevice joystickDevice = InputDevice.getDevice(deviceIds[i]);
if (SDLControllerManager.isDeviceSDLJoystick(deviceIds[i])) {
joystick.device_id = deviceIds[i];
joystick.name = joystickDevice.getName();
joystick.desc = getJoystickDescriptor(joystickDevice);
joystick.axes = new ArrayList<InputDevice.MotionRange>();
joystick.hats = new ArrayList<InputDevice.MotionRange>();
List<InputDevice.MotionRange> ranges = joystickDevice.getMotionRanges();
Collections.sort(ranges, new RangeComparator());
for (InputDevice.MotionRange range : ranges ) {
if ((range.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) != 0) {
if (range.getAxis() == MotionEvent.AXIS_HAT_X ||
range.getAxis() == MotionEvent.AXIS_HAT_Y) {
joystick.hats.add(range);
}
else {
joystick.axes.add(range);
}
}
}
mJoysticks.add(joystick);
SDLControllerManager.nativeAddJoystick(joystick.device_id, joystick.name, joystick.desc, getVendorId(joystickDevice), getProductId(joystickDevice), false, getButtonMask(joystickDevice), joystick.axes.size(), joystick.hats.size()/2, 0);
}
}
}
/* Check removed devices */
ArrayList<Integer> removedDevices = new ArrayList<Integer>();
for(int i=0; i < mJoysticks.size(); i++) {
int device_id = mJoysticks.get(i).device_id;
int j;
for (j=0; j < deviceIds.length; j++) {
if (device_id == deviceIds[j]) break;
}
if (j == deviceIds.length) {
removedDevices.add(Integer.valueOf(device_id));
}
}
for(int i=0; i < removedDevices.size(); i++) {
int device_id = removedDevices.get(i).intValue();
SDLControllerManager.nativeRemoveJoystick(device_id);
for (int j=0; j < mJoysticks.size(); j++) {
if (mJoysticks.get(j).device_id == device_id) {
mJoysticks.remove(j);
break;
}
}
}
}
protected SDLJoystick getJoystick(int device_id) {
for(int i=0; i < mJoysticks.size(); i++) {
if (mJoysticks.get(i).device_id == device_id) {
return mJoysticks.get(i);
}
}
return null;
}
@Override
public boolean handleMotionEvent(MotionEvent event) {
if ((event.getSource() & InputDevice.SOURCE_JOYSTICK) != 0) {
int actionPointerIndex = event.getActionIndex();
int action = event.getActionMasked();
switch(action) {
case MotionEvent.ACTION_MOVE:
SDLJoystick joystick = getJoystick(event.getDeviceId());
if ( joystick != null ) {
for (int i = 0; i < joystick.axes.size(); i++) {
InputDevice.MotionRange range = joystick.axes.get(i);
/* Normalize the value to -1...1 */
float value = ( event.getAxisValue( range.getAxis(), actionPointerIndex) - range.getMin() ) / range.getRange() * 2.0f - 1.0f;
SDLControllerManager.onNativeJoy(joystick.device_id, i, value );
}
for (int i = 0; i < joystick.hats.size(); i+=2) {
int hatX = Math.round(event.getAxisValue( joystick.hats.get(i).getAxis(), actionPointerIndex ) );
int hatY = Math.round(event.getAxisValue( joystick.hats.get(i+1).getAxis(), actionPointerIndex ) );
SDLControllerManager.onNativeHat(joystick.device_id, i/2, hatX, hatY );
}
}
break;
default:
break;
}
}
return true;
}
public String getJoystickDescriptor(InputDevice joystickDevice) {
String desc = joystickDevice.getDescriptor();
if (desc != null && !desc.isEmpty()) {
return desc;
}
return joystickDevice.getName();
}
public int getProductId(InputDevice joystickDevice) {
return 0;
}
public int getVendorId(InputDevice joystickDevice) {
return 0;
}
public int getButtonMask(InputDevice joystickDevice) {
return -1;
}
}
class SDLJoystickHandler_API19 extends SDLJoystickHandler_API16 {
@Override
public int getProductId(InputDevice joystickDevice) {
return joystickDevice.getProductId();
}
@Override
public int getVendorId(InputDevice joystickDevice) {
return joystickDevice.getVendorId();
}
@Override
public int getButtonMask(InputDevice joystickDevice) {
int button_mask = 0;
int[] keys = new int[] {
KeyEvent.KEYCODE_BUTTON_A,
KeyEvent.KEYCODE_BUTTON_B,
KeyEvent.KEYCODE_BUTTON_X,
KeyEvent.KEYCODE_BUTTON_Y,
KeyEvent.KEYCODE_BACK,
KeyEvent.KEYCODE_BUTTON_MODE,
KeyEvent.KEYCODE_BUTTON_START,
KeyEvent.KEYCODE_BUTTON_THUMBL,
KeyEvent.KEYCODE_BUTTON_THUMBR,
KeyEvent.KEYCODE_BUTTON_L1,
KeyEvent.KEYCODE_BUTTON_R1,
KeyEvent.KEYCODE_DPAD_UP,
KeyEvent.KEYCODE_DPAD_DOWN,
KeyEvent.KEYCODE_DPAD_LEFT,
KeyEvent.KEYCODE_DPAD_RIGHT,
KeyEvent.KEYCODE_BUTTON_SELECT,
KeyEvent.KEYCODE_DPAD_CENTER,
// These don't map into any SDL controller buttons directly
KeyEvent.KEYCODE_BUTTON_L2,
KeyEvent.KEYCODE_BUTTON_R2,
KeyEvent.KEYCODE_BUTTON_C,
KeyEvent.KEYCODE_BUTTON_Z,
KeyEvent.KEYCODE_BUTTON_1,
KeyEvent.KEYCODE_BUTTON_2,
KeyEvent.KEYCODE_BUTTON_3,
KeyEvent.KEYCODE_BUTTON_4,
KeyEvent.KEYCODE_BUTTON_5,
KeyEvent.KEYCODE_BUTTON_6,
KeyEvent.KEYCODE_BUTTON_7,
KeyEvent.KEYCODE_BUTTON_8,
KeyEvent.KEYCODE_BUTTON_9,
KeyEvent.KEYCODE_BUTTON_10,
KeyEvent.KEYCODE_BUTTON_11,
KeyEvent.KEYCODE_BUTTON_12,
KeyEvent.KEYCODE_BUTTON_13,
KeyEvent.KEYCODE_BUTTON_14,
KeyEvent.KEYCODE_BUTTON_15,
KeyEvent.KEYCODE_BUTTON_16,
};
int[] masks = new int[] {
(1 << 0), // A -> A
(1 << 1), // B -> B
(1 << 2), // X -> X
(1 << 3), // Y -> Y
(1 << 4), // BACK -> BACK
(1 << 5), // MODE -> GUIDE
(1 << 6), // START -> START
(1 << 7), // THUMBL -> LEFTSTICK
(1 << 8), // THUMBR -> RIGHTSTICK
(1 << 9), // L1 -> LEFTSHOULDER
(1 << 10), // R1 -> RIGHTSHOULDER
(1 << 11), // DPAD_UP -> DPAD_UP
(1 << 12), // DPAD_DOWN -> DPAD_DOWN
(1 << 13), // DPAD_LEFT -> DPAD_LEFT
(1 << 14), // DPAD_RIGHT -> DPAD_RIGHT
(1 << 4), // SELECT -> BACK
(1 << 0), // DPAD_CENTER -> A
(1 << 15), // L2 -> ??
(1 << 16), // R2 -> ??
(1 << 17), // C -> ??
(1 << 18), // Z -> ??
(1 << 20), // 1 -> ??
(1 << 21), // 2 -> ??
(1 << 22), // 3 -> ??
(1 << 23), // 4 -> ??
(1 << 24), // 5 -> ??
(1 << 25), // 6 -> ??
(1 << 26), // 7 -> ??
(1 << 27), // 8 -> ??
(1 << 28), // 9 -> ??
(1 << 29), // 10 -> ??
(1 << 30), // 11 -> ??
(1 << 31), // 12 -> ??
// We're out of room...
0xFFFFFFFF, // 13 -> ??
0xFFFFFFFF, // 14 -> ??
0xFFFFFFFF, // 15 -> ??
0xFFFFFFFF, // 16 -> ??
};
boolean[] has_keys = joystickDevice.hasKeys(keys);
for (int i = 0; i < keys.length; ++i) {
if (has_keys[i]) {
button_mask |= masks[i];
}
}
return button_mask;
}
}
class SDLHapticHandler_API26 extends SDLHapticHandler {
@Override
public void run(int device_id, float intensity, int length) {
SDLHaptic haptic = getHaptic(device_id);
if (haptic != null) {
Log.d("SDL", "Rtest: Vibe with intensity " + intensity + " for " + length);
if (intensity == 0.0f) {
stop(device_id);
return;
}
int vibeValue = Math.round(intensity * 255);
if (vibeValue > 255) {
vibeValue = 255;
}
if (vibeValue < 1) {
stop(device_id);
return;
}
try {
haptic.vib.vibrate(VibrationEffect.createOneShot(length, vibeValue));
}
catch (Exception e) {
// Fall back to the generic method, which uses DEFAULT_AMPLITUDE, but works even if
// something went horribly wrong with the Android 8.0 APIs.
haptic.vib.vibrate(length);
}
}
}
}
class SDLHapticHandler {
class SDLHaptic {
public int device_id;
public String name;
public Vibrator vib;
}
private ArrayList<SDLHaptic> mHaptics;
public SDLHapticHandler() {
mHaptics = new ArrayList<SDLHaptic>();
}
public void run(int device_id, float intensity, int length) {
SDLHaptic haptic = getHaptic(device_id);
if (haptic != null) {
haptic.vib.vibrate(length);
}
}
public void stop(int device_id) {
SDLHaptic haptic = getHaptic(device_id);
if (haptic != null) {
haptic.vib.cancel();
}
}
public void pollHapticDevices() {
final int deviceId_VIBRATOR_SERVICE = 999999;
boolean hasVibratorService = false;
int[] deviceIds = InputDevice.getDeviceIds();
// It helps processing the device ids in reverse order
// For example, in the case of the XBox 360 wireless dongle,
// so the first controller seen by SDL matches what the receiver
// considers to be the first controller
for (int i = deviceIds.length - 1; i > -1; i--) {
SDLHaptic haptic = getHaptic(deviceIds[i]);
if (haptic == null) {
InputDevice device = InputDevice.getDevice(deviceIds[i]);
Vibrator vib = device.getVibrator();
if (vib.hasVibrator()) {
haptic = new SDLHaptic();
haptic.device_id = deviceIds[i];
haptic.name = device.getName();
haptic.vib = vib;
mHaptics.add(haptic);
SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
}
}
}
/* Check VIBRATOR_SERVICE */
Vibrator vib = (Vibrator) SDL.getContext().getSystemService(Context.VIBRATOR_SERVICE);
if (vib != null) {
hasVibratorService = vib.hasVibrator();
if (hasVibratorService) {
SDLHaptic haptic = getHaptic(deviceId_VIBRATOR_SERVICE);
if (haptic == null) {
haptic = new SDLHaptic();
haptic.device_id = deviceId_VIBRATOR_SERVICE;
haptic.name = "VIBRATOR_SERVICE";
haptic.vib = vib;
mHaptics.add(haptic);
SDLControllerManager.nativeAddHaptic(haptic.device_id, haptic.name);
}
}
}
/* Check removed devices */
ArrayList<Integer> removedDevices = new ArrayList<Integer>();
for(int i=0; i < mHaptics.size(); i++) {
int device_id = mHaptics.get(i).device_id;
int j;
for (j=0; j < deviceIds.length; j++) {
if (device_id == deviceIds[j]) break;
}
if (device_id == deviceId_VIBRATOR_SERVICE && hasVibratorService) {
// don't remove the vibrator if it is still present
} else if (j == deviceIds.length) {
removedDevices.add(device_id);
}
}
for(int i=0; i < removedDevices.size(); i++) {
int device_id = removedDevices.get(i);
SDLControllerManager.nativeRemoveHaptic(device_id);
for (int j=0; j < mHaptics.size(); j++) {
if (mHaptics.get(j).device_id == device_id) {
mHaptics.remove(j);
break;
}
}
}
}
protected SDLHaptic getHaptic(int device_id) {
for(int i=0; i < mHaptics.size(); i++) {
if (mHaptics.get(i).device_id == device_id) {
return mHaptics.get(i);
}
}
return null;
}
}
class SDLGenericMotionListener_API12 implements View.OnGenericMotionListener {
// Generic Motion (mouse hover, joystick...) events go here
@Override
public boolean onGenericMotion(View v, MotionEvent event) {
float x, y;
int action;
switch ( event.getSource() ) {
case InputDevice.SOURCE_JOYSTICK:
case InputDevice.SOURCE_GAMEPAD:
case InputDevice.SOURCE_DPAD:
return SDLControllerManager.handleJoystickMotionEvent(event);
case InputDevice.SOURCE_MOUSE:
action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_SCROLL:
x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
SDLActivity.onNativeMouse(0, action, x, y, false);
return true;
case MotionEvent.ACTION_HOVER_MOVE:
x = event.getX(0);
y = event.getY(0);
SDLActivity.onNativeMouse(0, action, x, y, false);
return true;
default:
break;
}
break;
default:
break;
}
// Event was not managed
return false;
}
public boolean supportsRelativeMouse() {
return false;
}
public boolean inRelativeMode() {
return false;
}
public boolean setRelativeMouseEnabled(boolean enabled) {
return false;
}
public void reclaimRelativeMouseModeIfNeeded()
{
}
public float getEventX(MotionEvent event) {
return event.getX(0);
}
public float getEventY(MotionEvent event) {
return event.getY(0);
}
}
class SDLGenericMotionListener_API24 extends SDLGenericMotionListener_API12 {
// Generic Motion (mouse hover, joystick...) events go here
private boolean mRelativeModeEnabled;
@Override
public boolean onGenericMotion(View v, MotionEvent event) {
// Handle relative mouse mode
if (mRelativeModeEnabled) {
if (event.getSource() == InputDevice.SOURCE_MOUSE) {
int action = event.getActionMasked();
if (action == MotionEvent.ACTION_HOVER_MOVE) {
float x = event.getAxisValue(MotionEvent.AXIS_RELATIVE_X);
float y = event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y);
SDLActivity.onNativeMouse(0, action, x, y, true);
return true;
}
}
}
// Event was not managed, call SDLGenericMotionListener_API12 method
return super.onGenericMotion(v, event);
}
@Override
public boolean supportsRelativeMouse() {
return true;
}
@Override
public boolean inRelativeMode() {
return mRelativeModeEnabled;
}
@Override
public boolean setRelativeMouseEnabled(boolean enabled) {
mRelativeModeEnabled = enabled;
return true;
}
@Override
public float getEventX(MotionEvent event) {
if (mRelativeModeEnabled) {
return event.getAxisValue(MotionEvent.AXIS_RELATIVE_X);
}
else {
return event.getX(0);
}
}
@Override
public float getEventY(MotionEvent event) {
if (mRelativeModeEnabled) {
return event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y);
}
else {
return event.getY(0);
}
}
}
class SDLGenericMotionListener_API26 extends SDLGenericMotionListener_API24 {
// Generic Motion (mouse hover, joystick...) events go here
private boolean mRelativeModeEnabled;
@Override
public boolean onGenericMotion(View v, MotionEvent event) {
float x, y;
int action;
switch ( event.getSource() ) {
case InputDevice.SOURCE_JOYSTICK:
case InputDevice.SOURCE_GAMEPAD:
case InputDevice.SOURCE_DPAD:
return SDLControllerManager.handleJoystickMotionEvent(event);
case InputDevice.SOURCE_MOUSE:
// DeX desktop mouse cursor is a separate non-standard input type.
case InputDevice.SOURCE_MOUSE | InputDevice.SOURCE_TOUCHSCREEN:
action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_SCROLL:
x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
SDLActivity.onNativeMouse(0, action, x, y, false);
return true;
case MotionEvent.ACTION_HOVER_MOVE:
x = event.getX(0);
y = event.getY(0);
SDLActivity.onNativeMouse(0, action, x, y, false);
return true;
default:
break;
}
break;
case InputDevice.SOURCE_MOUSE_RELATIVE:
action = event.getActionMasked();
switch (action) {
case MotionEvent.ACTION_SCROLL:
x = event.getAxisValue(MotionEvent.AXIS_HSCROLL, 0);
y = event.getAxisValue(MotionEvent.AXIS_VSCROLL, 0);
SDLActivity.onNativeMouse(0, action, x, y, false);
return true;
case MotionEvent.ACTION_HOVER_MOVE:
x = event.getX(0);
y = event.getY(0);
SDLActivity.onNativeMouse(0, action, x, y, true);
return true;
default:
break;
}
break;
default:
break;
}
// Event was not managed
return false;
}
@Override
public boolean supportsRelativeMouse() {
return (!SDLActivity.isDeXMode() || (Build.VERSION.SDK_INT >= 27));
}
@Override
public boolean inRelativeMode() {
return mRelativeModeEnabled;
}
@Override
public boolean setRelativeMouseEnabled(boolean enabled) {
if (!SDLActivity.isDeXMode() || (Build.VERSION.SDK_INT >= 27)) {
if (enabled) {
SDLActivity.getContentView().requestPointerCapture();
}
else {
SDLActivity.getContentView().releasePointerCapture();
}
mRelativeModeEnabled = enabled;
return true;
}
else
{
return false;
}
}
@Override
public void reclaimRelativeMouseModeIfNeeded()
{
if (mRelativeModeEnabled && !SDLActivity.isDeXMode()) {
SDLActivity.getContentView().requestPointerCapture();
}
}
@Override
public float getEventX(MotionEvent event) {
// Relative mouse in capture mode will only have relative for X/Y
return event.getX(0);
}
@Override
public float getEventY(MotionEvent event) {
// Relative mouse in capture mode will only have relative for X/Y
return event.getY(0);
}
}

View File

@@ -1,105 +0,0 @@
package org.thecodedeposit.aerofoil;
import org.libsdl.app.SDLActivity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
public class GpActivity extends SDLActivity
{
private static final int SOURCE_EXPORT_REQUEST_ID = 20;
private AssetManager assetManager;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
assetManager = getAssets();
}
public String[] scanAssetDirectory(String directory)
{
try
{
return this.assetManager.list(directory);
}
catch (java.io.IOException ex)
{
return new String[0];
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent)
{
if (requestCode == SOURCE_EXPORT_REQUEST_ID)
{
if (resultCode == RESULT_OK)
{
Uri uri = intent.getData();
Context context = getContext();
ContentResolver contentResolver = context.getContentResolver();
try
{
ParcelFileDescriptor fd = contentResolver.openFileDescriptor(uri, "w");
GpFileSystemAPI.nativePostSourceExportRequest(false, fd.getFd(), fd);
}
catch (FileNotFoundException e)
{
GpFileSystemAPI.nativePostSourceExportRequest(true, 0, null);
return;
}
catch (IOException e)
{
GpFileSystemAPI.nativePostSourceExportRequest(true, 0, null);
return;
}
catch (Exception e)
{
GpFileSystemAPI.nativePostSourceExportRequest(true, 0, null);
return;
}
}
else
GpFileSystemAPI.nativePostSourceExportRequest(true, 0, null);
}
else
{
super.onActivityResult(requestCode, resultCode, intent);
}
}
public void selectSourceExportPath(String fname)
{
Intent intent = new Intent(Intent.ACTION_CREATE_DOCUMENT)
.setType("application/zip")
.addCategory(Intent.CATEGORY_OPENABLE)
.putExtra(Intent.EXTRA_TITLE, fname);
startActivityForResult(intent, SOURCE_EXPORT_REQUEST_ID);
}
public void closeSourceExportPFD(Object obj)
{
try
{
((ParcelFileDescriptor) obj).close();
}
catch (IOException e)
{
}
}
}

View File

@@ -1,6 +0,0 @@
package org.thecodedeposit.aerofoil;
public class GpFileSystemAPI
{
public static native void nativePostSourceExportRequest(boolean cancelled, int fd, Object pfd);
}

View File

@@ -1,5 +0,0 @@
package org.thecodedeposit.aerofoil;
public class GpSystemServices
{
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 525 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 746 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 966 B

View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>

View File

@@ -1,3 +0,0 @@
<resources>
<string name="app_name">Aerofoil</string>
</resources>

View File

@@ -1,8 +0,0 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
<!-- Customize your theme here. -->
</style>
</resources>

View File

@@ -1,25 +0,0 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
google()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}

View File

@@ -1,12 +0,0 @@
cd app
cd src
cd main
cd assets
rmdir /S /Q Packaged
mkdir Packaged
cd Packaged
rmdir /S /Q Houses
mkdir Houses
copy ..\..\..\..\..\..\Packaged\*.gpa .\
copy ..\..\..\..\..\..\Packaged\Houses\* Houses\
cd ..

View File

@@ -1,8 +0,0 @@
cd ..
copy /Y DefaultTimestamp.timestamp AerofoilAndroid\app\src\main\assets\Packaged\DefaultTimestamp.timestamp
del AerofoilAndroid\app\src\main\assets\Packaged\SourceCode.zip
del AerofoilAndroid\app\src\main\assets\Packaged\SourceCode.pkg
git archive -0 --format zip -o AerofoilAndroid\app\src\main\assets\Packaged\SourceCode.zip HEAD
tools\7z.exe d AerofoilAndroid\app\src\main\assets\Packaged\SourceCode.zip GliderProData\
cd AerofoilAndroid\app\src\main\assets\Packaged
rename SourceCode.zip SourceCode.pkg

View File

@@ -1,17 +0,0 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

Binary file not shown.

View File

@@ -1,6 +0,0 @@
#Sat Oct 17 02:06:49 EDT 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip

View File

@@ -1,160 +0,0 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

View File

@@ -1,90 +0,0 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -1,21 +0,0 @@
@setlocal enableextensions
@cd /d "%~dp0"
call remove_symlinks.bat
mklink /D app\jni\AerofoilSDL ..\..\..\AerofoilSDL
mklink /D app\jni\Common ..\..\..\Common
mklink /D app\jni\SDL2 ..\..\..\SDL2-2.0.12
mklink /D app\jni\GpApp ..\..\..\GpApp
mklink /D app\jni\GpShell ..\..\..\GpShell
mklink /D app\jni\GpCommon ..\..\..\GpCommon
mklink /D app\jni\GpFontHandler_FreeType2 ..\..\..\GpFontHandler_FreeType2
mklink /D app\jni\PortabilityLayer ..\..\..\PortabilityLayer
mklink /D app\jni\FreeType ..\..\..\FreeType
mklink /D app\jni\rapidjson ..\..\..\rapidjson
mklink /D app\jni\MacRomanConversion ..\..\..\MacRomanConversion
mklink /D app\jni\stb ..\..\..\stb
mklink /D app\src\main\assets\Resources ..\..\..\..\..\Resources
pause

View File

@@ -1,17 +0,0 @@
@setlocal enableextensions
@cd /d "%~dp0"
rmdir app\jni\AerofoilSDL
rmdir app\jni\Common
rmdir app\jni\SDL2
rmdir app\jni\GpShell
rmdir app\jni\GpCommon
rmdir app\jni\GpApp
rmdir app\jni\GpFontHandler_FreeType2
rmdir app\jni\PortabilityLayer
rmdir app\jni\FreeType
rmdir app\jni\zlib
rmdir app\jni\rapidjson
rmdir app\jni\MacRomanConversion
rmdir app\jni\stb
rmdir app\src\main\assets\Resources

View File

@@ -1 +0,0 @@
include ':app'

View File

@@ -1,16 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup>
<IncludePath>$(SolutionDir)SDL2-2.0.12\include;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)SDL2-2.0.12\lib\x64;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<ItemDefinitionGroup>
<Link>
<AdditionalDependencies>SDL2.lib;SDL2main.lib;%(AdditionalDependencies)</AdditionalDependencies>
<SubSystem>Windows</SubSystem>
</Link>
</ItemDefinitionGroup>
<ItemGroup />
</Project>

View File

@@ -1,129 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>15.0</VCProjectVersion>
<ProjectGuid>{33542FF0-0473-4802-BC79-3B8261790F65}</ProjectGuid>
<RootNamespace>AerofoilSDL</RootNamespace>
<WindowsTargetPlatformVersion>10.0.17763.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v141</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>MultiByte</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="AerofoilSDL.props" />
<Import Project="..\Common.props" />
<Import Project="..\GpShell.props" />
<Import Project="..\GpMainApp.props" />
<Import Project="..\PortabilityLayer.props" />
<Import Project="..\GpCommon.props" />
<Import Project="..\Debug.props" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
<Import Project="AerofoilSDL.props" />
<Import Project="..\Common.props" />
<Import Project="..\GpShell.props" />
<Import Project="..\Release.props" />
<Import Project="..\GpMainApp.props" />
<Import Project="..\PortabilityLayer.props" />
<Import Project="..\GpCommon.props" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup />
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<SDLCheck>true</SDLCheck>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<AdditionalDependencies>shlwapi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\Aerofoil\GpColorCursor_Win32.cpp" />
<ClCompile Include="..\Aerofoil\GpFileStream_Win32.cpp" />
<ClCompile Include="..\Aerofoil\GpFileSystem_Win32.cpp" />
<ClCompile Include="..\Aerofoil\GpLogDriver_Win32.cpp" />
<ClCompile Include="..\Aerofoil\GpMutex_Win32.cpp" />
<ClCompile Include="..\Aerofoil\GpSystemServices_Win32.cpp" />
<ClCompile Include="..\Aerofoil\GpThreadEvent_Win32.cpp" />
<ClCompile Include="GpAudioDriver_SDL2.cpp" />
<ClCompile Include="GpDisplayDriver_SDL_GL2.cpp" />
<ClCompile Include="GpFiberStarter_SDL.cpp" />
<ClCompile Include="GpFiber_SDL.cpp" />
<ClCompile Include="GpMain_SDL_Win32.cpp" />
<ClCompile Include="ShaderCode\CopyQuadP.cpp" />
<ClCompile Include="ShaderCode\DrawQuadPaletteP.cpp" />
<ClCompile Include="ShaderCode\DrawQuadV.cpp" />
<ClCompile Include="ShaderCode\ScaleQuadP.cpp" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\GpApp\GpApp.vcxproj">
<Project>{6233c3f2-5781-488e-b190-4fa8836f5a77}</Project>
</ProjectReference>
<ProjectReference Include="..\GpAudioDriver_XAudio2\GpAudioDriver_XAudio2.vcxproj">
<Project>{e3bdc783-8646-433e-adf0-8b6390d36669}</Project>
</ProjectReference>
<ProjectReference Include="..\GpFontHandler_FreeType2\GpFontHandler_FreeType2.vcxproj">
<Project>{4b564030-8985-4975-91e1-e1b2c16ae2a1}</Project>
</ProjectReference>
<ProjectReference Include="..\GpInputDriver_XInput\GpInputDriver_XInput.vcxproj">
<Project>{17b96f07-ef92-47cd-95a5-8e6ee38ab564}</Project>
</ProjectReference>
<ProjectReference Include="..\GpShell\GpShell.vcxproj">
<Project>{10cf9b5f-61d0-4b5b-89f4-810b58fc053d}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClInclude Include="GpFiber_SDL.h" />
<ClInclude Include="ShaderCode\DrawQuadPixelConstants.h" />
<ClInclude Include="ShaderCode\Functions.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@@ -1,81 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
<Filter Include="Source Files\ShaderCode">
<UniqueIdentifier>{85279826-1cd2-4894-a780-3f74af9c1260}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="GpMain_SDL_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Aerofoil\GpFileSystem_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Aerofoil\GpSystemServices_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Aerofoil\GpColorCursor_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Aerofoil\GpMutex_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Aerofoil\GpThreadEvent_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Aerofoil\GpFileStream_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ShaderCode\DrawQuadV.cpp">
<Filter>Source Files\ShaderCode</Filter>
</ClCompile>
<ClCompile Include="ShaderCode\DrawQuadPaletteP.cpp">
<Filter>Source Files\ShaderCode</Filter>
</ClCompile>
<ClCompile Include="ShaderCode\ScaleQuadP.cpp">
<Filter>Source Files\ShaderCode</Filter>
</ClCompile>
<ClCompile Include="GpFiber_SDL.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpFiberStarter_SDL.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpDisplayDriver_SDL_GL2.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="GpAudioDriver_SDL2.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\Aerofoil\GpLogDriver_Win32.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="ShaderCode\CopyQuadP.cpp">
<Filter>Source Files\ShaderCode</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ShaderCode\Functions.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="ShaderCode\DrawQuadPixelConstants.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="GpFiber_SDL.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -1,29 +0,0 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := AerofoilSDL
SDL_PATH := ../SDL2
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/../GpCommon \
$(LOCAL_PATH)/../GpShell \
$(LOCAL_PATH)/../Common \
$(LOCAL_PATH)/../PortabilityLayer \
$(LOCAL_PATH)/$(SDL_PATH)/include
LOCAL_CFLAGS := -DGP_DEBUG_CONFIG=0
# Add your application source files here...
LOCAL_SRC_FILES := \
GpAudioDriver_SDL2.cpp \
GpDisplayDriver_SDL_GL2.cpp \
GpFiber_SDL.cpp \
GpFiberStarter_SDL.cpp \
ShaderCode/CopyQuadP.cpp \
ShaderCode/DrawQuadPaletteP.cpp \
ShaderCode/DrawQuadV.cpp \
ShaderCode/ScaleQuadP.cpp
include $(BUILD_STATIC_LIBRARY)

View File

@@ -1,566 +0,0 @@
#include "IGpAudioDriver.h"
#include "IGpAudioChannel.h"
#include "IGpAudioChannelCallbacks.h"
#include "IGpPrefsHandler.h"
#include "GpAudioDriverProperties.h"
#include "CoreDefs.h"
#include "HostMutex.h"
#include "HostSystemServices.h"
#include "SDL_audio.h"
#include "GpRingBuffer.h"
#include "SDL_atomic.h"
#include <stdlib.h>
#include <string.h>
#include <new>
#include <stdio.h>
class GpAudioDriver_SDL2;
static void *AlignedAlloc(size_t size, size_t alignment)
{
void *storage = malloc(size + alignment);
if (!storage)
return nullptr;
uintptr_t alignedPtr = reinterpret_cast<uintptr_t>(storage);
size_t padding = alignment - static_cast<size_t>(alignedPtr % alignment);
uint8_t *storageLoc = static_cast<uint8_t*>(storage);
uint8_t *objectLoc = storageLoc + padding;
uint8_t *paddingSizeLoc = storageLoc + padding - 1;
*reinterpret_cast<uint8_t*>(paddingSizeLoc) = static_cast<uint8_t>(padding);
return objectLoc;
}
static void AlignedFree(void *ptr)
{
size_t padding = static_cast<uint8_t*>(ptr)[-1];
void *storageLoc = static_cast<uint8_t*>(ptr) - padding;
free(storageLoc);
}
struct GpAudioChannelBufferChain_SDL2 final
{
GpAudioChannelBufferChain_SDL2();
static GpAudioChannelBufferChain_SDL2 *Alloc();
void Release();
static const size_t kMaxCapacity = 65536;
size_t m_consumed;
size_t m_used;
uint8_t m_data[kMaxCapacity];
GpAudioChannelBufferChain_SDL2 *m_next;
bool m_hasTrigger;
};
class GP_ALIGNED(GP_SYSTEM_MEMORY_ALIGNMENT) GpAudioChannel_SDL2 final : public IGpAudioChannel
{
public:
enum ChannelState
{
ChannelState_Idle,
ChannelState_Playing,
ChannelState_Stopped,
};
friend class GpAudioDriver_SDL2;
GpAudioChannel_SDL2();
~GpAudioChannel_SDL2();
void AddRef();
void Release();
void SetAudioChannelContext(IGpAudioChannelCallbacks *callbacks) override;
void PostBuffer(const void *buffer, size_t bufferSize) override;
void Stop() override;
void Destroy() override;
void Consume(uint8_t *output, size_t sz);
static GpAudioChannel_SDL2 *Alloc(GpAudioDriver_SDL2 *driver);
private:
bool Init(GpAudioDriver_SDL2 *driver);
IGpAudioChannelCallbacks *m_callbacks;
PortabilityLayer::HostMutex *m_mutex;
GpAudioDriver_SDL2 *m_owner;
SDL_atomic_t m_refCount;
GpAudioChannelBufferChain_SDL2 *m_firstPendingBuffer;
GpAudioChannelBufferChain_SDL2 *m_lastPendingBuffer;
ChannelState m_channelState;
};
class GP_ALIGNED(GP_SYSTEM_MEMORY_ALIGNMENT) GpAudioDriver_SDL2 final : public IGpAudioDriver, public IGpPrefsHandler
{
public:
friend class GpAudioChannel_SDL2;
explicit GpAudioDriver_SDL2(const GpAudioDriverProperties &properties);
~GpAudioDriver_SDL2();
IGpAudioChannel *CreateChannel() override;
void SetMasterVolume(uint32_t vol, uint32_t maxVolume) override;
void Shutdown() override;
IGpPrefsHandler *GetPrefsHandler() const override;
void ApplyPrefs(const void *identifier, size_t identifierSize, const void *contents, size_t contentsSize, uint32_t version) override;
bool SavePrefs(void *context, WritePrefsFunc_t writeFunc) override;
bool Init();
private:
void DetachAudioChannel(GpAudioChannel_SDL2 *channel);
static void SDLCALL StaticMixAudio(void *userdata, Uint8 *stream, int len);
void MixAudio(void *stream, size_t len);
void RefillMixChunk(GpAudioChannel_SDL2 *const*channels, size_t numChannels);
GpAudioDriverProperties m_properties;
PortabilityLayer::HostMutex *m_mutex;
PortabilityLayer::HostMutex *m_mixState;
static const size_t kMaxChannels = 16;
static const size_t kMixChunkSize = 256;
GpAudioChannel_SDL2 *m_channels[kMaxChannels];
size_t m_numChannels;
bool m_sdlAudioRunning;
GP_ALIGNED(GP_SYSTEM_MEMORY_ALIGNMENT) int16_t m_mixChunk[kMixChunkSize];
size_t m_mixChunkReadOffset;
};
GpAudioChannelBufferChain_SDL2::GpAudioChannelBufferChain_SDL2()
: m_used(0)
, m_consumed(0)
, m_next(nullptr)
, m_hasTrigger(false)
{
}
GpAudioChannelBufferChain_SDL2 *GpAudioChannelBufferChain_SDL2::Alloc()
{
void *storage = AlignedAlloc(sizeof(GpAudioChannelBufferChain_SDL2), GP_SYSTEM_MEMORY_ALIGNMENT);
return new (storage) GpAudioChannelBufferChain_SDL2();
}
void GpAudioChannelBufferChain_SDL2::Release()
{
this->~GpAudioChannelBufferChain_SDL2();
AlignedFree(this);
}
/////////////////////////////////////////////////////////////////////////////////////////
// GpAudioChannel
GpAudioChannel_SDL2::GpAudioChannel_SDL2()
: m_callbacks(nullptr)
, m_mutex(nullptr)
, m_owner(nullptr)
, m_firstPendingBuffer(nullptr)
, m_lastPendingBuffer(nullptr)
{
SDL_AtomicSet(&m_refCount, 1);
}
GpAudioChannel_SDL2::~GpAudioChannel_SDL2()
{
Stop();
if (m_mutex)
m_mutex->Destroy();
while (m_firstPendingBuffer)
{
GpAudioChannelBufferChain_SDL2 *buffer = m_firstPendingBuffer;
m_firstPendingBuffer = buffer->m_next;
buffer->Release();
}
}
void GpAudioChannel_SDL2::AddRef()
{
SDL_AtomicIncRef(&m_refCount);
}
void GpAudioChannel_SDL2::Release()
{
if (SDL_AtomicDecRef(&m_refCount))
{
this->~GpAudioChannel_SDL2();
AlignedFree(this);
}
}
void GpAudioChannel_SDL2::SetAudioChannelContext(IGpAudioChannelCallbacks *callbacks)
{
m_callbacks = callbacks;
}
void GpAudioChannel_SDL2::PostBuffer(const void *buffer, size_t bufferSize)
{
m_mutex->Lock();
while (bufferSize > 0)
{
GpAudioChannelBufferChain_SDL2 *newBuffer = GpAudioChannelBufferChain_SDL2::Alloc();
if (newBuffer == nullptr)
break;
if (m_lastPendingBuffer == nullptr)
m_firstPendingBuffer = newBuffer;
else
m_lastPendingBuffer->m_next = newBuffer;
m_lastPendingBuffer = newBuffer;
size_t bufferable = newBuffer->kMaxCapacity;
if (bufferSize < bufferable)
bufferable = bufferSize;
memcpy(newBuffer->m_data, buffer, bufferable);
buffer = static_cast<const uint8_t*>(buffer) + bufferable;
bufferSize -= bufferable;
m_lastPendingBuffer->m_used = bufferable;
m_lastPendingBuffer->m_hasTrigger = (bufferSize == 0);
}
m_mutex->Unlock();
}
void GpAudioChannel_SDL2::Stop()
{
m_mutex->Lock();
GpAudioChannelBufferChain_SDL2 *buffer = m_firstPendingBuffer;
m_firstPendingBuffer = nullptr;
m_lastPendingBuffer = nullptr;
while (buffer)
{
if (buffer->m_hasTrigger && m_callbacks)
m_callbacks->NotifyBufferFinished();
GpAudioChannelBufferChain_SDL2 *nextBuffer = buffer->m_next;
buffer->Release();
buffer = nextBuffer;
}
m_mutex->Unlock();
}
void GpAudioChannel_SDL2::Destroy()
{
if (m_owner)
m_owner->DetachAudioChannel(this);
this->Release();
}
bool GpAudioChannel_SDL2::Init(GpAudioDriver_SDL2 *driver)
{
m_owner = driver;
m_mutex = driver->m_properties.m_systemServices->CreateRecursiveMutex();
if (!m_mutex)
return false;
return true;
}
void GpAudioChannel_SDL2::Consume(uint8_t *output, size_t sz)
{
m_mutex->Lock();
while (m_firstPendingBuffer != nullptr)
{
GpAudioChannelBufferChain_SDL2 *buffer = m_firstPendingBuffer;
const size_t available = (buffer->m_used - buffer->m_consumed);
if (available <= sz)
{
memcpy(output, buffer->m_data + buffer->m_consumed, available);
sz -= available;
output += available;
m_firstPendingBuffer = buffer->m_next;
if (m_firstPendingBuffer == nullptr)
m_lastPendingBuffer = nullptr;
if (buffer->m_hasTrigger && m_callbacks)
m_callbacks->NotifyBufferFinished();
buffer->Release();
if (sz == 0)
break;
}
else
{
memcpy(output, buffer->m_data + buffer->m_consumed, sz);
buffer->m_consumed += sz;
buffer += sz;
sz = 0;
break;
}
}
m_mutex->Unlock();
memset(output, 0x80, sz);
}
GpAudioChannel_SDL2 *GpAudioChannel_SDL2::Alloc(GpAudioDriver_SDL2 *driver)
{
void *storage = AlignedAlloc(sizeof(GpAudioChannel_SDL2), GP_SYSTEM_MEMORY_ALIGNMENT);
if (!storage)
return nullptr;
GpAudioChannel_SDL2 *channel = new (storage) GpAudioChannel_SDL2();
if (!channel->Init(driver))
{
channel->Destroy();
return nullptr;
}
return channel;
}
/////////////////////////////////////////////////////////////////////////////////////////
// GpAudioDriver_SDL2
GpAudioDriver_SDL2::GpAudioDriver_SDL2(const GpAudioDriverProperties &properties)
: m_properties(properties)
, m_mutex(nullptr)
, m_numChannels(0)
, m_sdlAudioRunning(false)
, m_mixChunkReadOffset(kMixChunkSize)
{
for (size_t i = 0; i < kMaxChannels; i++)
m_channels[i] = nullptr;
for (size_t i = 0; i < kMixChunkSize; i++)
m_mixChunk[i] = 0;
}
GpAudioDriver_SDL2::~GpAudioDriver_SDL2()
{
if (m_sdlAudioRunning)
SDL_CloseAudio();
if (m_mutex)
m_mutex->Destroy();
}
IGpAudioChannel *GpAudioDriver_SDL2::CreateChannel()
{
GpAudioChannel_SDL2 *newChannel = GpAudioChannel_SDL2::Alloc(this);
if (!newChannel)
return nullptr;
m_mutex->Lock();
if (m_numChannels == kMaxChannels)
{
newChannel->Destroy();
m_mutex->Unlock();
return nullptr;
}
m_channels[m_numChannels] = newChannel;
m_numChannels++;
m_mutex->Unlock();
return newChannel;
}
void GpAudioDriver_SDL2::SetMasterVolume(uint32_t vol, uint32_t maxVolume)
{
}
void GpAudioDriver_SDL2::Shutdown()
{
this->~GpAudioDriver_SDL2();
AlignedFree(this);
}
IGpPrefsHandler *GpAudioDriver_SDL2::GetPrefsHandler() const
{
return const_cast<GpAudioDriver_SDL2*>(this);
}
void GpAudioDriver_SDL2::ApplyPrefs(const void *identifier, size_t identifierSize, const void *contents, size_t contentsSize, uint32_t version)
{
}
bool GpAudioDriver_SDL2::SavePrefs(void *context, WritePrefsFunc_t writeFunc)
{
return true;
}
bool GpAudioDriver_SDL2::Init()
{
m_mutex = m_properties.m_systemServices->CreateMutex();
if (!m_mutex)
return false;
SDL_AudioSpec requestedSpec;
memset(&requestedSpec, 0, sizeof(requestedSpec));
requestedSpec.callback = GpAudioDriver_SDL2::StaticMixAudio;
requestedSpec.channels = 1;
requestedSpec.format = AUDIO_S16;
requestedSpec.freq = m_properties.m_sampleRate;
requestedSpec.samples = 512;
requestedSpec.userdata = this;
if (SDL_OpenAudio(&requestedSpec, nullptr))
{
requestedSpec.freq = 22050;
if (SDL_OpenAudio(&requestedSpec, nullptr))
return false;
}
SDL_PauseAudio(0);
m_sdlAudioRunning = true;
return true;
}
void GpAudioDriver_SDL2::DetachAudioChannel(GpAudioChannel_SDL2 *channel)
{
m_mutex->Lock();
const size_t numChannels = m_numChannels;
for (size_t i = 0; i < numChannels; i++)
{
if (m_channels[i] == channel)
{
m_numChannels = numChannels - 1;
m_channels[i] = m_channels[numChannels - 1];
m_channels[numChannels - 1] = nullptr;
break;
}
}
m_mutex->Unlock();
}
void GpAudioDriver_SDL2::StaticMixAudio(void *userdata, Uint8 *stream, int len)
{
static_cast<GpAudioDriver_SDL2*>(userdata)->MixAudio(stream, static_cast<size_t>(len));
}
void GpAudioDriver_SDL2::MixAudio(void *stream, size_t len)
{
GpAudioChannel_SDL2 *mixingChannels[kMaxChannels];
size_t numChannels = 0;
m_mutex->Lock();
numChannels = m_numChannels;
for (size_t i = 0; i < numChannels; i++)
{
GpAudioChannel_SDL2 *channel = m_channels[i];
channel->AddRef();
mixingChannels[i] = channel;
}
m_mutex->Unlock();
size_t samplesRemaining = len / sizeof(int16_t);
for (;;)
{
size_t availableInMixChunk = kMixChunkSize - m_mixChunkReadOffset;
if (availableInMixChunk > samplesRemaining)
{
m_mixChunkReadOffset += samplesRemaining;
memcpy(stream, m_mixChunk + m_mixChunkReadOffset, samplesRemaining * sizeof(int16_t));
break;
}
else
{
memcpy(stream, m_mixChunk + m_mixChunkReadOffset, availableInMixChunk * sizeof(int16_t));
stream = static_cast<int16_t*>(stream) + availableInMixChunk;
samplesRemaining -= availableInMixChunk;
m_mixChunkReadOffset = 0;
RefillMixChunk(mixingChannels, numChannels);
}
}
for (size_t i = 0; i < numChannels; i++)
mixingChannels[i]->Release();
}
void GpAudioDriver_SDL2::RefillMixChunk(GpAudioChannel_SDL2 *const*channels, size_t numChannels)
{
uint8_t audioMixBufferUnaligned[kMixChunkSize + GP_SYSTEM_MEMORY_ALIGNMENT];
uint8_t *audioMixBuffer = audioMixBufferUnaligned;
{
uintptr_t bufferPtr = reinterpret_cast<uintptr_t>(audioMixBuffer);
size_t alignPadding = GP_SYSTEM_MEMORY_ALIGNMENT - (bufferPtr % GP_SYSTEM_MEMORY_ALIGNMENT);
audioMixBuffer += alignPadding;
}
bool noAudio = true;
for (size_t i = 0; i < numChannels; i++)
{
channels[i]->Consume(audioMixBuffer, kMixChunkSize);
if (i == 0)
{
noAudio = false;
for (size_t j = 0; j < kMixChunkSize; j++)
m_mixChunk[j] = (audioMixBuffer[j] - 0x80) * 25;
}
else
{
for (size_t j = 0; j < kMixChunkSize; j++)
m_mixChunk[j] += (audioMixBuffer[j] - 0x80) * 25;
}
}
if (noAudio)
memset(m_mixChunk, 0, kMixChunkSize * sizeof(m_mixChunk[0]));
}
IGpAudioDriver *GpDriver_CreateAudioDriver_SDL(const GpAudioDriverProperties &properties)
{
void *storage = AlignedAlloc(sizeof(GpAudioDriver_SDL2), GP_SYSTEM_MEMORY_ALIGNMENT);
if (!storage)
return nullptr;
GpAudioDriver_SDL2 *driver = new (storage) GpAudioDriver_SDL2(properties);
if (!driver->Init())
{
driver->Shutdown();
return nullptr;
}
return driver;
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,70 +0,0 @@
#include "GpFiberStarter.h"
#include "GpFiber_SDL.h"
#include "HostSystemServices.h"
#include "HostThreadEvent.h"
#include "SDL_thread.h"
#include <assert.h>
namespace GpFiberStarter_SDL
{
struct FiberStartState
{
GpFiberStarter::ThreadFunc_t m_threadFunc;
PortabilityLayer::HostThreadEvent *m_creatingReturnEvent;
PortabilityLayer::HostThreadEvent *m_creatingWakeEvent;
void *m_context;
};
static int SDLCALL FiberStartRoutine(void *lpThreadParameter)
{
const FiberStartState *tss = static_cast<const FiberStartState*>(lpThreadParameter);
GpFiberStarter::ThreadFunc_t threadFunc = tss->m_threadFunc;
PortabilityLayer::HostThreadEvent *creatingReturnEvent = tss->m_creatingReturnEvent;
PortabilityLayer::HostThreadEvent *wakeEvent = tss->m_creatingWakeEvent;
void *context = tss->m_context;
creatingReturnEvent->Signal();
wakeEvent->Wait();
threadFunc(context);
return 0;
}
}
IGpFiber *GpFiberStarter::StartFiber(PortabilityLayer::HostSystemServices *systemServices, ThreadFunc_t threadFunc, void *context, IGpFiber *creatingFiber)
{
PortabilityLayer::HostThreadEvent *returnEvent = systemServices->CreateThreadEvent(true, false);
if (!returnEvent)
return nullptr;
PortabilityLayer::HostThreadEvent *wakeEvent = systemServices->CreateThreadEvent(true, false);
if (!wakeEvent)
{
returnEvent->Destroy();
return nullptr;
}
GpFiberStarter_SDL::FiberStartState startState;
startState.m_context = context;
startState.m_creatingReturnEvent = returnEvent;
startState.m_creatingWakeEvent = wakeEvent;
startState.m_threadFunc = threadFunc;
SDL_Thread *thread = SDL_CreateThread(GpFiberStarter_SDL::FiberStartRoutine, "Fiber", &startState);
if (!thread)
{
returnEvent->Destroy();
wakeEvent->Destroy();
return nullptr;
}
returnEvent->Wait();
returnEvent->Destroy();
return new GpFiber_SDL(thread, wakeEvent);
}

View File

@@ -1,30 +0,0 @@
#include "GpFiber_SDL.h"
#include "HostSystemServices.h"
#include "HostThreadEvent.h"
GpFiber_SDL::GpFiber_SDL(SDL_Thread *thread, PortabilityLayer::HostThreadEvent *threadEvent)
: m_event(threadEvent)
, m_thread(thread)
{
}
GpFiber_SDL::~GpFiber_SDL()
{
m_event->Destroy();
}
void GpFiber_SDL::YieldTo(IGpFiber *toFiber)
{
static_cast<GpFiber_SDL*>(toFiber)->m_event->Signal();
m_event->Wait();
}
void GpFiber_SDL::YieldToTerminal(IGpFiber *toFiber)
{
static_cast<GpFiber_SDL*>(toFiber)->m_event->Signal();
}
void GpFiber_SDL::Destroy()
{
delete this;
}

View File

@@ -1,28 +0,0 @@
#pragma once
#include "IGpFiber.h"
#include "SDL_thread.h"
namespace PortabilityLayer
{
class HostSystemServices;
class HostThreadEvent;
}
class GpFiber_SDL final : public IGpFiber
{
public:
explicit GpFiber_SDL(SDL_Thread *thread, PortabilityLayer::HostThreadEvent *threadEvent);
~GpFiber_SDL();
void YieldTo(IGpFiber *fromFiber) override;
void YieldToTerminal(IGpFiber *fromFiber) override;
void Destroy() override;
private:
static int SDLCALL InternalThreadFunction(void *data);
bool m_isDestroying;
PortabilityLayer::HostThreadEvent *m_event;
SDL_Thread *m_thread;
};

View File

@@ -1,107 +0,0 @@
#include "SDL.h"
#include "GpMain.h"
#include "GpAudioDriverFactory.h"
#include "GpDisplayDriverFactory.h"
#include "GpGlobalConfig.h"
#include "GpFiber_Win32.h"
#include "GpFiber_SDL.h"
#include "GpFileSystem_Win32.h"
#include "GpLogDriver_Win32.h"
#include "GpFontHandlerFactory.h"
#include "GpInputDriverFactory.h"
#include "GpAppInterface.h"
#include "GpSystemServices_Win32.h"
#include "GpVOSEvent.h"
#include "IGpVOSEventQueue.h"
#include "HostFileSystem.h"
#include "HostThreadEvent.h"
#include "GpWindows.h"
#include "resource.h"
#include <shellapi.h>
#include <stdio.h>
#include <windowsx.h>
GpWindowsGlobals g_gpWindowsGlobals;
extern "C" __declspec(dllimport) IGpInputDriver *GpDriver_CreateInputDriver_XInput(const GpInputDriverProperties &properties);
extern "C" __declspec(dllimport) IGpFontHandler *GpDriver_CreateFontHandler_FreeType2(const GpFontHandlerProperties &properties);
IGpDisplayDriver *GpDriver_CreateDisplayDriver_SDL_GL2(const GpDisplayDriverProperties &properties);
IGpAudioDriver *GpDriver_CreateAudioDriver_SDL(const GpAudioDriverProperties &properties);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
if (SDL_Init(SDL_INIT_VIDEO) < 0)
return -1;
LPWSTR cmdLine = GetCommandLineW();
int nArgs;
LPWSTR *cmdLineArgs = CommandLineToArgvW(cmdLine, &nArgs);
for (int i = 1; i < nArgs; i++)
{
if (!wcscmp(cmdLineArgs[i], L"-diagnostics"))
GpLogDriver_Win32::Init();
if (!wcscmp(cmdLineArgs[i], L"-touchscreensimulation"))
GpSystemServices_Win32::GetInstance()->SetTouchscreenSimulation(true);
}
IGpLogDriver *logger = GpLogDriver_Win32::GetInstance();
GpAppInterface_Get()->PL_HostFileSystem_SetInstance(GpFileSystem_Win32::GetInstance());
GpAppInterface_Get()->PL_HostSystemServices_SetInstance(GpSystemServices_Win32::GetInstance());
GpAppInterface_Get()->PL_HostLogDriver_SetInstance(GpLogDriver_Win32::GetInstance());
g_gpWindowsGlobals.m_hInstance = hInstance;
g_gpWindowsGlobals.m_hPrevInstance = hPrevInstance;
g_gpWindowsGlobals.m_cmdLine = cmdLine;
g_gpWindowsGlobals.m_cmdLineArgc = nArgs;
g_gpWindowsGlobals.m_cmdLineArgv = cmdLineArgs;
g_gpWindowsGlobals.m_nCmdShow = nCmdShow;
g_gpWindowsGlobals.m_baseDir = GpFileSystem_Win32::GetInstance()->GetBasePath();
g_gpWindowsGlobals.m_hwnd = nullptr;
g_gpGlobalConfig.m_displayDriverType = EGpDisplayDriverType_SDL_GL2;
g_gpGlobalConfig.m_audioDriverType = EGpAudioDriverType_SDL2;
g_gpGlobalConfig.m_fontHandlerType = EGpFontHandlerType_FreeType2;
EGpInputDriverType inputDrivers[] =
{
EGpInputDriverType_XInput
};
g_gpGlobalConfig.m_inputDriverTypes = inputDrivers;
g_gpGlobalConfig.m_numInputDrivers = sizeof(inputDrivers) / sizeof(inputDrivers[0]);
g_gpGlobalConfig.m_osGlobals = &g_gpWindowsGlobals;
g_gpGlobalConfig.m_logger = logger;
g_gpGlobalConfig.m_systemServices = GpSystemServices_Win32::GetInstance();
GpDisplayDriverFactory::RegisterDisplayDriverFactory(EGpDisplayDriverType_SDL_GL2, GpDriver_CreateDisplayDriver_SDL_GL2);
GpAudioDriverFactory::RegisterAudioDriverFactory(EGpAudioDriverType_SDL2, GpDriver_CreateAudioDriver_SDL);
GpInputDriverFactory::RegisterInputDriverFactory(EGpInputDriverType_XInput, GpDriver_CreateInputDriver_XInput);
GpFontHandlerFactory::RegisterFontHandlerFactory(EGpFontHandlerType_FreeType2, GpDriver_CreateFontHandler_FreeType2);
if (logger)
logger->Printf(IGpLogDriver::Category_Information, "SDL environment configured, starting up");
int returnCode = GpMain::Run();
if (logger)
logger->Printf(IGpLogDriver::Category_Information, "SDL environment exited with code %i, cleaning up", returnCode);
LocalFree(cmdLineArgs);
return returnCode;
}

View File

@@ -1,16 +0,0 @@
#include "Functions.h"
#define GP_GL_SHADER_CODE_COPYQUADP_GLSL "uniform sampler2D surfaceTexture;\n"\
"varying vec4 texCoord;\n"\
"\n"\
"uniform vec4 dxdy_dimensions;\n"\
"\n"\
"void main()\n"\
"{\n"\
" gl_FragColor = vec4(LinearToSRGB(texture2D(surfaceTexture, texCoord.xy).rgb), 1.0);\n"\
"}\n"
namespace GpBinarizedShaders
{
const char *g_copyQuadP_GL2 = GP_GL_SHADER_CODE_MEDIUM_PRECISION_PREFIX GP_GL_SHADER_CODE_FUNCTIONS_H GP_GL_SHADER_CODE_COPYQUADP_GLSL;
}

View File

@@ -1,36 +0,0 @@
#include "Functions.h"
#include "DrawQuadPixelConstants.h"
#define GP_GL_SHADER_CODE_DRAWQUADPALETTEP_GLSL \
"\n"\
"varying vec4 texCoord;\n"\
"uniform sampler2D surfaceTexture;\n"\
"uniform sampler2D paletteTexture;\n"\
"\n"\
"vec3 SamplePixel(vec2 tc)\n"\
"{\n"\
" float surfaceColor = texture2D(surfaceTexture, tc).r;\n"\
" return texture2D(paletteTexture, vec2(surfaceColor * (255.0 / 256.0) + (0.5 / 256.0), 0.5)).rgb;\n"\
"}\n"\
"\n"\
"void main()\n"\
"{\n"\
" vec4 resultColor = vec4(SamplePixel(texCoord.xy), 1.0);\n"\
" resultColor *= constants_Modulation;\n"\
"#ifdef ENABLE_FLICKER\n"\
" resultColor = ApplyFlicker(constants_FlickerAxis, texCoord.zw, constants_FlickerStartThreshold, constants_FlickerEndThreshold, resultColor * constants_Modulation);\n"\
" if (resultColor.a < 1.0)\n"\
" discard;\n"\
"#endif\n"\
" resultColor = ApplyDesaturation(constants_Desaturation, resultColor);\n"\
"\n"\
" gl_FragColor = vec4(ApplyColorSpaceTransform(resultColor.rgb), resultColor.a);\n"\
"}\n"
namespace GpBinarizedShaders
{
const char *g_drawQuadPalettePF_GL2 = "#define ENABLE_FLICKER\n" GP_GL_SHADER_CODE_MEDIUM_PRECISION_PREFIX GP_GL_SHADER_CODE_DRAWQUADPIXELCONSTANTS_H GP_GL_SHADER_CODE_FUNCTIONS_H GP_GL_SHADER_CODE_DRAWQUADPALETTEP_GLSL;
const char *g_drawQuadPalettePNF_GL2 = GP_GL_SHADER_CODE_MEDIUM_PRECISION_PREFIX GP_GL_SHADER_CODE_DRAWQUADPIXELCONSTANTS_H GP_GL_SHADER_CODE_FUNCTIONS_H GP_GL_SHADER_CODE_DRAWQUADPALETTEP_GLSL;
const char *g_drawQuadPaletteICCPF_GL2 = "#define USE_ICC_PROFILE\n" "#define ENABLE_FLICKER\n" GP_GL_SHADER_CODE_MEDIUM_PRECISION_PREFIX GP_GL_SHADER_CODE_DRAWQUADPIXELCONSTANTS_H GP_GL_SHADER_CODE_FUNCTIONS_H GP_GL_SHADER_CODE_DRAWQUADPALETTEP_GLSL;
const char *g_drawQuadPaletteICCPNF_GL2 = "#define USE_ICC_PROFILE\n" GP_GL_SHADER_CODE_MEDIUM_PRECISION_PREFIX GP_GL_SHADER_CODE_DRAWQUADPIXELCONSTANTS_H GP_GL_SHADER_CODE_FUNCTIONS_H GP_GL_SHADER_CODE_DRAWQUADPALETTEP_GLSL;
}

View File

@@ -1,5 +0,0 @@
#define GP_GL_SHADER_CODE_DRAWQUADPIXELCONSTANTS_H "uniform vec4 constants_Modulation;\n"\
"uniform vec2 constants_FlickerAxis;\n"\
"uniform float constants_FlickerStartThreshold;\n"\
"uniform float constants_FlickerEndThreshold;\n"\
"uniform float constants_Desaturation;\n"

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