Skip to content

Commit

Permalink
Add basic gamepad rumble support
Browse files Browse the repository at this point in the history
Controlled by new cvar joy_rumble (default: 0.3)
  • Loading branch information
andrei-drexler committed Aug 4, 2024
1 parent b37eaed commit 4dc3bec
Show file tree
Hide file tree
Showing 7 changed files with 92 additions and 1 deletion.
27 changes: 27 additions & 0 deletions Quake/in_sdl.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ cvar_t joy_flick_time = { "joy_flick_time", "0.125", CVAR_ARCHIVE };
cvar_t joy_flick_recenter = { "joy_flick_recenter", "0.0", CVAR_ARCHIVE };
cvar_t joy_flick_deadzone = { "joy_flick_deadzone", "0.9", CVAR_ARCHIVE };
cvar_t joy_flick_noise_thresh = { "joy_flick_noise_thresh", "2.0", CVAR_ARCHIVE };
cvar_t joy_rumble = { "joy_rumble", "0.3", CVAR_ARCHIVE };
cvar_t joy_device = { "joy_device", "0", CVAR_ARCHIVE };

cvar_t gyro_enable = {"gyro_enable", "1", CVAR_ARCHIVE};
Expand All @@ -89,6 +90,7 @@ static int joy_active_device = -1;
static SDL_GameController *joy_active_controller = NULL;
static gamepadtype_t joy_active_type = GAMEPAD_NONE;
static char joy_active_name[256];
static qboolean joy_has_rumble = false;

static qboolean no_mouse = false;

Expand Down Expand Up @@ -314,6 +316,10 @@ static qboolean IN_UseController (int device_index)

if (joy_active_device != -1)
{
#if SDL_VERSION_ATLEAST (2, 0, 9)
if (joy_has_rumble)
SDL_GameControllerRumble (joy_active_controller, 0, 0, 100);
#endif // SDL_VERSION_ATLEAST (2, 0, 9)
SDL_GameControllerClose (joy_active_controller);

// Only show "gamepad removed" message when disabling the gamepad altogether,
Expand All @@ -329,6 +335,7 @@ static qboolean IN_UseController (int device_index)
Cvar_SetValueQuick (&joy_device, -1);
gyro_present = false;
gyro_yaw = gyro_pitch = gyro_raw_mag = 0.f;
joy_has_rumble = false;
IN_ResetFlickState ();
}

Expand Down Expand Up @@ -409,6 +416,9 @@ static qboolean IN_UseController (int device_index)
}
#endif // SDL_VERSION_ATLEAST(2, 0, 14)

#if SDL_VERSION_ATLEAST (2, 0, 9)
joy_has_rumble = SDL_GameControllerHasRumble (joy_active_controller);
#endif // SDL_VERSION_ATLEAST (2, 0, 9)
return true;
}

Expand Down Expand Up @@ -507,6 +517,11 @@ void IN_UseNextGamepad (int dir, qboolean allow_disable)
}
}

qboolean IN_HasRumble (void)
{
return joy_has_rumble;
}

void IN_GyroActionDown (void)
{
gyro_button_pressed = true;
Expand Down Expand Up @@ -595,6 +610,7 @@ void IN_Init (void)
Cvar_RegisterVariable(&joy_flick_recenter);
Cvar_RegisterVariable(&joy_flick_deadzone);
Cvar_RegisterVariable(&joy_flick_noise_thresh);
Cvar_RegisterVariable(&joy_rumble);
Cvar_RegisterVariable(&joy_device);
Cvar_SetCallback(&joy_device, Joy_Device_f);
Cvar_SetCompletion(&joy_device, Joy_Device_Completion_f);
Expand Down Expand Up @@ -911,6 +927,17 @@ void IN_Commands (void)
IN_JoyKeyEvent(joy_axisstate.axisvalue[SDL_CONTROLLER_AXIS_TRIGGERRIGHT] > triggerthreshold, newaxisstate.axisvalue[SDL_CONTROLLER_AXIS_TRIGGERRIGHT] > triggerthreshold, K_RTRIGGER, &joy_emulatedkeytimer[5]);

joy_axisstate = newaxisstate;

#if SDL_VERSION_ATLEAST (2, 0, 9)
if (joy_has_rumble && joy_rumble.value > 0.f)
{
float strength = CLAMP (0.f, joy_rumble.value, 1.f) * 0xffff;
float lofreq = GetClampedFraction (S_GetLoFreqLevel (), 0.067f, 0.45f);
float hifreq = GetClampedFraction (S_GetHiFreqLevel (), 0.061f, 0.45f);
hifreq *= hifreq;
SDL_GameControllerRumble (joy_active_controller, lofreq * strength, hifreq * strength, 100);
}
#endif // SDL_VERSION_ATLEAST (2, 0, 9)
}

