From ccad6d8eccb1c5aa800a5200d24dd18fdd8473ac Mon Sep 17 00:00:00 2001 From: Halest Date: Fri, 28 Feb 2025 15:52:13 +0100 Subject: [PATCH 1/2] Add possibility to snap analog stick controller angle to better support circular design controllers --- .../emulate_game_controller_via_libretro.c | 17 ++++++- libretro/libretro.c | 21 +++++++++ libretro/libretro_core_options.h | 47 +++++++++++++++++++ 3 files changed, 83 insertions(+), 2 deletions(-) diff --git a/custom/mupen64plus-core/plugin/emulate_game_controller_via_libretro.c b/custom/mupen64plus-core/plugin/emulate_game_controller_via_libretro.c index 45cd2c124..c1954f358 100644 --- a/custom/mupen64plus-core/plugin/emulate_game_controller_via_libretro.c +++ b/custom/mupen64plus-core/plugin/emulate_game_controller_via_libretro.c @@ -32,6 +32,10 @@ #define ROUND(x) floor((x) + 0.5) +#ifndef M_PI +#define M_PI 3.1415926535897932384626433 +#endif + /* snprintf not available in MSVC 2010 and earlier */ #include "api/msvc_compat.h" @@ -42,6 +46,8 @@ extern int pad_pak_types[4]; extern int pad_present[4]; extern int astick_deadzone; extern int astick_sensitivity; +extern int astick_snap_active; +extern int astick_snap_max_angle; extern int r_cbutton; extern int l_cbutton; extern int d_cbutton; @@ -277,10 +283,9 @@ EXPORT void CALL inputControllerCommand(int Control, unsigned char *Command) #define CSTICK_UP 0x800 #define CSTICK_DOWN 0x400 - static void inputGetKeys_reuse(int16_t analogX, int16_t analogY, int Control, BUTTONS* Keys) { - double radius, angle; + double radius, angle, degrees, difference; // Keys->Value |= input_cb(Control, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_XX) ? 0x4000 : 0; // Mempak switch // Keys->Value |= input_cb(Control, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_XX) ? 0x8000 : 0; // Rumblepak switch @@ -293,6 +298,14 @@ static void inputGetKeys_reuse(int16_t analogX, int16_t analogY, int Control, BU if (radius > astick_deadzone) { + if (astick_snap_active) { + degrees = (int)(ROUND(angle * (180.0/M_PI))); + double nearest_45 = round(degrees / 45.0) * 45.0; + difference = fabs(degrees - nearest_45); + if (difference <= astick_snap_max_angle) { + angle = nearest_45 * (M_PI / 180.0); + } + } // Re-scale analog stick range to negate deadzone (makes slow movements possible) radius = (radius - astick_deadzone)*((float)ASTICK_MAX/(ASTICK_MAX - astick_deadzone)); // N64 Analog stick range is from -80 to 80 diff --git a/libretro/libretro.c b/libretro/libretro.c index a0a9f0414..1cb5ce99a 100644 --- a/libretro/libretro.c +++ b/libretro/libretro.c @@ -118,6 +118,8 @@ cothread_t retro_thread; int astick_deadzone; int astick_sensitivity; +int astick_snap_active; +int astick_snap_max_angle; int r_cbutton; int l_cbutton; int d_cbutton; @@ -1384,6 +1386,25 @@ static void update_variables(bool startup) if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) astick_sensitivity = atoi(var.value); + var.key = CORE_NAME "-astick-snap-angle-active"; + var.value = NULL; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + if (!strcmp(var.value, "enabled")) + astick_snap_active = 1; + else if (!strcmp(var.value, "disabled")) + astick_snap_active = 0; + } + + var.key = CORE_NAME "-astick-snap-max-angle"; + var.value = NULL; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + astick_snap_max_angle = (int)(atoi(var.value)); + } + var.key = CORE_NAME "-CountPerOp"; var.value = NULL; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) diff --git a/libretro/libretro_core_options.h b/libretro/libretro_core_options.h index 39a93ec33..e4e8bc2b3 100644 --- a/libretro/libretro_core_options.h +++ b/libretro/libretro_core_options.h @@ -1580,6 +1580,53 @@ struct retro_core_option_v2_definition option_defs_us[] = { }, "100" }, + { + CORE_NAME "-astick-snap-angle-active", + "Snap Analog Stick Angle to Cardinal Directions", + NULL, + "Should the analog stick snap to a cardinal direction to better support circular design controllers", + NULL, + "input", + { + {"enabled", NULL}, + {"disabled", NULL}, + { NULL, NULL }, + }, + "disabled" + }, + { + CORE_NAME "-astick-snap-max-angle", + "Maximum Snap Angle", + NULL, + "Up to what angle difference should the controller snap to the next cardinal direction. Example: Set to 5 will snap values from 85 to 95 degrees to 90", + NULL, + "input", + { + {"1", NULL}, + {"2", NULL}, + {"3", NULL}, + {"4", NULL}, + {"5", NULL}, + {"6", NULL}, + {"7", NULL}, + {"8", NULL}, + {"9", NULL}, + {"10", NULL}, + {"11", NULL}, + {"12", NULL}, + {"13", NULL}, + {"14", NULL}, + {"15", NULL}, + {"16", NULL}, + {"17", NULL}, + {"18", NULL}, + {"19", NULL}, + {"20", NULL}, + {"21", NULL}, + { NULL, NULL }, + }, + "15" + }, { CORE_NAME "-r-cbutton", "Right C Button", From 0454962a25703f125a006351ecd23dd67d2f80e5 Mon Sep 17 00:00:00 2001 From: Halest Date: Sat, 1 Mar 2025 23:01:12 +0100 Subject: [PATCH 2/2] Add percentage modifier to even more closely resemble classic controller behaviour --- .../emulate_game_controller_via_libretro.c | 18 ++++++++----- libretro/libretro.c | 9 +++++++ libretro/libretro_core_options.h | 27 +++++++++++++++++++ 3 files changed, 47 insertions(+), 7 deletions(-) diff --git a/custom/mupen64plus-core/plugin/emulate_game_controller_via_libretro.c b/custom/mupen64plus-core/plugin/emulate_game_controller_via_libretro.c index c1954f358..e4db44667 100644 --- a/custom/mupen64plus-core/plugin/emulate_game_controller_via_libretro.c +++ b/custom/mupen64plus-core/plugin/emulate_game_controller_via_libretro.c @@ -48,6 +48,7 @@ extern int astick_deadzone; extern int astick_sensitivity; extern int astick_snap_active; extern int astick_snap_max_angle; +extern int astick_snap_min_displacement_percent; extern int r_cbutton; extern int l_cbutton; extern int d_cbutton; @@ -285,7 +286,7 @@ EXPORT void CALL inputControllerCommand(int Control, unsigned char *Command) static void inputGetKeys_reuse(int16_t analogX, int16_t analogY, int Control, BUTTONS* Keys) { - double radius, angle, degrees, difference; + double radius, angle, circular_degrees, difference, nearest_45; // Keys->Value |= input_cb(Control, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_XX) ? 0x4000 : 0; // Mempak switch // Keys->Value |= input_cb(Control, RETRO_DEVICE_JOYPAD, 0, RETRO_DEVICE_ID_JOYPAD_XX) ? 0x8000 : 0; // Rumblepak switch @@ -298,16 +299,19 @@ static void inputGetKeys_reuse(int16_t analogX, int16_t analogY, int Control, BU if (radius > astick_deadzone) { + // Re-scale analog stick range to negate deadzone (makes slow movements possible) + radius = (radius - astick_deadzone)*((float)ASTICK_MAX/(ASTICK_MAX - astick_deadzone)); + + // Angle Snapping for beter support of circular design controllers if (astick_snap_active) { - degrees = (int)(ROUND(angle * (180.0/M_PI))); - double nearest_45 = round(degrees / 45.0) * 45.0; - difference = fabs(degrees - nearest_45); - if (difference <= astick_snap_max_angle) { + circular_degrees = (int)(ROUND(angle * (180.0/M_PI))); + nearest_45 = round(circular_degrees / 45.0) * 45.0; + difference = fabs(circular_degrees - nearest_45); + if (difference <= astick_snap_max_angle && (100*(radius / ASTICK_MAX)) >= astick_snap_min_displacement_percent) { angle = nearest_45 * (M_PI / 180.0); } } - // Re-scale analog stick range to negate deadzone (makes slow movements possible) - radius = (radius - astick_deadzone)*((float)ASTICK_MAX/(ASTICK_MAX - astick_deadzone)); + // N64 Analog stick range is from -80 to 80 radius *= 80.0 / ASTICK_MAX * (astick_sensitivity / 100.0); // Convert back to cartesian coordinates diff --git a/libretro/libretro.c b/libretro/libretro.c index 1cb5ce99a..98275f7c2 100644 --- a/libretro/libretro.c +++ b/libretro/libretro.c @@ -120,6 +120,7 @@ int astick_deadzone; int astick_sensitivity; int astick_snap_active; int astick_snap_max_angle; +int astick_snap_min_displacement_percent; int r_cbutton; int l_cbutton; int d_cbutton; @@ -1405,6 +1406,14 @@ static void update_variables(bool startup) astick_snap_max_angle = (int)(atoi(var.value)); } + var.key = CORE_NAME "-astick-snap-min-displacement-percent"; + var.value = NULL; + + if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) + { + astick_snap_min_displacement_percent = (int)(atoi(var.value)); + } + var.key = CORE_NAME "-CountPerOp"; var.value = NULL; if (environ_cb(RETRO_ENVIRONMENT_GET_VARIABLE, &var) && var.value) diff --git a/libretro/libretro_core_options.h b/libretro/libretro_core_options.h index e4e8bc2b3..8e91aed11 100644 --- a/libretro/libretro_core_options.h +++ b/libretro/libretro_core_options.h @@ -1627,6 +1627,33 @@ struct retro_core_option_v2_definition option_defs_us[] = { }, "15" }, + { + CORE_NAME "-astick-snap-min-displacement-percent", + "Which percentage of displacement causes snap to activate", + NULL, + "To closely emulate the behaviour of classic, notched controllers, angle snapping \ + can be activated only when the analog stick is displaced far enough from the center position, zero means always, even on slow movement", + NULL, + "input", + { + {"0", NULL}, + {"10", NULL}, + {"20", NULL}, + {"30", NULL}, + {"40", NULL}, + {"50", NULL}, + {"60", NULL}, + {"65", NULL}, + {"70", NULL}, + {"75", NULL}, + {"80", NULL}, + {"85", NULL}, + {"90", NULL}, + {"95", NULL}, + { NULL, NULL }, + }, + "70" + }, { CORE_NAME "-r-cbutton", "Right C Button",