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/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/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/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 2bee5218..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,11 +804,11 @@ 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) ) { - break; // controller axes handled by SDL_CONTROLLERAXISMOTION + break; // gamepad axes handled by SDL_EVENT_GAMEPAD_AXIS_MOTION } int axis_value = event.gaxis.value; @@ -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 @@ -838,7 +847,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); @@ -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,10 +2232,10 @@ 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) ) + && SDL_SetGamepadSensorEnabled(controller, SDL_SENSOR_GYRO, true) ) { show_gyro = true; Com_Printf( "Gyro sensor enabled at %.2f Hz\n", @@ -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); diff --git a/src/client/menu/menu.c b/src/client/menu/menu.c index bad95ee9..f059162d 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"}, @@ -2254,7 +2270,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 +2357,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 +2395,9 @@ Options_MenuInit(void) 0 }; - static const char *quality_items[] = + static const char *sound_items[] = { - "normal", "high", 0 + "openal", "sdl", 0 }; static const char *yesno_names[] = @@ -2458,9 +2465,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; @@ -6366,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, ...) 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..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; @@ -727,19 +728,35 @@ 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; + + 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; - 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 +764,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 +793,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); @@ -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); 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; } }