2021-04-22 09:33:48 +00:00
|
|
|
/*
|
2022-07-07 16:10:14 +00:00
|
|
|
* Copyright (c) 2016-2022 Vera Visions LLC.
|
2021-04-22 09:33:48 +00:00
|
|
|
*
|
|
|
|
* Permission to use, copy, modify, and distribute this software for any
|
|
|
|
* purpose with or without fee is hereby granted, provided that the above
|
|
|
|
* copyright notice and this permission notice appear in all copies.
|
|
|
|
*
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
|
|
|
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
2022-07-07 16:10:14 +00:00
|
|
|
*/
|
2021-11-15 02:59:39 +00:00
|
|
|
|
|
|
|
#ifndef EFXDATA_DYNAMIC
|
|
|
|
#ifndef EFXDATA_MAX
|
|
|
|
#define EFXDATA_MAX 64
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
|
|
#define EFXDATA_DYNAMIC
|
|
|
|
|
|
|
|
Your game can define EFXDATA_DYNAMIC in its progs.src if you want an unpredictable amount of EFX definitions.
|
|
|
|
Other than that, you can increase the value of EFXDATA_MAX.
|
|
|
|
|
|
|
|
We switched to up-front allocation because QCLIB fragments memory like hell as there's
|
|
|
|
no real garbage collector to speak of
|
|
|
|
*/
|
|
|
|
|
2021-04-27 10:53:21 +00:00
|
|
|
void
|
|
|
|
EFX_DebugInfo(void)
|
|
|
|
{
|
|
|
|
static vector pos = [16, 16];
|
|
|
|
|
|
|
|
static void epr(string tx) {
|
2021-11-04 21:48:19 +00:00
|
|
|
Font_DrawText(pos, tx, FONT_CON);
|
2021-04-27 10:53:21 +00:00
|
|
|
pos[1] += 12;
|
|
|
|
}
|
|
|
|
|
|
|
|
pos = [16,16];
|
|
|
|
epr("OpenAL EFX Debug Information:");
|
|
|
|
epr(strcat("EFX Name: ", g_efx_name[g_iEFX]));
|
|
|
|
epr(sprintf("Density: %d", g_efx[g_iEFX].flDensity));
|
|
|
|
epr(sprintf("Diffusion: %d", g_efx[g_iEFX].flDiffusion));
|
|
|
|
epr(sprintf("Gain: %d", g_efx[g_iEFX].flGain));
|
|
|
|
epr(sprintf("Gain HF: %d", g_efx[g_iEFX].flGainHF));
|
|
|
|
epr(sprintf("Gain LF: %d", g_efx[g_iEFX].flGainLF));
|
|
|
|
epr(sprintf("Decay Time: %d", g_efx[g_iEFX].flDecayTime));
|
|
|
|
epr(sprintf("Decay HF Ratio: %d", g_efx[g_iEFX].flDecayHFRatio));
|
|
|
|
epr(sprintf("Decay LF Ratio: %d", g_efx[g_iEFX].flDecayLFRatio));
|
|
|
|
epr(sprintf("Reflections Gain: %d", g_efx[g_iEFX].flReflectionsGain));
|
|
|
|
epr(sprintf("Reflections Delay: %d", g_efx[g_iEFX].flReflectionsDelay));
|
|
|
|
epr(sprintf("Reflections Pan: %v", g_efx[g_iEFX].flReflectionsPan));
|
|
|
|
epr(sprintf("Late Reverb Gain: %d", g_efx[g_iEFX].flLateReverbGain));
|
|
|
|
epr(sprintf("Late Reverb Delay: %d", g_efx[g_iEFX].flLateReverbDelay));
|
|
|
|
epr(sprintf("Late Reverb Pan: %v", g_efx[g_iEFX].flLateReverbPan));
|
|
|
|
epr(sprintf("Echo Time: %d", g_efx[g_iEFX].flEchoTime));
|
|
|
|
epr(sprintf("Echo Depth: %d", g_efx[g_iEFX].flEchoDepth));
|
|
|
|
epr(sprintf("Modulation Time: %d", g_efx[g_iEFX].flModulationTime));
|
|
|
|
epr(sprintf("Modulation Depth: %d", g_efx[g_iEFX].flModulationDepth));
|
|
|
|
epr(sprintf("Air Absorption Gain HF: %d", g_efx[g_iEFX].flAirAbsorptionGainHF));
|
|
|
|
epr(sprintf("HF Reference: %d", g_efx[g_iEFX].flHFReference));
|
|
|
|
epr(sprintf("LF Reference: %d", g_efx[g_iEFX].flLFReference));
|
|
|
|
epr(sprintf("Romm Rolloff Factor: %d", g_efx[g_iEFX].flRoomRolloffFactor));
|
|
|
|
epr(sprintf("Decay HF Limit: %i", g_efx[g_iEFX].iDecayHFLimit));
|
|
|
|
}
|
2021-04-22 09:33:48 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
EFX_Load(string efx_file)
|
|
|
|
{
|
|
|
|
filestream fh;
|
|
|
|
string line;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
if (!efx_file) {
|
2021-05-10 09:33:31 +00:00
|
|
|
return (0);
|
2021-04-22 09:33:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
i = g_efx_count;
|
|
|
|
efx_file = strtolower(efx_file);
|
|
|
|
|
|
|
|
/* check if it's already cached */
|
|
|
|
for (int x = 0; x < g_efx_count; x++) {
|
|
|
|
if (efx_file == g_efx_name[x]) {
|
|
|
|
return x;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
g_efx_count++;
|
2021-11-15 02:59:39 +00:00
|
|
|
|
|
|
|
#ifdef EFXDATA_DYNAMIC
|
2021-04-22 09:33:48 +00:00
|
|
|
g_efx = (reverbinfo_t *)memrealloc(g_efx, sizeof(reverbinfo_t), i, g_efx_count);
|
|
|
|
g_efx_name = (string *)memrealloc(g_efx_name, sizeof(string), i, g_efx_count);
|
2021-11-15 02:59:39 +00:00
|
|
|
#else
|
|
|
|
if (g_efx_count > EFXDATA_MAX) {
|
2024-03-02 08:40:08 +00:00
|
|
|
NSError("EFX_Load: Reached EFXDATA_MAX (%d)", EFXDATA_MAX);
|
|
|
|
return (0);
|
2021-11-15 02:59:39 +00:00
|
|
|
}
|
|
|
|
#endif
|
2021-04-22 09:33:48 +00:00
|
|
|
|
|
|
|
fh = fopen(strcat("efx/", efx_file, ".efx"), FILE_READ);
|
|
|
|
|
|
|
|
if (fh < 0) {
|
2021-05-10 09:33:31 +00:00
|
|
|
return (0);
|
2021-04-22 09:33:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* cache the name */
|
|
|
|
g_efx_name[i] = efx_file;
|
|
|
|
|
|
|
|
/* add some default values */
|
|
|
|
g_efx[i].flDensity = 1.000000;
|
|
|
|
g_efx[i].flDiffusion = 1.000000;
|
|
|
|
g_efx[i].flGain = 0.000000;
|
|
|
|
g_efx[i].flGainHF = 1.000000;
|
|
|
|
g_efx[i].flGainLF = 1.000000;
|
|
|
|
g_efx[i].flDecayTime = 1.000000;
|
|
|
|
g_efx[i].flDecayHFRatio = 1.000000;
|
|
|
|
g_efx[i].flDecayLFRatio = 1.000000;
|
|
|
|
g_efx[i].flReflectionsGain = 0.000000;
|
|
|
|
g_efx[i].flReflectionsDelay = 0.000000;
|
2021-04-23 09:43:40 +00:00
|
|
|
g_efx[i].flReflectionsPan = [0,0,0];
|
2021-04-22 09:33:48 +00:00
|
|
|
g_efx[i].flLateReverbGain = 1.000000;
|
|
|
|
g_efx[i].flLateReverbDelay = 0.000000;
|
|
|
|
g_efx[i].flLateReverbPan = [0,0,0];
|
|
|
|
g_efx[i].flEchoTime = 0.250000;
|
|
|
|
g_efx[i].flEchoDepth = 0.000000;
|
|
|
|
g_efx[i].flModulationTime = 0.250000;
|
|
|
|
g_efx[i].flModulationDepth = 0.000000;
|
|
|
|
g_efx[i].flAirAbsorptionGainHF = 1.000000;
|
|
|
|
g_efx[i].flHFReference = 5000.000000;
|
|
|
|
g_efx[i].flLFReference = 250.000000;
|
|
|
|
g_efx[i].flRoomRolloffFactor = 0.000000;
|
|
|
|
g_efx[i].iDecayHFLimit = 1i;
|
|
|
|
|
|
|
|
while ((line = fgets(fh))) {
|
|
|
|
int c = tokenize_console(line);
|
|
|
|
|
|
|
|
switch (argv(0)) {
|
|
|
|
case "density":
|
|
|
|
g_efx[i].flDensity = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "diffusion":
|
|
|
|
g_efx[i].flDiffusion = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "gain":
|
|
|
|
g_efx[i].flGain = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "gain_hf":
|
|
|
|
g_efx[i].flGainHF = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "gain_lf":
|
|
|
|
g_efx[i].flGainLF = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "decay_time":
|
|
|
|
g_efx[i].flDecayTime = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "decay_hf_ratio":
|
|
|
|
g_efx[i].flDecayHFRatio = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "decay_lf_ratio":
|
|
|
|
g_efx[i].flDecayLFRatio = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "reflections_gain":
|
|
|
|
g_efx[i].flReflectionsGain = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "reflections_delay":
|
|
|
|
g_efx[i].flReflectionsDelay = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "reflections_pan": /* VECTOR! */
|
|
|
|
g_efx[i].flReflectionsPan = stov(argv(1));
|
|
|
|
break;
|
|
|
|
case "late_reverb_gain":
|
|
|
|
g_efx[i].flLateReverbGain = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "late_reverb_delay":
|
|
|
|
g_efx[i].flLateReverbDelay = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "late_reverb_pan":
|
|
|
|
g_efx[i].flLateReverbPan = stov(argv(1));
|
|
|
|
break;
|
|
|
|
case "echo_time":
|
|
|
|
g_efx[i].flEchoTime = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "echo_depth":
|
|
|
|
g_efx[i].flEchoDepth = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "modulation_time":
|
|
|
|
g_efx[i].flModulationTime = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "modulation_depth":
|
|
|
|
g_efx[i].flModulationDepth = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "air_absorbtion_hf":
|
|
|
|
g_efx[i].flAirAbsorptionGainHF = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "hf_reference":
|
|
|
|
g_efx[i].flHFReference = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "lf_reference":
|
|
|
|
g_efx[i].flLFReference = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "room_rolloff_factor":
|
|
|
|
g_efx[i].flRoomRolloffFactor = stof(argv(1));
|
|
|
|
break;
|
|
|
|
case "decay_limit":
|
|
|
|
g_efx[i].iDecayHFLimit = stoi(argv(1));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-02 08:40:08 +00:00
|
|
|
NSLog("parsed EFXDef file %S", efx_file);
|
2021-04-22 09:33:48 +00:00
|
|
|
fclose(fh);
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
EFX_SetEnvironment(int id)
|
|
|
|
{
|
2021-04-22 09:44:53 +00:00
|
|
|
/* out of bounds... MAP BUG! */
|
|
|
|
if (id >= g_efx_count)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* same as before, skip */
|
|
|
|
if (g_iEFX == id)
|
2021-04-22 09:33:48 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
g_iEFXold = g_iEFX;
|
|
|
|
g_iEFX = id;
|
|
|
|
g_flEFXTime = 0.0f;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
EFX_Interpolate(int id)
|
|
|
|
{
|
2024-04-22 22:11:12 +00:00
|
|
|
mix.flDensity = lerp(mix.flDensity, g_efx[id].flDensity, g_flEFXTime);
|
|
|
|
mix.flDiffusion = lerp(mix.flDiffusion, g_efx[id].flDiffusion, g_flEFXTime);
|
|
|
|
mix.flGain = lerp(mix.flGain, g_efx[id].flGain, g_flEFXTime);
|
|
|
|
mix.flGainHF = lerp(mix.flGainHF, g_efx[id].flGainHF, g_flEFXTime);
|
|
|
|
mix.flGainLF = lerp(mix.flGainLF, g_efx[id].flGainLF, g_flEFXTime);
|
|
|
|
mix.flDecayTime = lerp(mix.flDecayTime, g_efx[id].flDecayTime, g_flEFXTime);
|
|
|
|
mix.flDecayHFRatio = lerp(mix.flDecayHFRatio, g_efx[id].flDecayHFRatio, g_flEFXTime);
|
|
|
|
mix.flDecayLFRatio = lerp(mix.flDecayLFRatio, g_efx[id].flDecayLFRatio, g_flEFXTime);
|
|
|
|
mix.flReflectionsGain = lerp(mix.flReflectionsGain, g_efx[id].flReflectionsGain, g_flEFXTime);
|
|
|
|
mix.flReflectionsDelay = lerp(mix.flReflectionsDelay, g_efx[id].flReflectionsDelay, g_flEFXTime);
|
|
|
|
mix.flReflectionsPan[0] = lerp(mix.flReflectionsPan[0], g_efx[id].flReflectionsPan[0], g_flEFXTime);
|
|
|
|
mix.flReflectionsPan[1] = lerp(mix.flReflectionsPan[1], g_efx[id].flReflectionsPan[1], g_flEFXTime);
|
|
|
|
mix.flReflectionsPan[1] = lerp(mix.flReflectionsPan[2], g_efx[id].flReflectionsPan[2], g_flEFXTime);
|
|
|
|
mix.flLateReverbGain = lerp(mix.flLateReverbGain, g_efx[id].flLateReverbGain, g_flEFXTime);
|
|
|
|
mix.flLateReverbDelay = lerp(mix.flLateReverbDelay, g_efx[id].flLateReverbDelay, g_flEFXTime);
|
|
|
|
mix.flLateReverbPan[0] = lerp(mix.flLateReverbPan[0], g_efx[id].flLateReverbPan[0], g_flEFXTime);
|
|
|
|
mix.flLateReverbPan[1] = lerp(mix.flLateReverbPan[1], g_efx[id].flLateReverbPan[1], g_flEFXTime);
|
|
|
|
mix.flLateReverbPan[2] = lerp(mix.flLateReverbPan[2], g_efx[id].flLateReverbPan[2], g_flEFXTime);
|
|
|
|
mix.flEchoTime = lerp(mix.flEchoTime, g_efx[id].flEchoTime, g_flEFXTime);
|
|
|
|
mix.flEchoDepth = lerp(mix.flEchoDepth, g_efx[id].flEchoDepth, g_flEFXTime);
|
|
|
|
mix.flModulationTime = lerp(mix.flModulationTime, g_efx[id].flModulationTime, g_flEFXTime);
|
|
|
|
mix.flModulationDepth = lerp(mix.flModulationDepth, g_efx[id].flModulationDepth, g_flEFXTime);
|
|
|
|
mix.flAirAbsorptionGainHF = lerp(mix.flAirAbsorptionGainHF, g_efx[id].flAirAbsorptionGainHF, g_flEFXTime);
|
|
|
|
mix.flHFReference = lerp(mix.flHFReference, g_efx[id].flHFReference, g_flEFXTime);
|
|
|
|
mix.flLFReference = lerp(mix.flLFReference, g_efx[id].flLFReference, g_flEFXTime);
|
|
|
|
mix.flRoomRolloffFactor = lerp(mix.flRoomRolloffFactor, g_efx[id].flRoomRolloffFactor, g_flEFXTime);
|
|
|
|
mix.iDecayHFLimit = lerp(mix.iDecayHFLimit, g_efx[id].iDecayHFLimit, g_flEFXTime);
|
2021-04-22 09:33:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2024-01-08 22:58:45 +00:00
|
|
|
EFX_UpdateListener(NSView playerView)
|
2021-04-22 09:33:48 +00:00
|
|
|
{
|
|
|
|
static int old_dsp;
|
|
|
|
|
|
|
|
vector vecPlayer;
|
|
|
|
|
|
|
|
if (autocvar_s_al_use_reverb == FALSE) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int s = (float)getproperty(VF_ACTIVESEAT);
|
|
|
|
pSeat = &g_seats[s];
|
|
|
|
vecPlayer = pSeat->m_vecPredictedOrigin;
|
|
|
|
|
|
|
|
float bestdist = 999999;
|
|
|
|
for (entity e = world; (e = find(e, classname, "env_sound"));) {
|
|
|
|
env_sound scape = (env_sound)e;
|
|
|
|
|
|
|
|
other = world;
|
|
|
|
traceline(scape.origin, vecPlayer, MOVE_OTHERONLY, scape);
|
|
|
|
if (trace_fraction < 1.0f) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
float dist = vlen(e.origin - vecPlayer);
|
|
|
|
if (dist > scape.m_iRadius) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dist > bestdist) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
bestdist = dist;
|
|
|
|
EFX_SetEnvironment(scape.m_iRoomType);
|
|
|
|
}
|
|
|
|
|
2024-01-08 22:58:45 +00:00
|
|
|
makevectors(playerView.GetCameraAngle());
|
|
|
|
SetListener(playerView.GetCameraOrigin(), v_forward, v_right, v_up, 12);
|
2021-04-22 09:33:48 +00:00
|
|
|
|
|
|
|
if (old_dsp == g_iEFX) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef EFX_LERP
|
|
|
|
if (g_flEFXTime < 1.0)
|
|
|
|
{
|
|
|
|
EFX_Interpolate(g_iEFX);
|
|
|
|
setup_reverb(12, &mix, sizeof(reverbinfo_t));
|
|
|
|
} else {
|
|
|
|
old_dsp = g_iEFX;
|
|
|
|
}
|
|
|
|
g_flEFXTime += clframetime;
|
|
|
|
#else
|
2024-03-02 08:40:08 +00:00
|
|
|
SndLog("Changed style to %s (%i)",
|
2022-05-11 19:49:04 +00:00
|
|
|
g_efx_name[g_iEFX], g_iEFX);
|
2021-04-22 09:33:48 +00:00
|
|
|
|
|
|
|
old_dsp = g_iEFX;
|
|
|
|
setup_reverb(12, &g_efx[g_iEFX], sizeof(reverbinfo_t));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
EFX_Init(void)
|
|
|
|
{
|
|
|
|
int efx_default;
|
|
|
|
int efx_underwater;
|
|
|
|
|
2024-03-02 08:40:08 +00:00
|
|
|
InitStart();
|
2022-02-23 09:17:05 +00:00
|
|
|
|
2021-11-15 02:59:39 +00:00
|
|
|
#ifndef EFXDATA_DYNAMIC
|
|
|
|
g_efx = (reverbinfo_t *)memalloc(sizeof(reverbinfo_t) * EFXDATA_MAX);
|
|
|
|
g_efx_name = (string *)memalloc(sizeof(string) * EFXDATA_MAX);
|
2024-03-02 08:40:08 +00:00
|
|
|
NSLog("...allocated %d bytes for EFXDefs.", (sizeof(string) * EFXDATA_MAX) + (sizeof(reverbinfo_t) * EFXDATA_MAX));
|
2022-03-03 22:16:02 +00:00
|
|
|
#else
|
2024-03-02 08:40:08 +00:00
|
|
|
NSLog("...dynamic allocation for EFXDefs enabled.");
|
2021-11-15 02:59:39 +00:00
|
|
|
#endif
|
|
|
|
|
2021-04-22 09:33:48 +00:00
|
|
|
efx_default = EFX_Load("default");
|
|
|
|
efx_underwater = EFX_Load("underwater");
|
|
|
|
EFX_SetEnvironment(efx_default);
|
|
|
|
|
|
|
|
/* mix the final value immediately */
|
|
|
|
#ifdef EFX_LERP
|
|
|
|
g_flEFXTime = 1.0f;
|
|
|
|
EFX_Interpolate(g_iEFX);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
setup_reverb(12, &g_efx[g_iEFX], sizeof(reverbinfo_t));
|
|
|
|
setup_reverb(10, &g_efx[efx_underwater], sizeof(reverbinfo_t));
|
2024-03-02 08:40:08 +00:00
|
|
|
InitEnd();
|
2021-04-22 09:33:48 +00:00
|
|
|
}
|
2021-05-07 14:29:24 +00:00
|
|
|
|
|
|
|
void
|
|
|
|
EFX_Shutdown(void)
|
|
|
|
{
|
|
|
|
if (!g_efx_count)
|
|
|
|
return;
|
|
|
|
|
|
|
|
g_efx_count = 0;
|
|
|
|
memfree(g_efx);
|
|
|
|
}
|