This is an automated email from the git hooks/post-receive script. smcv pushed a commit to annotated tag debian/7.10+ctf1.05_dfsg-1 in repository yquake2.
commit ec97f12c8d5b898fb4652c4e60b3d38409f612ef Author: Simon McVittie <[email protected]> Date: Sun Dec 10 19:55:14 2017 +0000 New upstream version 7.10+ctf1.05~dfsg --- CHANGELOG | 15 + CMakeLists.txt | 3 + Makefile | 6 +- src/backends/generic/vid.c | 23 +- src/backends/sdl/input.c | 724 +++++++++++++++++++++++++++++++++++++- src/backends/sdl/refresh.c | 32 +- src/backends/unix/system.c | 49 ++- src/backends/windows/system.c | 2 +- src/client/cl_cin.c | 17 +- src/client/cl_keyboard.c | 58 ++- src/client/cl_main.c | 10 +- src/client/cl_prediction.c | 4 +- src/client/cl_screen.c | 2 +- src/client/cl_tempentities.c | 20 +- src/client/header/client.h | 6 +- src/client/header/keyboard.h | 14 +- src/client/menu/menu.c | 280 +++++++++------ src/client/menu/videomenu.c | 11 +- src/client/refresh/files/pcx.c | 64 +++- src/client/refresh/gl/r_main.c | 11 + src/client/refresh/gl/r_sdl.c | 13 + src/client/refresh/gl3/gl3_main.c | 11 + src/client/refresh/gl3/gl3_sdl.c | 16 +- src/client/sound/ogg.c | 21 +- src/client/sound/sound.c | 10 + src/common/collision.c | 24 +- src/common/frame.c | 16 + src/common/header/common.h | 2 +- src/common/header/shared.h | 4 +- 29 files changed, 1264 insertions(+), 204 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 17aeb32..862e844 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,18 @@ +Quake II 7.02 to 7.10: +- Joystick support including haptic feedback. This fantastic work was + done by Denis Pauk. The dirty work is done by SDL, how good or bad + a joystick or gamepad is supported depends on SDLs support for it. +- Fix the old SDL sound backend, s_openal set to 0 is working again. +- Fix possible Vorbis buffer underruns if too many sound samples are + in flight. This occured only in large multi player games with at + least 6 custom models. +- Fix a possible crash on Windows if MSAA was set to a value not + supported by the driver. +- It's now possible to play through the whole game on a Raspberry PI + and other ARM boards. Please note that the RPIs hardware is really + limited. Only the OpenGL 1.4 renderer is supported and the framerate + is highly dependend on the screen resolution. + Quake II 7.01 to 7.02: - Fix several corner cases regarding render library loading. The game should now always fall back to the OpenGL 1.4 renderer if the new diff --git a/CMakeLists.txt b/CMakeLists.txt index c836f02..84e260d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -531,6 +531,7 @@ set_target_properties(game PROPERTIES PREFIX "" LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release/baseq2 RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release/baseq2 + SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX} ) target_link_libraries(game ${yquake2LinkerFlags}) @@ -540,6 +541,7 @@ set_target_properties(ref_gl1 PROPERTIES PREFIX "" LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release + SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX} ) target_link_libraries(ref_gl1 ${yquake2LinkerFlags} ${yquake2OpenGLLinkerFlags} ${yquake2SDLLinkerFlags}) @@ -549,5 +551,6 @@ set_target_properties(ref_gl3 PROPERTIES PREFIX "" LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release + SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX} ) target_link_libraries(ref_gl3 ${yquake2LinkerFlags} ${yquake2SDLLinkerFlags}) diff --git a/Makefile b/Makefile index 801db08..a34985f 100755 --- a/Makefile +++ b/Makefile @@ -277,7 +277,7 @@ endif CFLAGS += -fvisibility=hidden LDFLAGS += -fvisibility=hidden -ifneq ($(YQ2_OSTYPE), $(filter $(YQ2_OSTYPE), Darwin, OpenBSD)) +ifneq ($(YQ2_OSTYPE), $(filter $(YQ2_OSTYPE), Darwin OpenBSD)) # for some reason the OSX & OpenBSD linker doesn't support this LDFLAGS += -Wl,--no-undefined endif @@ -451,7 +451,7 @@ ifeq ($(YQ2_OSTYPE), OpenBSD) release/quake2 : CFLAGS += -DUSE_OPENAL -DDEFAULT_OPENAL_DRIVER='"libopenal.so"' -DDLOPEN_OPENAL else ifeq ($(YQ2_OSTYPE), Darwin) release/quake2 : CFLAGS += -DUSE_OPENAL -DDEFAULT_OPENAL_DRIVER='"libopenal.dylib"' -I/usr/local/opt/openal-soft/include -DDLOPEN_OPENAL -release/quake2 : LDFLAGS += -L/usr/local/opt/openal-soft/lib +release/quake2 : LDFLAGS += -L/usr/local/opt/openal-soft/lib -rpath /usr/local/opt/openal-soft/lib else release/quake2 : CFLAGS += -DUSE_OPENAL -DDEFAULT_OPENAL_DRIVER='"libopenal.so.1"' -DDLOPEN_OPENAL endif @@ -460,7 +460,7 @@ release/quake2 : CFLAGS += -DUSE_OPENAL release/quake2 : LDFLAGS += -lopenal ifeq ($(YQ2_OSTYPE), Darwin) release/quake2 : CFLAGS += -I/usr/local/opt/openal-soft/include -release/quake2 : LDFLAGS += -L/usr/local/opt/openal-soft/lib +release/quake2 : LDFLAGS += -L/usr/local/opt/openal-soft/lib -rpath /usr/local/opt/openal-soft/lib endif # Darwin endif # !DLOPEN_OPENAL endif # WITH_OPENAL diff --git a/src/backends/generic/vid.c b/src/backends/generic/vid.c index 76f6a9c..8a653b6 100644 --- a/src/backends/generic/vid.c +++ b/src/backends/generic/vid.c @@ -101,6 +101,14 @@ vidmode_t vid_modes[] = { {"Mode 21: 1920x1080", 1920, 1080, 21}, {"Mode 22: 1920x1200", 1920, 1200, 22}, {"Mode 23: 2048x1536", 2048, 1536, 23}, + {"Mode 24: 2560x1080", 2560, 1080, 24}, + {"Mode 25: 2560x1440", 2560, 1440, 25}, + {"Mode 26: 2560x1600", 2560, 1600, 26}, + {"Mode 27: 3440x1440", 3440, 1440, 27}, + {"Mode 28: 3840x1600", 3840, 1600, 28}, + {"Mode 29: 3840x2160", 3840, 2160, 29}, + {"Mode 30: 4096x2160", 4096, 2160, 30}, + {"Mode 31: 5120x2880", 5120, 2880, 31}, }; /* Console variables that we need to access from this module */ @@ -177,11 +185,18 @@ VID_CheckChanges(void) cls.disable_screen = true; // Proceed to reboot the refresher - if(!VID_LoadRefresh() && (strcmp(vid_renderer->string, "gl1") != 0)) + if(!VID_LoadRefresh()) { - Com_Printf("\n ... trying again with standard OpenGL1.x renderer ... \n\n"); - Cvar_Set("vid_renderer", "gl1"); - VID_LoadRefresh(); + if (strcmp(vid_renderer->string, "gl1") != 0) + { + Com_Printf("\n ... trying again with standard OpenGL1.x renderer ... \n\n"); + Cvar_Set("vid_renderer", "gl1"); + VID_LoadRefresh(); + } + else + { + Com_Error(ERR_FATAL, "Couldn't load a rendering backend!\n"); + } } cls.disable_screen = false; } diff --git a/src/backends/sdl/input.c b/src/backends/sdl/input.c index 2034617..23233bb 100644 --- a/src/backends/sdl/input.c +++ b/src/backends/sdl/input.c @@ -1,6 +1,6 @@ /* * Copyright (C) 2010 Yamagi Burmeister - * Copyright (C) 1997-2001 Id Software, Inc. + * Copyright (C) 1997-2005 Id Software, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,6 +23,8 @@ * This is the Quake II input system backend, implemented with SDL. * * ======================================================================= + * + * Joystick threshold code is partially based on http://ioquake3.org code. */ #include "../../client/header/keyboard.h" @@ -61,16 +63,65 @@ #define MOUSE_MAX 3000 #define MOUSE_MIN 40 - + /* Globals */ static int mouse_x, mouse_y; static int old_mouse_x, old_mouse_y; static qboolean mlooking; +#if SDL_VERSION_ATLEAST(2, 0, 0) +static float joystick_yaw, joystick_pitch; +static float joystick_forwardmove, joystick_sidemove; +static float joystick_up; +static int back_button_id = -1; +static char last_hat = SDL_HAT_CENTERED; +static qboolean left_trigger = false; +static qboolean right_trigger = false; +qboolean show_haptic = false; + +/* Haptic feedback types */ +enum QHARPICTYPES { + HAPTIC_EFFECT_UNKNOWN = -1, + HAPTIC_EFFECT_BLASTER = 0, + HAPTIC_EFFECT_MENY, + HAPTIC_EFFECT_HYPER_BLASTER, + HAPTIC_EFFECT_MACHINEGUN, + HAPTIC_EFFECT_SHOTGUN, + HAPTIC_EFFECT_SSHOTGUN, + HAPTIC_EFFECT_RAILGUN, + HAPTIC_EFFECT_ROCKETGUN, + HAPTIC_EFFECT_GRENADE, + HAPTIC_EFFECT_BFG, + HAPTIC_EFFECT_PALANX, + HAPTIC_EFFECT_IONRIPPER, + HAPTIC_EFFECT_ETFRIFLE, + HAPTIC_EFFECT_SHOTGUN2, + HAPTIC_EFFECT_TRACKER, + HAPTIC_EFFECT_PAIN, + HAPTIC_EFFECT_STEP, + HAPTIC_EFFECT_TRAPCOCK, + HAPTIC_EFFECT_LAST +}; + +struct hapric_effects_cache { + int effect_type; + int effect_id; +}; + +static int last_haptic_volume = 0; +static struct hapric_effects_cache last_haptic_efffect[HAPTIC_EFFECT_LAST]; +static int last_haptic_efffect_size = HAPTIC_EFFECT_LAST; +static int last_haptic_efffect_pos = 0; + +/* Joystick */ +static SDL_Haptic *joystick_haptic = NULL; +static SDL_Joystick *joystick = NULL; +static SDL_GameController *controller = NULL; +#endif + /* CVars */ cvar_t *vid_fullscreen; static cvar_t *in_grab; -static cvar_t *in_mouse; static cvar_t *exponential_speedup; cvar_t *freelook; cvar_t *lookstrafe; @@ -78,10 +129,35 @@ cvar_t *m_forward; static cvar_t *m_filter; cvar_t *m_pitch; cvar_t *m_side; +cvar_t *m_up; cvar_t *m_yaw; cvar_t *sensitivity; static cvar_t *windowed_mouse; +#if SDL_VERSION_ATLEAST(2, 0, 0) +/* Joystick sensitivity */ +static cvar_t *joy_yawsensitivity; +static cvar_t *joy_pitchsensitivity; +static cvar_t *joy_forwardsensitivity; +static cvar_t *joy_sidesensitivity; +static cvar_t *joy_upsensitivity; +/* Joystick direction settings */ +static cvar_t *joy_axis_leftx; +static cvar_t *joy_axis_lefty; +static cvar_t *joy_axis_rightx; +static cvar_t *joy_axis_righty; +static cvar_t *joy_axis_triggerleft; +static cvar_t *joy_axis_triggerright; +/* Joystick threshold settings */ +static cvar_t *joy_axis_leftx_threshold; +static cvar_t *joy_axis_lefty_threshold; +static cvar_t *joy_axis_rightx_threshold; +static cvar_t *joy_axis_righty_threshold; +static cvar_t *joy_axis_triggerleft_threshold; +static cvar_t *joy_axis_triggerright_threshold; +/* Joystick haptic */ +static cvar_t *joy_haptic_magnitude; +#endif extern void GLimp_GrabInput(qboolean grab); @@ -447,10 +523,162 @@ IN_Update(void) } #endif break; +#if SDL_VERSION_ATLEAST(2, 0, 0) + case SDL_CONTROLLERBUTTONUP: + case SDL_CONTROLLERBUTTONDOWN: /* Handle Controller Back button */ + { + qboolean down = (event.type == SDL_CONTROLLERBUTTONDOWN); + if(event.cbutton.button == SDL_CONTROLLER_BUTTON_BACK) { + Key_Event(K_JOY_BACK, down, true); + } + } + break; + case SDL_CONTROLLERAXISMOTION: /* Handle Controller Motion */ + { + char* direction_type; + float threshold = 0; + float fix_value = 0; + int axis_value = event.caxis.value; + switch (event.caxis.axis) + { + /* left/right */ + case SDL_CONTROLLER_AXIS_LEFTX: + direction_type = joy_axis_leftx->string; + threshold = joy_axis_leftx_threshold->value; + break; + /* top/bottom */ + case SDL_CONTROLLER_AXIS_LEFTY: + direction_type = joy_axis_lefty->string; + threshold = joy_axis_lefty_threshold->value; + break; + /* second left/right */ + case SDL_CONTROLLER_AXIS_RIGHTX: + direction_type = joy_axis_rightx->string; + threshold = joy_axis_rightx_threshold->value; + break; + /* second top/bottom */ + case SDL_CONTROLLER_AXIS_RIGHTY: + direction_type = joy_axis_righty->string; + threshold = joy_axis_righty_threshold->value; + break; + case SDL_CONTROLLER_AXIS_TRIGGERLEFT: + direction_type = joy_axis_triggerleft->string; + threshold = joy_axis_triggerleft_threshold->value; + break; + case SDL_CONTROLLER_AXIS_TRIGGERRIGHT: + direction_type = joy_axis_triggerright->string; + threshold = joy_axis_triggerright_threshold->value; + break; + default: + direction_type = "none"; + } + + if (threshold > 0.9) + threshold = 0.9; + + if (axis_value < 0 && (axis_value > (32768 * threshold))) + axis_value = 0; + else if (axis_value > 0 && (axis_value < (32768 * threshold))) + axis_value = 0; + + // Smoothly ramp from dead zone to maximum value (from ioquake) + // https://github.com/ioquake/ioq3/blob/master/code/sdl/sdl_input.c + fix_value = ((float)abs(axis_value) / 32767.0f - threshold) / (1.0f - threshold); + if (fix_value < 0.0f) + fix_value = 0.0f; + + axis_value = (int)(32767 * ((axis_value < 0) ? -fix_value : fix_value)); + + if (cls.key_dest == key_game && (int)cl_paused->value == 0) + { + if (strcmp(direction_type, "sidemove") == 0) + { + joystick_sidemove = axis_value * joy_sidesensitivity->value; + // We need to be twice faster because with joystic we run... + joystick_sidemove *= cl_sidespeed->value * 2.0f; + } + else if (strcmp(direction_type, "forwardmove") == 0) + { + joystick_forwardmove = axis_value * joy_forwardsensitivity->value; + // We need to be twice faster because with joystic we run... + joystick_forwardmove *= cl_forwardspeed->value * 2.0f; + } + else if (strcmp(direction_type, "yaw") == 0) + { + joystick_yaw = axis_value * joy_yawsensitivity->value; + joystick_yaw *= cl_yawspeed->value; + } + else if (strcmp(direction_type, "pitch") == 0) + { + joystick_pitch = axis_value * joy_pitchsensitivity->value; + joystick_pitch *= cl_pitchspeed->value; + } + else if (strcmp(direction_type, "updown") == 0) + { + joystick_up = axis_value * joy_upsensitivity->value; + joystick_up *= cl_upspeed->value; + } + } + + if (strcmp(direction_type, "triggerleft") == 0) + { + qboolean new_left_trigger = abs(axis_value) > (32767 / 4); + if (new_left_trigger != left_trigger) + { + left_trigger = new_left_trigger; + Key_Event(K_TRIG_LEFT, left_trigger, true); + } + } + else if (strcmp(direction_type, "triggerright") == 0) + { + qboolean new_right_trigger = abs(axis_value) > (32767 / 4); + if (new_right_trigger != right_trigger) + { + right_trigger = new_right_trigger; + Key_Event(K_TRIG_RIGHT, right_trigger, true); + } + } + } + break; + /* Joystick can have more buttons than on general game controller + * so try to map not free buttons */ + case SDL_JOYBUTTONUP: + case SDL_JOYBUTTONDOWN: + { + qboolean down = (event.type == SDL_JOYBUTTONDOWN); + /* Ignore back button, we dont need event for such button */ + if (back_button_id == event.jbutton.button) + return; + if(event.jbutton.button <= (K_JOY32 - K_JOY1)) { + Key_Event(event.jbutton.button + K_JOY1, down, true); + } + } + break; + case SDL_JOYHATMOTION: + { + if (last_hat != event.jhat.value) + { + char diff = last_hat ^ event.jhat.value; + int i; + for (i=0; i < 4; i++) { + if (diff & (1 << i)) { + /* check that we have button up for some bit */ + if (last_hat & (1 << i)) + Key_Event(i + K_HAT_UP, false, true); + /* check that we have button down for some bit */ + if (event.jhat.value & (1 << i)) + Key_Event(i + K_HAT_UP, true, true); + } + } + last_hat = event.jhat.value; + } + } + break; +#endif case SDL_QUIT: Com_Quit(); - + break; } } @@ -480,7 +708,7 @@ In_FlushQueue(void) Key_MarkAllUp(); } - + /* * Move handling */ @@ -559,8 +787,41 @@ IN_Move(usercmd_t *cmd) mouse_x = mouse_y = 0; } + +#if SDL_VERSION_ATLEAST(2, 0, 0) + // to make the the viewangles changes independent of framerate + // we need to scale with frametime (assuming the configured values are for 60hz) + // 1/32768 is to normalize the input values from SDL (they're between -32768 and 32768 and we want -1 to 1) + // (for movement this is not needed, as those are absolute values independent of framerate) + float joyViewFactor = (1.0f/32768.0f) * (cls.rframetime/0.01666f); + + if (joystick_yaw) + { + cl.viewangles[YAW] -= (m_yaw->value * joystick_yaw) * joyViewFactor; + } + + if(joystick_pitch) + { + cl.viewangles[PITCH] += (m_pitch->value * joystick_pitch) * joyViewFactor; + } + + if (joystick_forwardmove) + { + cmd->forwardmove -= (m_forward->value * joystick_forwardmove) / 32768; + } + + if (joystick_sidemove) + { + cmd->sidemove += (m_side->value * joystick_sidemove) / 32768; + } + + if (joystick_up) + { + cmd->upmove -= (m_up->value * joystick_up) / 32768; + } +#endif } - + /* ------------------------------------------------------------------ */ /* @@ -582,7 +843,317 @@ IN_MLookUp(void) IN_CenterView(); } +#if SDL_VERSION_ATLEAST(2, 0, 0) +/* + * Shutdown haptic functionality + */ +static void IN_Haptic_Shutdown(void); + /* ------------------------------------------------------------------ */ +/* + * Init haptic effects + */ +static int +IN_Haptic_Effect_Init(int dir, int period, int magnitude, int length, int attack, int fade) +{ + /* + * Direction: + * North - 0 + * East - 9000 + * South - 18000 + * West - 27000 + */ + int effect_id; + static SDL_HapticEffect haptic_effect; + SDL_memset(&haptic_effect, 0, sizeof(SDL_HapticEffect)); // 0 is safe default + haptic_effect.type = SDL_HAPTIC_SINE; + haptic_effect.periodic.direction.type = SDL_HAPTIC_POLAR; // Polar coordinates + haptic_effect.periodic.direction.dir[0] = dir; + haptic_effect.periodic.period = period; + haptic_effect.periodic.magnitude = magnitude; + haptic_effect.periodic.length = length; + haptic_effect.periodic.attack_length = attack; + haptic_effect.periodic.fade_length = fade; + effect_id = SDL_HapticNewEffect(joystick_haptic, &haptic_effect); + if (effect_id < 0) + { + Com_Printf ("SDL_HapticNewEffect failed: %s\n", SDL_GetError()); + Com_Printf ("Please try to rerun game. Effects will be disabled for now.\n"); + IN_Haptic_Shutdown(); + } + return effect_id; +} + +static int +IN_Haptic_Effects_To_Id(int haptic_effect) +{ + if ((SDL_HapticQuery(joystick_haptic) & SDL_HAPTIC_SINE)==0) + return -1; + + int hapric_volume = joy_haptic_magnitude->value * 255; // * 128 = 32767 max strength; + if (hapric_volume > 255) + hapric_volume = 255; + else if (hapric_volume < 0) + hapric_volume = 0; + + switch(haptic_effect) { + case HAPTIC_EFFECT_MENY: + case HAPTIC_EFFECT_TRAPCOCK: + case HAPTIC_EFFECT_STEP: + /* North */ + return IN_Haptic_Effect_Init( + 0/* Force comes from N*/, 500/* 500 ms*/, hapric_volume * 48, + 200/* 0.2 seconds long */, 100/* Takes 0.1 second to get max strength */, + 100/* Takes 0.1 second to fade away */); + case HAPTIC_EFFECT_PAIN: + return IN_Haptic_Effect_Init( + 0/* Force comes from N*/, 700/* 700 ms*/, hapric_volume * 196, + 300/* 0.3 seconds long */, 200/* Takes 0.2 second to get max strength */, + 200/* Takes 0.2 second to fade away */); + case HAPTIC_EFFECT_BLASTER: + /* 30 degrees */ + return IN_Haptic_Effect_Init( + 2000/* Force comes from NNE*/, 500/* 500 ms*/, hapric_volume * 64, + 200/* 0.2 seconds long */, 100/* Takes 0.1 second to get max strength */, + 100/* Takes 0.1 second to fade away */); + case HAPTIC_EFFECT_HYPER_BLASTER: + return IN_Haptic_Effect_Init( + 4000/* Force comes from NNE*/, 500/* 500 ms*/, hapric_volume * 64, + 200/* 0.2 seconds long */, 100/* Takes 0.1 second to get max strength */, + 100/* Takes 0.1 second to fade away */); + case HAPTIC_EFFECT_ETFRIFLE: + /* 60 degrees */ + return IN_Haptic_Effect_Init( + 5000/* Force comes from NEE*/, 500/* 500 ms*/, hapric_volume * 64, + 200/* 0.2 seconds long */, 100/* Takes 0.1 second to get max strength */, + 100/* Takes 0.1 second to fade away */); + case HAPTIC_EFFECT_TRACKER: + return IN_Haptic_Effect_Init( + 7000/* Force comes from NEE*/, 500/* 500 ms*/, hapric_volume * 64, + 200/* 0.2 seconds long */, 100/* Takes 0.1 second to get max strength */, + 100/* Takes 0.1 second to fade away */); + case HAPTIC_EFFECT_MACHINEGUN: + /* 90 degrees */ + return IN_Haptic_Effect_Init( + 9000/* Force comes from E*/, 800/* 800 ms*/, hapric_volume * 88, + 600/* 0.6 seconds long */, 200/* Takes 0.2 second to get max strength */, + 400/* Takes 0.4 second to fade away */); + case HAPTIC_EFFECT_SHOTGUN: + /* 120 degrees */ + return IN_Haptic_Effect_Init( + 12000/* Force comes from EES*/, 700/* 700 ms*/, hapric_volume * 100, + 500/* 0.5 seconds long */, 100/* Takes 0.1 second to get max strength */, + 200/* Takes 0.2 second to fade away */); + case HAPTIC_EFFECT_SHOTGUN2: + /* 150 degrees */ + return IN_Haptic_Effect_Init( + 14000/* Force comes from ESS*/, 700/* 700 ms*/, hapric_volume * 96, + 500/* 0.5 seconds long */, 100/* Takes 0.1 second to get max strength */, + 100/* Takes 0.1 second to fade away */); + case HAPTIC_EFFECT_SSHOTGUN: + return IN_Haptic_Effect_Init( + 16000/* Force comes from ESS*/, 700/* 700 ms*/, hapric_volume * 96, + 500/* 0.5 seconds long */, 100/* Takes 0.1 second to get max strength */, + 100/* Takes 0.1 second to fade away */); + case HAPTIC_EFFECT_RAILGUN: + /* 180 degrees */ + return IN_Haptic_Effect_Init( + 18000/* Force comes from S*/, 700/* 700 ms*/, hapric_volume * 64, + 400/* 0.4 seconds long */, 100/* Takes 0.1 second to get max strength */, + 100/* Takes 0.1 second to fade away */); + case HAPTIC_EFFECT_ROCKETGUN: + /* 210 degrees */ + return IN_Haptic_Effect_Init( + 21000/* Force comes from SSW*/, 700/* 700 ms*/, hapric_volume * 128, + 400/* 0.4 seconds long */, 300/* Takes 0.3 second to get max strength */, + 100/* Takes 0.1 second to fade away */); + case HAPTIC_EFFECT_GRENADE: + /* 240 degrees */ + return IN_Haptic_Effect_Init( + 24000/* Force comes from SWW*/, 500/* 500 ms*/, hapric_volume * 64, + 200/* 0.2 seconds long */, 100/* Takes 0.1 second to get max strength */, + 100/* Takes 0.1 second to fade away */); + case HAPTIC_EFFECT_BFG: + /* 270 degrees */ + return IN_Haptic_Effect_Init( + 27000/* Force comes from W*/, 800/* 800 ms*/, hapric_volume * 100, + 600/* 0.2 seconds long */, 100/* Takes 0.1 second to get max strength */, + 100/* Takes 0.1 second to fade away */); + case HAPTIC_EFFECT_PALANX: + /* 300 degrees */ + return IN_Haptic_Effect_Init( + 30000/* Force comes from WWN*/, 500/* 500 ms*/, hapric_volume * 64, + 200/* 0.2 seconds long */, 100/* Takes 0.1 second to get max strength */, + 100/* Takes 0.1 second to fade away */); + case HAPTIC_EFFECT_IONRIPPER: + /* 330 degrees */ + return IN_Haptic_Effect_Init( + 33000/* Force comes from WNN*/, 500/* 500 ms*/, hapric_volume * 64, + 200/* 0.2 seconds long */, 100/* Takes 0.1 second to get max strength */, + 100/* Takes 0.1 second to fade away */); + default: + return -1; + } +} + +static void +IN_Haptic_Effects_Info(void) +{ + show_haptic = true; + Com_Printf ("Joystic/Mouse haptic:\n"); + Com_Printf (" * %d effects\n", SDL_HapticNumEffects(joystick_haptic)); + Com_Printf (" * %d effects in same time\n", SDL_HapticNumEffectsPlaying(joystick_haptic)); + Com_Printf (" * %d haptic axis\n", SDL_HapticNumAxes(joystick_haptic)); +} + +static void +IN_Haptic_Effects_Init(void) +{ + last_haptic_efffect_size = SDL_HapticNumEffectsPlaying(joystick_haptic); + if (last_haptic_efffect_size > HAPTIC_EFFECT_LAST) + last_haptic_efffect_size = HAPTIC_EFFECT_LAST; + for (int i=0; i<HAPTIC_EFFECT_LAST; i++) + { + last_haptic_efffect[i].effect_type = HAPTIC_EFFECT_UNKNOWN; + last_haptic_efffect[i].effect_id = -1; + } +} + +/* + * Shuts the backend down + */ +static void +IN_Haptic_Effect_Shutdown(int * effect_id) +{ + if (!effect_id) + return; + if (*effect_id >= 0) + SDL_HapticDestroyEffect(joystick_haptic, *effect_id); + *effect_id = -1; +} + +static void +IN_Haptic_Effects_Shutdown(void) +{ + for (int i=0; i<HAPTIC_EFFECT_LAST; i++) + { + last_haptic_efffect[i].effect_type = HAPTIC_EFFECT_UNKNOWN; + IN_Haptic_Effect_Shutdown(&last_haptic_efffect[i].effect_id); + } +} +#endif + +void +Haptic_Feedback(char *name) +{ +#if SDL_VERSION_ATLEAST(2, 0, 0) + int effect_type = HAPTIC_EFFECT_UNKNOWN; + + if (joy_haptic_magnitude->value <= 0) + return; + + if (!joystick_haptic) + return; + + if (last_haptic_volume != (int)(joy_haptic_magnitude->value * 255)) + { + IN_Haptic_Effects_Shutdown(); + IN_Haptic_Effects_Init(); + } + last_haptic_volume = joy_haptic_magnitude->value * 255; + + if (strstr(name, "misc/menu")) + { + effect_type = HAPTIC_EFFECT_MENY; + } + else if (strstr(name, "weapons/blastf1a")) + { + effect_type = HAPTIC_EFFECT_BLASTER; + } + else if (strstr(name, "weapons/hyprbf1a")) + { + effect_type = HAPTIC_EFFECT_HYPER_BLASTER; + } + else if (strstr(name, "weapons/machgf")) + { + effect_type = HAPTIC_EFFECT_MACHINEGUN; + } + else if (strstr(name, "weapons/shotgf1b")) + { + effect_type = HAPTIC_EFFECT_SHOTGUN; + } + else if (strstr(name, "weapons/sshotf1b")) + { + effect_type = HAPTIC_EFFECT_SSHOTGUN; + } + else if (strstr(name, "weapons/railgf1a")) + { + effect_type = HAPTIC_EFFECT_RAILGUN; + } + else if (strstr(name, "weapons/rocklf1a")) + { + effect_type = HAPTIC_EFFECT_ROCKETGUN; + } + else if (strstr(name, "weapons/grenlf1a") || strstr(name, "weapons/hgrent1a")) + { + effect_type = HAPTIC_EFFECT_GRENADE; + } + else if (strstr(name, "weapons/bfg__f1y")) + { + effect_type = HAPTIC_EFFECT_BFG; + } + else if (strstr(name, "weapons/plasshot")) + { + effect_type = HAPTIC_EFFECT_PALANX; + } + else if (strstr(name, "weapons/rippfire")) + { + effect_type = HAPTIC_EFFECT_IONRIPPER; + } + else if (strstr(name, "weapons/nail1")) + { + effect_type = HAPTIC_EFFECT_ETFRIFLE; + } + else if (strstr(name, "weapons/shotg2")) + { + effect_type = HAPTIC_EFFECT_SHOTGUN2; + } + else if (strstr(name, "weapons/disint2")) + { + effect_type = HAPTIC_EFFECT_TRACKER; + } + else if (strstr(name, "player/male/pain") || + strstr(name, "player/female/pain") || + strstr(name, "players/male/pain") || + strstr(name, "players/female/pain")) + { + effect_type = HAPTIC_EFFECT_PAIN; + } + else if (strstr(name, "player/step") || + strstr(name, "player/land")) + { + effect_type = HAPTIC_EFFECT_STEP; + } + else if (strstr(name, "weapons/trapcock")) + { + effect_type = HAPTIC_EFFECT_TRAPCOCK; + } + + if (effect_type != HAPTIC_EFFECT_UNKNOWN) + { + // check last effect for reuse + if (last_haptic_efffect[last_haptic_efffect_pos].effect_type != effect_type) + { + // FIFO for effects + last_haptic_efffect_pos = (last_haptic_efffect_pos+1) % last_haptic_efffect_size; + IN_Haptic_Effect_Shutdown(&last_haptic_efffect[last_haptic_efffect_pos].effect_id); + last_haptic_efffect[last_haptic_efffect_pos].effect_type = effect_type; + last_haptic_efffect[last_haptic_efffect_pos].effect_id = IN_Haptic_Effects_To_Id(effect_type); + } + SDL_HapticRunEffect(joystick_haptic, last_haptic_efffect[last_haptic_efffect_pos].effect_id, 1); + } +#endif +} /* * Initializes the backend @@ -594,17 +1165,46 @@ IN_Init(void) mouse_x = mouse_y = 0; +#if SDL_VERSION_ATLEAST(2, 0, 0) + joystick_yaw = joystick_pitch = joystick_forwardmove = joystick_sidemove = 0; +#endif + exponential_speedup = Cvar_Get("exponential_speedup", "0", CVAR_ARCHIVE); freelook = Cvar_Get("freelook", "1", 0); in_grab = Cvar_Get("in_grab", "2", CVAR_ARCHIVE); - in_mouse = Cvar_Get("in_mouse", "0", CVAR_ARCHIVE); lookstrafe = Cvar_Get("lookstrafe", "0", 0); m_filter = Cvar_Get("m_filter", "0", CVAR_ARCHIVE); + m_up = Cvar_Get("m_up", "1", 0); m_forward = Cvar_Get("m_forward", "1", 0); m_pitch = Cvar_Get("m_pitch", "0.022", 0); m_side = Cvar_Get("m_side", "0.8", 0); m_yaw = Cvar_Get("m_yaw", "0.022", 0); sensitivity = Cvar_Get("sensitivity", "3", 0); + +#if SDL_VERSION_ATLEAST(2, 0, 0) + joy_haptic_magnitude = Cvar_Get("joy_haptic_magnitude", "0.0", CVAR_ARCHIVE); + + joy_yawsensitivity = Cvar_Get("joy_yawsensitivity", "1.0", CVAR_ARCHIVE); + joy_pitchsensitivity = Cvar_Get("joy_pitchsensitivity", "1.0", CVAR_ARCHIVE); + joy_forwardsensitivity = Cvar_Get("joy_forwardsensitivity", "1.0", CVAR_ARCHIVE); + joy_sidesensitivity = Cvar_Get("joy_sidesensitivity", "1.0", CVAR_ARCHIVE); + joy_upsensitivity = Cvar_Get("joy_upsensitivity", "1.0", CVAR_ARCHIVE); + + joy_axis_leftx = Cvar_Get("joy_axis_leftx", "sidemove", CVAR_ARCHIVE); + joy_axis_lefty = Cvar_Get("joy_axis_lefty", "forwardmove", CVAR_ARCHIVE); + joy_axis_rightx = Cvar_Get("joy_axis_rightx", "yaw", CVAR_ARCHIVE); + joy_axis_righty = Cvar_Get("joy_axis_righty", "pitch", CVAR_ARCHIVE); + joy_axis_triggerleft = Cvar_Get("joy_axis_triggerleft", "triggerleft", CVAR_ARCHIVE); + joy_axis_triggerright = Cvar_Get("joy_axis_triggerright", "triggerright", CVAR_ARCHIVE); + + joy_axis_leftx_threshold = Cvar_Get("joy_axis_leftx_threshold", "0.15", CVAR_ARCHIVE); + joy_axis_lefty_threshold = Cvar_Get("joy_axis_lefty_threshold", "0.15", CVAR_ARCHIVE); + joy_axis_rightx_threshold = Cvar_Get("joy_axis_rightx_threshold", "0.15", CVAR_ARCHIVE); + joy_axis_righty_threshold = Cvar_Get("joy_axis_righty_threshold", "0.15", CVAR_ARCHIVE); + joy_axis_triggerleft_threshold = Cvar_Get("joy_axis_triggerleft_threshold", "0.15", CVAR_ARCHIVE); + joy_axis_triggerright_threshold = Cvar_Get("joy_axis_triggerright_threshold", "0.15", CVAR_ARCHIVE); +#endif + vid_fullscreen = Cvar_Get("vid_fullscreen", "0", CVAR_ARCHIVE); windowed_mouse = Cvar_Get("windowed_mouse", "1", CVAR_USERINFO | CVAR_ARCHIVE); @@ -617,12 +1217,103 @@ IN_Init(void) SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); #endif +#if SDL_VERSION_ATLEAST(2, 0, 0) + /* joystik init */ + if (!SDL_WasInit(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC)) + { + if (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) == -1) + { + Com_Printf ("Couldn't init SDL joystick: %s.\n", SDL_GetError ()); + } else { + Com_Printf ("%i joysticks were found.\n", SDL_NumJoysticks()); + if (SDL_NumJoysticks() > 0) { + int i; + for (i=0; i<SDL_NumJoysticks(); i ++) { + joystick = SDL_JoystickOpen(i); + Com_Printf ("The name of the joystick is '%s'\n", SDL_JoystickName(joystick)); + Com_Printf ("Number of Axes: %d\n", SDL_JoystickNumAxes(joystick)); + Com_Printf ("Number of Buttons: %d\n", SDL_JoystickNumButtons(joystick)); + Com_Printf ("Number of Balls: %d\n", SDL_JoystickNumBalls(joystick)); + Com_Printf ("Number of Hats: %d\n", SDL_JoystickNumHats(joystick)); + + joystick_haptic = SDL_HapticOpenFromJoystick(joystick); + if (joystick_haptic == NULL) + Com_Printf ("Most likely joystick isn't haptic\n"); + else + IN_Haptic_Effects_Info(); + + if(SDL_IsGameController(i)) + { + SDL_GameControllerButtonBind backBind; + controller = SDL_GameControllerOpen(i); + Com_Printf ("Controller settings: %s\n", SDL_GameControllerMapping(controller)); + Com_Printf ("Controller axis: \n"); + Com_Printf (" * leftx = %s\n", joy_axis_leftx->string); + Com_Printf (" * lefty = %s\n", joy_axis_lefty->string); + Com_Printf (" * rightx = %s\n", joy_axis_rightx->string); + Com_Printf (" * righty = %s\n", joy_axis_righty->string); + Com_Printf (" * triggerleft = %s\n", joy_axis_triggerleft->string); + Com_Printf (" * triggerright = %s\n", joy_axis_triggerright->string); + + Com_Printf ("Controller thresholds: \n"); + Com_Printf (" * leftx = %f\n", joy_axis_leftx_threshold->value); + Com_Printf (" * lefty = %f\n", joy_axis_lefty_threshold->value); + Com_Printf (" * rightx = %f\n", joy_axis_rightx_threshold->value); + Com_Printf (" * righty = %f\n", joy_axis_righty_threshold->value); + Com_Printf (" * triggerleft = %f\n", joy_axis_triggerleft_threshold->value); + Com_Printf (" * triggerright = %f\n", joy_axis_triggerright_threshold->value); + + backBind = SDL_GameControllerGetBindForButton(controller, SDL_CONTROLLER_BUTTON_BACK); + + if (backBind.bindType == SDL_CONTROLLER_BINDTYPE_BUTTON) { + back_button_id = backBind.value.button; + Com_Printf ("\nBack button JOY%d will be unbindable.\n", back_button_id+1); + } + break; + } + else + { + char joystick_guid[256] = {0}; + SDL_JoystickGUID guid; + guid = SDL_JoystickGetDeviceGUID(i); + SDL_JoystickGetGUIDString(guid, joystick_guid, 255); + Com_Printf ("For use joystic as game contoller please set SDL_GAMECONTROLLERCONFIG:\n"); + Com_Printf ("e.g.: SDL_GAMECONTROLLERCONFIG='%s,%s,leftx:a0,lefty:a1,rightx:a2,righty:a3,back:b1,...\n", joystick_guid, SDL_JoystickName(joystick)); + } + } + } + else + { + joystick_haptic = SDL_HapticOpenFromMouse(); + if (joystick_haptic == NULL) + Com_Printf ("Most likely mouse isn't haptic\n"); + else + IN_Haptic_Effects_Info(); + } + } + } +#endif + Com_Printf("------------------------------------\n\n"); } +#if SDL_VERSION_ATLEAST(2, 0, 0) /* * Shuts the backend down */ +static void +IN_Haptic_Shutdown(void) +{ + if (joystick_haptic) + { + IN_Haptic_Effects_Shutdown(); + + SDL_HapticClose(joystick_haptic); + joystick_haptic = NULL; + } +} +#endif + void IN_Shutdown(void) { @@ -630,7 +1321,24 @@ IN_Shutdown(void) Cmd_RemoveCommand("+mlook"); Cmd_RemoveCommand("-mlook"); - Com_Printf("Shutting down input.\n"); + Com_Printf("Shutting down input.\n"); + +#if SDL_VERSION_ATLEAST(2, 0, 0) + IN_Haptic_Shutdown(); + + if (controller) + { + back_button_id = -1; + SDL_GameControllerClose(controller); + controller = NULL; + } + + if (joystick) + { + SDL_JoystickClose(joystick); + joystick = NULL; + } +#endif } /* ------------------------------------------------------------------ */ diff --git a/src/backends/sdl/refresh.c b/src/backends/sdl/refresh.c index 073db64..569bce7 100644 --- a/src/backends/sdl/refresh.c +++ b/src/backends/sdl/refresh.c @@ -232,6 +232,7 @@ static qboolean GetWindowSize(int* w, int* h) return true; } +static qboolean initSuccessful = false; /* * Initializes the OpenGL window @@ -257,7 +258,9 @@ GLimp_InitGraphics(int fullscreen, int *pwidth, int *pheight) } #endif - if (GetWindowSize(&curWidth, &curHeight) && (curWidth == width) && (curHeight == height)) + // only do this if we already have a working window and fully initialized rendering backend + // (GLimp_InitGraphics() is also called when recovering if creating GL context fails or the one we got is unusable) + if (initSuccessful && GetWindowSize(&curWidth, &curHeight) && (curWidth == width) && (curHeight == height)) { /* If we want fullscreen, but aren't */ if (fullscreen != IsFullscreen()) @@ -319,20 +322,17 @@ GLimp_InitGraphics(int fullscreen, int *pwidth, int *pheight) { if (!CreateSDLWindow(flags, width, height)) { - if (flags & SDL_OPENGL) + if((flags & SDL_OPENGL) && gl_msaa_samples->value) { - if (gl_msaa_samples->value) - { - Com_Printf("SDL SetVideoMode failed: %s\n", SDL_GetError()); - Com_Printf("Reverting to %s gl_mode %i (%ix%i) without MSAA.\n", - (flags & fs_flag) ? "fullscreen" : "windowed", - (int) Cvar_VariableValue("gl_mode"), width, height); - - /* Try to recover */ - Cvar_SetValue("gl_msaa_samples", 0); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); - SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); - } + Com_Printf("SDL SetVideoMode failed: %s\n", SDL_GetError()); + Com_Printf("Reverting to %s gl_mode %i (%ix%i) without MSAA.\n", + (flags & fs_flag) ? "fullscreen" : "windowed", + (int) Cvar_VariableValue("gl_mode"), width, height); + + /* Try to recover */ + Cvar_SetValue("gl_msaa_samples", 0); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); } else if (width != 640 || height != 480 || (flags & fs_flag)) { @@ -374,6 +374,8 @@ GLimp_InitGraphics(int fullscreen, int *pwidth, int *pheight) /* No cursor */ SDL_ShowCursor(0); + initSuccessful = true; + return true; } @@ -453,6 +455,8 @@ VID_ShutdownWindow(void) // make sure that after vid_restart the refreshrate will be queried from SDL2 again. glimp_refreshRate = -1; + initSuccessful = false; // not initialized anymore + if (SDL_WasInit(SDL_INIT_EVERYTHING) == SDL_INIT_VIDEO) { SDL_Quit(); diff --git a/src/backends/unix/system.c b/src/backends/unix/system.c index 410f436..1b6409a 100644 --- a/src/backends/unix/system.c +++ b/src/backends/unix/system.c @@ -46,6 +46,11 @@ #include <dirent.h> #include <time.h> +#ifdef __APPLE__ +#include <mach/clock.h> +#include <mach/mach.h> +#endif + #include "../../common/header/common.h" #include "../../common/header/glob.h" #include "../generic/header/input.h" @@ -82,19 +87,49 @@ Sys_Init(void) long long Sys_Microseconds(void) { - static struct timespec last; - struct timespec now; +#ifdef __APPLE__ + // OSX didn't have clock_gettime() until recently, so use Mach's clock_get_time() + // instead. fortunately its mach_timespec_t seems identical to POSIX struct timespec + // so lots of code can be shared + clock_serv_t cclock; + mach_timespec_t now; + static mach_timespec_t first; + + host_get_clock_service(mach_host_self(), SYSTEM_CLOCK, &cclock); + clock_get_time(cclock, &now); + mach_port_deallocate(mach_task_self(), cclock); + +#else // not __APPLE__ - other Unix-likes will hopefully support clock_gettime() + struct timespec now; + static struct timespec first; + #ifdef _POSIX_MONOTONIC_CLOCK clock_gettime(CLOCK_MONOTONIC, &now); + #else + clock_gettime(CLOCK_REALTIME, &now); + #endif + +#endif // not __APPLE__ - if(last.tv_sec == 0) + if(first.tv_sec == 0) { - clock_gettime(CLOCK_MONOTONIC, &last); - return last.tv_nsec / 1000ll; + long long nsec = now.tv_nsec; + long long sec = now.tv_sec; + // set back first by 1ms so neither this function nor Sys_Milliseconds() + // (which calls this) will ever return 0 + nsec -= 1000000; + if(nsec < 0) + { + nsec += 1000000000ll; // 1s in ns => definitely positive now + --sec; + } + + first.tv_sec = sec; + first.tv_nsec = nsec; } - long long sec = now.tv_sec - last.tv_sec; - long long nsec = now.tv_nsec - last.tv_nsec; + long long sec = now.tv_sec - first.tv_sec; + long long nsec = now.tv_nsec - first.tv_nsec; if(nsec < 0) { diff --git a/src/backends/windows/system.c b/src/backends/windows/system.c index 94c4267..3fa5147 100644 --- a/src/backends/windows/system.c +++ b/src/backends/windows/system.c @@ -432,7 +432,7 @@ Sys_Microseconds(void) if (!uSecbase) { - uSecbase = microseconds / 1000ll; + uSecbase = microseconds - 1001ll; } return microseconds - uSecbase; diff --git a/src/client/cl_cin.c b/src/client/cl_cin.c index 36b278b..62644e4 100644 --- a/src/client/cl_cin.c +++ b/src/client/cl_cin.c @@ -66,7 +66,7 @@ SCR_LoadPCX(char *filename, byte **pic, byte **palette, int *width, int *height) byte *raw; pcx_t *pcx; int x, y; - int len; + int len, full_size; int dataByte, runLength; byte *out, *pix; @@ -75,7 +75,7 @@ SCR_LoadPCX(char *filename, byte **pic, byte **palette, int *width, int *height) /* load the file */ len = FS_LoadFile(filename, (void **)&raw); - if (!raw) + if (!raw || len < sizeof(pcx_t)) { return; } @@ -95,7 +95,8 @@ SCR_LoadPCX(char *filename, byte **pic, byte **palette, int *width, int *height) return; } - out = Z_Malloc((pcx->ymax + 1) * (pcx->xmax + 1)); + full_size = (pcx->ymax + 1) * (pcx->xmax + 1); + out = Z_Malloc(full_size); *pic = out; @@ -135,7 +136,15 @@ SCR_LoadPCX(char *filename, byte **pic, byte **palette, int *width, int *height) while (runLength-- > 0) { - pix[x++] = dataByte; + if ((*pic + full_size) <= (pix + x)) + { + x += runLength; + runLength = 0; + } + else + { + pix[x++] = dataByte; + } } } } diff --git a/src/client/cl_keyboard.c b/src/client/cl_keyboard.c index 2b3c26c..3e612b3 100644 --- a/src/client/cl_keyboard.c +++ b/src/client/cl_keyboard.c @@ -106,6 +106,49 @@ keyname_t keynames[] = { {"MOUSE4", K_MOUSE4}, {"MOUSE5", K_MOUSE5}, + {"JOY1", K_JOY1}, + {"JOY2", K_JOY2}, + {"JOY3", K_JOY3}, + {"JOY4", K_JOY4}, + {"JOY5", K_JOY5}, + {"JOY6", K_JOY6}, + {"JOY7", K_JOY7}, + {"JOY8", K_JOY8}, + {"JOY9", K_JOY9}, + {"JOY10", K_JOY10}, + {"JOY11", K_JOY11}, + {"JOY12", K_JOY12}, + {"JOY13", K_JOY13}, + {"JOY14", K_JOY14}, + {"JOY15", K_JOY15}, + {"JOY16", K_JOY16}, + {"JOY17", K_JOY17}, + {"JOY18", K_JOY18}, + {"JOY19", K_JOY19}, + {"JOY20", K_JOY20}, + {"JOY21", K_JOY21}, + {"JOY22", K_JOY22}, + {"JOY23", K_JOY23}, + {"JOY24", K_JOY24}, + {"JOY25", K_JOY25}, + {"JOY26", K_JOY26}, + {"JOY27", K_JOY27}, + {"JOY28", K_JOY28}, + {"JOY29", K_JOY29}, + {"JOY30", K_JOY30}, + {"JOY31", K_JOY31}, + {"JOY32", K_JOY32}, + + {"HAT_UP", K_HAT_UP}, + {"HAT_RIGHT", K_HAT_RIGHT}, + {"HAT_DOWN", K_HAT_DOWN}, + {"HAT_LEFT", K_HAT_LEFT}, + + {"TRIG_LEFT", K_TRIG_LEFT}, + {"TRIG_RIGHT", K_TRIG_RIGHT}, + + {"JOY_BACK", K_JOY_BACK}, + {"AUX1", K_AUX1}, {"AUX2", K_AUX2}, {"AUX3", K_AUX3}, @@ -562,7 +605,7 @@ Key_Message(int key) } /* - * Returns a key number to be used to index + * Returns a key number to be used to index * keybindings[] by looking at the given string. * Single ascii characters return themselves, while * the K_* names are matched up. @@ -715,7 +758,7 @@ Key_Bind_f(void) } /* don't allow binding escape or the special console keys */ - if(b == K_ESCAPE || b == '^' || b == '`' || b == '~') + if(b == K_ESCAPE || b == '^' || b == '`' || b == '~' || b == K_JOY_BACK) { if(doneWithDefaultCfg) { @@ -773,7 +816,7 @@ Key_WriteBindings(FILE *f) { if (keybindings[i] && keybindings[i][0]) { - fprintf(f, "bind %s \"%s\"\n", + fprintf(f, "bind %s \"%s\"\n", Key_KeynumToString(i), keybindings[i]); } } @@ -1061,12 +1104,12 @@ Key_Event(int key, qboolean down, qboolean special) } /* Key is unbound */ - if ((key >= 200) && !keybindings[key] && (cls.key_dest != key_console)) + if ((key >= K_MOUSE1 && key != K_JOY_BACK) && !keybindings[key] && (cls.key_dest != key_console)) { Com_Printf("%s is unbound, hit F4 to set.\n", Key_KeynumToString(key)); } - /* While in attract loop all keys besides F1 to F12 (to + /* While in attract loop all keys besides F1 to F12 (to allow quick load and the like) are treated like escape. */ if (cl.attractloop && (cls.key_dest != key_menu) && !((key >= K_F1) && (key <= K_F12))) @@ -1081,10 +1124,11 @@ Key_Event(int key, qboolean down, qboolean special) - moves one menu level up - closes the menu - closes the help computer - - closes the chat window */ + - closes the chat window + Fully same logic for K_JOY_BACK */ if (!cls.disable_screen) { - if (key == K_ESCAPE) + if (key == K_ESCAPE || key == K_JOY_BACK) { if (!down) { diff --git a/src/client/cl_main.c b/src/client/cl_main.c index 3ee4091..4180206 100644 --- a/src/client/cl_main.c +++ b/src/client/cl_main.c @@ -57,7 +57,6 @@ cvar_t *cl_showclamp; cvar_t *cl_paused; -cvar_t *lookspring; cvar_t *lookstrafe; cvar_t *sensitivity; @@ -93,6 +92,11 @@ centity_t cl_entities[MAX_EDICTS]; entity_state_t cl_parse_entities[MAX_PARSE_ENTITIES]; +/*Evil hack against too many power screen and power + shield impact sounds. For example if the player + fires his shotgun onto a Brain. */ +int num_power_sounds; + extern cvar_t *allow_download; extern cvar_t *allow_download_players; extern cvar_t *allow_download_models; @@ -490,7 +494,6 @@ CL_InitLocal(void) cl_run = Cvar_Get("cl_run", "0", CVAR_ARCHIVE); freelook = Cvar_Get("freelook", "1", CVAR_ARCHIVE); - lookspring = Cvar_Get("lookspring", "0", CVAR_ARCHIVE); lookstrafe = Cvar_Get("lookstrafe", "0", CVAR_ARCHIVE); sensitivity = Cvar_Get("sensitivity", "3", CVAR_ARCHIVE); @@ -735,6 +738,9 @@ CL_Frame(int packetdelta, int renderdelta, int timedelta, qboolean packetframe, cls.netchan.last_received = Sys_Milliseconds(); } + // Reset power shield / power screen sound counter. + num_power_sounds = 0; + if (!cl_timedemo->value) { // Don't throttle too much when connecting / loading. diff --git a/src/client/cl_prediction.c b/src/client/cl_prediction.c index a451e23..b607f9e 100644 --- a/src/client/cl_prediction.c +++ b/src/client/cl_prediction.c @@ -231,6 +231,7 @@ CL_PredictMovement(void) pmove_t pm; int i; int step; + vec3_t tmp; if (cls.state != ca_active) { @@ -296,9 +297,10 @@ CL_PredictMovement(void) } step = pm.s.origin[2] - (int)(cl.predicted_origin[2] * 8); + VectorCopy(tmp, pm.s.velocity); if (((step > 126 && step < 130)) - && !VectorCompare((float *)pm.s.velocity, vec3_origin) + && !VectorCompare(tmp, vec3_origin) && (pm.s.pm_flags & PMF_ON_GROUND)) { cl.predicted_step = step * 0.125f; diff --git a/src/client/cl_screen.c b/src/client/cl_screen.c index e7a6f9d..1c0334d 100644 --- a/src/client/cl_screen.c +++ b/src/client/cl_screen.c @@ -1445,7 +1445,7 @@ SCR_Framecounter(void) { char str[10]; snprintf(str, sizeof(str), "%3.2ffps", (1000.0 * 1000.0) / (avg / num)); - DrawStringScaled(scale*(viddef.width - 80), 0, str, scale); + DrawStringScaled(viddef.width - scale*(strlen(str)*8 + 2), 0, str, scale); } else if (cl_drawfps->value >= 2) { // Calculate average of frames. int avg = 0; diff --git a/src/client/cl_tempentities.c b/src/client/cl_tempentities.c index 0cb4f69..5b3f539 100644 --- a/src/client/cl_tempentities.c +++ b/src/client/cl_tempentities.c @@ -24,7 +24,9 @@ * ======================================================================= */ +#include <SDL2/SDL_scancode.h> #include "header/client.h" +#include "sound/header/local.h" typedef enum { @@ -716,7 +718,23 @@ CL_ParseTEnt(void) CL_ParticleEffect(pos, dir, 0xb0, 40); } - S_StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); + num_power_sounds++; + + /* If too many of these sounds are started in one frame (for + * example if the player shoots with the super shotgun into + * the power screen of a Brain) things get too loud and OpenAL + * is forced to scale the volume of several other sounds and + * the background music down. That leads to a noticable and + * annoying drop in the overall volume. + * + * Work around that by limiting the number of sounds started. + * 16 was choosen by empirical testing. + */ + if (sound_started == SS_OAL && num_power_sounds < 16) + { + S_StartSound(pos, 0, 0, cl_sfx_lashit, 1, ATTN_NORM, 0); + } + break; case TE_SHOTGUN: /* bullet hitting wall */ diff --git a/src/client/header/client.h b/src/client/header/client.h index eacad82..9c58b0e 100644 --- a/src/client/header/client.h +++ b/src/client/header/client.h @@ -249,6 +249,11 @@ typedef struct extern client_static_t cls; +/*Evil hack against too many power screen and power + shield impact sounds. For example if the player + fires his shotgun onto a Brain. */ +extern int num_power_sounds; + /* cvars */ extern cvar_t *gl_stereo_separation; extern cvar_t *gl_stereo_convergence; @@ -271,7 +276,6 @@ extern cvar_t *cl_anglespeedkey; extern cvar_t *cl_shownet; extern cvar_t *cl_showmiss; extern cvar_t *cl_showclamp; -extern cvar_t *lookspring; extern cvar_t *lookstrafe; extern cvar_t *sensitivity; extern cvar_t *m_pitch; diff --git a/src/client/header/keyboard.h b/src/client/header/keyboard.h index c6431c0..668606b 100644 --- a/src/client/header/keyboard.h +++ b/src/client/header/keyboard.h @@ -144,6 +144,17 @@ enum QKEYS { K_JOY31, K_JOY32, + K_HAT_UP, + K_HAT_RIGHT, + K_HAT_DOWN, + K_HAT_LEFT, + + K_TRIG_LEFT, + K_TRIG_RIGHT, + + /* Can't be mapped to any action */ + K_JOY_BACK, + K_AUX1, K_AUX2, K_AUX3, @@ -305,6 +316,7 @@ void Key_ReadConsoleHistory(); void Key_WriteConsoleHistory(); void Key_SetBinding(int keynum, char *binding); void Key_MarkAllUp(void); -int Key_GetKey(void); +void Haptic_Feedback(char *name); +int Key_GetMenuKey(int key); #endif diff --git a/src/client/menu/menu.c b/src/client/menu/menu.c index b8c07f6..93336f1 100644 --- a/src/client/menu/menu.c +++ b/src/client/menu/menu.c @@ -165,7 +165,7 @@ M_PushMenu(void (*draw)(void), const char *(*key)(int)) } #ifdef USE_OPENAL - if (cl.cinematic_file) + if (cl.cinematic_file && sound_started == SS_OAL) { AL_UnqueueRawSamples(); } @@ -215,11 +215,122 @@ M_PushMenu(void (*draw)(void), const char *(*key)(int)) cls.key_dest = key_menu; } +int +Key_GetMenuKey(int key) +{ + switch (key) + { + case K_KP_UPARROW: + case K_UPARROW: + case K_HAT_UP: + return K_UPARROW; + + case K_TAB: + case K_KP_DOWNARROW: + case K_DOWNARROW: + case K_HAT_DOWN: + return K_DOWNARROW; + + case K_KP_LEFTARROW: + case K_LEFTARROW: + case K_HAT_LEFT: + case K_TRIG_LEFT: + return K_LEFTARROW; + + case K_KP_RIGHTARROW: + case K_RIGHTARROW: + case K_HAT_RIGHT: + case K_TRIG_RIGHT: + return K_RIGHTARROW; + + case K_MOUSE1: + case K_MOUSE2: + case K_MOUSE3: + case K_MOUSE4: + case K_MOUSE5: + + case K_JOY1: + case K_JOY2: + case K_JOY3: + case K_JOY4: + case K_JOY5: + case K_JOY6: + case K_JOY7: + case K_JOY8: + case K_JOY9: + case K_JOY10: + case K_JOY11: + case K_JOY12: + case K_JOY13: + case K_JOY14: + case K_JOY15: + case K_JOY16: + case K_JOY17: + case K_JOY18: + case K_JOY19: + case K_JOY20: + case K_JOY21: + case K_JOY22: + case K_JOY23: + case K_JOY24: + case K_JOY25: + case K_JOY26: + case K_JOY27: + case K_JOY28: + case K_JOY29: + case K_JOY30: + case K_JOY31: + + case K_AUX1: + case K_AUX2: + case K_AUX3: + case K_AUX4: + case K_AUX5: + case K_AUX6: + case K_AUX7: + case K_AUX8: + case K_AUX9: + case K_AUX10: + case K_AUX11: + case K_AUX12: + case K_AUX13: + case K_AUX14: + case K_AUX15: + case K_AUX16: + case K_AUX17: + case K_AUX18: + case K_AUX19: + case K_AUX20: + case K_AUX21: + case K_AUX22: + case K_AUX23: + case K_AUX24: + case K_AUX25: + case K_AUX26: + case K_AUX27: + case K_AUX28: + case K_AUX29: + case K_AUX30: + case K_AUX31: + case K_AUX32: + + case K_KP_ENTER: + case K_ENTER: + return K_ENTER; + + case K_ESCAPE: + case K_JOY_BACK: + return K_ESCAPE; + } + + return key; +} const char * Default_MenuKey(menuframework_s *m, int key) { const char *sound = NULL; menucommon_s *item; + int menu_key = Key_GetMenuKey(key); if (m) { @@ -235,110 +346,51 @@ Default_MenuKey(menuframework_s *m, int key) } } - switch (key) + switch (menu_key) { case K_ESCAPE: M_PopMenu(); return menu_out_sound; - case K_KP_UPARROW: - case K_UPARROW: + case K_UPARROW: if (m) { m->cursor--; Menu_AdjustCursor(m, -1); sound = menu_move_sound; } - break; - case K_TAB: - if (m) - { - m->cursor++; - Menu_AdjustCursor(m, 1); - sound = menu_move_sound; - } - - break; - case K_KP_DOWNARROW: case K_DOWNARROW: - if (m) { m->cursor++; Menu_AdjustCursor(m, 1); sound = menu_move_sound; } - break; - case K_KP_LEFTARROW: - case K_LEFTARROW: + case K_LEFTARROW: if (m) { Menu_SlideItem(m, -1); sound = menu_move_sound; } - break; - case K_KP_RIGHTARROW: - case K_RIGHTARROW: + case K_RIGHTARROW: if (m) { Menu_SlideItem(m, 1); sound = menu_move_sound; } - break; - case K_MOUSE1: - case K_MOUSE2: - case K_MOUSE3: - case K_MOUSE4: - case K_MOUSE5: - case K_AUX1: - case K_AUX2: - case K_AUX3: - case K_AUX4: - case K_AUX5: - case K_AUX6: - case K_AUX7: - case K_AUX8: - case K_AUX9: - case K_AUX10: - case K_AUX11: - case K_AUX12: - case K_AUX13: - case K_AUX14: - case K_AUX15: - case K_AUX16: - case K_AUX17: - case K_AUX18: - case K_AUX19: - case K_AUX20: - case K_AUX21: - case K_AUX22: - case K_AUX23: - case K_AUX24: - case K_AUX25: - case K_AUX26: - case K_AUX27: - case K_AUX28: - case K_AUX29: - case K_AUX30: - case K_AUX31: - case K_AUX32: - - case K_KP_ENTER: case K_ENTER: - if (m) { Menu_SelectItem(m); } - sound = menu_move_sound; break; } @@ -593,35 +645,29 @@ M_Main_Draw(void) const char * M_Main_Key(int key) { - const char *sound = menu_move_sound; + const char *sound = menu_move_sound; + int menu_key = Key_GetMenuKey(key); - switch (key) + switch (menu_key) { case K_ESCAPE: M_PopMenu(); break; - case K_KP_DOWNARROW: case K_DOWNARROW: - if (++m_main_cursor >= MAIN_ITEMS) { m_main_cursor = 0; } - return sound; - case K_KP_UPARROW: case K_UPARROW: - if (--m_main_cursor < 0) { m_main_cursor = MAIN_ITEMS - 1; } - return sound; - case K_KP_ENTER: case K_ENTER: m_entersound = true; @@ -1003,10 +1049,12 @@ static menuslider_s s_options_sensitivity_slider; static menulist_s s_options_freelook_box; static menulist_s s_options_alwaysrun_box; static menulist_s s_options_invertmouse_box; -static menulist_s s_options_lookspring_box; static menulist_s s_options_lookstrafe_box; static menulist_s s_options_crosshair_box; static menuslider_s s_options_sfxvolume_slider; +#ifdef SDL2 +static menuslider_s s_options_haptic_slider; +#endif #if defined(OGG) || defined(CDA) static menulist_s s_options_cdshuffle_box; #endif @@ -1023,6 +1071,14 @@ CrosshairFunc(void *unused) Cvar_SetValue("crosshair", (float)s_options_crosshair_box.curvalue); } +#ifdef SDL2 +static void +HapticMagnitudeFunc(void *unused) +{ + Cvar_SetValue("joy_haptic_magnitude", s_options_haptic_slider.curvalue / 10.0F); +} +#endif + static void CustomizeControlsFunc(void *unused) { @@ -1097,13 +1153,15 @@ ControlsSetMenuItemValues(void) s_options_invertmouse_box.curvalue = (m_pitch->value < 0); - s_options_lookspring_box.curvalue = (lookspring->value != 0); - s_options_lookstrafe_box.curvalue = (lookstrafe->value != 0); s_options_freelook_box.curvalue = (freelook->value != 0); s_options_crosshair_box.curvalue = ClampCvar(0, 3, crosshair->value); + +#ifdef SDL2 + s_options_haptic_slider.curvalue = Cvar_VariableValue("joy_haptic_magnitude") * 10.0F; +#endif } static void @@ -1123,12 +1181,6 @@ InvertMouseFunc(void *unused) } static void -LookspringFunc(void *unused) -{ - Cvar_SetValue("lookspring", (float)!lookspring->value); -} - -static void LookstrafeFunc(void *unused) { Cvar_SetValue("lookstrafe", (float)!lookstrafe->value); @@ -1319,7 +1371,11 @@ Options_MenuInit(void) 0 }; - float scale = SCR_GetMenuScale(); + float scale = SCR_GetMenuScale(); + +#ifdef SDL2 + extern qboolean show_haptic; +#endif /* configure controls menu and menu items */ s_options_menu.x = viddef.width / 2; @@ -1389,34 +1445,37 @@ Options_MenuInit(void) s_options_invertmouse_box.generic.callback = InvertMouseFunc; s_options_invertmouse_box.itemnames = yesno_names; - s_options_lookspring_box.generic.type = MTYPE_SPINCONTROL; - s_options_lookspring_box.generic.x = 0; - s_options_lookspring_box.generic.y = 90; - s_options_lookspring_box.generic.name = "lookspring"; - s_options_lookspring_box.generic.callback = LookspringFunc; - s_options_lookspring_box.itemnames = yesno_names; - s_options_lookstrafe_box.generic.type = MTYPE_SPINCONTROL; s_options_lookstrafe_box.generic.x = 0; - s_options_lookstrafe_box.generic.y = 100; + s_options_lookstrafe_box.generic.y = 90; s_options_lookstrafe_box.generic.name = "lookstrafe"; s_options_lookstrafe_box.generic.callback = LookstrafeFunc; s_options_lookstrafe_box.itemnames = yesno_names; s_options_freelook_box.generic.type = MTYPE_SPINCONTROL; s_options_freelook_box.generic.x = 0; - s_options_freelook_box.generic.y = 110; + s_options_freelook_box.generic.y = 100; s_options_freelook_box.generic.name = "free look"; s_options_freelook_box.generic.callback = FreeLookFunc; s_options_freelook_box.itemnames = yesno_names; s_options_crosshair_box.generic.type = MTYPE_SPINCONTROL; s_options_crosshair_box.generic.x = 0; - s_options_crosshair_box.generic.y = 120; + s_options_crosshair_box.generic.y = 110; s_options_crosshair_box.generic.name = "crosshair"; s_options_crosshair_box.generic.callback = CrosshairFunc; s_options_crosshair_box.itemnames = crosshair_names; +#ifdef SDL2 + s_options_haptic_slider.generic.type = MTYPE_SLIDER; + s_options_haptic_slider.generic.x = 0; + s_options_haptic_slider.generic.y = 120; + s_options_haptic_slider.generic.name = "haptic magnitude"; + s_options_haptic_slider.generic.callback = HapticMagnitudeFunc; + s_options_haptic_slider.minvalue = 0; + s_options_haptic_slider.maxvalue = 22; +#endif + s_options_customize_options_action.generic.type = MTYPE_ACTION; s_options_customize_options_action.generic.x = 0; s_options_customize_options_action.generic.y = 140; @@ -1450,10 +1509,15 @@ Options_MenuInit(void) Menu_AddItem(&s_options_menu, (void *)&s_options_sensitivity_slider); Menu_AddItem(&s_options_menu, (void *)&s_options_alwaysrun_box); Menu_AddItem(&s_options_menu, (void *)&s_options_invertmouse_box); - Menu_AddItem(&s_options_menu, (void *)&s_options_lookspring_box); Menu_AddItem(&s_options_menu, (void *)&s_options_lookstrafe_box); Menu_AddItem(&s_options_menu, (void *)&s_options_freelook_box); Menu_AddItem(&s_options_menu, (void *)&s_options_crosshair_box); + +#ifdef SDL2 + if (show_haptic) + Menu_AddItem(&s_options_menu, (void *)&s_options_haptic_slider); +#endif + Menu_AddItem(&s_options_menu, (void *)&s_options_customize_options_action); Menu_AddItem(&s_options_menu, (void *)&s_options_defaults_action); Menu_AddItem(&s_options_menu, (void *)&s_options_console_action); @@ -2305,10 +2369,10 @@ static const char * LoadGame_MenuKey(int key) { static menuframework_s *m = &s_loadgame_menu; + int menu_key = Key_GetMenuKey(key); - switch (key) + switch (menu_key) { - case K_KP_UPARROW: case K_UPARROW: if (m->cursor == 0) { @@ -2316,8 +2380,7 @@ LoadGame_MenuKey(int key) LoadGame_MenuInit(); } break; - case K_TAB: - case K_KP_DOWNARROW: + case K_DOWNARROW: if (m->cursor == m->nitems - 1) { @@ -2325,16 +2388,17 @@ LoadGame_MenuKey(int key) LoadGame_MenuInit(); } break; - case K_KP_LEFTARROW: + case K_LEFTARROW: LoadSave_AdjustPage(-1); LoadGame_MenuInit(); return menu_move_sound; - case K_KP_RIGHTARROW: + case K_RIGHTARROW: LoadSave_AdjustPage(1); LoadGame_MenuInit(); return menu_move_sound; + default: s_savegame_menu.cursor = s_loadgame_menu.cursor; break; @@ -2416,6 +2480,7 @@ static const char * SaveGame_MenuKey(int key) { static menuframework_s *m = &s_savegame_menu; + int menu_key = Key_GetMenuKey(key); if (m_popup_string) { @@ -2423,9 +2488,8 @@ SaveGame_MenuKey(int key) return NULL; } - switch (key) + switch (menu_key) { - case K_KP_UPARROW: case K_UPARROW: if (m->cursor == 0) { @@ -2433,8 +2497,7 @@ SaveGame_MenuKey(int key) SaveGame_MenuInit(); } break; - case K_TAB: - case K_KP_DOWNARROW: + case K_DOWNARROW: if (m->cursor == m->nitems - 1) { @@ -2442,16 +2505,17 @@ SaveGame_MenuKey(int key) SaveGame_MenuInit(); } break; - case K_KP_LEFTARROW: + case K_LEFTARROW: LoadSave_AdjustPage(-1); SaveGame_MenuInit(); return menu_move_sound; - case K_KP_RIGHTARROW: + case K_RIGHTARROW: LoadSave_AdjustPage(1); SaveGame_MenuInit(); return menu_move_sound; + default: s_loadgame_menu.cursor = s_savegame_menu.cursor; break; @@ -4257,7 +4321,8 @@ M_Menu_PlayerConfig_f(void) static const char * M_Quit_Key(int key) { - switch (key) + int menu_key = Key_GetMenuKey(key); + switch (menu_key) { case K_ESCAPE: case 'n': @@ -4265,6 +4330,7 @@ M_Quit_Key(int key) M_PopMenu(); break; + case K_ENTER: case 'Y': case 'y': cls.key_dest = key_console; diff --git a/src/client/menu/videomenu.c b/src/client/menu/videomenu.c index 331dbf7..8511907 100644 --- a/src/client/menu/videomenu.c +++ b/src/client/menu/videomenu.c @@ -261,6 +261,14 @@ VID_MenuInit(void) "[1920 1080 ]", "[1920 1200 ]", "[2048 1536 ]", + "[2560x1080 ]", + "[2560x1440 ]", + "[2560x1600 ]", + "[3440x1440 ]", + "[3840x1600 ]", + "[3840x2160 ]", + "[4096x2160 ]", + "[5120x2880 ]", "[custom ]", 0 }; @@ -522,8 +530,9 @@ VID_MenuKey(int key) menuframework_s *m = &s_opengl_menu; static const char *sound = "misc/menu1.wav"; + int menu_key = Key_GetMenuKey(key); - switch (key) + switch (menu_key) { case K_ESCAPE: M_PopMenu(); diff --git a/src/client/refresh/files/pcx.c b/src/client/refresh/files/pcx.c index 010a224..926e0ea 100644 --- a/src/client/refresh/files/pcx.c +++ b/src/client/refresh/files/pcx.c @@ -122,7 +122,9 @@ LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height) byte *raw; pcx_t *pcx; int x, y; - int len; + int len, full_size; + int pcx_width, pcx_height; + qboolean image_issues = false; int dataByte, runLength; byte *out, *pix; char filename[256]; @@ -145,7 +147,7 @@ LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height) /* load the file */ len = ri.FS_LoadFile(filename, (void **)&raw); - if (!raw) + if (!raw || len < sizeof(pcx_t)) { R_Printf(PRINT_DEVELOPER, "Bad pcx file %s\n", filename); return; @@ -165,15 +167,19 @@ LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height) raw = &pcx->data; + pcx_width = pcx->xmax - pcx->xmin; + pcx_height = pcx->ymax - pcx->ymin; + if ((pcx->manufacturer != 0x0a) || (pcx->version != 5) || (pcx->encoding != 1) || (pcx->bits_per_pixel != 8) || - (pcx->xmax >= 640) || (pcx->ymax >= 480)) + (pcx_width >= 4096) || (pcx_height >= 4096)) { R_Printf(PRINT_ALL, "Bad pcx file %s\n", filename); return; } - out = malloc((pcx->ymax + 1) * (pcx->xmax + 1)); + full_size = (pcx_height + 1) * (pcx_width + 1); + out = malloc(full_size); *pic = out; @@ -182,28 +188,49 @@ LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height) if (palette) { *palette = malloc(768); - memcpy(*palette, (byte *)pcx + len - 768, 768); + if (len > 768) + { + memcpy(*palette, (byte *)pcx + len - 768, 768); + } + else + { + image_issues = true; + } } if (width) { - *width = pcx->xmax + 1; + *width = pcx_width + 1; } if (height) { - *height = pcx->ymax + 1; + *height = pcx_height + 1; } - for (y = 0; y <= pcx->ymax; y++, pix += pcx->xmax + 1) + for (y = 0; y <= pcx_height; y++, pix += pcx_width + 1) { - for (x = 0; x <= pcx->xmax; ) + for (x = 0; x <= pcx_width; ) { + if (raw - (byte *)pcx > len) + { + // no place for read + image_issues = true; + x = pcx_width; + break; + } dataByte = *raw++; if ((dataByte & 0xC0) == 0xC0) { runLength = dataByte & 0x3F; + if (raw - (byte *)pcx > len) + { + // no place for read + image_issues = true; + x = pcx_width; + break; + } dataByte = *raw++; } else @@ -213,7 +240,17 @@ LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height) while (runLength-- > 0) { - pix[x++] = dataByte; + if ((*pic + full_size) <= (pix + x)) + { + // no place for write + image_issues = true; + x += runLength; + runLength = 0; + } + else + { + pix[x++] = dataByte; + } } } } @@ -224,7 +261,7 @@ LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height) free(*pic); *pic = NULL; } - else if(pcx->xmax == 319 && pcx->ymax == 239 + else if(pcx_width == 319 && pcx_height == 239 && Q_strcasecmp(origname, "pics/quit.pcx") == 0 && Com_BlockChecksum(pcx, len) == 3329419434u) { @@ -233,6 +270,11 @@ LoadPCX(char *origname, byte **pic, byte **palette, int *width, int *height) fixQuitScreen(*pic); } + if (image_issues) + { + R_Printf(PRINT_ALL, "PCX file %s has possible size issues.\n", filename); + } + ri.FS_FreeFile(pcx); } diff --git a/src/client/refresh/gl/r_main.c b/src/client/refresh/gl/r_main.c index 003465b..bc0e213 100644 --- a/src/client/refresh/gl/r_main.c +++ b/src/client/refresh/gl/r_main.c @@ -1344,6 +1344,17 @@ R_SetMode(void) else if (err == rserr_invalid_mode) { R_Printf(PRINT_ALL, "ref_gl::R_SetMode() - invalid mode\n"); + if (gl_msaa_samples->value != 0.0f) + { + R_Printf(PRINT_ALL, "gl_msaa_samples was %d - will try again with gl_msaa_samples = 0\n", (int)gl_msaa_samples->value); + ri.Cvar_SetValue("gl_msaa_samples", 0.0f); + gl_msaa_samples->modified = false; + + if ((err = SetMode_impl(&vid.width, &vid.height, gl_mode->value, 0)) == rserr_ok) + { + return true; + } + } if(gl_mode->value == gl_state.prev_mode) { // trying again would result in a crash anyway, give up already diff --git a/src/client/refresh/gl/r_sdl.c b/src/client/refresh/gl/r_sdl.c index dd64c3c..7a6f261 100644 --- a/src/client/refresh/gl/r_sdl.c +++ b/src/client/refresh/gl/r_sdl.c @@ -360,6 +360,11 @@ int RI_PrepareForWindow(void) SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); } } + else + { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); + } /* Initiate the flags */ #if SDL_VERSION_ATLEAST(2, 0, 0) @@ -410,6 +415,14 @@ int RI_InitContext(void* win) #endif + const char* glver = (char *)glGetString(GL_VERSION); + sscanf(glver, "%d.%d", &gl_config.major_version, &gl_config.minor_version); + if (gl_config.major_version < 1 || (gl_config.major_version == 1 && gl_config.minor_version < 4)) + { + R_Printf(PRINT_ALL, "R_InitContext(): Got an OpenGL version %d.%d context - need (at least) 1.4!\n", gl_config.major_version, gl_config.minor_version); + return false; + } + if (gl_msaa_samples->value) { if (SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &msaa_samples) == 0) diff --git a/src/client/refresh/gl3/gl3_main.c b/src/client/refresh/gl3/gl3_main.c index b40cff0..ea517d3 100644 --- a/src/client/refresh/gl3/gl3_main.c +++ b/src/client/refresh/gl3/gl3_main.c @@ -406,6 +406,17 @@ GL3_SetMode(void) { R_Printf(PRINT_ALL, "ref_gl3::GL3_SetMode() - invalid mode\n"); + if (gl_msaa_samples->value != 0.0f) + { + R_Printf(PRINT_ALL, "gl_msaa_samples was %d - will try again with gl_msaa_samples = 0\n", (int)gl_msaa_samples->value); + ri.Cvar_SetValue("gl_msaa_samples", 0.0f); + gl_msaa_samples->modified = false; + + if ((err = SetMode_impl(&vid.width, &vid.height, gl_mode->value, 0)) == rserr_ok) + { + return true; + } + } if(gl_mode->value == gl3state.prev_mode) { // trying again would result in a crash anyway, give up already diff --git a/src/client/refresh/gl3/gl3_sdl.c b/src/client/refresh/gl3/gl3_sdl.c index 45519c6..c932364 100644 --- a/src/client/refresh/gl3/gl3_sdl.c +++ b/src/client/refresh/gl3/gl3_sdl.c @@ -113,6 +113,11 @@ int GL3_PrepareForWindow(void) SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); } } + else + { + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 0); + SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 0); + } /* Initiate the flags */ #if SDL_VERSION_ATLEAST(2, 0, 0) @@ -131,7 +136,7 @@ enum { QGL_DEBUG_SEVERITY_NOTIFICATION = 0x826B }; -static void +static void APIENTRY DebugCallback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const void *userParam) { @@ -230,12 +235,17 @@ int GL3_InitContext(void* win) if(!gladLoadGLLoader(SDL_GL_GetProcAddress)) { - R_Printf(PRINT_ALL, "R_InitContext(): loading OpenGL function pointers failed!\n"); + R_Printf(PRINT_ALL, "GL3_InitContext(): ERROR: loading OpenGL function pointers failed!\n"); + return false; + } + else if (GLVersion.major < 3 || (GLVersion.major == 3 && GLVersion.minor < 2)) + { + R_Printf(PRINT_ALL, "GL3_InitContext(): ERROR: glad only got GL version %d.%d!\n", GLVersion.major, GLVersion.minor); return false; } else { - R_Printf(PRINT_ALL, "Successfully loaded OpenGL function pointers using glad!\n"); + R_Printf(PRINT_ALL, "Successfully loaded OpenGL function pointers using glad, got version %d.%d!\n", GLVersion.major, GLVersion.minor); } #if SDL_VERSION_ATLEAST(2, 0, 0) diff --git a/src/client/sound/ogg.c b/src/client/sound/ogg.c index 4f521f7..35fab85 100644 --- a/src/client/sound/ogg.c +++ b/src/client/sound/ogg.c @@ -636,18 +636,12 @@ OGG_Stream(void) /* Calculate the number of buffers used for storing decoded OGG/Vorbis data. We take the number of active buffers - at startup (at this point most of the - samples should be precached and loaded - into buffers) and add 64. Empircal - testing showed, that at most times - at least 52 buffers remain available - for OGG/Vorbis, enough for about 3 - seconds playback. The music won't - stutter as long as the framerate - stayes over 1 FPS. */ - if (ogg_numbufs == 0) + and add 256. 256 are about 12 seconds + worth of sound, more than enough to + be resilent against underruns. */ + if (ogg_numbufs == 0 || active_buffers < ogg_numbufs - 256) { - ogg_numbufs = active_buffers + 64; + ogg_numbufs = active_buffers + 256; } /* active_buffers are all active OpenAL buffers, @@ -761,7 +755,10 @@ OGG_PauseCmd(void) } #ifdef USE_OPENAL - AL_UnqueueRawSamples(); + if (sound_started == SS_OAL) + { + AL_UnqueueRawSamples(); + } #endif } diff --git a/src/client/sound/sound.c b/src/client/sound/sound.c index 6f98c39..36d384d 100644 --- a/src/client/sound/sound.c +++ b/src/client/sound/sound.c @@ -669,6 +669,16 @@ S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx, ps->fixed_origin = false; } + if (sfx->name[0]) + { + // with !fixed we have all sounds related directly to player, + // e.g. players fire, pain, menu + if (!ps->fixed_origin) + { + Haptic_Feedback(sfx->name); + } + } + ps->entnum = entnum; ps->entchannel = entchannel; ps->attenuation = attenuation; diff --git a/src/common/collision.c b/src/common/collision.c index f494013..bdaa5e4 100644 --- a/src/common/collision.c +++ b/src/common/collision.c @@ -119,7 +119,7 @@ vec3_t trace_extents; int c_pointcontents; int c_traces, c_brush_traces; #endif - + /* 1/32 epsilon to keep floating point happy */ #define DIST_EPSILON (0.03125f) @@ -738,7 +738,7 @@ CM_ClipBoxToBrush(vec3_t mins, vec3_t maxs, vec3_t p1, } void -CM_TestBoxInBrush(vec3_t mins, vec3_t maxs, vec3_t p1, +CM_TestBoxInBrush(vec3_t mins, vec3_t maxs, vec3_t p1, trace_t *trace, cbrush_t *brush) { int i, j; @@ -1186,7 +1186,7 @@ CMod_LoadSubmodels(lump_t *l) if (l->filelen % sizeof(*in)) { - Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + Com_Error(ERR_DROP, "Mod_LoadSubmodels: funny lump size"); } count = l->filelen / sizeof(*in); @@ -1230,7 +1230,7 @@ CMod_LoadSurfaces(lump_t *l) if (l->filelen % sizeof(*in)) { - Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + Com_Error(ERR_DROP, "Mod_LoadSurfaces: funny lump size"); } count = l->filelen / sizeof(*in); @@ -1269,7 +1269,7 @@ CMod_LoadNodes(lump_t *l) if (l->filelen % sizeof(*in)) { - Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + Com_Error(ERR_DROP, "Mod_LoadNodes: funny lump size"); } count = l->filelen / sizeof(*in); @@ -1311,7 +1311,7 @@ CMod_LoadBrushes(lump_t *l) if (l->filelen % sizeof(*in)) { - Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + Com_Error(ERR_DROP, "Mod_LoadBrushes: funny lump size"); } count = l->filelen / sizeof(*in); @@ -1345,7 +1345,7 @@ CMod_LoadLeafs(lump_t *l) if (l->filelen % sizeof(*in)) { - Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + Com_Error(ERR_DROP, "Mod_LoadLeafs: funny lump size"); } count = l->filelen / sizeof(*in); @@ -1415,7 +1415,7 @@ CMod_LoadPlanes(lump_t *l) if (l->filelen % sizeof(*in)) { - Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + Com_Error(ERR_DROP, "Mod_LoadPlanes: funny lump size"); } count = l->filelen / sizeof(*in); @@ -1466,7 +1466,7 @@ CMod_LoadLeafBrushes(lump_t *l) if (l->filelen % sizeof(*in)) { - Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + Com_Error(ERR_DROP, "Mod_LoadLeafBrushes: funny lump size"); } count = l->filelen / sizeof(*in); @@ -1504,7 +1504,7 @@ CMod_LoadBrushSides(lump_t *l) if (l->filelen % sizeof(*in)) { - Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + Com_Error(ERR_DROP, "Mod_LoadBrushSides: funny lump size"); } count = l->filelen / sizeof(*in); @@ -1545,7 +1545,7 @@ CMod_LoadAreas(lump_t *l) if (l->filelen % sizeof(*in)) { - Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + Com_Error(ERR_DROP, "Mod_LoadAreas: funny lump size"); } count = l->filelen / sizeof(*in); @@ -1578,7 +1578,7 @@ CMod_LoadAreaPortals(lump_t *l) if (l->filelen % sizeof(*in)) { - Com_Error(ERR_DROP, "MOD_LoadBmodel: funny lump size"); + Com_Error(ERR_DROP, "Mod_LoadAreaPortals: funny lump size"); } count = l->filelen / sizeof(*in); diff --git a/src/common/frame.c b/src/common/frame.c index 1fcc90f..606ac14 100644 --- a/src/common/frame.c +++ b/src/common/frame.c @@ -293,6 +293,22 @@ Qcommon_Frame(int msec) c_pointcontents = 0; } + // gl_maxfps > 1000 breaks things, and so does <= 0 + // so cap to 1000 and treat <= 0 as "as fast as possible", which is 1000 + if (gl_maxfps->value > 1000 || gl_maxfps->value < 1) + { + Cvar_SetValue("gl_maxfps", 1000); + } + + if(cl_maxfps->value > 250) + { + Cvar_SetValue("cl_maxfps", 130); + } + else if(cl_maxfps->value < 1) + { + Cvar_SetValue("cl_maxfps", 60); + } + // Save global time for network- und input code. curtime = Sys_Milliseconds(); diff --git a/src/common/header/common.h b/src/common/header/common.h index 2f8afe2..2d6c598 100644 --- a/src/common/header/common.h +++ b/src/common/header/common.h @@ -32,7 +32,7 @@ #include "shared.h" #include "crc.h" -#define YQ2VERSION "7.02" +#define YQ2VERSION "7.10" #define BASEDIRNAME "baseq2" #ifndef YQ2OSTYPE diff --git a/src/common/header/shared.h b/src/common/header/shared.h index b6813c0..d12ab68 100644 --- a/src/common/header/shared.h +++ b/src/common/header/shared.h @@ -457,8 +457,8 @@ typedef struct cmodel_s typedef struct csurface_s { char name[16]; - int flags; - int value; + int flags; /* SURF_* */ + int value; /* unused */ } csurface_t; typedef struct mapsurface_s /* used internally due to name len probs */ -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-games/yquake2.git _______________________________________________ Pkg-games-commits mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-games-commits