/*
Expand Down
2 changes: 1 addition & 1 deletion Quake/input.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,11 @@ typedef enum gamepadtype_t
GAMEPAD_NINTENDO,
} gamepadtype_t;

qboolean IN_HasRumble (void);
qboolean IN_HasGamepad (void);
const char *IN_GetGamepadName (void);
gamepadtype_t IN_GetGamepadType (void);
void IN_UseNextGamepad (int dir, qboolean allow_disable);
const char *IN_GamepadButtonName (int keynum);

void IN_SendKeyEvents (void);
// used as a callback for Sys_SendKeyEvents() by some drivers
Expand Down
11 changes: 11 additions & 0 deletions Quake/mathlib.c
Original file line number Diff line number Diff line change
Expand Up @@ -378,6 +378,17 @@ int Q_nextPow2(int val)
return val;
}

float GetFraction (float val, float minval, float maxval)
{
return (val - minval) / (maxval - minval);
}

float GetClampedFraction (float val, float minval, float maxval)
{
val = GetFraction (val, minval, maxval);
return CLAMP (0.f, val, 1.f);
}

/*
==================
Interleave0
Expand Down
3 changes: 3 additions & 0 deletions Quake/mathlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ void VectorScale (vec3_t in, vec_t scale, vec3_t out);
int Q_log2(int val);
int Q_nextPow2(int val);

float GetFraction (float val, float minval, float maxval);
float GetClampedFraction (float val, float minval, float maxval);

uint32_t Interleave0 (uint16_t x);
uint32_t Interleave (uint16_t even, uint16_t odd);
uint16_t DeinterleaveEven (uint32_t x);
Expand Down
20 changes: 20 additions & 0 deletions Quake/menu.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ extern cvar_t joy_exponent;
extern cvar_t joy_exponent_move;
extern cvar_t joy_swapmovelook;
extern cvar_t joy_flick;
extern cvar_t joy_rumble;
extern cvar_t gyro_enable;
extern cvar_t gyro_mode;
extern cvar_t gyro_turning_axis;
Expand Down Expand Up @@ -3277,6 +3278,10 @@ void M_Menu_Gamepad_f (void)
\
def(GPAD_OPT_SPACE5, "") \
\
def(GPAD_OPT_RUMBLE, "Vibration") \
\
def(GPAD_OPT_SPACE6, "") \
\
def(GPAD_OPT_GYROENABLE, "Gyro") \
def(GPAD_OPT_FLICKSTICK, "Flick Stick") \
def(GPAD_OPT_GYROMODE, "Gyro Button") \
Expand Down Expand Up @@ -3406,6 +3411,8 @@ static qboolean M_Options_IsEnabled (int index)
return false;
if (index > GPAD_OPTIONS_FIRST && index < GPAD_OPTIONS_FIRST + GPAD_OPTIONS_ITEMS && !IN_HasGamepad ())
return false;
if (index == GPAD_OPT_RUMBLE && !IN_HasRumble ())
return false;
if (M_Options_IsGyroId (index))
{
if (!IN_HasGyro ())
Expand Down Expand Up @@ -3774,6 +3781,9 @@ void M_AdjustSliders (int dir)
case GPAD_OPT_DEADZONE_TRIG:
Cvar_SetValueQuick (&joy_deadzone_trigger, CLAMP (MIN_TRIGGER_DEADZONE, joy_deadzone_trigger.value + dir * 0.05f, MAX_TRIGGER_DEADZONE));
break;
case GPAD_OPT_RUMBLE:
Cvar_SetValueQuick (&joy_rumble, CLAMP (0.f, joy_rumble.value + dir * 0.1f, 1.f));
break;
case GPAD_OPT_GYROENABLE:
Cvar_SetValueQuick (&gyro_enable, !gyro_enable.value);
break;
Expand Down Expand Up @@ -3952,6 +3962,9 @@ qboolean M_SetSliderValue (int option, float f)
f = LERP (MIN_TRIGGER_DEADZONE, MAX_TRIGGER_DEADZONE, f);
Cvar_SetValueQuick (&joy_deadzone_trigger, f);
return true;
case GPAD_OPT_RUMBLE:
Cvar_SetValueQuick (&joy_rumble, f);
return true;
case GPAD_OPT_GYROSENSX:
f = LERP (MIN_GYRO_SENS, MAX_GYRO_SENS, f);
Cvar_SetValueQuick (&gyro_yawsensitivity, f);
Expand Down Expand Up @@ -4275,6 +4288,13 @@ static void M_Options_DrawItem (int y, int item)
l = (IN_GetRawTriggerMagnitude () - MIN_TRIGGER_DEADZONE) / (MAX_TRIGGER_DEADZONE - MIN_TRIGGER_DEADZONE);
M_DrawThresholdSlider (x, y, r, selected && IN_HasGamepad (), l, va ("%.0f%%", joy_deadzone_trigger.value * 100.f));
break;
case GPAD_OPT_RUMBLE:
r = joy_rumble.value;
if (!IN_HasRumble ())
M_Print (x, y, "Unavailable");
else
M_DrawSlider (x, y, r, va ("%.0f%%", joy_rumble.value * 100.f));
break;
case GPAD_OPT_GYROENABLE:
if (!IN_HasGyro ())
M_Print (x, y, "Unavailable");
Expand Down
2 changes: 2 additions & 0 deletions Quake/q_sound.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ void S_BeginPrecaching (void);
void S_EndPrecaching (void);
void S_PaintChannels (int endtime);
void S_InitPaintChannels (void);
float S_GetLoFreqLevel (void);
float S_GetHiFreqLevel (void);

/* picks a channel based on priorities, empty slots, number of channels */
channel_t *SND_PickChannel (int entnum, int entchannel);
Expand Down
28 changes: 28 additions & 0 deletions Quake/snd_mix.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ short *snd_out;

static int snd_vol;

static float snd_lofreqlevel;
static float snd_hifreqlevel;

static void Snd_WriteLinearBlastStereo16 (void)
{
int i;
Expand Down Expand Up @@ -382,6 +385,30 @@ static void S_UnderwaterFilter (int endtime)
}
}

static void S_UpdateLevels (int endtime)
{
int i;
float scale;

scale = 0.5f / (snd_vol * 32768.f);
for (i = 0; i < endtime; i++)
{
float sample = (abs (paintbuffer[i].left) + abs (paintbuffer[i].right)) * scale;
snd_lofreqlevel = LERP (snd_lofreqlevel, sample, 1e-3f);
snd_hifreqlevel = LERP (snd_hifreqlevel, sample, 1e-2f);
}
}

float S_GetLoFreqLevel (void)
{
return snd_lofreqlevel;
}

float S_GetHiFreqLevel (void)
{
return snd_hifreqlevel;
}

/*
===============================================================================
Expand Down Expand Up @@ -480,6 +507,7 @@ void S_PaintChannels (int endtime)
}

S_UnderwaterFilter (end - paintedtime);
S_UpdateLevels (end - paintedtime);

// paint in the music
if (s_rawend >= paintedtime)
Expand Down

0 comments on commit 4dc3bec

Please sign in to comment.