diff --git a/input.cpp b/input.cpp index 15e0197..182322e 100644 --- a/input.cpp +++ b/input.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include "input.h" #include "user_io.h" @@ -1198,7 +1199,9 @@ typedef struct char id[80]; char name[128]; char sysfs[512]; - int max_range; + int ss_range; + int max_cardinal; + float max_range; } devInput; static devInput input[NUMDEV] = {}; @@ -2088,14 +2091,25 @@ static void joy_analog(int dev, int axis, int offset, int stick = 0) int y = pos[stick][num][1]; if (is_n64() && stick == 0) { + // Update maximum observed cardinal distance const int abs_x = abs(x); const int abs_y = abs(y); - if (abs_x > input[dev].max_range) input[dev].max_range = abs_x; - if (abs_y > input[dev].max_range) input[dev].max_range = abs_y; + if (abs_x > input[dev].max_cardinal) input[dev].max_cardinal = abs_x; + if (abs_y > input[dev].max_cardinal) input[dev].max_cardinal = abs_y; + + // Update maximum observed diag + // Use sum of squares and only calc sqrt() when necessary + const int ss_range_curr = x*x + y*y; + // compare to max ss_range and update if larger + if ((ss_range_curr > input[dev].ss_range) & (abs(abs_x - abs_y) <= 3)) + { + input[dev].ss_range = ss_range_curr; + input[dev].max_range = sqrt(ss_range_curr); + } // emulate n64 joystick range and shape for regular -127-+127 controllers - n64_joy_emu(x, y, &x, &y, input[dev].max_range); + n64_joy_emu(x, y, &x, &y, input[dev].max_cardinal, input[dev].max_range); } if(stick) user_io_r_analog_joystick(num, (char)x, (char)y); else user_io_l_analog_joystick(num, (char)x, (char)y); diff --git a/support/n64/n64_joy_emu.cpp b/support/n64/n64_joy_emu.cpp index ada266d..a0b4936 100644 --- a/support/n64/n64_joy_emu.cpp +++ b/support/n64/n64_joy_emu.cpp @@ -2,7 +2,13 @@ #include #include -void n64_joy_emu(int x, int y, int* x2, int* y2, int max_range) +#define N64_MAX_DIAG 69 +#define N64_MAX_DIST sqrt(N64_MAX_DIAG * N64_MAX_DIAG * 2) +#define N64_MAX_CARDINAL 85 +#define OUTER_DEADZONE 2.0f +#define WEDGE_BOUNDARY (N64_MAX_CARDINAL - 69.0f) / 69.0f + +void n64_joy_emu(int x, int y, int* x2, int* y2, int max_cardinal, float max_range) { // Move to top right quadrant to standardize solutions const int x_flip = x < 0 ? -1 : 1; @@ -10,10 +16,15 @@ void n64_joy_emu(int x, int y, int* x2, int* y2, int max_range) const int abs_x = x * x_flip; const int abs_y = y * y_flip; - // Reduce range to radius 97.5807358037f ((69,69) diagonal of original controller) + // Either reduce range to radius 97.5807358037f ((69,69) diagonal of original controller) + // or reduce cardinals to 85, whichever is less aggressive (smaller reduction in scaling) + // (subtracts 2 from each to allow for minor outer deadzone) // assumes the max range is at least 85 (max cardinal of original controller) - if (max_range < 85) max_range = 85; - float scale = 97.5807358037f / max_range; + if (max_cardinal < N64_MAX_CARDINAL) max_cardinal = N64_MAX_CARDINAL; + if (max_range < N64_MAX_DIST) max_range = N64_MAX_DIST; + float scale_cardinal = N64_MAX_CARDINAL / (max_cardinal - OUTER_DEADZONE); + float scale_range = N64_MAX_DIST / (max_range - OUTER_DEADZONE); + float scale = scale_cardinal > scale_range ? scale_cardinal : scale_range; float scaled_x = abs_x * scale; float scaled_y = abs_y * scale; @@ -31,14 +42,14 @@ void n64_joy_emu(int x, int y, int* x2, int* y2, int max_range) // Clamp scaled_min and scaled_max // Note: wedge boundary is given by x = 85 - y * ((85 - 69) / 69) // If x + y * (16 / 69) > 85, coordinates exceed boundary and need clamped - float boundary = scaled_max + scaled_min * 0.231884057971f; - if (boundary > 85) { + float boundary = scaled_max + scaled_min * WEDGE_BOUNDARY; + if (boundary > N64_MAX_CARDINAL) { // We know target value is on: // 1) Boundary line: x = 85 - y * (16 / 69) // 2) Observed slope line: y = (scaled_max / scaled_min) * x // Solving system of equations yields: - scaled_min = 85 * scaled_min / boundary; - scaled_max = 85 - scaled_min * 0.231884057971f; // Boundary line + scaled_min = N64_MAX_CARDINAL * scaled_min / boundary; + scaled_max = N64_MAX_CARDINAL - scaled_min * WEDGE_BOUNDARY; // Boundary line } // Move back from wedge to actual coordinates @@ -50,3 +61,9 @@ void n64_joy_emu(int x, int y, int* x2, int* y2, int max_range) *y2 = y_flip * scaled_max; } } + +#undef N64_MAX_DIAG +#undef N64_MAX_DIST +#undef N64_MAX_CARDINAL +#undef OUTER_DEADZONE +#undef WEDGE_BOUNDARY \ No newline at end of file diff --git a/support/n64/n64_joy_emu.h b/support/n64/n64_joy_emu.h index 4398ad3..efce2f1 100644 --- a/support/n64/n64_joy_emu.h +++ b/support/n64/n64_joy_emu.h @@ -1 +1 @@ -void n64_joy_emu(int x, int y, int* x2, int* y2, int max_range); +void n64_joy_emu(int x, int y, int* x2, int* y2, int max_cardinal, float max_range);