From 8f5ec2f59685d1b701dd66d29c3d6f8961951c8e Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sun, 9 Jul 2023 19:22:29 -0700 Subject: [PATCH] Added shared code between testgamepad and gamepadmap The goal is to eventually create a single program that can do mapping and testing of game controllers. --- .../tests/testgamepad/testgamepad.vcxproj | 769 +- .../testgamepad/testgamepad.vcxproj.filters | 105 +- VisualC/tests/gamepadmap/gamepadmap.vcxproj | 75 +- VisualC/tests/testgamepad/testgamepad.vcxproj | 75 +- test/CMakeLists.txt | 4 +- test/axis.bmp | Bin 10138 -> 0 bytes test/button.bmp | Bin 3746 -> 0 bytes test/gamepad_axis.h | 848 + test/gamepad_back.h | 40590 ++++++++++++++++ test/gamepad_button.h | 316 + test/gamepad_front.h | 13624 ++++++ test/gamepadmap.bmp | Bin 163450 -> 0 bytes test/gamepadmap.c | 156 +- test/gamepadmap_back.bmp | Bin 487034 -> 0 bytes test/gamepadutils.c | 413 + test/gamepadutils.h | 54 + test/testgamepad.c | 157 +- 17 files changed, 56303 insertions(+), 883 deletions(-) delete mode 100644 test/axis.bmp delete mode 100644 test/button.bmp create mode 100644 test/gamepad_axis.h create mode 100644 test/gamepad_back.h create mode 100644 test/gamepad_button.h create mode 100644 test/gamepad_front.h delete mode 100644 test/gamepadmap.bmp delete mode 100644 test/gamepadmap_back.bmp create mode 100644 test/gamepadutils.c create mode 100644 test/gamepadutils.h diff --git a/VisualC-GDK/tests/testgamepad/testgamepad.vcxproj b/VisualC-GDK/tests/testgamepad/testgamepad.vcxproj index 66f3d59b41..bb3c52e22f 100644 --- a/VisualC-GDK/tests/testgamepad/testgamepad.vcxproj +++ b/VisualC-GDK/tests/testgamepad/testgamepad.vcxproj @@ -1,438 +1,333 @@ - - - - - Debug - Gaming.Desktop.x64 - - - Debug - Gaming.Xbox.Scarlett.x64 - - - Debug - Gaming.Xbox.XboxOne.x64 - - - Release - Gaming.Desktop.x64 - - - Release - Gaming.Xbox.Scarlett.x64 - - - Release - Gaming.Xbox.XboxOne.x64 - - - - {55812185-D13C-4022-9C81-32E0F4A08305} - testgamepad - 10.0 - - - - Application - $(DefaultPlatformToolset) - - - Application - $(DefaultPlatformToolset) - true - - - Application - $(DefaultPlatformToolset) - true - - - Application - $(DefaultPlatformToolset) - - - Application - $(DefaultPlatformToolset) - - - Application - $(DefaultPlatformToolset) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.40219.1 - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - $(Platform)\$(Configuration)\ - AllRules.ruleset - AllRules.ruleset - AllRules.ruleset - - - - - - - AllRules.ruleset - AllRules.ruleset - AllRules.ruleset - - - - - - - - - - NDEBUG;%(PreprocessorDefinitions) - true - true - .\Release/testgamepad.tlb - - - $(SolutionDir)/../include;%(AdditionalIncludeDirectories) - %(AdditionalUsingDirectories) - WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) - MultiThreadedDLL - Level3 - - - NDEBUG;%(PreprocessorDefinitions) - 0x0409 - - - Windows - xgameruntime.lib;../Microsoft.Xbox.Services.141.GDK.C.Thunks.lib;%(AdditionalDependencies) - - - - - NDEBUG;%(PreprocessorDefinitions) - true - true - .\Release/testgamepad.tlb - - - $(SolutionDir)/../include;%(AdditionalIncludeDirectories) - %(AdditionalUsingDirectories) - WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) - MultiThreadedDLL - Level3 - - - NDEBUG;%(PreprocessorDefinitions) - 0x0409 - - - Windows - xgameruntime.lib;%(AdditionalDependencies) - - - - - NDEBUG;%(PreprocessorDefinitions) - true - true - .\Release/testgamepad.tlb - - - $(SolutionDir)/../include;%(AdditionalIncludeDirectories) - %(AdditionalUsingDirectories) - WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) - MultiThreadedDLL - Level3 - - - NDEBUG;%(PreprocessorDefinitions) - 0x0409 - - - Windows - xgameruntime.lib;%(AdditionalDependencies) - - - - - _DEBUG;%(PreprocessorDefinitions) - true - true - .\Debug/testgamepad.tlb - - - Disabled - $(SolutionDir)/../include;%(AdditionalIncludeDirectories) - %(AdditionalUsingDirectories) - WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) - MultiThreadedDebugDLL - Level3 - OldStyle - - - _DEBUG;%(PreprocessorDefinitions) - 0x0409 - - - true - Windows - xgameruntime.lib;../Microsoft.Xbox.Services.141.GDK.C.Thunks.lib;%(AdditionalDependencies) - - - - - _DEBUG;%(PreprocessorDefinitions) - true - true - .\Debug/testgamepad.tlb - - - Disabled - $(SolutionDir)/../include;%(AdditionalIncludeDirectories) - %(AdditionalUsingDirectories) - WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) - MultiThreadedDebugDLL - Level3 - OldStyle - - - _DEBUG;%(PreprocessorDefinitions) - 0x0409 - - - true - Windows - xgameruntime.lib;%(AdditionalDependencies) - - - - - _DEBUG;%(PreprocessorDefinitions) - true - true - .\Debug/testgamepad.tlb - - - Disabled - $(SolutionDir)/../include;%(AdditionalIncludeDirectories) - %(AdditionalUsingDirectories) - WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) - MultiThreadedDebugDLL - Level3 - OldStyle - - - _DEBUG;%(PreprocessorDefinitions) - 0x0409 - - - true - Windows - xgameruntime.lib;%(AdditionalDependencies) - - - - - {81ce8daf-ebb2-4761-8e45-b71abcca8c68} - false - false - true - - - - - Copying %(Filename)%(Extension) - Copying %(Filename)%(Extension) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - copy "%(FullPath)" "$(ProjectDir)\" - - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - Copying %(Filename)%(Extension) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - copy "%(FullPath)" "$(ProjectDir)\" - - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - - - Copying %(Filename)%(Extension) - Copying %(Filename)%(Extension) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - copy "%(FullPath)" "$(ProjectDir)\" - - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - Copying %(Filename)%(Extension) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - copy "%(FullPath)" "$(ProjectDir)\" - - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - - - Copying %(Filename)%(Extension) - Copying %(Filename)%(Extension) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - copy "%(FullPath)" "$(ProjectDir)\" - - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - Copying %(Filename)%(Extension) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - copy "%(FullPath)" "$(ProjectDir)\" - - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - - - Copying %(Filename)%(Extension) - Copying %(Filename)%(Extension) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - copy "%(FullPath)" "$(ProjectDir)\" - - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - Copying %(Filename)%(Extension) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - copy "%(FullPath)" "$(ProjectDir)\" - - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - - - - - - - - - Document - true - true - true - true - - - - - - - - - - - - - - Document - true - true - true - true - - - - - Document - true - true - true - true - - - - - Document - true - true - true - true - - - - - - - - + + + + + Debug + Gaming.Desktop.x64 + + + Debug + Gaming.Xbox.Scarlett.x64 + + + Debug + Gaming.Xbox.XboxOne.x64 + + + Release + Gaming.Desktop.x64 + + + Release + Gaming.Xbox.Scarlett.x64 + + + Release + Gaming.Xbox.XboxOne.x64 + + + + {55812185-D13C-4022-9C81-32E0F4A08305} + testgamepad + 10.0 + + + + Application + $(DefaultPlatformToolset) + + + Application + $(DefaultPlatformToolset) + true + + + Application + $(DefaultPlatformToolset) + true + + + Application + $(DefaultPlatformToolset) + + + Application + $(DefaultPlatformToolset) + + + Application + $(DefaultPlatformToolset) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.40219.1 + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(SolutionDir)$(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + $(Platform)\$(Configuration)\ + AllRules.ruleset + AllRules.ruleset + AllRules.ruleset + + + + + + + AllRules.ruleset + AllRules.ruleset + AllRules.ruleset + + + + + + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\Release/testgamepad.tlb + + + $(SolutionDir)/../include;%(AdditionalIncludeDirectories) + %(AdditionalUsingDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + Windows + xgameruntime.lib;../Microsoft.Xbox.Services.141.GDK.C.Thunks.lib;%(AdditionalDependencies) + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\Release/testgamepad.tlb + + + $(SolutionDir)/../include;%(AdditionalIncludeDirectories) + %(AdditionalUsingDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + Windows + xgameruntime.lib;%(AdditionalDependencies) + + + + + NDEBUG;%(PreprocessorDefinitions) + true + true + .\Release/testgamepad.tlb + + + $(SolutionDir)/../include;%(AdditionalIncludeDirectories) + %(AdditionalUsingDirectories) + WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDLL + Level3 + + + NDEBUG;%(PreprocessorDefinitions) + 0x0409 + + + Windows + xgameruntime.lib;%(AdditionalDependencies) + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\Debug/testgamepad.tlb + + + Disabled + $(SolutionDir)/../include;%(AdditionalIncludeDirectories) + %(AdditionalUsingDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + OldStyle + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + Windows + xgameruntime.lib;../Microsoft.Xbox.Services.141.GDK.C.Thunks.lib;%(AdditionalDependencies) + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\Debug/testgamepad.tlb + + + Disabled + $(SolutionDir)/../include;%(AdditionalIncludeDirectories) + %(AdditionalUsingDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + OldStyle + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + Windows + xgameruntime.lib;%(AdditionalDependencies) + + + + + _DEBUG;%(PreprocessorDefinitions) + true + true + .\Debug/testgamepad.tlb + + + Disabled + $(SolutionDir)/../include;%(AdditionalIncludeDirectories) + %(AdditionalUsingDirectories) + WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) + MultiThreadedDebugDLL + Level3 + OldStyle + + + _DEBUG;%(PreprocessorDefinitions) + 0x0409 + + + true + Windows + xgameruntime.lib;%(AdditionalDependencies) + + + + + {81ce8daf-ebb2-4761-8e45-b71abcca8c68} + false + false + true + + + + + + + + + + Document + true + true + true + true + + + + + + + + + + + + + + Document + true + true + true + true + + + + + Document + true + true + true + true + + + + + Document + true + true + true + true + + + + + + + + \ No newline at end of file diff --git a/VisualC-GDK/tests/testgamepad/testgamepad.vcxproj.filters b/VisualC-GDK/tests/testgamepad/testgamepad.vcxproj.filters index 3862703856..a5de19eb3b 100644 --- a/VisualC-GDK/tests/testgamepad/testgamepad.vcxproj.filters +++ b/VisualC-GDK/tests/testgamepad/testgamepad.vcxproj.filters @@ -1,55 +1,52 @@ - - - - - - - - - - - - - logos - - - logos - - - logos - - - logos - - - wingdk - - - wingdk - - - xboxseries - - - xboxone - - - logos - - - - - - {5e858cf0-6fba-498d-b33d-11c8ecbb79c7} - - - {5790a250-283e-4f51-8f28-6a977d3c7a6c} - - - {a4d235e4-4017-4193-af62-ecb2ac249be4} - - - {e704dcb9-c83c-4c94-a139-b0f3e3f428f2} - - + + + + + + + + + + logos + + + logos + + + logos + + + logos + + + wingdk + + + wingdk + + + xboxseries + + + xboxone + + + logos + + + + + + {5e858cf0-6fba-498d-b33d-11c8ecbb79c7} + + + {5790a250-283e-4f51-8f28-6a977d3c7a6c} + + + {a4d235e4-4017-4193-af62-ecb2ac249be4} + + + {e704dcb9-c83c-4c94-a139-b0f3e3f428f2} + + \ No newline at end of file diff --git a/VisualC/tests/gamepadmap/gamepadmap.vcxproj b/VisualC/tests/gamepadmap/gamepadmap.vcxproj index 2f3ee2bb72..d40bd05f28 100644 --- a/VisualC/tests/gamepadmap/gamepadmap.vcxproj +++ b/VisualC/tests/gamepadmap/gamepadmap.vcxproj @@ -195,82 +195,9 @@ true - - - Copying %(Filename)%(Extension) - copy %(FullPath) $(ProjectDir)\ - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy %(FullPath) $(ProjectDir)\ - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy %(FullPath) $(ProjectDir)\ - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy %(FullPath) $(ProjectDir)\ - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - - - Copying %(Filename)%(Extension) - copy %(FullPath) $(ProjectDir)\ - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy %(FullPath) $(ProjectDir)\ - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy %(FullPath) $(ProjectDir)\ - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy %(FullPath) $(ProjectDir)\ - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - - - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - - - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - - + diff --git a/VisualC/tests/testgamepad/testgamepad.vcxproj b/VisualC/tests/testgamepad/testgamepad.vcxproj index add2fd5306..73890d630d 100644 --- a/VisualC/tests/testgamepad/testgamepad.vcxproj +++ b/VisualC/tests/testgamepad/testgamepad.vcxproj @@ -196,80 +196,7 @@ - - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - - - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - - - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - - - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - Copying %(Filename)%(Extension) - copy "%(FullPath)" "$(ProjectDir)\" - - $(ProjectDir)\%(Filename)%(Extension);%(Outputs) - - - + diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 637a0c45ed..cd5cf591eb 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -209,7 +209,7 @@ if(SDL3_TESTS_SUBPROJECT) endif() add_sdl_test_executable(testfile NONINTERACTIVE SOURCES testfile.c) -add_sdl_test_executable(testgamepad NEEDS_RESOURCES TESTUTILS SOURCES testgamepad.c) +add_sdl_test_executable(testgamepad TESTUTILS SOURCES testgamepad.c gamepadutils.c) add_sdl_test_executable(testgeometry TESTUTILS SOURCES testgeometry.c) add_sdl_test_executable(testgl SOURCES testgl.c) add_sdl_test_executable(testgles SOURCES testgles.c) @@ -258,7 +258,7 @@ add_sdl_test_executable(testdisplayinfo SOURCES testdisplayinfo.c) add_sdl_test_executable(testqsort NONINTERACTIVE SOURCES testqsort.c) add_sdl_test_executable(testbounds NONINTERACTIVE SOURCES testbounds.c) add_sdl_test_executable(testcustomcursor SOURCES testcustomcursor.c) -add_sdl_test_executable(gamepadmap NEEDS_RESOURCES TESTUTILS SOURCES gamepadmap.c) +add_sdl_test_executable(gamepadmap TESTUTILS SOURCES gamepadmap.c gamepadutils.c) add_sdl_test_executable(testvulkan NO_C90 SOURCES testvulkan.c) add_sdl_test_executable(testoffscreen SOURCES testoffscreen.c) add_sdl_test_executable(testpopup SOURCES testpopup.c) diff --git a/test/axis.bmp b/test/axis.bmp deleted file mode 100644 index 2b3a7c8af6aa0bbefe26885523d7eb4387841606..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10138 zcmeHKF;2uV5cC~T(ID}GD-g7ZCtO1V4PT+9L_(sYTx0k4ePezWeBoAZ$9^B!{^9~;HIBJ3;oFX^oO!hKaUHK*E&}y-w|H(J+c2i= zWd+eY?9=YY{(m5*%Ya=@@i@{;Ao6DGd+-liV?A&mvCIPo44CoCgn9sLwf}b zu*x&+N8}mC8Q7SAnYX#6ULzM6JWs^#XHagJ^)8G9Y)CK2fdK=|h*^$h9@1^Y#{1mo z18K<3t5zp^FYtH(DYMk`gjnQ&6*1~C%tw6&IkQ+Vh(T&I8?12em>$4hH;VuxzyOr-(+#82FZ8o*$bB~tz TTyt+)M&qkJSr72>Nc{*u97*TN diff --git a/test/button.bmp b/test/button.bmp deleted file mode 100644 index 1593ccea49037934f387f73ea40c96ea32c18d41..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3746 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 p^cuC0Ic}X*Ed9Y8;bx?%g */ -#include -#include - #include #include #include + #include "testutils.h" +#include "gamepadutils.h" /* Define this for verbose output while mapping gamepads */ #define DEBUG_GAMEPADMAP @@ -27,12 +26,6 @@ #define SCREEN_WIDTH 512 #define SCREEN_HEIGHT 320 -enum marker_type -{ - MARKER_BUTTON, - MARKER_AXIS, -}; - enum { SDL_GAMEPAD_BINDING_AXIS_LEFTX_NEGATIVE, @@ -50,47 +43,6 @@ enum #define BINDING_COUNT (SDL_GAMEPAD_BUTTON_MAX + SDL_GAMEPAD_BINDING_AXIS_MAX) -static struct -{ - int x, y; - double angle; - enum marker_type marker; - -} s_arrBindingDisplay[] = { - { 387, 167, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_A */ - { 431, 132, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_B */ - { 342, 132, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_X */ - { 389, 101, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_Y */ - { 174, 132, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_BACK */ - { 232, 128, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_GUIDE */ - { 289, 132, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_START */ - { 75, 154, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_LEFT_STICK */ - { 305, 230, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_RIGHT_STICK */ - { 77, 40, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_LEFT_SHOULDER */ - { 396, 36, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER */ - { 154, 188, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_DPAD_UP */ - { 154, 249, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_DPAD_DOWN */ - { 116, 217, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_DPAD_LEFT */ - { 186, 217, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_DPAD_RIGHT */ - { 232, 174, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_MISC1 */ - { 132, 135, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_PADDLE1 */ - { 330, 135, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_PADDLE2 */ - { 132, 175, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_PADDLE3 */ - { 330, 175, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_PADDLE4 */ - { 0, 0, 0.0, MARKER_BUTTON }, /* SDL_GAMEPAD_BUTTON_TOUCHPAD */ - { 74, 153, 270.0, MARKER_AXIS }, /* SDL_GAMEPAD_BINDING_AXIS_LEFTX_NEGATIVE */ - { 74, 153, 90.0, MARKER_AXIS }, /* SDL_GAMEPAD_BINDING_AXIS_LEFTX_POSITIVE */ - { 74, 153, 0.0, MARKER_AXIS }, /* SDL_GAMEPAD_BINDING_AXIS_LEFTY_NEGATIVE */ - { 74, 153, 180.0, MARKER_AXIS }, /* SDL_GAMEPAD_BINDING_AXIS_LEFTY_POSITIVE */ - { 306, 231, 270.0, MARKER_AXIS }, /* SDL_GAMEPAD_BINDING_AXIS_RIGHTX_NEGATIVE */ - { 306, 231, 90.0, MARKER_AXIS }, /* SDL_GAMEPAD_BINDING_AXIS_RIGHTX_POSITIVE */ - { 306, 231, 0.0, MARKER_AXIS }, /* SDL_GAMEPAD_BINDING_AXIS_RIGHTY_NEGATIVE */ - { 306, 231, 180.0, MARKER_AXIS }, /* SDL_GAMEPAD_BINDING_AXIS_RIGHTY_POSITIVE */ - { 91, -20, 180.0, MARKER_AXIS }, /* SDL_GAMEPAD_BINDING_AXIS_TRIGGERLEFT */ - { 375, -20, 180.0, MARKER_AXIS }, /* SDL_GAMEPAD_BINDING_AXIS_TRIGGERRIGHT */ -}; -SDL_COMPILE_TIME_ASSERT(s_arrBindingDisplay, SDL_arraysize(s_arrBindingDisplay) == BINDING_COUNT); - static int s_arrBindingOrder[] = { SDL_GAMEPAD_BUTTON_A, SDL_GAMEPAD_BUTTON_B, @@ -171,6 +123,7 @@ static SDL_bool s_bBindingComplete; static SDL_Window *window; static SDL_Renderer *screen; +static GamepadImage *image; static SDL_bool done = SDL_FALSE; static SDL_bool bind_touchpad = SDL_FALSE; @@ -189,8 +142,9 @@ StandardizeAxisValue(int nValue) static void SetCurrentBinding(int iBinding) { - int iIndex; + int iIndex, iElement; SDL_GameControllerExtendedBind *pBinding; + SDL_bool on_front; if (iBinding < 0) { return; @@ -221,6 +175,53 @@ SetCurrentBinding(int iBinding) s_arrAxisState[iIndex].m_nFarthestValue = s_arrAxisState[iIndex].m_nStartingValue; } + iElement = s_arrBindingOrder[iBinding]; + on_front = SDL_TRUE; + if (iElement >= SDL_GAMEPAD_BUTTON_PADDLE1 && + iElement <= SDL_GAMEPAD_BUTTON_PADDLE4) { + on_front = SDL_FALSE; + } + SetGamepadImageShowingFront(image, on_front); + + ClearGamepadImage(image); + if (iElement < SDL_GAMEPAD_BUTTON_MAX) { + SDL_GamepadButton eButton = (SDL_GamepadButton)iElement; + SetGamepadImageButton(image, eButton, SDL_TRUE); + } else { + switch (iElement - SDL_GAMEPAD_BUTTON_MAX) { + case SDL_GAMEPAD_BINDING_AXIS_LEFTX_NEGATIVE: + SetGamepadImageAxis(image, SDL_GAMEPAD_AXIS_LEFTX, -1); + break; + case SDL_GAMEPAD_BINDING_AXIS_LEFTX_POSITIVE: + SetGamepadImageAxis(image, SDL_GAMEPAD_AXIS_LEFTX, 1); + break; + case SDL_GAMEPAD_BINDING_AXIS_LEFTY_NEGATIVE: + SetGamepadImageAxis(image, SDL_GAMEPAD_AXIS_LEFTY, -1); + break; + case SDL_GAMEPAD_BINDING_AXIS_LEFTY_POSITIVE: + SetGamepadImageAxis(image, SDL_GAMEPAD_AXIS_LEFTY, 1); + break; + case SDL_GAMEPAD_BINDING_AXIS_RIGHTX_NEGATIVE: + SetGamepadImageAxis(image, SDL_GAMEPAD_AXIS_RIGHTX, -1); + break; + case SDL_GAMEPAD_BINDING_AXIS_RIGHTX_POSITIVE: + SetGamepadImageAxis(image, SDL_GAMEPAD_AXIS_RIGHTX, 1); + break; + case SDL_GAMEPAD_BINDING_AXIS_RIGHTY_NEGATIVE: + SetGamepadImageAxis(image, SDL_GAMEPAD_AXIS_RIGHTY, -1); + break; + case SDL_GAMEPAD_BINDING_AXIS_RIGHTY_POSITIVE: + SetGamepadImageAxis(image, SDL_GAMEPAD_AXIS_RIGHTY, 1); + break; + case SDL_GAMEPAD_BINDING_AXIS_TRIGGERLEFT: + SetGamepadImageAxis(image, SDL_GAMEPAD_AXIS_LEFT_TRIGGER, 1); + break; + case SDL_GAMEPAD_BINDING_AXIS_TRIGGERRIGHT: + SetGamepadImageAxis(image, SDL_GAMEPAD_AXIS_RIGHT_TRIGGER, 1); + break; + } + } + s_unPendingAdvanceTime = 0; } @@ -351,19 +352,12 @@ BMergeAxisBindings(int iIndex) static void WatchJoystick(SDL_Joystick *joystick) { - SDL_Texture *background_front, *background_back, *button, *axis, *marker = NULL; const char *name = NULL; SDL_Event event; - SDL_FRect dst; - int texture_w, texture_h; - Uint8 alpha = 200, alpha_step = -1; - Uint64 alpha_ticks = 0; SDL_JoystickID nJoystickID; - background_front = LoadTexture(screen, "gamepadmap.bmp", SDL_FALSE, NULL, NULL); - background_back = LoadTexture(screen, "gamepadmap_back.bmp", SDL_FALSE, NULL, NULL); - button = LoadTexture(screen, "button.bmp", SDL_TRUE, NULL, NULL); - axis = LoadTexture(screen, "axis.bmp", SDL_TRUE, NULL, NULL); + image = CreateGamepadImage(screen); + SDL_RaiseWindow(window); /* scale for platforms that don't give you the window size you asked for. */ @@ -396,47 +390,13 @@ WatchJoystick(SDL_Joystick *joystick) while (SDL_PollEvent(&event) > 0) { } + SetCurrentBinding(0); + /* Loop, getting joystick events! */ while (!done && !s_bBindingComplete) { - int iElement = s_arrBindingOrder[s_iCurrentBinding]; - - switch (s_arrBindingDisplay[iElement].marker) { - case MARKER_AXIS: - marker = axis; - break; - case MARKER_BUTTON: - marker = button; - break; - } - - SDL_QueryTexture(marker, NULL, NULL, &texture_w, &texture_h); - dst.x = (float)s_arrBindingDisplay[iElement].x; - dst.y = (float)s_arrBindingDisplay[iElement].y; - dst.w = (float)texture_w; - dst.h = (float)texture_h; - - if (SDL_GetTicks() >= (alpha_ticks + 5)) { - alpha_ticks = SDL_GetTicks(); - alpha += alpha_step; - if (alpha == 255) { - alpha_step = -1; - } - if (alpha < 128) { - alpha_step = 1; - } - } - SDL_SetRenderDrawColor(screen, 0xFF, 0xFF, 0xFF, SDL_ALPHA_OPAQUE); SDL_RenderClear(screen); - if (s_arrBindingOrder[s_iCurrentBinding] >= SDL_GAMEPAD_BUTTON_PADDLE1 && - s_arrBindingOrder[s_iCurrentBinding] <= SDL_GAMEPAD_BUTTON_PADDLE4) { - SDL_RenderTexture(screen, background_back, NULL, NULL); - } else { - SDL_RenderTexture(screen, background_front, NULL, NULL); - } - SDL_SetTextureAlphaMod(marker, alpha); - SDL_SetTextureColorMod(marker, 10, 255, 21); - SDL_RenderTextureRotated(screen, marker, NULL, &dst, s_arrBindingDisplay[iElement].angle, NULL, SDL_FLIP_NONE); + RenderGamepadImage(image); SDL_RenderPresent(screen); while (SDL_PollEvent(&event) > 0) { @@ -696,8 +656,6 @@ WatchJoystick(SDL_Joystick *joystick) } SDL_Log("Mapping:\n\n%s\n\n", mapping); - /* Print to stdout as well so the user can cat the output somewhere */ - printf("%s\n", mapping); } SDL_free(s_arrAxisState); diff --git a/test/gamepadmap_back.bmp b/test/gamepadmap_back.bmp deleted file mode 100644 index bfaed6f026621ed2c0d921462aca5eb08e4654c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 487034 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 HKH~oe94kFB diff --git a/test/gamepadutils.c b/test/gamepadutils.c new file mode 100644 index 0000000000..212aad2ae6 --- /dev/null +++ b/test/gamepadutils.c @@ -0,0 +1,413 @@ +/* + Copyright (C) 1997-2023 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely. +*/ +#include + +#include "gamepadutils.h" +#include "gamepad_front.h" +#include "gamepad_back.h" +#include "gamepad_button.h" +#include "gamepad_axis.h" + +/* This is indexed by SDL_GamepadButton. */ +static const struct +{ + int x; + int y; +} button_positions[] = { + { 412, 192 }, /* SDL_GAMEPAD_BUTTON_A */ + { 456, 157 }, /* SDL_GAMEPAD_BUTTON_B */ + { 367, 157 }, /* SDL_GAMEPAD_BUTTON_X */ + { 414, 126 }, /* SDL_GAMEPAD_BUTTON_Y */ + { 199, 157 }, /* SDL_GAMEPAD_BUTTON_BACK */ + { 257, 153 }, /* SDL_GAMEPAD_BUTTON_GUIDE */ + { 314, 157 }, /* SDL_GAMEPAD_BUTTON_START */ + { 100, 179 }, /* SDL_GAMEPAD_BUTTON_LEFT_STICK */ + { 330, 255 }, /* SDL_GAMEPAD_BUTTON_RIGHT_STICK */ + { 102, 65 }, /* SDL_GAMEPAD_BUTTON_LEFT_SHOULDER */ + { 421, 61 }, /* SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER */ + { 179, 213 }, /* SDL_GAMEPAD_BUTTON_DPAD_UP */ + { 179, 274 }, /* SDL_GAMEPAD_BUTTON_DPAD_DOWN */ + { 141, 242 }, /* SDL_GAMEPAD_BUTTON_DPAD_LEFT */ + { 211, 242 }, /* SDL_GAMEPAD_BUTTON_DPAD_RIGHT */ + { 257, 199 }, /* SDL_GAMEPAD_BUTTON_MISC1 */ + { 157, 160 }, /* SDL_GAMEPAD_BUTTON_PADDLE1 */ + { 355, 160 }, /* SDL_GAMEPAD_BUTTON_PADDLE2 */ + { 157, 200 }, /* SDL_GAMEPAD_BUTTON_PADDLE3 */ + { 355, 200 }, /* SDL_GAMEPAD_BUTTON_PADDLE4 */ +}; + +/* This is indexed by SDL_GamepadAxis. */ +static const struct +{ + int x; + int y; + double angle; +} axis_positions[] = { + { 99, 178, 270.0 }, /* LEFTX */ + { 99, 178, 0.0 }, /* LEFTY */ + { 331, 256, 270.0 }, /* RIGHTX */ + { 331, 256, 0.0 }, /* RIGHTY */ + { 116, 5, 0.0 }, /* TRIGGERLEFT */ + { 400, 5, 0.0 }, /* TRIGGERRIGHT */ +}; + +struct GamepadImage +{ + SDL_Renderer *renderer; + SDL_Texture *front_texture; + SDL_Texture *back_texture; + SDL_Texture *button_texture; + SDL_Texture *axis_texture; + int gamepad_width; + int gamepad_height; + int button_width; + int button_height; + int axis_width; + int axis_height; + + int x; + int y; + SDL_bool showing_front; + + SDL_bool buttons[SDL_GAMEPAD_BUTTON_MAX]; + int axes[SDL_GAMEPAD_AXIS_MAX]; +}; + +static SDL_Texture *CreateTexture(SDL_Renderer *renderer, unsigned char *data, unsigned int len) +{ + SDL_Texture *texture = NULL; + SDL_Surface *surface; + SDL_RWops *src = SDL_RWFromConstMem(data, len); + if (src) { + surface = SDL_LoadBMP_RW(src, SDL_TRUE); + if (surface) { + if (surface->format->palette) { + SDL_SetSurfaceColorKey(surface, SDL_TRUE, *(Uint8 *)surface->pixels); + } else { + switch (surface->format->BitsPerPixel) { + case 15: + SDL_SetSurfaceColorKey(surface, SDL_TRUE, + (*(Uint16 *)surface->pixels) & 0x00007FFF); + break; + case 16: + SDL_SetSurfaceColorKey(surface, SDL_TRUE, *(Uint16 *)surface->pixels); + break; + case 24: + SDL_SetSurfaceColorKey(surface, SDL_TRUE, + (*(Uint32 *)surface->pixels) & 0x00FFFFFF); + break; + case 32: + SDL_SetSurfaceColorKey(surface, SDL_TRUE, *(Uint32 *)surface->pixels); + break; + } + } + texture = SDL_CreateTextureFromSurface(renderer, surface); + SDL_DestroySurface(surface); + } + } + return texture; +} + +GamepadImage *CreateGamepadImage(SDL_Renderer *renderer) +{ + GamepadImage *ctx = SDL_calloc(1, sizeof(*ctx)); + if (ctx) { + ctx->renderer = renderer; + ctx->front_texture = CreateTexture(renderer, gamepad_front_bmp, gamepad_front_bmp_len); + ctx->back_texture = CreateTexture(renderer, gamepad_back_bmp, gamepad_back_bmp_len); + SDL_QueryTexture(ctx->front_texture, NULL, NULL, &ctx->gamepad_width, &ctx->gamepad_height); + + ctx->button_texture = CreateTexture(renderer, gamepad_button_bmp, gamepad_button_bmp_len); + SDL_QueryTexture(ctx->button_texture, NULL, NULL, &ctx->button_width, &ctx->button_height); + SDL_SetTextureColorMod(ctx->button_texture, 10, 255, 21); + + ctx->axis_texture = CreateTexture(renderer, gamepad_axis_bmp, gamepad_axis_bmp_len); + SDL_QueryTexture(ctx->axis_texture, NULL, NULL, &ctx->axis_width, &ctx->axis_height); + SDL_SetTextureColorMod(ctx->axis_texture, 10, 255, 21); + + ctx->showing_front = SDL_TRUE; + } + return ctx; +} + +void SetGamepadImagePosition(GamepadImage *ctx, int x, int y) +{ + if (!ctx) { + return; + } + + ctx->x = x; + ctx->y = y; +} + +void SetGamepadImageShowingFront(GamepadImage *ctx, SDL_bool showing_front) +{ + if (!ctx) { + return; + } + + ctx->showing_front = showing_front; +} + +void GetGamepadImageArea(GamepadImage *ctx, int *x, int *y, int *width, int *height) +{ + if (!ctx) { + if (x) { + *x = 0; + } + if (y) { + *y = 0; + } + if (width) { + *width = 0; + } + if (height) { + *height = 0; + } + return; + } + + if (x) { + *x = ctx->x; + } + if (y) { + *y = ctx->y; + } + if (width) { + *width = ctx->gamepad_width; + } + if (height) { + *height = ctx->gamepad_height; + } +} + +int GetGamepadImageButtonWidth(GamepadImage *ctx) +{ + if (!ctx) { + return 0; + } + + return ctx->button_width; +} + +int GetGamepadImageButtonHeight(GamepadImage *ctx) +{ + if (!ctx) { + return 0; + } + + return ctx->button_height; +} + +int GetGamepadImageAxisWidth(GamepadImage *ctx) +{ + if (!ctx) { + return 0; + } + + return ctx->axis_width; +} + +int GetGamepadImageAxisHeight(GamepadImage *ctx) +{ + if (!ctx) { + return 0; + } + + return ctx->axis_height; +} + +SDL_GamepadButton GetGamepadImageButtonAt(GamepadImage *ctx, float x, float y) +{ + SDL_FPoint point; + int i; + + if (!ctx) { + return SDL_GAMEPAD_BUTTON_INVALID; + } + + point.x = x; + point.y = y; + for (i = 0; i < SDL_arraysize(button_positions); ++i) { + SDL_bool on_front = SDL_TRUE; + + if (i >= SDL_GAMEPAD_BUTTON_PADDLE1 && i <= SDL_GAMEPAD_BUTTON_PADDLE4) { + on_front = SDL_FALSE; + } + if (on_front == ctx->showing_front) { + SDL_FRect rect; + rect.x = (float)ctx->x + button_positions[i].x - ctx->button_width / 2; + rect.y = (float)ctx->y + button_positions[i].y - ctx->button_height / 2; + rect.w = (float)ctx->button_width; + rect.h = (float)ctx->button_height; + if (SDL_PointInRectFloat(&point, &rect)) { + return (SDL_GamepadButton)i; + } + } + } + return SDL_GAMEPAD_BUTTON_INVALID; +} + +SDL_GamepadAxis GetGamepadImageAxisAt(GamepadImage *ctx, float x, float y) +{ + SDL_FPoint point; + int i; + + if (!ctx) { + return SDL_GAMEPAD_AXIS_INVALID; + } + + point.x = x; + point.y = y; + if (ctx->showing_front) { + for (i = 0; i < SDL_arraysize(axis_positions); ++i) { + SDL_FRect rect; + rect.x = (float)ctx->x + axis_positions[i].x - ctx->axis_width / 2; + rect.y = (float)ctx->y + axis_positions[i].y - ctx->axis_height / 2; + rect.w = (float)ctx->axis_width; + rect.h = (float)ctx->axis_height; + if (SDL_PointInRectFloat(&point, &rect)) { + return (SDL_GamepadAxis)i; + } + } + } + return SDL_GAMEPAD_AXIS_INVALID; +} + +void ClearGamepadImage(GamepadImage *ctx) +{ + if (!ctx) { + return; + } + + SDL_zeroa(ctx->buttons); + SDL_zeroa(ctx->axes); +} + +void SetGamepadImageButton(GamepadImage *ctx, SDL_GamepadButton button, SDL_bool active) +{ + if (!ctx) { + return; + } + + ctx->buttons[button] = active; +} + +void SetGamepadImageAxis(GamepadImage *ctx, SDL_GamepadAxis axis, int direction) +{ + if (!ctx) { + return; + } + + ctx->axes[axis] = direction; +} + +void UpdateGamepadImageFromGamepad(GamepadImage *ctx, SDL_Gamepad *gamepad) +{ + int i; + + if (!ctx) { + return; + } + + for (i = 0; i < SDL_GAMEPAD_BUTTON_TOUCHPAD; ++i) { + const SDL_GamepadButton button = (SDL_GamepadButton)i; + + if (SDL_GetGamepadButton(gamepad, button) == SDL_PRESSED) { + SetGamepadImageButton(ctx, button, SDL_TRUE); + } else { + SetGamepadImageButton(ctx, button, SDL_FALSE); + } + } + + for (i = 0; i < SDL_GAMEPAD_AXIS_MAX; ++i) { + const SDL_GamepadAxis axis = (SDL_GamepadAxis)i; + const Sint16 deadzone = 8000; /* !!! FIXME: real deadzone */ + const Sint16 value = SDL_GetGamepadAxis(gamepad, axis); + if (value < -deadzone) { + SetGamepadImageAxis(ctx, axis, -1); + } else if (value > deadzone) { + SetGamepadImageAxis(ctx, axis, 1); + } else { + SetGamepadImageAxis(ctx, axis, 0); + } + } +} + +void RenderGamepadImage(GamepadImage *ctx) +{ + SDL_FRect dst; + int i; + + if (!ctx) { + return; + } + + dst.x = (float)ctx->x; + dst.y = (float)ctx->y; + dst.w = (float)ctx->gamepad_width; + dst.h = (float)ctx->gamepad_height; + + if (ctx->showing_front) { + SDL_RenderTexture(ctx->renderer, ctx->front_texture, NULL, &dst); + } else { + SDL_RenderTexture(ctx->renderer, ctx->back_texture, NULL, &dst); + } + + for (i = 0; i < SDL_arraysize(button_positions); ++i) { + if (ctx->buttons[i]) { + SDL_bool on_front = SDL_TRUE; + + if (i >= SDL_GAMEPAD_BUTTON_PADDLE1 && i <= SDL_GAMEPAD_BUTTON_PADDLE4) { + on_front = SDL_FALSE; + } + if (on_front == ctx->showing_front) { + dst.x = (float)ctx->x + button_positions[i].x - ctx->button_width / 2; + dst.y = (float)ctx->y + button_positions[i].y - ctx->button_height / 2; + dst.w = (float)ctx->button_width; + dst.h = (float)ctx->button_height; + SDL_RenderTexture(ctx->renderer, ctx->button_texture, NULL, &dst); + } + } + } + + if (ctx->showing_front) { + for (i = 0; i < SDL_arraysize(axis_positions); ++i) { + if (ctx->axes[i] < 0) { + const double angle = axis_positions[i].angle; + dst.x = (float)ctx->x + axis_positions[i].x - ctx->axis_width / 2; + dst.y = (float)ctx->y + axis_positions[i].y - ctx->axis_height / 2; + dst.w = (float)ctx->axis_width; + dst.h = (float)ctx->axis_height; + SDL_RenderTextureRotated(ctx->renderer, ctx->axis_texture, NULL, &dst, angle, NULL, SDL_FLIP_NONE); + } else if (ctx->axes[i] > 0) { + const double angle = axis_positions[i].angle + 180.0; + dst.x = (float)ctx->x + axis_positions[i].x - ctx->axis_width / 2; + dst.y = (float)ctx->y + axis_positions[i].y - ctx->axis_height / 2; + dst.w = (float)ctx->axis_width; + dst.h = (float)ctx->axis_height; + SDL_RenderTextureRotated(ctx->renderer, ctx->axis_texture, NULL, &dst, angle, NULL, SDL_FLIP_NONE); + } + } + } +} + +void DestroyGamepadImage(GamepadImage *ctx) +{ + if (ctx) { + SDL_DestroyTexture(ctx->front_texture); + SDL_DestroyTexture(ctx->back_texture); + SDL_DestroyTexture(ctx->button_texture); + SDL_DestroyTexture(ctx->axis_texture); + SDL_free(ctx); + } +} diff --git a/test/gamepadutils.h b/test/gamepadutils.h new file mode 100644 index 0000000000..6715b766b6 --- /dev/null +++ b/test/gamepadutils.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 1997-2023 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely. +*/ + +/* Joystick element display */ + +typedef struct JoystickDisplay JoystickDisplay; + +extern JoystickDisplay *CreateJoystickDisplay(SDL_Renderer *renderer); +extern void SetJoystickDisplayArea(JoystickDisplay *ctx, int x, int y, int w, int h); +extern void UpdateJoystickDisplayFromJoystick(JoystickDisplay *ctx, SDL_Joystick *joystick); +extern void RenderJoystickDisplay(JoystickDisplay *ctx); + +/* Gamepad element display */ + +typedef struct GamepadDisplay GamepadDisplay; + +extern GamepadDisplay *CreateGamepadDisplay(SDL_Renderer *renderer); +extern void SetGamepadDisplayArea(GamepadDisplay *ctx, int x, int y, int w, int h); +extern void UpdateGamepadDisplayFromGamepad(GamepadDisplay *ctx, SDL_Gamepad *joystick); +extern void RenderGamepadDisplay(GamepadDisplay *ctx); + +/* Gamepad image */ + +typedef struct GamepadImage GamepadImage; + +extern GamepadImage *CreateGamepadImage(SDL_Renderer *renderer); +extern void SetGamepadImagePosition(GamepadImage *ctx, int x, int y); +extern void SetGamepadImageShowingFront(GamepadImage *ctx, SDL_bool showing_front); +extern void GetGamepadImageArea(GamepadImage *ctx, int *x, int *y, int *width, int *height); +extern int GetGamepadImageButtonWidth(GamepadImage *ctx); +extern int GetGamepadImageButtonHeight(GamepadImage *ctx); +extern int GetGamepadImageAxisWidth(GamepadImage *ctx); +extern int GetGamepadImageAxisHeight(GamepadImage *ctx); + +extern SDL_GamepadButton GetGamepadImageButtonAt(GamepadImage *ctx, float x, float y); +extern SDL_GamepadAxis GetGamepadImageAxisAt(GamepadImage *ctx, float x, float y); + +extern void ClearGamepadImage(GamepadImage *ctx); +extern void SetGamepadImageButton(GamepadImage *ctx, SDL_GamepadButton button, SDL_bool active); +extern void SetGamepadImageAxis(GamepadImage *ctx, SDL_GamepadAxis axis, int direction); + +extern void UpdateGamepadImageFromGamepad(GamepadImage *ctx, SDL_Gamepad *gamepad); +extern void RenderGamepadImage(GamepadImage *ctx); +extern void DestroyGamepadImage(GamepadImage *ctx); + diff --git a/test/testgamepad.c b/test/testgamepad.c index 4d065d5616..992c98d72c 100644 --- a/test/testgamepad.c +++ b/test/testgamepad.c @@ -15,6 +15,8 @@ #include #include #include + +#include "gamepadutils.h" #include "testutils.h" #ifdef __EMSCRIPTEN__ @@ -24,55 +26,6 @@ #define SCREEN_WIDTH 512 #define SCREEN_HEIGHT 320 -#define BUTTON_SIZE 50 -#define AXIS_SIZE 50 - -/* This is indexed by SDL_GamepadButton. */ -static const struct -{ - int x; - int y; -} button_positions[] = { - { 387, 167 }, /* SDL_GAMEPAD_BUTTON_A */ - { 431, 132 }, /* SDL_GAMEPAD_BUTTON_B */ - { 342, 132 }, /* SDL_GAMEPAD_BUTTON_X */ - { 389, 101 }, /* SDL_GAMEPAD_BUTTON_Y */ - { 174, 132 }, /* SDL_GAMEPAD_BUTTON_BACK */ - { 232, 128 }, /* SDL_GAMEPAD_BUTTON_GUIDE */ - { 289, 132 }, /* SDL_GAMEPAD_BUTTON_START */ - { 75, 154 }, /* SDL_GAMEPAD_BUTTON_LEFT_STICK */ - { 305, 230 }, /* SDL_GAMEPAD_BUTTON_RIGHT_STICK */ - { 77, 40 }, /* SDL_GAMEPAD_BUTTON_LEFT_SHOULDER */ - { 396, 36 }, /* SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER */ - { 154, 188 }, /* SDL_GAMEPAD_BUTTON_DPAD_UP */ - { 154, 249 }, /* SDL_GAMEPAD_BUTTON_DPAD_DOWN */ - { 116, 217 }, /* SDL_GAMEPAD_BUTTON_DPAD_LEFT */ - { 186, 217 }, /* SDL_GAMEPAD_BUTTON_DPAD_RIGHT */ - { 232, 174 }, /* SDL_GAMEPAD_BUTTON_MISC1 */ - { 132, 135 }, /* SDL_GAMEPAD_BUTTON_PADDLE1 */ - { 330, 135 }, /* SDL_GAMEPAD_BUTTON_PADDLE2 */ - { 132, 175 }, /* SDL_GAMEPAD_BUTTON_PADDLE3 */ - { 330, 175 }, /* SDL_GAMEPAD_BUTTON_PADDLE4 */ - { 0, 0 }, /* SDL_GAMEPAD_BUTTON_TOUCHPAD */ -}; -SDL_COMPILE_TIME_ASSERT(button_positions, SDL_arraysize(button_positions) == SDL_GAMEPAD_BUTTON_MAX); - -/* This is indexed by SDL_GamepadAxis. */ -static const struct -{ - int x; - int y; - double angle; -} axis_positions[] = { - { 74, 153, 270.0 }, /* LEFTX */ - { 74, 153, 0.0 }, /* LEFTY */ - { 306, 231, 270.0 }, /* RIGHTX */ - { 306, 231, 0.0 }, /* RIGHTY */ - { 91, -20, 0.0 }, /* TRIGGERLEFT */ - { 375, -20, 0.0 }, /* TRIGGERRIGHT */ -}; -SDL_COMPILE_TIME_ASSERT(axis_positions, SDL_arraysize(axis_positions) == SDL_GAMEPAD_AXIS_MAX); - /* This is indexed by SDL_JoystickPowerLevel + 1. */ static const char *power_level_strings[] = { "unknown", /* SDL_JOYSTICK_POWER_UNKNOWN */ @@ -86,11 +39,11 @@ SDL_COMPILE_TIME_ASSERT(power_level_strings, SDL_arraysize(power_level_strings) static SDL_Window *window = NULL; static SDL_Renderer *screen = NULL; +static GamepadImage *image = NULL; static SDL_bool retval = SDL_FALSE; static SDL_bool done = SDL_FALSE; static SDL_bool set_LED = SDL_FALSE; static int trigger_effect = 0; -static SDL_Texture *background_front, *background_back, *button_texture, *axis_texture; static SDL_Gamepad *gamepad; static SDL_Gamepad **gamepads; static int num_gamepads = 0; @@ -494,49 +447,12 @@ static void CloseVirtualGamepad(void) static SDL_GamepadButton FindButtonAtPosition(float x, float y) { - SDL_FPoint point; - int i; - SDL_bool showing_front = ShowingFront(); - - point.x = x; - point.y = y; - for (i = 0; i < SDL_GAMEPAD_BUTTON_TOUCHPAD; ++i) { - SDL_bool on_front = (i < SDL_GAMEPAD_BUTTON_PADDLE1 || i > SDL_GAMEPAD_BUTTON_PADDLE4); - if (on_front == showing_front) { - SDL_FRect rect; - rect.x = (float)button_positions[i].x; - rect.y = (float)button_positions[i].y; - rect.w = (float)BUTTON_SIZE; - rect.h = (float)BUTTON_SIZE; - if (SDL_PointInRectFloat(&point, &rect)) { - return (SDL_GamepadButton)i; - } - } - } - return SDL_GAMEPAD_BUTTON_INVALID; + return GetGamepadImageButtonAt(image, x, y); } static SDL_GamepadAxis FindAxisAtPosition(float x, float y) { - SDL_FPoint point; - int i; - SDL_bool showing_front = ShowingFront(); - - point.x = x; - point.y = y; - for (i = 0; i < SDL_GAMEPAD_AXIS_MAX; ++i) { - if (showing_front) { - SDL_FRect rect; - rect.x = (float)axis_positions[i].x; - rect.y = (float)axis_positions[i].y; - rect.w = (float)AXIS_SIZE; - rect.h = (float)AXIS_SIZE; - if (SDL_PointInRectFloat(&point, &rect)) { - return (SDL_GamepadAxis)i; - } - } - } - return SDL_GAMEPAD_AXIS_INVALID; + return GetGamepadImageAxisAt(image, x, y); } static void VirtualGamepadMouseMotion(float x, float y) @@ -556,12 +472,12 @@ static void VirtualGamepadMouseMotion(float x, float y) if (virtual_axis_active == SDL_GAMEPAD_AXIS_LEFT_TRIGGER || virtual_axis_active == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) { int range = (SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN); - float distance = SDL_clamp((y - virtual_axis_start_y) / AXIS_SIZE, 0.0f, 1.0f); + float distance = SDL_clamp((y - virtual_axis_start_y) / GetGamepadImageAxisHeight(image), 0.0f, 1.0f); Sint16 value = (Sint16)(SDL_JOYSTICK_AXIS_MIN + (distance * range)); SDL_SetJoystickVirtualAxis(virtual_joystick, virtual_axis_active, value); } else { - float distanceX = SDL_clamp((x - virtual_axis_start_x) / AXIS_SIZE, -1.0f, 1.0f); - float distanceY = SDL_clamp((y - virtual_axis_start_y) / AXIS_SIZE, -1.0f, 1.0f); + float distanceX = SDL_clamp((x - virtual_axis_start_x) / GetGamepadImageAxisWidth(image), -1.0f, 1.0f); + float distanceY = SDL_clamp((y - virtual_axis_start_y) / GetGamepadImageAxisHeight(image), -1.0f, 1.0f); Sint16 valueX, valueY; if (distanceX >= 0) { @@ -621,8 +537,6 @@ static void VirtualGamepadMouseUp(float x, float y) static void loop(void *arg) { SDL_Event event; - int i; - SDL_bool showing_front; /* Update to get the current event state */ SDL_PumpEvents(); @@ -754,52 +668,14 @@ static void loop(void *arg) } } - showing_front = ShowingFront(); - /* blank screen, set up for drawing this frame. */ SDL_SetRenderDrawColor(screen, 0xFF, 0xFF, 0xFF, SDL_ALPHA_OPAQUE); SDL_RenderClear(screen); - SDL_RenderTexture(screen, showing_front ? background_front : background_back, NULL, NULL); if (gamepad) { - /* Update visual gamepad state */ - for (i = 0; i < SDL_GAMEPAD_BUTTON_TOUCHPAD; ++i) { - if (SDL_GetGamepadButton(gamepad, (SDL_GamepadButton)i) == SDL_PRESSED) { - SDL_bool on_front = (i < SDL_GAMEPAD_BUTTON_PADDLE1 || i > SDL_GAMEPAD_BUTTON_PADDLE4); - if (on_front == showing_front) { - SDL_FRect dst; - dst.x = (float)button_positions[i].x; - dst.y = (float)button_positions[i].y; - dst.w = (float)BUTTON_SIZE; - dst.h = (float)BUTTON_SIZE; - SDL_RenderTextureRotated(screen, button_texture, NULL, &dst, 0, NULL, SDL_FLIP_NONE); - } - } - } - - if (showing_front) { - for (i = 0; i < SDL_GAMEPAD_AXIS_MAX; ++i) { - const Sint16 deadzone = 8000; /* !!! FIXME: real deadzone */ - const Sint16 value = SDL_GetGamepadAxis(gamepad, (SDL_GamepadAxis)(i)); - if (value < -deadzone) { - const double angle = axis_positions[i].angle; - SDL_FRect dst; - dst.x = (float)axis_positions[i].x; - dst.y = (float)axis_positions[i].y; - dst.w = (float)AXIS_SIZE; - dst.h = (float)AXIS_SIZE; - SDL_RenderTextureRotated(screen, axis_texture, NULL, &dst, angle, NULL, SDL_FLIP_NONE); - } else if (value > deadzone) { - const double angle = axis_positions[i].angle + 180.0; - SDL_FRect dst; - dst.x = (float)axis_positions[i].x; - dst.y = (float)axis_positions[i].y; - dst.w = (float)AXIS_SIZE; - dst.h = (float)AXIS_SIZE; - SDL_RenderTextureRotated(screen, axis_texture, NULL, &dst, angle, NULL, SDL_FLIP_NONE); - } - } - } + SetGamepadImageShowingFront(image, ShowingFront()); + UpdateGamepadImageFromGamepad(image, gamepad); + RenderGamepadImage(image); /* Update LED based on left thumbstick position */ { @@ -955,18 +831,12 @@ int main(int argc, char *argv[]) SDL_LOGICAL_PRESENTATION_LETTERBOX, SDL_SCALEMODE_LINEAR); - background_front = LoadTexture(screen, "gamepadmap.bmp", SDL_FALSE, NULL, NULL); - background_back = LoadTexture(screen, "gamepadmap_back.bmp", SDL_FALSE, NULL, NULL); - button_texture = LoadTexture(screen, "button.bmp", SDL_TRUE, NULL, NULL); - axis_texture = LoadTexture(screen, "axis.bmp", SDL_TRUE, NULL, NULL); - - if (background_front == NULL || background_back == NULL || button_texture == NULL || axis_texture == NULL) { + image = CreateGamepadImage(screen); + if (image == NULL) { SDL_DestroyRenderer(screen); SDL_DestroyWindow(window); return 2; } - SDL_SetTextureColorMod(button_texture, 10, 255, 21); - SDL_SetTextureColorMod(axis_texture, 10, 255, 21); /* Process the initial gamepad list */ loop(NULL); @@ -994,6 +864,7 @@ int main(int argc, char *argv[]) } CloseVirtualGamepad(); + DestroyGamepadImage(image); SDL_DestroyRenderer(screen); SDL_DestroyWindow(window); SDL_QuitSubSystem(SDL_INIT_VIDEO | SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD);