mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2025-02-18 01:51:44 +00:00
Merge pull request #883 from protocultor/thumbsticks_fs
Improved controller thumbsticks precision + Flick Stick
This commit is contained in:
commit
e705b48a8e
4 changed files with 503 additions and 210 deletions
|
@ -470,6 +470,42 @@ Set `0` by default.
|
||||||
`2` to use the Guide/Home/PS button. Requires a game restart
|
`2` to use the Guide/Home/PS button. Requires a game restart
|
||||||
(or controller replug) when changed.
|
(or controller replug) when changed.
|
||||||
|
|
||||||
|
* **joy_layout**: Allows to select the stick layout of the gamepad.
|
||||||
|
- `0`: *Default*, left stick moves, right aims
|
||||||
|
- `1`: *Southpaw*, same as previous one with inverted sticks
|
||||||
|
- `2`: *Legacy*, left moves forward/backward and turns, right strafes
|
||||||
|
and looks up/down
|
||||||
|
- `3`: *Legacy Southpaw*, inverted sticks version of previous one
|
||||||
|
- `4`: *Flick Stick*, left stick moves, right checks your surroundings
|
||||||
|
in 360º, gyro required for looking up/down
|
||||||
|
- `5`: *Flick Stick Southpaw*, swapped sticks version of last one
|
||||||
|
|
||||||
|
* **joy_left_deadzone** / **joy_right_deadzone**: Inner, circular
|
||||||
|
deadzone for each stick, where inputs below this radius will be
|
||||||
|
ignored. Default is `0.16` (16% of possible stick travel).
|
||||||
|
|
||||||
|
* **joy_left_snapaxis** / **joy_right_snapaxis**: Ratio on the value of
|
||||||
|
one axis (X or Y) to snap you to the other. It creates an axial
|
||||||
|
deadzone with the shape of a "bowtie", which will help you to do
|
||||||
|
perfectly horizontal or vertical movements the more you mark a
|
||||||
|
direction with the stick. Increasing this too much will reduce speed
|
||||||
|
for the diagonals, but will help you to mark 90º/180º turns with Flick
|
||||||
|
Stick. Default `0.15`.
|
||||||
|
|
||||||
|
* **joy_left_expo** / **joy_right_expo**: Exponents on the response
|
||||||
|
curve on each stick. Increasing this will make small movements to
|
||||||
|
represent much smaller inputs, which helps precision with the sticks.
|
||||||
|
`1.0` is linear. Default `2.0` (quadratic curve).
|
||||||
|
|
||||||
|
* **joy_flick_threshold**: Used only with Flick Stick, specifies the
|
||||||
|
distance from the center of the stick that will make the player flick
|
||||||
|
or rotate. Default `0.65` (65%).
|
||||||
|
|
||||||
|
* **joy_flick_smoothed**: Flick Stick only, rotations below this angle
|
||||||
|
(in degrees) will be smoothed. Reducing this will increase
|
||||||
|
responsiveness at the cost of jittery movement. Most gamepads will work
|
||||||
|
nicely with a value between 4.0 and 8.0. Default `8.0`.
|
||||||
|
|
||||||
* **gyro_mode**: Operation mode for the gyroscope sensor of the game
|
* **gyro_mode**: Operation mode for the gyroscope sensor of the game
|
||||||
controller. Options are `0` = always off, `1` = off with the
|
controller. Options are `0` = always off, `1` = off with the
|
||||||
`+gyroaction` bind to enable, `2` = on with `+gyroaction` to
|
`+gyroaction` bind to enable, `2` = on with `+gyroaction` to
|
||||||
|
|
|
@ -294,6 +294,7 @@ extern cvar_t *cl_shownet;
|
||||||
extern cvar_t *cl_showmiss;
|
extern cvar_t *cl_showmiss;
|
||||||
extern cvar_t *cl_showclamp;
|
extern cvar_t *cl_showclamp;
|
||||||
extern cvar_t *lookstrafe;
|
extern cvar_t *lookstrafe;
|
||||||
|
extern cvar_t *joy_layout;
|
||||||
extern cvar_t *gyro_mode;
|
extern cvar_t *gyro_mode;
|
||||||
extern cvar_t *gyro_turning_axis;
|
extern cvar_t *gyro_turning_axis;
|
||||||
extern cvar_t *m_pitch;
|
extern cvar_t *m_pitch;
|
||||||
|
|
|
@ -18,7 +18,14 @@
|
||||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||||
* 02111-1307, USA.
|
* 02111-1307, USA.
|
||||||
*
|
*
|
||||||
* Joystick threshold code is partially based on http://ioquake3.org code.
|
* Joystick reading and deadzone handling is based on:
|
||||||
|
* http://joshsutphin.com/2013/04/12/doing-thumbstick-dead-zones-right.html
|
||||||
|
* ...and implementation is partially based on code from:
|
||||||
|
* - http://quakespasm.sourceforge.net
|
||||||
|
* - https://github.com/Minimuino/thumbstick-deadzones
|
||||||
|
*
|
||||||
|
* Flick Stick handling is based on:
|
||||||
|
* http://gyrowiki.jibbsmart.com/blog:good-gyro-controls-part-2:the-flick-stick
|
||||||
*
|
*
|
||||||
* =======================================================================
|
* =======================================================================
|
||||||
*
|
*
|
||||||
|
@ -43,6 +50,21 @@
|
||||||
|
|
||||||
// ----
|
// ----
|
||||||
|
|
||||||
|
enum {
|
||||||
|
LAYOUT_DEFAULT = 0,
|
||||||
|
LAYOUT_SOUTHPAW,
|
||||||
|
LAYOUT_LEGACY,
|
||||||
|
LAYOUT_LEGACY_SOUTHPAW,
|
||||||
|
LAYOUT_FLICK_STICK,
|
||||||
|
LAYOUT_FLICK_STICK_SOUTHPAW
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
} thumbstick_t;
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
REASON_NONE,
|
REASON_NONE,
|
||||||
|
@ -57,9 +79,7 @@ typedef enum
|
||||||
// actual movement functions called at a later time.
|
// actual movement functions called at a later time.
|
||||||
static float mouse_x, mouse_y;
|
static float mouse_x, mouse_y;
|
||||||
static int sdl_back_button = SDL_CONTROLLER_BUTTON_BACK;
|
static int sdl_back_button = SDL_CONTROLLER_BUTTON_BACK;
|
||||||
static float joystick_yaw, joystick_pitch;
|
static int joystick_left_x, joystick_left_y, joystick_right_x, joystick_right_y;
|
||||||
static float joystick_forwardmove, joystick_sidemove;
|
|
||||||
static float joystick_up;
|
|
||||||
static float gyro_yaw, gyro_pitch;
|
static float gyro_yaw, gyro_pitch;
|
||||||
static qboolean mlooking;
|
static qboolean mlooking;
|
||||||
|
|
||||||
|
@ -118,24 +138,17 @@ static cvar_t *joy_yawsensitivity;
|
||||||
static cvar_t *joy_pitchsensitivity;
|
static cvar_t *joy_pitchsensitivity;
|
||||||
static cvar_t *joy_forwardsensitivity;
|
static cvar_t *joy_forwardsensitivity;
|
||||||
static cvar_t *joy_sidesensitivity;
|
static cvar_t *joy_sidesensitivity;
|
||||||
static cvar_t *joy_upsensitivity;
|
|
||||||
static cvar_t *joy_expo;
|
|
||||||
|
|
||||||
// Joystick direction settings
|
// Joystick's analog sticks configuration
|
||||||
static cvar_t *joy_axis_leftx;
|
cvar_t *joy_layout;
|
||||||
static cvar_t *joy_axis_lefty;
|
static cvar_t *joy_left_expo;
|
||||||
static cvar_t *joy_axis_rightx;
|
static cvar_t *joy_left_snapaxis;
|
||||||
static cvar_t *joy_axis_righty;
|
static cvar_t *joy_left_deadzone;
|
||||||
static cvar_t *joy_axis_triggerleft;
|
static cvar_t *joy_right_expo;
|
||||||
static cvar_t *joy_axis_triggerright;
|
static cvar_t *joy_right_snapaxis;
|
||||||
|
static cvar_t *joy_right_deadzone;
|
||||||
// Joystick threshold settings
|
static cvar_t *joy_flick_threshold;
|
||||||
static cvar_t *joy_axis_leftx_threshold;
|
static cvar_t *joy_flick_smoothed;
|
||||||
static cvar_t *joy_axis_lefty_threshold;
|
|
||||||
static cvar_t *joy_axis_rightx_threshold;
|
|
||||||
static cvar_t *joy_axis_righty_threshold;
|
|
||||||
static cvar_t *joy_axis_triggerleft_threshold;
|
|
||||||
static cvar_t *joy_axis_triggerright_threshold;
|
|
||||||
|
|
||||||
// Joystick haptic
|
// Joystick haptic
|
||||||
static cvar_t *joy_haptic_magnitude;
|
static cvar_t *joy_haptic_magnitude;
|
||||||
|
@ -166,15 +179,24 @@ static cvar_t *gyro_calibration_z;
|
||||||
static qboolean first_init = true;
|
static qboolean first_init = true;
|
||||||
|
|
||||||
// Countdown of calls to IN_Update(), needed for controller init and gyro calibration
|
// Countdown of calls to IN_Update(), needed for controller init and gyro calibration
|
||||||
static unsigned int updates_countdown = 30;
|
static unsigned short int updates_countdown = 30;
|
||||||
|
|
||||||
// Reason for the countdown
|
// Reason for the countdown
|
||||||
static updates_countdown_reasons countdown_reason = REASON_CONTROLLERINIT;
|
static updates_countdown_reasons countdown_reason = REASON_CONTROLLERINIT;
|
||||||
|
|
||||||
// Factors used to transform from SDL input to Q2 "view angle" change
|
// Factor used to transform from SDL input to Q2 "view angle" change
|
||||||
#define NORMALIZE_SDL_AXIS (1.0f/32768.0f)
|
|
||||||
static float normalize_sdl_gyro = 1.0f / M_PI; // can change depending on hardware
|
static float normalize_sdl_gyro = 1.0f / M_PI; // can change depending on hardware
|
||||||
|
|
||||||
|
// Flick Stick
|
||||||
|
#define FLICK_TIME 6 // number of frames it takes for a flick to execute
|
||||||
|
static float target_angle; // angle to end up facing at the end of a flick
|
||||||
|
static unsigned short int flick_progress = FLICK_TIME;
|
||||||
|
|
||||||
|
// Flick Stick's rotation input samples to smooth out
|
||||||
|
#define MAX_SMOOTH_SAMPLES 8
|
||||||
|
static float flick_samples[MAX_SMOOTH_SAMPLES];
|
||||||
|
static unsigned short int front_sample = 0;
|
||||||
|
|
||||||
extern void CalibrationFinishedCallback(void);
|
extern void CalibrationFinishedCallback(void);
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
|
@ -689,133 +711,51 @@ IN_Update(void)
|
||||||
|
|
||||||
case SDL_CONTROLLERAXISMOTION: /* Handle Controller Motion */
|
case SDL_CONTROLLERAXISMOTION: /* Handle Controller Motion */
|
||||||
{
|
{
|
||||||
char *direction_type;
|
|
||||||
float threshold = 0;
|
|
||||||
float fix_value = 0;
|
|
||||||
int axis_value = event.caxis.value;
|
int axis_value = event.caxis.value;
|
||||||
|
|
||||||
switch (event.caxis.axis)
|
switch (event.caxis.axis)
|
||||||
{
|
{
|
||||||
/* left/right */
|
|
||||||
case SDL_CONTROLLER_AXIS_LEFTX:
|
|
||||||
direction_type = joy_axis_leftx->string;
|
|
||||||
threshold = joy_axis_leftx_threshold->value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* top/bottom */
|
|
||||||
case SDL_CONTROLLER_AXIS_LEFTY:
|
|
||||||
direction_type = joy_axis_lefty->string;
|
|
||||||
threshold = joy_axis_lefty_threshold->value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* second left/right */
|
|
||||||
case SDL_CONTROLLER_AXIS_RIGHTX:
|
|
||||||
direction_type = joy_axis_rightx->string;
|
|
||||||
threshold = joy_axis_rightx_threshold->value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
/* second top/bottom */
|
|
||||||
case SDL_CONTROLLER_AXIS_RIGHTY:
|
|
||||||
direction_type = joy_axis_righty->string;
|
|
||||||
threshold = joy_axis_righty_threshold->value;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
|
case SDL_CONTROLLER_AXIS_TRIGGERLEFT:
|
||||||
direction_type = joy_axis_triggerleft->string;
|
{
|
||||||
threshold = joy_axis_triggerleft_threshold->value;
|
qboolean new_left_trigger = axis_value > 8192;
|
||||||
|
if (new_left_trigger != left_trigger)
|
||||||
|
{
|
||||||
|
left_trigger = new_left_trigger;
|
||||||
|
Key_Event(K_TRIG_LEFT, left_trigger, true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
|
case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
|
||||||
direction_type = joy_axis_triggerright->string;
|
{
|
||||||
threshold = joy_axis_triggerright_threshold->value;
|
qboolean new_right_trigger = axis_value > 8192;
|
||||||
|
if (new_right_trigger != right_trigger)
|
||||||
|
{
|
||||||
|
right_trigger = new_right_trigger;
|
||||||
|
Key_Event(K_TRIG_RIGHT, right_trigger, true);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
|
||||||
direction_type = "none";
|
|
||||||
}
|
|
||||||
|
|
||||||
if (threshold > 0.9)
|
|
||||||
{
|
|
||||||
threshold = 0.9;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (axis_value < 0 && (axis_value > (32768 * threshold)))
|
|
||||||
{
|
|
||||||
axis_value = 0;
|
|
||||||
}
|
|
||||||
else if (axis_value > 0 && (axis_value < (32768 * threshold)))
|
|
||||||
{
|
|
||||||
axis_value = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Smoothly ramp from dead zone to maximum value (from ioquake)
|
|
||||||
// https://github.com/ioquake/ioq3/blob/master/code/sdl/sdl_input.c
|
|
||||||
fix_value = ((float) abs(axis_value) / 32767.0f - threshold) / (1.0f - threshold);
|
|
||||||
|
|
||||||
if (fix_value < 0.0f)
|
|
||||||
{
|
|
||||||
fix_value = 0.0f;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply expo
|
|
||||||
fix_value = pow(fix_value, joy_expo->value);
|
|
||||||
|
|
||||||
axis_value = (int) (32767 * ((axis_value < 0) ? -fix_value : fix_value));
|
|
||||||
|
|
||||||
if (cls.key_dest == key_game && (int) cl_paused->value == 0)
|
|
||||||
{
|
|
||||||
if (strcmp(direction_type, "sidemove") == 0)
|
|
||||||
{
|
|
||||||
joystick_sidemove = axis_value * joy_sidesensitivity->value;
|
|
||||||
|
|
||||||
// We need to be twice faster because with joystic we run...
|
|
||||||
joystick_sidemove *= cl_sidespeed->value * 2.0f;
|
|
||||||
}
|
|
||||||
else if (strcmp(direction_type, "forwardmove") == 0)
|
|
||||||
{
|
|
||||||
joystick_forwardmove = axis_value * joy_forwardsensitivity->value;
|
|
||||||
|
|
||||||
// We need to be twice faster because with joystic we run...
|
|
||||||
joystick_forwardmove *= cl_forwardspeed->value * 2.0f;
|
|
||||||
}
|
|
||||||
else if (strcmp(direction_type, "yaw") == 0)
|
|
||||||
{
|
|
||||||
joystick_yaw = axis_value * joy_yawsensitivity->value;
|
|
||||||
joystick_yaw *= cl_yawspeed->value;
|
|
||||||
}
|
|
||||||
else if (strcmp(direction_type, "pitch") == 0)
|
|
||||||
{
|
|
||||||
joystick_pitch = axis_value * joy_pitchsensitivity->value;
|
|
||||||
joystick_pitch *= cl_pitchspeed->value;
|
|
||||||
}
|
|
||||||
else if (strcmp(direction_type, "updown") == 0)
|
|
||||||
{
|
|
||||||
joystick_up = axis_value * joy_upsensitivity->value;
|
|
||||||
joystick_up *= cl_upspeed->value;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(direction_type, "triggerleft") == 0)
|
if (!cl_paused->value && cls.key_dest == key_game)
|
||||||
{
|
{
|
||||||
qboolean new_left_trigger = abs(axis_value) > (32767 / 4);
|
switch (event.caxis.axis)
|
||||||
|
|
||||||
if (new_left_trigger != left_trigger)
|
|
||||||
{
|
{
|
||||||
left_trigger = new_left_trigger;
|
case SDL_CONTROLLER_AXIS_LEFTX:
|
||||||
Key_Event(K_TRIG_LEFT, left_trigger, true);
|
joystick_left_x = axis_value;
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_AXIS_LEFTY:
|
||||||
|
joystick_left_y = axis_value;
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_AXIS_RIGHTX:
|
||||||
|
joystick_right_x = axis_value;
|
||||||
|
break;
|
||||||
|
case SDL_CONTROLLER_AXIS_RIGHTY:
|
||||||
|
joystick_right_y = axis_value;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (strcmp(direction_type, "triggerright") == 0)
|
|
||||||
{
|
|
||||||
qboolean new_right_trigger = abs(axis_value) > (32767 / 4);
|
|
||||||
|
|
||||||
if (new_right_trigger != right_trigger)
|
|
||||||
{
|
|
||||||
right_trigger = new_right_trigger;
|
|
||||||
Key_Event(K_TRIG_RIGHT, right_trigger, true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -833,11 +773,9 @@ IN_Update(void)
|
||||||
num_samples++;
|
num_samples++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!gyro_active || !gyro_mode->value)
|
|
||||||
{
|
if (gyro_active && gyro_mode->value &&
|
||||||
gyro_yaw = gyro_pitch = 0;
|
!cl_paused->value && cls.key_dest == key_game)
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if (!gyro_turning_axis->value)
|
if (!gyro_turning_axis->value)
|
||||||
{
|
{
|
||||||
|
@ -851,6 +789,10 @@ IN_Update(void)
|
||||||
gyro_pitch = (event.csensor.data[0] - gyro_calibration_x->value)
|
gyro_pitch = (event.csensor.data[0] - gyro_calibration_x->value)
|
||||||
* gyro_pitchsensitivity->value * cl_pitchspeed->value;
|
* gyro_pitchsensitivity->value * cl_pitchspeed->value;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
gyro_yaw = gyro_pitch = 0;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
#endif // SDL_VERSION_ATLEAST(2, 0, 16)
|
#endif // SDL_VERSION_ATLEAST(2, 0, 16)
|
||||||
|
|
||||||
|
@ -942,14 +884,220 @@ IN_Update(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Joystick vector magnitude
|
||||||
|
*/
|
||||||
|
static float
|
||||||
|
IN_StickMagnitude(thumbstick_t stick)
|
||||||
|
{
|
||||||
|
return sqrtf((stick.x * stick.x) + (stick.y * stick.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scales "v" from [deadzone, 1] range to [0, 1] range, then inherits sign
|
||||||
|
*/
|
||||||
|
static float
|
||||||
|
IN_MapRange(float v, float deadzone, float sign)
|
||||||
|
{
|
||||||
|
return ((v - deadzone) / (1 - deadzone)) * sign;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Radial deadzone based on github.com/jeremiah-sypult/Quakespasm-Rift
|
||||||
|
*/
|
||||||
|
static thumbstick_t
|
||||||
|
IN_RadialDeadzone(thumbstick_t stick, float deadzone)
|
||||||
|
{
|
||||||
|
thumbstick_t result = {0};
|
||||||
|
float magnitude = min(IN_StickMagnitude(stick), 1.0f);
|
||||||
|
deadzone = min( max(deadzone, 0.0f), 0.9f); // clamp to [0.0, 0.9]
|
||||||
|
|
||||||
|
if ( magnitude > deadzone )
|
||||||
|
{
|
||||||
|
const float scale = ((magnitude - deadzone) / (1.0 - deadzone)) / magnitude;
|
||||||
|
result.x = stick.x * scale;
|
||||||
|
result.y = stick.y * scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sloped axial deadzone based on github.com/Minimuino/thumbstick-deadzones
|
||||||
|
* Provides a "snap-to-axis" feeling, without losing precision near the center of the stick
|
||||||
|
*/
|
||||||
|
static thumbstick_t
|
||||||
|
IN_SlopedAxialDeadzone(thumbstick_t stick, float deadzone)
|
||||||
|
{
|
||||||
|
thumbstick_t result = {0};
|
||||||
|
float abs_x = fabsf(stick.x);
|
||||||
|
float abs_y = fabsf(stick.y);
|
||||||
|
float sign_x = copysignf(1.0f, stick.x);
|
||||||
|
float sign_y = copysignf(1.0f, stick.y);
|
||||||
|
deadzone = min(deadzone, 0.5f);
|
||||||
|
float deadzone_x = deadzone * abs_y; // deadzone of one axis depends...
|
||||||
|
float deadzone_y = deadzone * abs_x; // ...on the value of the other axis
|
||||||
|
|
||||||
|
if (abs_x > deadzone_x)
|
||||||
|
{
|
||||||
|
result.x = IN_MapRange(abs_x, deadzone_x, sign_x);
|
||||||
|
}
|
||||||
|
if (abs_y > deadzone_y)
|
||||||
|
{
|
||||||
|
result.y = IN_MapRange(abs_y, deadzone_y, sign_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Exponent applied on stick magnitude
|
||||||
|
*/
|
||||||
|
static thumbstick_t
|
||||||
|
IN_ApplyExpo(thumbstick_t stick, float exponent)
|
||||||
|
{
|
||||||
|
thumbstick_t result = {0};
|
||||||
|
float magnitude = IN_StickMagnitude(stick);
|
||||||
|
if (magnitude == 0)
|
||||||
|
{
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float eased = powf(magnitude, exponent) / magnitude;
|
||||||
|
result.x = stick.x * eased;
|
||||||
|
result.y = stick.y * eased;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Delete flick stick's buffer of angle samples for smoothing
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
IN_ResetSmoothSamples()
|
||||||
|
{
|
||||||
|
front_sample = 0;
|
||||||
|
for (int i = 0; i < MAX_SMOOTH_SAMPLES; i++)
|
||||||
|
{
|
||||||
|
flick_samples[i] = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Soft tiered smoothing for angle rotations with Flick Stick
|
||||||
|
* http://gyrowiki.jibbsmart.com/blog:tight-and-smooth:soft-tiered-smoothing
|
||||||
|
*/
|
||||||
|
static float
|
||||||
|
IN_SmoothedStickRotation(float value)
|
||||||
|
{
|
||||||
|
float top_threshold = joy_flick_smoothed->value;
|
||||||
|
float bottom_threshold = top_threshold / 2.0f;
|
||||||
|
if (top_threshold == 0)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sample in the circular smoothing buffer we want to write over
|
||||||
|
front_sample = (front_sample + 1) % MAX_SMOOTH_SAMPLES;
|
||||||
|
|
||||||
|
// if input > top threshold, it'll all be consumed immediately
|
||||||
|
// 0 gets put into the smoothing buffer
|
||||||
|
// if input < bottom threshold, it'll all be put in the smoothing buffer
|
||||||
|
// 0 for immediate consumption
|
||||||
|
float immediate_weight = (fabsf(value) - bottom_threshold)
|
||||||
|
/ (top_threshold - bottom_threshold);
|
||||||
|
immediate_weight = min( max(immediate_weight, 0.0f), 1.0f ); // clamp to [0, 1] range
|
||||||
|
|
||||||
|
// now we can push the smooth sample
|
||||||
|
float smooth_weight = 1.0f - immediate_weight;
|
||||||
|
flick_samples[front_sample] = value * smooth_weight;
|
||||||
|
|
||||||
|
// calculate smoothed result
|
||||||
|
float average = 0;
|
||||||
|
for (int i = 0; i < MAX_SMOOTH_SAMPLES; i++)
|
||||||
|
{
|
||||||
|
average += flick_samples[i];
|
||||||
|
}
|
||||||
|
average /= MAX_SMOOTH_SAMPLES;
|
||||||
|
|
||||||
|
// finally, add immediate portion (original input)
|
||||||
|
return average + value * immediate_weight;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Flick Stick handling: detect if the player just started one, or return the
|
||||||
|
* player rotation if stick was already flicked
|
||||||
|
*/
|
||||||
|
static float
|
||||||
|
IN_FlickStick(thumbstick_t stick, float axial_deadzone)
|
||||||
|
{
|
||||||
|
static qboolean is_flicking;
|
||||||
|
static float last_stick_angle;
|
||||||
|
thumbstick_t processed = stick;
|
||||||
|
float angle_change = 0;
|
||||||
|
|
||||||
|
if (IN_StickMagnitude(stick) > min(joy_flick_threshold->value, 1.0f)) // flick!
|
||||||
|
{
|
||||||
|
// Make snap-to-axis only if player wasn't already flicking
|
||||||
|
if (!is_flicking || flick_progress < FLICK_TIME)
|
||||||
|
{
|
||||||
|
processed = IN_SlopedAxialDeadzone(stick, axial_deadzone);
|
||||||
|
}
|
||||||
|
|
||||||
|
const float stick_angle = (180 / M_PI) * atan2f(-processed.x, -processed.y);
|
||||||
|
|
||||||
|
if (!is_flicking)
|
||||||
|
{
|
||||||
|
// Flicking begins now, with a new target
|
||||||
|
is_flicking = true;
|
||||||
|
flick_progress = 0;
|
||||||
|
target_angle = stick_angle;
|
||||||
|
IN_ResetSmoothSamples();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Was already flicking, just turning now
|
||||||
|
angle_change = stick_angle - last_stick_angle;
|
||||||
|
|
||||||
|
// angle wrap: https://stackoverflow.com/a/11498248/1130520
|
||||||
|
angle_change = fmod(angle_change + 180.0f, 360.0f);
|
||||||
|
if (angle_change < 0)
|
||||||
|
{
|
||||||
|
angle_change += 360.0f;
|
||||||
|
}
|
||||||
|
angle_change -= 180.0f;
|
||||||
|
angle_change = IN_SmoothedStickRotation(angle_change);
|
||||||
|
}
|
||||||
|
|
||||||
|
last_stick_angle = stick_angle;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
is_flicking = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return angle_change;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Move handling
|
* Move handling
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
IN_Move(usercmd_t *cmd)
|
IN_Move(usercmd_t *cmd)
|
||||||
{
|
{
|
||||||
|
// Factor used to transform from SDL joystick input ([-32768, 32767]) to [-1, 1] range
|
||||||
|
static const float normalize_sdl_axis = 1.0f / 32768.0f;
|
||||||
|
|
||||||
|
// Flick Stick's factors to change to the target angle with a feeling of "ease out"
|
||||||
|
static const float rotation_factor[FLICK_TIME] =
|
||||||
|
{
|
||||||
|
0.305555556f, 0.249999999f, 0.194444445f, 0.138888889f, 0.083333333f, 0.027777778f
|
||||||
|
};
|
||||||
|
|
||||||
static float old_mouse_x;
|
static float old_mouse_x;
|
||||||
static float old_mouse_y;
|
static float old_mouse_y;
|
||||||
|
static float joystick_yaw, joystick_pitch;
|
||||||
|
static float joystick_forwardmove, joystick_sidemove;
|
||||||
|
static thumbstick_t left_stick = {0}, right_stick = {0};
|
||||||
|
|
||||||
if (m_filter->value)
|
if (m_filter->value)
|
||||||
{
|
{
|
||||||
|
@ -1024,39 +1172,106 @@ IN_Move(usercmd_t *cmd)
|
||||||
mouse_x = mouse_y = 0;
|
mouse_x = mouse_y = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Joystick reading and processing
|
||||||
|
left_stick.x = joystick_left_x * normalize_sdl_axis;
|
||||||
|
left_stick.y = joystick_left_y * normalize_sdl_axis;
|
||||||
|
right_stick.x = joystick_right_x * normalize_sdl_axis;
|
||||||
|
right_stick.y = joystick_right_y * normalize_sdl_axis;
|
||||||
|
|
||||||
|
if (left_stick.x || left_stick.y)
|
||||||
|
{
|
||||||
|
left_stick = IN_RadialDeadzone(left_stick, joy_left_deadzone->value);
|
||||||
|
if ((int)joy_layout->value == LAYOUT_FLICK_STICK_SOUTHPAW)
|
||||||
|
{
|
||||||
|
cl.viewangles[YAW] += IN_FlickStick(left_stick, joy_left_snapaxis->value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
left_stick = IN_SlopedAxialDeadzone(left_stick, joy_left_snapaxis->value);
|
||||||
|
left_stick = IN_ApplyExpo(left_stick, joy_left_expo->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (right_stick.x || right_stick.y)
|
||||||
|
{
|
||||||
|
right_stick = IN_RadialDeadzone(right_stick, joy_right_deadzone->value);
|
||||||
|
if ((int)joy_layout->value == LAYOUT_FLICK_STICK)
|
||||||
|
{
|
||||||
|
cl.viewangles[YAW] += IN_FlickStick(right_stick, joy_right_snapaxis->value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
right_stick = IN_SlopedAxialDeadzone(right_stick, joy_right_snapaxis->value);
|
||||||
|
right_stick = IN_ApplyExpo(right_stick, joy_right_expo->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch((int)joy_layout->value)
|
||||||
|
{
|
||||||
|
case LAYOUT_SOUTHPAW:
|
||||||
|
joystick_forwardmove = right_stick.y;
|
||||||
|
joystick_sidemove = right_stick.x;
|
||||||
|
joystick_yaw = left_stick.x;
|
||||||
|
joystick_pitch = left_stick.y;
|
||||||
|
break;
|
||||||
|
case LAYOUT_LEGACY:
|
||||||
|
joystick_forwardmove = left_stick.y;
|
||||||
|
joystick_sidemove = right_stick.x;
|
||||||
|
joystick_yaw = left_stick.x;
|
||||||
|
joystick_pitch = right_stick.y;
|
||||||
|
break;
|
||||||
|
case LAYOUT_LEGACY_SOUTHPAW:
|
||||||
|
joystick_forwardmove = right_stick.y;
|
||||||
|
joystick_sidemove = left_stick.x;
|
||||||
|
joystick_yaw = right_stick.x;
|
||||||
|
joystick_pitch = left_stick.y;
|
||||||
|
break;
|
||||||
|
case LAYOUT_FLICK_STICK: // yaw already set by now
|
||||||
|
joystick_forwardmove = left_stick.y;
|
||||||
|
joystick_sidemove = left_stick.x;
|
||||||
|
break;
|
||||||
|
case LAYOUT_FLICK_STICK_SOUTHPAW:
|
||||||
|
joystick_forwardmove = right_stick.y;
|
||||||
|
joystick_sidemove = right_stick.x;
|
||||||
|
break;
|
||||||
|
default: // LAYOUT_DEFAULT
|
||||||
|
joystick_forwardmove = left_stick.y;
|
||||||
|
joystick_sidemove = left_stick.x;
|
||||||
|
joystick_yaw = right_stick.x;
|
||||||
|
joystick_pitch = right_stick.y;
|
||||||
|
}
|
||||||
|
|
||||||
// To make the the viewangles changes independent of framerate we need to scale
|
// To make the the viewangles changes independent of framerate we need to scale
|
||||||
// with frametime (assuming the configured values are for 60hz)
|
// with frametime (assuming the configured values are for 60hz)
|
||||||
//
|
//
|
||||||
// 1/32768 is to normalize the input values from SDL (they're between -32768 and
|
// For movement this is not needed, as those are absolute values independent of framerate
|
||||||
// 32768 and we want -1 to 1) for movement this is not needed, as those are
|
float joyViewFactor = cls.rframetime/0.01666f;
|
||||||
// absolute values independent of framerate
|
float gyroViewFactor = normalize_sdl_gyro * joyViewFactor;
|
||||||
float frametime_ratio = cls.rframetime/0.01666f;
|
|
||||||
float joyViewFactor = NORMALIZE_SDL_AXIS * frametime_ratio;
|
|
||||||
float gyroViewFactor = normalize_sdl_gyro * frametime_ratio;
|
|
||||||
|
|
||||||
if (joystick_yaw)
|
if (joystick_yaw)
|
||||||
{
|
{
|
||||||
cl.viewangles[YAW] -= (m_yaw->value * joystick_yaw) * joyViewFactor;
|
cl.viewangles[YAW] -= (m_yaw->value * joy_yawsensitivity->value
|
||||||
|
* cl_yawspeed->value * joystick_yaw) * joyViewFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(joystick_pitch)
|
if(joystick_pitch)
|
||||||
{
|
{
|
||||||
cl.viewangles[PITCH] += (m_pitch->value * joystick_pitch) * joyViewFactor;
|
cl.viewangles[PITCH] += (m_pitch->value * joy_pitchsensitivity->value
|
||||||
|
* cl_pitchspeed->value * joystick_pitch) * joyViewFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (joystick_forwardmove)
|
if (joystick_forwardmove)
|
||||||
{
|
{
|
||||||
cmd->forwardmove -= (m_forward->value * joystick_forwardmove) / 32768;
|
// We need to be twice as fast because with joystick we run...
|
||||||
|
cmd->forwardmove -= m_forward->value * joy_forwardsensitivity->value
|
||||||
|
* cl_forwardspeed->value * 2.0f * joystick_forwardmove;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (joystick_sidemove)
|
if (joystick_sidemove)
|
||||||
{
|
{
|
||||||
cmd->sidemove += (m_side->value * joystick_sidemove) / 32768;
|
// We need to be twice as fast because with joystick we run...
|
||||||
}
|
cmd->sidemove += m_side->value * joy_sidesensitivity->value
|
||||||
|
* cl_sidespeed->value * 2.0f * joystick_sidemove;
|
||||||
if (joystick_up)
|
|
||||||
{
|
|
||||||
cmd->upmove -= (m_up->value * joystick_up) / 32768;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gyro_yaw)
|
if (gyro_yaw)
|
||||||
|
@ -1068,6 +1283,13 @@ IN_Move(usercmd_t *cmd)
|
||||||
{
|
{
|
||||||
cl.viewangles[PITCH] -= (m_pitch->value * gyro_pitch) * gyroViewFactor;
|
cl.viewangles[PITCH] -= (m_pitch->value * gyro_pitch) * gyroViewFactor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Flick Stick: flick in progress, changing the yaw angle to the target progressively
|
||||||
|
if (flick_progress < FLICK_TIME)
|
||||||
|
{
|
||||||
|
cl.viewangles[YAW] += target_angle * rotation_factor[flick_progress];
|
||||||
|
flick_progress++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------------------------------------------------------ */
|
/* ------------------------------------------------------------------ */
|
||||||
|
@ -1474,7 +1696,7 @@ IN_Controller_Init(qboolean notify_user)
|
||||||
|
|
||||||
Com_Printf ("The name of the joystick is '%s'\n", joystick_name);
|
Com_Printf ("The name of the joystick is '%s'\n", joystick_name);
|
||||||
|
|
||||||
// Ugly hack to detect IMU-only devices - works for Switch Pro Controller at least
|
// Ugly hack to detect IMU-only devices - works for Switch controllers at least
|
||||||
if (name_len > 4 && !strncmp(joystick_name + name_len - 4, " IMU", 4))
|
if (name_len > 4 && !strncmp(joystick_name + name_len - 4, " IMU", 4))
|
||||||
{
|
{
|
||||||
Com_Printf ("Skipping IMU device.\n");
|
Com_Printf ("Skipping IMU device.\n");
|
||||||
|
@ -1511,21 +1733,14 @@ IN_Controller_Init(qboolean notify_user)
|
||||||
controller = SDL_GameControllerOpen(i);
|
controller = SDL_GameControllerOpen(i);
|
||||||
|
|
||||||
Com_Printf ("Controller settings: %s\n", SDL_GameControllerMapping(controller));
|
Com_Printf ("Controller settings: %s\n", SDL_GameControllerMapping(controller));
|
||||||
Com_Printf ("Controller axis: \n");
|
Com_Printf ("Left stick config:\n");
|
||||||
Com_Printf (" * leftx = %s\n", joy_axis_leftx->string);
|
Com_Printf (" * response curve exponent = %.3f\n", joy_left_expo->value);
|
||||||
Com_Printf (" * lefty = %s\n", joy_axis_lefty->string);
|
Com_Printf (" * snap-to-axis ratio = %.3f\n", joy_left_snapaxis->value);
|
||||||
Com_Printf (" * rightx = %s\n", joy_axis_rightx->string);
|
Com_Printf (" * inner deadzone = %.3f\n", joy_left_deadzone->value);
|
||||||
Com_Printf (" * righty = %s\n", joy_axis_righty->string);
|
Com_Printf ("Right stick config:\n");
|
||||||
Com_Printf (" * triggerleft = %s\n", joy_axis_triggerleft->string);
|
Com_Printf (" * response curve exponent = %.3f\n", joy_right_expo->value);
|
||||||
Com_Printf (" * triggerright = %s\n", joy_axis_triggerright->string);
|
Com_Printf (" * snap-to-axis ratio = %.3f\n", joy_right_snapaxis->value);
|
||||||
|
Com_Printf (" * inner deadzone = %.3f\n", joy_right_deadzone->value);
|
||||||
Com_Printf ("Controller thresholds: \n");
|
|
||||||
Com_Printf (" * leftx = %f\n", joy_axis_leftx_threshold->value);
|
|
||||||
Com_Printf (" * lefty = %f\n", joy_axis_lefty_threshold->value);
|
|
||||||
Com_Printf (" * rightx = %f\n", joy_axis_rightx_threshold->value);
|
|
||||||
Com_Printf (" * righty = %f\n", joy_axis_righty_threshold->value);
|
|
||||||
Com_Printf (" * triggerleft = %f\n", joy_axis_triggerleft_threshold->value);
|
|
||||||
Com_Printf (" * triggerright = %f\n", joy_axis_triggerright_threshold->value);
|
|
||||||
|
|
||||||
joystick_haptic = SDL_HapticOpenFromJoystick(SDL_GameControllerGetJoystick(controller));
|
joystick_haptic = SDL_HapticOpenFromJoystick(SDL_GameControllerGetJoystick(controller));
|
||||||
|
|
||||||
|
@ -1581,7 +1796,7 @@ IN_Init(void)
|
||||||
Com_Printf("------- input initialization -------\n");
|
Com_Printf("------- input initialization -------\n");
|
||||||
|
|
||||||
mouse_x = mouse_y = 0;
|
mouse_x = mouse_y = 0;
|
||||||
joystick_yaw = joystick_pitch = joystick_forwardmove = joystick_sidemove = 0;
|
joystick_left_x = joystick_left_y = joystick_right_x = joystick_right_y = 0;
|
||||||
gyro_yaw = gyro_pitch = 0;
|
gyro_yaw = gyro_pitch = 0;
|
||||||
|
|
||||||
exponential_speedup = Cvar_Get("exponential_speedup", "0", CVAR_ARCHIVE);
|
exponential_speedup = Cvar_Get("exponential_speedup", "0", CVAR_ARCHIVE);
|
||||||
|
@ -1602,22 +1817,16 @@ IN_Init(void)
|
||||||
joy_pitchsensitivity = Cvar_Get("joy_pitchsensitivity", "1.0", CVAR_ARCHIVE);
|
joy_pitchsensitivity = Cvar_Get("joy_pitchsensitivity", "1.0", CVAR_ARCHIVE);
|
||||||
joy_forwardsensitivity = Cvar_Get("joy_forwardsensitivity", "1.0", CVAR_ARCHIVE);
|
joy_forwardsensitivity = Cvar_Get("joy_forwardsensitivity", "1.0", CVAR_ARCHIVE);
|
||||||
joy_sidesensitivity = Cvar_Get("joy_sidesensitivity", "1.0", CVAR_ARCHIVE);
|
joy_sidesensitivity = Cvar_Get("joy_sidesensitivity", "1.0", CVAR_ARCHIVE);
|
||||||
joy_upsensitivity = Cvar_Get("joy_upsensitivity", "1.0", CVAR_ARCHIVE);
|
|
||||||
joy_expo = Cvar_Get("joy_expo", "2.0", CVAR_ARCHIVE);
|
|
||||||
|
|
||||||
joy_axis_leftx = Cvar_Get("joy_axis_leftx", "sidemove", CVAR_ARCHIVE);
|
joy_layout = Cvar_Get("joy_layout", "0", CVAR_ARCHIVE);
|
||||||
joy_axis_lefty = Cvar_Get("joy_axis_lefty", "forwardmove", CVAR_ARCHIVE);
|
joy_left_expo = Cvar_Get("joy_left_expo", "2.0", CVAR_ARCHIVE);
|
||||||
joy_axis_rightx = Cvar_Get("joy_axis_rightx", "yaw", CVAR_ARCHIVE);
|
joy_left_snapaxis = Cvar_Get("joy_left_snapaxis", "0.15", CVAR_ARCHIVE);
|
||||||
joy_axis_righty = Cvar_Get("joy_axis_righty", "pitch", CVAR_ARCHIVE);
|
joy_left_deadzone = Cvar_Get("joy_left_deadzone", "0.16", CVAR_ARCHIVE);
|
||||||
joy_axis_triggerleft = Cvar_Get("joy_axis_triggerleft", "triggerleft", CVAR_ARCHIVE);
|
joy_right_expo = Cvar_Get("joy_right_expo", "2.0", CVAR_ARCHIVE);
|
||||||
joy_axis_triggerright = Cvar_Get("joy_axis_triggerright", "triggerright", CVAR_ARCHIVE);
|
joy_right_snapaxis = Cvar_Get("joy_right_snapaxis", "0.15", CVAR_ARCHIVE);
|
||||||
|
joy_right_deadzone = Cvar_Get("joy_right_deadzone", "0.16", CVAR_ARCHIVE);
|
||||||
joy_axis_leftx_threshold = Cvar_Get("joy_axis_leftx_threshold", "0.15", CVAR_ARCHIVE);
|
joy_flick_threshold = Cvar_Get("joy_flick_threshold", "0.65", CVAR_ARCHIVE);
|
||||||
joy_axis_lefty_threshold = Cvar_Get("joy_axis_lefty_threshold", "0.15", CVAR_ARCHIVE);
|
joy_flick_smoothed = Cvar_Get("joy_flick_smoothed", "8.0", CVAR_ARCHIVE);
|
||||||
joy_axis_rightx_threshold = Cvar_Get("joy_axis_rightx_threshold", "0.15", CVAR_ARCHIVE);
|
|
||||||
joy_axis_righty_threshold = Cvar_Get("joy_axis_righty_threshold", "0.15", CVAR_ARCHIVE);
|
|
||||||
joy_axis_triggerleft_threshold = Cvar_Get("joy_axis_triggerleft_threshold", "0.15", CVAR_ARCHIVE);
|
|
||||||
joy_axis_triggerright_threshold = Cvar_Get("joy_axis_triggerright_threshold", "0.15", CVAR_ARCHIVE);
|
|
||||||
|
|
||||||
gyro_calibration_x = Cvar_Get("gyro_calibration_x", "0.0", CVAR_ARCHIVE);
|
gyro_calibration_x = Cvar_Get("gyro_calibration_x", "0.0", CVAR_ARCHIVE);
|
||||||
gyro_calibration_y = Cvar_Get("gyro_calibration_y", "0.0", CVAR_ARCHIVE);
|
gyro_calibration_y = Cvar_Get("gyro_calibration_y", "0.0", CVAR_ARCHIVE);
|
||||||
|
@ -1680,6 +1889,7 @@ IN_Controller_Shutdown(qboolean notify_user)
|
||||||
SDL_GameControllerClose(controller);
|
SDL_GameControllerClose(controller);
|
||||||
controller = NULL;
|
controller = NULL;
|
||||||
gyro_hardware = false;
|
gyro_hardware = false;
|
||||||
|
joystick_left_x = joystick_left_y = joystick_right_x = joystick_right_y = 0;
|
||||||
gyro_yaw = gyro_pitch = 0;
|
gyro_yaw = gyro_pitch = 0;
|
||||||
normalize_sdl_gyro = 1.0f / M_PI;
|
normalize_sdl_gyro = 1.0f / M_PI;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1709,12 +1709,12 @@ Gyro_MenuInit(void)
|
||||||
s_gyro_pitchsensitivity_slider.maxvalue = 8.0f;
|
s_gyro_pitchsensitivity_slider.maxvalue = 8.0f;
|
||||||
|
|
||||||
s_calibrating_text[0].generic.type = MTYPE_SEPARATOR;
|
s_calibrating_text[0].generic.type = MTYPE_SEPARATOR;
|
||||||
s_calibrating_text[0].generic.x = 48 * scale + 30;
|
s_calibrating_text[0].generic.x = 48 * scale + 32;
|
||||||
s_calibrating_text[0].generic.y = (y += 20);
|
s_calibrating_text[0].generic.y = (y += 20);
|
||||||
s_calibrating_text[0].generic.name = "place the controller on a flat,";
|
s_calibrating_text[0].generic.name = "place the controller on a flat,";
|
||||||
|
|
||||||
s_calibrating_text[1].generic.type = MTYPE_SEPARATOR;
|
s_calibrating_text[1].generic.type = MTYPE_SEPARATOR;
|
||||||
s_calibrating_text[1].generic.x = 48 * scale + 30;
|
s_calibrating_text[1].generic.x = 48 * scale + 32;
|
||||||
s_calibrating_text[1].generic.y = (y += 10);
|
s_calibrating_text[1].generic.y = (y += 10);
|
||||||
s_calibrating_text[1].generic.name = "stable surface to...";
|
s_calibrating_text[1].generic.name = "stable surface to...";
|
||||||
|
|
||||||
|
@ -1764,12 +1764,13 @@ M_Menu_Gyro_f(void)
|
||||||
/*
|
/*
|
||||||
* JOY MENU
|
* JOY MENU
|
||||||
*/
|
*/
|
||||||
static menuslider_s s_joy_expo_slider;
|
static menulist_s s_joy_layout_box;
|
||||||
static menuslider_s s_joy_yawsensitivity_slider;
|
static menuslider_s s_joy_yawsensitivity_slider;
|
||||||
static menuslider_s s_joy_pitchsensitivity_slider;
|
static menuslider_s s_joy_pitchsensitivity_slider;
|
||||||
static menuslider_s s_joy_forwardsensitivity_slider;
|
static menuslider_s s_joy_forwardsensitivity_slider;
|
||||||
static menuslider_s s_joy_sidesensitivity_slider;
|
static menuslider_s s_joy_sidesensitivity_slider;
|
||||||
static menuslider_s s_joy_upsensitivity_slider;
|
static menuslider_s s_joy_left_expo_slider;
|
||||||
|
static menuslider_s s_joy_right_expo_slider;
|
||||||
static menuslider_s s_joy_haptic_slider;
|
static menuslider_s s_joy_haptic_slider;
|
||||||
static menuaction_s s_joy_gyro_action;
|
static menuaction_s s_joy_gyro_action;
|
||||||
static menuaction_s s_joy_customize_buttons_action;
|
static menuaction_s s_joy_customize_buttons_action;
|
||||||
|
@ -1793,10 +1794,37 @@ ConfigGyroFunc(void *unused)
|
||||||
M_Menu_Gyro_f();
|
M_Menu_Gyro_f();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
StickLayoutFunc(void *unused)
|
||||||
|
{
|
||||||
|
Cvar_SetValue("joy_layout", (int)s_joy_layout_box.curvalue);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
Joy_MenuInit(void)
|
Joy_MenuInit(void)
|
||||||
{
|
{
|
||||||
extern qboolean show_haptic;
|
extern qboolean show_haptic;
|
||||||
|
|
||||||
|
static const char *stick_layouts[] =
|
||||||
|
{
|
||||||
|
"default",
|
||||||
|
"southpaw",
|
||||||
|
"legacy",
|
||||||
|
"legacy southpaw",
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *stick_layouts_fs[] =
|
||||||
|
{
|
||||||
|
"default",
|
||||||
|
"southpaw",
|
||||||
|
"legacy",
|
||||||
|
"legacy southpaw",
|
||||||
|
"flick stick",
|
||||||
|
"flick stick spaw",
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
int y = 0;
|
int y = 0;
|
||||||
|
|
||||||
s_joy_menu.x = (int)(viddef.width * 0.50f);
|
s_joy_menu.x = (int)(viddef.width * 0.50f);
|
||||||
|
@ -1846,27 +1874,25 @@ Joy_MenuInit(void)
|
||||||
|
|
||||||
y += 10;
|
y += 10;
|
||||||
|
|
||||||
s_joy_upsensitivity_slider.generic.type = MTYPE_SLIDER;
|
s_joy_left_expo_slider.generic.type = MTYPE_SLIDER;
|
||||||
s_joy_upsensitivity_slider.generic.x = 0;
|
s_joy_left_expo_slider.generic.x = 0;
|
||||||
s_joy_upsensitivity_slider.generic.y = y;
|
s_joy_left_expo_slider.generic.y = y;
|
||||||
y += 10;
|
y += 10;
|
||||||
s_joy_upsensitivity_slider.generic.name = "up sensitivity";
|
s_joy_left_expo_slider.generic.name = "left expo";
|
||||||
s_joy_upsensitivity_slider.cvar = "joy_upsensitivity";
|
s_joy_left_expo_slider.cvar = "joy_left_expo";
|
||||||
s_joy_upsensitivity_slider.minvalue = 0.0f;
|
s_joy_left_expo_slider.minvalue = 1;
|
||||||
s_joy_upsensitivity_slider.maxvalue = 2.0f;
|
s_joy_left_expo_slider.maxvalue = 5;
|
||||||
Menu_AddItem(&s_joy_menu, (void *)&s_joy_upsensitivity_slider);
|
Menu_AddItem(&s_joy_menu, (void *)&s_joy_left_expo_slider);
|
||||||
|
|
||||||
|
s_joy_right_expo_slider.generic.type = MTYPE_SLIDER;
|
||||||
|
s_joy_right_expo_slider.generic.x = 0;
|
||||||
|
s_joy_right_expo_slider.generic.y = y;
|
||||||
y += 10;
|
y += 10;
|
||||||
|
s_joy_right_expo_slider.generic.name = "right expo";
|
||||||
s_joy_expo_slider.generic.type = MTYPE_SLIDER;
|
s_joy_right_expo_slider.cvar = "joy_right_expo";
|
||||||
s_joy_expo_slider.generic.x = 0;
|
s_joy_right_expo_slider.minvalue = 1;
|
||||||
s_joy_expo_slider.generic.y = y;
|
s_joy_right_expo_slider.maxvalue = 5;
|
||||||
y += 10;
|
Menu_AddItem(&s_joy_menu, (void *)&s_joy_right_expo_slider);
|
||||||
s_joy_expo_slider.generic.name = "expo";
|
|
||||||
s_joy_expo_slider.cvar = "joy_expo";
|
|
||||||
s_joy_expo_slider.minvalue = 1;
|
|
||||||
s_joy_expo_slider.maxvalue = 5;
|
|
||||||
Menu_AddItem(&s_joy_menu, (void *)&s_joy_expo_slider);
|
|
||||||
|
|
||||||
if (show_haptic) {
|
if (show_haptic) {
|
||||||
y += 10;
|
y += 10;
|
||||||
|
@ -1882,6 +1908,26 @@ Joy_MenuInit(void)
|
||||||
Menu_AddItem(&s_joy_menu, (void *)&s_joy_haptic_slider);
|
Menu_AddItem(&s_joy_menu, (void *)&s_joy_haptic_slider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
y += 10;
|
||||||
|
|
||||||
|
s_joy_layout_box.generic.type = MTYPE_SPINCONTROL;
|
||||||
|
s_joy_layout_box.generic.x = 0;
|
||||||
|
s_joy_layout_box.generic.y = y;
|
||||||
|
y += 10;
|
||||||
|
s_joy_layout_box.generic.name = "stick layout";
|
||||||
|
s_joy_layout_box.generic.callback = StickLayoutFunc;
|
||||||
|
if (gyro_hardware || joy_layout->value > 3)
|
||||||
|
{
|
||||||
|
s_joy_layout_box.itemnames = stick_layouts_fs;
|
||||||
|
s_joy_layout_box.curvalue = ClampCvar(0, 5, joy_layout->value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
s_joy_layout_box.itemnames = stick_layouts;
|
||||||
|
s_joy_layout_box.curvalue = ClampCvar(0, 3, joy_layout->value);
|
||||||
|
}
|
||||||
|
Menu_AddItem(&s_joy_menu, (void *)&s_joy_layout_box);
|
||||||
|
|
||||||
if (gyro_hardware)
|
if (gyro_hardware)
|
||||||
{
|
{
|
||||||
y += 10;
|
y += 10;
|
||||||
|
@ -1909,7 +1955,7 @@ Joy_MenuInit(void)
|
||||||
s_joy_customize_alt_buttons_action.generic.x = 0;
|
s_joy_customize_alt_buttons_action.generic.x = 0;
|
||||||
s_joy_customize_alt_buttons_action.generic.y = y;
|
s_joy_customize_alt_buttons_action.generic.y = y;
|
||||||
y += 10;
|
y += 10;
|
||||||
s_joy_customize_alt_buttons_action.generic.name = "customize alt buttons";
|
s_joy_customize_alt_buttons_action.generic.name = "custom. alt buttons";
|
||||||
s_joy_customize_alt_buttons_action.generic.callback = CustomizeControllerAltButtonsFunc;
|
s_joy_customize_alt_buttons_action.generic.callback = CustomizeControllerAltButtonsFunc;
|
||||||
Menu_AddItem(&s_joy_menu, (void *)&s_joy_customize_alt_buttons_action);
|
Menu_AddItem(&s_joy_menu, (void *)&s_joy_customize_alt_buttons_action);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue