mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2024-11-22 12:41:21 +00:00
Gyro aiming for Switch controllers on SDL < 2.0.14
dkms-hid-nintendo can expose the IMU sensors of a Switch controller as a "second joystick", which makes possible to use gyro aiming on a system without SDL 2.0.14 available (the minimum required to read controller sensors like gyro and accelerometer). This commit makes both "sensor" and "joystick reading" to coexist. "Sensor" is still the preferred method when available.
This commit is contained in:
parent
c2d80c64ee
commit
61df6a74d5
1 changed files with 118 additions and 9 deletions
|
@ -167,12 +167,25 @@ static qboolean gyro_active = false;
|
|||
|
||||
// Gyro calibration
|
||||
static float gyro_accum[3];
|
||||
static unsigned int num_samples;
|
||||
|
||||
static cvar_t *gyro_calibration_x;
|
||||
static cvar_t *gyro_calibration_y;
|
||||
static cvar_t *gyro_calibration_z;
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 14) // support for controller sensors (gyro, accelerometer)
|
||||
|
||||
static unsigned int num_samples;
|
||||
#define NATIVE_SDL_GYRO 1 // uses SDL_CONTROLLERSENSORUPDATE to read gyro
|
||||
|
||||
#else // for SDL < 2.0.14, gyro can be read as a "secondary joystick" exposed by dkms-hid-nintendo
|
||||
|
||||
static unsigned int num_samples[3];
|
||||
static SDL_Joystick *imu_joystick = NULL; // gyro "joystick"
|
||||
#define IMU_JOY_AXIS_GYRO_ROLL 3
|
||||
#define IMU_JOY_AXIS_GYRO_PITCH 4
|
||||
#define IMU_JOY_AXIS_GYRO_YAW 5
|
||||
|
||||
#endif
|
||||
|
||||
// To ignore SDL_JOYDEVICEADDED at game init. Allows for hot plugging of game controller afterwards.
|
||||
static qboolean first_init = true;
|
||||
|
||||
|
@ -766,7 +779,7 @@ IN_Update(void)
|
|||
break;
|
||||
}
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 16) // support for controller sensors (gyro, accelerometer)
|
||||
#ifdef NATIVE_SDL_GYRO // controller sensors' reading supported (gyro, accelerometer)
|
||||
case SDL_CONTROLLERSENSORUPDATE:
|
||||
if (event.csensor.sensor != SDL_SENSOR_GYRO)
|
||||
{
|
||||
|
@ -781,9 +794,39 @@ IN_Update(void)
|
|||
break;
|
||||
}
|
||||
|
||||
#else // gyro read as "secondary joystick"
|
||||
case SDL_JOYAXISMOTION:
|
||||
if ( !imu_joystick || event.cdevice.which != SDL_JoystickInstanceID(imu_joystick) )
|
||||
{
|
||||
break; // controller axes handled by SDL_CONTROLLERAXISMOTION
|
||||
}
|
||||
|
||||
int axis_value = event.caxis.value;
|
||||
if (countdown_reason == REASON_GYROCALIBRATION && updates_countdown)
|
||||
{
|
||||
switch (event.caxis.axis)
|
||||
{
|
||||
case IMU_JOY_AXIS_GYRO_PITCH:
|
||||
gyro_accum[0] += axis_value;
|
||||
num_samples[0]++;
|
||||
break;
|
||||
case IMU_JOY_AXIS_GYRO_YAW:
|
||||
gyro_accum[1] += axis_value;
|
||||
num_samples[1]++;
|
||||
break;
|
||||
case IMU_JOY_AXIS_GYRO_ROLL:
|
||||
gyro_accum[2] += axis_value;
|
||||
num_samples[2]++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
#endif // NATIVE_SDL_GYRO
|
||||
|
||||
if (gyro_active && gyro_mode->value &&
|
||||
!cl_paused->value && cls.key_dest == key_game)
|
||||
{
|
||||
#ifdef NATIVE_SDL_GYRO
|
||||
if (!gyro_turning_axis->value)
|
||||
{
|
||||
gyro_yaw = event.csensor.data[1] - gyro_calibration_y->value; // yaw
|
||||
|
@ -793,13 +836,31 @@ IN_Update(void)
|
|||
gyro_yaw = -(event.csensor.data[2] - gyro_calibration_z->value); // roll
|
||||
}
|
||||
gyro_pitch = event.csensor.data[0] - gyro_calibration_x->value;
|
||||
#else // old "joystick" gyro
|
||||
switch (event.caxis.axis) // inside "case SDL_JOYAXISMOTION" here
|
||||
{
|
||||
case IMU_JOY_AXIS_GYRO_PITCH:
|
||||
gyro_pitch = -(axis_value - gyro_calibration_x->value);
|
||||
break;
|
||||
case IMU_JOY_AXIS_GYRO_YAW:
|
||||
if (!gyro_turning_axis->value)
|
||||
{
|
||||
gyro_yaw = axis_value - gyro_calibration_y->value;
|
||||
}
|
||||
break;
|
||||
case IMU_JOY_AXIS_GYRO_ROLL:
|
||||
if (gyro_turning_axis->value)
|
||||
{
|
||||
gyro_yaw = axis_value - gyro_calibration_z->value;
|
||||
}
|
||||
}
|
||||
#endif // NATIVE_SDL_GYRO
|
||||
}
|
||||
else
|
||||
{
|
||||
gyro_yaw = gyro_pitch = 0;
|
||||
}
|
||||
break;
|
||||
#endif // SDL_VERSION_ATLEAST(2, 0, 16)
|
||||
|
||||
case SDL_CONTROLLERDEVICEREMOVED:
|
||||
if (!controller)
|
||||
|
@ -889,10 +950,23 @@ IN_Update(void)
|
|||
|
||||
case REASON_GYROCALIBRATION: // finish and save calibration
|
||||
{
|
||||
#ifdef NATIVE_SDL_GYRO
|
||||
const float inverseSamples = 1.f / num_samples;
|
||||
Cvar_SetValue("gyro_calibration_x", gyro_accum[0] * inverseSamples);
|
||||
Cvar_SetValue("gyro_calibration_y", gyro_accum[1] * inverseSamples);
|
||||
Cvar_SetValue("gyro_calibration_z", gyro_accum[2] * inverseSamples);
|
||||
#else
|
||||
if (!num_samples[0] || !num_samples[1] || !num_samples[2])
|
||||
{
|
||||
Com_Printf("Calibration failed, please retry inside a level after having moved your controller a little.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Cvar_SetValue("gyro_calibration_x", gyro_accum[0] / num_samples[0]);
|
||||
Cvar_SetValue("gyro_calibration_y", gyro_accum[1] / num_samples[1]);
|
||||
Cvar_SetValue("gyro_calibration_z", gyro_accum[2] / num_samples[2]);
|
||||
}
|
||||
#endif
|
||||
Com_Printf("Calibration results:\n X=%f Y=%f Z=%f\n",
|
||||
gyro_calibration_x->value, gyro_calibration_y->value, gyro_calibration_z->value);
|
||||
CalibrationFinishedCallback();
|
||||
|
@ -1269,7 +1343,11 @@ IN_Move(usercmd_t *cmd)
|
|||
//
|
||||
// For movement this is not needed, as those are absolute values independent of framerate
|
||||
float joyViewFactor = cls.rframetime/0.01666f;
|
||||
#ifdef NATIVE_SDL_GYRO
|
||||
float gyroViewFactor = (1.0f / M_PI) * joyViewFactor;
|
||||
#else
|
||||
float gyroViewFactor = (1.0f / 2560.0f) * joyViewFactor; // normalized for Switch gyro
|
||||
#endif
|
||||
|
||||
if (joystick_yaw)
|
||||
{
|
||||
|
@ -1915,10 +1993,14 @@ Controller_Rumble(const char *name, vec3_t source, qboolean from_player,
|
|||
void
|
||||
StartCalibration(void)
|
||||
{
|
||||
#ifdef NATIVE_SDL_GYRO
|
||||
num_samples = 0;
|
||||
#else
|
||||
num_samples[0] = num_samples[1] = num_samples[2] = 0;
|
||||
#endif
|
||||
gyro_accum[0] = 0.0;
|
||||
gyro_accum[1] = 0.0;
|
||||
gyro_accum[2] = 0.0;
|
||||
num_samples = 0;
|
||||
updates_countdown = 300;
|
||||
countdown_reason = REASON_GYROCALIBRATION;
|
||||
}
|
||||
|
@ -2033,9 +2115,26 @@ IN_Controller_Init(qboolean notify_user)
|
|||
// 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))
|
||||
{
|
||||
Com_Printf ("Skipping IMU device.\n");
|
||||
SDL_JoystickClose(joystick);
|
||||
joystick = NULL;
|
||||
#ifdef NATIVE_SDL_GYRO
|
||||
Com_Printf ("Skipping IMU device.\n");
|
||||
#else // if it's not a Left JoyCon, use it as Gyro
|
||||
Com_Printf ("IMU device found.\n");
|
||||
if ( !imu_joystick && name_len > 16 && strncmp(joystick_name + name_len - 16, "Left Joy-Con IMU", 16) != 0 )
|
||||
{
|
||||
imu_joystick = SDL_JoystickOpen(i);
|
||||
if (imu_joystick)
|
||||
{
|
||||
show_gyro = true;
|
||||
Com_Printf ("Using this device as Gyro sensor.\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
Com_Printf ("Couldn't open IMU: %s.\n", SDL_GetError());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -2059,7 +2158,7 @@ IN_Controller_Init(qboolean notify_user)
|
|||
SDL_JoystickClose(joystick);
|
||||
joystick = NULL;
|
||||
|
||||
if (is_controller)
|
||||
if (is_controller && !controller)
|
||||
{
|
||||
controller = SDL_GameControllerOpen(i);
|
||||
if (!controller)
|
||||
|
@ -2071,7 +2170,7 @@ IN_Controller_Init(qboolean notify_user)
|
|||
show_gamepad = true;
|
||||
Com_Printf("Enabled as Game Controller, settings:\n%s\n", SDL_GameControllerMapping(controller));
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 16) // support for controller sensors
|
||||
#ifdef NATIVE_SDL_GYRO
|
||||
|
||||
if ( SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO)
|
||||
&& !SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE) )
|
||||
|
@ -2090,7 +2189,7 @@ IN_Controller_Init(qboolean notify_user)
|
|||
SDL_GameControllerSetLED(controller, 0, 80, 0); // green light
|
||||
}
|
||||
|
||||
#endif // SDL_VERSION_ATLEAST(2, 0, 16)
|
||||
#endif // NATIVE_SDL_GYRO
|
||||
|
||||
joystick_haptic = SDL_HapticOpenFromJoystick(SDL_GameControllerGetJoystick(controller));
|
||||
|
||||
|
@ -2124,7 +2223,9 @@ IN_Controller_Init(qboolean notify_user)
|
|||
Com_Printf("Controller doesn't support rumble.\n");
|
||||
}
|
||||
|
||||
#ifdef NATIVE_SDL_GYRO // "native" exits when finding a single working controller
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2236,6 +2337,14 @@ IN_Controller_Shutdown(qboolean notify_user)
|
|||
show_gamepad = show_gyro = show_haptic = false;
|
||||
joystick_left_x = joystick_left_y = joystick_right_x = joystick_right_y = 0;
|
||||
gyro_yaw = gyro_pitch = 0;
|
||||
|
||||
#ifndef NATIVE_SDL_GYRO
|
||||
if (imu_joystick)
|
||||
{
|
||||
SDL_JoystickClose(imu_joystick);
|
||||
imu_joystick = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue