Unify thumbsticks
- Combined the functions that handle dead zone, digital threshold, and response curves together. - A lot less copy-paste between the different platforms. - Combine the X and Y settings for dead zone, digital threshold, and response curve for analog sticks. This fixes many issues: - The dead zone shape for sticks are now a true circle, instead of being axial. - The new response curves work better when moving diagonally. Previously, it'd nerf your move speed up to ~60-50% if you had it on anything but Linear. - Refactored the new POSIX SDL gamepad axis code to work more like Windows' XInput code. This comes with the following benefits: - Right thumbstick should function now. - Left thumbstick now sends the gamepad keycodes instead of raw joystick keycodes. - Added `stat analog`, to display current movement analog stick values. (I've needed it a lot lately.)
This commit is contained in:
parent
ca562829c5
commit
e1a5326947
8 changed files with 442 additions and 198 deletions
|
|
@ -475,40 +475,6 @@ CCMD (gamepad)
|
|||
return usage();
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Joy_RemoveDeadZone
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
double Joy_RemoveDeadZone(double axisval, double deadzone, uint8_t *buttons)
|
||||
{
|
||||
uint8_t butt;
|
||||
|
||||
// Cancel out deadzone.
|
||||
if (fabs(axisval) < deadzone)
|
||||
{
|
||||
axisval = 0;
|
||||
butt = 0;
|
||||
}
|
||||
// Make the dead zone the new 0.
|
||||
else if (axisval < 0)
|
||||
{
|
||||
axisval = (axisval + deadzone) / (1.0 - deadzone);
|
||||
butt = 2; // button minus
|
||||
}
|
||||
else
|
||||
{
|
||||
axisval = (axisval - deadzone) / (1.0 - deadzone);
|
||||
butt = 1; // button plus
|
||||
}
|
||||
if (buttons != NULL)
|
||||
{
|
||||
*buttons = butt;
|
||||
}
|
||||
return axisval;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Joy_ApplyResponseCurveBezier
|
||||
|
|
@ -551,6 +517,54 @@ double Joy_ApplyResponseCurveBezier(const CubicBezier &curve, double input)
|
|||
return sign*t;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Joy_ManageSingleAxis
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
double Joy_ManageSingleAxis(double axisval, double deadzone, double threshold, const CubicBezier &curve, uint8_t *buttons)
|
||||
{
|
||||
uint8_t butt;
|
||||
|
||||
// Cancel out deadzone.
|
||||
if (fabs(axisval) < deadzone)
|
||||
{
|
||||
axisval = 0;
|
||||
butt = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make the dead zone the new 0.
|
||||
if (axisval < 0)
|
||||
{
|
||||
axisval = (axisval + deadzone) / (1.0 - deadzone);
|
||||
butt = 2; // button minus
|
||||
}
|
||||
else
|
||||
{
|
||||
axisval = (axisval - deadzone) / (1.0 - deadzone);
|
||||
butt = 1; // button plus
|
||||
}
|
||||
|
||||
// Apply input response curve
|
||||
axisval = Joy_ApplyResponseCurveBezier(curve, axisval);
|
||||
|
||||
if (abs(axisval) < threshold)
|
||||
{
|
||||
// Needs to meet digital threshold to send button
|
||||
butt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (buttons != NULL)
|
||||
{
|
||||
*buttons = butt;
|
||||
}
|
||||
|
||||
return axisval;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Joy_XYAxesToButtons
|
||||
|
|
@ -588,6 +602,86 @@ int Joy_XYAxesToButtons(double x, double y)
|
|||
return JoyAngleButtons[int(rad) & 7];
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Joy_ManageThumbstick
|
||||
//
|
||||
// Given two axes and their settings, handle applying deadzone, digital
|
||||
// threshold, input response curve, and setting button state. This is
|
||||
// necessary, because doing the two axes individually creates awkward
|
||||
// behavior (such as cross shaped deadzones, sluggish input response when
|
||||
// pressing diagonally, so on).
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
double Joy_ManageThumbstick(
|
||||
double *axis_x, double *axis_y,
|
||||
double deadzone_x, double deadzone_y,
|
||||
double threshold_x, double threshold_y,
|
||||
const CubicBezier &curve_x, const CubicBezier &curve_y,
|
||||
uint8_t *buttons)
|
||||
{
|
||||
double ret_x = *axis_x;
|
||||
double ret_y = *axis_y;
|
||||
|
||||
double x_abs = abs(*axis_x);
|
||||
double y_abs = abs(*axis_y);
|
||||
double magnitude = sqrt((x_abs * x_abs) + (y_abs * y_abs));
|
||||
|
||||
double ret_dist = 0;
|
||||
uint8_t ret_butt = 0;
|
||||
|
||||
double xy_lerp = 0.5;
|
||||
if (magnitude > 0)
|
||||
{
|
||||
// Later it would be nice to have a single deadzone / threshold / curve setting
|
||||
// for the whole thumbstick instead of awkwardly trying to combine them, but
|
||||
// that requires re-considering how axes are exposed to the rest of the engine.
|
||||
// This will do for now.
|
||||
xy_lerp = abs(cos(atan2(ret_y, ret_x)));
|
||||
}
|
||||
|
||||
double deadzone = (xy_lerp * deadzone_x) + ((1.0 - xy_lerp) * deadzone_y);
|
||||
if (magnitude < deadzone)
|
||||
{
|
||||
ret_x = 0;
|
||||
ret_y = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make the dead zone the new 0.
|
||||
ret_dist = (magnitude - deadzone) / (1.0 - deadzone);
|
||||
|
||||
const CubicBezier curve = {
|
||||
(float)((xy_lerp * curve_x.x1) + ((1.0 - xy_lerp) * curve_y.x1)),
|
||||
(float)((xy_lerp * curve_x.y1) + ((1.0 - xy_lerp) * curve_y.y1)),
|
||||
(float)((xy_lerp * curve_x.x2) + ((1.0 - xy_lerp) * curve_y.x2)),
|
||||
(float)((xy_lerp * curve_x.y2) + ((1.0 - xy_lerp) * curve_y.y2))
|
||||
};
|
||||
|
||||
ret_dist = Joy_ApplyResponseCurveBezier(curve, ret_dist);
|
||||
|
||||
ret_x = (ret_x / magnitude) * ret_dist;
|
||||
ret_y = (ret_y / magnitude) * ret_dist;
|
||||
|
||||
double threshold = (xy_lerp * threshold_x) + ((1.0 - xy_lerp) * threshold_y);
|
||||
if (ret_dist >= threshold)
|
||||
{
|
||||
ret_butt = Joy_XYAxesToButtons(ret_x, ret_y);
|
||||
}
|
||||
}
|
||||
|
||||
*axis_x = ret_x;
|
||||
*axis_y = ret_y;
|
||||
|
||||
if (buttons != NULL)
|
||||
{
|
||||
*buttons = ret_butt;
|
||||
}
|
||||
|
||||
return ret_dist;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// Joy_GenerateButtonEvent
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue