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 zcmZ?rou$qI23-sc3^fc43`S7Q$e_T$%)r1Ppw7S`%niX{g%ILD0|Oi}IJpNELxhPZ znTS_9s&X_0MnhmU1V%$(Gz3ONU^E0qLtr!nMnhmU1V%$(Gz3Oo2>k#5pMe-W$V2A; z|NsC05x^idgWMaSs2KIfAc`bVni)-3gC{~p<74o|1;{0%@c{~j!GlNRWAMZU$R(rk z0Sbk|gNIstF#iAlA02~2lN5iT>j&{cX3z_R>|^==|35kg*-wf;(Dj4(AhSW{&;u)g z9E$`0A<*{#wIM-jaA^MzGMgTLfZ6dF>X2{$|Ns91#XpJg1IQmB3{nfz2QmX>9LP+V z`Shfpf-EP&?I8DK!yscoX3^8_AiH2`7?cJ+{Qv*|F9m)9=>?eqG7H&k5Stzt<`*AO zV3O$286fsxz*j+zBf>8rWgxYK!Ohs*paOCr6k|(EATg-)e~?;iW(>3# zERU)|9SU+YHVl#msR6kcrU%3xOqdCpR}4Uog<_arpxpl;Igp!SYC-J5jN73O2bHZL p4B~>s2D6*d-3AM5P+kVPAA~_{kUE$gh&`0>h5!HmgD|b#3;-NS=g9y7 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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 diff --git a/test/gamepadmap.c b/test/gamepadmap.c index df3b98e111..63d2af878f 100644 --- a/test/gamepadmap.c +++ b/test/gamepadmap.c @@ -13,13 +13,12 @@ /* Gamepad mapping generator */ /* Gabriel Jacobo */ -#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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 + + 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);