From 1825aa9723e5fbf4fb5d51941457fd24166b98dd Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Wed, 4 Dec 2024 18:53:57 -0300 Subject: [PATCH 1/7] Sound backend selector Changes s_openal, replaces sound quality selector. --- src/client/menu/menu.c | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/src/client/menu/menu.c b/src/client/menu/menu.c index bad95ee9..ae950de7 100644 --- a/src/client/menu/menu.c +++ b/src/client/menu/menu.c @@ -2254,7 +2254,7 @@ ControlsSetMenuItemValues(void) { s_options_oggshuffle_box.curvalue = Cvar_VariableValue("ogg_shuffle"); s_options_oggenable_box.curvalue = (Cvar_VariableValue("ogg_enable") != 0); - s_options_quality_list.curvalue = (Cvar_VariableValue("s_loadas8bit") == 0); + s_options_quality_list.curvalue = (Cvar_VariableValue("s_openal") == 0); s_options_alwaysrun_box.curvalue = (cl_run->value != 0); s_options_invertmouse_box.curvalue = (m_pitch->value < 0); s_options_lookstrafe_box.curvalue = (lookstrafe->value != 0); @@ -2341,18 +2341,9 @@ ConsoleFunc(void *unused) } static void -UpdateSoundQualityFunc(void *unused) +UpdateSoundBackendFunc(void *unused) { - if (s_options_quality_list.curvalue == 0) - { - Cvar_SetValue("s_khz", 22); - Cvar_SetValue("s_loadas8bit", false); - } - else - { - Cvar_SetValue("s_khz", 44); - Cvar_SetValue("s_loadas8bit", false); - } + Cvar_Set("s_openal", (s_options_quality_list.curvalue == 0)? "1":"0" ); m_popup_string = "Restarting the sound system. This\n" "could take up to a minute, so\n" @@ -2388,9 +2379,9 @@ Options_MenuInit(void) 0 }; - static const char *quality_items[] = + static const char *sound_items[] = { - "normal", "high", 0 + "openal (quality)", "sdl (performance)", 0 }; static const char *yesno_names[] = @@ -2458,9 +2449,9 @@ Options_MenuInit(void) s_options_quality_list.generic.type = MTYPE_SPINCONTROL; s_options_quality_list.generic.x = 0; s_options_quality_list.generic.y = (y += 10); - s_options_quality_list.generic.name = "sound quality"; - s_options_quality_list.generic.callback = UpdateSoundQualityFunc; - s_options_quality_list.itemnames = quality_items; + s_options_quality_list.generic.name = "sound backend"; + s_options_quality_list.generic.callback = UpdateSoundBackendFunc; + s_options_quality_list.itemnames = sound_items; s_options_sensitivity_slider.generic.type = MTYPE_SLIDER; s_options_sensitivity_slider.generic.x = 0; From 6b8cd8fdf9d671d6bafd54f6d414a4816a6add50 Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Wed, 4 Dec 2024 18:57:19 -0300 Subject: [PATCH 2/7] Weapon preview for cycleweap 'Pickup style' just like weapprev/weapnext, only works when cycleweap is called with 3 or more parameters. Weapon binds in gamepad menus now include xatrix and rogue weapons. --- src/client/menu/menu.c | 40 ++++++++++++++++++++++++++++------------ src/game/g_cmds.c | 28 ++++++++++++++++++---------- 2 files changed, 46 insertions(+), 22 deletions(-) diff --git a/src/client/menu/menu.c b/src/client/menu/menu.c index ae950de7..a3484a29 100644 --- a/src/client/menu/menu.c +++ b/src/client/menu/menu.c @@ -1326,12 +1326,20 @@ char *controller_bindnames[][2] = {"+movedown", "down / crouch"}, {"weapnext", "next weapon"}, {"weapprev", "previous weapon"}, - {"cycleweap weapon_chaingun weapon_machinegun weapon_blaster", "long range: quickswitch 1"}, - {"cycleweap weapon_supershotgun weapon_shotgun", "close range: quickswitch 2"}, - {"cycleweap weapon_rocketlauncher weapon_grenadelauncher ammo_grenades", "explosives: quickswitch 3"}, - {"cycleweap weapon_bfg weapon_railgun weapon_hyperblaster", "special: quickswitch 4"}, - {"prefweap weapon_railgun weapon_hyperblaster weapon_chaingun weapon_supershotgun weapon_machinegun weapon_shotgun weapon_blaster", "best safe weapon"}, - {"prefweap weapon_bfg weapon_railgun weapon_rocketlauncher weapon_hyperblaster weapon_grenadelauncher weapon_chaingun ammo_grenades weapon_supershotgun", "best unsafe weapon"}, + {"cycleweap weapon_plasmabeam weapon_boomer weapon_chaingun weapon_etf_rifle" + " weapon_machinegun weapon_blaster", "long range: quickswitch 1"}, + {"cycleweap weapon_supershotgun weapon_shotgun weapon_chainfist", + "close range: quickswitch 2"}, + {"cycleweap weapon_phalanx weapon_rocketlauncher weapon_proxlauncher" + " weapon_grenadelauncher ammo_grenades", "explosives: quickswitch 3"}, + {"cycleweap weapon_bfg weapon_disintegrator weapon_railgun weapon_hyperblaster" + " ammo_tesla ammo_trap", "special: quickswitch 4"}, + {"prefweap weapon_railgun weapon_plasmabeam weapon_boomer weapon_hyperblaster weapon_chaingun" + " weapon_supershotgun weapon_etf_rifle weapon_machinegun weapon_shotgun weapon_blaster", + "best safe weapon"}, + {"prefweap weapon_bfg weapon_disintegrator weapon_phalanx weapon_railgun weapon_rocketlauncher" + " weapon_plasmabeam weapon_boomer weapon_hyperblaster weapon_grenadelauncher weapon_chaingun" + " weapon_proxlauncher ammo_grenades weapon_supershotgun", "best unsafe weapon"}, {"centerview", "center view"}, {"inven", "inventory"}, {"invuse", "use item"}, @@ -1489,12 +1497,20 @@ char *controller_alt_bindnames[][2] = { {"weapnext", "next weapon"}, {"weapprev", "previous weapon"}, - {"cycleweap weapon_chaingun weapon_machinegun weapon_blaster", "long range: quickswitch 1"}, - {"cycleweap weapon_supershotgun weapon_shotgun", "close range: quickswitch 2"}, - {"cycleweap weapon_rocketlauncher weapon_grenadelauncher ammo_grenades", "explosives: quickswitch 3"}, - {"cycleweap weapon_bfg weapon_railgun weapon_hyperblaster", "special: quickswitch 4"}, - {"prefweap weapon_railgun weapon_hyperblaster weapon_chaingun weapon_supershotgun weapon_machinegun weapon_shotgun weapon_blaster", "best safe weapon"}, - {"prefweap weapon_bfg weapon_railgun weapon_rocketlauncher weapon_hyperblaster weapon_grenadelauncher weapon_chaingun ammo_grenades weapon_supershotgun", "best unsafe weapon"}, + {"cycleweap weapon_plasmabeam weapon_boomer weapon_chaingun weapon_etf_rifle" + " weapon_machinegun weapon_blaster", "long range: quickswitch 1"}, + {"cycleweap weapon_supershotgun weapon_shotgun weapon_chainfist", + "close range: quickswitch 2"}, + {"cycleweap weapon_phalanx weapon_rocketlauncher weapon_proxlauncher" + " weapon_grenadelauncher ammo_grenades", "explosives: quickswitch 3"}, + {"cycleweap weapon_bfg weapon_disintegrator weapon_railgun weapon_hyperblaster" + " ammo_tesla ammo_trap", "special: quickswitch 4"}, + {"prefweap weapon_railgun weapon_plasmabeam weapon_boomer weapon_hyperblaster weapon_chaingun" + " weapon_supershotgun weapon_etf_rifle weapon_machinegun weapon_shotgun weapon_blaster", + "best safe weapon"}, + {"prefweap weapon_bfg weapon_disintegrator weapon_phalanx weapon_railgun weapon_rocketlauncher" + " weapon_plasmabeam weapon_boomer weapon_hyperblaster weapon_grenadelauncher weapon_chaingun" + " weapon_proxlauncher ammo_grenades weapon_supershotgun", "best unsafe weapon"}, {"centerview", "center view"}, {"inven", "inventory"}, {"invuse", "use item"}, diff --git a/src/game/g_cmds.c b/src/game/g_cmds.c index 304d0c6e..1f217986 100644 --- a/src/game/g_cmds.c +++ b/src/game/g_cmds.c @@ -1708,29 +1708,37 @@ static void Cmd_CycleWeap_f(edict_t *ent) { gitem_t *weap; + gclient_t *cl; + int num_weaps; if (!ent) { return; } - if (gi.argc() <= 1) + num_weaps = gi.argc(); + if (num_weaps <= 1) { gi.cprintf(ent, PRINT_HIGH, "Usage: cycleweap classname1 classname2 .. classnameN\n"); return; } weap = cycle_weapon(ent); - if (weap) + if (!weap) return; + + cl = ent->client; + if (cl->pers.inventory[ITEM_INDEX(weap)] <= 0) { - if (ent->client->pers.inventory[ITEM_INDEX(weap)] <= 0) - { - gi.cprintf(ent, PRINT_HIGH, "Out of item: %s\n", weap->pickup_name); - } - else - { - weap->use(ent, weap); - } + gi.cprintf(ent, PRINT_HIGH, "Out of item: %s\n", weap->pickup_name); + return; + } + + weap->use(ent, weap); + if (num_weaps > 3 && cl->newweapon == weap) + { + cl->ps.stats[STAT_PICKUP_ICON] = gi.imageindex(weap->icon); + cl->ps.stats[STAT_PICKUP_STRING] = CS_ITEMS + ITEM_INDEX(weap); + cl->pickup_msg_time = level.time + 0.7f; } } From 6a3a081b4b4cfc74c52ec3e494f3288b77dc4b14 Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Wed, 11 Dec 2024 20:46:53 -0300 Subject: [PATCH 3/7] Refactored gluPerspective-like function in GL1 It was being called repeteadly with the same parameters, so it was re-written with only one needed parameter, with the rest of the data being obtained inside the function, to avoid logic duplication. --- src/client/refresh/gl1/gl1_buffer.c | 7 ++---- src/client/refresh/gl1/gl1_main.c | 34 ++++++++++++++--------------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/src/client/refresh/gl1/gl1_buffer.c b/src/client/refresh/gl1/gl1_buffer.c index edbd2e44..40ededfb 100644 --- a/src/client/refresh/gl1/gl1_buffer.c +++ b/src/client/refresh/gl1/gl1_buffer.c @@ -36,7 +36,7 @@ int cur_lm_copy; // which lightmap copy to use (when lightmapcopies=on) static GLushort vtx_ptr, idx_ptr; // pointers for array positions in gl_buf -extern void R_MYgluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); +extern void R_SetPerspective(GLdouble fovy); void R_ResetGLBuffer(void) @@ -50,7 +50,6 @@ R_ApplyGLBuffer(void) // Properties of batched draws here GLint vtx_size; qboolean texture, mtex, alpha, color, alias, texenv_set; - float fovy, dist; if (vtx_ptr == 0 || idx_ptr == 0) { @@ -107,9 +106,7 @@ R_ApplyGLBuffer(void) glScalef(-1, 1, 1); } - fovy = (r_gunfov->value < 0) ? r_newrefdef.fov_y : r_gunfov->value; - dist = (r_farsee->value == 0) ? 4096.0f : 8192.0f; - R_MYgluPerspective(fovy, (float)r_newrefdef.width / r_newrefdef.height, 4, dist); + R_SetPerspective( (r_gunfov->value < 0) ? r_newrefdef.fov_y : r_gunfov->value ); glMatrixMode(GL_MODELVIEW); diff --git a/src/client/refresh/gl1/gl1_main.c b/src/client/refresh/gl1/gl1_main.c index c9a1b75f..f4cbdfb4 100644 --- a/src/client/refresh/gl1/gl1_main.c +++ b/src/client/refresh/gl1/gl1_main.c @@ -727,19 +727,28 @@ R_SetupFrame(void) } void -R_MYgluPerspective(GLdouble fovy, GLdouble aspect, - GLdouble zNear, GLdouble zFar) +R_SetPerspective(GLdouble fovy) { + // gluPerspective style parameters + static const GLdouble zNear = 4; + const GLdouble zFar = (r_farsee->value) ? 8192.0f : 4096.0f; + const GLdouble aspectratio = (GLdouble)r_newrefdef.width / r_newrefdef.height; + GLdouble xmin, xmax, ymin, ymax; + // traditional gluPerspective calculations - https://youtu.be/YqSNGcF5nvM?t=644 ymax = zNear * tan(fovy * M_PI / 360.0); + xmax = ymax * aspectratio; + ymin = -ymax; + xmin = -xmax; - xmin = ymin * aspect; - xmax = ymax * aspect; - - xmin += - gl1_stereo_convergence->value * (2 * gl_state.camera_separation) / zNear; - xmax += - gl1_stereo_convergence->value * (2 * gl_state.camera_separation) / zNear; + if (gl_state.camera_separation) + { + const GLdouble separation = - gl1_stereo_convergence->value * (2 * gl_state.camera_separation) / zNear; + xmin += separation; + xmax += separation; + } glFrustum(xmin, xmax, ymin, ymax, zNear, zFar); } @@ -747,7 +756,6 @@ R_MYgluPerspective(GLdouble fovy, GLdouble aspect, void R_SetupGL(void) { - float screenaspect; int x, x2, y2, y, w, h; /* set up viewport */ @@ -777,18 +785,10 @@ R_SetupGL(void) glViewport(x, y2, w, h); /* set up projection matrix */ - screenaspect = (float)r_newrefdef.width / r_newrefdef.height; glMatrixMode(GL_PROJECTION); glLoadIdentity(); - if (r_farsee->value == 0) - { - R_MYgluPerspective(r_newrefdef.fov_y, screenaspect, 4, 4096); - } - else - { - R_MYgluPerspective(r_newrefdef.fov_y, screenaspect, 4, 8192); - } + R_SetPerspective(r_newrefdef.fov_y); glCullFace(GL_FRONT); From 5d201fce9a8daff2e880c8f675bfe44b4c9371b6 Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Wed, 11 Dec 2024 21:05:27 -0300 Subject: [PATCH 4/7] GL1 water warp effect A basic "squeeze/stretch" effect to fov when diving underwater. Intensity is controlled by gl1_waterwarp, 0 disables the effect. Original from Fitzquake. --- doc/040_cvarlist.md | 4 ++++ src/client/refresh/gl1/gl1_main.c | 10 ++++++++++ 2 files changed, 14 insertions(+) diff --git a/doc/040_cvarlist.md b/doc/040_cvarlist.md index 9f1e0905..fe4a0f36 100644 --- a/doc/040_cvarlist.md +++ b/doc/040_cvarlist.md @@ -511,6 +511,10 @@ it's `+set busywait 0` (setting the `busywait` cvar) and `-portable` look a bit better (no flickering) by using the stencil buffer. Does not work when `gl1_stereo` is `3`, `4` or `5`. +* **gl1_waterwarp**: Intensity of the "squeeze/stretch" effect on the + FOV when diving underwater. Can be any floating point number, `0` + disables it (Vanilla Quake II look). Default `1.0`. + * **gl1_lightmapcopies**: When enabled (`1`), keep 3 copies of the same lightmap rotating, shifting to another one when drawing a new frame. Meant for mobile/embedded devices, where changing textures just shown diff --git a/src/client/refresh/gl1/gl1_main.c b/src/client/refresh/gl1/gl1_main.c index f4cbdfb4..c931f7e8 100644 --- a/src/client/refresh/gl1/gl1_main.c +++ b/src/client/refresh/gl1/gl1_main.c @@ -143,6 +143,7 @@ cvar_t *gl1_stereo_separation; cvar_t *gl1_stereo_anaglyph_colors; cvar_t *gl1_stereo_convergence; +static cvar_t *gl1_waterwarp; refimport_t ri; @@ -740,6 +741,13 @@ R_SetPerspective(GLdouble fovy) ymax = zNear * tan(fovy * M_PI / 360.0); xmax = ymax * aspectratio; + if ((r_newrefdef.rdflags & RDF_UNDERWATER) && gl1_waterwarp->value) + { + const GLdouble warp = sin(r_newrefdef.time * 1.5) * 0.03 * gl1_waterwarp->value; + ymax *= 1.0 - warp; + xmax *= 1.0 + warp; + } + ymin = -ymax; xmin = -xmax; @@ -1302,6 +1310,8 @@ R_Register(void) gl1_stereo_anaglyph_colors = ri.Cvar_Get( "gl1_stereo_anaglyph_colors", "rc", CVAR_ARCHIVE ); gl1_stereo_convergence = ri.Cvar_Get( "gl1_stereo_convergence", "1", CVAR_ARCHIVE ); + gl1_waterwarp = ri.Cvar_Get( "gl1_waterwarp", "1.0", CVAR_ARCHIVE ); + ri.Cmd_AddCommand("imagelist", R_ImageList_f); ri.Cmd_AddCommand("screenshot", R_ScreenShot); ri.Cmd_AddCommand("modellist", Mod_Modellist_f); From 661761f047c287c08539cff8302e51aa44133ace Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Sun, 15 Dec 2024 22:22:28 -0300 Subject: [PATCH 5/7] Gamepad Gyro properly detected in SDL3 Using correct return value for SDL_SetGamepadSensorEnabled now. Added menu command for gamepad sticks. --- src/client/input/sdl3.c | 6 +++--- src/client/menu/menu.c | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/client/input/sdl3.c b/src/client/input/sdl3.c index 2bee5218..b4b61080 100644 --- a/src/client/input/sdl3.c +++ b/src/client/input/sdl3.c @@ -799,7 +799,7 @@ IN_Update(void) case SDL_EVENT_JOYSTICK_AXIS_MOTION : if ( !imu_joystick || event.gdevice.which != SDL_GetJoystickID(imu_joystick) ) { - break; // controller axes handled by SDL_CONTROLLERAXISMOTION + break; // gamepad axes handled by SDL_EVENT_GAMEPAD_AXIS_MOTION } int axis_value = event.gaxis.value; @@ -838,7 +838,7 @@ IN_Update(void) } gyro_pitch = event.gsensor.data[0] - gyro_calibration_x->value; #else // old "joystick" gyro - switch (event.gaxis.axis) // inside "case SDL_JOYAXISMOTION" here + switch (event.gaxis.axis) // inside "case SDL_EVENT_JOYSTICK_AXIS_MOTION" here { case IMU_JOY_AXIS_GYRO_PITCH: gyro_pitch = -(axis_value - gyro_calibration_x->value); @@ -2213,7 +2213,7 @@ IN_Controller_Init(qboolean notify_user) #ifdef NATIVE_SDL_GYRO if (SDL_GamepadHasSensor(controller, SDL_SENSOR_GYRO) - && !SDL_SetGamepadSensorEnabled(controller, SDL_SENSOR_GYRO, true) ) + && SDL_SetGamepadSensorEnabled(controller, SDL_SENSOR_GYRO, true) ) { show_gyro = true; Com_Printf( "Gyro sensor enabled at %.2f Hz\n", diff --git a/src/client/menu/menu.c b/src/client/menu/menu.c index a3484a29..3451a862 100644 --- a/src/client/menu/menu.c +++ b/src/client/menu/menu.c @@ -6373,6 +6373,7 @@ M_Init(void) Cmd_AddCommand("menu_gyro", M_Menu_Gyro_f); Cmd_AddCommand("menu_buttons", M_Menu_ControllerButtons_f); Cmd_AddCommand("menu_altbuttons", M_Menu_ControllerAltButtons_f); + Cmd_AddCommand("menu_sticks", M_Menu_Stick_f); Cmd_AddCommand("menu_quit", M_Menu_Quit_f); /* initialize the server address book cvars (adr0, adr1, ...) From 60f0fdd9691367962247a4aad289b8ccb5b29c32 Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Sun, 15 Dec 2024 22:51:56 -0300 Subject: [PATCH 6/7] Makefile parameter to disable SDL Gyro support "make NO_SDL_GYRO=1" disables sensor reading support and forces behavior of SDL < 2.0.14 under any version, even SDL 3. Meant for Arch Linux ARM, which supports 2.30.10 at this time, but doesn't support gyro readings (no HIDAPI support?), even if it shows an additional "IMU joystick" when connecting Nintendo gamepads. This commit allows to use the "IMU joystick" in game, extending #990. Identification of joysticks as "IMU" or "Left Joy-Con" is more generic now, covering more possible naming conventions. --- Makefile | 4 +++ src/client/input/sdl2.c | 60 ++++++++++++++++++++++++----------------- src/client/input/sdl3.c | 60 ++++++++++++++++++++++++++++------------- 3 files changed, 80 insertions(+), 44 deletions(-) diff --git a/Makefile b/Makefile index 89926966..a74d244f 100644 --- a/Makefile +++ b/Makefile @@ -286,6 +286,10 @@ else SDLCFLAGS := $(shell sdl2-config --cflags) endif +ifdef NO_SDL_GYRO +SDLCFLAGS += -DNO_SDL_GYRO +endif + # ---------- # Base include path. diff --git a/src/client/input/sdl2.c b/src/client/input/sdl2.c index ed2a28f9..0faece38 100644 --- a/src/client/input/sdl2.c +++ b/src/client/input/sdl2.c @@ -173,19 +173,20 @@ 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) +// If the used SDL version doesn't support gamepad sensors... +#if !SDL_VERSION_ATLEAST(2, 0, 14) +// ...disable support for reading them. +#define NO_SDL_GYRO +#endif +#ifndef NO_SDL_GYRO // use SDL_CONTROLLERSENSORUPDATE to read gyro static unsigned int num_samples; -#define NATIVE_SDL_GYRO // 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 - +#else // 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. @@ -789,7 +790,7 @@ IN_Update(void) break; } -#ifdef NATIVE_SDL_GYRO // controller sensors' reading supported (gyro, accelerometer) +#ifndef NO_SDL_GYRO // gamepad sensors' reading is supported (gyro, accelerometer) case SDL_CONTROLLERSENSORUPDATE: if (event.csensor.sensor != SDL_SENSOR_GYRO) { @@ -804,7 +805,7 @@ IN_Update(void) break; } -#else // gyro read as "secondary joystick" +#else // gyro read from a "secondary joystick" (usually with name ending in "IMU") case SDL_JOYAXISMOTION: if ( !imu_joystick || event.cdevice.which != SDL_JoystickInstanceID(imu_joystick) ) { @@ -831,12 +832,12 @@ IN_Update(void) break; } -#endif // NATIVE_SDL_GYRO +#endif // !NO_SDL_GYRO if (gyro_active && gyro_mode->value && !cl_paused->value && cls.key_dest == key_game) { -#ifdef NATIVE_SDL_GYRO +#ifndef NO_SDL_GYRO if (!gyro_turning_axis->value) { gyro_yaw = event.csensor.data[1] - gyro_calibration_y->value; // yaw @@ -864,7 +865,7 @@ IN_Update(void) gyro_yaw = axis_value - gyro_calibration_z->value; } } -#endif // NATIVE_SDL_GYRO +#endif // !NO_SDL_GYRO } else { @@ -956,7 +957,7 @@ IN_Update(void) case REASON_GYROCALIBRATION: // finish and save calibration { -#ifdef NATIVE_SDL_GYRO +#ifndef NO_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); @@ -1081,7 +1082,7 @@ IN_TightenInput(float yaw, float pitch) { thumbstick_t input = { yaw, pitch }; const float magnitude = IN_StickMagnitude(input); -#ifdef NATIVE_SDL_GYRO +#ifndef NO_SDL_GYRO const float threshold = (M_PI / 180.0f) * gyro_tightening->value; #else const float threshold = (2560.0f / 180.0f) * gyro_tightening->value; @@ -1369,7 +1370,7 @@ 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 +#ifndef NO_SDL_GYRO float gyroViewFactor = (1.0f / M_PI) * joyViewFactor; #else float gyroViewFactor = (1.0f / 2560.0f) * joyViewFactor; // normalized for Switch gyro @@ -2039,7 +2040,7 @@ Controller_Rumble(const char *name, vec3_t source, qboolean from_player, void StartCalibration(void) { -#ifdef NATIVE_SDL_GYRO +#ifndef NO_SDL_GYRO num_samples = 0; #else num_samples[0] = num_samples[1] = num_samples[2] = 0; @@ -2159,27 +2160,36 @@ IN_Controller_Init(qboolean notify_user) Com_Printf ("Trying joystick %d, '%s'\n", i+1, joystick_name); // 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)) + if ( name_len > 6 && strstr(joystick_name + name_len - 6, "IMU") ) { +#ifndef NO_SDL_GYRO 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 ) + qboolean using_imu = !imu_joystick && !( strstr(joystick_name, "Joy-Con") && strstr(joystick_name, "L") ); + Com_Printf ("IMU device found... "); + SDL_JoystickClose(joystick); + joystick = NULL; + + if (using_imu) { imu_joystick = SDL_JoystickOpen(i); if (imu_joystick) { show_gyro = true; - Com_Printf ("Using this device as Gyro sensor.\n"); + Com_Printf ("using it as Gyro sensor.\n"); } else { - Com_Printf ("Couldn't open IMU: %s.\n", SDL_GetError()); + Com_Printf ("\nCouldn't open IMU: %s.\n", SDL_GetError()); } } + else + { + Com_Printf ("skipping.\n"); + } #endif continue; } @@ -2216,7 +2226,7 @@ IN_Controller_Init(qboolean notify_user) show_gamepad = true; Com_Printf("Enabled as Game Controller, settings:\n%s\n", SDL_GameControllerMapping(controller)); -#ifdef NATIVE_SDL_GYRO +#ifndef NO_SDL_GYRO if ( SDL_GameControllerHasSensor(controller, SDL_SENSOR_GYRO) && !SDL_GameControllerSetSensorEnabled(controller, SDL_SENSOR_GYRO, SDL_TRUE) ) @@ -2239,7 +2249,7 @@ IN_Controller_Init(qboolean notify_user) SDL_GameControllerSetLED(controller, 0, 80, 0); // green light } -#endif // NATIVE_SDL_GYRO +#endif // !NO_SDL_GYRO joystick_haptic = SDL_HapticOpenFromJoystick(SDL_GameControllerGetJoystick(controller)); @@ -2273,7 +2283,7 @@ 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 +#ifndef NO_SDL_GYRO // "native SDL gyro" exits when finding a single working gamepad break; #endif } @@ -2390,7 +2400,7 @@ IN_Controller_Shutdown(qboolean notify_user) joystick_left_x = joystick_left_y = joystick_right_x = joystick_right_y = 0; gyro_yaw = gyro_pitch = 0; -#ifndef NATIVE_SDL_GYRO +#ifdef NO_SDL_GYRO if (imu_joystick) { SDL_JoystickClose(imu_joystick); diff --git a/src/client/input/sdl3.c b/src/client/input/sdl3.c index b4b61080..808ae93c 100644 --- a/src/client/input/sdl3.c +++ b/src/client/input/sdl3.c @@ -175,8 +175,17 @@ static float gyro_accum[3]; static cvar_t *gyro_calibration_x; static cvar_t *gyro_calibration_y; static cvar_t *gyro_calibration_z; + +// If "SDL gyro" is not explicitly disabled, use SDL_EVENT_GAMEPAD_SENSOR_UPDATE to read gyro +#ifndef NO_SDL_GYRO static unsigned int num_samples; -#define NATIVE_SDL_GYRO // uses SDL_EVENT_GAMEPAD_SENSOR_UPDATE to read gyro +#else // otherwise, 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_EVENT_JOYSTICK_ADDED at game init. Allows for hot plugging of gamepad afterwards. static qboolean first_init = true; @@ -780,7 +789,7 @@ IN_Update(void) break; } -#ifdef NATIVE_SDL_GYRO // controller sensors' reading supported (gyro, accelerometer) +#ifndef NO_SDL_GYRO // gamepad sensors' reading is supported (gyro, accelerometer) case SDL_EVENT_GAMEPAD_SENSOR_UPDATE : if (event.gsensor.sensor != SDL_SENSOR_GYRO) { @@ -795,7 +804,7 @@ IN_Update(void) break; } -#else // gyro read as "secondary joystick" +#else // gyro read from a "secondary joystick" (usually with name ending in "IMU") case SDL_EVENT_JOYSTICK_AXIS_MOTION : if ( !imu_joystick || event.gdevice.which != SDL_GetJoystickID(imu_joystick) ) { @@ -822,12 +831,12 @@ IN_Update(void) break; } -#endif // NATIVE_SDL_GYRO +#endif // !NO_SDL_GYRO if (gyro_active && gyro_mode->value && !cl_paused->value && cls.key_dest == key_game) { -#ifdef NATIVE_SDL_GYRO +#ifndef NO_SDL_GYRO if (!gyro_turning_axis->value) { gyro_yaw = event.gsensor.data[1] - gyro_calibration_y->value; // yaw @@ -855,7 +864,7 @@ IN_Update(void) gyro_yaw = axis_value - gyro_calibration_z->value; } } -#endif // NATIVE_SDL_GYRO +#endif // !NO_SDL_GYRO } else { @@ -945,7 +954,7 @@ IN_Update(void) case REASON_GYROCALIBRATION: // finish and save calibration { -#ifdef NATIVE_SDL_GYRO +#ifndef NO_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); @@ -1070,7 +1079,11 @@ IN_TightenInput(float yaw, float pitch) { thumbstick_t input = { yaw, pitch }; const float magnitude = IN_StickMagnitude(input); +#ifndef NO_SDL_GYRO const float threshold = (M_PI / 180.0f) * gyro_tightening->value; +#else + const float threshold = (2560.0f / 180.0f) * gyro_tightening->value; +#endif if (magnitude < threshold) { @@ -1354,7 +1367,7 @@ 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 +#ifndef NO_SDL_GYRO float gyroViewFactor = (1.0f / M_PI) * joyViewFactor; #else float gyroViewFactor = (1.0f / 2560.0f) * joyViewFactor; // normalized for Switch gyro @@ -2025,7 +2038,7 @@ Controller_Rumble(const char *name, vec3_t source, qboolean from_player, void StartCalibration(void) { -#ifdef NATIVE_SDL_GYRO +#ifndef NO_SDL_GYRO num_samples = 0; #else num_samples[0] = num_samples[1] = num_samples[2] = 0; @@ -2152,27 +2165,36 @@ IN_Controller_Init(qboolean notify_user) Com_Printf ("Trying joystick %d, '%s'\n", i+1, joystick_name); // 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)) + if ( name_len > 6 && strstr(joystick_name + name_len - 6, "IMU") ) { +#ifndef NO_SDL_GYRO SDL_CloseJoystick(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 ) + qboolean using_imu = !imu_joystick && !( strstr(joystick_name, "Joy-Con") && strstr(joystick_name, "L") ); + Com_Printf ("IMU device found... "); + SDL_CloseJoystick(joystick); + joystick = NULL; + + if (using_imu) { imu_joystick = SDL_OpenJoystick(joysticks[i]); if (imu_joystick) { show_gyro = true; - Com_Printf ("Using this device as Gyro sensor.\n"); + Com_Printf ("using it as Gyro sensor.\n"); } else { - Com_Printf ("Couldn't open IMU: %s.\n", SDL_GetError()); + Com_Printf ("\nCouldn't open IMU: %s.\n", SDL_GetError()); } } + else + { + Com_Printf ("skipping.\n"); + } #endif continue; } @@ -2210,7 +2232,7 @@ IN_Controller_Init(qboolean notify_user) Com_Printf("Enabled as Gamepad, settings:\n%s\n", SDL_GetGamepadMapping(controller)); -#ifdef NATIVE_SDL_GYRO +#ifndef NO_SDL_GYRO if (SDL_GamepadHasSensor(controller, SDL_SENSOR_GYRO) && SDL_SetGamepadSensorEnabled(controller, SDL_SENSOR_GYRO, true) ) @@ -2230,7 +2252,7 @@ IN_Controller_Init(qboolean notify_user) SDL_SetGamepadLED(controller, 0, 80, 0); // green light } -#endif // NATIVE_SDL_GYRO +#endif // !NO_SDL_GYRO joystick_haptic = SDL_OpenHapticFromJoystick(SDL_GetGamepadJoystick(controller)); @@ -2259,7 +2281,7 @@ IN_Controller_Init(qboolean notify_user) Com_Printf("Gamepad doesn't support rumble.\n"); } -#ifdef NATIVE_SDL_GYRO // "native" exits when finding a single working controller +#ifndef NO_SDL_GYRO // "native SDL gyro" exits when finding a single working gamepad break; #endif } @@ -2384,7 +2406,7 @@ IN_Controller_Shutdown(qboolean notify_user) joystick_left_x = joystick_left_y = joystick_right_x = joystick_right_y = 0; gyro_yaw = gyro_pitch = 0; -#ifndef NATIVE_SDL_GYRO +#ifdef NO_SDL_GYRO if (imu_joystick) { SDL_CloseJoystick(imu_joystick); From d3a98cf66b7f877f11d369abaa7f97e29b618462 Mon Sep 17 00:00:00 2001 From: Jaime Moreira Date: Fri, 20 Dec 2024 16:36:53 -0300 Subject: [PATCH 7/7] Text simplified for sound backend menu option "Quality vs performance" might not correspond to reality; text deleted. Documentation updated to reflect current state of both OpenAL and SDL sound systems. Authored by @Yamagi. --- doc/030_configuration.md | 11 +++++------ src/client/menu/menu.c | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/doc/030_configuration.md b/doc/030_configuration.md index 0e49bf1c..8cf0b811 100644 --- a/doc/030_configuration.md +++ b/doc/030_configuration.md @@ -39,18 +39,17 @@ Yamagi Quake II ships with 4 renderers: ## Choosing a Sound System -Yamagi Quake II ships with 2 sound system: +Yamagi Quake II ships with 2 sound systems: * The **OpenAL** sound system: This is the default and highly - recommended. It provides full surround sound support and even HRTF for + recommended. It provides full surround sound support and HRTF for headphones. But also the plain stereo playback is much better than in the original sound system. The setup is done mostly through OpenAL, have a look at the documentation of your OpenAL library. * The **SDL** sound system: This is the classic sound system, providing - an experience like the original client. Set `s_openal` to `0` and - execute an `snd_restart` to activate it. The classic sound system may - be somewhat problematic on modern systems like Windows 10 or Linux - with Pulseaudio. + an experience like the original client. It's less CPU demanding than + OpenAL. Choose it in the options menu, or set `s_openal` to `0` and + execute an `snd_restart`, to activate it. ## Tuning for Precise Timings diff --git a/src/client/menu/menu.c b/src/client/menu/menu.c index 3451a862..f059162d 100644 --- a/src/client/menu/menu.c +++ b/src/client/menu/menu.c @@ -2397,7 +2397,7 @@ Options_MenuInit(void) static const char *sound_items[] = { - "openal (quality)", "sdl (performance)", 0 + "openal", "sdl", 0 }; static const char *yesno_names[] =