foxygit / doom Log in
commit 3ec6cf25a28526d27b19a21dd5c08fc89c3350c5
Author:     Michael Day <contact@michaelcday.com>
AuthorDate: Mon Oct 16 07:50:01 2023 -0400
Commit:     Michael Day <contact@michaelcday.com>
CommitDate: Wed Oct 25 22:28:54 2023 -0400

    Introduce gamepad analog control
---
 src/doom/g_game.c    | 78 ++++++++++++++++++++++++++++++++++++++++------------
 src/i_joystick.c     | 15 +++++++++-
 src/i_joystick.h     |  5 ++++
 src/m_config.c       | 24 ++++++++++++++++
 src/setup/joystick.c | 54 ++++++++++++++++++++++++++++++------
 5 files changed, 150 insertions(+), 26 deletions(-)

diff --git a/src/doom/g_game.c b/src/doom/g_game.c
index 91e97d73..b07ff570 100644
--- a/src/doom/g_game.c
+++ b/src/doom/g_game.c
@@ -35,6 +35,7 @@
 #include "m_misc.h"
 #include "m_menu.h"
 #include "m_random.h"
+#include "i_joystick.h"
 #include "i_system.h"
 #include "i_timer.h"
 #include "i_input.h"
@@ -380,11 +381,20 @@ void G_BuildTiccmd (ticcmd_t* cmd, int maketic)
 	    //	fprintf(stderr, "strafe left\n");
 	    side -= sidemove[speed];
 	}
-	if (joyxmove > 0)
-	    side += sidemove[speed];
-	if (joyxmove < 0)
-	    side -= sidemove[speed];
-
+        if (use_analog && joyxmove)
+        {
+            joyxmove = joyxmove * joystick_move_sensitivity / 10;
+            joyxmove = (joyxmove > FRACUNIT) ? FRACUNIT : joyxmove;
+            joyxmove = (joyxmove < -FRACUNIT) ? -FRACUNIT : joyxmove;
+            side += FixedMul(sidemove[speed], joyxmove);
+        }
+        else
+        {
+            if (joyxmove > 0)
+                side += sidemove[speed];
+            if (joyxmove < 0)
+                side -= sidemove[speed];
+        }
     }
     else
     {
@@ -392,10 +402,21 @@ void G_BuildTiccmd (ticcmd_t* cmd, int maketic)
 	    cmd->angleturn -= angleturn[tspeed];
 	if (gamekeydown[key_left] || mousebuttons[mousebturnleft])
 	    cmd->angleturn += angleturn[tspeed];
-	if (joyxmove > 0)
-	    cmd->angleturn -= angleturn[tspeed];
-	if (joyxmove < 0)
-	    cmd->angleturn += angleturn[tspeed];
+        if (use_analog && joyxmove)
+        {
+            // Cubic response curve allows for finer control when stick
+            // deflection is small.
+            joyxmove = FixedMul(FixedMul(joyxmove, joyxmove), joyxmove);
+            joyxmove = joyxmove * joystick_turn_sensitivity / 10;
+            cmd->angleturn -= FixedMul(angleturn[1], joyxmove);
+        }
+        else
+        {
+            if (joyxmove > 0)
+                cmd->angleturn -= angleturn[tspeed];
+            if (joyxmove < 0)
+                cmd->angleturn += angleturn[tspeed];
+        }
     }

     if (gamekeydown[key_up])
@@ -409,27 +430,50 @@ void G_BuildTiccmd (ticcmd_t* cmd, int maketic)
 	forward -= forwardmove[speed];
     }

-    if (joyymove < 0)
-        forward += forwardmove[speed];
-    if (joyymove > 0)
-        forward -= forwardmove[speed];
+    if (use_analog && joyymove)
+    {
+        joyymove = joyymove * joystick_move_sensitivity / 10;
+        joyymove = (joyymove > FRACUNIT) ? FRACUNIT : joyymove;
+        joyymove = (joyymove < -FRACUNIT) ? -FRACUNIT : joyymove;
+        forward -= FixedMul(forwardmove[speed], joyymove);
+    }
+    else
+    {
+        if (joyymove < 0)
+            forward += forwardmove[speed];
+        if (joyymove > 0)
+            forward -= forwardmove[speed];
+    }

     if (gamekeydown[key_strafeleft]
      || joybuttons[joybstrafeleft]
-     || mousebuttons[mousebstrafeleft]
-     || joystrafemove < 0)
+     || mousebuttons[mousebstrafeleft])
     {
         side -= sidemove[speed];
     }

     if (gamekeydown[key_straferight]
      || joybuttons[joybstraferight]
-     || mousebuttons[mousebstraferight]
-     || joystrafemove > 0)
+     || mousebuttons[mousebstraferight])
     {
         side += sidemove[speed];
     }

