mirror of
https://github.com/yquake2/yquake2remaster.git
synced 2025-01-19 16:00:56 +00:00
Merge pull request #944 from 0lvin/haptic_feedback
Restore haptic feedback functionality.
This commit is contained in:
commit
502bd78c31
5 changed files with 521 additions and 7 deletions
|
@ -270,7 +270,7 @@ Set `0` by default.
|
|||
default this cvar is disabled (set to 0).
|
||||
|
||||
* **s_reverb_preset**: Enable reverb effect. By default this cvar is disabled
|
||||
(set to `-1`). Possibe values:
|
||||
(set to `-1`). Possible values:
|
||||
`-2`: Auto reverb effect select,
|
||||
`-1`: Disable reverb effect,
|
||||
`>=0`: select predefined effect.
|
||||
|
@ -546,6 +546,22 @@ Set `0` by default.
|
|||
the controller alone. As these vary by device, it's better to use
|
||||
'calibrate' in the 'gamepad' -> 'gyro' menu to set them.
|
||||
|
||||
* **joy_haptic_magnitude**: Haptic magnitude value, By default this cvar
|
||||
is `0.0` or disabled. Valid values are positive, e.g. 0..2.0.
|
||||
|
||||
* **joy_haptic_filter**: List of sound file names produced haptic feedback
|
||||
separated by space. `*` could be used for replace part of file name as
|
||||
regular expression. `!` at the beginning of value could be used for skip
|
||||
file name equal to value.
|
||||
|
||||
* **joy_haptic_distance**: Haptic maximum effect distance value, By default
|
||||
this cvar is `100.0`. Any positive value is valid. E.g. effect of shoot
|
||||
to a barrel has 58 points when player stay near the barrel.
|
||||
|
||||
* **s_feedback_kind**: Select kind of controller feedback to use. By default
|
||||
this cvar is `0`. Possible values:
|
||||
`0`: Rumble feedback,
|
||||
`1`: Haptic feedback.
|
||||
|
||||
## cvar operations
|
||||
|
||||
|
|
|
@ -287,6 +287,9 @@ void Key_SetBinding(int keynum, char *binding);
|
|||
void Key_MarkAllUp(void);
|
||||
void Controller_Rumble(const char *name, vec3_t source, qboolean from_player,
|
||||
unsigned int duration, unsigned short int volume);
|
||||
void Haptic_Feedback(const char *name, int effect_volume, int effect_duration,
|
||||
int effect_delay, int effect_attack, int effect_fade,
|
||||
int effect_x, int effect_y, int effect_z, float effect_distance);
|
||||
int Key_GetMenuKey(int key);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -105,13 +105,34 @@ static cvar_t *exponential_speedup;
|
|||
static cvar_t *in_grab;
|
||||
static cvar_t *m_filter;
|
||||
static cvar_t *windowed_mouse;
|
||||
static cvar_t *haptic_feedback_filter;
|
||||
|
||||
// ----
|
||||
|
||||
typedef struct haptic_effects_cache {
|
||||
int effect_volume;
|
||||
int effect_duration;
|
||||
int effect_delay;
|
||||
int effect_attack;
|
||||
int effect_fade;
|
||||
int effect_id;
|
||||
int effect_x;
|
||||
int effect_y;
|
||||
int effect_z;
|
||||
} haptic_effects_cache_t;
|
||||
|
||||
qboolean show_gamepad = false, show_haptic = false, show_gyro = false;
|
||||
|
||||
static SDL_Haptic *joystick_haptic = NULL;
|
||||
static SDL_GameController *controller = NULL;
|
||||
|
||||
#define HAPTIC_EFFECT_LIST_SIZE 16
|
||||
|
||||
static int last_haptic_volume = 0;
|
||||
static int last_haptic_effect_size = HAPTIC_EFFECT_LIST_SIZE;
|
||||
static int last_haptic_effect_pos = 0;
|
||||
static haptic_effects_cache_t last_haptic_effect[HAPTIC_EFFECT_LIST_SIZE];
|
||||
|
||||
// Joystick sensitivity
|
||||
static cvar_t *joy_yawsensitivity;
|
||||
static cvar_t *joy_pitchsensitivity;
|
||||
|
@ -131,6 +152,7 @@ static cvar_t *joy_flick_smoothed;
|
|||
|
||||
// Joystick haptic
|
||||
static cvar_t *joy_haptic_magnitude;
|
||||
static cvar_t *joy_haptic_distance;
|
||||
|
||||
// Gyro mode (0=off, 3=on, 1-2=uses button to enable/disable)
|
||||
cvar_t *gyro_mode;
|
||||
|
@ -1360,6 +1382,363 @@ In_FlushQueue(void)
|
|||
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
static void IN_Haptic_Shutdown(void);
|
||||
|
||||
/*
|
||||
* Init haptic effects
|
||||
*/
|
||||
static int
|
||||
IN_Haptic_Effect_Init(int effect_x, int effect_y, int effect_z,
|
||||
int period, int magnitude,
|
||||
int delay, int attack, int fade)
|
||||
{
|
||||
static SDL_HapticEffect haptic_effect;
|
||||
|
||||
/* limit magnitude */
|
||||
if (magnitude > SHRT_MAX)
|
||||
{
|
||||
magnitude = SHRT_MAX;
|
||||
}
|
||||
else if (magnitude < 0)
|
||||
{
|
||||
magnitude = 0;
|
||||
}
|
||||
|
||||
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_CARTESIAN; // Cartesian/3d coordinates
|
||||
haptic_effect.periodic.direction.dir[0] = effect_x;
|
||||
haptic_effect.periodic.direction.dir[1] = effect_y;
|
||||
haptic_effect.periodic.direction.dir[2] = effect_z;
|
||||
haptic_effect.periodic.period = period;
|
||||
haptic_effect.periodic.magnitude = magnitude;
|
||||
haptic_effect.periodic.length = period;
|
||||
haptic_effect.periodic.delay = delay;
|
||||
haptic_effect.periodic.attack_length = attack;
|
||||
haptic_effect.periodic.fade_length = fade;
|
||||
|
||||
return SDL_HapticNewEffect(joystick_haptic, &haptic_effect);
|
||||
}
|
||||
|
||||
static void
|
||||
IN_Haptic_Effects_Info(void)
|
||||
{
|
||||
Com_Printf ("Joystick/Mouse haptic:\n");
|
||||
Com_Printf (" * %d effects\n", SDL_HapticNumEffects(joystick_haptic));
|
||||
Com_Printf (" * %d haptic effects at the 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_effect_size = SDL_HapticNumEffectsPlaying(joystick_haptic);
|
||||
|
||||
if (last_haptic_effect_size > HAPTIC_EFFECT_LIST_SIZE)
|
||||
{
|
||||
last_haptic_effect_size = HAPTIC_EFFECT_LIST_SIZE;
|
||||
}
|
||||
|
||||
memset(&last_haptic_effect, 0, sizeof(last_haptic_effect));
|
||||
for (int i=0; i<HAPTIC_EFFECT_LIST_SIZE; i++)
|
||||
{
|
||||
last_haptic_effect[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_LIST_SIZE; i++)
|
||||
{
|
||||
last_haptic_effect[i].effect_volume = 0;
|
||||
last_haptic_effect[i].effect_duration = 0;
|
||||
last_haptic_effect[i].effect_delay = 0;
|
||||
last_haptic_effect[i].effect_attack = 0;
|
||||
last_haptic_effect[i].effect_fade = 0;
|
||||
last_haptic_effect[i].effect_x = 0;
|
||||
last_haptic_effect[i].effect_y = 0;
|
||||
last_haptic_effect[i].effect_z = 0;
|
||||
|
||||
IN_Haptic_Effect_Shutdown(&last_haptic_effect[i].effect_id);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
IN_Haptic_GetEffectId(int effect_volume, int effect_duration,
|
||||
int effect_delay, int effect_attack, int effect_fade,
|
||||
int effect_x, int effect_y, int effect_z)
|
||||
{
|
||||
int i, haptic_volume;
|
||||
|
||||
// check effects for reuse
|
||||
for (i=0; i < last_haptic_effect_size; i++)
|
||||
{
|
||||
if (
|
||||
last_haptic_effect[i].effect_volume != effect_volume ||
|
||||
last_haptic_effect[i].effect_duration != effect_duration ||
|
||||
last_haptic_effect[i].effect_delay != effect_delay ||
|
||||
last_haptic_effect[i].effect_attack != effect_attack ||
|
||||
last_haptic_effect[i].effect_fade != effect_fade ||
|
||||
last_haptic_effect[i].effect_x != effect_x ||
|
||||
last_haptic_effect[i].effect_y != effect_y ||
|
||||
last_haptic_effect[i].effect_z != effect_z)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
return last_haptic_effect[i].effect_id;
|
||||
}
|
||||
|
||||
/* create new effect */
|
||||
haptic_volume = joy_haptic_magnitude->value * effect_volume; // 32767 max strength;
|
||||
|
||||
/*
|
||||
Com_Printf("%d: volume %d: %d ms %d:%d:%d ms speed: %.2f\n",
|
||||
last_haptic_effect_pos, effect_volume, effect_duration,
|
||||
effect_delay, effect_attack, effect_fade,
|
||||
(float)effect_volume / effect_fade);
|
||||
*/
|
||||
|
||||
// FIFO for effects
|
||||
last_haptic_effect_pos = (last_haptic_effect_pos + 1) % last_haptic_effect_size;
|
||||
IN_Haptic_Effect_Shutdown(&last_haptic_effect[last_haptic_effect_pos].effect_id);
|
||||
last_haptic_effect[last_haptic_effect_pos].effect_volume = effect_volume;
|
||||
last_haptic_effect[last_haptic_effect_pos].effect_duration = effect_duration;
|
||||
last_haptic_effect[last_haptic_effect_pos].effect_delay = effect_delay;
|
||||
last_haptic_effect[last_haptic_effect_pos].effect_attack = effect_attack;
|
||||
last_haptic_effect[last_haptic_effect_pos].effect_fade = effect_fade;
|
||||
last_haptic_effect[last_haptic_effect_pos].effect_x = effect_x;
|
||||
last_haptic_effect[last_haptic_effect_pos].effect_y = effect_y;
|
||||
last_haptic_effect[last_haptic_effect_pos].effect_z = effect_z;
|
||||
last_haptic_effect[last_haptic_effect_pos].effect_id = IN_Haptic_Effect_Init(
|
||||
effect_x, effect_y, effect_z,
|
||||
effect_duration, haptic_volume,
|
||||
effect_delay, effect_attack, effect_fade);
|
||||
|
||||
return last_haptic_effect[last_haptic_effect_pos].effect_id;
|
||||
}
|
||||
|
||||
// Keep it same with rumble rules, look for descriptions to rumble
|
||||
// filtering in Controller_Rumble
|
||||
static char *default_haptic_filter = (
|
||||
// skipped files should be before wider rule
|
||||
"!weapons/*grenlb " // bouncing grenades don't have feedback
|
||||
"!weapons/*hgrenb " // bouncing grenades don't have feedback
|
||||
"!weapons/*open " // rogue's items don't have feedback
|
||||
"!weapons/*warn " // rogue's items don't have feedback
|
||||
// any weapons that are not in previous list
|
||||
"weapons/ "
|
||||
// player{,s} effects
|
||||
"player/*land " // fall without injury
|
||||
"player/*burn "
|
||||
"player/*pain "
|
||||
"player/*fall "
|
||||
"player/*death "
|
||||
"players/*burn "
|
||||
"players/*pain "
|
||||
"players/*fall "
|
||||
"players/*death "
|
||||
// environment effects
|
||||
"doors/ "
|
||||
"plats/ "
|
||||
"world/*dish "
|
||||
"world/*drill2a "
|
||||
"world/*dr_ "
|
||||
"world/*explod1 "
|
||||
"world/*rocks "
|
||||
"world/*rumble "
|
||||
"world/*quake "
|
||||
"world/*train2 "
|
||||
);
|
||||
|
||||
/*
|
||||
* name: sound name
|
||||
* filter: sound name rule with '*'
|
||||
* return false for empty filter
|
||||
*/
|
||||
static qboolean
|
||||
Haptic_Feedback_Filtered_Line(const char *name, const char *filter)
|
||||
{
|
||||
const char *current_filter = filter;
|
||||
|
||||
// skip empty filter
|
||||
if (!*current_filter)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
while (*current_filter)
|
||||
{
|
||||
char part_filter[MAX_QPATH];
|
||||
const char *name_part;
|
||||
const char *str_end;
|
||||
|
||||
str_end = strchr(current_filter, '*');
|
||||
if (!str_end)
|
||||
{
|
||||
if (!strstr(name, current_filter))
|
||||
{
|
||||
// no such part in string
|
||||
return false;
|
||||
}
|
||||
// have such part
|
||||
break;
|
||||
}
|
||||
// copy filter line
|
||||
if ((str_end - current_filter) >= MAX_QPATH)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
memcpy(part_filter, current_filter, str_end - current_filter);
|
||||
part_filter[str_end - current_filter] = 0;
|
||||
// place part in name
|
||||
name_part = strstr(name, part_filter);
|
||||
if (!name_part)
|
||||
{
|
||||
// no such part in string
|
||||
return false;
|
||||
}
|
||||
// have such part
|
||||
name = name_part + strlen(part_filter);
|
||||
// move to next filter
|
||||
current_filter = str_end + 1;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* name: sound name
|
||||
* filter: sound names separated by space, and '!' for skip file
|
||||
*/
|
||||
static qboolean
|
||||
Haptic_Feedback_Filtered(const char *name, const char *filter)
|
||||
{
|
||||
const char *current_filter = filter;
|
||||
|
||||
while (*current_filter)
|
||||
{
|
||||
char line_filter[MAX_QPATH];
|
||||
const char *str_end;
|
||||
|
||||
str_end = strchr(current_filter, ' ');
|
||||
// its end of filter
|
||||
if (!str_end)
|
||||
{
|
||||
// check rules inside line
|
||||
if (Haptic_Feedback_Filtered_Line(name, current_filter))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// copy filter line
|
||||
if ((str_end - current_filter) >= MAX_QPATH)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
memcpy(line_filter, current_filter, str_end - current_filter);
|
||||
line_filter[str_end - current_filter] = 0;
|
||||
// check rules inside line
|
||||
if (*line_filter == '!')
|
||||
{
|
||||
// has invert rule
|
||||
if (Haptic_Feedback_Filtered_Line(name, line_filter + 1))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Haptic_Feedback_Filtered_Line(name, line_filter))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// move to next filter
|
||||
current_filter = str_end + 1;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Haptic Feedback:
|
||||
* effect_volume=0..SHRT_MAX
|
||||
* effect{x,y,z} - effect direction
|
||||
* effect{delay,attack,fade} - effect durations
|
||||
* effect_distance - distance to sound source
|
||||
* name - sound file name
|
||||
*/
|
||||
void
|
||||
Haptic_Feedback(const char *name, int effect_volume, int effect_duration,
|
||||
int effect_delay, int effect_attack, int effect_fade,
|
||||
int effect_x, int effect_y, int effect_z, float effect_distance)
|
||||
{
|
||||
float max_distance = joy_haptic_distance->value;
|
||||
|
||||
if (!joystick_haptic || joy_haptic_magnitude->value <= 0 ||
|
||||
max_distance <= 0 || /* skip haptic if distance is negative */
|
||||
effect_distance > max_distance ||
|
||||
effect_volume <= 0 || effect_duration <= 0 ||
|
||||
last_haptic_effect_size <= 0) /* haptic but without slots? */
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* combine distance and volume */
|
||||
effect_volume *= (max_distance - effect_distance) / max_distance;
|
||||
|
||||
if (last_haptic_volume != (int)(joy_haptic_magnitude->value * 16))
|
||||
{
|
||||
IN_Haptic_Effects_Shutdown();
|
||||
IN_Haptic_Effects_Init();
|
||||
}
|
||||
|
||||
last_haptic_volume = joy_haptic_magnitude->value * 16;
|
||||
|
||||
if (Haptic_Feedback_Filtered(name, haptic_feedback_filter->string))
|
||||
{
|
||||
int effect_id;
|
||||
|
||||
effect_id = IN_Haptic_GetEffectId(effect_volume, effect_duration,
|
||||
effect_delay, effect_attack, effect_fade,
|
||||
effect_x, effect_y, effect_z);
|
||||
|
||||
if (effect_id == -1)
|
||||
{
|
||||
/* have rumble used some slots in haptic effect list?,
|
||||
* ok, use little bit less haptic effects at the same time*/
|
||||
IN_Haptic_Effects_Shutdown();
|
||||
last_haptic_effect_size --;
|
||||
Com_Printf("%d haptic effects at the same time\n", last_haptic_effect_size);
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_HapticRunEffect(joystick_haptic, effect_id, 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Controller_Rumble:
|
||||
* name = sound file name
|
||||
|
@ -1509,7 +1888,17 @@ Controller_Rumble(const char *name, vec3_t source, qboolean from_player,
|
|||
// name, effect_volume, duration, dist_prop, low_freq, hi_freq);
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 9)
|
||||
SDL_GameControllerRumble(controller, low_freq, hi_freq, duration);
|
||||
if (SDL_GameControllerRumble(controller, low_freq, hi_freq, duration) == -1)
|
||||
{
|
||||
if (!joystick_haptic)
|
||||
{
|
||||
/* no haptic, some other reason of error */
|
||||
return;
|
||||
}
|
||||
|
||||
/* All haptic/force feedback slots are busy, try to clean up little bit. */
|
||||
IN_Haptic_Effects_Shutdown();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1582,7 +1971,7 @@ IN_Controller_Init(qboolean notify_user)
|
|||
SDL_SetHint( SDL_HINT_JOYSTICK_HIDAPI_PS5_RUMBLE, "1" );
|
||||
#endif
|
||||
|
||||
if (SDL_Init(SDL_INIT_GAMECONTROLLER) == -1)
|
||||
if (SDL_Init(SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC) == -1)
|
||||
{
|
||||
Com_Printf ("Couldn't init SDL Game Controller: %s.\n", SDL_GetError());
|
||||
return;
|
||||
|
@ -1593,6 +1982,22 @@ IN_Controller_Init(qboolean notify_user)
|
|||
|
||||
if (!SDL_NumJoysticks())
|
||||
{
|
||||
joystick_haptic = SDL_HapticOpenFromMouse();
|
||||
|
||||
if (joystick_haptic &&
|
||||
(SDL_HapticQuery(joystick_haptic) & SDL_HAPTIC_SINE) == 0)
|
||||
{
|
||||
/* Disable haptic for joysticks without SINE */
|
||||
SDL_HapticClose(joystick_haptic);
|
||||
joystick_haptic = NULL;
|
||||
}
|
||||
|
||||
if (joystick_haptic)
|
||||
{
|
||||
IN_Haptic_Effects_Info();
|
||||
show_haptic = true;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1680,6 +2085,22 @@ IN_Controller_Init(qboolean notify_user)
|
|||
|
||||
#endif // SDL_VERSION_ATLEAST(2, 0, 16)
|
||||
|
||||
joystick_haptic = SDL_HapticOpenFromJoystick(SDL_GameControllerGetJoystick(controller));
|
||||
|
||||
if (joystick_haptic &&
|
||||
(SDL_HapticQuery(joystick_haptic) & SDL_HAPTIC_SINE) == 0)
|
||||
{
|
||||
/* Disable haptic for joysticks without SINE */
|
||||
SDL_HapticClose(joystick_haptic);
|
||||
joystick_haptic = NULL;
|
||||
}
|
||||
|
||||
if (joystick_haptic)
|
||||
{
|
||||
IN_Haptic_Effects_Info();
|
||||
show_haptic = true;
|
||||
}
|
||||
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 18) // support for query on features from controller
|
||||
if (SDL_GameControllerHasRumble(controller))
|
||||
#elif SDL_VERSION_ATLEAST(2, 0, 9) // support for rumble
|
||||
|
@ -1726,6 +2147,8 @@ IN_Init(void)
|
|||
sensitivity = Cvar_Get("sensitivity", "3", CVAR_ARCHIVE);
|
||||
|
||||
joy_haptic_magnitude = Cvar_Get("joy_haptic_magnitude", "0.0", CVAR_ARCHIVE);
|
||||
joy_haptic_distance = Cvar_Get("joy_haptic_distance", "100.0", CVAR_ARCHIVE);
|
||||
haptic_feedback_filter = Cvar_Get("joy_haptic_filter", default_haptic_filter, CVAR_ARCHIVE);
|
||||
|
||||
joy_yawsensitivity = Cvar_Get("joy_yawsensitivity", "1.0", CVAR_ARCHIVE);
|
||||
joy_pitchsensitivity = Cvar_Get("joy_pitchsensitivity", "1.0", CVAR_ARCHIVE);
|
||||
|
@ -1773,6 +2196,21 @@ IN_Init(void)
|
|||
Com_Printf("------------------------------------\n\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Shuts the backend down
|
||||
*/
|
||||
static void
|
||||
IN_Haptic_Shutdown(void)
|
||||
{
|
||||
if (joystick_haptic)
|
||||
{
|
||||
IN_Haptic_Effects_Shutdown();
|
||||
|
||||
SDL_HapticClose(joystick_haptic);
|
||||
joystick_haptic = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
IN_Controller_Shutdown(qboolean notify_user)
|
||||
{
|
||||
|
@ -1781,6 +2219,8 @@ IN_Controller_Shutdown(qboolean notify_user)
|
|||
Com_Printf("- Game Controller disconnected -\n");
|
||||
}
|
||||
|
||||
IN_Haptic_Shutdown();
|
||||
|
||||
if (controller)
|
||||
{
|
||||
SDL_GameControllerClose(controller);
|
||||
|
@ -1810,7 +2250,7 @@ IN_Shutdown(void)
|
|||
|
||||
IN_Controller_Shutdown(false);
|
||||
|
||||
const Uint32 subsystems = SDL_INIT_GAMECONTROLLER;
|
||||
const Uint32 subsystems = SDL_INIT_GAMECONTROLLER | SDL_INIT_HAPTIC;
|
||||
if (SDL_WasInit(subsystems) == subsystems)
|
||||
SDL_QuitSubSystem(subsystems);
|
||||
}
|
||||
|
|
|
@ -178,7 +178,6 @@ extern cvar_t* s_underwater_gain_hf;
|
|||
extern cvar_t* s_doppler;
|
||||
extern cvar_t* s_occlusion_strength;
|
||||
extern cvar_t* s_reverb_preset;
|
||||
extern cvar_t* s_ps_sorting;
|
||||
|
||||
/*
|
||||
* Globals
|
||||
|
|
|
@ -74,7 +74,8 @@ cvar_t* s_underwater_gain_hf;
|
|||
cvar_t* s_doppler;
|
||||
cvar_t* s_occlusion_strength;
|
||||
cvar_t* s_reverb_preset;
|
||||
cvar_t* s_ps_sorting;
|
||||
static cvar_t* s_ps_sorting;
|
||||
static cvar_t* s_feedback_kind;
|
||||
|
||||
channel_t channels[MAX_CHANNELS];
|
||||
static int num_sfx;
|
||||
|
@ -1107,7 +1108,60 @@ S_StartSound(vec3_t origin, int entnum, int entchannel, sfx_t *sfx,
|
|||
ps->fixed_origin = false;
|
||||
}
|
||||
|
||||
if (sfx->name[0])
|
||||
if (sfx->name[0] && s_feedback_kind->value == 1)
|
||||
{
|
||||
vec3_t orientation, direction;
|
||||
vec_t distance_direction;
|
||||
int dir_x, dir_y, dir_z;
|
||||
int effect_volume = -1;
|
||||
|
||||
VectorSubtract(listener_forward, listener_up, orientation);
|
||||
|
||||
// with !fixed we have all sounds related directly to player,
|
||||
// e.g. players fire, pain, menu
|
||||
if (!ps->fixed_origin)
|
||||
{
|
||||
VectorCopy(orientation, direction);
|
||||
distance_direction = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
VectorSubtract(listener_origin, ps->origin, direction);
|
||||
distance_direction = VectorLength(direction);
|
||||
}
|
||||
|
||||
VectorNormalize(direction);
|
||||
VectorNormalize(orientation);
|
||||
|
||||
dir_x = 16 * orientation[0] * direction[0];
|
||||
dir_y = 16 * orientation[1] * direction[1];
|
||||
dir_z = 16 * orientation[2] * direction[2];
|
||||
|
||||
if (sfx->cache)
|
||||
{
|
||||
int effect_duration;
|
||||
|
||||
effect_duration = sfx->cache->length;
|
||||
|
||||
if (sfx->cache->stereo)
|
||||
{
|
||||
effect_duration /= 2;
|
||||
}
|
||||
|
||||
/* sound near player has 16 points */
|
||||
effect_volume = sfx->cache->volume;
|
||||
|
||||
/* remove silence duration in the end of sound effect */
|
||||
effect_duration -= sfx->cache->end;
|
||||
|
||||
Haptic_Feedback(
|
||||
sfx->name, effect_volume,
|
||||
effect_duration,
|
||||
sfx->cache->begin, sfx->cache->attack, sfx->cache->fade,
|
||||
dir_x, dir_y, dir_z, distance_direction);
|
||||
}
|
||||
}
|
||||
else if (sfx->name[0] && s_feedback_kind->value == 0)
|
||||
{
|
||||
vec3_t direction = {0};
|
||||
unsigned int effect_duration = 0;
|
||||
|
@ -1544,6 +1598,8 @@ S_Init(void)
|
|||
/* Reverb and occlusion is fully disabled by default */
|
||||
s_reverb_preset = Cvar_Get("s_reverb_preset", "-1", CVAR_ARCHIVE);
|
||||
s_occlusion_strength = Cvar_Get("s_occlusion_strength", "0", CVAR_ARCHIVE);
|
||||
/* Feedback kind: 0 - rumble, 1 - haptic */
|
||||
s_feedback_kind = Cvar_Get("s_feedback_kind", "0", CVAR_ARCHIVE);
|
||||
|
||||
Cmd_AddCommand("play", S_Play);
|
||||
Cmd_AddCommand("stopsound", S_StopAllSounds);
|
||||
|
|
Loading…
Reference in a new issue