From 68973b6ae728869c1ef5f65f291ee4855faedd3f Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Tue, 27 Aug 2024 13:05:44 -0400 Subject: [PATCH] Flick Stick fixed duration to 0.1 seconds Formerly, there were "6 frames" with a precalculated change factor on each frame. This allowed to use Flick Stick exclusively on vsync 60 Hz screens only (6 * 16.6 ms = 100 ms). By using any other refresh rate, or just disabling vsync, these 6 frames could take any time, normally much less than the intended 100 ms. Now delta time is used to calculate the angle change on each frame displayed, so the entire flick duration remains at 100 ms, independent of refresh rate. --- src/client/input/sdl2.c | 36 +++++++++++++++++++++++------------- src/client/input/sdl3.c | 36 +++++++++++++++++++++++------------- 2 files changed, 46 insertions(+), 26 deletions(-) diff --git a/src/client/input/sdl2.c b/src/client/input/sdl2.c index 050c8ae2..10be4ae4 100644 --- a/src/client/input/sdl2.c +++ b/src/client/input/sdl2.c @@ -198,9 +198,10 @@ static unsigned short int updates_countdown = 30; static updates_countdown_reasons countdown_reason = REASON_CONTROLLERINIT; // Flick Stick -#define FLICK_TIME 6 // number of frames it takes for a flick to execute +#define FLICK_TIME 100 // time it takes for a flick to execute, in ms static float target_angle; // angle to end up facing at the end of a flick -static unsigned short int flick_progress = FLICK_TIME; +static float flick_progress = 1.0f; // from 0.0 to 1.0 +static int started_flick; // time of flick start // Flick Stick's rotation input samples to smooth out #define MAX_SMOOTH_SAMPLES 8 @@ -1163,7 +1164,7 @@ IN_FlickStick(thumbstick_t stick, float axial_deadzone) if (IN_StickMagnitude(stick) > Q_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) + if (!is_flicking || flick_progress < 1.0f) { processed = IN_SlopedAxialDeadzone(stick, axial_deadzone); } @@ -1174,7 +1175,8 @@ IN_FlickStick(thumbstick_t stick, float axial_deadzone) { // Flicking begins now, with a new target is_flicking = true; - flick_progress = 0; + flick_progress = 0.0f; + started_flick = cls.realtime; target_angle = stick_angle; IN_ResetSmoothSamples(); } @@ -1212,12 +1214,6 @@ 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_y; static float joystick_yaw, joystick_pitch; @@ -1422,10 +1418,24 @@ IN_Move(usercmd_t *cmd) } // Flick Stick: flick in progress, changing the yaw angle to the target progressively - if (flick_progress < FLICK_TIME) + if (flick_progress < 1.0f) { - cl.viewangles[YAW] += target_angle * rotation_factor[flick_progress]; - flick_progress++; + float old = flick_progress; + float new = (float)(cls.realtime - started_flick) / FLICK_TIME; + + if (new > 1.0f) new = 1.0f; + flick_progress = new; + + // "Ease out" warp processing for both old and new progress + // http://gyrowiki.jibbsmart.com/blog:good-gyro-controls-part-2:the-flick-stick#toc0 + old = 1.0f - old; + old *= old; + old = 1.0f - old; + new = 1.0f - new; + new *= new; + new = 1.0f - new; + + cl.viewangles[YAW] += (new - old) * target_angle; } } diff --git a/src/client/input/sdl3.c b/src/client/input/sdl3.c index 40e778c0..1c72ab0e 100644 --- a/src/client/input/sdl3.c +++ b/src/client/input/sdl3.c @@ -188,9 +188,10 @@ static unsigned short int updates_countdown = 30; static updates_countdown_reasons countdown_reason = REASON_CONTROLLERINIT; // Flick Stick -#define FLICK_TIME 6 // number of frames it takes for a flick to execute +#define FLICK_TIME 100 // time it takes for a flick to execute, in ms static float target_angle; // angle to end up facing at the end of a flick -static unsigned short int flick_progress = FLICK_TIME; +static float flick_progress = 1.0f; // from 0.0 to 1.0 +static int started_flick; // time of flick start // Flick Stick's rotation input samples to smooth out #define MAX_SMOOTH_SAMPLES 8 @@ -1148,7 +1149,7 @@ IN_FlickStick(thumbstick_t stick, float axial_deadzone) if (IN_StickMagnitude(stick) > Q_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) + if (!is_flicking || flick_progress < 1.0f) { processed = IN_SlopedAxialDeadzone(stick, axial_deadzone); } @@ -1159,7 +1160,8 @@ IN_FlickStick(thumbstick_t stick, float axial_deadzone) { // Flicking begins now, with a new target is_flicking = true; - flick_progress = 0; + flick_progress = 0.0f; + started_flick = cls.realtime; target_angle = stick_angle; IN_ResetSmoothSamples(); } @@ -1197,12 +1199,6 @@ 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_y; static float joystick_yaw, joystick_pitch; @@ -1407,10 +1403,24 @@ IN_Move(usercmd_t *cmd) } // Flick Stick: flick in progress, changing the yaw angle to the target progressively - if (flick_progress < FLICK_TIME) + if (flick_progress < 1.0f) { - cl.viewangles[YAW] += target_angle * rotation_factor[flick_progress]; - flick_progress++; + float old = flick_progress; + float new = (float)(cls.realtime - started_flick) / FLICK_TIME; + + if (new > 1.0f) new = 1.0f; + flick_progress = new; + + // "Ease out" warp processing for both old and new progress + // http://gyrowiki.jibbsmart.com/blog:good-gyro-controls-part-2:the-flick-stick#toc0 + old = 1.0f - old; + old *= old; + old = 1.0f - old; + new = 1.0f - new; + new *= new; + new = 1.0f - new; + + cl.viewangles[YAW] += (new - old) * target_angle; } }