+    if (use_analog && joystrafemove)
+    {
+        joystrafemove = joystrafemove * joystick_move_sensitivity / 10;
+        joystrafemove = (joystrafemove > FRACUNIT) ? FRACUNIT : joystrafemove;
+        joystrafemove = (joystrafemove < -FRACUNIT) ? -FRACUNIT : joystrafemove;
+        side += FixedMul(sidemove[speed], joystrafemove);
+    }
+    else
+    {
+        if (joystrafemove < 0)
+            side -= sidemove[speed];
+        if (joystrafemove > 0)
+            side += sidemove[speed];
+    }
+
     // buttons
     cmd->chatchar = HU_dequeueChatChar();

diff --git a/src/i_joystick.c b/src/i_joystick.c
index abf2177c..403e5e9b 100644
--- a/src/i_joystick.c
+++ b/src/i_joystick.c
@@ -30,6 +30,7 @@
 #include "i_system.h"

 #include "m_config.h"
+#include "m_fixed.h"
 #include "m_misc.h"

 static SDL_GameController *gamepad = NULL;
@@ -80,6 +81,12 @@ static int joystick_y_dead_zone = 33;
 static int joystick_strafe_dead_zone = 33;
 static int joystick_look_dead_zone = 33;

+int use_analog = 0;
+
+int joystick_turn_sensitivity = 10;
+int joystick_move_sensitivity = 10;
+int joystick_look_sensitivity = 10;
+
 // Virtual to physical button joystick button mapping. By default this
 // is a straight mapping.
 static int joystick_physical_buttons[NUM_VIRTUAL_BUTTONS] = {
@@ -294,7 +301,7 @@ static int GetAxisStateGamepad(int axis, int invert, int dead_zone)

     if (result < dead_zone && result > -dead_zone)
     {
-        result = 0;
+        return 0;
     }

     if (invert)
@@ -302,6 +309,8 @@ static int GetAxisStateGamepad(int axis, int invert, int dead_zone)
         result = -result;
     }

+    result *= FRACUNIT / 32768; // Want FXP number between -1 and 1
+
     return result;
 }

@@ -667,6 +676,10 @@ void I_BindJoystickVariables(void)
     M_BindIntVariable("joystick_y_dead_zone", &joystick_y_dead_zone);
     M_BindIntVariable("joystick_strafe_dead_zone", &joystick_strafe_dead_zone);
     M_BindIntVariable("joystick_look_dead_zone", &joystick_look_dead_zone);
+    M_BindIntVariable("use_analog", &use_analog);
+    M_BindIntVariable("joystick_turn_sensitivity", &joystick_turn_sensitivity);
+    M_BindIntVariable("joystick_move_sensitivity", &joystick_move_sensitivity);
+    M_BindIntVariable("joystick_look_sensitivity", &joystick_look_sensitivity);

     for (i = 0; i < NUM_VIRTUAL_BUTTONS; ++i)
     {
diff --git a/src/i_joystick.h b/src/i_joystick.h
index b99b8d24..9831ee1c 100644
--- a/src/i_joystick.h
+++ b/src/i_joystick.h
@@ -82,6 +82,11 @@ enum
     GAMEPAD_BUTTON_MAX
 };

+extern int use_analog;
+extern int joystick_turn_sensitivity;
+extern int joystick_move_sensitivity;
+extern int joystick_look_sensitivity;
+
 void I_InitJoystick(void);
 void I_ShutdownJoystick(void);
 void I_UpdateJoystick(void);
diff --git a/src/m_config.c b/src/m_config.c
index 7c3e0e8a..57024b0f 100644
--- a/src/m_config.c
+++ b/src/m_config.c
@@ -1242,6 +1242,12 @@ static default_t extra_defaults_list[] =

     CONFIG_VARIABLE_INT(joystick_index),

+    //!
+    // If non-zero, use analog movement when playing with a gamepad.
+    //
+
+    CONFIG_VARIABLE_INT(use_analog),
+
     //!
     // Joystick axis to use to for horizontal (X) movement.
     //
@@ -1254,6 +1260,12 @@ static default_t extra_defaults_list[] =

     CONFIG_VARIABLE_INT(joystick_x_invert),

+    //!
+    // Joystick turn analog sensitivity, specified as a value between 0 and 20.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_turn_sensitivity),
+
     //!
     // Joystick axis to use to for vertical (Y) movement.
     //
@@ -1279,6 +1291,12 @@ static default_t extra_defaults_list[] =

     CONFIG_VARIABLE_INT(joystick_strafe_invert),

+    //!
+    // Joystick move and strafe analog sensitivity, specified as a value
+    // between 0 and 20.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_move_sensitivity),
     //!
     // Joystick axis to use to for looking up and down.
     //
@@ -1292,6 +1310,12 @@ static default_t extra_defaults_list[] =

     CONFIG_VARIABLE_INT(joystick_look_invert),

