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..e4db44667 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,9 @@ 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 astick_snap_min_displacement_percent; extern int r_cbutton; extern int l_cbutton; extern int d_cbutton; @@ -277,10 +284,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, 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 @@ -295,6 +301,17 @@ static void inputGetKeys_reuse(int16_t analogX, int16_t analogY, int Control, BU { // 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) { + 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); + } + } + // 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 a0a9f0414..98275f7c2 100644 --- a/libretro/libretro.c +++ b/libretro/libretro.c @@ -118,6 +118,9 @@ cothread_t retro_thread; 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; @@ -1384,6 +1387,33 @@ 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 "-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 39a93ec33..8e91aed11 100644 --- a/libretro/libretro_core_options.h +++ b/libretro/libretro_core_options.h @@ -1580,6 +1580,80 @@ 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 "-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",