From 045b3a2797a14f3112b93d792a34c2721990dfd8 Mon Sep 17 00:00:00 2001 From: ceski <56656010+ceski-1@users.noreply.github.com> Date: Sat, 25 May 2024 06:35:15 -0700 Subject: [PATCH] Refactor game input utility functions (#1705) --- src/CMakeLists.txt | 1 + src/d_main.c | 32 +--- src/d_main.h | 2 +- src/g_game.c | 348 ++++------------------------------ src/g_game.h | 18 +- src/g_input.c | 456 +++++++++++++++++++++++++++++++++++++++++++++ src/g_input.h | 73 ++++++++ src/i_input.c | 62 ------ src/i_input.h | 4 - src/m_config.c | 2 - src/mn_setup.c | 3 +- src/p_pspr.c | 25 +-- src/r_main.c | 1 - src/r_main.h | 3 - src/r_state.h | 1 + 15 files changed, 593 insertions(+), 438 deletions(-) create mode 100644 src/g_input.c create mode 100644 src/g_input.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b4b5e386..1511a539 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -28,6 +28,7 @@ set(WOOF_SOURCES f_wipe.c f_wipe.h font.h g_game.c g_game.h + g_input.c g_input.h hu_command.c hu_command.h hu_lib.c hu_lib.h hu_obituary.c hu_obituary.h diff --git a/src/d_main.c b/src/d_main.c index f88e6ea0..4fd1ef86 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -223,39 +223,13 @@ void D_ProcessEvents (void) } } -static boolean input_ready; - -void D_UpdateDeltaTics(void) -{ - if (uncapped && raw_input) - { - static uint64_t last_time; - const uint64_t current_time = I_GetTimeUS(); - - if (input_ready) - { - const uint64_t delta_time = current_time - last_time; - deltatics = (double)delta_time * TICRATE / 1000000.0; - deltatics = BETWEEN(0.0, 1.0, deltatics); - } - else - { - deltatics = 0.0; - } - - last_time = current_time; - } - else - { - deltatics = 1.0; - } -} - // // D_Display // draw current display, possibly wiping it from the previous // +boolean input_ready; + // wipegamestate can be set to -1 to force a wipe on the next draw gamestate_t wipegamestate = GS_DEMOSCREEN; static int screen_melt = wipe_Melt; @@ -2504,7 +2478,7 @@ void D_DoomMain(void) G_UpdateSideMove(); G_UpdateAngleFunctions(); - I_UpdateAccelerateMouse(); + G_UpdateAccelerateMouse(); MN_ResetTimeScale(); diff --git a/src/d_main.h b/src/d_main.h index 1758877a..f689dbcc 100644 --- a/src/d_main.h +++ b/src/d_main.h @@ -46,7 +46,7 @@ boolean D_CheckEndDoom(void); // Called by IO functions when input is detected. void D_PostEvent(struct event_s *ev); -void D_UpdateDeltaTics(void); +extern boolean input_ready; void D_BindMiscVariables(void); diff --git a/src/g_game.c b/src/g_game.c index a51a4845..198574dc 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -153,7 +153,7 @@ wbstartstruct_t wminfo; // parms for world map / intermission boolean haswolflevels = false;// jff 4/18/98 wolf levels present byte *savebuffer; boolean autorun = false; // always running? // phares -static boolean autostrafe50; +boolean autostrafe50; boolean novert = false; boolean mouselook = false; boolean padlook = false; @@ -178,14 +178,16 @@ static ticcmd_t* last_cmd = NULL; int key_escape = KEY_ESCAPE; // phares 4/13/98 int key_help = KEY_F1; // phares 4/13/98 -static int mouse_sensitivity; -static int mouse_sensitivity_y; -static int mouse_sensitivity_strafe; // [FG] strafe -static int mouse_sensitivity_y_look; // [FG] look +int mouse_sensitivity; +int mouse_sensitivity_y; +int mouse_sensitivity_strafe; // [FG] strafe +int mouse_sensitivity_y_look; // [FG] look // [FG] double click acts as "use" static boolean dclick_use; // [FG] invert vertical axis -static boolean mouse_y_invert; +boolean mouse_y_invert; +int mouse_acceleration; +int mouse_acceleration_threshold; #define MAXPLMOVE (forwardmove[1]) #define TURBOTHRESHOLD 0x32 @@ -193,11 +195,10 @@ static boolean mouse_y_invert; #define QUICKREVERSE 32768 // 180 degree reverse // phares #define NUMKEYS 256 -static fixed_t default_forwardmove[2] = {0x19, 0x32}; -static fixed_t default_sidemove[2] = {0x18, 0x28}; -fixed_t *forwardmove = default_forwardmove; +fixed_t forwardmove[2] = {0x19, 0x32}; +fixed_t default_sidemove[2] = {0x18, 0x28}; fixed_t *sidemove = default_sidemove; -fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn +const fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn boolean gamekeydown[NUMKEYS]; int turnheld; // for accelerative turning @@ -205,26 +206,14 @@ int turnheld; // for accelerative turning boolean mousebuttons[NUM_MOUSE_BUTTONS]; // mouse values are used once -static int mousex; -static int mousey; +int mousex; +int mousey; boolean dclick; -typedef struct carry_s -{ - double angle; - double pitch; - double side; - double vert; -} carry_t; - -static carry_t prevcarry; -static carry_t carry; static ticcmd_t basecmd; boolean joybuttons[NUM_CONTROLLER_BUTTONS]; -static const int direction[] = { 1, -1 }; - int savegameslot = -1; char savedescription[32]; @@ -391,267 +380,6 @@ static void G_DemoSkipTics(void) } } -static int RoundSide_Strict(double side) -{ - return lround(side * 0.5) * 2; // Even values only. -} - -static int RoundSide_Full(double side) -{ - return lround(side); -} - -static int (*RoundSide)(double side) = RoundSide_Full; - -void G_UpdateSideMove(void) -{ - if (strictmode || (netgame && !solonet)) - { - RoundSide = RoundSide_Strict; - sidemove = default_sidemove; - } - else - { - RoundSide = RoundSide_Full; - sidemove = autostrafe50 ? default_forwardmove : default_sidemove; - } -} - -static int CalcControllerForward(int speed) -{ - const int forward = lroundf(forwardmove[speed] * axes[AXIS_FORWARD] * - direction[joy_invert_forward]); - return BETWEEN(-forwardmove[speed], forwardmove[speed], forward); -} - -static int CalcControllerSideTurn(int speed) -{ - const int side = RoundSide(forwardmove[speed] * axes[AXIS_TURN] * - direction[joy_invert_turn]); - return BETWEEN(-forwardmove[speed], forwardmove[speed], side); -} - -static int CalcControllerSideStrafe(int speed) -{ - const int side = RoundSide(forwardmove[speed] * axes[AXIS_STRAFE] * - direction[joy_invert_strafe]); - return BETWEEN(-sidemove[speed], sidemove[speed], side); -} - -static double CalcControllerAngle(void) -{ - return (angleturn[1] * axes[AXIS_TURN] * direction[joy_invert_turn]); -} - -static double CalcControllerPitch(void) -{ - return (angleturn[1] * axes[AXIS_LOOK] * direction[joy_invert_look] - * FRACUNIT); -} - -static int CarryError(double value, const double *prevcarry, double *carry) -{ - const double desired = value + *prevcarry; - const int actual = lround(desired); - *carry = desired - actual; - return actual; -} - -static short CarryAngleTic_Full(double angle) -{ - return CarryError(angle, &prevcarry.angle, &carry.angle); -} - -static short CarryAngle_Full(double angle) -{ - const short fullres = CarryAngleTic_Full(angle); - localview.angle = fullres << FRACBITS; - return fullres; -} - -static short CarryAngle_FakeLongTics(double angle) -{ - return (localview.angleoffset = (CarryAngle_Full(angle) + 128) & 0xFF00); -} - -static short CarryAngleTic_LowRes(double angle) -{ - const double fullres = angle + prevcarry.angle; - const short lowres = ((short)lround(fullres) + 128) & 0xFF00; - carry.angle = fullres - lowres; - return lowres; -} - -static short CarryAngle_LowRes(double angle) -{ - const short lowres = CarryAngleTic_LowRes(angle); - localview.angle = lowres << FRACBITS; - return lowres; -} - -static void UpdateLocalView_Zero(void) -{ - memset(&localview, 0, sizeof(localview)); -} - -static void UpdateLocalView_FakeLongTics(void) -{ - localview.angle -= localview.angleoffset << FRACBITS; - localview.rawangle -= localview.angleoffset; - localview.angleoffset = 0; - localview.pitch = 0; - localview.rawpitch = 0.0; -} - -static short (*CarryAngleTic)(double angle); -static short (*CarryAngle)(double angle); -static void (*UpdateLocalView)(void); - -void G_UpdateAngleFunctions(void) -{ - CarryAngleTic = lowres_turn ? CarryAngleTic_LowRes : CarryAngleTic_Full; - CarryAngle = CarryAngleTic; - UpdateLocalView = UpdateLocalView_Zero; - - if (raw_input && (!netgame || solonet)) - { - if (lowres_turn && fake_longtics) - { - CarryAngle = CarryAngle_FakeLongTics; - UpdateLocalView = UpdateLocalView_FakeLongTics; - } - else if (uncapped) - { - CarryAngle = lowres_turn ? CarryAngle_LowRes : CarryAngle_Full; - } - } -} - -static int CarryPitch(double pitch) -{ - return (localview.pitch = CarryError(pitch, &prevcarry.pitch, &carry.pitch)); -} - -static int CarryMouseVert(double vert) -{ - return CarryError(vert, &prevcarry.vert, &carry.vert); -} - -static int CarryMouseSide(double side) -{ - const double desired = side + prevcarry.side; - const int actual = RoundSide(desired); - carry.side = desired - actual; - return actual; -} - -static double CalcMouseAngle(int mousex) -{ - if (!mouse_sensitivity) - return 0.0; - - return (I_AccelerateMouse(mousex) * (mouse_sensitivity + 5) * 8 / 10); -} - -static double CalcMousePitch(int mousey) -{ - if (!mouse_sensitivity_y_look) - return 0.0; - - return (I_AccelerateMouse(mousey) * (mouse_sensitivity_y_look + 5) * 8 / 10 - * direction[mouse_y_invert] * FRACUNIT); -} - -static double CalcMouseSide(int mousex) -{ - if (!mouse_sensitivity_strafe) - return 0.0; - - return (I_AccelerateMouse(mousex) * (mouse_sensitivity_strafe + 5) * 2 / 10); -} - -static double CalcMouseVert(int mousey) -{ - if (!mouse_sensitivity_y) - return 0.0; - - return (I_AccelerateMouse(mousey) * (mouse_sensitivity_y + 5) / 10); -} - -// -// ApplyQuickstartCache -// When recording a demo and the map is reloaded, cached input from a circular -// buffer can be applied prior to the screen wipe. Adapted from DSDA-Doom. -// - -static int quickstart_cache_tics; -static boolean quickstart_queued; -static float axis_turn_tic; -static int mousex_tic; - -static void ClearQuickstartTic(void) -{ - axis_turn_tic = 0.0f; - mousex_tic = 0; -} - -static void ApplyQuickstartCache(ticcmd_t *cmd, boolean strafe) -{ - static float axis_turn_cache[TICRATE]; - static int mousex_cache[TICRATE]; - static short angleturn_cache[TICRATE]; - static int index; - - if (quickstart_cache_tics < 1) - { - return; - } - - if (quickstart_queued) - { - axes[AXIS_TURN] = 0.0f; - mousex = 0; - - if (strafe) - { - for (int i = 0; i < quickstart_cache_tics; i++) - { - axes[AXIS_TURN] += axis_turn_cache[i]; - mousex += mousex_cache[i]; - } - - cmd->angleturn = 0; - localview.rawangle = 0.0; - } - else - { - short result = 0; - - for (int i = 0; i < quickstart_cache_tics; i++) - { - result += angleturn_cache[i]; - } - - cmd->angleturn = CarryAngleTic(result); - localview.rawangle = cmd->angleturn; - } - - memset(axis_turn_cache, 0, sizeof(axis_turn_cache)); - memset(mousex_cache, 0, sizeof(mousex_cache)); - memset(angleturn_cache, 0, sizeof(angleturn_cache)); - index = 0; - - quickstart_queued = false; - } - else - { - axis_turn_cache[index] = axis_turn_tic; - mousex_cache[index] = mousex_tic; - angleturn_cache[index] = cmd->angleturn; - index = (index + 1) % quickstart_cache_tics; - } -} - void G_PrepTiccmd(void) { const boolean strafe = M_InputGameActive(input_strafe); @@ -661,21 +389,18 @@ void G_PrepTiccmd(void) if (I_UseController() && I_CalcControllerAxes()) { - D_UpdateDeltaTics(); - + G_UpdateDeltaTics(); axis_turn_tic = axes[AXIS_TURN]; if (axes[AXIS_TURN] && !strafe) { - localview.rawangle -= CalcControllerAngle() * deltatics; - cmd->angleturn = CarryAngle(localview.rawangle); + cmd->angleturn = G_CalcControllerAngle(); axes[AXIS_TURN] = 0.0f; } if (axes[AXIS_LOOK] && padlook) { - localview.rawpitch -= CalcControllerPitch() * deltatics; - cmd->pitch = CarryPitch(localview.rawpitch); + cmd->pitch = G_CalcControllerPitch(); axes[AXIS_LOOK] = 0.0f; } } @@ -684,15 +409,13 @@ void G_PrepTiccmd(void) if (mousex && !strafe) { - localview.rawangle -= CalcMouseAngle(mousex); - cmd->angleturn = CarryAngle(localview.rawangle); + cmd->angleturn = G_CalcMouseAngle(); mousex = 0; } if (mousey && mouselook) { - localview.rawpitch += CalcMousePitch(mousey); - cmd->pitch = CarryPitch(localview.rawpitch); + cmd->pitch = G_CalcMousePitch(); mousey = 0; } } @@ -728,7 +451,7 @@ void G_BuildTiccmd(ticcmd_t* cmd) memcpy(cmd, &basecmd, sizeof(*cmd)); memset(&basecmd, 0, sizeof(basecmd)); - ApplyQuickstartCache(cmd, strafe); + G_ApplyQuickstartCache(cmd, strafe); cmd->consistancy = consistancy[consoleplayer][maketic%BACKUPTICS]; @@ -787,17 +510,17 @@ void G_BuildTiccmd(ticcmd_t* cmd) { if (axes[AXIS_TURN] && strafe && !cmd->angleturn) { - side += CalcControllerSideTurn(speed); + side += G_CalcControllerSideTurn(speed); } if (axes[AXIS_STRAFE]) { - side += CalcControllerSideStrafe(speed); + side += G_CalcControllerSideStrafe(speed); } if (axes[AXIS_FORWARD]) { - forward -= CalcControllerForward(speed); + forward -= G_CalcControllerForward(speed); } } @@ -805,23 +528,19 @@ void G_BuildTiccmd(ticcmd_t* cmd) if (mousex && strafe && !cmd->angleturn) { - const double mouseside = CalcMouseSide(mousex); - side += CarryMouseSide(mouseside); + side += G_CalcMouseSide(); } if (mousey && !mouselook && !novert) { - const double mousevert = CalcMouseVert(mousey); - forward += CarryMouseVert(mousevert); + forward += G_CalcMouseVert(); } // Update/reset if (angle) { - const short old_angleturn = cmd->angleturn; - cmd->angleturn = CarryAngleTic(localview.rawangle + angle); - cmd->ticangleturn = cmd->angleturn - old_angleturn; + G_UpdateTicAngleTurn(cmd, angle); } if (forward > MAXPLMOVE) @@ -836,11 +555,11 @@ void G_BuildTiccmd(ticcmd_t* cmd) cmd->forwardmove = forward; cmd->sidemove = side; - ClearQuickstartTic(); + G_ClearQuickstartTic(); I_ResetControllerAxes(); mousex = mousey = 0; - UpdateLocalView(); - prevcarry = carry; + G_UpdateLocalView(); + G_UpdateCarry(); // Buttons @@ -991,12 +710,11 @@ void G_BuildTiccmd(ticcmd_t* cmd) void G_ClearInput(void) { - ClearQuickstartTic(); + G_ClearQuickstartTic(); I_ResetControllerLevel(); mousex = mousey = 0; - memset(&localview, 0, sizeof(localview)); - memset(&carry, 0, sizeof(carry)); - memset(&prevcarry, 0, sizeof(prevcarry)); + G_ClearLocalView(); + G_ClearCarry(); memset(&basecmd, 0, sizeof(basecmd)); } @@ -4637,6 +4355,10 @@ void G_BindGameInputVariables(void) "Horizontal mouse sensitivity for strafing"); BIND_NUM_GENERAL(mouse_sensitivity_y_look, 5, 0, UL, "Vertical mouse sensitivity for looking"); + BIND_NUM_GENERAL(mouse_acceleration, 10, 0, 40, + "Mouse acceleration (0 = 1.0; 40 = 5.0)"); + BIND_NUM(mouse_acceleration_threshold, 10, 0, 32, + "Mouse acceleration threshold"); BIND_BOOL_GENERAL(mouse_y_invert, false, "Invert vertical mouse axis"); BIND_BOOL_GENERAL(dclick_use, true, "Double-click acts as use-button"); BIND_BOOL(novert, true, "Disable vertical mouse movement"); diff --git a/src/g_game.h b/src/g_game.h index cabef24b..6d0df3a8 100644 --- a/src/g_game.h +++ b/src/g_game.h @@ -20,6 +20,7 @@ #include "doomdef.h" #include "doomstat.h" #include "doomtype.h" +#include "g_input.h" #include "m_fixed.h" struct event_s; @@ -53,8 +54,6 @@ void G_SecretExitLevel(void); void G_WorldDone(void); void G_Ticker(void); void G_ScreenShot(void); -void G_UpdateSideMove(void); -void G_UpdateAngleFunctions(void); void G_ReloadDefaults(boolean keep_demover); // killough 3/1/98: loads game defaults char *G_SaveGameName(int); // killough 3/22/98: sets savegame filename char *G_MBFSaveGameName(int); // MBF savegame filename @@ -104,12 +103,25 @@ extern int key_escape; extern int key_enter; extern int key_help; extern boolean autorun; // always running? // phares +extern boolean autostrafe50; extern boolean novert; extern boolean mouselook; extern boolean padlook; -extern fixed_t *forwardmove; +extern int mouse_sensitivity; +extern int mouse_sensitivity_y; +extern int mouse_sensitivity_strafe; +extern int mouse_sensitivity_y_look; +extern boolean mouse_y_invert; +extern int mouse_acceleration; +extern int mouse_acceleration_threshold; +extern int mousex; +extern int mousey; + +extern fixed_t forwardmove[2]; +extern fixed_t default_sidemove[2]; extern fixed_t *sidemove; +extern const fixed_t angleturn[3]; extern int default_skill; //jff 3/24/98 default skill extern boolean haswolflevels; //jff 4/18/98 wolf levels present diff --git a/src/g_input.c b/src/g_input.c new file mode 100644 index 00000000..c723f9ba --- /dev/null +++ b/src/g_input.c @@ -0,0 +1,456 @@ +// +// Copyright(C) 2024 ceski +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Game Input Utility Functions +// + +#include +#include + +#include "d_main.h" +#include "g_game.h" +#include "i_gamepad.h" +#include "i_timer.h" +#include "i_video.h" +#include "p_mobj.h" +#include "r_state.h" + +// +// Local View +// + +void (*G_UpdateLocalView)(void); + +void G_ClearLocalView(void) +{ + memset(&localview, 0, sizeof(localview)); +} + +static void UpdateLocalView_FakeLongTics(void) +{ + localview.angle -= localview.angleoffset << FRACBITS; + localview.rawangle -= localview.angleoffset; + localview.angleoffset = 0; + localview.pitch = 0; + localview.rawpitch = 0.0; +} + +// +// Side Movement +// + +static int (*RoundSide)(double side); + +static int RoundSide_Strict(double side) +{ + return lround(side * 0.5) * 2; // Even values only. +} + +static int RoundSide_Full(double side) +{ + return lround(side); +} + +void G_UpdateSideMove(void) +{ + if (strictmode || (netgame && !solonet)) + { + RoundSide = RoundSide_Strict; + sidemove = default_sidemove; + } + else + { + RoundSide = RoundSide_Full; + sidemove = autostrafe50 ? forwardmove : default_sidemove; + } +} + +// +// Error Accumulation +// + +// Round to nearest 256 for single byte turning. From Chocolate Doom. +#define BYTE_TURN(x) (((x) + 128) & 0xFF00) + +typedef struct +{ + double angle; + double pitch; + double side; + double vert; +} carry_t; + +static carry_t prevcarry, carry; +static short (*CarryAngleTic)(double angle); +static short (*CarryAngle)(double angle); + +void G_UpdateCarry(void) +{ + prevcarry = carry; +} + +void G_ClearCarry(void) +{ + memset(&prevcarry, 0, sizeof(prevcarry)); + memset(&carry, 0, sizeof(carry)); +} + +static int CarryError(double value, const double *prevcarry, double *carry) +{ + const double desired = value + *prevcarry; + const int actual = lround(desired); + *carry = desired - actual; + return actual; +} + +static short CarryAngleTic_Full(double angle) +{ + return CarryError(angle, &prevcarry.angle, &carry.angle); +} + +static short CarryAngle_Full(double angle) +{ + const short fullres = CarryAngleTic_Full(angle); + localview.angle = fullres << FRACBITS; + return fullres; +} + +static short CarryAngle_FakeLongTics(double angle) +{ + return (localview.angleoffset = BYTE_TURN(CarryAngle_Full(angle))); +} + +static short CarryAngleTic_LowRes(double angle) +{ + const double fullres = angle + prevcarry.angle; + const short lowres = BYTE_TURN((short)lround(fullres)); + carry.angle = fullres - lowres; + return lowres; +} + +static short CarryAngle_LowRes(double angle) +{ + const short lowres = CarryAngleTic_LowRes(angle); + localview.angle = lowres << FRACBITS; + return lowres; +} + +void G_UpdateAngleFunctions(void) +{ + CarryAngleTic = lowres_turn ? CarryAngleTic_LowRes : CarryAngleTic_Full; + CarryAngle = CarryAngleTic; + G_UpdateLocalView = G_ClearLocalView; + + if (raw_input && (!netgame || solonet)) + { + if (lowres_turn && fake_longtics) + { + CarryAngle = CarryAngle_FakeLongTics; + G_UpdateLocalView = UpdateLocalView_FakeLongTics; + } + else if (uncapped) + { + CarryAngle = lowres_turn ? CarryAngle_LowRes : CarryAngle_Full; + } + } +} + +static int CarryPitch(double pitch) +{ + return (localview.pitch = + CarryError(pitch, &prevcarry.pitch, &carry.pitch)); +} + +static int CarrySide(double side) +{ + const double desired = side + prevcarry.side; + const int actual = RoundSide(desired); + carry.side = desired - actual; + return actual; +} + +static int CarryVert(double vert) +{ + return CarryError(vert, &prevcarry.vert, &carry.vert); +} + +// +// Gamepad +// + +static const int direction[] = {1, -1}; +static double deltatics; + +void G_UpdateDeltaTics(void) +{ + if (uncapped && raw_input) + { + static uint64_t last_time; + const uint64_t current_time = I_GetTimeUS(); + + if (input_ready) + { + const uint64_t delta_time = current_time - last_time; + deltatics = (double)delta_time * TICRATE / 1000000.0; + deltatics = BETWEEN(0.0, 1.0, deltatics); + } + else + { + deltatics = 0.0; + } + + last_time = current_time; + } + else + { + deltatics = 1.0; + } +} + +short G_CalcControllerAngle(void) +{ + localview.rawangle -= (deltatics * axes[AXIS_TURN] * angleturn[1] + * direction[joy_invert_turn]); + return CarryAngle(localview.rawangle); +} + +int G_CalcControllerPitch(void) +{ + localview.rawpitch -= (deltatics * axes[AXIS_LOOK] * angleturn[1] + * direction[joy_invert_look] * FRACUNIT); + return CarryPitch(localview.rawpitch); +} + +int G_CalcControllerSideTurn(int speed) +{ + const int side = RoundSide(axes[AXIS_TURN] * forwardmove[speed] + * direction[joy_invert_turn]); + return BETWEEN(-forwardmove[speed], forwardmove[speed], side); +} + +int G_CalcControllerSideStrafe(int speed) +{ + const int side = RoundSide(axes[AXIS_STRAFE] * forwardmove[speed] + * direction[joy_invert_strafe]); + return BETWEEN(-sidemove[speed], sidemove[speed], side); +} + +int G_CalcControllerForward(int speed) +{ + const int forward = lroundf(axes[AXIS_FORWARD] * forwardmove[speed] + * direction[joy_invert_forward]); + return BETWEEN(-forwardmove[speed], forwardmove[speed], forward); +} + +// +// Mouse +// + +static double (*AccelerateMouse)(int val); + +static double AccelerateMouse_Threshold(int val) +{ + if (val < 0) + { + return -AccelerateMouse_Threshold(-val); + } + + if (val > mouse_acceleration_threshold) + { + return ((double)(val - mouse_acceleration_threshold) + * (mouse_acceleration + 10) / 10 + + mouse_acceleration_threshold); + } + else + { + return val; + } +} + +static double AccelerateMouse_NoThreshold(int val) +{ + return ((double)val * (mouse_acceleration + 10) / 10); +} + +static double AccelerateMouse_Skip(int val) +{ + return val; +} + +void G_UpdateAccelerateMouse(void) +{ + if (mouse_acceleration) + { + AccelerateMouse = raw_input ? AccelerateMouse_NoThreshold + : AccelerateMouse_Threshold; + } + else + { + AccelerateMouse = AccelerateMouse_Skip; + } +} + +short G_CalcMouseAngle(void) +{ + if (mouse_sensitivity) + { + localview.rawangle -= (AccelerateMouse(mousex) + * (mouse_sensitivity + 5) * 8 / 10); + return CarryAngle(localview.rawangle); + } + else + { + return 0; + } +} + +int G_CalcMousePitch(void) +{ + if (mouse_sensitivity_y_look) + { + localview.rawpitch += (AccelerateMouse(mousey) + * (mouse_sensitivity_y_look + 5) * 8 / 10 + * direction[mouse_y_invert] * FRACUNIT); + return CarryPitch(localview.rawpitch); + } + else + { + return 0; + } +} + +int G_CalcMouseSide(void) +{ + if (mouse_sensitivity_strafe) + { + const double side = (AccelerateMouse(mousex) + * (mouse_sensitivity_strafe + 5) * 2 / 10); + return CarrySide(side); + } + else + { + return 0; + } +} + +int G_CalcMouseVert(void) +{ + if (mouse_sensitivity_y) + { + const double vert = (AccelerateMouse(mousey) + * (mouse_sensitivity_y + 5) / 10); + return CarryVert(vert); + } + else + { + return 0; + } +} + +// +// Composite Turn +// + +static angle_t saved_angle; + +void G_SavePlayerAngle(const player_t *player) +{ + saved_angle = player->mo->angle; +} + +void G_AddToTicAngle(player_t *player) +{ + player->ticangle += player->mo->angle - saved_angle; +} + +void G_UpdateTicAngleTurn(ticcmd_t *cmd, int angle) +{ + const short old_angleturn = cmd->angleturn; + cmd->angleturn = CarryAngleTic(localview.rawangle + angle); + cmd->ticangleturn = cmd->angleturn - old_angleturn; +} + +// +// Quickstart Cache +// When recording a demo and the map is reloaded, cached input from a circular +// buffer can be applied prior to the screen wipe. Adapted from DSDA-Doom. +// + +int quickstart_cache_tics; +boolean quickstart_queued; +float axis_turn_tic; +int mousex_tic; + +void G_ClearQuickstartTic(void) +{ + axis_turn_tic = 0.0f; + mousex_tic = 0; +} + +void G_ApplyQuickstartCache(ticcmd_t *cmd, boolean strafe) +{ + static float axis_turn_cache[TICRATE]; + static int mousex_cache[TICRATE]; + static short angleturn_cache[TICRATE]; + static int index; + + if (quickstart_cache_tics < 1) + { + return; + } + + if (quickstart_queued) + { + axes[AXIS_TURN] = 0.0f; + mousex = 0; + + if (strafe) + { + for (int i = 0; i < quickstart_cache_tics; i++) + { + axes[AXIS_TURN] += axis_turn_cache[i]; + mousex += mousex_cache[i]; + } + + cmd->angleturn = 0; + localview.rawangle = 0.0; + } + else + { + short result = 0; + + for (int i = 0; i < quickstart_cache_tics; i++) + { + result += angleturn_cache[i]; + } + + cmd->angleturn = CarryAngleTic(result); + localview.rawangle = cmd->angleturn; + } + + memset(axis_turn_cache, 0, sizeof(axis_turn_cache)); + memset(mousex_cache, 0, sizeof(mousex_cache)); + memset(angleturn_cache, 0, sizeof(angleturn_cache)); + index = 0; + + quickstart_queued = false; + } + else + { + axis_turn_cache[index] = axis_turn_tic; + mousex_cache[index] = mousex_tic; + angleturn_cache[index] = cmd->angleturn; + index = (index + 1) % quickstart_cache_tics; + } +} diff --git a/src/g_input.h b/src/g_input.h new file mode 100644 index 00000000..cfefd23a --- /dev/null +++ b/src/g_input.h @@ -0,0 +1,73 @@ +// +// Copyright(C) 2024 ceski +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// DESCRIPTION: +// Game Input Utility Functions +// + +#ifndef __G_INPUT__ +#define __G_INPUT__ + +#include "doomtype.h" + +struct player_s; +struct ticcmd_s; + +// Local View + +extern void (*G_UpdateLocalView)(void); +void G_ClearLocalView(void); + +// Side Movement + +void G_UpdateSideMove(void); + +// Error Accumulation + +void G_UpdateCarry(void); +void G_ClearCarry(void); +void G_UpdateAngleFunctions(void); + +// Gamepad + +void G_UpdateDeltaTics(void); +short G_CalcControllerAngle(void); +int G_CalcControllerPitch(void); +int G_CalcControllerSideTurn(int speed); +int G_CalcControllerSideStrafe(int speed); +int G_CalcControllerForward(int speed); + +// Mouse + +void G_UpdateAccelerateMouse(void); +short G_CalcMouseAngle(void); +int G_CalcMousePitch(void); +int G_CalcMouseSide(void); +int G_CalcMouseVert(void); + +// Composite Turn + +void G_SavePlayerAngle(const struct player_s *player); +void G_AddToTicAngle(struct player_s *player); +void G_UpdateTicAngleTurn(struct ticcmd_s *cmd, int angle); + +// Quickstart Cache + +extern int quickstart_cache_tics; +extern boolean quickstart_queued; +extern float axis_turn_tic; +extern int mousex_tic; +void G_ClearQuickstartTic(void); +void G_ApplyQuickstartCache(struct ticcmd_s *cmd, boolean strafe); + +#endif diff --git a/src/i_input.c b/src/i_input.c index 0d65145c..8645ed3e 100644 --- a/src/i_input.c +++ b/src/i_input.c @@ -24,7 +24,6 @@ #include "i_printf.h" #include "i_system.h" #include "m_config.h" -#include "r_main.h" #define AXIS_BUTTON_DEADZONE (SDL_JOYSTICK_AXIS_MAX / 3) @@ -463,59 +462,6 @@ void I_DelayEvent(void) // // Read the change in mouse state to generate mouse motion events // -// This is to combine all mouse movement for a tic into one mouse -// motion event. - -// The mouse input values are input directly to the game, but when the values -// exceed the value of mouse_acceleration_threshold, they are multiplied by -// mouse_acceleration to increase the speed. - -static int mouse_acceleration; -static int mouse_acceleration_threshold; - -static double AccelerateMouse_Thresh(int val) -{ - if (val < 0) - { - return -AccelerateMouse_Thresh(-val); - } - - if (val > mouse_acceleration_threshold) - { - return ((double)(val - mouse_acceleration_threshold) - * (mouse_acceleration + 10) / 10 - + mouse_acceleration_threshold); - } - else - { - return val; - } -} - -static double AccelerateMouse_NoThresh(int val) -{ - return ((double)val * (mouse_acceleration + 10) / 10); -} - -static double AccelerateMouse_Skip(int val) -{ - return val; -} - -double (*I_AccelerateMouse)(int val) = AccelerateMouse_NoThresh; - -void I_UpdateAccelerateMouse(void) -{ - if (mouse_acceleration) - { - I_AccelerateMouse = - raw_input ? AccelerateMouse_NoThresh : AccelerateMouse_Thresh; - } - else - { - I_AccelerateMouse = AccelerateMouse_Skip; - } -} void I_ReadMouse(void) { @@ -593,11 +539,3 @@ void I_HandleKeyboardEvent(SDL_Event *sdlevent) break; } } - -void I_BindInputVariables(void) -{ - BIND_NUM_GENERAL(mouse_acceleration, 10, 0, 40, - "Mouse acceleration (0 = 1.0; 40 = 5.0)"); - BIND_NUM(mouse_acceleration_threshold, 10, 0, 32, - "Mouse acceleration threshold"); -} diff --git a/src/i_input.h b/src/i_input.h index 885dd0da..8a950d42 100644 --- a/src/i_input.h +++ b/src/i_input.h @@ -26,8 +26,6 @@ void I_InitController(void); void I_OpenController(int which); void I_CloseController(int which); -extern double (*I_AccelerateMouse)(int val); -void I_UpdateAccelerateMouse(void); void I_ReadMouse(void); void I_UpdateJoystick(boolean axis_buttons); void I_UpdateJoystickMenu(void); @@ -37,6 +35,4 @@ void I_HandleJoystickEvent(SDL_Event *sdlevent); void I_HandleKeyboardEvent(SDL_Event *sdlevent); void I_HandleMouseEvent(SDL_Event *sdlevent); -void I_BindInputVariables(void); - #endif diff --git a/src/m_config.c b/src/m_config.c index 8a1ad99a..0079346b 100644 --- a/src/m_config.c +++ b/src/m_config.c @@ -37,7 +37,6 @@ #include "hu_stuff.h" #include "i_gamepad.h" #include "i_printf.h" -#include "i_input.h" #include "i_sound.h" #include "i_system.h" #include "i_video.h" @@ -117,7 +116,6 @@ void M_InitConfig(void) G_BindGameVariables(); G_BindGameInputVariables(); - I_BindInputVariables(); I_BindGamepadVariables(); M_BindInputVariables(); diff --git a/src/mn_setup.c b/src/mn_setup.c index 25eaae74..7c13225b 100644 --- a/src/mn_setup.c +++ b/src/mn_setup.c @@ -25,7 +25,6 @@ #include "hu_lib.h" #include "hu_stuff.h" #include "i_gamepad.h" -#include "i_input.h" #include "i_oalsound.h" #include "i_sound.h" #include "i_timer.h" @@ -2158,7 +2157,7 @@ static setup_menu_t gen_settings3[] = { MI_GAP, {"Mouse acceleration", S_THERMO, CNTR_X, M_THRM_SPC, {"mouse_acceleration"}, - m_null, input_null, str_mouse_accel, I_UpdateAccelerateMouse}, + m_null, input_null, str_mouse_accel, G_UpdateAccelerateMouse}, MI_END }; diff --git a/src/p_pspr.c b/src/p_pspr.c index d5fe0636..5944ce58 100644 --- a/src/p_pspr.c +++ b/src/p_pspr.c @@ -22,6 +22,7 @@ #include "d_items.h" #include "d_player.h" #include "doomstat.h" +#include "g_input.h" #include "i_printf.h" #include "i_video.h" // uncapped #include "m_random.h" @@ -649,18 +650,6 @@ void A_GunFlash(player_t *player, pspdef_t *psp) // WEAPON ATTACKS // -static angle_t saved_angle; - -static void SavePlayerAngle(player_t *player) -{ - saved_angle = player->mo->angle; -} - -static void AddToTicAngle(player_t *player) -{ - player->ticangle += player->mo->angle - saved_angle; -} - // // A_Punch // @@ -697,10 +686,10 @@ void A_Punch(player_t *player, pspdef_t *psp) // turn to face target - SavePlayerAngle(player); + G_SavePlayerAngle(player); player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, linetarget->x, linetarget->y); - AddToTicAngle(player); + G_AddToTicAngle(player); } // @@ -743,7 +732,7 @@ void A_Saw(player_t *player, pspdef_t *psp) angle = R_PointToAngle2(player->mo->x, player->mo->y, linetarget->x, linetarget->y); - SavePlayerAngle(player); + G_SavePlayerAngle(player); if (angle - player->mo->angle > ANG180) if ((signed int) (angle - player->mo->angle) < -ANG90/20) player->mo->angle = angle + ANG90/21; @@ -754,7 +743,7 @@ void A_Saw(player_t *player, pspdef_t *psp) player->mo->angle = angle - ANG90/21; else player->mo->angle += ANG90/20; - AddToTicAngle(player); + G_AddToTicAngle(player); player->mo->flags |= MF_JUSTATTACKED; } @@ -1318,9 +1307,9 @@ void A_WeaponMeleeAttack(player_t *player, pspdef_t *psp) S_StartSound(player->mo, hitsound); // turn to face target - SavePlayerAngle(player); + G_SavePlayerAngle(player); player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, linetarget->x, linetarget->y); - AddToTicAngle(player); + G_AddToTicAngle(player); } // diff --git a/src/r_main.c b/src/r_main.c index b62b077d..533b8bc5 100644 --- a/src/r_main.c +++ b/src/r_main.c @@ -70,7 +70,6 @@ fixed_t skyiscale; fixed_t viewx, viewy, viewz; angle_t viewangle; localview_t localview; -double deltatics; boolean raw_input; fixed_t viewcos, viewsin; player_t *viewplayer; diff --git a/src/r_main.h b/src/r_main.h index 13ef94eb..36e45672 100644 --- a/src/r_main.h +++ b/src/r_main.h @@ -153,9 +153,6 @@ inline static angle_t LerpAngle(angle_t oangle, angle_t nangle) } } -extern double deltatics; -extern boolean raw_input; - extern int autodetect_hom; #endif diff --git a/src/r_state.h b/src/r_state.h index 1dc7991c..bb3915da 100644 --- a/src/r_state.h +++ b/src/r_state.h @@ -106,6 +106,7 @@ extern fixed_t viewy; extern fixed_t viewz; extern angle_t viewangle; extern localview_t localview; // View orientation offsets for current frame. +extern boolean raw_input; extern struct player_s *viewplayer; extern angle_t clipangle; extern angle_t vx_clipangle;