+    //!
+    // Joystick look analog sensitivity, specified as a value between 0 and 20.
+    //
+
+    CONFIG_VARIABLE_INT(joystick_look_sensitivity),
+
     //!
     // The physical joystick button that corresponds to joystick
     // virtual button #0.
diff --git a/src/setup/joystick.c b/src/setup/joystick.c
index 25bb0bdd..abb007f7 100644
--- a/src/setup/joystick.c
+++ b/src/setup/joystick.c
@@ -92,6 +92,12 @@ static int joystick_y_dead_zone = 33;
 static int joystick_strafe_dead_zone = 33;
 static int joystick_look_dead_zone = 33;

+int use_analog = 0;
+
+int joystick_turn_sensitivity = 10;
+int joystick_move_sensitivity = 10;
+int joystick_look_sensitivity = 10;
+
 // Virtual to physical mapping.
 int joystick_physical_buttons[NUM_VIRTUAL_BUTTONS] = {
     0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
@@ -1002,6 +1008,7 @@ static int CalibrationEventCallback(SDL_Event *event, void *user_data)
     // joystick is being configured and which button the user is pressing.
     usejoystick = 1;
     use_gamepad = 0;
+    use_analog = 0;
     gamepad_type = SDL_CONTROLLER_TYPE_UNKNOWN;
     calibrate_button = event->jbutton.button;

@@ -1133,6 +1140,34 @@ static void SwapLRSticks(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
     }
 }

+static void AdjustAnalog(TXT_UNCAST_ARG(widget), TXT_UNCAST_ARG(unused))
+{
+    txt_window_t *window;
+
+    window = TXT_NewWindow("Analog Settings");
+    TXT_SetTableColumns(window, 2);
+    TXT_SetColumnWidths(window, 10, 6);
+    TXT_AddWidgets(window,
+        TXT_NewCheckBox("Use analog controls", &use_analog),
+        TXT_NewSeparator("Sensitivity"),
+        TXT_NewLabel("Movement"),
+        TXT_NewSpinControl(&joystick_move_sensitivity, 0, 20),
+        TXT_NewLabel("Turn"),
+        TXT_NewSpinControl(&joystick_turn_sensitivity, 0, 20),
+        NULL);
+    if (gamemission == heretic || gamemission == hexen || gamemission == strife)
+    {
+        TXT_AddWidgets(window,
+            TXT_NewLabel("Look"),
+            TXT_NewSpinControl(&joystick_look_sensitivity, 0, 20), NULL);
+    }
+    TXT_SetWindowAction(window, TXT_HORIZ_LEFT, NULL);
+    TXT_SetWindowAction(window, TXT_HORIZ_CENTER,
+        TXT_NewWindowEscapeAction(window));
+    TXT_SetWindowAction(window, TXT_HORIZ_RIGHT, NULL);
+    TXT_SetWidgetAlign(window, TXT_HORIZ_CENTER);
+}
+
 void ConfigJoystick(TXT_UNCAST_ARG(widget), void *user_data)
 {
     txt_window_t *window;
@@ -1197,14 +1232,13 @@ void ConfigJoystick(TXT_UNCAST_ARG(widget), void *user_data)

     TXT_AddWidget(window,
         TXT_NewConditional(&use_gamepad, 1,
-            TXT_MakeTable(6,
-                   TXT_NewButton2("Swap L and R sticks", SwapLRSticks, NULL),
-                   TXT_TABLE_OVERFLOW_RIGHT,
-                   TXT_TABLE_OVERFLOW_RIGHT,
-                   TXT_TABLE_EMPTY,
-                   TXT_TABLE_EMPTY,
-                   TXT_TABLE_EMPTY,
-                   NULL)));
+                   TXT_NewButton2("Swap L and R sticks", SwapLRSticks, NULL)));
+    TXT_AddWidget(window, TXT_TABLE_EOL);
+
+    TXT_AddWidget(window,
+        TXT_NewConditional(&use_gamepad, 1,
+                   TXT_NewButton2("Analog settings", AdjustAnalog, NULL)));
+    TXT_AddWidget(window, TXT_TABLE_EOL);

     TXT_AddWidget(window, TXT_NewSeparator("Buttons"));

@@ -1267,6 +1301,10 @@ void BindJoystickVariables(void)
     M_BindIntVariable("joystick_y_dead_zone", &joystick_y_dead_zone);
     M_BindIntVariable("joystick_strafe_dead_zone", &joystick_strafe_dead_zone);
     M_BindIntVariable("joystick_look_dead_zone", &joystick_look_dead_zone);
+    M_BindIntVariable("use_analog", &use_analog);
+    M_BindIntVariable("joystick_turn_sensitivity", &joystick_turn_sensitivity);
+    M_BindIntVariable("joystick_move_sensitivity", &joystick_move_sensitivity);
+    M_BindIntVariable("joystick_look_sensitivity", &joystick_look_sensitivity);

     for (i = 0; i < NUM_VIRTUAL_BUTTONS; ++i)
     {